summaryrefslogtreecommitdiff
path: root/TAO/examples/Advanced/ch_21/icp.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'TAO/examples/Advanced/ch_21/icp.cpp')
-rw-r--r--TAO/examples/Advanced/ch_21/icp.cpp411
1 files changed, 411 insertions, 0 deletions
diff --git a/TAO/examples/Advanced/ch_21/icp.cpp b/TAO/examples/Advanced/ch_21/icp.cpp
new file mode 100644
index 00000000000..33d4bf9e072
--- /dev/null
+++ b/TAO/examples/Advanced/ch_21/icp.cpp
@@ -0,0 +1,411 @@
+// $Id$
+// ============================================================================
+//
+// = LIBRARY
+// TAO/examples/Advanced/ch_21
+//
+// = 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 <iostream>
+#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 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 on-line already, 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 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 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 the attributed 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
+}
+
+//----------------------------------------------------------------
+
+#include <fstream>
+
+class ICP_Persist {
+public:
+ ICP_Persist(const char * file);
+ ~ICP_Persist();
+private:
+ string m_filename;
+};
+
+// Read device state from a file and initialize the dstate map.
+
+ICP_Persist::
+ICP_Persist(const char * file) : m_filename(file)
+{
+ // Open input file, creating it if necessary.
+ std::ifstream db(m_filename.c_str(), std::ios::in|std::ios::out);//, 0666);
+ if (!db) {
+ std::cerr << "Error opening " << m_filename << std::endl;
+ exit(1);
+ }
+
+ // Read device details, one attribute per line.
+ DeviceState ds;
+ unsigned long id;
+ while (db >> id) {
+ // Read device type and set model string accordingly.
+ int dtype;
+ db >> dtype;
+ ds.type = dtype == thermometer
+ ? thermometer : thermostat;
+ ds.model = dtype == thermometer
+ ? "Sens-A-Temp" : "Select-A-Temp";
+ char loc[MAXSTR];
+ db.get(loc[0]); // Skip newline
+ db.getline(loc, sizeof(loc)); // Read location
+ ds.location = loc;
+ if (ds.type == thermostat)
+ db >> ds.nominal_temp; // Read temperature
+ dstate[id] = ds; // Add entry to map
+ }
+
+ // db.close();
+ // if (!db) {
+ // cerr << "Error closing " << m_filename << endl;
+ // exit(1);
+ // }
+}
+
+// Write device state to the file.
+
+ICP_Persist::
+~ICP_Persist()
+{
+ // Open input file, truncating it.
+ std::ofstream db(m_filename.c_str());
+ if (!db) {
+ std::cerr << "Error opening " << m_filename << std::endl;
+ exit(1);
+ }
+
+ // Write the state details for each device.
+ StateMap::iterator i;
+ for (i = dstate.begin(); i != dstate.end(); i++) {
+ db << i->first << std::endl;
+ db << (unsigned long)(i->second.type) << std::endl;
+ db << i->second.location << std::endl;
+ if (i->second.type == thermostat)
+ db << i->second.nominal_temp << std::endl;
+ }
+ if (!db) {
+ std::cerr << "Error writing " << m_filename << std::endl;
+ exit(1);
+ }
+
+ // db.close();
+ // if (!db) {
+ // cerr << "Error closing " << m_filename << endl;
+ // exit(1);
+ // }
+}
+
+// Instantiate a single global instance of the class.
+static ICP_Persist mydb("/tmp/CCS_DB");
+
+
+
+
+
+
+
+
+
+
+