diff --git a/documentation/pvDataCpp.html b/documentation/pvDataCpp.html index 002ccc8..8fe5dc8 100644 --- a/documentation/pvDataCpp.html +++ b/documentation/pvDataCpp.html @@ -10,13 +10,13 @@
TODO
NOT IMPLEMENTED+
class MessageNode {
+public:
+ String getMessage() const;
+ MessageType getMessageType() const;
+};
+
+class MessageQueue : private NoDefaultMethods {
+public:
+ MessageQueue(int size);
+ ~MessageQueue();
+ static ConstructDestructCallback *getConstructDestructCallback();
+ MessageNode *get();
+ // must call release before next get
+ void release();
+ // return (false,true) if message (was not, was) put into queue
+ bool put(String message,MessageType messageType,bool replaceLast);
+ bool isEmpty() const;
+ bool isFull() const;
+ int getClearOverrun();
+};
A messageNode is a class with two public data members:
A messageQueue is an interface with methods:
+A messageQueue is an interface with public methods:
MessageQueueFactory provides the public method:
-An example is:
- private ExecutorNode executorNode;
- ...
- executorNode = executor.createNode(this);
- ...
-
- public void message(final String message, MessageType messageType) {
- boolean execute = false;
- synchronized(messageQueue) {
- if(messageQueue.isEmpty()) execute = true;
- if(messageQueue.isFull()) {
- messageQueue.replaceLast(message, messageType);
- } else {
- messageQueue.put(message, messageType);
- }
- }
- if(syncExec) {
- iocExecutor.execute(executorNode);
- }
- }
- ...
- public run() { // handle messages
- while(true) {
- String message = null;
- int numOverrun = 0;
- synchronized(messageQueue) {
- MessageNode messageNode = messageQueue.get();
- numOverrun = messageQueue.getClearOverrun();
- if(messageNode==null && numOverrun==0) break;
- message = messageNode.message;
- }
- if(numOverrun>0) {
- System.out.printf(String.format("%n%d missed messages&n", numOverrun));
- }
- if(message!=null) {
- System.out.printf(String.format("%s%n",message));
- }
- }
- }
+Look at miscTest/testMessageQueue.cpp for an example.
This provides a queue which has an immutable capacit. When the queue is +
This provides a queue which has an immutable capacity. When the queue is full the user code is expected to keep using the current element until a new free element becomes avalable.
template <typename T>
class QueueElement : private QueueElementVoid {
public:
- QueueElement(T *object) : QueueElementVoid(static_cast<void *>(object)){}
- ~QueueElement() {}
T *getObject() { return static_cast<T *>(QueueElementVoid::getObject());}
- friend class Queue<T>;
+protected:
};
template <typename T>
class Queue : private QueueVoid {
public:
- Queue(QueueElement<T> **array,int number)
- : QueueVoid((QueueElementVoid**)array,number)
- //: QueueVoid(static_cast<QueueElementVoid**>(array),number)
- {}
- ~Queue() {}
- void clear() {QueueVoid::clear();}
- int getNumberFree() {return QueueVoid::getNumberFree();}
- int capacity() {return QueueVoid::capacity();}
- QueueElement<T> *getFree() {
- return static_cast<QueueElement<T> *>(QueueVoid::getFree());}
- void setUsed(QueueElement<T> *queueElement) {
- QueueVoid::setUsed(static_cast<QueueElementVoid *>(queueElement));}
- QueueElement<T> *getUsed() {
- return static_cast<QueueElement<T> *>(QueueVoid::getUsed());}
- void releaseUsed(QueueElement<T> *queueElement) {
- QueueVoid::releaseUsed(static_cast<QueueElementVoid *>(queueElement));}
+ Queue(T *array[],int number);
+ ~Queue();
+ void clear();
+ int getNumberFree();
+ int capacity();
+ QueueElement<T> *getFree();
+ void setUsed(QueueElement<T> *queueElement);
+ QueueElement<T> *getUsed();
+ void releaseUsed(QueueElement<T> *queueElement);
};
-miscTest/queueTest.cpp provides an example of how to define queueElements -and a queue.
+miscTest/queueTest.cpp provides an example of how to define a queue.
The queue methods are:
A queue is created as follows:
+ class MyClass;
+ typedef MyQueueElement<MyClass> MyElement;
+ typedef MyQueue<MyClass> MyQueue;
+ int numElement = 5;
+ ...
+ MyClass *array[numElements];
+ for(int i=0; i<numElements; i++) {
+ array[i] = new MyClass();
+ }
+ MyQueue *queue = new MyQueue(array,numElements);
+
A producer calls getFree and setUsed via code like the following:
- MyObject *getFree() {
- QueueElement<MyObject> *queueElement = queue->getFree();
- if(queueElement==0) return 0;
- return queueElement->getObject();
+ MyClass *getFree() {
+ MyElement *element = queue->getFree();
+ if(element==0) return 0;
+ return element->getObject();
}
A consumer calls getUsed and releaseUsed via code like the following:
while(true) {
- QueueElement<MyObject> *queueElement = queue->getUsed();
- if(queueElement==0) break;
- MyObject *myObject = queueElement->getObject();
- // do something with myObject
- queue->releaseUsed(queueElement);
+ MyElement *element = queue->getUsed();
+ if(element==0) break;
+ MyClass *myClass = element->getObject();
+ // do something with myClass
+ queue->releaseUsed(element);
}
diff --git a/pvDataApp/Makefile b/pvDataApp/Makefile
index 2675fe5..4c16ee6 100644
--- a/pvDataApp/Makefile
+++ b/pvDataApp/Makefile
@@ -6,5 +6,6 @@ DIRS += factory
DIRS += property
DIRS += miscTest
DIRS += pvTest
+DIRS += propertyTest
include $(TOP)/configure/RULES_DIRS
diff --git a/pvDataApp/factory/AbstractPVField.h b/pvDataApp/factory/AbstractPVField.h
index 423447b..662d3a5 100644
--- a/pvDataApp/factory/AbstractPVField.h
+++ b/pvDataApp/factory/AbstractPVField.h
@@ -193,20 +193,22 @@ void PVField::renameField(String newName)
FieldCreate *fieldCreate = getFieldCreate();
switch(pImpl->field->getType()) {
case scalar: {
- ScalarConstPtr scalar = (ScalarConstPtr)pImpl->field;
+ ScalarConstPtr scalar = static_cast(pImpl->field);
scalar = fieldCreate->createScalar(newName, scalar->getScalarType());
pImpl->field = scalar;
break;
}
case scalarArray: {
- ScalarArrayConstPtr array = (ScalarArrayConstPtr)pImpl->field;
+ ScalarArrayConstPtr array =
+ static_cast(pImpl->field);
array = fieldCreate->createScalarArray(
newName, array->getElementType());
pImpl->field = array;
break;
}
case structure: {
- StructureConstPtr structure = (StructureConstPtr)pImpl->field;
+ StructureConstPtr structure =
+ static_cast(pImpl->field);
FieldConstPtrArray origFields = structure->getFields();
int numberFields = structure->getNumberFields();
structure = fieldCreate->createStructure(
@@ -215,7 +217,8 @@ void PVField::renameField(String newName)
break;
}
case structureArray: {
- StructureArrayConstPtr structureArray = (StructureArrayConstPtr)pImpl->field;
+ StructureArrayConstPtr structureArray =
+ static_cast(pImpl->field);
structureArray = fieldCreate->createStructureArray(newName,
structureArray->getStructure());
pImpl->field = structureArray;
@@ -258,7 +261,7 @@ void PVField::computeOffset(PVField * pvField) {
pvField->pImpl->nextFieldOffset = 1;
return;
}
- pvTop = (PVStructure *)pvField;
+ pvTop = static_cast(pvField);
} else {
while(pvTop->getParent()!=0) pvTop = pvTop->getParent();
}
@@ -292,7 +295,7 @@ void PVField::computeOffset(PVField * pvField) {
void PVField::computeOffset(PVField * pvField,int offset) {
int beginOffset = offset;
int nextOffset = offset + 1;
- PVStructure *pvStructure = (PVStructure *)pvField;
+ PVStructure *pvStructure = static_cast(pvField);
PVFieldPtrArray pvFields = pvStructure->getPVFields();
for(int i=0; i < pvStructure->getStructure()->getNumberFields(); i++) {
offset = nextOffset;
diff --git a/pvDataApp/factory/FieldCreateFactory.cpp b/pvDataApp/factory/FieldCreateFactory.cpp
index 167100c..401bfd5 100644
--- a/pvDataApp/factory/FieldCreateFactory.cpp
+++ b/pvDataApp/factory/FieldCreateFactory.cpp
@@ -261,19 +261,19 @@ FieldConstPtr FieldCreate::create(String fieldName,
Type type = pfield->getType();
switch(type) {
case scalar: {
- ScalarConstPtr pscalar = dynamic_cast(pfield);
+ ScalarConstPtr pscalar = static_cast(pfield);
return createScalar(fieldName,pscalar->getScalarType());
}
case scalarArray: {
- ScalarArrayConstPtr pscalarArray = dynamic_cast(pfield);
+ ScalarArrayConstPtr pscalarArray = static_cast(pfield);
return createScalarArray(fieldName,pscalarArray->getElementType());
}
case structure: {
- StructureConstPtr pstructure = dynamic_cast(pfield);
+ StructureConstPtr pstructure = static_cast(pfield);
return createStructure(fieldName,pstructure->getNumberFields(),pstructure->getFields());
}
case structureArray: {
- StructureArrayConstPtr pstructureArray = dynamic_cast(pfield);
+ StructureArrayConstPtr pstructureArray = static_cast(pfield);
return createStructureArray(fieldName,pstructureArray->getStructure());
}
}
diff --git a/pvDataApp/factory/StandardField.cpp b/pvDataApp/factory/StandardField.cpp
index 76c6844..6b176a1 100644
--- a/pvDataApp/factory/StandardField.cpp
+++ b/pvDataApp/factory/StandardField.cpp
@@ -300,8 +300,7 @@ StructureConstPtr StandardField::structure(
return fieldCreate->createStructure(fieldName,numFields,fields);
}
-StructureConstPtr StandardField::enumerated(
- String fieldName,StringArray choices)
+StructureConstPtr StandardField::enumerated(String fieldName)
{
FieldConstPtrArray fields = new FieldConstPtr[2];
fields[0] = fieldCreate->createScalar(String("index"),pvInt);
@@ -310,9 +309,9 @@ StructureConstPtr StandardField::enumerated(
}
StructureConstPtr StandardField::enumerated(
- String fieldName,StringArray choices, String properties)
+ String fieldName,String properties)
{
- StructureConstPtr field = standardField->enumerated(valueFieldName,choices);
+ StructureConstPtr field = standardField->enumerated(valueFieldName);
return createProperties(fieldName,field,properties);
}
@@ -362,7 +361,7 @@ StructureConstPtr StandardField::structureValue(
return fieldCreate->createStructure(valueFieldName,numFields,fields);
}
-StructureConstPtr StandardField::enumeratedValue(StringArray choices)
+StructureConstPtr StandardField::enumeratedValue()
{
FieldConstPtrArray fields = new FieldConstPtr[2];
fields[0] = fieldCreate->createScalar(String("index"),pvInt);
@@ -370,10 +369,9 @@ StructureConstPtr StandardField::enumeratedValue(StringArray choices)
return fieldCreate->createStructure(valueFieldName,2,fields);
}
-StructureConstPtr StandardField::enumeratedValue(
- StringArray choices, String properties)
+StructureConstPtr StandardField::enumeratedValue( String properties)
{
- StructureConstPtr field = standardField->enumerated(valueFieldName,choices);
+ StructureConstPtr field = standardField->enumerated(valueFieldName);
return createProperties(valueFieldName,field,properties);
}
diff --git a/pvDataApp/factory/StandardPVField.cpp b/pvDataApp/factory/StandardPVField.cpp
index 8993eb2..0b96f6e 100644
--- a/pvDataApp/factory/StandardPVField.cpp
+++ b/pvDataApp/factory/StandardPVField.cpp
@@ -73,19 +73,34 @@ PVStructure* StandardPVField::structureArray(PVStructure *parent,
}
PVStructure * StandardPVField::enumerated(PVStructure *parent,
- String fieldName,StringArray choices)
+ String fieldName,StringArray choices,int number)
{
- StructureConstPtr field = standardField->enumerated(
- fieldName,choices);
- return pvDataCreate->createPVStructure(parent,field);
+ StructureConstPtr field = standardField->enumerated(fieldName);
+ PVStructure *pvStructure = pvDataCreate->createPVStructure(parent,field);
+ PVScalarArray *pvScalarArray = pvStructure->getScalarArrayField(
+ "choices",pvString);
+ if(pvScalarArray==0) {
+ throw std::logic_error(String("StandardPVField::enumerated"));
+ }
+ PVStringArray *pvChoices = static_cast(pvScalarArray);
+ pvChoices->put(0,number,choices,0);
+ return pvStructure;
}
PVStructure * StandardPVField::enumerated(PVStructure *parent,
- String fieldName,StringArray choices, String properties)
+ String fieldName,StringArray choices,int number, String properties)
{
StructureConstPtr field = standardField->enumerated(
- fieldName,choices,properties);
- return pvDataCreate->createPVStructure(parent,field);
+ fieldName,properties);
+ PVStructure *pvStructure = pvDataCreate->createPVStructure(parent,field);
+ PVScalarArray *pvScalarArray = pvStructure->getScalarArrayField(
+ fieldName += ".choices",pvString);
+ if(pvScalarArray==0) {
+ throw std::logic_error(String("StandardPVField::enumerated"));
+ }
+ PVStringArray *pvChoices = static_cast(pvScalarArray);
+ pvChoices->put(0,number,choices,0);
+ return pvStructure;
}
PVScalar * StandardPVField::scalarValue(PVStructure *parent,
@@ -135,17 +150,33 @@ PVStructure * StandardPVField::structureArrayValue(PVStructure *parent,
}
PVStructure * StandardPVField::enumeratedValue(PVStructure *parent,
- StringArray choices)
+ StringArray choices,int number)
{
- StructureConstPtr field = standardField->enumeratedValue( choices);
- return pvDataCreate->createPVStructure(parent,field);
+ StructureConstPtr field = standardField->enumeratedValue();
+ PVStructure *pvStructure = pvDataCreate->createPVStructure(parent,field);
+ PVScalarArray *pvScalarArray = pvStructure->getScalarArrayField(
+ "choices",pvString);
+ if(pvScalarArray==0) {
+ throw std::logic_error(String("StandardPVField::enumerated"));
+ }
+ PVStringArray *pvChoices = static_cast(pvScalarArray);
+ pvChoices->put(0,number,choices,0);
+ return pvStructure;
}
PVStructure * StandardPVField::enumeratedValue(PVStructure *parent,
- StringArray choices, String properties)
+ StringArray choices, int number,String properties)
{
- StructureConstPtr field = standardField->enumeratedValue(
- choices,properties);
+ StructureConstPtr field = standardField->enumeratedValue( properties);
+ PVStructure *pvStructure = pvDataCreate->createPVStructure(parent,field);
+ PVScalarArray *pvScalarArray = pvStructure->getScalarArrayField(
+ String("value.choices"),pvString);
+ if(pvScalarArray==0) {
+ throw std::logic_error(String("StandardPVField::enumerated"));
+ }
+ PVStringArray *pvChoices = static_cast(pvScalarArray);
+ pvChoices->put(0,number,choices,0);
+ return pvStructure;
return pvDataCreate->createPVStructure(parent,field);
}
diff --git a/pvDataApp/factory/TypeFunc.cpp.orig b/pvDataApp/factory/TypeFunc.cpp.orig
new file mode 100644
index 0000000..177325c
--- /dev/null
+++ b/pvDataApp/factory/TypeFunc.cpp.orig
@@ -0,0 +1,72 @@
+/*TypeFunc.cpp*/
+/**
+ * Copyright - See the COPYRIGHT that is included with this distribution.
+ * EPICS pvDataCPP is distributed subject to a Software License Agreement found
+ * in file LICENSE that is included with this distribution.
+ */
+#include
+#include
+#include
+#include
+
+#include "pvIntrospect.h"
+
+namespace epics { namespace pvData {
+
+ void TypeFunc::toString(StringBuilder buf,const Type type) {
+ static String unknownString = "logic error unknown Type";
+ switch(type) {
+ case pvScalar : *buf += "scalar"; break;
+ case pvScalarArray : *buf += "scalarArray"; break;
+ case pvStructure : *buf += "structure"; break;
+ case pvStructureArray : *buf += "structureArray"; break;
+ default:
+ throw std::invalid_argument(unknownString);
+ }
+ }
+
+
+ bool ScalarTypeFunc::isInteger(ScalarType type) {
+ if(type>=pvByte && type<=pvLong) return true;
+ return false;
+ }
+
+ bool ScalarTypeFunc::isNumeric(ScalarType type) {
+ if(type>=pvByte && type<=pvDouble) return true;
+ return false;
+ }
+
+ bool ScalarTypeFunc::isPrimitive(ScalarType type) {
+ if(type>=pvBoolean && type<=pvDouble) return true;
+ return false;
+ }
+
+ ScalarType ScalarTypeFunc::getScalarType(String pvalue) {
+ static String unknownString = "error unknown ScalarType";
+ if(pvalue.compare("boolean")==0) return pvBoolean;
+ if(pvalue.compare("byte")==0) return pvByte;
+ if(pvalue.compare("short")==0) return pvShort;
+ if(pvalue.compare("int")==0) return pvInt;
+ if(pvalue.compare("long")==0) return pvLong;
+ if(pvalue.compare("float")==0) return pvFloat;
+ if(pvalue.compare("double")==0) return pvDouble;
+ if(pvalue.compare("string")==0) return pvString;
+ throw std::invalid_argument(unknownString);
+ }
+ void ScalarTypeFunc::toString(StringBuilder buf,const ScalarType scalarType) {
+ static String unknownString = "logic error unknown ScalarType";
+ switch(scalarType) {
+ case pvBoolean : *buf += "boolean"; return;
+ case pvByte : *buf += "byte"; return;;
+ case pvShort : *buf += "short"; return;
+ case pvInt : *buf += "int"; return;
+ case pvLong : *buf += "long"; return;
+ case pvFloat : *buf += "float"; return;
+ case pvDouble : *buf += "double"; return;
+ case pvString : *buf += "string"; return;
+ }
+ throw std::invalid_argument(unknownString);
+ }
+
+
+}}
diff --git a/pvDataApp/misc/Makefile b/pvDataApp/misc/Makefile
index 91fc38a..548f06e 100644
--- a/pvDataApp/misc/Makefile
+++ b/pvDataApp/misc/Makefile
@@ -22,6 +22,7 @@ INC += timeFunction.h
INC += timer.h
INC += queueVoid.h
INC += queue.h
+INC += messageQueue.h
LIBSRCS += byteBuffer.cpp
LIBSRCS += bitSet.cpp
@@ -36,6 +37,7 @@ LIBSRCS += timeStamp.cpp
LIBSRCS += timeFunction.cpp
LIBSRCS += timer.cpp
LIBSRCS += queueVoid.cpp
+LIBSRCS += messageQueue.cpp
LIBRARY=pvMisc
diff --git a/pvDataApp/misc/messageQueue.cpp b/pvDataApp/misc/messageQueue.cpp
new file mode 100644
index 0000000..5743914
--- /dev/null
+++ b/pvDataApp/misc/messageQueue.cpp
@@ -0,0 +1,166 @@
+/* messageQueue.cpp */
+/**
+ * Copyright - See the COPYRIGHT that is included with this distribution.
+ * EPICS pvDataCPP is distributed subject to a Software License Agreement found
+ * in file LICENSE that is included with this distribution.
+ */
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include "pvType.h"
+#include "lock.h"
+#include "requester.h"
+#include "noDefaultMethods.h"
+#include "showConstructDestruct.h"
+#include "queue.h"
+#include "messageQueue.h"
+
+namespace epics { namespace pvData {
+
+static volatile int64 totalQueueConstruct = 0;
+static volatile int64 totalQueueDestruct = 0;
+static Mutex *globalMutex = 0;
+
+static int64 getTotalQueueConstruct()
+{
+ Lock xx(globalMutex);
+ return totalQueueConstruct;
+}
+
+static int64 getTotalQueueDestruct()
+{
+ Lock xx(globalMutex);
+ return totalQueueDestruct;
+}
+
+static ConstructDestructCallback *pCDCallbackQueue;
+
+static void initPvt()
+{
+ static Mutex mutex = Mutex();
+ Lock xx(&mutex);
+ if(globalMutex==0) {
+ globalMutex = new Mutex();
+ pCDCallbackQueue = new ConstructDestructCallback(
+ "messageQueue",
+ getTotalQueueConstruct,getTotalQueueDestruct,0);
+ }
+}
+
+typedef MessageNode * MessageNodePtr;
+typedef QueueElement MessageElement;
+typedef MessageElement *MessageElementPtr;
+typedef Queue MessageNodeQueue;
+
+
+MessageNode::MessageNode()
+: message(String("")),messageType(infoMessage){}
+
+MessageNode::~MessageNode() {}
+
+String MessageNode::getMessage() const { return message;};
+
+MessageType MessageNode::getMessageType() const { return messageType;}
+
+
+class MessageQueuePvt {
+public:
+ MessageNodePtr *messageNodeArray;
+ MessageNodeQueue *queue;
+ MessageNodePtr lastPut;
+ MessageElementPtr lastGet;
+ int size;
+ int overrun;
+};
+
+MessageQueue::MessageQueue(int size)
+: pImpl(new MessageQueuePvt)
+{
+ initPvt();
+ Lock xx(globalMutex);
+ totalQueueConstruct++;
+ pImpl->size = size;
+ pImpl->overrun = 0;
+ pImpl->lastPut = 0;
+ pImpl->lastGet = 0;
+ pImpl->messageNodeArray = new MessageNodePtr[size];
+ for(int i=0; imessageNodeArray[i] = new MessageNode();
+ }
+ pImpl->queue = new MessageNodeQueue(pImpl->messageNodeArray,size);
+}
+
+MessageQueue::~MessageQueue()
+{
+ delete pImpl->queue;
+ for(int i=0; i< pImpl->size; i++) {
+ delete pImpl->messageNodeArray[i];
+ }
+ delete[] pImpl->messageNodeArray;
+ initPvt();
+ Lock xx(globalMutex);
+ totalQueueDestruct++;
+}
+
+MessageNode *MessageQueue::get() {
+ if(pImpl->lastGet!=0) {
+ throw std::logic_error(
+ String("MessageQueue::get() but did not release last"));
+ }
+ MessageElementPtr element = pImpl->queue->getUsed();
+ if(element==0) return 0;
+ pImpl->lastGet = element;
+ return element->getObject();
+}
+
+void MessageQueue::release() {
+ if(pImpl->lastGet==0) return;
+ pImpl->queue->releaseUsed(pImpl->lastGet);
+ pImpl->lastGet = 0;
+}
+
+bool MessageQueue::put(String message,MessageType messageType,bool replaceLast)
+{
+ MessageElementPtr element = pImpl->queue->getFree();
+ if(element!=0) {
+ MessageNodePtr node = element->getObject();
+ node->message = message;
+ node->messageType = messageType;
+ pImpl->lastPut = node;
+ pImpl->queue->setUsed(element);
+ return true;
+ }
+ pImpl->overrun++;
+ if(replaceLast) {
+ MessageNodePtr node = pImpl->lastPut;
+ node->message = message;
+ node->messageType = messageType;
+ }
+ return false;
+}
+
+bool MessageQueue::isEmpty() const
+{
+ int free = pImpl->queue->getNumberFree();
+ if(free==pImpl->size) return true;
+ return false;
+}
+
+bool MessageQueue::isFull() const
+{
+ if(pImpl->queue->getNumberFree()==0) return true;
+ return false;
+}
+
+int MessageQueue::getClearOverrun()
+{
+ int num = pImpl->overrun;
+ pImpl->overrun = 0;
+ return num;
+}
+
+}}
diff --git a/pvDataApp/misc/messageQueue.h b/pvDataApp/misc/messageQueue.h
new file mode 100644
index 0000000..b029afe
--- /dev/null
+++ b/pvDataApp/misc/messageQueue.h
@@ -0,0 +1,49 @@
+/* messageQueue.h */
+/**
+ * Copyright - See the COPYRIGHT that is included with this distribution.
+ * EPICS pvDataCPP is distributed subject to a Software License Agreement found
+ * in file LICENSE that is included with this distribution.
+ */
+#ifndef MESSAGEQUEUE_H
+#define MESSAGEQUEUE_H
+#include "pvType.h"
+#include "requester.h"
+#include "noDefaultMethods.h"
+#include "showConstructDestruct.h"
+
+namespace epics { namespace pvData {
+
+class MessageNode {
+public:
+ String getMessage() const;
+ MessageType getMessageType() const;
+private:
+ MessageNode();
+ ~MessageNode();
+ friend class MessageQueue;
+ String message;
+ MessageType messageType;
+};
+
+class MessageQueue : private NoDefaultMethods {
+public:
+ MessageQueue(int size);
+ ~MessageQueue();
+ static ConstructDestructCallback *getConstructDestructCallback();
+ MessageNode *get();
+ // must call release before next get
+ void release();
+ // return (false,true) if message (was not, was) put into queue
+ bool put(String message,MessageType messageType,bool replaceLast);
+ bool isEmpty() const;
+ bool isFull() const;
+ int getClearOverrun();
+private:
+ class MessageQueuePvt *pImpl;
+};
+
+}}
+#endif /* MESSAGEQUEUE_H */
+
+
+
diff --git a/pvDataApp/misc/queue.h b/pvDataApp/misc/queue.h
index d7ac146..2b808d6 100644
--- a/pvDataApp/misc/queue.h
+++ b/pvDataApp/misc/queue.h
@@ -18,18 +18,19 @@ class QueueElement;
template
class QueueElement : private QueueElementVoid {
public:
+ T *getObject() { return static_cast(QueueElementVoid::getObject());}
+protected:
QueueElement(T *object) : QueueElementVoid(static_cast(object)){}
~QueueElement() {}
- T *getObject() { return static_cast(QueueElementVoid::getObject());}
friend class Queue;
};
template
class Queue : private QueueVoid {
public:
- Queue(QueueElement **array,int number)
- : QueueVoid((QueueElementVoid**)array,number)
- //: QueueVoid(static_cast(array),number)
+ Queue(T *array[],int number)
+ : QueueVoid((ObjectPtr*)array,number)
+ //: QueueVoid(static_cast(array),number)
{}
~Queue() {}
void clear() {QueueVoid::clear();}
diff --git a/pvDataApp/misc/queueVoid.cpp b/pvDataApp/misc/queueVoid.cpp
index 6a5af79..a33257e 100644
--- a/pvDataApp/misc/queueVoid.cpp
+++ b/pvDataApp/misc/queueVoid.cpp
@@ -67,7 +67,7 @@ static void initPvt()
}
-QueueElementVoid::QueueElementVoid(void *object)
+QueueElementVoid::QueueElementVoid(ObjectPtr object)
: object(object)
{
initPvt();
@@ -88,16 +88,21 @@ ConstructDestructCallback *QueueElementVoid::getConstructDestructCallback()
return pCDCallbackQueueNode;
}
-void *QueueElementVoid::getObject() {
+ObjectPtr QueueElementVoid::getObject() {
return object;
}
-QueueVoid::QueueVoid(QueueElementVoidPtrArray array,int number)
-: array(array),number(number),
+
+
+QueueVoid::QueueVoid(ObjectPtr object[],int number)
+: array(new QueueElementVoidPtr[number]),number(number),
numberFree(number),numberUsed(0),
nextGetFree(0),nextSetUsed(),
nextGetUsed(0),nextReleaseUsed(0)
{
+ for(int i=0; i
+#include
+#include
+#include
+#include
+
+#include
+
+#include "lock.h"
+#include "timeStamp.h"
+#include "requester.h"
+#include "messageQueue.h"
+#include "showConstructDestruct.h"
+#include "event.h"
+#include "thread.h"
+#include "executor.h"
+
+
+using namespace epics::pvData;
+
+static void testBasic(FILE * fd,FILE *auxfd ) {
+ int queueSize = 3;
+ int numMessages = 5;
+ String messages[]= {
+ String("1"),String("2"),String("3"),String("4"),String("5")
+ };
+ MessageQueue *queue = new MessageQueue(queueSize);
+ bool result;
+ MessageNode *messageNode;
+ result = queue->isEmpty();
+ assert(result);
+ result = queue->put(messages[0],infoMessage,true);
+ assert(result);
+ result = queue->put(messages[1],infoMessage,true);
+ assert(result);
+ result = queue->put(messages[2],infoMessage,true);
+ assert(result);
+ assert(queue->isFull());
+ result = queue->put(messages[3],infoMessage,true);
+ assert(result==false);
+ messageNode = queue->get();
+ assert(messageNode!=0);
+ fprintf(auxfd,"message %s messageType %s\n",
+ messageNode->getMessage().c_str(),
+ messageTypeName[messageNode->getMessageType()].c_str());
+ assert(messageNode->getMessage().compare(messages[0])==0);
+ queue->release();
+ messageNode = queue->get();
+ assert(messageNode!=0);
+ assert(messageNode->getMessage().compare(messages[1])==0);
+ queue->release();
+ messageNode = queue->get();
+ assert(messageNode!=0);
+ fprintf(auxfd,"message %s messageType %s\n",
+ messageNode->getMessage().c_str(),
+ messageTypeName[messageNode->getMessageType()].c_str());
+ assert(messageNode->getMessage().compare(messages[3])==0);
+ queue->release();
+ result = queue->isEmpty();
+ delete queue;
+}
+
+int main(int argc, char *argv[]) {
+ char *fileName = 0;
+ if(argc>1) fileName = argv[1];
+ FILE * fd = stdout;
+ if(fileName!=0 && fileName[0]!=0) {
+ fd = fopen(fileName,"w+");
+ }
+ char *auxFileName = 0;
+ if(argc>2) auxFileName = argv[2];
+ FILE *auxfd = stdout;
+ if(auxFileName!=0 && auxFileName[0]!=0) {
+ auxfd = fopen(auxFileName,"w+");
+ }
+ testBasic(fd,auxfd);
+ getShowConstructDestruct()->constuctDestructTotals(fd);
+ return (0);
+}
+
diff --git a/pvDataApp/miscTest/testQueue.cpp b/pvDataApp/miscTest/testQueue.cpp
index c0ab94f..da2402b 100644
--- a/pvDataApp/miscTest/testQueue.cpp
+++ b/pvDataApp/miscTest/testQueue.cpp
@@ -110,14 +110,13 @@ void Sink::run()
}
static void testBasic(FILE * fd,FILE *auxfd ) {
- Data dataArray[numElements];
- DataElement *array[numElements];
+ Data *dataArray[numElements];
for(int i=0; ia = i;
+ dataArray[i]->b = i*10;
}
- DataQueue *queue = new DataQueue(array,numElements);
+ DataQueue *queue = new DataQueue(dataArray,numElements);
Sink *sink = new Sink(queue,auxfd);
while(true) {
DataElement *element = queue->getFree();
@@ -139,7 +138,7 @@ static void testBasic(FILE * fd,FILE *auxfd ) {
sink->stop();
delete sink;
delete queue;
- for(int i=0; i
+#include
+#include "pvType.h"
+#include "pvIntrospect.h"
+#include "pvData.h"
+#include "alarm.h"
+namespace epics { namespace pvData {
+
+static String severityNames[4] =
+{
+ String("none"),
+ String("minor"),
+ String("major"),
+ String("invalid")
+};
+
+AlarmSeverity AlarmSeverityFunc::getSeverity(int value)
+{
+ if(value<0 || value>3) {
+ throw std::logic_error(String("getSeverity value is illegal"));
+ }
+ switch (value) {
+ case 0: return noAlarm;
+ case 1: return minorAlarm;
+ case 2: return majorAlarm;
+ case 3: return invalidAlarm;
+ }
+ throw std::logic_error(String("should never get here"));
+}
+
+StringArray AlarmSeverityFunc::getSeverityNames()
+{
+ return severityNames;
+}
+
+AlarmSeverity Alarm::getSeverity() const
+{
+ switch(severity) {
+ case 0: return noAlarm;
+ case 1: return minorAlarm;
+ case 2: return majorAlarm;
+ case 3: return invalidAlarm;
+ }
+ throw std::logic_error(String("should never get here"));
+}
+
+}}
diff --git a/pvDataApp/property/alarm.h b/pvDataApp/property/alarm.h
new file mode 100644
index 0000000..acaf8f7
--- /dev/null
+++ b/pvDataApp/property/alarm.h
@@ -0,0 +1,37 @@
+/* alarm.h */
+/**
+ * Copyright - See the COPYRIGHT that is included with this distribution.
+ * EPICS pvDataCPP is distributed subject to a Software License Agreement found
+ * in file LICENSE that is included with this distribution.
+ */
+#include
+#include "pvType.h"
+#ifndef ALARM_H
+#define ALARM_H
+namespace epics { namespace pvData {
+
+enum AlarmSeverity {
+ noAlarm,minorAlarm,majorAlarm,invalidAlarm
+};
+
+class AlarmSeverityFunc {
+public:
+ static AlarmSeverity getSeverity(int value);
+ static StringArray getSeverityNames();
+};
+
+class Alarm {
+public:
+ Alarm() : severity(0), message(String("")) {}
+ //default constructors and destructor are OK
+ String getMessage() const {return message;}
+ void setMessage(String value) {message = value;}
+ AlarmSeverity getSeverity() const;
+ void setSeverity(AlarmSeverity value) {severity = value;}
+private:
+ int32 severity;
+ String message;
+};
+
+}}
+#endif /* ALARM_H */
diff --git a/pvDataApp/property/control.h b/pvDataApp/property/control.h
new file mode 100644
index 0000000..a2b403e
--- /dev/null
+++ b/pvDataApp/property/control.h
@@ -0,0 +1,25 @@
+/* control.h */
+/**
+ * Copyright - See the COPYRIGHT that is included with this distribution.
+ * EPICS pvDataCPP is distributed subject to a Software License Agreement found
+ * in file LICENSE that is included with this distribution.
+ */
+#ifndef CONTROL_H
+#define CONTROL_H
+namespace epics { namespace pvData {
+
+class Control {
+public:
+ Control() : low(0.0), high(0.0) {}
+ //default constructors and destructor are OK
+ double getLow() const {return low;}
+ double getHigh() const {return high;}
+ void setLow(double value) {low = value;}
+ void setHigh(double value) {high = value;}
+private:
+ double low;
+ double high;
+};
+
+}}
+#endif /* CONTROL_H */
diff --git a/pvDataApp/property/display.h b/pvDataApp/property/display.h
new file mode 100644
index 0000000..15d34a2
--- /dev/null
+++ b/pvDataApp/property/display.h
@@ -0,0 +1,39 @@
+/* display.h */
+/**
+ * Copyright - See the COPYRIGHT that is included with this distribution.
+ * EPICS pvDataCPP is distributed subject to a Software License Agreement found
+ * in file LICENSE that is included with this distribution.
+ */
+#include
+#include "pvType.h"
+#include "pvData.h"
+#ifndef DISPLAY_H
+#define DISPLAY_H
+namespace epics { namespace pvData {
+
+class Display {
+public:
+ Display()
+ : description(String("")),format(String("")),units(String("")),
+ low(0.0),high(0.0) {}
+ //default constructors and destructor are OK
+ double getLow() const {return low;}
+ double getHigh() const{ return high;}
+ void setLow(double value){low = value;}
+ void setHigh(double value){high = value;}
+ String getDescription() const {return description;}
+ void setDescription(String value) {description = value;}
+ String getFormat() const {return format;}
+ void setFormat(String value) {format = value;}
+ String getUnits() const {return units;}
+ void setUnits(String value) {units = value;}
+private:
+ String description;
+ String format;
+ String units;
+ double low;
+ double high;
+};
+
+}}
+#endif /* DISPLAY_H */
diff --git a/pvDataApp/property/enumerated.cpp b/pvDataApp/property/enumerated.cpp
deleted file mode 100644
index 19e75fc..0000000
--- a/pvDataApp/property/enumerated.cpp
+++ /dev/null
@@ -1,67 +0,0 @@
-/* enumerated.cpp */
-/**
- * Copyright - See the COPYRIGHT that is included with this distribution.
- * EPICS pvDataCPP is distributed subject to a Software License Agreement found
- * in file LICENSE that is included with this distribution.
- */
-#include
-#include
-#include "pvType.h"
-#include "pvIntrospect.h"
-#include "pvData.h"
-#include "enumerated.h"
-#include "noDefaultMethods.h"
-namespace epics { namespace pvData {
-
-
-static String notStructure("field is not a structure");
-static String notEqual2("structure does not have exactly two fields");
-static String badIndex("structure does not have field index of type int");
-static String badChoices("structure does not have field choices of type stringArray");
-
-Enumerated* Enumerated::create(PVField *pvField){
- if(pvField->getField()->getType()!=structure) {
- pvField->message(notStructure,errorMessage);
- return 0;
- }
- PVStructure *pvStructure = (PVStructure*)pvField;
- int numberFields = pvStructure->getNumberFields();
- if(numberFields!=2) {
- pvField->message(notEqual2,errorMessage);
- return 0;
- }
- PVFieldPtrArray pvFields = pvStructure->getPVFields();
- FieldConstPtrArray fields = pvStructure->getStructure()->getFields();
- FieldConstPtr field = fields[0];
- if(field->getFieldName().compare("index")!=0 || field->getType()!=scalar) {
- pvField->message(badIndex,errorMessage);
- return 0;
- }
- PVInt *pvInt = (PVInt *) pvFields[0];
- field = fields[1];
- if(field->getFieldName().compare("choices")!=0 || field->getType()!=scalarArray) {
- pvField->message(badChoices,errorMessage);
- return 0;
- }
- ScalarArrayConstPtr pscalarArray = (ScalarArrayConstPtr)field;
- if(pscalarArray->getElementType()!=pvString) {
- pvField->message(badChoices,errorMessage);
- return 0;
- }
- PVStringArray *pvStringArray = (PVStringArray *) pvFields[1];
- return new Enumerated(pvStructure,pvInt,pvStringArray);
-}
-
-Enumerated::~Enumerated() {}
-
-Enumerated::Enumerated(
- PVStructure *pvStructure,PVInt *pvIndex,PVStringArray *pvChoices)
-: pvStructure(pvStructure),pvIndex(pvIndex),pvChoices(pvChoices),
- stringArrayData(StringArrayData()) {}
-
-String Enumerated::getChoice() {
- pvChoices->get(0, pvChoices->getLength(), &stringArrayData);
- return stringArrayData.data[pvIndex->get()];
-}
-
-}}
diff --git a/pvDataApp/property/pvAlarm.cpp b/pvDataApp/property/pvAlarm.cpp
new file mode 100644
index 0000000..c7138e1
--- /dev/null
+++ b/pvDataApp/property/pvAlarm.cpp
@@ -0,0 +1,82 @@
+/* pvAlarm.cpp */
+/**
+ * Copyright - See the COPYRIGHT that is included with this distribution.
+ * EPICS pvDataCPP is distributed subject to a Software License Agreement found
+ * in file LICENSE that is included with this distribution.
+ */
+#include
+#include
+#include "pvType.h"
+#include "pvIntrospect.h"
+#include "pvData.h"
+#include "pvAlarm.h"
+namespace epics { namespace pvData {
+
+static String noAlarmFound("No alarm structure found");
+static String notAttached("Not attached to an alarm structure");
+
+bool PVAlarm::attach(PVField *pvField)
+{
+ PVStructure *pvStructure = 0;
+ if(pvField->getField()->getFieldName().compare("alarm")!=0) {
+ PVStructure *pvParent = pvField->getParent();
+ if(pvParent==0) {
+ pvField->message(noAlarmFound,errorMessage);
+ return false;
+ }
+ pvStructure = pvParent->getStructureField(String("alarm"));
+ if(pvStructure==0) {
+ pvField->message(noAlarmFound,errorMessage);
+ return false;
+ }
+ } else {
+ if(pvField->getField()->getType()!=structure) {
+ pvField->message(noAlarmFound,errorMessage);
+ return false;
+ }
+ pvStructure = static_cast(pvField);
+ }
+ PVInt *pvInt = pvStructure->getIntField(String("severity"));
+ if(pvInt==0) {
+ pvField->message(noAlarmFound,errorMessage);
+ return false;
+ }
+ PVString *pvString = pvStructure->getStringField(String("message"));
+ if(pvInt==0) {
+ pvField->message(noAlarmFound,errorMessage);
+ return false;
+ }
+ pvSeverity = pvInt;
+ pvMessage = pvString;
+ return true;
+}
+
+void PVAlarm::detach()
+{
+ pvSeverity = 0;
+ pvMessage = 0;
+}
+
+Alarm PVAlarm::get() const
+{
+ if(pvSeverity==0 || pvMessage==0) {
+ throw std::logic_error(notAttached);
+ }
+ Alarm alarm;
+ alarm.setSeverity(AlarmSeverityFunc::getSeverity(pvSeverity->get()));
+ alarm.setMessage(pvMessage->get());
+ return alarm;
+}
+
+bool PVAlarm::set(Alarm alarm)
+{
+ if(pvSeverity==0 || pvMessage==0) {
+ throw std::logic_error(notAttached);
+ }
+ if(pvSeverity->isImmutable() || pvMessage->isImmutable()) return false;
+ pvSeverity->put(alarm.getSeverity());
+ pvMessage->put(alarm.getMessage());
+ return true;
+}
+
+}}
diff --git a/pvDataApp/property/pvAlarm.h b/pvDataApp/property/pvAlarm.h
new file mode 100644
index 0000000..49f99b4
--- /dev/null
+++ b/pvDataApp/property/pvAlarm.h
@@ -0,0 +1,32 @@
+/* pvAlarm.h */
+/**
+ * Copyright - See the COPYRIGHT that is included with this distribution.
+ * EPICS pvDataCPP is distributed subject to a Software License Agreement found
+ * in file LICENSE that is included with this distribution.
+ */
+#include
+#include "pvType.h"
+#include "alarm.h"
+#ifndef PVALARM_H
+#define PVALARM_H
+namespace epics { namespace pvData {
+
+class PVAlarm {
+public:
+ PVAlarm() : pvSeverity(0),pvMessage(0) {}
+ //default constructors and destructor are OK
+ //returns (false,true) if pvField(isNot, is valid enumerated structure
+ //An automatic detach is issued if already attached.
+ bool attach(PVField *pvField);
+ void detach();
+ // each of the following throws logic_error is not attached to PVField
+ // set returns false if field is immutable
+ Alarm get() const;
+ bool set(Alarm alarm);
+private:
+ PVInt *pvSeverity;
+ PVString *pvMessage;
+};
+
+}}
+#endif /* PVALARM_H */
diff --git a/pvDataApp/property/pvControl.cpp b/pvDataApp/property/pvControl.cpp
new file mode 100644
index 0000000..1d58501
--- /dev/null
+++ b/pvDataApp/property/pvControl.cpp
@@ -0,0 +1,83 @@
+/* pvControl.cpp */
+/**
+ * Copyright - See the COPYRIGHT that is included with this distribution.
+ * EPICS pvDataCPP is distributed subject to a Software License Agreement found
+ * in file LICENSE that is included with this distribution.
+ */
+#include
+#include
+#include "pvType.h"
+#include "pvIntrospect.h"
+#include "pvData.h"
+#include "pvControl.h"
+namespace epics { namespace pvData {
+
+static String noControlFound("No control structure found");
+static String notAttached("Not attached to an control structure");
+
+bool PVControl::attach(PVField *pvField)
+{
+ PVStructure *pvStructure = 0;
+ if(pvField->getField()->getFieldName().compare("control")!=0) {
+ PVStructure *pvParent = pvField->getParent();
+ if(pvParent==0) {
+ pvField->message(noControlFound,errorMessage);
+ return false;
+ }
+ pvStructure = pvParent->getStructureField(String("control"));
+ if(pvStructure==0) {
+ pvField->message(noControlFound,errorMessage);
+ return false;
+ }
+ } else {
+ if(pvField->getField()->getType()!=structure) {
+ pvField->message(noControlFound,errorMessage);
+ return false;
+ }
+ pvStructure = static_cast(pvField);
+ }
+ PVDouble *pvDouble = pvStructure->getDoubleField(String("limit.low"));
+ if(pvDouble==0) {
+ pvField->message(noControlFound,errorMessage);
+ return false;
+ }
+ pvLow = pvDouble;
+ pvDouble = pvStructure->getDoubleField(String("limit.high"));
+ if(pvDouble==0) {
+ pvLow = 0;
+ pvField->message(noControlFound,errorMessage);
+ return false;
+ }
+ pvHigh = pvDouble;
+ return true;
+}
+
+void PVControl::detach()
+{
+ pvLow = 0;
+ pvHigh = 0;
+}
+
+Control PVControl::get() const
+{
+ if(pvLow==0 || pvHigh==0) {
+ throw std::logic_error(notAttached);
+ }
+ Control control;
+ control.setLow(pvLow->get());
+ control.setHigh(pvHigh->get());
+ return control;
+}
+
+bool PVControl::set(Control control)
+{
+ if(pvLow==0 || pvHigh==0) {
+ throw std::logic_error(notAttached);
+ }
+ if(pvLow->isImmutable() || pvHigh->isImmutable()) return false;
+ pvLow->put(control.getLow());
+ pvHigh->put(control.getHigh());
+ return true;
+}
+
+}}
diff --git a/pvDataApp/property/pvControl.h b/pvDataApp/property/pvControl.h
new file mode 100644
index 0000000..952c2c3
--- /dev/null
+++ b/pvDataApp/property/pvControl.h
@@ -0,0 +1,31 @@
+/* pvControl.h */
+/**
+ * Copyright - See the COPYRIGHT that is included with this distribution.
+ * EPICS pvDataCPP is distributed subject to a Software License Agreement found
+ * in file LICENSE that is included with this distribution.
+ */
+#include "control.h"
+#include "pvData.h"
+#ifndef PVCONTROL_H
+#define PVCONTROL_H
+namespace epics { namespace pvData {
+
+class PVControl {
+public:
+ PVControl() : pvLow(0),pvHigh(0) {}
+ //default constructors and destructor are OK
+ //returns (false,true) if pvField(isNot, is valid enumerated structure
+ //An automatic detach is issued if already attached.
+ bool attach(PVField *pvField);
+ void detach();
+ // each of the following throws logic_error is not attached to PVField
+ // set returns false if field is immutable
+ Control get() const;
+ bool set(Control control);
+private:
+ PVDouble *pvLow;
+ PVDouble *pvHigh;
+};
+
+}}
+#endif /* PVCONTROL_H */
diff --git a/pvDataApp/property/pvDisplay.cpp b/pvDataApp/property/pvDisplay.cpp
new file mode 100644
index 0000000..146957b
--- /dev/null
+++ b/pvDataApp/property/pvDisplay.cpp
@@ -0,0 +1,109 @@
+/* pvDisplay.cpp */
+/**
+ * Copyright - See the COPYRIGHT that is included with this distribution.
+ * EPICS pvDataCPP is distributed subject to a Software License Agreement found
+ * in file LICENSE that is included with this distribution.
+ */
+#include
+#include
+#include "pvType.h"
+#include "pvIntrospect.h"
+#include "pvData.h"
+#include "pvDisplay.h"
+namespace epics { namespace pvData {
+
+static String noDisplayFound("No display structure found");
+static String notAttached("Not attached to an display structure");
+
+bool PVDisplay::attach(PVField *pvField)
+{
+ PVStructure *pvStructure = 0;
+ if(pvField->getField()->getFieldName().compare("display")!=0) {
+ PVStructure *pvParent = pvField->getParent();
+ if(pvParent==0) {
+ pvField->message(noDisplayFound,errorMessage);
+ return false;
+ }
+ pvStructure = pvParent->getStructureField(String("display"));
+ if(pvStructure==0) {
+ pvField->message(noDisplayFound,errorMessage);
+ return false;
+ }
+ } else {
+ if(pvField->getField()->getType()!=structure) {
+ pvField->message(noDisplayFound,errorMessage);
+ return false;
+ }
+ pvStructure = static_cast(pvField);
+ }
+ pvDescription = pvStructure->getStringField(String("description"));
+ if(pvDescription==0) {
+ pvField->message(noDisplayFound,errorMessage);
+ return false;
+ }
+ pvFormat = pvStructure->getStringField(String("format"));
+ if(pvFormat==0) {
+ pvField->message(noDisplayFound,errorMessage);
+ detach();
+ return false;
+ }
+ pvUnits = pvStructure->getStringField(String("units"));
+ if(pvUnits==0) {
+ pvField->message(noDisplayFound,errorMessage);
+ detach();
+ return false;
+ }
+ pvLow = pvStructure->getDoubleField(String("limit.low"));
+ if(pvLow==0) {
+ pvField->message(noDisplayFound,errorMessage);
+ detach();
+ return false;
+ }
+ pvHigh = pvStructure->getDoubleField(String("limit.high"));
+ if(pvHigh==0) {
+ pvField->message(noDisplayFound,errorMessage);
+ detach();
+ return false;
+ }
+ return true;
+}
+
+void PVDisplay::detach()
+{
+ pvDescription = 0;
+ pvFormat = 0;
+ pvUnits = 0;
+ pvLow = 0;
+ pvHigh = 0;
+}
+
+Display PVDisplay::get() const
+{
+ if(pvDescription==0 || pvFormat==0 || pvUnits==0 || pvLow==0 || pvHigh==0) {
+ throw std::logic_error(notAttached);
+ }
+ Display display;
+ display.setDescription(pvDescription->get());
+ display.setFormat(pvFormat->get());
+ display.setUnits(pvUnits->get());
+ display.setLow(pvLow->get());
+ display.setHigh(pvHigh->get());
+ return display;
+}
+
+bool PVDisplay::set(Display display)
+{
+ if(pvDescription==0 || pvFormat==0 || pvUnits==0 || pvLow==0 || pvHigh==0) {
+ throw std::logic_error(notAttached);
+ }
+ if(pvDescription->isImmutable() || pvFormat->isImmutable()) return false;
+ if(pvUnits->isImmutable() || pvLow->isImmutable() || pvHigh->isImmutable()) return false;
+ pvDescription->put(display.getDescription());
+ pvFormat->put(display.getFormat());
+ pvUnits->put(display.getUnits());
+ pvLow->put(display.getLow());
+ pvHigh->put(display.getHigh());
+ return true;
+}
+
+}}
diff --git a/pvDataApp/property/pvDisplay.h b/pvDataApp/property/pvDisplay.h
new file mode 100644
index 0000000..ff1947d
--- /dev/null
+++ b/pvDataApp/property/pvDisplay.h
@@ -0,0 +1,36 @@
+/* pvDisplay.h */
+/**
+ * Copyright - See the COPYRIGHT that is included with this distribution.
+ * EPICS pvDataCPP is distributed subject to a Software License Agreement found
+ * in file LICENSE that is included with this distribution.
+ */
+#include
+#include "pvType.h"
+#include "pvData.h"
+#include "display.h"
+#ifndef PVDISPLAY_H
+#define PVDISPLAY_H
+namespace epics { namespace pvData {
+
+class PVDisplay {
+public:
+ PVDisplay()
+ : pvDescription(0),pvFormat(),pvUnits(),pvLow(),pvHigh() {}
+ //default constructors and destructor are OK
+ //An automatic detach is issued if already attached.
+ bool attach(PVField *pvField);
+ void detach();
+ // each of the following throws logic_error is not attached to PVField
+ // a set returns false if field is immutable
+ Display get() const;
+ bool set(Display display);
+private:
+ PVString *pvDescription;
+ PVString *pvFormat;
+ PVString *pvUnits;
+ PVDouble *pvLow;
+ PVDouble *pvHigh;
+};
+
+}}
+#endif /* PVDISPLAY_H */
diff --git a/pvDataApp/property/pvEnumerated.cpp b/pvDataApp/property/pvEnumerated.cpp
new file mode 100644
index 0000000..f2b28af
--- /dev/null
+++ b/pvDataApp/property/pvEnumerated.cpp
@@ -0,0 +1,115 @@
+/* pvEnumerated.cpp */
+/**
+ * Copyright - See the COPYRIGHT that is included with this distribution.
+ * EPICS pvDataCPP is distributed subject to a Software License Agreement found
+ * in file LICENSE that is included with this distribution.
+ */
+#include
+#include
+#include "pvType.h"
+#include "pvIntrospect.h"
+#include "pvData.h"
+#include "pvEnumerated.h"
+namespace epics { namespace pvData {
+
+
+static String notStructure("field is not a structure");
+static String notEnumerated("field is not an enumerated structure");
+static String notAttached("Not attached to an enumerated structure");
+
+bool PVEnumerated::attach(PVField *pvField)
+{
+ if(pvField->getField()->getType()!=structure) {
+ pvField->message(notStructure,errorMessage);
+ return false;
+ }
+ PVStructure *pvStructure = static_cast(pvField);
+ PVInt *pvInt = pvStructure->getIntField(String("index"));
+ if(pvLong==0) {
+ pvField->message(notEnumerated,errorMessage);
+ return false;
+ }
+ PVScalarArray *pvScalarArray = pvStructure->getScalarArrayField(
+ String("choices"),pvString);
+ if(pvScalarArray==0) {
+ pvField->message(notEnumerated,errorMessage);
+ return false;
+ }
+ pvIndex = pvInt;
+ pvChoices = static_cast(pvScalarArray);
+ return true;
+}
+
+void PVEnumerated::detach()
+{
+ pvIndex = 0;
+ pvChoices = 0;
+}
+
+bool PVEnumerated::setIndex(int32 index)
+{
+ if(pvIndex==0 || pvChoices==0) {
+ throw std::logic_error(notAttached);
+ }
+ if(pvIndex->isImmutable()) return false;
+ pvIndex->put(index);
+ return true;
+}
+
+int32 PVEnumerated::getIndex()
+{
+ if(pvIndex==0 || pvChoices==0) {
+ throw std::logic_error(notAttached);
+ }
+ return pvIndex->get();
+}
+
+String PVEnumerated::getChoice()
+{
+ if(pvIndex==0 || pvChoices==0) {
+ throw std::logic_error(notAttached);
+ }
+ int index = pvIndex->get();
+ StringArrayData data;
+ pvChoices->get(0,pvChoices->getLength(),&data);
+ return data.data[index];
+}
+
+bool PVEnumerated::choicesMutable()
+{
+ if(pvIndex==0 || pvChoices==0) {
+ throw std::logic_error(notAttached);
+ }
+ return pvChoices->isImmutable();
+}
+
+StringArray PVEnumerated:: getChoices()
+{
+ if(pvIndex==0 || pvChoices==0) {
+ throw std::logic_error(notAttached);
+ }
+ StringArrayData data;
+ pvChoices->get(0,pvChoices->getLength(),&data);
+ return data.data;
+}
+
+int32 PVEnumerated::getNumberChoices()
+{
+ if(pvIndex==0 || pvChoices==0) {
+ throw std::logic_error(notAttached);
+ }
+ return pvChoices->getLength();
+}
+
+bool PVEnumerated:: setChoices(StringArray choices,int32 numberChoices)
+{
+ if(pvIndex==0 || pvChoices==0) {
+ throw std::logic_error(notAttached);
+ }
+ if(pvChoices->isImmutable()) return false;
+ pvChoices->put(0,numberChoices,choices,0);
+ return true;
+}
+
+
+}}
diff --git a/pvDataApp/property/enumerated.h b/pvDataApp/property/pvEnumerated.h
similarity index 65%
rename from pvDataApp/property/enumerated.h
rename to pvDataApp/property/pvEnumerated.h
index 6b9a3dd..8bddbdc 100644
--- a/pvDataApp/property/enumerated.h
+++ b/pvDataApp/property/pvEnumerated.h
@@ -1,38 +1,38 @@
-/* enumerated.h */
+/* pvEnumerated.h */
/**
* Copyright - See the COPYRIGHT that is included with this distribution.
* EPICS pvDataCPP is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
*/
#include
-#include "pvTypes.h"
+#include "pvType.h"
#include "pvData.h"
-#ifndef ENUMERATED_H
-#define ENUMERATED_H
-#include "noDefaultMethods.h"
+#ifndef PVENUMERATED_H
+#define PVENUMERATED_H
namespace epics { namespace pvData {
-class Enumerated ;
+class PVEnumerated {
public:
+ PVEnumerated() : pvIndex(0), pvChoices(0) {}
//default constructors and destructor are OK
//This class should not be extended
-
//returns (false,true) if pvField(isNot, is valid enumerated structure
+ //An automatic detach is issued if already attached.
bool attach(PVField *pvField);
- ~Enumerated();
+ void detach();
// each of the following throws logic_error is not attached to PVField
- void putIndex(int32 index);
+ // a set returns false if field is immutable
+ bool setIndex(int32 index);
int32 getIndex();
String getChoice();
bool choicesMutable();
StringArray getChoices();
int32 getNumberChoices();
- // also throws logic_error of immutable
- void putChoices(StringArray choices,int32 numberChoices);
+ bool setChoices(StringArray choices,int32 numberChoices);
private:
PVInt *pvIndex;
PVStringArray *pvChoices;
};
}}
-#endif /* ENUMERATED_H */
+#endif /* PVENUMERATED_H */
diff --git a/pvDataApp/property/pvTimeStamp.cpp b/pvDataApp/property/pvTimeStamp.cpp
new file mode 100644
index 0000000..22e7ca7
--- /dev/null
+++ b/pvDataApp/property/pvTimeStamp.cpp
@@ -0,0 +1,81 @@
+/* pvTimeStamp.cpp */
+/**
+ * Copyright - See the COPYRIGHT that is included with this distribution.
+ * EPICS pvDataCPP is distributed subject to a Software License Agreement found
+ * in file LICENSE that is included with this distribution.
+ */
+#include
+#include
+#include "pvType.h"
+#include "timeStamp.h"
+#include "pvData.h"
+#include "pvTimeStamp.h"
+namespace epics { namespace pvData {
+
+static String noTimeStamp("No timeStamp structure found");
+static String notAttached("Not attached to a timeStamp structure");
+
+bool PVTimeStamp::attach(PVField *pvField)
+{
+ PVStructure *pvStructure = 0;
+ if(pvField->getField()->getFieldName().compare("timeStamp")!=0) {
+ PVStructure *pvParent = pvField->getParent();
+ if(pvParent==0) {
+ pvField->message(noTimeStamp,errorMessage);
+ return false;
+ }
+ pvStructure = pvParent->getStructureField(String("timeStamp"));
+ if(pvStructure==0) {
+ pvField->message(noTimeStamp,errorMessage);
+ return false;
+ }
+ } else {
+ if(pvField->getField()->getType()!=structure) {
+ pvField->message(noTimeStamp,errorMessage);
+ return false;
+ }
+ pvStructure = static_cast(pvField);
+ }
+ PVLong *pvLong = pvStructure->getLongField(String("secondsPastEpoch"));
+ if(pvLong==0) {
+ pvField->message(noTimeStamp,errorMessage);
+ return false;
+ }
+ PVInt *pvInt = pvStructure->getIntField(String("nanoSeconds"));
+ if(pvLong==0) {
+ pvField->message(noTimeStamp,errorMessage);
+ return false;
+ }
+ pvSecs = pvLong;
+ pvNano = pvInt;
+ return true;
+}
+
+void PVTimeStamp::detach()
+{
+ pvSecs = 0;
+ pvNano = 0;
+}
+
+TimeStamp PVTimeStamp::get() const
+{
+ if(pvSecs==0 || pvNano==0) {
+ throw std::logic_error(notAttached);
+ }
+ TimeStamp timeStamp;
+ timeStamp.put(pvSecs->get(),pvNano->get());
+ return timeStamp;
+}
+
+bool PVTimeStamp::set(TimeStamp timeStamp)
+{
+ if(pvSecs==0 || pvNano==0) {
+ throw std::logic_error(notAttached);
+ }
+ if(pvSecs->isImmutable() || pvNano->isImmutable()) return false;
+ pvSecs->put(timeStamp.getSecondsPastEpoch());
+ pvNano->put(timeStamp.getNanoSeconds());
+ return true;
+}
+
+}}
diff --git a/pvDataApp/property/pvTimeStamp.h b/pvDataApp/property/pvTimeStamp.h
index a0547de..2c3eb48 100644
--- a/pvDataApp/property/pvTimeStamp.h
+++ b/pvDataApp/property/pvTimeStamp.h
@@ -6,24 +6,26 @@
*/
#include
#include
-#ifndef PVTIMESTAMP_H
-#define PVTIMESTAMP_H
-#include "pvTypes.h"
+#include "pvType.h"
#include "timeStamp.h"
#include "pvData.h"
+#ifndef PVTIMESTAMP_H
+#define PVTIMESTAMP_H
namespace epics { namespace pvData {
class PVTimeStamp {
public:
+ PVTimeStamp() : pvSecs(0),pvNano(0) {}
//default constructors and destructor are OK
//This class should not be extended
//returns (false,true) if pvField(isNot, is valid timeStamp structure
bool attach(PVField *pvField);
- // throws logic_error is not attached to PVField
- TimeStamp &get();
- // throws logic_error is not attached to PVField
- void put (TimeStamp &timeStamp);
+ void detach();
+ // following throw logic_error is not attached to PVField
+ // a set returns false if field is immutable
+ TimeStamp get() const;
+ bool set(TimeStamp timeStamp);
private:
PVLong* pvSecs;
PVInt* pvNano;
diff --git a/pvDataApp/propertyTest/306 b/pvDataApp/propertyTest/306
new file mode 100644
index 0000000..993ba9d
--- /dev/null
+++ b/pvDataApp/propertyTest/306
@@ -0,0 +1,311 @@
+/* testPVdata.cpp */
+/**
+ * Copyright - See the COPYRIGHT that is included with this distribution.
+ * EPICS pvDataCPP is distributed subject to a Software License Agreement found
+ * in file LICENSE that is included with this distribution.
+ */
+/* Author: Marty Kraimer Date: 2010.11 */
+
+#include
+#include
+#include
+#include
+#include
+
+#include
+
+#include "requester.h"
+#include "pvIntrospect.h"
+#include "pvData.h"
+#include "convert.h"
+#include "standardField.h"
+#include "standardPVField.h"
+#include "alarm.h"
+#include "control.h"
+#include "display.h"
+#include "timeStamp.h"
+#include "pvAlarm.h"
+#include "pvControl.h"
+#include "pvDisplay.h"
+#include "pvEnumerated.h"
+#include "pvTimeStamp.h"
+#include "showConstructDestruct.h"
+
+using namespace epics::pvData;
+
+static FieldCreate * fieldCreate = 0;
+static PVDataCreate * pvDataCreate = 0;
+static StandardField *standardField = 0;
+static StandardPVField *standardPVField = 0;
+static Convert *convert = 0;
+static String builder("");
+static String alarmTimeStamp("alarm,timeStamp");
+static String alarmTimeStampValueAlarm("alarm,timeStamp,valueAlarm");
+static String allProperties("alarm,timeStamp,display,control,valueAlarm");
+
+static PVStructure *doubleRecord = 0;
+static PVStructure *enumeratedRecord = 0;
+
+static void createRecords(FILE * fd,String fieldName,ScalarType stype)
+{
+ doubleRecord = standardPVField->scalarValue(0,pvDouble,allProperties);
+ builder.clear();
+ doubleRecord->toString(&builder);
+ fprintf(fd,"%s\n",builder.c_str());
+ String choices[4] = {
+ String("0"),String("1"),String("2"),String("3")
+ };
+ enumeratedRecord = standardPVField->enumeratedValue(0,choices,alarmTimeStamp);
+ builder.clear();
+ enumeratedRecord->toString(&builder);
+ fprintf(fd,"%s\n",builder.c_str());
+}
+
+static void deleteRecords(FILE * fd,String fieldName,ScalarType stype)
+{
+ delete doubleRecord;
+ delete enumeratedRecord;
+}
+
+static void testPVScalarCommon(FILE * fd,String fieldName,ScalarType stype)
+{
+ PVScalar *pvScalar = standardPVField->scalar(0,fieldName,stype);
+ if(stype==pvBoolean) {
+ convert->fromString(pvScalar,String("true"));
+ } else {
+ convert->fromString(pvScalar,String("10"));
+ }
+ builder.clear();
+ pvScalar->toString(&builder);
+ fprintf(fd,"%s\n",builder.c_str());
+ delete pvScalar;
+}
+
+static void testPVScalarWithProperties(
+ FILE * fd,String fieldName,ScalarType stype)
+{
+ PVStructure *pvStructure = 0;
+ bool hasValueAlarm = false;
+ bool hasDisplayControl = false;
+ switch(stype) {
+ case pvBoolean: {
+ pvStructure = standardPVField->scalar(
+ 0,fieldName,stype,alarmTimeStampValueAlarm);
+ hasValueAlarm = true;
+ PVBoolean *pvField = pvStructure->getBooleanField(String("value"));
+ pvField->put(true);
+ break;
+ }
+ case pvByte: {
+ pvStructure = standardPVField->scalar(
+ 0,fieldName,stype,allProperties);
+ hasValueAlarm = true;
+ hasDisplayControl = true;
+ PVByte *pvField = pvStructure->getByteField(String("value"));
+ pvField->put(127);
+ break;
+ }
+ case pvShort: {
+ pvStructure = standardPVField->scalar(
+ 0,fieldName,stype,allProperties);
+ hasValueAlarm = true;
+ hasDisplayControl = true;
+ PVShort *pvField = pvStructure->getShortField(String("value"));
+ pvField->put(32767);
+ break;
+ }
+ case pvInt: {
+ pvStructure = standardPVField->scalar(
+ 0,fieldName,stype,allProperties);
+ hasValueAlarm = true;
+ hasDisplayControl = true;
+ PVInt *pvField = pvStructure->getIntField(String("value"));
+ pvField->put((int)0x80000000);
+ break;
+ }
+ case pvLong: {
+ pvStructure = standardPVField->scalar(
+ 0,fieldName,stype,allProperties);
+ hasValueAlarm = true;
+ hasDisplayControl = true;
+ PVLong *pvField = pvStructure->getLongField(String("value"));
+ int64 value = 0x80000000;
+ value <<= 32;
+ value |= 0xffffffff;
+ pvField->put(value);
+ break;
+ }
+ case pvFloat: {
+ pvStructure = standardPVField->scalar(
+ 0,fieldName,stype,allProperties);
+ hasValueAlarm = true;
+ hasDisplayControl = true;
+ PVFloat *pvField = pvStructure->getFloatField(String("value"));
+ pvField->put(1.123e8);
+ break;
+ }
+ case pvDouble: {
+ pvStructure = standardPVField->scalar(
+ 0,fieldName,stype,allProperties);
+ hasValueAlarm = true;
+ hasDisplayControl = true;
+ PVDouble *pvField = pvStructure->getDoubleField(String("value"));
+ pvField->put(1.123e35);
+ break;
+ }
+ case pvString: {
+ pvStructure = standardPVField->scalar(
+ 0,fieldName,stype,alarmTimeStamp);
+ PVString *pvField = pvStructure->getStringField(String("value"));
+ pvField->put(String("this is a string"));
+ break;
+ }
+ }
+ PVLong *seconds = pvStructure->getLongField(
+ String("timeStamp.secondsPastEpoch"));
+ assert(seconds!=0);
+ seconds->put(123456789);
+ PVInt *nano = pvStructure->getIntField(String("timeStamp.nanoSeconds"));
+ assert(nano!=0);
+ nano->put(1000000);
+ PVInt *severity = pvStructure->getIntField(String("alarm.severity"));
+ assert(severity!=0);
+ severity->put(2);
+ PVString *message = pvStructure->getStringField(String("alarm.message"));
+ assert(message!=0);
+ message->put(String("messageForAlarm"));
+ if(hasDisplayControl) {
+ PVString *desc = pvStructure->getStringField(
+ String("display.description"));
+ assert(desc!=0);
+ desc->put(String("this is a description"));
+ PVString *format = pvStructure->getStringField(
+ String("display.format"));
+ assert(format!=0);
+ format->put(String("f10.2"));
+ PVString *units = pvStructure->getStringField(
+ String("display.units"));
+ assert(units!=0);
+ units->put(String("SomeUnits"));
+ PVDouble *limit = pvStructure->getDoubleField(
+ String("display.limit.low"));
+ assert(limit!=0);
+ limit->put(0.0);
+ limit = pvStructure->getDoubleField(
+ String("display.limit.high"));
+ assert(limit!=0);
+ limit->put(10.0);
+ limit = pvStructure->getDoubleField(
+ String("control.limit.low"));
+ assert(limit!=0);
+ limit->put(1.0);
+ limit = pvStructure->getDoubleField(
+ String("control.limit.high"));
+ assert(limit!=0);
+ limit->put(9.0);
+ PVScalar *pvtemp = (PVScalar *)pvStructure->getSubField(
+ String("valueAlarm.lowAlarmLimit"));
+ assert(pvtemp!=0);
+ convert->fromDouble(pvtemp,1.0);
+ pvtemp = (PVScalar *)pvStructure->getSubField(
+ String("valueAlarm.highAlarmLimit"));
+ assert(pvtemp!=0);
+ convert->fromDouble(pvtemp,9.0);
+ severity = pvStructure->getIntField(
+ String("valueAlarm.lowAlarmSeverity"));
+ assert(severity!=0);
+ severity->put(2);
+ severity = pvStructure->getIntField(
+ String("valueAlarm.highAlarmSeverity"));
+ assert(severity!=0);
+ severity->put(2);
+ PVBoolean *active = pvStructure->getBooleanField(
+ String("valueAlarm.active"));
+ assert(active!=0);
+ active->put(true);
+ }
+ builder.clear();
+ pvStructure->toString(&builder);
+ fprintf(fd,"%s\n",builder.c_str());
+ delete pvStructure;
+}
+
+static void testPVScalar(FILE * fd) {
+ fprintf(fd,"\ntestScalar\n");
+ testPVScalarCommon(fd,String("boolean"),pvBoolean);
+ testPVScalarCommon(fd,String("byte"),pvByte);
+ testPVScalarCommon(fd,String("short"),pvShort);
+ testPVScalarCommon(fd,String("int"),pvInt);
+ testPVScalarCommon(fd,String("long"),pvLong);
+ testPVScalarCommon(fd,String("float"),pvFloat);
+ testPVScalarCommon(fd,String("double"),pvDouble);
+ testPVScalarCommon(fd,String("string"),pvString);
+
+ testPVScalarWithProperties(fd,String("boolean"),pvBoolean);
+ testPVScalarWithProperties(fd,String("byte"),pvByte);
+ testPVScalarWithProperties(fd,String("short"),pvShort);
+ testPVScalarWithProperties(fd,String("int"),pvInt);
+ testPVScalarWithProperties(fd,String("long"),pvLong);
+ testPVScalarWithProperties(fd,String("float"),pvFloat);
+ testPVScalarWithProperties(fd,String("double"),pvDouble);
+ testPVScalarWithProperties(fd,String("string"),pvString);
+}
+
+static void testScalarArrayCommon(FILE * fd,String fieldName,ScalarType stype)
+{
+ PVStructure *pvStructure = standardPVField->scalarArray(
+ 0,fieldName,stype,alarmTimeStamp);
+ PVScalarArray *scalarArray = pvStructure->getScalarArrayField(
+ String("value"),stype);
+ assert(scalarArray!=0);
+ if(stype==pvBoolean) {
+ String values[] = {String("true"),String("false"),String("true")};
+ convert->fromStringArray(scalarArray, 0,3,values,0);
+ } else {
+ String values[] = {String("0"),String("1"),String("2")};
+ convert->fromStringArray(scalarArray, 0,3,values,0);
+ }
+ builder.clear();
+ pvStructure->toString(&builder);
+ fprintf(fd,"%s\n",builder.c_str());
+ delete pvStructure;
+}
+
+static void testScalarArray(FILE * fd) {
+ fprintf(fd,"\ntestScalarArray\n");
+ testScalarArrayCommon(fd,String("boolean"),pvBoolean);
+ testScalarArrayCommon(fd,String("byte"),pvByte);
+ testScalarArrayCommon(fd,String("short"),pvShort);
+ testScalarArrayCommon(fd,String("int"),pvInt);
+ testScalarArrayCommon(fd,String("long"),pvLong);
+ testScalarArrayCommon(fd,String("float"),pvFloat);
+ testScalarArrayCommon(fd,String("double"),pvDouble);
+ testScalarArrayCommon(fd,String("string"),pvString);
+}
+
+
+int main(int argc,char *argv[])
+{
+ char *fileName = 0;
+ if(argc>1) fileName = argv[1];
+ FILE * fd = stdout;
+ if(fileName!=0 && fileName[0]!=0) {
+ fd = fopen(fileName,"w+");
+ }
+ char *auxFileName = 0;
+ if(argc>2) auxFileName = argv[2];
+ FILE *auxfd = stdout;
+ if(auxFileName!=0 && auxFileName[0]!=0) {
+ auxfd = fopen(auxFileName,"w+");
+ }
+ fieldCreate = getFieldCreate();
+ pvDataCreate = getPVDataCreate();
+ standardField = getStandardField();
+ standardPVField = getStandardPVField();
+ convert = getConvert();
+ createRecords(fd,auxfd);
+ deleteRecords(fd,auxfd);
+ getShowConstructDestruct()->constuctDestructTotals(fd);
+ return(0);
+}
+
diff --git a/pvDataApp/propertyTest/Makefile b/pvDataApp/propertyTest/Makefile
new file mode 100644
index 0000000..1cb48a9
--- /dev/null
+++ b/pvDataApp/propertyTest/Makefile
@@ -0,0 +1,13 @@
+TOP=../..
+
+include $(TOP)/configure/CONFIG
+
+PROD_HOST += testProperty
+testProperty_SRCS += testProperty.cpp
+testProperty_LIBS += pvFactory pvMisc pvProperty Com
+
+
+include $(TOP)/configure/RULES
+#----------------------------------------
+# ADD RULES AFTER THIS LINE
+
diff --git a/pvDataApp/propertyTest/testProperty.cpp b/pvDataApp/propertyTest/testProperty.cpp
new file mode 100644
index 0000000..5cf30d9
--- /dev/null
+++ b/pvDataApp/propertyTest/testProperty.cpp
@@ -0,0 +1,249 @@
+/* testPVdata.cpp */
+/**
+ * Copyright - See the COPYRIGHT that is included with this distribution.
+ * EPICS pvDataCPP is distributed subject to a Software License Agreement found
+ * in file LICENSE that is included with this distribution.
+ */
+/* Author: Marty Kraimer Date: 2010.11 */
+
+#include
+#include
+#include
+#include
+#include
+
+#include
+
+#include "requester.h"
+#include "pvIntrospect.h"
+#include "pvData.h"
+#include "convert.h"
+#include "standardField.h"
+#include "standardPVField.h"
+#include "alarm.h"
+#include "control.h"
+#include "display.h"
+#include "timeStamp.h"
+#include "pvAlarm.h"
+#include "pvControl.h"
+#include "pvDisplay.h"
+#include "pvEnumerated.h"
+#include "pvTimeStamp.h"
+#include "showConstructDestruct.h"
+
+using namespace epics::pvData;
+
+static FieldCreate * fieldCreate = 0;
+static PVDataCreate * pvDataCreate = 0;
+static StandardField *standardField = 0;
+static StandardPVField *standardPVField = 0;
+static Convert *convert = 0;
+static String builder("");
+static String alarmTimeStamp("alarm,timeStamp");
+static String allProperties("alarm,timeStamp,display,control");
+
+static PVStructure *doubleRecord = 0;
+static PVStructure *enumeratedRecord = 0;
+
+static void createRecords(FILE * fd,FILE *auxfd)
+{
+ doubleRecord = standardPVField->scalarValue(0,pvDouble,allProperties);
+ builder.clear();
+ doubleRecord->toString(&builder);
+ fprintf(fd,"%s\n",builder.c_str());
+ String choices[4] = {
+ String("0"),String("1"),String("2"),String("3")
+ };
+ enumeratedRecord = standardPVField->enumeratedValue(0,choices,4,alarmTimeStamp);
+ builder.clear();
+ enumeratedRecord->toString(&builder);
+ fprintf(fd,"%s\n",builder.c_str());
+}
+
+static void deleteRecords(FILE * fd,FILE *auxfd)
+{
+ fprintf(fd,"doubleRecord\n");
+ builder.clear();
+ doubleRecord->toString(&builder);
+ fprintf(fd,"%s\n",builder.c_str());
+ fprintf(fd,"enumeratedRecord\n");
+ builder.clear();
+ enumeratedRecord->toString(&builder);
+ fprintf(fd,"%s\n",builder.c_str());
+ delete doubleRecord;
+ delete enumeratedRecord;
+}
+
+static void testAlarm(FILE * fd,FILE *auxfd)
+{
+ fprintf(fd,"testAlarm\n");
+ Alarm alarm;
+ PVAlarm pvAlarm;
+ bool result;
+ PVField *pvField = doubleRecord->getSubField(String("alarm"));
+ if(pvField==0) {
+ printf("testAlarm ERROR did not find field alarm\n");
+ return;
+ }
+ result = pvAlarm.attach(pvField);
+ assert(result);
+ Alarm al;
+ al.setMessage(String("testMessage"));
+ al.setSeverity(majorAlarm);
+ result = pvAlarm.set(al);
+ assert(result);
+ alarm = pvAlarm.get();
+ assert(al.getMessage().compare(alarm.getMessage())==0);
+ assert(al.getSeverity()==alarm.getSeverity());
+ String message = alarm.getMessage();
+ String severity = AlarmSeverityFunc::getSeverityNames()[alarm.getSeverity()];
+ fprintf(fd," message %s severity %s\n",message.c_str(),severity.c_str());
+}
+
+static void testTimeStamp(FILE * fd,FILE *auxfd)
+{
+ fprintf(fd,"testTimeStamp\n");
+ TimeStamp timeStamp;
+ PVTimeStamp pvTimeStamp;
+ bool result;
+ PVField *pvField = doubleRecord->getSubField(String("timeStamp"));
+ if(pvField==0) {
+ printf("testTimeStamp ERROR did not find field timeStamp\n");
+ return;
+ }
+ result = pvTimeStamp.attach(pvField);
+ assert(result);
+ TimeStamp ts;
+ ts.getCurrent();
+ result = pvTimeStamp.set(ts);
+ assert(result);
+ timeStamp = pvTimeStamp.get();
+ assert(ts.getSecondsPastEpoch()==timeStamp.getSecondsPastEpoch());
+ assert(ts.getNanoSeconds()==timeStamp.getNanoSeconds());
+ time_t tt;
+ timeStamp.toTime_t(tt);
+ struct tm ctm;
+ memcpy(&ctm,localtime(&tt),sizeof(struct tm));
+ fprintf(auxfd,
+ "%4.4d.%2.2d.%2.2d %2.2d:%2.2d:%2.2d %d nanoSeconds isDst %s\n",
+ ctm.tm_year+1900,ctm.tm_mon + 1,ctm.tm_mday,
+ ctm.tm_hour,ctm.tm_min,ctm.tm_sec,
+ timeStamp.getNanoSeconds(),
+ (ctm.tm_isdst==0) ? "false" : "true");
+ timeStamp.put(0,0);
+ pvTimeStamp.set(timeStamp);
+}
+
+static void testControl(FILE * fd,FILE *auxfd)
+{
+ fprintf(fd,"testControl\n");
+ Control control;
+ PVControl pvControl;
+ bool result;
+ PVField *pvField = doubleRecord->getSubField(String("control"));
+ if(pvField==0) {
+ printf("testControl ERROR did not find field control\n");
+ return;
+ }
+ result = pvControl.attach(pvField);
+ assert(result);
+ Control cl;
+ cl.setLow(1.0);
+ cl.setHigh(10.0);
+ result = pvControl.set(cl);
+ assert(result);
+ control = pvControl.get();
+ assert(cl.getLow()==control.getLow());
+ assert(cl.getHigh()==control.getHigh());
+ double low = control.getLow();
+ double high = control.getHigh();
+ fprintf(fd," low %f high %f\n",low,high);
+}
+
+static void testDisplay(FILE * fd,FILE *auxfd)
+{
+ fprintf(fd,"testDisplay\n");
+ Display display;
+ PVDisplay pvDisplay;
+ bool result;
+ PVField *pvField = doubleRecord->getSubField(String("display"));
+ if(pvField==0) {
+ printf("testDisplay ERROR did not find field display\n");
+ return;
+ }
+ result = pvDisplay.attach(pvField);
+ assert(result);
+ Display dy;
+ dy.setLow(-10.0);
+ dy.setHigh(-1.0);
+ dy.setDescription(String("testDescription"));
+ dy.setFormat(String("%f10.0"));
+ dy.setUnits(String("volts"));
+ result = pvDisplay.set(dy);
+ assert(result);
+ display = pvDisplay.get();
+ assert(dy.getLow()==display.getLow());
+ assert(dy.getHigh()==display.getHigh());
+ assert(dy.getDescription().compare(display.getDescription())==0);
+ assert(dy.getFormat().compare(display.getFormat())==0);
+ assert(dy.getUnits().compare(display.getUnits())==0);
+ double low = display.getLow();
+ double high = display.getHigh();
+ fprintf(fd," low %f high %f\n",low,high);
+}
+
+static void testEnumerated(FILE * fd,FILE *auxfd)
+{
+ fprintf(fd,"testEnumerated\n");
+ PVEnumerated pvEnumerated;
+ bool result;
+ PVField *pvField = enumeratedRecord->getSubField(String("value"));
+ if(pvField==0) {
+ printf("testEnumerated ERROR did not find field enumerated\n");
+ return;
+ }
+ result = pvEnumerated.attach(pvField);
+ assert(result);
+ int32 index = pvEnumerated.getIndex();
+ String choice = pvEnumerated.getChoice();
+ StringArray choices = pvEnumerated.getChoices();
+ int32 numChoices = pvEnumerated.getNumberChoices();
+ fprintf(fd,"index %d choice %s choices",index,choice.c_str());
+ for(int i=0; i1) fileName = argv[1];
+ FILE * fd = stdout;
+ if(fileName!=0 && fileName[0]!=0) {
+ fd = fopen(fileName,"w+");
+ }
+ char *auxFileName = 0;
+ if(argc>2) auxFileName = argv[2];
+ FILE *auxfd = stdout;
+ if(auxFileName!=0 && auxFileName[0]!=0) {
+ auxfd = fopen(auxFileName,"w+");
+ }
+ fieldCreate = getFieldCreate();
+ pvDataCreate = getPVDataCreate();
+ standardField = getStandardField();
+ standardPVField = getStandardPVField();
+ convert = getConvert();
+ createRecords(fd,auxfd);
+ testAlarm(fd,auxfd);
+ testTimeStamp(fd,auxfd);
+ testControl(fd,auxfd);
+ testDisplay(fd,auxfd);
+ testEnumerated(fd,auxfd);
+ deleteRecords(fd,auxfd);
+ getShowConstructDestruct()->constuctDestructTotals(fd);
+ return(0);
+}
+
diff --git a/pvDataApp/pv/standardField.h b/pvDataApp/pv/standardField.h
index 0c7e709..6e17bbc 100644
--- a/pvDataApp/pv/standardField.h
+++ b/pvDataApp/pv/standardField.h
@@ -29,10 +29,8 @@ public:
StructureConstPtr structure,String properties);
StructureConstPtr structure(String fieldName,
int numFields,FieldConstPtrArray fields);
- StructureConstPtr enumerated(String fieldName,
- StringArray choices);
- StructureConstPtr enumerated(String fieldName,
- StringArray choices, String properties);
+ StructureConstPtr enumerated(String fieldName);
+ StructureConstPtr enumerated(String fieldName, String properties);
ScalarConstPtr scalarValue(ScalarType type);
StructureConstPtr scalarValue(ScalarType type,String properties);
ScalarArrayConstPtr scalarArrayValue(ScalarType elementType);
@@ -43,9 +41,8 @@ public:
String properties);
StructureConstPtr structureValue(
int numFields,FieldConstPtrArray fields);
- StructureConstPtr enumeratedValue(StringArray choices);
- StructureConstPtr enumeratedValue(StringArray choices,
- String properties);
+ StructureConstPtr enumeratedValue();
+ StructureConstPtr enumeratedValue(String properties);
StructureConstPtr alarm();
StructureConstPtr timeStamp();
StructureConstPtr display();
diff --git a/pvDataApp/pv/standardPVField.h b/pvDataApp/pv/standardPVField.h
index 3600e34..dbbb1a4 100644
--- a/pvDataApp/pv/standardPVField.h
+++ b/pvDataApp/pv/standardPVField.h
@@ -29,9 +29,9 @@ public:
PVStructure* structureArray(PVStructure *parent,
String fieldName,StructureConstPtr structure,String properties);
PVStructure * enumerated(PVStructure *parent,
- String fieldName,StringArray choices);
+ String fieldName,StringArray choices, int number);
PVStructure * enumerated(PVStructure *parent,
- String fieldName,StringArray choices, String properties);
+ String fieldName,StringArray choices, int number, String properties);
PVScalar * scalarValue(PVStructure *parent,ScalarType type);
PVStructure * scalarValue(PVStructure *parent,
ScalarType type,String properties);
@@ -42,9 +42,9 @@ public:
StructureConstPtr structure);
PVStructure * structureArrayValue(PVStructure *parent,
StructureConstPtr structure,String properties);
- PVStructure * enumeratedValue(PVStructure *parent,StringArray choices);
+ PVStructure * enumeratedValue(PVStructure *parent,StringArray choices,int number);
PVStructure * enumeratedValue(PVStructure *parent,
- StringArray choices, String properties);
+ StringArray choices,int number, String properties);
PVStructure * alarm(PVStructure *parent);
PVStructure * timeStamp(PVStructure *parent);
PVStructure * display(PVStructure *parent);
diff --git a/test/testAll.pl b/test/testAll.pl
index c2aefb8..587a31c 100755
--- a/test/testAll.pl
+++ b/test/testAll.pl
@@ -10,3 +10,5 @@ system ("./testPVStructureArray.pl");
system ("./testPVAuxInfo.pl");
system ("./testTimeStamp.pl");
system ("./testTimer.pl");
+system ("./testQueue.pl");
+system ("./testMessageQueue.pl");
diff --git a/test/testLinkedListAux b/test/testLinkedListAux
index 5b7cd91..e098cea 100644
--- a/test/testLinkedListAux
+++ b/test/testLinkedListAux
@@ -1,20 +1,20 @@
Time test
-diff 30.073240 milliSeconds
-time per iteration 30.073240 microseconds
-time per addTail/removeHead 0.015037 microseconds
+diff 25.970556 milliSeconds
+time per iteration 25.970556 microseconds
+time per addTail/removeHead 0.012985 microseconds
Time test locked
-diff 188.396252 milliSeconds
-time per iteration 188.396252 microseconds
-time per addTail/removeHead 0.094198 microseconds
+diff 187.406963 milliSeconds
+time per iteration 187.406963 microseconds
+time per addTail/removeHead 0.093703 microseconds
Time std::list test
-diff 656.937507 milliSeconds
-time per iteration 656.937507 microseconds
-time per addTail/removeHead 0.328469 microseconds
+diff 647.811113 milliSeconds
+time per iteration 647.811113 microseconds
+time per addTail/removeHead 0.323906 microseconds
Time std::list test locked
-diff 814.306906 milliSeconds
-time per iteration 814.306906 microseconds
-time per addTail/removeHead 0.407153 microseconds
+diff 804.343752 milliSeconds
+time per iteration 804.343752 microseconds
+time per addTail/removeHead 0.402172 microseconds
diff --git a/test/testMessageQueue b/test/testMessageQueue
new file mode 100644
index 0000000..2b51b75
--- /dev/null
+++ b/test/testMessageQueue
@@ -0,0 +1,5 @@
+linkedListNode: totalConstruct 6 totalDestruct 0
+linkedList: totalConstruct 1 totalDestruct 0
+messageQueue: totalConstruct 1 totalDestruct 1
+queueElement: totalConstruct 3 totalDestruct 3
+queue: totalConstruct 1 totalDestruct 1
diff --git a/test/testMessageQueue.pl b/test/testMessageQueue.pl
new file mode 100755
index 0000000..3b64671
--- /dev/null
+++ b/test/testMessageQueue.pl
@@ -0,0 +1,12 @@
+eval 'exec perl -S $0 ${1+"$@"}' # -*- Mode: perl -*-
+ if $running_under_some_shell; # testMessageQueue.pl
+use Env;
+system ("rm testMessageQueue");
+system ("rm testMessageQueueDiff");
+system ("../bin/${EPICS_HOST_ARCH}/testMessageQueue testMessageQueue testMessageQueueAux");
+system ("diff testMessageQueue testMessageQueueGold >> testMessageQueueDiff");
+if(-z "testMessageQueueDiff") {
+ print "testMessageQueue OK\n";
+} else {
+ print "testMessageQueue Failed\n";
+}
diff --git a/test/testMessageQueueAux b/test/testMessageQueueAux
new file mode 100644
index 0000000..622297d
--- /dev/null
+++ b/test/testMessageQueueAux
@@ -0,0 +1,2 @@
+message 1 messageType info
+message 4 messageType info
diff --git a/test/testMessageQueueDiff b/test/testMessageQueueDiff
new file mode 100644
index 0000000..e69de29
diff --git a/test/testMessageQueueGold b/test/testMessageQueueGold
new file mode 100644
index 0000000..2b51b75
--- /dev/null
+++ b/test/testMessageQueueGold
@@ -0,0 +1,5 @@
+linkedListNode: totalConstruct 6 totalDestruct 0
+linkedList: totalConstruct 1 totalDestruct 0
+messageQueue: totalConstruct 1 totalDestruct 1
+queueElement: totalConstruct 3 totalDestruct 3
+queue: totalConstruct 1 totalDestruct 1
diff --git a/test/testProperty b/test/testProperty
new file mode 100644
index 0000000..6d0c59b
--- /dev/null
+++ b/test/testProperty
@@ -0,0 +1,76 @@
+structure value
+ double value 0
+ structure alarm
+ int severity 0
+ string message
+ structure timeStamp
+ long secondsPastEpoch 0
+ int nanoSeconds 0
+ structure display
+ string description
+ string format
+ string units
+ structure limit
+ double low 0
+ double high 0
+ structure control
+ structure limit
+ double low 0
+ double high 0
+ double minStep 0
+structure value
+ structure value
+ int index 0
+ stringArray choices [0,1,2,3]
+ structure alarm
+ int severity 0
+ string message
+ structure timeStamp
+ long secondsPastEpoch 0
+ int nanoSeconds 0
+testAlarm
+ message testMessage severity major
+testTimeStamp
+testControl
+ low 1.000000 high 10.000000
+testDisplay
+ low -10.000000 high -1.000000
+testEnumerated
+index 0 choice 0 choices 0 1 2 3
+index 2 choice 2
+doubleRecord
+structure value
+ double value 0
+ structure alarm
+ int severity 2
+ string message testMessage
+ structure timeStamp
+ long secondsPastEpoch 0
+ int nanoSeconds 0
+ structure display
+ string description testDescription
+ string format %f10.0
+ string units volts
+ structure limit
+ double low -10
+ double high -1
+ structure control
+ structure limit
+ double low 1
+ double high 10
+ double minStep 0
+enumeratedRecord
+structure value
+ structure value
+ int index 2
+ stringArray choices [0,1,2,3]
+ structure alarm
+ int severity 0
+ string message
+ structure timeStamp
+ long secondsPastEpoch 0
+ int nanoSeconds 0
+linkedListNode: totalConstruct 5 totalDestruct 0
+linkedList: totalConstruct 1 totalDestruct 0
+field: totalConstruct 127 totalDestruct 34 totalReference 93
+pvField: totalConstruct 30 totalDestruct 30
diff --git a/test/testProperty.pl b/test/testProperty.pl
new file mode 100755
index 0000000..fd68010
--- /dev/null
+++ b/test/testProperty.pl
@@ -0,0 +1,12 @@
+eval 'exec perl -S $0 ${1+"$@"}' # -*- Mode: perl -*-
+ if $running_under_some_shell; # testProperty.pl
+use Env;
+system ("rm testProperty");
+system ("rm testPropertyDiff");
+system ("../bin/${EPICS_HOST_ARCH}/testProperty testProperty testPropertyAux");
+system ("diff testProperty testPropertyGold >> testPropertyDiff");
+if(-z "testPropertyDiff") {
+ print "testProperty OK\n";
+} else {
+ print "testProperty Failed\n";
+}
diff --git a/test/testPropertyAux b/test/testPropertyAux
new file mode 100644
index 0000000..8c0f4fb
--- /dev/null
+++ b/test/testPropertyAux
@@ -0,0 +1 @@
+2010.12.07 14:16:00 824222648 nanoSeconds isDst false
diff --git a/test/testPropertyDiff b/test/testPropertyDiff
new file mode 100644
index 0000000..e69de29
diff --git a/test/testPropertyGold b/test/testPropertyGold
new file mode 100644
index 0000000..6d0c59b
--- /dev/null
+++ b/test/testPropertyGold
@@ -0,0 +1,76 @@
+structure value
+ double value 0
+ structure alarm
+ int severity 0
+ string message
+ structure timeStamp
+ long secondsPastEpoch 0
+ int nanoSeconds 0
+ structure display
+ string description
+ string format
+ string units
+ structure limit
+ double low 0
+ double high 0
+ structure control
+ structure limit
+ double low 0
+ double high 0
+ double minStep 0
+structure value
+ structure value
+ int index 0
+ stringArray choices [0,1,2,3]
+ structure alarm
+ int severity 0
+ string message
+ structure timeStamp
+ long secondsPastEpoch 0
+ int nanoSeconds 0
+testAlarm
+ message testMessage severity major
+testTimeStamp
+testControl
+ low 1.000000 high 10.000000
+testDisplay
+ low -10.000000 high -1.000000
+testEnumerated
+index 0 choice 0 choices 0 1 2 3
+index 2 choice 2
+doubleRecord
+structure value
+ double value 0
+ structure alarm
+ int severity 2
+ string message testMessage
+ structure timeStamp
+ long secondsPastEpoch 0
+ int nanoSeconds 0
+ structure display
+ string description testDescription
+ string format %f10.0
+ string units volts
+ structure limit
+ double low -10
+ double high -1
+ structure control
+ structure limit
+ double low 1
+ double high 10
+ double minStep 0
+enumeratedRecord
+structure value
+ structure value
+ int index 2
+ stringArray choices [0,1,2,3]
+ structure alarm
+ int severity 0
+ string message
+ structure timeStamp
+ long secondsPastEpoch 0
+ int nanoSeconds 0
+linkedListNode: totalConstruct 5 totalDestruct 0
+linkedList: totalConstruct 1 totalDestruct 0
+field: totalConstruct 127 totalDestruct 34 totalReference 93
+pvField: totalConstruct 30 totalDestruct 30
diff --git a/test/testQueue b/test/testQueue
new file mode 100644
index 0000000..5764de8
--- /dev/null
+++ b/test/testQueue
@@ -0,0 +1,6 @@
+linkedListNode: totalConstruct 9 totalDestruct 1
+linkedList: totalConstruct 2 totalDestruct 0
+queueElement: totalConstruct 5 totalDestruct 5
+queue: totalConstruct 1 totalDestruct 1
+event: totalConstruct 5 totalDestruct 5
+thread: totalConstruct 1 totalDestruct 1
diff --git a/test/testQueue.pl b/test/testQueue.pl
new file mode 100755
index 0000000..def4d1e
--- /dev/null
+++ b/test/testQueue.pl
@@ -0,0 +1,12 @@
+eval 'exec perl -S $0 ${1+"$@"}' # -*- Mode: perl -*-
+ if $running_under_some_shell; # testQueue.pl
+use Env;
+system ("rm testQueue");
+system ("rm testQueueDiff");
+system ("../bin/${EPICS_HOST_ARCH}/testQueue testQueue testQueueAux");
+system ("diff testQueue testQueueGold >> testQueueDiff");
+if(-z "testQueueDiff") {
+ print "testQueue OK\n";
+} else {
+ print "testQueue Failed\n";
+}
diff --git a/test/testQueueAux b/test/testQueueAux
new file mode 100644
index 0000000..6c26d17
--- /dev/null
+++ b/test/testQueueAux
@@ -0,0 +1,20 @@
+source a 0 b 0
+source a 1 b 10
+source a 2 b 20
+source a 3 b 30
+source a 4 b 40
+ sink a 0 b 0
+ sink a 1 b 10
+ sink a 2 b 20
+ sink a 3 b 30
+ sink a 4 b 40
+source a 0 b 0
+ sink a 0 b 0
+source a 1 b 10
+ sink a 1 b 10
+source a 2 b 20
+ sink a 2 b 20
+source a 3 b 30
+ sink a 3 b 30
+source a 4 b 40
+ sink a 4 b 40
diff --git a/test/testQueueDiff b/test/testQueueDiff
new file mode 100644
index 0000000..e69de29
diff --git a/test/testQueueGold b/test/testQueueGold
new file mode 100644
index 0000000..5764de8
--- /dev/null
+++ b/test/testQueueGold
@@ -0,0 +1,6 @@
+linkedListNode: totalConstruct 9 totalDestruct 1
+linkedList: totalConstruct 2 totalDestruct 0
+queueElement: totalConstruct 5 totalDestruct 5
+queue: totalConstruct 1 totalDestruct 1
+event: totalConstruct 5 totalDestruct 5
+thread: totalConstruct 1 totalDestruct 1
diff --git a/test/testThreadAux b/test/testThreadAux
index a2b64c8..e80e989 100644
--- a/test/testThreadAux
+++ b/test/testThreadAux
@@ -1 +1 @@
-time per call 33.872702 microseconds
+time per call 49.544413 microseconds
diff --git a/test/testTimeStampAux b/test/testTimeStampAux
index f9ffe35..fc917dc 100644
--- a/test/testTimeStampAux
+++ b/test/testTimeStampAux
@@ -1,5 +1,5 @@
-current 1291321593 147449761 milliSec 1291321593147
-2010.12.02 15:26:33 147449761 nanoSeconds isDst false
+current 1291749608 920077694 milliSec 1291749608920
+2010.12.07 14:20:08 920077694 nanoSeconds isDst false
fromTime_t
-current 1291321593 0 milliSec 1291321593000
-2010.12.02 15:26:33 0 nanoSeconds isDst false
+current 1291749608 0 milliSec 1291749608000
+2010.12.07 14:20:08 0 nanoSeconds isDst false
diff --git a/test/testTimerAux b/test/testTimerAux
index 9592f2b..c730f1b 100644
--- a/test/testTimerAux
+++ b/test/testTimerAux
@@ -1,6 +1,6 @@
-one requested 0.400000 diff 0.400275 seconds
-two requested 0.200000 diff 0.200137 seconds
-one requested 0.200000 diff 0.200168 seconds
-two requested 0.400000 diff 0.400172 seconds
-one requested 0.000000 diff 0.000026 seconds
-two requested 0.000000 diff 0.000082 seconds
+one requested 0.400000 diff 0.400357 seconds
+two requested 0.200000 diff 0.200185 seconds
+one requested 0.200000 diff 0.200381 seconds
+two requested 0.400000 diff 0.400276 seconds
+one requested 0.000000 diff 0.000038 seconds
+two requested 0.000000 diff 0.000054 seconds