Main Page | Class Hierarchy | Class List | File List | Class Members | File Members | Related Pages | Examples

DeviceServer.h

Implementation of the DeviceServer class from Device Server Example.

See also:
Device.h
#ifndef _EXAMPLES_DEVICE_SERVER_H_
#define _EXAMPLES_DEVICE_SERVER_H_

#include "Device.h"

//
// The logger which is used to trace activities in our device server.
// Initialized in main().
//
static rdaLogger* logger;

class DeviceServer : public rdaDeviceServerBase
{
   //
   // The array of pointers to associated devices.
   // Implements the DeviceServer --> Device relationship.
   //
   Device** devices;
   int numDevices;

   //
   // Returns a pointer to the device identified by name or throws the
   // rdaBadParameter exception if the device is not found. This function
   // is called from all device access methods.
   //
   Device* findDevice(const char* name)
   {
      Device* result = 0;
      for (int i = 0; i < numDevices; i++)
      {
         if (!strcmp(devices[i]->getName(), name))
         {
            result = devices[i];
            break;
         }
      }
      if (result == 0) throw rdaBadParameter("No such device");
      return result;
   }

   //
   // The updater thread and related variables.
   //
   pthread_t updater;
   bool runUpdater;   // when set to false terminates the updater thread
   double updateTime; // see update(), getStatus() and getState()

   //
   // The run function of the updater thread.
   // arg - pointer to the device server
   //
   static void* runFunction(void* arg)
   {
      logger->info("updater thread running");
      DeviceServer* theServer = (DeviceServer*) arg;
      //
      // Update measurement values in all devices at 1 second interval
      // until the runUpdater flag is set to false (see shutdownHook).
      //
      while (theServer->runUpdater)
      {
         logger->trace("updating measurement values");
         theServer->update();
         sleep(1);
      }
      logger->info("updater thread terminates");
      return 0;
   }
   
   protected:

      //
      // Iterate through the list of devices and update measurement values
      // in each device. Measure the time spent to update the values and 
      // store it in the updateTime variable.
      //
      virtual void update()
      {
         double startTime = timeNow(); // timeNow defined in Property.h
         for (int i = 0; i < numDevices; i++) devices[i]->update();
         updateTime = timeNow() - startTime;
      }

   public:
   
      //
      // Constructor
      //
      DeviceServer(const char* name) 
      : rdaDeviceServerBase(name), numDevices(10), updateTime(0)
      {
         logger->info("creating device server");
         //
         // Create devices
         //
         devices = new Device* [numDevices];
         char deviceName[16];
         for (int i = 0; i < numDevices; i++)
         {
            sprintf(deviceName, "PowerSupply-%u", (i+1));
            devices[i] = new Device(deviceName);
         }
         //
         // Create and run the updater thread
         //
         logger->info("starting updater thread");
         runUpdater = true;
         pthread_create(&updater, NULL, runFunction, this);
      } 

      //
      // Destructor: deletes devices
      //
      virtual ~DeviceServer()
      {
         logger->info("deleting device server");
         for (int i = 0; i < numDevices; i++) delete devices[i];
         delete [] devices;
      }
      
      //
      // Device access methods
      // =====================
      //
      // All device access methods first try to look up the device
      // specified in the iop argument. If the device is not found
      // in the server, findDevice() will throw the rdaBadParameter
      // exception. This exception is not caught here: RDA will pass
      // it to the calling client. If findDevice() returns normally,
      // then the call is delegated further to the device.
      //
      virtual rdaData* get(const rdaIOPoint& iop, const rdaData&)
      {
         Device* device = findDevice(iop.getDeviceName());
         return device->get(iop.getPropertyName());
      }
      
      virtual void set(const rdaIOPoint& iop, 
                       const rdaData&, 
                       const rdaData& value)
      {
         Device* device = findDevice(iop.getDeviceName());
         device->set(iop.getPropertyName(), value);
      }

      virtual void monitorOn(const rdaIOPoint& iop,
                             const rdaData&,
                             rdaValueChangeListener* listener)
      {
         Device* device = findDevice(iop.getDeviceName());
         device->monitorOn(iop.getPropertyName(), listener);
      }

      virtual void monitorOff(const rdaIOPoint& iop, 
                              rdaValueChangeListener* listener)
      {
         Device* device = findDevice(iop.getDeviceName());
         device->monitorOff(iop.getPropertyName(), listener);
      }

      //
      // Attempts to push subscription reports to clients when
      // the RDA starts to shut down may result in segmentation
      // faults. So we have to stop the updater thread prior to
      // the RDA shutdown.
      //
      virtual void shutdownHook()
      {
         logger->info("terminating updater thread");
         void* dummy;
         //
         // Ask the updater thread to terminate and wait till
         // it actually terminates.
         //
         runUpdater = false;
         pthread_join(updater, &dummy);
      }

      //
      // Example of the getState method implementation: adds updateTime to 
      // the server state data.
      //
      // updateTime measured in the update() function includes:
      //
      //  (1) the time needed to calculate simulated measurement values, and
      //  (2) the time required to notify all clients on the value updates.
      //
      // The first portion is practically constant and relatively small, the
      // second may vary very widely depending on the number of subscriptions
      // and the network performance. So updateTime may serve as an indicator
      // of the general load on the server and of the efficiency of the 
      // subscription mechanism, and it may be useful to monitor it via the
      // server administration interface.
      //
      virtual rdaData* getState()
      {
         //
         // Get the RDA server state
         //
         rdaData* result = rdaDeviceServerBase::getState();
         //
         // Add our state variable (updateTime) to the state data
         //
         result->insert("example.updateTime", updateTime);
         return result;
      }

      //
      // Example of the getStatus() method implementation: sets the server
      // status depending on the update time. This is just an example: all
      // the limits on the update time are absolutely arbitrary.
      //
      virtual ServerStatus getStatus()
      {
         //
         // Evaluate status of our server
         //
         ServerStatus myStatus;
         if (updateTime < 10) myStatus = STATUS_GREEN;       // OK
         else if (updateTime < 15) myStatus = STATUS_YELLOW; // heavy load
         else myStatus = STATUS_RED;                         // overloaded
         //
         // Get the status of the RDA server, compare it with our status,
         // and return the higher severity value.
         //
         ServerStatus result = rdaDeviceServerBase::getStatus();
         if (myStatus > result) result = myStatus;
         return result;
      }
};

#endif

RDA-2.3 documentation - 27 Jun 2007 - N.Trofimov