📄 icp.cpp
字号:
#ifdef _MSC_VER#pragma warning ( disable : 4786 )#define lrand48 rand#elif !defined(__hpux)#endif#include <OB/Basic.h>#include <string>#include <map>#include <algorithm>#ifdef HAVE_STDLIB_H# include <stdlib.h>#endif#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 NULconst short MIN_TEMP = 40; // 40 F == 4.44 Cconst short MAX_TEMP = 90; // 90 F == 32.22 Cconst short DFLT_TEMP = 68; // 68 F == 20.00 Cstatic 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"intICP_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"intICP_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%staticshortvary_temp(short temp){ long r = lrand48() % 50; long delta; if (r < 5) delta = 3; else if (r < 15) delta = 2; else if (r < 30) delta = 1; else delta = 0; if (lrand48() % 2) 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().staticshortactual_temp(const StateMap::iterator & pos){ long sum = 0; long count = 0; StateMap::iterator where = find_if( dstate.begin(), dstate.end(), ThermostatInSameRoom(pos) ); while (where != dstate.end()) { ++count; sum += where->second.nominal_temp; where = 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 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"intICP_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, min(len, sizeof(pos->second.nominal_temp)) ); } else if (strcmp(attr, "temperature") == 0) { short temp = actual_temp(pos); memcpy(value, &temp, min(len, sizeof(temp))); } else if (strcmp(attr, "MIN_TEMP") == 0) { memcpy(value, &MIN_TEMP, min(len, sizeof(MIN_TEMP))); } else if (strcmp(attr, "MAX_TEMP") == 0) { memcpy(value, &MAX_TEMP, 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"intICP_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 = reinterpret_cast<const char *>(value); if (pos->second.location.size() >= MAXSTR) pos->second.location[MAXSTR - 1] = '\0'; } 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}//----------------------------------------------------------------#ifdef HAVE_FSTREAM# include <fstream>#else# include <fstream.h>#endifclass 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. fstream db(m_filename.c_str(), ios::in|ios::out#if defined(_MSC_VER) |ios::app#elif defined(__sun) |ios::app, 0666#else , 0666#endif ); if (!db) { cerr << "Error opening " << m_filename << 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"; db.get(); // Skip newline char loc[MAXSTR]; 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 !defined(__GNUC__) && !defined(_MSC_VER) if (!db) { cerr << "Error closing " << m_filename << endl; exit(1); }#endif}// Write device state to the file.ICP_Persist::~ICP_Persist(){ // Open output file, truncating it. ofstream db(m_filename.c_str()); if (!db) { cerr << "Error opening " << m_filename << endl; exit(1); } // Write the state details for each device. StateMap::iterator i; for (i = dstate.begin(); i != dstate.end(); ++i) { db << i->first << endl; db << i->second.type << endl; db << i->second.location.c_str() << endl; if (i->second.type == thermostat) db << i->second.nominal_temp << endl; } if (!db) { cerr << "Error writing " << m_filename << endl; exit(1); } db.close();#if !defined(__GNUC__) && !defined(_MSC_VER) if (!db) { cerr << "Error closing " << m_filename << endl; exit(1); }#endif}// Instantiate a single global instance of the class.static ICP_Persist mydb("CCS_DB");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -