TINE 4.0.0 Release Notes

 

TINE Release 4.0 introduces a large number of improvements and new features as well as considerable refactoring of (internal) code variables and function names as well as module and header file names.

For example, servdef.h is now called srvcore.h, rpcdefs.h is now called tinedefs.h, etc.  By and large, the single header file "tine.h" is the only header file you'll need to include (also true in Release 3.xx).

 

Release 4.0 is fully compatible with TINE Release 3.xx with the notable exception that a TINE Release 3 client will not be able to receive Multicasts from a TINE Release 4 Server (unless the server explicitly re-assigns its multicast group to the Release 3 standard).

 

===============================================================

 Make File breaks:

===============================================================

 

You should pay attention to the make file used to make the tine libraries for your platform.  Some modules have been renamed [1].  The header dependencies are also slightly different.

 

If you simply remake the libraries using the tar package for your platform then you do not need to concern yourself with this issue.

 

Converting existing MakeFiles to use Release 4 should make sure that the header TINE dependencies reflect the new TINE header files [2].  And as noted above, please make sure that all user modules #include only 'tine.h' in lieu of any specific tine header files.

 

===============================================================

 API Breaks:

===============================================================

 

The variable 'NGdebug' is now 'tineDebug'.  Although there is a macro #definition to point NGdebug to tineDebug, you should change any code module which might use this variable to the modern form. 

 

NOTE: This variable is seldom used in user code modules, so you will likely not have to deal with this issue.

 

Most API calls can be used as before.  There are a number of new calls, reflecting the new functionality. In a few circumstances there have been breaks with the previous API.  Those calls which are affected are quite generally 'specialty' routines, i.e. not in common use. Nonetheless they are sometimes used and we list below those routines which now have different calling parameters.

 

  ============================================

·        Server-side calls

  ============================================

 

GetCallerInfo(NAME16 *un,BYTE *ipx,UINT32 *ip,short *prot,int *num);

 

and

 

char *GetCaller(void);

 

now take the equipment module local name as an argument:

 

GetCallerInfo(char *eqm,NAME16 *un,BYTE *ipx,UINT32 *ip,short *prot,int *num);

 

and

 

char *GetCaller(char *eqm);

 

The following routine has been deprecated:

 

void SetRPCCompletion(char *errstr);

 

Use instead:

 

void SetEqmCompletion(char *eqm, char *errstr)

 

If you use a property query function (rarely the case), the legacy variant is no longer supported, the API call now takes a function pointer with a prototype which uses a PrpQueryStruct type instead of a PropertyQueryStruct type:

 

RegisterPropertyQueryFunction(char *eqm, int (*fcn)(char *devName,PrpQueryStruct **prpqs),int numprops)

 

If you need to pipe your own output to the console and have made use of dbgoutput(), the routine int dbgoutput(char *str,time_t *ts) is no longer available.  Instead use

 

int dbglog(char *text,...);

 

Finally, the following routines take an array of NAME64 elements as an argument instead of NAME16:

 

AssignPropertyList(char *eqm,char *devname,char *listname,int listsize,NAME64 *list);

 

GetRegisteredPropertyList(char *eqm,NAME64 *prpNames,int *nprps);

 

This is due to the longer names now supported in TINE Release 4.0.

============================================

·        Client-side calls

============================================

 

There are no specific API breaks at the client side.  Noteworthy is fact that the 'link' routines such as AttachLink() or ExecLink() take 'const char' pointers instead of 'char' pointers where appropriate.

 

All exported 'Set', 'Get', and 'Put' routines now start categorically with a capital 'S', 'G', and 'P'.  This is the case with all exported routines with the execption of the network calls (e.g. recvNetGlobal()), and common logging (e.g. feclog()).  In general, the tine header file containing the prototype will contain a macro #define of the corresponding name with a small letter.

 

===============================================================

New Features

===============================================================

 

============================================

·        Longer name lengths.

============================================

 

All contact name lengths have been expanded.  Registered Property names and Device names can now be up to 64 characters in length.  Registered contexts and server names can now be up to 32 characters in length.  In addition, the device name string passed in a link can be up to 1024 characters long.

 

While such a long name would not itself correspond to a registered device, it can none the less be used to supply information from the caller to the server, such as a long file path name or, in the case of CDI, a range or group of CDI devices,  This feature alone necessitates a restructuring of the tine protocol headers and consequently this new major release.

 

Structure and bitfield tag names can now contain up to 16 characters.

 

