ttdriver: Thompson Stack Driver

Contents

1: Introduction

ttdriver is a QNX driver for the Tommy Thompson data acquisition boards. It consists of an executable program (ttdriver) which interfaces to the hardware and a library of C functions which communicate with the driver to supply applications with all the functionality of the Thompson Stack. The library functions communicate with the driver via QNX messages. As such, there is a C-level interface and a message-level interface.

2: Invocation

    ttdriver [options]
             -c <node> send msgs to memo on specified node
             -e <error filename>
             -h <msg header>
             -l add a level of debug messages
             -o <dev>[,<r>,<c>,<w>,<pass>,<warn>,<fail>,<debug>]
             -q Ask resident ttdriver to terminate
             -s no message sounds
             -v disable verbose to stderr
             -y disable system error message concatenation to messages
ttdriver is usually run in the background. It may either be invoked at boot time out of /etc/config/sysinit.$NODE or at runtime via and "interact" or "runfile" script. The -q option is the most graceful way to get ttdriver to terminate from the command line. There is also a library function to ask the resident ttdriver to terminate. If run from the sysinit.$NODE, there may be no reason to have ttdriver terminate at all.

All the other options pertain to memo messages and are identical to the options on all other executables in this architecture.

Note that if ttdriver is run from sysinit.$NODE, it will be invoked before any memo program is resident, so it will not be able to log its messages with memo. In this case the appropriate invocation will likely be "ttdriver -v &".

3: C-Level Interface

3.1: Initialization

   unsigned short tt_init( void );
This function makes contact with the ttdriver. It is usually unnecessary, since each of the other functions will make the initial contact if necessary, but it is often desirable to find out whether the driver is present before you actually need it.

3.2: A/D Functions

   unsigned short tt_read_atod( unsigned short channel );

3.3: Digital I/O Functions

   unsigned short tt_write_digital( unsigned short dig_word,
             unsigned short value );
   unsigned short tt_read_digital( unsigned short dig_word );
   unsigned short tt_scdc_command( unsigned char cmd_no );
   unsigned short tt_scdc_multcmd( unsigned char *cmds );

3.4: GC Board Functions

   unsigned short tt_gc_reset( void );
   unsigned short tt_gc_byte( void );
   unsigned short tt_gc_read( gc_data_buf *gcbuf );
   unsigned long tt_gc_chan( unsigned short chan );
These four functions actually define three totally distinct ways of accessing the GC counter board. tt_gc_reset() is required before any of the other functions are called, and is generally required before switching from one method to another.

tt_gc_byte() is the lowest level routine, and reads a single byte of data from the GC board. Detailed knowledge of the GC counter board architecture is required in order to make use of this function.

tt_gc_read() returns all of the data currently available from the GC board for all channels in the gc_data_buf structure. The details of the contents of the structure are noted in the Message-Level Interface section. Since the GC board has an microprocessor of its own, it can buffer up to two seconds worth of data. That means you could call this function every second or two and still get all the data. On the other hand, you would have to write some non-trivial code to deal with these chunks of data when they arrive.

tt_gc_chan() is the simplest interface to the GC board. It returns the single latest value available from the GC board for the specified channel. In order not to lose data, this function must be called at the GC board's data rate (8 Hz).

3.5: D/A Functions

   unsigned short tt_dac_out( unsigned short channel, unsigned short value );
   unsigned short tt_dac_in( unsigned short channel );
   unsigned short tt_dac_enbl( unsigned short safe );
These three functions are the interface to Ray Dunn's Digital to Analog board. tt_dac_out( channel, value ) writes the specified value to the specified channel, returning zero on success and 0xFFFF if the channel number is out of range.

tt_dac_in( channel ) returns the last value written to the specified channel or 0xFFFF if the channel number is out of range.

tt_dac_enbl() determines whether the programmed values are enabled to the outputs of the D/A board.

3.6: Counter Board Functions

At the present time, there is no support for the standard Thompson Stack counter board, though the effort to add such support is deemed to be trivial.

4: Message-Level Interface

