summaryrefslogtreecommitdiff
path: root/TAO/examples/Advanced/ch_8_and_10/icp.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'TAO/examples/Advanced/ch_8_and_10/icp.cpp')
-rw-r--r--TAO/examples/Advanced/ch_8_and_10/icp.cpp310
1 files changed, 310 insertions, 0 deletions
diff --git a/TAO/examples/Advanced/ch_8_and_10/icp.cpp b/TAO/examples/Advanced/ch_8_and_10/icp.cpp
new file mode 100644
index 00000000000..5922fef8674
--- /dev/null
+++ b/TAO/examples/Advanced/ch_8_and_10/icp.cpp
@@ -0,0 +1,310 @@
+// $Id$
+// ============================================================================
+//
+// = LIBRARY
+// TAO/examples/Advanced/ch_8_and_10
+//
+// = FILENAME
+// icp.cpp
+//
+// = AUTHORS
+// Source code used in TAO has been modified and adapted from the code
+// provided in the book, "Advanced CORBA Programming with C++" by Michi
+// Henning and Steve Vinoski. Copyright 1999. Addison-Wesley, Reading,
+// MA.
+//
+// Modified for TAO by Mike Moran <mm4@cs.wustl.edu>
+//
+// ============================================================================
+
+
+
+
+#include <string>
+#include <map>
+#include <algorithm>
+//#include <stdlib.h>
+#include "icp.h"
+
+using namespace std;
+
+//----------------------------------------------------------------
+
+enum DeviceType { thermometer, thermostat };
+
+struct DeviceState { // State for a device
+ DeviceType type;
+ const char * model;
+ string location;
+ short nominal_temp; // For thermostats only
+};
+typedef std::map<unsigned long, DeviceState> StateMap;
+
+//----------------------------------------------------------------
+
+const size_t MAXSTR = 32; // Max len of string including NUL
+
+const short MIN_TEMP = 40; // 40 F == 4.44 C
+const short MAX_TEMP = 90; // 90 F == 32.22 C
+const short DFLT_TEMP = 68; // 68 F == 20.00 C
+
+static StateMap dstate; // Map of known devices
+
+//----------------------------------------------------------------
+
+// ICP_online() simulates adding a new device to the network by
+// adding it to the dstate map.
+//
+// For this simple simulation, devices with odd asset numbers
+// are thermometers and devices with even asset numbers
+// are thermostats.
+//
+// Thermostats get an initial nominal temperature of DFLT_TEMP.
+// The location string is intentionally left blank because it
+// must be programmed by the controller after putting the device
+// on-line (as should be the nominal temperature).
+//
+// If a device with the specified ID is already on-line, the
+// return value is -1. A zero return value indicates success.
+
+extern "C"
+int
+ICP_online(unsigned long id)
+{
+ // Look for id in state map.
+ StateMap::iterator pos = dstate.find(id);
+ if (pos != dstate.end())
+ return -1; // Already exists
+
+ // Fill in state.
+ DeviceState ds;
+ ds.type = (id % 2) ? thermometer : thermostat;
+ ds.model = (ds.type == thermometer)
+ ? "Sens-A-Temp" : "Select-A-Temp";
+ ds.nominal_temp = DFLT_TEMP;
+
+ // Insert new device into map
+ dstate[id] = ds;
+
+ return 0;
+}
+
+//----------------------------------------------------------------
+
+// ICP_offline() simulates removing a device from the network by
+// removing it from the dstate map. If the device isn't known, the
+// return value is -1. A zero return value indicates success.
+
+extern "C"
+int
+ICP_offline(unsigned long id)
+{
+ // Look for id in state map
+ StateMap::iterator pos = dstate.find(id);
+ if (pos == dstate.end())
+ return -1; // No such device
+ dstate.erase(id);
+ return 0;
+}
+
+//----------------------------------------------------------------
+
+// vary_temp() simulates the variation in actual temperature
+// around a thermostat. The function randomly varies the
+// temperature as a percentage of calls as follows:
+//
+// 3 degrees too cold: 5%
+// 3 degrees too hot: 5%
+// 2 degrees too cold: 10%
+// 2 degrees too hot: 10%
+// 1 degree too cold: 15%
+// 1 degree too hot: 15%
+// exact temperature: 40%
+
+static
+short
+vary_temp(short temp)
+{
+#if defined (__BORLANDC__) || defined (_MSC_VER)
+ long r = rand() % 50;
+#else
+ long r = lrand48() % 50;
+#endif
+ long delta;
+ if (r < 5)
+ delta = 3;
+ else if (r < 15)
+ delta = 2;
+ else if (r < 30)
+ delta = 1;
+ else
+ delta = 0;
+#if defined (__BORLANDC__) || defined (_MSC_VER)
+ if (rand() % 2)
+#else
+ if (lrand48() % 2)
+#endif
+ delta = -delta;
+ return temp + delta;
+}
+
+//----------------------------------------------------------------
+
+// Function object. Locates a thermostat that is in the same room
+// as the device at position pos.
+
+class ThermostatInSameRoom {
+public:
+ ThermostatInSameRoom(
+ const StateMap::iterator & pos
+ ) : m_pos(pos) {}
+ bool operator()(
+ pair<const unsigned long, DeviceState> & p
+ ) const
+ {
+ return(
+ p.second.type == thermostat
+ && p.second.location
+ == m_pos->second.location
+ );
+ }
+private:
+ const StateMap::iterator & m_pos;
+};
+
+//----------------------------------------------------------------
+
+// actual_temp() is a helper function to determine the actual
+// temperature returned by a particular thermometer or thermostat.
+// The pos argument indicates the device.
+//
+// The function locates all thermostats that are in the same room
+// as the device denoted by pos and computes the average of all
+// the thermostats' nominal temperatures. (If no thermostats are
+// in the same room as the device, the function assumes that the
+// average of the nominal temperatures is DFLT_TEMP.)
+//
+// The returned temperature varies from the average as
+// determined by vary_temp().
+
+static
+short
+actual_temp(const StateMap::iterator & pos)
+{
+ long sum = 0;
+ long count = 0;
+ StateMap::iterator where = std::find_if(
+ dstate.begin(), dstate.end(),
+ ThermostatInSameRoom(pos)
+ );
+ while (where != dstate.end()) {
+ count++;
+ sum += where->second.nominal_temp;
+ where = std::find_if(
+ ++where, dstate.end(),
+ ThermostatInSameRoom(pos)
+ );
+ }
+ return vary_temp(count == 0 ? DFLT_TEMP : sum / count);
+}
+
+//---------------------------------------------------------------
+
+// ICP_get() returns an attribute value of the device with the
+// given id. The attribute is named by the attr parameter. The
+// value is copied into the buffer pointed to by the value
+// pointer. The len parameter is the size of the passed buffer,
+// so ICP_get can avoid overrunning the buffer.
+//
+// By default, thermometers report a temperature that varies
+// somewhat around DFLT_TEMP. However, if there is another
+// thermostat in the same room as the thermometer, the
+// thermometer reports a temperature that varies around that
+// thermostat's temperature. For several thermostats that are in
+// the same room, the thermometer reports a temperature that
+// varies around the average nominal temperature of all the
+// thermostats.
+//
+// Attempts to read from a non-existent device or to read a
+// non-existent attribute return -1. A return value of zero
+// indicates success. If the supplied buffer is too short to hold
+// a value, ICP_get() silently truncates the value and
+// returns success.
+
+extern "C"
+int
+ICP_get(
+ unsigned long id,
+ const char * attr,
+ void * value,
+ size_t len)
+{
+ // Look for id in state map
+ StateMap::iterator pos = dstate.find(id);
+ if (pos == dstate.end())
+ return -1; // No such device
+
+ // Depending on the attribute, return the
+ // corresponding piece of state.
+ if (strcmp(attr, "model") == 0) {
+ strncpy((char *)value, pos->second.model, len);
+ } else if (strcmp(attr, "location") == 0) {
+ strncpy((char *)value, pos->second.location.c_str(), len);
+ } else if (strcmp(attr, "nominal_temp") == 0) {
+ if (pos->second.type != thermostat)
+ return -1; // Must be thermostat
+ memcpy(
+ value, &pos->second.nominal_temp,
+ std::min(len, sizeof(pos->second.nominal_temp))
+ );
+ } else if (strcmp(attr, "temperature") == 0) {
+ short temp = actual_temp(pos);
+ memcpy(value, &temp, std::min(len, sizeof(temp)));
+ } else if (strcmp(attr, "MIN_TEMP") == 0) {
+ memcpy(value, &MIN_TEMP, std::min(len, sizeof(MIN_TEMP)));
+ } else if (strcmp(attr, "MAX_TEMP") == 0) {
+ memcpy(value, &MAX_TEMP, std::min(len, sizeof(MAX_TEMP)));
+ } else {
+ return -1; // No such attribute
+ }
+ return 0; // OK
+}
+
+//----------------------------------------------------------------
+
+// ICP_set() sets the attribute specified by attr to the
+// value specified by value for the device with ID id. Attempts to
+// write a string longer than MAXSTR bytes (including the
+// terminating NUL) result in silent truncation of the string.
+// Attempts to access a non-existent device or attribute
+// return -1. Attempts to set a nominal temperature outside the
+// legal range also return -1. A zero return value
+// indicates success.
+
+extern "C"
+int
+ICP_set(unsigned long id, const char * attr, const void * value)
+{
+ // Look for id in state map
+ StateMap::iterator pos = dstate.find(id);
+ if (pos == dstate.end())
+ return -1; // No such device
+
+ // Change either location or nominal temp, depending on attr.
+ if (strcmp(attr, "location") == 0) {
+ pos->second.location.assign(
+ (const char *)value, MAXSTR - 1
+ );
+ } else if (strcmp(attr, "nominal_temp") == 0) {
+ if (pos->second.type != thermostat)
+ return -1; // Must be thermostat
+ short temp;
+ memcpy(&temp, value, sizeof(temp));
+ if (temp < MIN_TEMP || temp > MAX_TEMP)
+ return -1;
+ pos->second.nominal_temp = temp;
+ } else {
+ return -1; // No such attribute
+ }
+ return 0; // OK
+}