The FEC Name as before can contain up to 16 characters.  The local equipment module name is as before a 6 character local tag used by the tine kernel to de-reference an incoming call.

 

============================================

·        Case insensitivity.

============================================

 

All context, server, device and property names are now case insensitive. This is true at the kernel level, which means that any user introduced string comparisons of device name or server name which might occur inside an equipment module handler can be either string sensitive or not.  Normally handlers make use of the underlying hash tables via GetPropertyId() and GetDeviceNumber() which use case-insensitive hash tables.

 

============================================

·        Server configuration.

============================================

 

If a server does not make use of the API registration calls, but instead uses local configuration files, these can be the standard .csv file set (or subset) as before, or a single .xml configuration file, called fec.xml.  There are multiple advantages of using configuration files over the API registration calls (such as avoiding the hard-coding of exported names).  A good strategy is to have a central configuration database file repository and to distribute the FEC specific files to the server at startup.

 

This avoids a single point of failure if the repository cannot be reached as long as the 'last good' configuration files are available in the local FEC startup directory.

 

A FEC can now specify its local history HISTORY_HOME via its configuration file (which takes precedence over the HISTORY_HOME environment variable).  This allows multiple FECs on computer, otherwise sharing an environment, to maintain separate local history locations.

 

Equipment modules can now specify its context and subsystem independently of the 'global' settings in the FEC configuration (fecid.csv or fec.xml).  Thus, a FEC containing multiple equipment modules can register each module in its own context and subsystem if need be.  This can be achieved by supplying a ‘Context’ and ‘Subsystem’ column in the export.csv file if used or ‘Context’ and ‘Subsystem’ tags within the fec.xml file, if used.  The API registration call RegisterEquipuipmentModule() can likewise specify the equipment module specific context and/or subsystem by supplying a fully specified export name tag in the form “/<context>/<server name>[<subsystem>]’. 

 

============================================

·        Expanded Tagged Structures

============================================

 

Tagged structure fields can now contain any tine data type (not just primitives) as well as other tagged structures.  Tagged structures are now registered with field names using the API call

 

int AddFieldToStruct(char *tag,int addr,int size,int fmt,char *field);

 

repeatedly for all structure fields, calling the routine

 

int SealTaggedStruct(char *tag,int size,int number);

 

when all fields are registered. As an example, consider the following two simple structures

 

  typedef struct

  {

    int   a;

    float b;

    char  t[16];

  } StHdr;

 

  typedef struct

  {

    int c;

    float d;

    FLTINT e;

  } StBod;

 

  and a third structure whose fields are composed of these structures:

 

  typedef struct

  {

    StHdr hdr;

    StBod body[4];

  } StCmp;

 

If the data transfer is to make use of the composite structure type "StCmp", then one needs to register the header structure "stHdr" and the body structure "StBod":

 

AddFieldToStruct("StHdr",OFFSETIN(StHdr,a),1,CF_INT32,"a");

AddFieldToStruct("StHdr",OFFSETIN(StHdr,b),1,CF_FLOAT,"b");

AddFieldToStruct("StHdr",OFFSETIN(StHdr,t),16,CF_TEXT,"t");

SealTaggedStruct("StHdr",sizeof(StHdr),NUM_DEVICES);

 

AddFieldToStruct("StBod",OFFSETIN(StBod,c),1,CF_INT32,"c");

AddFieldToStruct("StBod",OFFSETIN(StBod,d),1,CF_FLOAT,"d");

AddFieldToStruct("StBod",OFFSETIN(StBod,e),1,CF_DOUBLE,"e");

SealTaggedStruct("StBod",sizeof(StBod),NUM_DEVICES);

 

and finally the composite structure "StCmp" as follows:

 

AddFieldToStruct("StCmp",OFFSETIN(StCmp,hdr),1,CF_STRUCT,"<StHdr>hdr");

  AddFieldToStruct("StCmp",OFFSETIN(StCmp,body),4,CF_STRUCT,"<StBod>body");

SealTaggedStruct("StCmp",sizeof(StCmp),NUM_DEVICES);

 

============================================

·        New Data Formats

============================================

 

Several new 'bitfield' data types are now available.  These include CF_BITFIELD8, CF_BITFIELD16, CF_BITFIELD32, and CF_BITFIELD64.  Bitfields are transferred in their entirety as the corresponding integer value (e.g. CF_BITFIELD16 is transferred as a CF_INT16).  A registered bitfield is kept in the local bitfield registry in analogy with the structure registry.  This means that there are bitfield 'tags' as with structures.

 

