|
|
|
ins_util
- IN-SNEC CORTEX UtilitiesThe INS_UTIL package provides a simplified means of communicating with an IN-SNEC CORTEX Command Ranging & Telemetry unit over TCP/IP network connections. Layered on top of the lower-level TCP_UTIL package, the INS_UTIL package can be used for both VME- and NT-based CORTEX units. (The package has been built and tested on Unix, Windows, and VMS platforms.)
A CORTEX message is composed of a fixed-length message header, a variable-length message body, and a fixed-length message trailer; one of the fields in the header specifies the message length (header, body, and trailer). The INS_UTIL functions are used to read messages from a stream and to write messages to a stream.
A CORTEX stream is created on a previously established network connection. As a result, the INS_UTIL package can be used for implementing both client and server CORTEX applications. The following code fragment connects to the logging port on a CORTEX unit:
#include <stdio.h> -- Standard I/O definitions. #include "tcp_util.h" -- TCP/IP networking utilities. #include "ins_util.h" -- IN-SNEC CORTEX utilities. char name[64] ; CortexStream stream ; TcpEndpoint connection ; ... sprintf (name, "%d@host", insPort ("LOG")) ; tcpCall (name, 0, &connection) ; -- Call LOG unit ("3040@host"). insCreate (connection, &stream) ; -- Create CORTEX stream.
The insPort()
function used above provides a convenient means for
determining the CORTEX ports by name; insPortName()
is available
for performing the reverse translation.
insRead()
reads the next message (header, body, and trailer)
from a CORTEX stream:
CortexHeader header ; char *body ; ... insRead (stream, -1.0, &header, &body) ;
insRead()
fills in the header and returns a pointer to the message
body (which is stored in memory private to the INS_UTIL package); the
length
field in the header contains the length in bytes of the
message body (excluding the header and trailer).
Before writing a message to a CORTEX stream, the application must fill in
the header with the length of the message body (excluding header and
trailer) and the desired flow ID; insWrite()
is then called
to output the message to the stream:
#include <stdlib.h> -- Standard C Library definitions. char body[100] ; ... ... fill in the message body ... ... header.length = sizeof body ; header.flowID = 0 ; insWrite (stream, -1.0, &header, body) ;
insWrite()
automatically adds the header and trailer lengths
to the length field in the header of the outgoing message. Both
insRead()
and insWrite()
take a timeout argument
that allows the application to limit the amount of time these routines wait
to perform their respective functions.
The CORTEX unit transmits and receives data in XDR format; consequently,
the data must be converted to and from the client's host-machine format.
insRead()
and insWrite()
take care of decoding
and encoding, respectively, the fields in the caller's header structure.
The message body is another matter. The VME-based CORTEX only utilizes
integers in its messages, so a blanket conversion of each 32-bit quantity
in a message body would probably suffice and could conceivably be done
automatically by insRead()
and insWrite()
.
The NT-based CORTEX, however, has some single-precision floating-point
fields to which xdr_float(3)
must be applied. Therefore,
the INS_UTIL utilities leave it to the application to perform the
appropriate conversions, although not without a little help.
NOTE: The XDR representations of a host CPU'sint
s andlong
s are both 32-bits wide. To ensure no loss of precision, applications built for platforms on which Cint
s are less than 32-bits wide should uselong
s andxdr_long(3)
when encoding and decoding CORTEX messages. (Assuminglong
is at least 32-bits wide.)
insDecode()
converts data received on a CORTEX stream from XDR
format to host-machine format by applying an XDR conversion function to the
input data. The conversion function can be for a user-defined structure that
encompasses the entire message body:
extern xdrproc_t xdr_TelemetryFrame ; char *body ; CortexHeader header ; TelemetryFrame frame ; ... insRead (stream, -1.0, &header, &body) ; insDecode (body, xdr_TelemetryFrame, 0, header.length, &frame) ; ... ... converted fields stored in FRAME ... ...
or for a primitive data type that is repeated throughout the message body:
long numbers[256] ; ... insDecode (body, xdr_long, sizeof (long), header.length, &numbers) ; ... ... header.length/4 integers are converted and stored in NUMBERS ... ...
(If the widths of the host-machine data types are identical to the widths of the corresponding XDR types, the conversion could take place in the same memory buffer.)
insEncode()
is insDecode()
's counterpart for
converting data from host-machine format to XDR format before calling
insWrite()
to output the message on a CORTEX stream:
char body[sizeof (long) * 256] ; long numbers[256] ; ... ... fill in NUMBERS array ... ... header.length = insEncode (numbers, xdr_long, sizeof (long), sizeof body, body) ; header.flowID = 0 ; insWrite (stream, -1.0, &header, body) ;
The actual frame data in a telemetry message, being a byte sequence, can
be used directly as received from the CORTEX unit; politically correct
applications might wish to call xdr_opaque(3)
.
The integrity of CORTEX TC (telecommand) request and instruction messages
is guaranteed (more or less!) by a checksum computed and appended to the
messages. The INS_UTIL package expects the application to handle checksum
processing. Before calling insWrite()
to send a TC message,
the application must encode the message body (excluding the checksum) in
XDR format, compute the checksum, and add it to the message body in network
byte order. The following code fragment sends an "Execute" instruction to
the CORTEX unit:
char body[5 * BYTES_PER_XDR_UNIT] ; long checksum, i = 0, numbers[4] ; ... numbers[i++] = 4 ; -- "Execute" request code. numbers[i++] = 1234 ; -- # of Execute pulses. numbers[i++] = 100000 ; -- Execute pulse width. numbers[i++] = 10000 ; -- Execute pulse period. header.length = insEncode (numbers, xdr_long, sizeof (long), i * BYTES_PER_XDR_UNIT, body) ; header.flowID = TC flow ID ; checksum = insChecksum (&header, body) ; *((uint32_t *) &body[header.length]) = htonl (checksum) ; header.length += BYTES_PER_XDR_UNIT ; insWrite (stream, -1.0, &header, body) ;
After calling insRead()
to input a TC message, the application
must compute the checksum for the XDR-encoded message body (excluding the
checksum) and compare the checksum to the last integer (converted to host
byte order) in the body.
char *body ; long numbers[256] ; ... insRead (stream, -1.0, &header, &body) ; if (insChecksum (&header, body) != ntohl (*((uint32_t *) &body[header.length-BYTES_PER_XDR_UNIT]))) { ... checksum error ... } insDecode (body, xdr_long, sizeof (long), header.length, &numbers) ;
In event-driven applications (e.g., those based on the X Toolkit or the
IOX dispatcher), the socket connection
underlying the CORTEX stream, returned by insFd()
, can be
monitored for input by your event dispatcher. Because input is buffered,
the input callback must repeatedly call insRead()
while
insIsReadable()
is true.
Configuration and monitoring messages sent to and received from a CORTEX unit
contain a numeric code identifying the CORTEX component or table with which the
message is concerned. insPart()
and insPartName()
,
respectively, provide a convenient means of converting a component/table name
to a numeric code and vice-versa. Identically named components have different
numeric codes in the VME- and NT-based CORTEX units, so the type of the
CORTEX unit must be passed to insPart()
.
When a CORTEX stream is no longer needed, a single call will close the network connection and discard the stream:
insDestroy (stream) ;
insChecksum()
- compute the checksum for a message.
insCreate()
- creates a CORTEX network stream.
insDecode()
- decodes XDR-encoded data.
insDestroy()
- deletes a CORTEX network stream.
insEncode()
- encodes data in XDR format.
insFd()
- returns a CORTEX stream's socket number.
insIsReadable()
- checks if input is waiting to be read from a stream.
insIsUp()
- checks if a CORTEX stream is up.
insIsWriteable()
- checks if data can be written to a stream.
insName()
- returns the name of a CORTEX stream.
insPart()
- converts a component name to a component code.
insPartName()
- converts a component code to a component name.
insPort()
- converts a port name to a port number.
insPortName()
- converts a port number to a port name.
insRead()
- reads the next message from a CORTEX stream.
insWrite()
- writes a message to a CORTEX stream.
ins_util.c
ins_util.h