1 //=============================================================================
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
8 * @author MA.Modified for TAO by Mike Moran <mm4@cs.wustl.edu>
10 //=============================================================================
21 // #include <stdlib.h>
25 //----------------------------------------------------------------
27 enum DeviceType
{ thermometer
, thermostat
};
29 struct DeviceState
{ // State for a device
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
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.
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
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
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.
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
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%
122 long r
= ACE_OS::rand() % 50;
133 if (ACE_OS::rand() % 2)
139 //----------------------------------------------------------------
141 // Function object. Locates a thermostat that is in the same room
142 // as the device at position pos.
144 class ThermostatInSameRoom
{
146 ThermostatInSameRoom(
147 const StateMap::iterator
& pos
150 pair
<const unsigned long, DeviceState
> & p
154 p
.second
.type
== thermostat
156 == m_pos
->second
.location
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().
180 actual_temp(const StateMap::iterator
& pos
)
184 StateMap::iterator where
= std::find_if(
185 dstate
.begin(), dstate
.end(),
186 ThermostatInSameRoom(pos
)
188 while (where
!= dstate
.end()) {
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
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
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
)));
256 return -1; // No such attribute
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.
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
290 ACE_OS::memcpy(&temp
, value
, sizeof(temp
));
291 if (temp
< MIN_TEMP
|| temp
> MAX_TEMP
)
293 pos
->second
.nominal_temp
= temp
;
295 return -1; // No such attribute
300 //----------------------------------------------------------------
306 ICP_Persist(const char * file
);
312 // Read device state from a file and initialize the dstate map.
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);
320 std::cerr
<< "Error opening " << m_filename
<< std::endl
;
324 // Read device details, one attribute per line.
328 // Read device type and set model string accordingly.
331 ds
.type
= dtype
== thermometer
332 ? thermometer
: thermostat
;
333 ds
.model
= dtype
== thermometer
334 ? "Sens-A-Temp" : "Select-A-Temp";
336 db
.get(loc
[0]); // Skip newline
337 db
.getline(loc
, sizeof(loc
)); // Read location
339 if (ds
.type
== thermostat
)
340 db
>> ds
.nominal_temp
; // Read temperature
341 dstate
[id
] = ds
; // Add entry to map
346 // cerr << "Error closing " << m_filename << endl;
351 // Write device state to the file.
356 // Open input file, truncating it.
357 std::ofstream
db(m_filename
.c_str());
359 std::cerr
<< "Error opening " << m_filename
<< std::endl
;
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
;
373 std::cerr
<< "Error writing " << m_filename
<< std::endl
;
379 std::cerr
<< "Error closing " << m_filename
<< std::endl
;
384 // Instantiate a single global instance of the class.
385 static ICP_Persist
mydb("/tmp/CCS_DB");