diff --git a/src/gdd/gdd.html b/src/gdd/gdd.html index 55ddf23b4..723952493 100644 --- a/src/gdd/gdd.html +++ b/src/gdd/gdd.html @@ -2,7 +2,7 @@
-
typedef enum {
- aitEnumInvalid=0,
- aitEnumInt8,
- aitEnumUint8,
- aitEnumInt16,
- aitEnumUint16,
- aitEnumEnum16,
- aitEnumInt32,
- aitEnumUint32,
- aitEnumFloat32,
- aitEnumFloat64,
- aitEnumFixedString,
- aitEnumString,
- aitEnumContainer
+ aitEnumInvalid=0,
+ aitEnumInt8,
+ aitEnumUint8,
+ aitEnumInt16,
+ aitEnumUint16,
+ aitEnumEnum16,
+ aitEnumInt32,
+ aitEnumUint32,
+ aitEnumFloat32,
+ aitEnumFloat64,
+ aitEnumFixedString,
+ aitEnumString,
+ aitEnumContainer
} aitEnum;
The enumerated type code allows a user to dynamically convert from one
type to another. The AIT portion of the GDD library contains a large
primitive type conversion matrix. The conversion matrix is indexed by
-the source and destination enumeration type codes. The matrix is a
-
+the source and destination enumeration type codes. The 12x12 matrix
+contains functions pointers for each type of conversion that can take
+place. Generally this matrix is never accessed directly by the user,
+a convert function:
++ void aitConvert(aitEnum dest_type, void* dest_data, + aitEnum src_type, const void* src_data, + aitIndex element_count) ++runs the correct function to perform the calculation. This function is used +extensively in the gdd class when data is put into or retrieved from a GDD.
+The primitive type code really only describes the storage format and length +of an element within a GDD. This code does not imply or assign any meaning +to the data. Assigning meaning to the data is the job of the application +type code. + +
+A typical way that application type codes are used is in defining structures. +A type code of 54 may be assigned the meaning "Temperature Reading". The +"Temperature Reading" structure may be a container with four GDD in it: +a value, a high alarm limit, a low alarm limit, and units. Each +of these GDDs also have an application type code. A generic program can +actually be written to completely discover the contents of the +"Temperature Reading" structure and configure itself to display meaningful +data. + +
+Storing time stamp and status information in each GDD was really a processing +versus storage compromise. Most data in a control system that is +constantly changing and needs to be transfered in GDDs requires a status +and time stamp. Transfering this type of data in one GDD in fairly easy. +If GDDs did not contain time stamps and status, then this actively changing +data would need to be transfered as a structure of three GDDs: one for +the value, one for the status, and one for the time stamp. In addition +to the three GDDs, a fourth that described the GDD container will need to +be transfered. + +
+Bounds, and consequencely a single dimension, in GDD are described by two +fields, a start and an element count. With this setup, and n-dimensional +space can be described. For example, a typical three dimension array +wouldbe described as a(5,4,6), which is a 5x4x6 cube. In a GDD this +cube would be described with dimension=3, bounds={(0,5)(0,4)(0,6)}. If +we want to describe a subset of this array, we would normally do so by +giving two endpoints of the sub-cube, such as (1,2,3)->(2,3,5). In GDD +terms, this would be bounds={(1,2),(2,3),(3,5)}. +
+The dimension information is stored directly within the GDD. The bounds +information is not. If bounds are required, then they are allocated as +a single dimensional array and referenced by the GDD. Methods exist in +the GDD class to automatically manipulate, allocate, and deallocate +bounds structures. Typically GDD are assigned a dimension when created +and do not morph into a different space. + +
+The gddDestructor allows reference counting similar to the GDD class. +Typically a data array will be associated with one instance of the +gddDestructor class. If more then one GDD needs to reference the array, +the each GDD is registered with the same gddDestructor. Each time +the gddDestructor is registered, the reference count should be bumped +up. The gddDestructor "run" method will only be invoked when the +reference count drops to zero. + +
+A fixed string class exists in the GDD library in order to support +certain features of EPICS. Fixed strings are used internally and +should generally not be used when creating and maniplulating strings with +the GDD library. Fixed strings are too big to fit into a GDD and also +always referenced, even if the GDD is a scalar. + +
+ #include "gdd.h"
+ .
+ .
+ // my destructor ------------------
+ class myDest : public gddDestructor
+ {
+ public:
+ myDest(void) : gddDestructor() { }
+ void run(void*);
+ }
+
+ void myDest::run(void* v)
+ {
+ aitInt16* i16 = (aitInt16*)v;
+ delete [] i16;
+ }
+ // --------------------------------
+ .
+ .
+ .
+ int app_type_code = 100;
+
+ // create a scalar GDD of type Int32 and put the value 5 into it
+ aitInt32 ival = 5;
+ aitFloat64 sval;
+ gdd* dds = new gddScalar(app_type_code,aitEnumInt32);
+ dds->put(ival);
+ dds->getConvert(sval);
+ dds->dump();
+
+ aitString str = "test string";
+ gdd* dd_str = new gddScalar(++app_type_code,aitEnumString);
+ dd_str->put(str);
+ printf("string length = %n",str->length());
+ dd_str->dump();
+
+ // create an array GDD and of dimension 1 and bound of 20 elements
+ // reference the array into the container
+ aitUint32 tot_elements = 20;
+ int dim = 1;
+ aitFloat64 a[20];
+ gdd* dda = new gddAtomic(++app_type_code,aitEnumFloat64,dim,&tot_elements);
+ dda->putRef(a);
+ dda->dump();
+
+ aitInt16* i16 = new aitInt16[tot_elements];
+ gdd* ddb = new gddAtomic(++app_type_code,aitEnumInt16,dim,&tot_elements);
+ ddb->putRef(i16,new myDest);
+ ddb->dump();
+
+ // create a container GDD that holds to GDDs and put the previously
+ // created GDDs into it.
+ int tot_in_container = 2;
+ gddContainer* ddc = new gddContainer(++app_type_code,tot_in_container);
+ ddc->insert(dds);
+ ddc->insert(dda);
+ ddc->dump();
+
+ // clean up the container GDD, this will clean up all member GDDs,
+ // myDest run() should also be invoked
+ delete ddc;
+ .
+ .
+ .
+
+
++GDDs in general have several components that are references, they do not +hold all the information they need. Creating and using array GDDs or +container GDDs +can be very time consuming. For an array GDD, the bounds and a destructor +must be allocated in addition to the GDD itself and referenced into the +GDD. For a container GDD, the GDD elements are really stored as a linked +list. To access the third element of a container, the linked list must be +traversed. With aitStrings GDD the situation is worse yet. The GDD class +allow for a given GDD to be packed or flattened into a simple linear buffer. +This mechanism includes packing GDD containers. In the array case, +the actual GDD is the first thing in the buffer, followed by any bounds +information, followed by the actual data array. The fields of the GDD +work exactly as before, except that they reference bounds and data that is +in the same buffer. In the case of containers, all the GDDs are stored as +an array of GDDs at the front of the buffer, followed by the bounds +information for each of the GDDs, followed by each of the GDDs data array if +present. There are many advantages of this configuration. Since all the +GDDs in a container are stored as an array instead of a linked list, the +user can directly index a particular GDD within the container. The +application type table performs with packing on a GDD that is registered +as a prototype for a particular type code. Since the GDD for a given +type code is now a fixed size, the type code table can manage the GDDs on +a free list. Each type code with a prototype GDD contains a free list +of GDDs for that type code. Creating a GDD using the type code table +involves retrieving a preallocated, packed GDD from a particular free list +and giving it to the user. This operation is very fast and efficient since +complex GDD structures are already constructed. +
+As stated above, container GDDs managed by the application type table can +be directly indexed as an array by the user. Unfortunetly the application +type code and indexes have no correlation - you cannot use the application +type code to index the GDD container. The type table has mapping functions +that convert between an application type code and an index into a container +GDD. Of course each type code maintains it's own index map and the +container GDD type code determines which mapping is to be used. A mechanism +exists in the GDD library for generating "#define" statements that +label container index values with a unique string. Preregistered containers +use this mechanism to generate indexing labels. The index label is a +concatenation of the type code names. If a container GDD type code name is +"TemperatureReading" and the first element is "Value", then the index +label generated will be "TemperatureReading_Value". At any time in a +running application, the user can request that index labels for all +registered prototypes be generated and dumped into a file. + +The library preregisters a number of application type names: + +