Changes to attempt to silence bcc64x
[ACE_TAO.git] / TAO / examples / Advanced / ch_18 / icp.cpp
blob7f22eb1e08496e467fdf3147dd3e68e5eebfb8fb
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 //=============================================================================
15 #include <string>
16 #include <map>
17 #include <algorithm>
18 #include <iostream>
19 #include "icp.h"
20 // #include <stdlib.h>
22 using namespace std;
24 //----------------------------------------------------------------
26 enum DeviceType { thermometer, thermostat };
28 struct DeviceState { // State for a device
29 DeviceType type;
30 const char * model;
31 string location;
32 short nominal_temp; // For thermostats only
34 typedef map<unsigned long, DeviceState> StateMap;
36 //----------------------------------------------------------------
38 const size_t MAXSTR = 32; // Max len of string including NUL
40 const long MIN_TEMP = 40; // 40 F == 4.44 C
41 const long MAX_TEMP = 90; // 90 F == 32.22 C
42 const long DFLT_TEMP = 68; // 68 F == 20.00 C
44 static StateMap dstate; // Map of known devices
46 //----------------------------------------------------------------
48 // ICP_online() simulates adding a new device to the network by
49 // adding it to the dstate map.
51 // For this simple simulation, devices with odd asset numbers
52 // are thermometers and devices with even asset numbers
53 // are thermostats.
55 // Thermostats get an initial nominal temperature of DFLT_TEMP.
56 // The location string is intentionally left blank because it
57 // must be programmed by the controller after putting the device
58 // on-line (as should be the nominal temperature).
60 // If a device with the specified ID is already on-line, the
61 // return value is -1. A zero return value indicates success.
63 extern "C"
64 int
65 ICP_online(unsigned long id)
67 // Look for id in state map.
68 StateMap::iterator pos = dstate.find(id);
69 if (pos != dstate.end())
70 return -1; // Already exists
72 // Fill in state.
73 DeviceState ds;
74 ds.type = (id % 2) ? thermometer : thermostat;
75 ds.model = (ds.type == thermometer)
76 ? "Sens-A-Temp" : "Select-A-Temp";
77 ds.nominal_temp = DFLT_TEMP;
79 // Insert new device into map
80 dstate[id] = ds;
82 return 0;
85 //----------------------------------------------------------------
87 // ICP_offline() simulates removing a device from the network by
88 // removing it from the dstate map. If the device isn't known, the
89 // return value is -1. A zero return value indicates success.
91 extern "C"
92 int
93 ICP_offline(unsigned long id)
95 // Look for id in state map
96 StateMap::iterator pos = dstate.find(id);
97 if (pos == dstate.end())
98 return -1; // No such device
99 dstate.erase(id);
100 return 0;
103 //----------------------------------------------------------------
105 // vary_temp() simulates the variation in actual temperature
106 // around a thermostat.The function randomly varies the
107 // temperature as a percentage of calls as follows:
109 // 3 degrees too cold: 5%
110 // 3 degrees too hot: 5%
111 // 2 degrees too cold: 10%
112 // 2 degrees too hot: 10%
113 // 1 degree too cold: 15%
114 // 1 degree too hot: 15%
115 // exact temperature: 40%
117 static
118 long
119 vary_temp(long temp)
121 long r = ACE_OS::rand() % 50;
122 long delta;
123 if (r < 5)
124 delta = 3;
125 else if (r < 15)
126 delta = 2;
127 else if (r < 30)
128 delta = 1;
129 else
130 delta = 0;
132 if (ACE_OS::rand() % 2)
133 delta = -delta;
134 return temp + delta;
137 //----------------------------------------------------------------
139 // Function object. Locates a thermostat that is in the same room
140 // as the device at position pos.
142 class ThermostatInSameRoom {
143 public:
144 ThermostatInSameRoom(
145 const StateMap::iterator & pos
146 ) : m_pos(pos) {}
147 bool operator()(
148 pair<const unsigned long, DeviceState> & p) const
150 return(
151 p.second.type == thermostat
152 && p.second.location
153 == m_pos->second.location
156 private:
157 const StateMap::iterator & m_pos;
160 //----------------------------------------------------------------
162 // actual_temp() is a helper function to determine the actual
163 // temperature returned by a particular thermometer or thermostat.
164 // The pos argument indicates the device.
166 // The function locates all thermostats that are in the same room
167 // as the device denoted by pos and computes the average of all
168 // the thermostats' nominal temperatures. (If no thermostats are
169 // in the same room as the device, the function assumes that the
170 // average of the nominal temperatures is DFLT_TEMP.)
172 // The returned temperature varies from the average as
173 // determined by vary_temp().
175 static
176 long
177 actual_temp(const StateMap::iterator & pos)
179 long sum = 0;
180 long count = 0;
181 StateMap::iterator where = std::find_if(
182 dstate.begin(), dstate.end(),
183 ThermostatInSameRoom(pos)
185 while (where != dstate.end()) {
186 count++;
187 sum += where->second.nominal_temp;
188 where = std::find_if(
189 ++where, dstate.end(),
190 ThermostatInSameRoom(pos)
193 return vary_temp(count == 0 ? DFLT_TEMP : sum / count);
196 //---------------------------------------------------------------
199 // ICP_get() returns an attribute value of the device with the
200 // given id. The attribute is named by the attr parameter. The
201 // value is copied into the buffer pointed to by the value
202 // pointer. The len parameter is the size of the passed buffer,
203 // so ICP_get can avoid overrunning the buffer.
205 // By default, thermometers report a temperature that varies
206 // somewhat around DFLT_TEMP. However, if there is another
207 // thermostat in the same room as the the thermometer, the
208 // thermometer reports a temperature that varies around that
209 // thermostat's temperature. For several thermostats that are in
210 // the same room, the thermometer reports around the average
211 // nominal temperature of all the thermostats.
213 // Attempts to read from a non-existent device or to read a
214 // non-existent attribute return -1. A return value of zero
215 // indicates success. If the supplied buffer is too short to hold
216 // a value, ICP_get() silently truncates the value and
217 // returns success.
219 extern "C"
221 ICP_get(
222 unsigned long id,
223 const char * attr,
224 void * value,
225 size_t len)
227 // Look for id in state map
228 StateMap::iterator pos = dstate.find(id);
229 if (pos == dstate.end())
230 return -1; // No such device
232 // Depending on the attribute, return the
233 // corresponding piece of state.
234 if (ACE_OS::strcmp(attr, "model") == 0) {
235 ACE_OS::strncpy((char *)value, pos->second.model, len);
236 } else if (ACE_OS::strcmp(attr, "location") == 0) {
237 ACE_OS::strncpy((char *)value, pos->second.location.c_str(), len);
238 } else if (ACE_OS::strcmp(attr, "nominal_temp") == 0) {
239 if (pos->second.type != thermostat)
240 return -1; // Must be thermostat
241 ACE_OS::memcpy(
242 value, &pos->second.nominal_temp,
243 ace_min(len, sizeof(pos->second.nominal_temp))
245 } else if (ACE_OS::strcmp(attr, "temperature") == 0) {
246 long temp = actual_temp(pos);
247 ACE_OS::memcpy(value, &temp, ace_min(len, sizeof(temp)));
248 } else if (ACE_OS::strcmp(attr, "MIN_TEMP") == 0) {
249 ACE_OS::memcpy(value, &MIN_TEMP, ace_min(len, sizeof(MIN_TEMP)));
250 } else if (ACE_OS::strcmp(attr, "MAX_TEMP") == 0) {
251 ACE_OS::memcpy(value, &MAX_TEMP, ace_min(len, sizeof(MAX_TEMP)));
252 } else {
253 return -1; // No such attribute
255 return 0; // OK
258 //----------------------------------------------------------------
260 // ICP_set() sets the the attributed specified by attr to the
261 // value specified by value for the device with ID id. Attempts to
262 // write a string longer than MAXSTR bytes (including the
263 // terminating NUL) result in silent truncation of the string.
264 // Attempts to access a non-existent device or attribute
265 // return -1. Attempts to set a nominal temperature outside the
266 // legal range also return -1. A zero return value
267 // indicates success.
269 extern "C"
271 ICP_set(unsigned long id, const char * attr, const void * value)
273 // Look for id in state map
274 StateMap::iterator pos = dstate.find(id);
275 if (pos == dstate.end())
276 return -1; // No such device
278 // Change either location or nominal temp, depending on attr.
279 if (ACE_OS::strcmp(attr, "location") == 0) {
280 pos->second.location.assign(
281 (const char *)value, MAXSTR - 1
283 } else if (ACE_OS::strcmp(attr, "nominal_temp") == 0) {
284 if (pos->second.type != thermostat)
285 return -1; // Must be thermostat
286 short temp;
287 ACE_OS::memcpy(&temp, value, sizeof(temp));
288 if (temp < MIN_TEMP || temp > MAX_TEMP)
289 return -1;
290 pos->second.nominal_temp = temp;
291 } else {
292 return -1; // No such attribute
294 return 0; // OK
297 //----------------------------------------------------------------
299 #include <fstream>
301 class ICP_Persist {
302 public:
303 ICP_Persist(const char * file);
304 ~ICP_Persist();
305 private:
306 string m_filename;
309 // Read device state from a file and initialize the dstate map.
311 ICP_Persist::
312 ICP_Persist(const char * file) : m_filename(file)
314 // Open input file, creating it if necessary.
315 std::ifstream db(m_filename.c_str(), std::ios::in|std::ios::out);//, 0666);
316 if (!db) {
317 std::cerr << "Error opening " << m_filename << std::endl;
318 ACE_OS::exit(1);
321 // Read device details, one attribute per line.
322 DeviceState ds;
323 unsigned long id;
324 while (db >> id) {
325 // Read device type and set model string accordingly.
326 int dtype;
327 db >> dtype;
328 ds.type = dtype == thermometer
329 ? thermometer : thermostat;
330 ds.model = dtype == thermometer
331 ? "Sens-A-Temp" : "Select-A-Temp";
332 char loc[MAXSTR];
333 db.get(loc[0]); // Skip newline
334 db.getline(loc, sizeof(loc)); // Read location
335 ds.location = loc;
336 if (ds.type == thermostat)
337 db >> ds.nominal_temp; // Read temperature
338 dstate[id] = ds; // Add entry to map
341 //db.close();
342 //if (!db) {
343 // cerr << "Error closing " << m_filename << endl;
344 // exit(1);
348 // Write device state to the file.
350 ICP_Persist::
351 ~ICP_Persist()
353 // Open input file, truncating it.
354 std::ofstream db(m_filename.c_str());
355 if (!db) {
356 std::cerr << "Error opening " << m_filename << std::endl;
357 ACE_OS::exit(1);
360 // Write the state details for each device.
361 StateMap::iterator i;
362 for (i = dstate.begin(); i != dstate.end(); i++) {
363 db << i->first << std::endl;
364 db << (unsigned long)(i->second.type) << std::endl;
365 db << i->second.location << std::endl;
366 if (i->second.type == thermostat)
367 db << i->second.nominal_temp << std::endl;
369 if (!db) {
370 std::cerr << "Error writing " << m_filename << std::endl;
371 ACE_OS::exit(1);
374 db.close();
375 if (!db) {
376 std::cerr << "Error closing " << m_filename << std::endl;
377 ACE_OS::exit(1);
381 // Instantiate a single global instance of the class.
382 static ICP_Persist mydb("/tmp/CCS_DB");