MIDAS - The Multiple Instance Data Acquisition System

Data Acquisition - data transfer procedures (DataXferLib)
Version 4

These procedures provide a method for a data acquisition program to transfer data blocks via a TCP/IP connection to a server which will normally be the MIDAS Merger or MIDAS Tape Server. However the method can also be used to transfer data blocks within the components of a data acquisition system (see Installation of the MIDAS Tape Server).


Usage

   To initialise and establish connection

      int transferBlockSize(int BlockSize);          /* optional - default 64 Kbytes */
      int transferPort(int Port);                    /* optional - default 10305 */
      int transferMode(int Mode);                    /* optional - default 3 */

      int transferInit(TS_Server);

   To close connection

      void transferClose();
      
   To restart connection using existing options  (not normally needed)

      transferTxRestart();
      
   To send a data block
   
      int transferTxData (char *data, int stream, int length);  
   

TS_Server is the name of the tape server or the IP address of the tape server In the case of a name the client must be able to convert this to an IP address using gethostbyname

BlockSize is the data block size used - default is 16Kbytes
Port is the TCP port of the Tape Server Link handler (or other server) (default is 10305)
Mode is the transfer protocol mode - default is Mode=1:

Mode=1 there is a 32 byte protocol header with acknowledgment required from the tape server for each data block
Mode=2 has no protocol header and no acknowledgement
Mode=3 there is a 32 byte protocol header but with acknowledgment from the tape server not essential. It is expected that normally the TCP flow control will be used to manage the data rate.
Mode=4 special MBS (GSI) compatible mode

Only Mode=1 will return a completion code from the tape server in calls to transferTxData
If the transfer is succesful 0 is returned. In the event of an error <0 is returned.

data is a pointer to the data buffer which should be of length (BlockSize - 32) bytes
The procedure assumes that 32 bytes are available BEFORE data which will be overwritten with control information. Thus a buffer char * data[BlockSize] should be allocated and the user data should start at data[32]. The address &data[32] should be supplied to transferTxData.

stream should currently have the value = 1
length is the maximum length of the data buffer and should have the value (BlockSize - 32)

For mode=2 the requirement for the 32 bytes to be available before the user data does not exist.

If it is detected that the TCP socket has been closed by the server or any other network error occurs then when transferTxData is next called an attempt will be made to reestablish the connection.

   There are a number of optional calls which are available to permit further management of the TCP connection.

      int transferStatus ();
      int transferEndian(int n);
      int transferSndBufSize(int n);
      int transferRcvBufSize(int n);
      int transferBlockMode(int n);

transferEndian allows a custom value for the Endian flag if this is not determined by the processor hardware
transferBlockMode allows a custom value for the TCP No Blocking Mode. By default blocking is enabled.
transferStatus returns the state of the socket - 0: no connection
transferSndBufSize allows a custom value for the TCP send window to be set. By default this is set as large as permitted by the system up to 4Mbytes
transferRcvBufSize allows a custom value for the TCP receive window to be set. By default this is set as large as permitted by the system up to 4Mbytes

Version 4 of the library supports use of 2 user buffers per TCP connection by the use of threads. The following are only valid when threads are available.

      int transferNice(int n);
      int transferUseOverlap(int n);
      int transferTxWait();
      int transferState();

transferUseOverlap enables use of threads
transferState returns the state of the current thread
transferNice sets the priority of the current thread
transferTxWait wait for the current thread to become idle

In order that the procedure interface can support multiple concurrent connections (to different servers or to the same server using different ports) the following procedure is available.


   To define current user

      int transferSetUser(int n);
   
where n is in the range 0 (default) => MAXUSERS-1 (MAXUSERS is currently set at 8)

Hence


      (void) transferSetUser(0);
      (void) transferInit(TS_Server1);

      (void) transferSetUser(1);
      (void) transferInit(TS_Server2);
   

      (void) transferSetUser(0);
      s = transferTxData (char *data, int stream, int length); 

      (void) transferSetUser(1);
      s = transferTxData (char *data, int stream, int length); 

would establish a connection to TS_Server1 and then establish a concurrent connection to TS_Server2. Next a data block is sent first to TS_Server1 and then to TS_Server2.
It should be noted that in the current implementation if one of the connections blocks then the other connection is also blocked.

In Version 4 of the library an additional set of procedure calls are provided in which the first argument is the connection ID. This replaces the transferSetUser procedure.

   Hence
      s = transferMultiTxData (int ID, char *data, int stream, int length);
   is equivalent to
      (void) transferSetUser(ID);
      s = transferTxData (char *data, int stream, int length); 


Data Formats
  
typedef struct block_header {              /* format of data block  */
        unsigned short hdr_flags;          /* see below */
        unsigned short hdr_stream;         /* =0 for forced ack request or stream number  */
        unsigned short hdr_endian;         /*   data byte order */
        unsigned short hdr_ID;             /* value of ID variable 0 => 7  */
        unsigned long hdr_sequence;        /* for this stream */
        unsigned long hdr_blocklength;     /*  total length of this block including the header */
        unsigned long hdr_datalength;      /*  length of user data in the block  */
        unsigned long hdr_offset;          /*  very large blocks may be fragmented  */
        unsigned long hdr_id1;             /*  for spy to locate header  =0x19062002 */
        unsigned long hdr_id2;             /*  for spy to locate header  =0x09592400 */
} HEADER;

/*
    flags   (bit 0 is lsb)
    bit 0       request = 0;  ack = 1
    bit 1       = 1  suppress ack;  =0 normal ack
    bit 2       = 1  force ack   (no data follows)
*/

#define HDR_ID1 0x19062002
#define HDR_ID2 0x09592400

typedef struct ack {
    unsigned short acq_flags;          /* bit 0 = 1 for ack  */
        unsigned short acq_code;           /* =0 for good ack otherwise error reason */
        unsigned short acq_ts_state;       /* tape server state - see below */
        unsigned short acq_stream;         /* =0 for forced ack ack or 1=>MAX_STREAM  */
        unsigned short acq_endian;         /* =1 transmitted in host byte order */
        unsigned short acq_ID;
        unsigned long  acq_sequence;       /* for stream != 0 is sequence being acked */
        unsigned short acq_stream_state1;           /*   */
        unsigned short acq_stream_state2;           /*   */
        unsigned short acq_stream_state3;           /*   */
        unsigned short acq_stream_state4;           /*   */
        unsigned short acq_stream_window1;          /*   */
        unsigned short acq_stream_window2;          /*   */
        unsigned short acq_stream_window3;          /*   */
        unsigned short acq_stream_window4;          /*   */
} ACK;



Implementation

The block_header fields are transmitted in network ordering (see htonl, htons and ntohl, ntohs etc) with the exception of the field hdr_endian which is transmitted in the native ordering of the client processor.

Immediately after the TCP connection to the server is established a 1Kbyte block is sent to the server. The hdr_datalength field in the block header has the value -1 and the hdr_blocklength field in the block header contains the BlockSize to be used by the connection. All subsequent data blocks sent to the server have this length until the TCP connection is terminated.

 

Return to documentation index documentation index


© Dec 2014 NPG - STFC