#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