#ifndef _EXAMPLES_PROPERTY_H_
#define _EXAMPLES_PROPERTY_H_
#include <stdlib.h>
#include <unistd.h>
#include <math.h>
#include <sys/time.h>
#include <sys/times.h>
#include <rda/DeviceServerBase.h>
static const char* VTAG = "value";
static const char* TTAG = "timestamp";
static double timeNow()
{
struct timeval tv;
struct timezone tz;
gettimeofday(&tv, &tz);
return 1000.0 * (double)tv.tv_sec + (double)(tv.tv_usec) / 1000.0;
}
static void fatalError(const rdaInternalError& ex)
{
char message[1000];
sprintf(message, "RDA internal error [%s:%d]: %s",
ex.getFile(), ex.getLine(), ex.getMessage());
rdaDeviceServerBase::getGlobalLogger()->error(message);
rdaDeviceServerBase::shutDown();
}
class Property
{
const char* name;
protected:
double value;
double timestamp;
static const double minValue = 0;
static const double maxValue = 100.0;
rdaValueChangeListener** listeners;
int numListeners;
void notifyClients(double newValue, bool hasChanged)
{
rdaData oldData;
oldData.insert(VTAG, value);
rdaData newData;
newData.insert(VTAG, newValue);
newData.insert(TTAG, timestamp);
try
{
for (int i = 0; i < numListeners; i++)
listeners[i]->valueUpdated(oldData, newData, hasChanged);
}
catch(const rdaInternalError& ex)
{
fatalError(ex);
}
value = newValue;
}
public:
Property(const char* pname)
: name(pname), value(0), listeners(0), numListeners(0)
{
timestamp = timeNow();
}
virtual ~Property() {}
const char* getName()
{
return name;
}
double getValue()
{
return value;
}
void addListener(rdaValueChangeListener* listener)
{
rdaValueChangeListener** newListeners =
new rdaValueChangeListener* [numListeners + 1];
for (int i=0; i < numListeners; i++)
newListeners[i] = listeners[i];
delete [] listeners;
listeners = newListeners;
listeners[numListeners] = listener;
numListeners++;
rdaData* data = get();
rdaData empty;
try
{
listener->valueUpdated(empty, *data, true);
}
catch(const rdaInternalError& ex)
{
fatalError(ex);
}
delete data;
}
void removeListener(rdaValueChangeListener* listener)
{
rdaValueChangeListener** newListeners =
new rdaValueChangeListener* [numListeners - 1];
int j = 0;
for (int i=0; i < numListeners; i++)
if (listeners[i] != listener) newListeners[j++] = listeners[i];
delete [] listeners;
listeners = newListeners;
numListeners--;
}
virtual rdaData* get()
{
rdaData* result = new rdaData;
result->insert(VTAG, value);
result->insert(TTAG, timestamp);
return result;
}
virtual void set(const rdaData&) = 0;
};
class Measurement : public Property
{
public:
Measurement() : Property("voltage") {}
virtual ~Measurement() {}
void update(double newValue)
{
if (newValue < minValue) newValue = minValue;
if (newValue > maxValue) newValue = maxValue;
timestamp = timeNow();
bool hasChanged = (fabs(value - newValue) > 1.0);
notifyClients(newValue, hasChanged);
}
virtual void set(const rdaData&)
{
throw rdaIOError("EXAMPLE", 1, "Can't set readonly property");
}
};
class Setting : public Property
{
public:
Setting() : Property("requestedVoltage") {}
virtual ~Setting() {}
virtual void set(const rdaData& data)
{
double newValue = 0;
try
{
newValue = data.extractDouble(VTAG);
}
catch(const rdaBadParameter&)
{
throw rdaBadParameter("No 'value' entry in value data");
}
catch(const rdaTypeMismatch&)
{
throw rdaBadParameter("Bad value type: 'double' expected");
}
if (newValue < minValue || newValue > maxValue)
throw rdaBadParameter("Value out of range");
timestamp = timeNow();
notifyClients(newValue, true);
}
};
#endif