When starting up, ttdriver registers the name huarp/exp/ttdriver, where "exp" is the experiment mnemonic (e.g. "acats") (huarp is the acronym for the folks who wrote the program) Application programs can use that name to locate the driver and establish message communications.

ttdriver will also register the name huarp/exp/scdc in order to mimic the HUARP scdc program. Soldrv will use this name to locate ttdriver in order to cycle digital commands efficiently.

ttdriver will recognize two types of messages: the new board-specific messages and the scdc messages.

The board-specific messages use the following structure. The first two bytes of the message are a signature to uniquely identify the message. The SCDC interface was defined before this sort of convention was established, so the SCDC message structure is different. Fortunately, we have not run into any sort of conflict to date.

Each special function has a different function code enumerated in the ttmsgtype. Most functions require an address, and many require data. If a function does not require one or the other, it need not be sent.

          typedef struct {
            unsigned short signature;   /* 'tt' */
            unsigned short function; /* ttmsgtype */
            unsigned short address;
            unsigned short data;
          } Send_to_tt;

          typedef enum {
            TTMSG_READ_ATOD,
            TTMSG_WRITE_DIGITAL,
            TTMSG_READ_DIGITAL,
            TTMSG_GC_RESET,
            TTMSG_GC_BYTE,
            TTMSG_GC_READ,
            TTMSG_GC_CHAN,
            TTMSG_DAC_OUT,
            TTMSG_DAC_IN,
            TTMSG_DAC_ENBL,
            TTMSG_QUIT,
            TTMSG_MAX
          } ttmsgtype;
Replies from ttdriver all begin with the 'tt' signature. With the exception of TTMSG_GC_READ and TTMSG_GC_CHAN, every function returns an unsigned short value in the value.shrt member of the Reply_from_tt structure. TTMSG_GC_CHAN return an unsigned long in value.lng. In the case of functions returning unsigned short, a value of 0xFFFF is an unambiguous error code. TTMSG_GC_CHAN returns ~0L (0xFFFFFFFF) on error.
          typedef struct {
            unsigned short signature; /* 'tt' */
            union {
              unsigned short shrt;
              unsigned long lng;
            } value;
          } Reply_from_tt;
TTMSG_GC_READ returns as much data as the GC board currently has available in the gc_data_buf structure. The samples read from the board are written sequentially into the samples array. If gcbuf is of type gc_data_buf, the samples from channel 0 begin at gcbuf.samples[0] and end with gcbuf.samples[gcbuf.end_offset[0]-1]. gcbuf.end_offset[0] then represents the index of the first sample from channel 1, as well as the number of samples which were read from channel 0. The number of samples read from channel 1 is gcbuf.end_offset[1] - gcbuf.end_offset[0].

In case of error, gcbuf.end_offset[0] will be set to 0xFFFF.

          typedef struct {
            unsigned short end_offset[ N_GC_CHANNELS ];
            unsigned long samples[ MAX_GC_SAMPLES * N_GC_CHANNELS ];
          } gc_data_buf;

          typedef struct {
            unsigned short signature; /* 'tt' */
            gc_data_buf gcbuf;
          } Reply_from_gc;
There are two message formats which SCDC recognizes. The first is for a single command to set or clear a single digital output. The command to set a singal digital output is different from the command to clear that output. I propose to use the digital output channel number as the clear command and the digital output channel number plus 100 as the set command.
          typedef struct {
            unsigned char signature[2]; /* DASCMD, DCT_SCDC (1, 3) */
            unsigned char command;
          } Send_to_scdc;
The second message format allows multiple set or clear commands to be communicated in a single message, a feature which soldrv takes advantage of. The commands array contains a list of command codes terminated by 0xFF.
          typedef struct {
            unsigned char signature; /* SC_MULTCMD (11) */
            unsigned char commands[ MAX_MSG_SIZE ];
          } Mult_send_to_scdc;
Both of these messages return a single byte return code defined in /usr/local/include/reply.h.


Return to Manuals Guide


last updated: Unkown webmaster@huarp.harvard.edu
Copyright 2012 by the President and Fellows of Harvard College