2 //=============================================================================
6 * @author Source code used in TAO has been modified and adapted from thecode provided in the book
7 * @author "Advanced CORBA Programming with C++"by Michi Henning and Steve Vinoski. Copyright1999. Addison-Wesley
9 * @author MA. Used with permission ofAddison-Wesley.Modified for TAO by Mike Moran <mm4@cs.wustl.edu>
11 //=============================================================================
22 // The following header is #included automatically by ACE+TAO.
23 // Therefore, they don't need to be included explicitly.
26 enum DeviceType
{ thermometer
, thermostat
};
29 { // State for a device
33 short nominal_temp
; // For thermostats only
36 typedef map
<unsigned long, DeviceState
> StateMap
;
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 // ICP_online () simulates adding a new device to the network by
47 // adding it to the dstate map.
49 // For this simple simulation, devices with odd asset numbers
50 // are thermometers and devices with even asset numbers
53 // Thermostats get an initial nominal temperature of DFLT_TEMP.
54 // The location string is intentionally left blank because it
55 // must be programmed by the controller after putting the device
56 // on-line (as should be the nominal temperature).
58 // If a device with the specified ID is already on-line, the
59 // return value is -1. A zero return value indicates success.
63 ICP_online (unsigned long id
)
65 // Look for id in state map.
66 StateMap::iterator pos
= dstate
.find (id
);
67 if (pos
!= dstate
.end ())
68 return -1; // Already exists
72 ds
.type
= (id
% 2) ? thermometer
: thermostat
;
73 ds
.model
= (ds
.type
== thermometer
)
74 ? "Sens-A-Temp" : "Select-A-Temp";
75 ds
.nominal_temp
= DFLT_TEMP
;
77 // Insert new device into map
83 // ICP_offline () simulates removing a device from the network by
84 // removing it from the dstate map. If the device isn't known, the
85 // return value is -1. A zero return value indicates success.
89 ICP_offline (unsigned long id
)
91 // Look for id in state map
92 StateMap::iterator pos
= dstate
.find (id
);
94 if (pos
== dstate
.end ())
95 return -1; // No such device
100 // vary_temp () simulates the variation in actual temperature around a
101 // thermostat.The function randomly varies the temperature as a
102 // percentage of calls as follows:
104 // 3 degrees too cold: 5%
105 // 3 degrees too hot: 5%
106 // 2 degrees too cold: 10%
107 // 2 degrees too hot: 10%
108 // 1 degree too cold: 15%
109 // 1 degree too hot: 15%
110 // exact temperature: 40%
114 vary_temp (long temp
)
116 long r
= ACE_OS::rand() % 50;
127 if (ACE_OS::rand() % 2)
132 // Function object. Locates a thermostat that is in the same room as
133 // the device at position pos.
135 class ThermostatInSameRoom
138 ThermostatInSameRoom (const StateMap::iterator
&pos
):
140 bool operator () (pair
<const unsigned long, DeviceState
> &p
) const
142 return p
.second
.type
== thermostat
143 && p
.second
.location
== m_pos
->second
.location
;
146 const StateMap::iterator
& m_pos
;
149 // actual_temp () is a helper function to determine the actual
150 // temperature returned by a particular thermometer or thermostat.
151 // The pos argument indicates the device.
153 // The function locates all thermostats that are in the same room
154 // as the device denoted by pos and computes the average of all
155 // the thermostats' nominal temperatures. (If no thermostats are
156 // in the same room as the device, the function assumes that the
157 // average of the nominal temperatures is DFLT_TEMP.)
159 // The returned temperature varies from the average as
160 // determined by vary_temp ().
164 actual_temp (const StateMap::iterator
& pos
)
168 StateMap::iterator where
= std::find_if (dstate
.begin (), dstate
.end (),
169 ThermostatInSameRoom (pos
));
170 while (where
!= dstate
.end ())
173 sum
+= where
->second
.nominal_temp
;
174 where
= std::find_if (++where
, dstate
.end (),
175 ThermostatInSameRoom (pos
));
178 return vary_temp (count
== 0 ? DFLT_TEMP
: sum
/ count
);
181 //---------------------------------------------------------------
183 // ICP_get () returns an attribute value of the device with the given
184 // id. The attribute is named by the attr parameter. The value is
185 // copied into the buffer pointed to by the value pointer. The len
186 // parameter is the size of the passed buffer, so ICP_get can avoid
187 // overrunning the buffer.
189 // By default, thermometers report a temperature that varies somewhat
190 // around DFLT_TEMP. However, if there is another thermostat in the
191 // same room as the the thermometer, the thermometer reports a
192 // temperature that varies around that thermostat's temperature. For
193 // several thermostats that are in the same room, the thermometer
194 // reports around the average nominal temperature of all the
197 // Attempts to read from a non-existent device or to read a
198 // non-existent attribute return -1. A return value of zero indicates
199 // success. If the supplied buffer is too short to hold a value,
200 // ICP_get () silently truncates the value and returns success.
204 ICP_get (unsigned long id
,
209 // Look for id in state map
210 StateMap::iterator pos
= dstate
.find (id
);
211 if (pos
== dstate
.end ())
212 return -1; // No such device
214 // Depending on the attribute, return the
215 // corresponding piece of state.
216 if (ACE_OS::strcmp (attr
, "model") == 0)
218 ACE_OS::strncpy ( (char *)value
, pos
->second
.model
, len
);
220 else if (ACE_OS::strcmp (attr
, "location") == 0)
222 ACE_OS::strncpy ( (char *)value
, pos
->second
.location
.c_str (), len
);
224 else if (ACE_OS::strcmp (attr
, "nominal_temp") == 0)
226 if (pos
->second
.type
!= thermostat
)
227 return -1; // Must be thermostat
228 ACE_OS::memcpy (value
, &pos
->second
.nominal_temp
,
229 ace_min (len
, sizeof (pos
->second
.nominal_temp
)));
231 else if (ACE_OS::strcmp (attr
, "temperature") == 0)
233 long temp
= actual_temp (pos
);
234 ACE_OS::memcpy (value
, &temp
, ace_min (len
, sizeof (temp
)));
236 else if (ACE_OS::strcmp (attr
, "MIN_TEMP") == 0)
238 ACE_OS::memcpy (value
, &MIN_TEMP
, ace_min (len
, sizeof (MIN_TEMP
)));
240 else if (ACE_OS::strcmp (attr
, "MAX_TEMP") == 0)
242 ACE_OS::memcpy (value
, &MAX_TEMP
, ace_min (len
, sizeof (MAX_TEMP
)));
246 return -1; // No such attribute
251 // ICP_set () sets the the attributed specified by attr to the value
252 // specified by value for the device with ID id. Attempts to write a
253 // string longer than MAXSTR bytes (including the terminating NUL)
254 // result in silent truncation of the string. Attempts to access a
255 // non-existent device or attribute return -1. Attempts to set a
256 // nominal temperature outside the legal range also return -1. A zero
257 // return value indicates success.
261 ICP_set (unsigned long id
, const char * attr
, const void * value
)
263 // Look for id in state map
264 StateMap::iterator pos
= dstate
.find (id
);
265 if (pos
== dstate
.end ())
266 return -1; // No such device
268 // Change either location or nominal temp, depending on attr.
269 if (ACE_OS::strcmp (attr
, "location") == 0)
271 pos
->second
.location
.assign ((const char *)value
, MAXSTR
- 1);
273 else if (ACE_OS::strcmp (attr
, "nominal_temp") == 0)
275 if (pos
->second
.type
!= thermostat
)
276 return -1; // Must be thermostat
278 ACE_OS::memcpy (&temp
, value
, sizeof (temp
));
279 if (temp
< MIN_TEMP
|| temp
> MAX_TEMP
)
281 pos
->second
.nominal_temp
= temp
;
285 return -1; // No such attribute
295 ICP_Persist (const char *file
);
301 // Read device state from a file and initialize the dstate map.
304 ICP_Persist (const char *file
)
307 // Open input file, creating it if necessary.
308 std::ifstream
db (m_filename
.c_str (), std::ios::in
|std::ios::out
);//, 0666);
311 std::cerr
<< "Error opening " << m_filename
<< std::endl
;
315 // Read device details, one attribute per line.
320 // Read device type and set model string accordingly.
323 ds
.type
= dtype
== thermometer
324 ? thermometer
: thermostat
;
325 ds
.model
= dtype
== thermometer
326 ? "Sens-A-Temp" : "Select-A-Temp";
328 db
.get (loc
[0]); // Skip newline
329 db
.getline (loc
, sizeof (loc
)); // Read location
331 if (ds
.type
== thermostat
)
332 db
>> ds
.nominal_temp
; // Read temperature
333 dstate
[id
] = ds
; // Add entry to map
338 // cerr << "Error closing " << m_filename << endl;
343 // Write device state to the file.
348 std::cout
<<"~ICP_Persist"<<std::endl
;///////////////////////
349 // Open input file, truncating it.
350 ofstream
db (m_filename
.c_str ());
353 std::cerr
<< "Error opening " << m_filename
<< std::endl
;
357 // Write the state details for each device.
358 StateMap::iterator i
;
359 for (i
= dstate
.begin (); i
!= dstate
.end (); i
++)
361 db
<< i
->first
<< std::endl
;
362 db
<< (unsigned long) (i
->second
.type
) << std::endl
;
363 db
<< i
->second
.location
<< std::endl
;
364 if (i
->second
.type
== thermostat
)
365 db
<< i
->second
.nominal_temp
<< std::endl
;
369 std::cerr
<< "Error writing " << m_filename
<< std::endl
;
376 std::cerr
<< "Error closing " << m_filename
<< std::endl
;
381 // Instantiate a single global instance of the class.
382 static ICP_Persist
mydb ("/tmp/CCS_DB");