Registering bitfields is analogous to registering tagged structures.  However, with bitfields the type size is known a priori, so the bitfield does not need to be "sealed".  On the other hand, it does need to be "opened" and thereby declaring the type size.  Thus one uses the following two functions:

 

int OpenBitField(char *srv,char *tag,int fmt);

int AddFieldToBitField(char *srv,char *tag,UINT32 mask,char *field);

 

Note that in addition to the bitfield 'tag', a server name 'srv' can be specified.  This secondary tag is used to distinguish among distinct bitfields using common names (e.g. "status") coming from different FECs.  The bitfield registered at a FEC would either pass a null pointer or a simple tag such as "this".

 

For example

 

OpenBitField("this","StsBits",CF_BITFIELD16);

 

AddFieldToBitField("this","StsBits",0x01,"field1");

AddFieldToBitField("this","StsBits",0x02,"field2");

AddFieldToBitField("this","StsBits",0x04,"field3");

AddFieldToBitField("this","StsBits",0x08,"field4");

AddFieldToBitField("this","StsBits",0xf0,"field5");

AddFieldToBitField("this","StsBits",0xf00,"field6");

AddFieldToBitField("this","StsBits",0xf000,"field7");

 

In general a caller does not have to register the bit field explicitly, although it is a good idea to do so, as any logic built around the fields within the bitfield will need to know their names a priori.  If the caller knows the bitfield tag he is interested in he can make a call as usual:

 

UINT16 v;

 

dout.dFormat = CF_BITFIELD16;

dout.dArrayLength = 1;

dout.data.sptr = &v;

strncpy(dout.dTag,"StsBits",8);

 

ExecLinkEx("/TEST/WinSineGen/SineGen0","Status",&dout,NULL,CA_READ,200);

 

From this point on, the bitfield is registered locally.  The caller can then interpret the bitfield or examine its contents using one of the routines:

 

int GetBitfieldAsString(char *srv,char *tag,UINT32 value,char *strbuf,int buflen);

 

or

 

int GetFieldFromBitfield(char *srv,char *tag,char *field,UINT32 value);

 

For example:

 

char strbuf[1024];

 

GetBitfieldAsString("/TEST/SineGen","StsBits",v,strbuf,1024);

 

will interpret the bitfield passed in the variable v.  If the caller only acquires bitfields from a single FEC, then a NULL can be passed instead of the device server name in the call without fear of naming collisions.

 

If the caller is interested in a single field only, he can append the bitfield to the property in the call as (other calling parameters same as above):

 

ExecLinkEx("/TEST/SineGen/SineGen0","Status.field1",&dout,NULL,CA_READ,200);

 

The returned value is the field in question (i.e. the same as obtaining the entire bitfield and following with a call to GetFieldFromBitfield()).

 

============================================

·        New Data Acquisition Mode

============================================

 

A call to AttachLink() or AttachLinkEx() can no request the acquisition mode CM_EVENT, which signals the subsystem to suppress all data exchange for the specified property unless the server has classified the call as an event, which it does by simply calling the scheduler.

 

============================================

·        Expanded Data Type Object

============================================

 

The data type object DTYPE contains the original fields found in tine Release 3.xx.  The dTag field can now contain up to 16 characters.  The DUNION field now has both signed and unsigned references.  New fields include 'dStamp', which is a user supplied integer tag, 'sysStamp', which is a systematic integer tag (e.g. a run number or cycle number), and 'xferReason', which in the case of data returned to a caller is a coded integer reflecting the reason why the data was sent (CX_NULL, CX_RESPONSE, CX_STALE, CX_HEARTBEAT, CX_EVENT, CX_TIMER, etc.).

 

These new parameters can be retrieved by the caller by calling one of the following if the link id is known: 

 

int GetDataStamp(int linkId); 

 

returns the user supplied data stamp.

 

int GetSystemDataStamp(int linkId); 

 

returns the system supplied data stamp

 

int GetDataFromLinkId(int linkId, DTYPE *dout, UINT16 *status);

 

supplies a DTYPE object containing all flags as well as the returned call status.

 

UINT16 GetTransferFlag(int linkId);

 

returns the transfer reason which can itself be used to determine if the return code originated locally (transfer flag = CX_NULL) or remotely.

 

If the original link id has not been maintained and the callback fires with a user supplied callback id, the equivalent routines may be used:

 

