Merge pull request #1551 from DOCGroup/plm_jira_333
[ACE_TAO.git] / TAO / examples / Advanced / ch_18 / icp.cpp
blobd06ee1dcf348ffb4adbab7c1547aaa14f5907c62
1 //=============================================================================
2 /**
3 * @file icp.cpp
5 * @author Source code used in TAO has been modified and adapted from the codeprovided in the book
6 * @author "Advanced CORBA Programming with C++" by MichiHenning and Steve Vinoski. Copyright 1999. Addison-Wesley
7 * @author Reading
8 * @author MA.Modified for TAO by Mike Moran <mm4@cs.wustl.edu>
9 */
10 //=============================================================================
16 #include <string>
17 #include <map>
18 #include <algorithm>
19 #include <iostream>
20 #include "icp.h"
21 // #include <stdlib.h>
23 using namespace std;
25 //----------------------------------------------------------------
27 enum DeviceType { thermometer, thermostat };
29 struct DeviceState { // State for a device
30 DeviceType type;
31 const char * model;
32 string location;
33 short nominal_temp; // For thermostats only
35 typedef map<unsigned long, DeviceState> StateMap;
37 //----------------------------------------------------------------
39 const size_t MAXSTR = 32; // Max len of string including NUL
41 const long MIN_TEMP = 40; // 40 F == 4.44 C
42 const long MAX_TEMP = 90; // 90 F == 32.22 C
43 const long DFLT_TEMP = 68; // 68 F == 20.00 C
45 static StateMap dstate; // Map of known devices
47 //----------------------------------------------------------------
49 // ICP_online() simulates adding a new device to the network by
50 // adding it to the dstate map.
52 // For this simple simulation, devices with odd asset numbers
53 // are thermometers and devices with even asset numbers
54 // are thermostats.
56 // Thermostats get an initial nominal temperature of DFLT_TEMP.
57 // The location string is intentionally left blank because it
58 // must be programmed by the controller after putting the device
59 // on-line (as should be the nominal temperature).
61 // If a device with the specified ID is already on-line, the
62 // return value is -1. A zero return value indicates success.
64 extern "C"
65 int
66 ICP_online(unsigned long id)
68 // Look for id in state map.
69 StateMap::iterator pos = dstate.find(id);
70 if (pos != dstate.end())
71 return -1; // Already exists
73 // Fill in state.
74 DeviceState ds;
75 ds.type = (id % 2) ? thermometer : thermostat;
76 ds.model = (ds.type == thermometer)
77 ? "Sens-A-Temp" : "Select-A-Temp";
78 ds.nominal_temp = DFLT_TEMP;
80 // Insert new device into map
81 dstate[id] = ds;
83 return 0;
86 //----------------------------------------------------------------
88 // ICP_offline() simulates removing a device from the network by
89 // removing it from the dstate map. If the device isn't known, the
90 // return value is -1. A zero return value indicates success.
92 extern "C"
93 int
94 ICP_offline(unsigned long id)
96 // Look for id in state map
97 StateMap::iterator pos = dstate.find(id);
98 if (pos == dstate.end())
99 return -1; // No such device
100 dstate.erase(id);
101 return 0;
104 //----------------------------------------------------------------
106 // vary_temp() simulates the variation in actual temperature
107 // around a thermostat.The function randomly varies the
108 // temperature as a percentage of calls as follows:
110 // 3 degrees too cold: 5%
111 // 3 degrees too hot: 5%
112 // 2 degrees too cold: 10%
113 // 2 degrees too hot: 10%
114 // 1 degree too cold: 15%
115 // 1 degree too hot: 15%
116 // exact temperature: 40%
118 static
119 long
120 vary_temp(long temp)
122 long r = ACE_OS::rand() % 50;
123 long delta;
124 if (r < 5)
125 delta = 3;
126 else if (r < 15)
127 delta = 2;
128 else if (r < 30)
129 delta = 1;
130 else
131 delta = 0;
133 if (ACE_OS::rand() % 2)
134 delta = -delta;
135 return temp + delta;
139 //----------------------------------------------------------------
141 // Function object. Locates a thermostat that is in the same room
142 // as the device at position pos.
144 class ThermostatInSameRoom {
145 public:
146 ThermostatInSameRoom(
147 const StateMap::iterator & pos
148 ) : m_pos(pos) {}
149 bool operator()(
150 pair<const unsigned long, DeviceState> & p
151 ) const
153 return(
154 p.second.type == thermostat
155 && p.second.location
156 == m_pos->second.location
159 private:
160 const StateMap::iterator & m_pos;
163 //----------------------------------------------------------------
165 // actual_temp() is a helper function to determine the actual
166 // temperature returned by a particular thermometer or thermostat.
167 // The pos argument indicates the device.
169 // The function locates all thermostats that are in the same room
170 // as the device denoted by pos and computes the average of all
171 // the thermostats' nominal temperatures. (If no thermostats are
172 // in the same room as the device, the function assumes that the
173 // average of the nominal temperatures is DFLT_TEMP.)
175 // The returned temperature varies from the average as
176 // determined by vary_temp().
178 static
179 long
180 actual_temp(const StateMap::iterator & pos)
182 long sum = 0;
183 long count = 0;
184 StateMap::iterator where = std::find_if(
185 dstate.begin(), dstate.end(),
186 ThermostatInSameRoom(pos)
188 while (where != dstate.end()) {
189 count++;
190 sum += where->second.nominal_temp;
191 where = std::find_if(
192 ++where, dstate.end(),
193 ThermostatInSameRoom(pos)
196 return vary_temp(count == 0 ? DFLT_TEMP : sum / count);
199 //---------------------------------------------------------------
202 // ICP_get() returns an attribute value of the device with the
203 // given id. The attribute is named by the attr parameter. The
204 // value is copied into the buffer pointed to by the value
205 // pointer. The len parameter is the size of the passed buffer,
206 // so ICP_get can avoid overrunning the buffer.
208 // By default, thermometers report a temperature that varies
209 // somewhat around DFLT_TEMP. However, if there is another
210 // thermostat in the same room as the the thermometer, the
211 // thermometer reports a temperature that varies around that
212 // thermostat's temperature. For several thermostats that are in
213 // the same room, the thermometer reports around the average
214 // nominal temperature of all the thermostats.
216 // Attempts to read from a non-existent device or to read a
217 // non-existent attribute return -1. A return value of zero
218 // indicates success. If the supplied buffer is too short to hold
219 // a value, ICP_get() silently truncates the value and
220 // returns success.
222 extern "C"
224 ICP_get(
225 unsigned long id,
226 const char * attr,
227 void * value,
228 size_t len)
230 // Look for id in state map
231 StateMap::iterator pos = dstate.find(id);
232 if (pos == dstate.end())
233 return -1; // No such device
235 // Depending on the attribute, return the
236 // corresponding piece of state.
237 if (ACE_OS::strcmp(attr, "model") == 0) {
238 ACE_OS::strncpy((char *)value, pos->second.model, len);
239 } else if (ACE_OS::strcmp(attr, "location") == 0) {
240 ACE_OS::strncpy((char *)value, pos->second.location.c_str(), len);
241 } else if (ACE_OS::strcmp(attr, "nominal_temp") == 0) {
242 if (pos->second.type != thermostat)
243 return -1; // Must be thermostat
244 ACE_OS::memcpy(
245 value, &pos->second.nominal_temp,
246 ace_min(len, sizeof(pos->second.nominal_temp))
248 } else if (ACE_OS::strcmp(attr, "temperature") == 0) {
249 long temp = actual_temp(pos);
250 ACE_OS::memcpy(value, &temp, ace_min(len, sizeof(temp)));
251 } else if (ACE_OS::strcmp(attr, "MIN_TEMP") == 0) {
252 ACE_OS::memcpy(value, &MIN_TEMP, ace_min(len, sizeof(MIN_TEMP)));
253 } else if (ACE_OS::strcmp(attr, "MAX_TEMP") == 0) {
254 ACE_OS::memcpy(value, &MAX_TEMP, ace_min(len, sizeof(MAX_TEMP)));
255 } else {
256 return -1; // No such attribute
258 return 0; // OK
261 //----------------------------------------------------------------
263 // ICP_set() sets the the attributed specified by attr to the
264 // value specified by value for the device with ID id. Attempts to
265 // write a string longer than MAXSTR bytes (including the
266 // terminating NUL) result in silent truncation of the string.
267 // Attempts to access a non-existent device or attribute
268 // return -1. Attempts to set a nominal temperature outside the
269 // legal range also return -1. A zero return value
270 // indicates success.
272 extern "C"
274 ICP_set(unsigned long id, const char * attr, const void * value)
276 // Look for id in state map
277 StateMap::iterator pos = dstate.find(id);
278 if (pos == dstate.end())
279 return -1; // No such device
281 // Change either location or nominal temp, depending on attr.
282 if (ACE_OS::strcmp(attr, "location") == 0) {
283 pos->second.location.assign(
284 (const char *)value, MAXSTR - 1
286 } else if (ACE_OS::strcmp(attr, "nominal_temp") == 0) {
287 if (pos->second.type != thermostat)
288 return -1; // Must be thermostat
289 short temp;
290 ACE_OS::memcpy(&temp, value, sizeof(temp));
291 if (temp < MIN_TEMP || temp > MAX_TEMP)
292 return -1;
293 pos->second.nominal_temp = temp;
294 } else {
295 return -1; // No such attribute
297 return 0; // OK
300 //----------------------------------------------------------------
302 #include <fstream>
304 class ICP_Persist {
305 public:
306 ICP_Persist(const char * file);
307 ~ICP_Persist();
308 private:
309 string m_filename;
312 // Read device state from a file and initialize the dstate map.
314 ICP_Persist::
315 ICP_Persist(const char * file) : m_filename(file)
317 // Open input file, creating it if necessary.
318 std::ifstream db(m_filename.c_str(), std::ios::in|std::ios::out);//, 0666);
319 if (!db) {
320 std::cerr << "Error opening " << m_filename << std::endl;
321 ACE_OS::exit(1);
324 // Read device details, one attribute per line.
325 DeviceState ds;
326 unsigned long id;
327 while (db >> id) {
328 // Read device type and set model string accordingly.
329 int dtype;
330 db >> dtype;
331 ds.type = dtype == thermometer
332 ? thermometer : thermostat;
333 ds.model = dtype == thermometer
334 ? "Sens-A-Temp" : "Select-A-Temp";
335 char loc[MAXSTR];
336 db.get(loc[0]); // Skip newline
337 db.getline(loc, sizeof(loc)); // Read location
338 ds.location = loc;
339 if (ds.type == thermostat)
340 db >> ds.nominal_temp; // Read temperature
341 dstate[id] = ds; // Add entry to map
344 //db.close();
345 //if (!db) {
346 // cerr << "Error closing " << m_filename << endl;
347 // exit(1);
351 // Write device state to the file.
353 ICP_Persist::
354 ~ICP_Persist()
356 // Open input file, truncating it.
357 std::ofstream db(m_filename.c_str());
358 if (!db) {
359 std::cerr << "Error opening " << m_filename << std::endl;
360 ACE_OS::exit(1);
363 // Write the state details for each device.
364 StateMap::iterator i;
365 for (i = dstate.begin(); i != dstate.end(); i++) {
366 db << i->first << std::endl;
367 db << (unsigned long)(i->second.type) << std::endl;
368 db << i->second.location << std::endl;
369 if (i->second.type == thermostat)
370 db << i->second.nominal_temp << std::endl;
372 if (!db) {
373 std::cerr << "Error writing " << m_filename << std::endl;
374 ACE_OS::exit(1);
377 db.close();
378 if (!db) {
379 std::cerr << "Error closing " << m_filename << std::endl;
380 ACE_OS::exit(1);
384 // Instantiate a single global instance of the class.
385 static ICP_Persist mydb("/tmp/CCS_DB");