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 //=============================================================================
24 //----------------------------------------------------------------
26 enum DeviceType
{ thermometer
, thermostat
};
28 struct DeviceState
{ // State for a device
32 short nominal_temp
; // For thermostats only
34 typedef std::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
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.
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
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
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.
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
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%
121 long r
= ACE_OS::rand() % 50;
131 if (ACE_OS::rand() % 2)
136 //----------------------------------------------------------------
138 // Function object. Locates a thermostat that is in the same room
139 // as the device at position pos.
141 class ThermostatInSameRoom
{
143 ThermostatInSameRoom(
144 const StateMap::iterator
& pos
147 pair
<const unsigned long, DeviceState
> & p
151 p
.second
.type
== thermostat
153 == m_pos
->second
.location
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().
177 actual_temp(const StateMap::iterator
& pos
)
181 StateMap::iterator where
= std::find_if(
182 dstate
.begin(), dstate
.end(),
183 ThermostatInSameRoom(pos
)
185 while (where
!= dstate
.end()) {
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 //---------------------------------------------------------------
198 // ICP_get() returns an attribute value of the device with the
199 // given id. The attribute is named by the attr parameter. The
200 // value is copied into the buffer pointed to by the value
201 // pointer. The len parameter is the size of the passed buffer,
202 // so ICP_get can avoid overrunning the buffer.
204 // By default, thermometers report a temperature that varies
205 // somewhat around DFLT_TEMP. However, if there is another
206 // thermostat in the same room as the thermometer, the
207 // thermometer reports a temperature that varies around that
208 // thermostat's temperature. For several thermostats that are in
209 // the same room, the thermometer reports a temperature that
210 // varies around the average nominal temperature of all the
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
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
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
)));
253 return -1; // No such attribute
258 //----------------------------------------------------------------
260 // ICP_set() sets the attribute 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.
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
287 ACE_OS::memcpy(&temp
, value
, sizeof(temp
));
288 if (temp
< MIN_TEMP
|| temp
> MAX_TEMP
)
290 pos
->second
.nominal_temp
= temp
;
292 return -1; // No such attribute