Files
cdev-1.7.2n/extensions/cdevGenericServer/cdevMonitorTable/cdevMonitorTable.cc
2022-12-13 12:44:04 +01:00

1023 lines
37 KiB
C++
Executable File

#include <cdevMonitorTable.h>
// *****************************************************************************
// * cdevMonitorNode::cdevMonitorEntry Static Variables.
// *****************************************************************************
int cdevMonitorNode::cdevMonitorEntry::VALUE_TAG = 0;
int cdevMonitorNode::cdevMonitorEntry::STATUS_TAG = 0;
int cdevMonitorNode::cdevMonitorEntry::TIME_TAG = 0;
int cdevMonitorNode::cdevMonitorEntry::DEVICE_TAG = 0;
// *****************************************************************************
// * cdevMonitorData::cdevMonitorData:
// * This is the default constructor.
// *****************************************************************************
cdevMonitorData::cdevMonitorData ( void ) :
criticalTags(NULL), criticalTagCnt(0), cdevData()
{
}
// *****************************************************************************
// * cdevMonitorData::cdevMonitorData:
// * This builds a cdevMonitorData from a cdevData.
// *****************************************************************************
cdevMonitorData::cdevMonitorData ( const cdevData & data ) :
criticalTags(NULL), criticalTagCnt(0), cdevData(data)
{
}
// *****************************************************************************
// * cdevMonitorData::cdevMonitorData:
// * This builds a cdevMonitorData from a cdevMonitorData.
// *****************************************************************************
cdevMonitorData::cdevMonitorData ( const cdevMonitorData & data ) :
criticalTags(data.criticalTags),
criticalTagCnt(data.criticalTagCnt),
cdevData(*(const cdevData *)&data)
{
}
// *****************************************************************************
// * isTagCritical :
// * This method will walk through the list of tags and attempt to find
// * the caller specified tag. This method returns 1 if it is present, or
// * 0 if it is not.
// *****************************************************************************
int cdevMonitorData::isTagCritical ( int tag )
{
for(int i=0; i<criticalTagCnt && tag!=criticalTags[i]; i++);
return i<criticalTagCnt?1:0;
}
// *****************************************************************************
// * setCriticalTags :
// * This method is used to specify the tags in the cdevData object that
// * are critical.
// *****************************************************************************
void cdevMonitorData::setCriticalTags ( int * tags, int tagCnt )
{
criticalTags = tags;
criticalTagCnt = tagCnt;
}
// *****************************************************************************
// * changeTag :
// * This method is called when the tags in the cdevData object are remapped
// * to the client tags. When the tag is remapped in this method, the
// * critical tag value (if it exists) will also be remapped.
// *****************************************************************************
int cdevMonitorData::changeTag ( int oldTag, int newTag )
{
for(int i=0; i<criticalTagCnt && criticalTags[i]!=oldTag; i++);
if(criticalTags[i]==oldTag) criticalTags[i] = newTag;
return cdevData::changeTag(oldTag, newTag);
}
// *****************************************************************************
// * xdrSize:
// * Calculates the size of the XDR Buffer necessary to store the cdevData
// * object. This function may be used to determine the size of a
// * preallocated buffer for storing the xdr representation of a cdevData
// * object. The bufLen parameter will receive the size of the buffer, and
// * the elementCount variable will receive the number of elements that will
// * be stored in the buffer.
// *****************************************************************************
int cdevMonitorData::xdrSize (size_t * bufLen, size_t * elementCount)
{
cdevDataEntry * ptr = entries;
int xdrDataSize = 0;
int cdevElementCnt = 0;
int i;
// ************************************#
// * CALCULATE THE SIZE OF THE BUFFER #
// ************************************#
// *************************************
// * Add the size of the tag count int *
// *************************************
xdrDataSize += XDR_Sizeof(cdevElementCnt);
// *************************************
// * Add the size of each valid item *
// *************************************
for(ptr=entries; ptr!=NULL; ptr = ptr->next_)
{
// *****************************
// * Do not process entries *
// * with CDEV_INVALID as the *
// * dataType or 0 as the tag. *
// *****************************
if(ptr->dataType_==CDEV_INVALID ||
ptr->tag_==0 ||
!isTagCritical(ptr->tag_)) continue;
// *****************************
// * Calculate the number of *
// * elements in this tagged *
// * data item. *
// *****************************
int numElements = ptr->dim_!=0?ptr->elems_:1;
// *****************************
// * Increment the counter *
// *****************************
cdevElementCnt++;
// *****************************
// * Add the size of the *
// * cdevDataEntries tag_, *
// * dataType_, dim_, elems_. *
// *****************************
xdrDataSize += 4 * XDR_Sizeof((int)1);
// *****************************
// * Add the size of the *
// * cdevBounds data. *
// *****************************
xdrDataSize += ptr->dim_ * (XDR_Sizeof((int)1) * 2);
// *****************************
// * Add the size of the data *
// *****************************
if (ptr->dataType_==CDEV_BYTE) xdrDataSize += numElements * XDR_Sizeof((unsigned char)'c');
else if(ptr->dataType_==CDEV_INT16) xdrDataSize += numElements * XDR_Sizeof((short)1);
else if(ptr->dataType_==CDEV_UINT16) xdrDataSize += numElements * XDR_Sizeof((unsigned short)1);
else if(ptr->dataType_==CDEV_INT32) xdrDataSize += numElements * XDR_Sizeof((long)1);
else if(ptr->dataType_==CDEV_UINT32) xdrDataSize += numElements * XDR_Sizeof((unsigned long)1);
else if(ptr->dataType_==CDEV_FLOAT) xdrDataSize += numElements * XDR_Sizeof((float)1);
else if(ptr->dataType_==CDEV_DOUBLE) xdrDataSize += numElements * XDR_Sizeof((double)1);
else if(ptr->dataType_==CDEV_STRING)
{
if(numElements==1) xdrDataSize += XDR_Sizeof(ptr->data_.str);
else for(i=0; i<numElements; i++) xdrDataSize += XDR_Sizeof(ptr->data_.strarr[i]);
}
else if(ptr->dataType_==CDEV_TIMESTAMP) xdrDataSize += numElements * XDR_Sizeof(ptr->data_.ts);
}
*elementCount = cdevElementCnt;
*bufLen = xdrDataSize;
return *bufLen>0?CDEV_SUCCESS:CDEV_ERROR;
}
// *****************************************************************************
// * xdrExport:
// * This function encapsulates the contents of the cdevData class into a
// * binary stream. This function allocates the buffer and returns the new
// * buffer and the buffer size.
// *****************************************************************************
int cdevMonitorData::xdrExport ( char ** buf, size_t * bufLen )
{
size_t count = 0;
// ************************************#
// * Calculate the size of the buffer #
// ************************************#
xdrSize(bufLen, &count);
// ************************************#
// * Allocate the buffer and call the #
// * export function. #
// ************************************#
if((*buf = new char[*bufLen])!=NULL) xdrExport(*buf, *bufLen, count);
return buf==NULL?CDEV_ERROR:CDEV_SUCCESS;
}
// *****************************************************************************
// * xdrExport:
// * This function encapsulates the contents of the cdevData class into a
// * preallocated binary stream. The buf parameter contains the address of
// * the caller allocated buffer, the bufLen parameter specifies the size
// * of the buffer, and the count parameter specifies the number of tagged
// * data items that will be copied from the cdevData object into the
// * binary stream.
// *****************************************************************************
int cdevMonitorData::xdrExport ( char * buf, size_t bufLen, size_t count )
{
cdevDataEntry * ptr;
XDR_Writer writer;
int xdrDataSize = bufLen;
int cdevElementCnt = count;
int i;
// ************************************#
// * Allocate the buffer #
// ************************************#
writer.attachData(buf, bufLen);
// ************************************#
// * Transfer the data to the buffer #
// ************************************#
// *************************************
// * Write the number of elements *
// *************************************
writer.put(cdevElementCnt);
// *************************************
// * Write each valid item. *
// *************************************
for(ptr = entries; ptr != NULL; ptr = ptr->next_)
{
// *****************************
// * Do not process entries *
// * with CDEV_INVALID as the *
// * dataType or 0 as the tag. *
// *****************************
if(ptr->dataType_==CDEV_INVALID ||
ptr->tag_==0 ||
!isTagCritical(ptr->tag_)) continue;
// *****************************
// * Calculate the number of *
// * elements in this tagged *
// * data item. *
// *****************************
int numElements = ptr->dim_!=0?ptr->elems_:1;
// *****************************
// * Decrement the counter *
// *****************************
cdevElementCnt--;
// *****************************
// * Write the tag_, dataType_ *
// * dim_, and elems_ of the *
// * cdevDataEntry object. *
// *****************************
writer.put((int)ptr->tag_);
writer.put((int)ptr->dataType_);
writer.put((int)ptr->dim_);
writer.put((int)ptr->elems_);
// *****************************
// * Write the cdevBounds *
// * values asssociated with *
// * the cdevDataEntry (if any)*
// *****************************
cdevBounds * bounds = ptr->bounds();
for(i=0; i<ptr->dim_; i++)
{
writer.put((int)bounds[i].offset);
writer.put((int)bounds[i].length);
}
// *****************************
// * Write the data *
// *****************************
if(ptr->dataType_==CDEV_BYTE)
{
if(numElements==1) writer.put(ptr->data_.cval);
else for(i=0; i<numElements; i++) writer.put(ptr->data_.cptr[i]);
}
else if(ptr->dataType_==CDEV_INT16)
{
if(numElements==1) writer.put(ptr->data_.sval);
else for(i=0; i<numElements; i++) writer.put(ptr->data_.sptr[i]);
}
else if(ptr->dataType_==CDEV_UINT16)
{
if(numElements==1) writer.put(ptr->data_.usval);
else for(i=0; i<numElements; i++) writer.put(ptr->data_.usptr[i]);
}
else if(ptr->dataType_==CDEV_INT32)
{
if(numElements==1) writer.put(ptr->data_.lval);
else for(i=0; i<numElements; i++) writer.put(ptr->data_.lptr[i]);
}
else if(ptr->dataType_==CDEV_UINT32)
{
if(numElements==1) writer.put(ptr->data_.ulval);
else for(i=0; i<numElements; i++) writer.put(ptr->data_.ulptr[i]);
}
else if(ptr->dataType_==CDEV_FLOAT)
{
if(numElements==1) writer.put(ptr->data_.fval);
else for(i=0; i<numElements; i++) writer.put(ptr->data_.fptr[i]);
}
else if(ptr->dataType_==CDEV_DOUBLE)
{
if(numElements==1) writer.put(ptr->data_.dval);
else for(i=0; i<numElements; i++) writer.put(ptr->data_.dptr[i]);
}
else if(ptr->dataType_==CDEV_STRING)
{
if(numElements==1) writer.put(ptr->data_.str);
else for(i=0; i<numElements; i++) writer.put(ptr->data_.strarr[i]);
}
else if(ptr->dataType_==CDEV_TIMESTAMP)
{
if(numElements==1) writer.put(ptr->data_.ts);
}
}
// *************************************
// * Detach the data from the writer *
// * object before the object is *
// * destroyed. *
// *************************************
writer.detachData();
return CDEV_SUCCESS;
}
// *****************************************************************************
// * cdevMonitorNode::cdevMonitorEntry::cdevMonitorEntry :
// * This is the constructor for the cdevMonitorEntry class that is internal to the
// * cdevMonitorNode class.
// *
// * This constructor will initialize all data items and will then populate
// * the list of triggers with all properties from the context that are
// * marked with 2 or 3. It will then populate the properties list with
// * all properties from the context that have any value other than 0.
// *
// * If not properties are in the context, then the following settings will
// * be used by default...
// * value = 3
// * status = 1
// * time = 1
// *
// * The cdevMessage object becomes the property of the cdevMonitorNode
// * object and should not be accessed again by the caller.
// *
// * The deviceIdx indicates the specific device that is being monitored
// * within a multi-device list.
// *****************************************************************************
cdevMonitorNode::cdevMonitorEntry::cdevMonitorEntry( cdevMessage * Message, int DeviceIdx=0 )
: next(NULL), message(Message), triggers(NULL), trigType(NULL),
trigCnt(0), properties(NULL), propCnt(0), deviceIdx(DeviceIdx)
{
// *********************************************************************
// * Populate the static variables if they have not already been set.
// *********************************************************************
if(VALUE_TAG==0)
{
cdevData::tagC2I("value", &VALUE_TAG);
cdevData::tagC2I("status", &STATUS_TAG);
cdevData::tagC2I("time", &TIME_TAG);
// *************************************************************
// * Added to support multi-device monitors.
// *************************************************************
cdevData::tagC2I("device", &DEVICE_TAG);
}
if(message!=NULL)
{
int tag;
size_t tagElems;
int tagVal;
// *************************************************************
// * Start by removing the cdevData data if it has been
// * included. This component will not be necessary to process
// * the monitors.
// *************************************************************
message->setData(NULL);
// *************************************************************
// * If the context has been specified, then read the context
// * to determine the number of monitorable data items.
// *************************************************************
if(message->getContext()!=NULL)
{
cdevData * context = message->getContext();
cdevDataIterator iter(context);
iter.init();
while((tag=iter.tag())!=0)
{
tagElems = 0;
tagVal = 0;
context->getElems(tag, &tagElems);
if(tagElems==1)
{
context->get(tag, &tagVal);
if(tagVal>1) trigCnt++;
if(tagVal>0) propCnt++;
}
++iter;
}
// *****************************************************
// * If the number of monitorable data items is greater
// * than 0, then allocate a sufficient buffer and copy
// * the tag names and tag types into the buffer.
// *****************************************************
if(trigCnt>0)
{
// *********************************************
// * Added to support multi-device list.
// *********************************************
if(message->getDeviceCount()>1) propCnt++;
iter.init();
triggers = new int[trigCnt+trigCnt+propCnt];
trigType = &triggers[trigCnt];
properties = &triggers[trigCnt+trigCnt];
trigCnt = 0;
propCnt = 0;
while((tag=iter.tag())!=0)
{
tagElems = 0;
tagVal = 0;
context->getElems(tag, &tagElems);
if(tagElems==1)
{
context->get(tag, &tagVal);
if(tagVal>1)
{
triggers[trigCnt] = tag;
trigType[trigCnt++] = tagVal;
}
if(tagVal>0) properties[propCnt++] = tag;
}
++iter;
}
// *********************************************
// * Added to support multi-device list.
// *********************************************
if(message->getDeviceCount()>1)
properties[propCnt++] = DEVICE_TAG;
}
}
// *************************************************************
// * If not tags were specified or the context was blank... then
// * use the default setup.
// *************************************************************
if(trigCnt<=0)
{
trigCnt = 1;
propCnt = 3;
// *****************************************************
// * Added to support multi-device list.
// *****************************************************
if(message->getDeviceCount()>1) propCnt++;
triggers = new int[2+propCnt];
trigType = &triggers[1];
properties = &triggers[2];
triggers[0] = VALUE_TAG;
trigType[0] = 3;
properties[0] = VALUE_TAG;
properties[1] = STATUS_TAG;
properties[2] = TIME_TAG;
// *****************************************************
// * Added to support multi-device list.
// *****************************************************
if(message->getDeviceCount()>1) properties[3] = DEVICE_TAG;
}
}
}
// *****************************************************************************
// * cdevMonitorNode::cdevMonitorEntry::~cdevMonitorEntry :
// * This is the destructor for the node object that is internal to the
// * cdevMonitorNode class. It is responsible for deleteing the cdevMessage
// * object and freeing any memory that was allocated to the triggers
// * object.
// *
// * Note that this destructor will delete all of the nodes that are stored
// * below this one in the list.
// ******************************************************************************
cdevMonitorNode::cdevMonitorEntry::~cdevMonitorEntry ( void )
{
if(message) delete message;
if(triggers) delete triggers;
if(next!=NULL) delete next;
}
// *****************************************************************************
// * cdevMonitorNode::cdevMonitorNode :
// * This is the constructor for the cdevMonitorNode class. It will save a
// * copy of the Parent variable and will use the user specified Device and
// * Attrib to create the hashString.
// *****************************************************************************
cdevMonitorNode::cdevMonitorNode ( cdevMonitorTable * Parent,
char * Device,
char * Attrib )
: parent(Parent), hashString(NULL), nodes(NULL)
{
hashString = new char[strlen(Device)+strlen(Attrib)+2];
sprintf(hashString, "%s %s", Device, Attrib);
}
// *****************************************************************************
// * cdevMonitorNode::~cdevMonitorNode :
// * This is the destructor for the cdevMonitorNode object. It will delete
// * the hashString and each node from the list of monitors.
// *****************************************************************************
cdevMonitorNode::~cdevMonitorNode ( void )
{
if(hashString) delete hashString;
if(nodes)
{
// *************************************************************
// * Prior to deleteing itself, this class will first fire its
// * monitors once more using a 1 in the endOfTransaction
// * parameter in order to inform the client side that it will
// * receive no further transactions.
// *************************************************************
cdevMonitorEntry * node = nodes;
while(node)
{
fireMonitor(node, -1, &mData, 1);
node = node->next;
}
delete nodes;
}
}
// *****************************************************************************
// * cdevMonitorNode::insertMonitor :
// * This method is used to add a new monitor for the device / attribute
// * pair associated with this object.
// *
// * The cdevData object that is provided in the cdevData object is the
// * collection of all current property values for the device / attribute
// * pair. This data will be used to automatically dispatch the first
// * callback when the monitor is initially installed.
// *
// * The deviceIdx indicates the specific device that is being monitored
// * within a multi-device list.
// *****************************************************************************
int cdevMonitorNode::insertMonitor ( cdevMessage * request,
cdevData * data,
int deviceIdx = 0 )
{
int result = 0;
cdevMonitorEntry * node = new cdevMonitorEntry(request, deviceIdx);
if(node->trigCnt > 0)
{
node->next = nodes;
nodes = node;
}
else {
delete node;
result = -1;
}
if(data!=NULL)
{
mData = *data;
fireMonitor(node, -1, &mData);
}
return result;
}
// *****************************************************************************
// * cdevMonitorNode::removeMonitor :
// * This method is used to remove a specific monitor by submitting a
// * cdevMessage that contains the transaction index to be canceled in the
// * cancelTransIndex element.
// *****************************************************************************
int cdevMonitorNode::removeMonitor ( cdevMessage * request )
{
return request==NULL?-1:removeMonitor(request->getCancelTransIndex());
}
// *****************************************************************************
// * cdevMonitorNode::removeMonitor :
// * This method is used to remove a specific monitor by submitting a
// * the transaction index to be canceled.
// *****************************************************************************
int cdevMonitorNode::removeMonitor ( unsigned cancelTransIndex )
{
int result = -1;
cdevMonitorEntry * node = nodes, *prev = NULL;
while(node!=NULL &&
node->message->getTransIndex() != cancelTransIndex)
{
prev = node;
node = node->next;
}
if(node!=NULL)
{
if(prev==NULL) nodes = node->next;
else prev->next = node->next;
node->next = NULL;
// *************************************************************
// * This code portion added to inform client side that the
// * monitor is terminating. When a monitor returns an
// * operationCode of 0 - it indicates that there will be no
// * further data transmissions.
// *
// * The 1 provided in the endOfTransaction parameter indicates
// * that this transaction is finished.
// *************************************************************
fireMonitor(node, -1, &mData, 1);
delete node;
result = 0;
}
return result;
}
// *****************************************************************************
// * cdevMonitorNode::removeClientMonitors :
// * This method is used to remove all nodes that are associated with a
// * specified clientID.
// *****************************************************************************
int cdevMonitorNode::removeClientMonitors ( short clientID, int fire )
{
cdevMonitorEntry * node = nodes, *prev = NULL;
while(node!=NULL)
{
if(node->message->getClientID() == clientID)
{
cdevMonitorEntry * nextcdevMonitorEntry = node->next;
node->next = NULL;
// *****************************************************
// * This code portion added to inform client side that
// * the monitor is terminating. When a monitor returns
// * an operationCode of 0 - it indicates that there
// * will be no further data transmissions.
// *
// * The 1 provided in the endOfTransaction parameter
// * indicates that this transaction is finished.
// *****************************************************
if(fire) fireMonitor(node, -1, &mData, 1);
delete node;
if(prev==NULL) nodes = nextcdevMonitorEntry;
else prev->next = nextcdevMonitorEntry;
node = nextcdevMonitorEntry;
}
else {
prev = node;
node = node->next;
}
}
return 0;
}
// *****************************************************************************
// * cdevMonitorNode::fireMonitor :
// * This method is used to submit a change to a monitored property. If the
// * value of property is NULL, then all of the trigger properties will be
// * fired.
// *
// * Note that the data parameter should be populated with all of the
// * properties that are associated with the particular device / attribute
// * pair.
// *****************************************************************************
int cdevMonitorNode::fireMonitor( char * property, cdevData * data )
{
int tag = -1;
if(property!=NULL) cdevData::tagC2I(property, &tag);
return fireMonitor(tag, data);
}
// *****************************************************************************
// * cdevMonitorNode::fireMonitor :
// * This method is used to submit a change to a monitored property. If the
// * value of property is -1, then it will fire all monitors that are listed
// * in the triggers parameter.
// *
// * Note that the data parameter should be populated with all of the
// * properties that are associated with the particular device / attribute
// * pair.
// *
// * This method will return 0 if any monitors were actually dispatched,
// * otherwise it will return -1.
// *****************************************************************************
int cdevMonitorNode::fireMonitor( int property, cdevData * data )
{
int result = -1;
cdevMonitorEntry * node = nodes;
// *********************************************************************
// * Attach the data that is contained in the cdevData object to the
// * cdevMonitorData object.
// *********************************************************************
if(data!=NULL)
{
// *************************************************************
// * Note here I am copying the contents of the user provided
// * data to the mData structure that is local to the
// * cdevMonitorNode.
// *************************************************************
mData = *data;
while(node!=NULL)
{
if(fireMonitor(node, property, &mData)==0) result = 0;
node = node->next;
}
}
return result;
}
// *****************************************************************************
// * cdevMonitorNode::fireMonitor :
// * This method is used to submit a change to a monitored property. If the
// * value of property is -1, then it will fire all monitors that are listed
// * in the triggers parameter.
// *
// * The endOfTransaction flag indicates that this is the last monitor that
// * will be returned in association with this cdevMonitorNode and,
// * therefore, the cdevMessage's operationCode should be set to indicate
// * that.
// *
// * Note that the data parameter should be populated with all of the
// * properties that are associated with the particular device / attribute
// * pair.
// *
// * This method will return 0 if any monitors were actually dispatched,
// * otherwise it will return -1.
// *****************************************************************************
int cdevMonitorNode::fireMonitor( cdevMonitorEntry * entry,
int property,
cdevMonitorData *data,
int endOfTransaction )
{
int result = -1;
if(entry!=NULL && data!=NULL)
{
int found = 0;
// *************************************************************
// * An operationCode value with bit one set indicates that this
// * is NOT the end of the transaction, an operationCode value
// * with bit one unset indicates that this IS the end of the
// * transaction.
// *************************************************************
entry->message->setOperationCode(endOfTransaction?0:1);
for(int i=0; !found && i<entry->trigCnt; i++)
{
if(property<0 || entry->triggers[i]==property)
{
if(property>0) found = 1;
// *********************************************
// * Trigger type 3 means that the callback
// * wants the changed value and all other
// * values that were specified in the
// * context.
// *********************************************
if(entry->trigType[i]==3)
data->setCriticalTags(entry->properties,
entry->propCnt);
// *********************************************
// * Trigger type 2 means that the callback
// * wants only the changed value.
// *********************************************
if(entry->trigType[i]==2)
data->setCriticalTags(&entry->triggers[i], 1);
// *********************************************
// * Determine if the changed data item exists
// * in the user provided data. If it does,
// * then execute the fireCallback method on
// * the cdevMonitorTable to dispatch the
// * monitor.
// *********************************************
if(data->getType(entry->triggers[i])!=CDEV_INVALID)
{
// *************************************
// * Added to support multi-device
// *************************************
if(entry->message->getDeviceCount()>1)
data->insert(cdevMonitorEntry::DEVICE_TAG,
entry->message->getDeviceList()
[entry->deviceIdx]);
entry->message->setData(data, 1);
parent->fireCallback(entry->message);
// *************************************
// * Added to support multi-device
// *************************************
if(entry->message->getDeviceCount()>0)
data->remove(cdevMonitorEntry::DEVICE_TAG);
result = 0;
}
}
}
}
return result;
}
// *****************************************************************************
// * cdevMonitorTable::cdevMonitorTable :
// * This is the constructor for the cdevMonitortable class. This class
// * contains a hash table that maintains a list of all of the monitored
// * device / attribute pairs on the system.
// *****************************************************************************
cdevMonitorTable::cdevMonitorTable ( void )
: monitors(0)
{
}
// *****************************************************************************
// * cdevMonitorTable::~cdevMonitorTable :
// * This method walks through the monitors hash table and deletes all
// * cdevMonitorNodes that have been allocated.
// *****************************************************************************
cdevMonitorTable::~cdevMonitorTable ( void )
{
char * ptr;
StringHashIterator iter(&monitors);
iter.first();
while((ptr= iter.key())!=NULL)
{
cdevMonitorNode * node = (cdevMonitorNode *)iter.data();
monitors.remove(ptr);
delete node;
iter.first();
}
}
// *****************************************************************************
// * cdevMonitorTable::insertMonitor:
// * This method allows the caller to add a new monitored device / attribute
// * pair to the cdevMonitorTable.
// *
// * The cdevData object that is provided in the cdevData object is the
// * collection of all current property values for the device / attribute
// * pair. This data will be used to automatically dispatch the first
// * callback when the monitor is initially installed.
// *****************************************************************************
int cdevMonitorTable::insertMonitor ( cdevMessage * request, cdevData * data )
{
return insertMonitor(request, &data, 1);
}
// *****************************************************************************
// * cdevMonitorTable::insertMonitor:
// * This method allows the caller to add a new monitored device / attribute
// * pair to the cdevMonitorTable.
// *
// * The cdevData objects that are provided in the data parameter are the
// * initial values for each item in the deviceList in sequence. This data
// * will be used to automatically dispatch the first callback when the
// * monitor is initially installed.
// *****************************************************************************
int cdevMonitorTable::insertMonitor ( cdevMessage * request, cdevData ** data, size_t dataCnt )
{
if(request!=NULL && request->getDeviceList()!=NULL && request->getMessage()!=NULL)
{
char * attrib = strchr(request->getMessage(), ' ');
if(attrib)
{
attrib++;
cdevMonitorNode * node;
cdevMessage ** msgList;
// *****************************************************
// * Allocate additional cdevMessage objects if a
// * deviceList greater than 1 is specified.
// *****************************************************
if(request->getDeviceCount()>1)
{
msgList = new cdevMessage *[request->getDeviceCount()];
msgList[0] = request;
}
else msgList = &request;
// *****************************************************
// * Walk through each device in the list.
// *****************************************************
for(int i=0; i<request->getDeviceCount(); i++)
{
if(i>0) msgList[i] = new cdevMessage(*request);
if((node=findMonitor(request->getDeviceList()[i], attrib))==NULL)
{
node = new cdevMonitorNode(this, request->getDeviceList()[i], attrib);
monitors.insert(node->getHashString(), node);
}
if(dataCnt>0 && data!=NULL)
{
node->insertMonitor(msgList[i], ((i<dataCnt)?data[i]:data[dataCnt-1]), i);
}
else node->insertMonitor(msgList[i], NULL, i);
}
// *****************************************************
// * Delete the containing array of cdevMessage pointers
// *****************************************************
if(request->getDeviceCount()>1) delete msgList;
}
}
return 0;
}
// *****************************************************************************
// * cdevMonitorTable::removeMonitor :
// * This method allows the caller to remove a specific monitor using the
// * cancelTransIndex component of the cdevMessage object.
// *****************************************************************************
int cdevMonitorTable::removeMonitor ( cdevMessage * request )
{
int cancelTransIndex = request->getCancelTransIndex();
if(cancelTransIndex > 0)
{
StringHashIterator iter(&monitors);
iter.first();
while(iter.key()!=NULL)
{
cdevMonitorNode * node = (cdevMonitorNode *)iter.data();
node->removeMonitor(cancelTransIndex);
++iter;
}
}
return 0;
}
// *****************************************************************************
// * cdevMonitorTable::removeClientMonitors :
// * This method will walk through the hash table and will remove all
// * monitors that are associated with a specific clientID.
// *****************************************************************************
int cdevMonitorTable::removeClientMonitors ( short clientID, int fire )
{
char * ptr;
StringHashIterator iter(&monitors);
iter.first();
while((ptr= iter.key())!=NULL)
{
cdevMonitorNode * node = (cdevMonitorNode *)iter.data();
node->removeClientMonitors(clientID, fire);
iter++;
}
return 0;
}
// *****************************************************************************
// * cdevMonitorTable::findMonitor :
// * This method locates a cdevMonitorNode associated with the specified
// * device / attribute pair and returns it to the caller.
// *****************************************************************************
cdevMonitorNode * cdevMonitorTable::findMonitor ( char * device, char * attrib )
{
char hashString [512];
sprintf(hashString, "%s %s", device, attrib);
return (cdevMonitorNode *)monitors.find(hashString);
}
// *****************************************************************************
// * cdevMonitorTable:fireMonitor :
// * This method is used to deploy all monitors associated with the
// * device / attribute / property set.
// *
// * If the property parameter is NULL, then all properties will be fired
// * for all monitor associated with the device / attribute pair.
// *****************************************************************************
int cdevMonitorTable::fireMonitor ( char * device, char * attrib,
char * property, cdevData * data )
{
cdevMonitorNode * node = findMonitor(device, attrib);
return node==NULL?-1:node->fireMonitor(property, data);
}
// *****************************************************************************
// * cdevMonitorTable:fireMonitor :
// * This method is used to deploy all monitors associated with the
// * device / attribute / property set.
// *
// * If the property parameter is -1, then all properties will be fired
// * for all monitors associated with the device / attribute pair.
// *****************************************************************************
int cdevMonitorTable::fireMonitor ( char * device, char * attrib,
int property, cdevData * data )
{
cdevMonitorNode * node = findMonitor(device, attrib);
return node==NULL?-1:node->fireMonitor(property, data);
}
// *****************************************************************************
// * cdevMonitorTable::fireCallback :
// * This is a stub for the fireCallback method that must b e provided by
// * the developer. This method is provided here - because this method may
// * potentially be called during program termination - resulting in the
// * attempted execution of a pure virtual function.
// *****************************************************************************
int cdevMonitorTable::fireCallback ( cdevMessage * /* message */ )
{
return CDEV_SUCCESS;
}