UINT16 GetTransferFlagFromCallbackId(int id);

int GetDataStampFromCallbackId(int id);

int GetSystemDataStampFromCallbackId(int id);

int GetDataFromCallbackId(int id,DTYPE *dout,UINT16 *status);

 

============================================

·        Better Control over Data Acquisition Queues

============================================

 

If a caller does not supply the CA_SYNCNOTIFY access flag, then event notification is delayed until all incoming data are processed.  This postpones the notification callback and thus allows actions such as other synchronous links to take place within a callback that are otherwise not possible due to lockout.  This is convenient but could cause loss of data if bursts of data arrive before the caller can be notified.  To this end, the caller can adjust the default queue settings for all data links or each link individually by using the routines:

 

SetClnRecvQueueDepth(int depth);  // default settings

 

or

 

void SetLinkQueueDepth(int linkId,int depth);  // link 'linkId'

 

The default depth is 10 for each data link.  Note that in many circumstances (high data rates, where it is more important to display the most recent data than deal with 'everything') setting the queue depth to '0' can be what is desired!

 

============================================

·        Expanded Alarm Message Structure

============================================

 

The alarm message structure now contains up to 64 bytes of alarm data.  It also contains the start time of the alarm along with the alarm time (both of which contain a higher time resolution).

 

The Alarm settings can also be adjusted remotely without stopping the server (new stock feature).  The will allow, for instance, an operator to adjust the archive severity or thresholds of (watched) alarms.

 

============================================

·        Expanded Name Resolution

============================================

 

The equipment name server references contained within the cshosts.csv file can now contain in lieu of an address column, a host column (FEC_HOST) which can contain the host name of the server running the ENS (e.g. tinesrv1.embl-hamburg.de).  The ip address will be resolved via the configured domain name server, where the assumption that the ENS has a zero port offset. 

 

If the cshosts.csv file is not found or otherwise determined, the tine kernel will ask the domain server for the address of a host called tineens on the local domain.  If successful, that will be taken as the (sole) tine ENS.

 

Client applications maintain a dynamic cache of all locally acquired addresses (if there is a local disk).  If the route to the configured ENSes is not available or the server(s) are down, client applications then consult the local cache for the 'last good' address of the target endpoint.

 

============================================

·        Expanded Multicast Scheme.

============================================

 

Each tine server can deliver data via multicast if called on to do so.  With release 4.0, each server has its own multicast group. This is formed by appending the last two bytes of the servers ip address to 238.1, e.g. 131.169.120.41 will multicast on the group 238.1.120.41, etc.  If a client closes a multicast link, it will drop its membership from the multicast group.

 

Each Globals server (set up to multicast in producer-consumer mode) likewise has its own multicast group.  Generally, if a Globals server is used, there is one server per tine context.  The tine 'site' Globals server is in the context 'SERVICE' and has a redirected reference to the tine time server.

 

============================================

·        Expanded local history server

============================================

 

A server's local history server can make use of 'worst-case' non-fragmented history files for its history records.  A file system such as NTFS can become seriously fragmented if a server has many local history records which are appended to asynchronously throughout the day or month.  If the non-fragmented set is used, the history record files are pre-generated and rotated according the depth settings of the local history configuration.

 

The local history settings can be adjusted remotely without stopping the server (new stock features).  This will allow, for instance, an operator to increase or decrease a tolerance or archive interval, or even to add records to the subsystem.

 

There are more supported formats available for the local history subsystem.  Archived data retrieved from the local history subsystem has traditionally been obtained in doublets containing a value and a timestamp.  This has necessitated the originating property call to support primitive data types (a float or array of floats, an int or array of ints, etc.).  The property can now be called and stored as a more complex data type, e.g. a FLTINT, i.e. already a value + status pair.  Retrieving the stored values as an array of FLTINTs would return the float part plus the simple timestamp.  An array of DBLDBLs would return the float part (cast as a double) and the (high resolution) timestamp.  Requesting an array of FLTINTINTs (or DBLDBLDBLs) would return a triplet containing the original FLTINT pair + the timestamp.  As should be clear, only a subset of tine data types can be retrieved in their entirety by asking for arrays of (other) tine data types (a property already returning a DBLDBLDBL value would have to retrieved with a DBLDBLDBLDBL - which is not implemented!).  The more complex data types can only be retrieved via a dedicated 'getHistory' API call, which knows how to append a timestamp to each stored data record and deliver the (properly swapped) data + timestamp to the caller.  Such a mechanism will appear in a future release.

 

