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 @@

EPICS pvDataCPP
Overview
-2010.12.03

+2010.12.06

TODO

CONTENTS @@ -2670,7 +2670,26 @@ once. This can be implemented as follows:

Message Queue

Definitions

-
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();
+};

MessageQueue

@@ -2679,76 +2698,39 @@ higher priority threads.

A messageNode is a class with two public data members:

-
message
+
getMessage
The message.
-
messageType
+
getMessageType
The message type.
-

A messageQueue is an interface with methods:

+

A messageQueue is an interface with public methods:

+
MessageQueue
+
The constructor. The queue size must be specified.
+
~MessageQueue
+
The destructor.
put
Put a new message into the queue. False is returned if the queue was - full and true otherwise.
+ full and true otherwise. If replaceLast is true then the last message is + replaced with this message. +
get
+
Get the oldest queue element. If the queue is empty null is returned. + Before the next get can be issued release must be called.
+
release
+
Release the queue element returned by the last get.
isEmpty
Is the queue empty?
isFull
Is the queue full?
-
replaceFirst
-
Replace the oldest member in the queue.
-
replaceLast
-
Replace the newest member in the queue.
getClearOverrun
-
Get the number of times replaceFirst or replaceLast have been called - since the last call to getClearOverrun. The internal counter is reset - to 0.
+
Get the number of times put has been called but no free element is + available.
-

MessageQueueFactory provides the public method:

-
-
create
-
Create a MessageQueue and return the interface.
-
- -

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.

NoDefaultMethods

@@ -3315,41 +3297,31 @@ private:

Queue

-

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:

@@ -3376,20 +3348,32 @@ and a queue.

last call to getUsed.
+

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