Merge pull request #1844 from jrw972/monterey
[ACE_TAO.git] / TAO / examples / Advanced / ch_21 / icp.cpp
blob892857db7b0f47fc34a4a268b45587bf01e554d8
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 <stdlib.h>
20 #include <iostream>
21 #include "icp.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 short MIN_TEMP = 40; // 40 F == 4.44 C
42 const short MAX_TEMP = 90; // 90 F == 32.22 C
43 const short 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 on-line already, 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;
132 if (ACE_OS::rand() % 2)
133 delta = -delta;
134 return temp + delta;
138 //----------------------------------------------------------------
140 // Function object. Locates a thermostat that is in the same room
141 // as the device at position pos.
143 class ThermostatInSameRoom {
144 public:
145 ThermostatInSameRoom(
146 const StateMap::iterator & pos
147 ) : m_pos(pos) {}
148 bool operator()(
149 pair<const unsigned long, DeviceState> & p
150 ) const
152 return(
153 p.second.type == thermostat
154 && p.second.location
155 == m_pos->second.location
158 private:
159 const StateMap::iterator & m_pos;
162 //----------------------------------------------------------------
164 // actual_temp() is a helper function to determine the actual
165 // temperature returned by a particular thermometer or thermostat.
166 // The pos argument indicates the device.
168 // The function locates all thermostats that are in the same room
169 // as the device denoted by pos and computes the average of all
170 // the thermostats' nominal temperatures. (If no thermostats are
171 // in the same room as the device, the function assumes that the
172 // average of the nominal temperatures is DFLT_TEMP.)
174 // The returned temperature varies from the average as
175 // determined by vary_temp().
177 static
178 long
179 actual_temp(const StateMap::iterator & pos)
181 long sum = 0;
182 long count = 0;
183 StateMap::iterator where = std::find_if(
184 dstate.begin(), dstate.end(),
185 ThermostatInSameRoom(pos)
187 while (where != dstate.end()) {
188 count++;
189 sum += where->second.nominal_temp;
190 where = std::find_if(
191 ++where, dstate.end(),
192 ThermostatInSameRoom(pos)
195 return vary_temp(count == 0 ? DFLT_TEMP : sum / count);
198 //---------------------------------------------------------------
200 // ICP_get() returns an attribute value of the device with the
201 // given id. The attribute is named by the attr parameter. The
202 // value is copied into the buffer pointed to by the value
203 // pointer. The len parameter is the size of the passed buffer,
204 // so ICP_get can avoid overrunning the buffer.
206 // By default, thermometers report a temperature that varies
207 // somewhat around DFLT_TEMP. However, if there is another
208 // thermostat in the same room as the the thermometer, the
209 // thermometer reports a temperature that varies around that
210 // thermostat's temperature. For several thermostats that are in
211 // the same room, the thermometer reports around the average
212 // nominal temperature of all the thermostats.
214 // Attempts to read from a non-existent device or to read a
215 // non-existent attribute return -1. A return value of zero
216 // indicates success. If the supplied buffer is too short to hold
217 // a value, ICP_get() silently truncates the value and
218 // returns success.
220 extern "C"
222 ICP_get(
223 unsigned long id,
224 const char * attr,
225 void * value,
226 size_t len)
228 // Look for id in state map
229 StateMap::iterator pos = dstate.find(id);
230 if (pos == dstate.end())
231 return -1; // No such device
233 // Depending on the attribute, return the
234 // corresponding piece of state.
235 if (ACE_OS::strcmp(attr, "model") == 0) {
236 ACE_OS::strncpy((char *)value, pos->second.model, len);
237 } else if (ACE_OS::strcmp(attr, "location") == 0) {
238 ACE_OS::strncpy((char *)value, pos->second.location.c_str(), len);
239 } else if (ACE_OS::strcmp(attr, "nominal_temp") == 0) {
240 if (pos->second.type != thermostat)
241 return -1; // Must be thermostat
242 ACE_OS::memcpy(
243 value, &pos->second.nominal_temp,
244 ace_min(len, sizeof(pos->second.nominal_temp))
246 } else if (ACE_OS::strcmp(attr, "temperature") == 0) {
247 long temp = actual_temp(pos);
248 ACE_OS::memcpy(value, &temp, ace_min(len, sizeof(temp)));
249 } else if (ACE_OS::strcmp(attr, "MIN_TEMP") == 0) {
250 ACE_OS::memcpy(value, &MIN_TEMP, ace_min(len, sizeof(MIN_TEMP)));
251 } else if (ACE_OS::strcmp(attr, "MAX_TEMP") == 0) {
252 ACE_OS::memcpy(value, &MAX_TEMP, ace_min(len, sizeof(MAX_TEMP)));
253 } else {
254 return -1; // No such attribute
256 return 0; // OK
259 //----------------------------------------------------------------
261 // ICP_set() sets the the attributed specified by attr to the
262 // value specified by value for the device with ID id. Attempts to
263 // write a string longer than MAXSTR bytes (including the
264 // terminating NUL) result in silent truncation of the string.
265 // Attempts to access a non-existent device or attribute
266 // return -1. Attempts to set a nominal temperature outside the
267 // legal range also return -1. A zero return value
268 // indicates success.
270 extern "C"
272 ICP_set(unsigned long id, const char * attr, const void * value)
274 // Look for id in state map
275 StateMap::iterator pos = dstate.find(id);
276 if (pos == dstate.end())
277 return -1; // No such device
279 // Change either location or nominal temp, depending on attr.
280 if (ACE_OS::strcmp(attr, "location") == 0) {
281 pos->second.location.assign(
282 (const char *)value, MAXSTR - 1
284 } else if (ACE_OS::strcmp(attr, "nominal_temp") == 0) {
285 if (pos->second.type != thermostat)
286 return -1; // Must be thermostat
287 short temp;
288 ACE_OS::memcpy(&temp, value, sizeof(temp));
289 if (temp < MIN_TEMP || temp > MAX_TEMP)
290 return -1;
291 pos->second.nominal_temp = temp;
292 } else {
293 return -1; // No such attribute
295 return 0; // OK
298 //----------------------------------------------------------------
300 #include <fstream>
302 class ICP_Persist {
303 public:
304 ICP_Persist(const char * file);
305 ~ICP_Persist();
306 private:
307 string m_filename;
310 // Read device state from a file and initialize the dstate map.
312 ICP_Persist::
313 ICP_Persist(const char * file) : m_filename(file)
315 // Open input file, creating it if necessary.
316 std::ifstream db(m_filename.c_str(), std::ios::in|std::ios::out);//, 0666);
317 if (!db) {
318 std::cerr << "Error opening " << m_filename << std::endl;
319 ACE_OS::exit(1);
322 // Read device details, one attribute per line.
323 DeviceState ds;
324 unsigned long id;
325 while (db >> id) {
326 // Read device type and set model string accordingly.
327 int dtype;
328 db >> dtype;
329 ds.type = dtype == thermometer
330 ? thermometer : thermostat;
331 ds.model = dtype == thermometer
332 ? "Sens-A-Temp" : "Select-A-Temp";
333 char loc[MAXSTR];
334 db.get(loc[0]); // Skip newline
335 db.getline(loc, sizeof(loc)); // Read location
336 ds.location = loc;
337 if (ds.type == thermostat)
338 db >> ds.nominal_temp; // Read temperature
339 dstate[id] = ds; // Add entry to map
342 // db.close();
343 // if (!db) {
344 // cerr << "Error closing " << m_filename << endl;
345 // ACE_OS::exit(1);
346 // }
349 // Write device state to the file.
351 ICP_Persist::
352 ~ICP_Persist()
354 // Open input file, truncating it.
355 std::ofstream db(m_filename.c_str());
356 if (!db) {
357 std::cerr << "Error opening " << m_filename << std::endl;
358 ACE_OS::exit(1);
361 // Write the state details for each device.
362 StateMap::iterator i;
363 for (i = dstate.begin(); i != dstate.end(); i++) {
364 db << i->first << std::endl;
365 db << (unsigned long)(i->second.type) << std::endl;
366 db << i->second.location << std::endl;
367 if (i->second.type == thermostat)
368 db << i->second.nominal_temp << std::endl;
370 if (!db) {
371 std::cerr << "Error writing " << m_filename << std::endl;
372 ACE_OS::exit(1);
375 // db.close();
376 // if (!db) {
377 // cerr << "Error closing " << m_filename << endl;
378 // exit(1);
379 // }
382 // Instantiate a single global instance of the class.
383 static ICP_Persist mydb("/tmp/CCS_DB");