============================================

·        Central Logging Server API

============================================

 

If the (new) central logging server is being used at a tine site, servers and applications can make use the central logging server API call

 

int clslog(char *context,char *tag,char *logger,int priority,int status,char *text,...);

 

where the status settings can be

 

#define CLOG_STATUS_NONE 0

#define CLOG_STATUS_INFO 1

#define CLOG_STATUS_WARN 2

#define CLOG_STATUS_ERR 3

 

and the priority settings can be

 

#define CLOG_PRIORITY_NONE 0

#define CLOG_PRIORITY_USEFUL 1

#define CLOG_PRIORITY_IMPORTANT 2

#define CLOG_PRIORITY_URGENT 3 

 

The central logging server maintains a running list of all entries.  Entries can be queried over a time span and according to (many) filter criteria (e.g. all entries for tag = "RF" from user "OPERATOR").

 

It is planned to have automatic entries from designated servers (e.g. rebooting), from the state server (state change), and from the event server (new event).

 

==============================================================

Central Servers

==============================================================

The Equipment Name Server (ENS) now maintains tine version information within its database.  It also supports queries for the longer server and context names available in Release 4.0 as well as legacy queries.  The ENS will correct its 'self entry' (the reference to itself in its own database) unless the environment variable NO_ENS_CHECK is set to TRUE (or YES). 

 

The Central Alarm Server (CAS) now utilizes the new Alarm Message Structures and Alarm Definition Structures found in Release 4.0.  The CAS now registers all properties per API and registers itself with the export name "CAS" within the context supplied in the fecid.csv or fec.xml file.  The CAS archive equipment module within the same FEC registers itself as "CAS.HISTORY".

 

The Central Archive Server pair, the Machine ARCHive (MARCH) data acquisition server and the Archive retrieval Server have also been upgraded to Release 4.0 standards.  In addition, the Archive Server now maintains the sets of viewer configurations available to the archive viewer(s) and the multi-channel analyzer, obviating any need for these client applications to maintain local configuration files.  The MARCH server now automatically registers local histories (.HIST meta properties) for all properties, with redirection to the originating server if the originating property call does not contain any parameter structure (usually the case).  Else the local history is redirected to the central archive server. The MARCH server registers its equipment module as "ARCHIVER" within the context supplied via the fecid.csv file.  The Archive server registers its equipment module as "HISTORY" within the context supplied.

 

The Central Archive Server does not as yet support storage with higher resolution timestamps or reduced file fragmentation.  That will also become available in a future release.

 

The Globals Server is nominally identical with the MARCH server.  In this special case, it does not store data but instead sends all acquired parameters as network globals.  It registers its equipment module as "GLOBALS" within the context given.

 

The Time Server is a simple Globals server sending only its local time as the site system time.  It should run on the same machine as the site Globals server, as they should share the same multicast group.  It registers itself as "TIMESERV" within the context "SERVICE".

 

The Event/Post Mortem Archive Server (PMARCH) has likewise been upgraded to support the longer names of Release 4.0.  As the newer data storage has a different format, care has been taken to allow data stored under Release 3.xx conditions to be able to be read by the Release 4.0 PMARCH server.  The event archive server has three equipment modules, registered as EVENTS, EVENTSTORE, and EVENTAPC, all within the context given.

 

The Event Server has been upgraded to Release 4.0 conditions.  The event server registers its equipment module as "EVENTMGR" and its archive module as "EVENT.HISTORY".

 

The State Server has been upgraded to Release 4.0 conditions.  The state server registers its equipment module as "STATE" in the context given.

 

The central logging server "CLOG" accepts log entries sent to it (as noted above).  It registers itself as "CLOG" in the context "SERVICE".

 

===============================================================

 

 [1] Most module file names have kept their old names, however: err_list.c -> errlist.c, database.c -> dbtools.c, almsrv.c -> almlib.c, history.c -> hst.lib.c.  The old platform specific command line interpreters (unixcmd.c, doscmd.h, ntcmd.h, nioscmd.c, etc.) have been replaced by a single module: ttycmd.c.

 

 [2] Most header file names have kept their old names, however: servdef.h -> srvcore.h, rpcdefs.h -> tinedefs.h, rpctypes.h -> tinetype.h, history.h -> hstlib.h, almsrv.h -> almlib.h, database.h -> dbtools.h. cprolog.h has disappeared.