HP OpenVMS Systems Documentation

Content starts here

OpenVMS I/O User's Reference Manual


Previous Contents Index

5.6 Terminal Driver Programming Examples

The VAX C program LAT.C shown in Example 5-1 initiates and maintainsan outbound LAT session from the local node. It demonstrates thefollowing LAT $QIO functions:

  • Cloning the LAT template device (LTA0:)
  • IO$M_LT_SETMODE
  • IO$M_LT_CONNECT (on forward port)
  • IO$M_LT_SENSEMODE

Example 5-1 LAT.C Terminal Driver Programming Example

#module LAT_FORWARD_CONNECT "X1.0-001"/***++****  MODULE DESCRIPTION:****      In initiating and maintaining an outbound LAT session from the local**      node, this program demonstrates the following LAT $QIO functions:****          o Cloning the LAT template device (LTA0:)**          o IO$M_LT_SETMODE**          o IO$M_LT_CONNECT   (on forward port)**          o IO$M_LT_SENSEMODE****--*//*****  INCLUDE FILES***/#include <descrip> /* VMS Descriptor Definitions      */#include <iodef>   /* I/O Function Codes Definitions  */#include <latdef>  /* LAT Definitions                 */#include <ssdef>   /* System Service Return Status    */                                        /* Code Definitions                */#include <ttdef>   /* Terminal Characteristics        */#include <tt2def>  /* Terminal Extended               */                                        /* Characteristics                 *//*****  MACRO DEFINITIONS***//*** Service name which the session will be to.*/#define SERVICE_NAME        "LAT_SERVICE"#define SERVICE_NAME_LENGTH 11/*** For the sake of clarity, the sizes of the buffers used for reading from** and writing to the LTA and TT devices are set to the values below.  In** order to gain maximum throughput from this program, the following system** parameters can be set:****      o TTY_ALTYPAHD - 1500**      o TTY_TYPAHDSZ - 80**** To get the best performance from this program without touching these** system parameters on your system, modify the program to set the size of** the buffers to the following:****      o LTA_BUFFER_SIZE = MIN(TTY_ALTYPAHD, 1500)**      o TT_BUFFER_SIZE  = MIN(TTY_TYPAHDSZ, 132)*/#define LTA_MAXBUF              1500#define TT_MAXBUF               80/*** Size of the LAT SENSEmode itemlist.*/#define MAX_SENSE_ITEMLIST_SIZE 1500/*** Character user can press to terminate the LAT connection (CTRL+\).*/#define CONNECTION_TERMINATOR   0x1C/*****  FUNCTION PROTOTYPES***/unsigned long   SetDeviceChars(void);void            ConnectAST(void);void            LTAreadChannelAST(void);void            TTreadChannelAST(void);void            LTAhangupHandler(void);void            EndSession(void);void            ExitHandler(void);/*****  GLOBAL DATA***/char            *LTAbuffer, /* LTA device I/O buffer                */                *TTbuffer,  /* TT device  I/O buffer                */                /*                ** Text for LAT reject codes.  Note that some LAT                ** implementations will return a 0 reject code to                ** indicate a normal disconnect.                */                *LATrejectTable[] = {                        "Unknown",                        "User requested disconnect",                        "System shutdown in progress",                        "Invalid slot received",                        "Invalid service class received",                        "Insufficient resources at server",                        "Port or service in use",                        "No such service",                        "Service is disabled",                        "Service is not offeredon the requested port",                        "Port name is unknown",                        "Invalid service password",                        "Remote entry is not in queue",                        "Immediate access rejected",                        "Access denied",                        "Corrupted request",                        "Requested function is not supported",                        "Session cannot be started",                        "Queue entry deleted by server",                        "Illegal request parameters"                };unsigned short  LTAchannel,         /* LTA device I/O channel               */                TTchannel,          /* TT device I/O channel                */                LTA_QIOiosb[4],     /* IOSB for LTA device functions        */                TT_QIOiosb[4];      /* IOSB for TT device functions         */unsigned long   ReadTerminatorMask[2] = { 0, 0 },                                    /* $QIO read terminator mask            */                SavedTTdeviceChar[3],                                    /* Saved TT device characteristics      */                DeviceCharBuffSize = sizeof(SavedTTdeviceChar);                                    /* Size of device characteristics buffer*/                ExitConditionValue, /* Exit condition value of program      */                LATrejectTableSize =/* Number of elements in LAT reject tbl */                    sizeof(LATrejectTable) / sizeof(LATrejectTable[0]);/*** Itemlist for setting LAT port with the target service name.*/struct {        unsigned short  item_code;        char            item_byte_count;        char            item_value[ SERVICE_NAME_LENGTH ];} PortSetmodeItemlist = {        LAT$_ITM_TARGET_SERVICE_NAME, SERVICE_NAME_LENGTH, SERVICE_NAME};/*** Exit handler block.*/struct {        unsigned long   flink;        void            (*exit_handler)();        unsigned long   arg_count;        unsigned long   *exit_status;} ExitHandlerBlock = { 0, ExitHandler, 1, &ExitConditionValue };/*** Devices which channels are assigned to.*/$DESCRIPTOR(LTAtemplateDSC, "LTA0:");$DESCRIPTOR(TTchannelDSC, "SYS$COMMAND");main(){        /*        ** Local Variables:        */        unsigned long        status,                        portSetmodeItemlistSize = sizeof(PortSetmodeItemlist);        /*        ** BEGIN:        **        ** Declare an exit handler.        */        if (!((status = sys$dclexh(&ExitHandlerBlock)) & 1))                lib$signal(status);        /*        ** Assign a channel to LTA0: to get a forward LAT port and assign a        ** channel to the terminal.        */        if (!((status = sys$assign(&LTAtemplateDSC, &LTAchannel, 0, 0)) & 1))                lib$signal(status);        if (!((status = sys$assign(&TTchannelDSC, &TTchannel, 0, 0)) & 1))                lib$signal(status);        /*        ** Allocate memory for the channel data buffers.        */        LTAbuffer = malloc(LTA_MAXBUF);        TTbuffer = malloc(TT_MAXBUF);        /*        ** Set device characteristics for the two channels.        */        if (!((status = SetDeviceChars()) & 1))                lib$signal(status);        /*        ** Do SETmode $QIO to set the port entity with the target service name        ** specified in the item list.        */        if (!((status = sys$qiow(                            0,                            LTAchannel,                            IO$_TTY_PORT|IO$M_LT_SETMODE,                            &LTA_QIOiosb, 0, 0,                            &PortSetmodeItemlist,                            portSetmodeItemlistSize,                            LAT$C_ENT_PORT|(LAT$C_ENTS_OLD << 0x10),                            0, 0, 0)) & 1))                lib$signal(status);        if (!(LTA_QIOiosb[0] & 1))                lib$signal(LTA_QIOiosb[0]);        /*        ** Enable a CTRL+Y AST on the LAT channel.        */        if (!((status = sys$qiow(                            0,                            LTAchannel,                            IO$_SETMODE|IO$M_CTRLYAST,                            &LTA_QIOiosb, 0, 0,                            LTAhangupHandler,                            0, 0, 0, 0, 0)) & 1))                lib$signal(status);        if (!(LTA_QIOiosb[0] & 1))                lib$signal(LTA_QIOiosb[0]);        /*        ** Post the first read (with AST) on the LTA device to ensure that the        ** first burst of data from the target service is not lost.  It is very        ** important that the first read is queued before doing the connect        ** $QIO to ensure no data lossage.        */        if (!((status = sys$qio(                            0,                            LTAchannel,                            IO$_READVBLK|IO$M_NOECHO,                            &LTA_QIOiosb,                            LTAreadChannelAST, 0,                            LTAbuffer,                            1, 0, &ReadTerminatorMask, 0, 0)) & 1))                lib$signal(status);        /*        ** Do the LAT connect $QIO and hibernate until program exit.  The        ** ConnectAST will execute when the connection completes and post the        ** initial read on the TT channel.        */        if (!((status = sys$qio(                            0,                            LTAchannel,                            IO$_TTY_PORT|IO$M_LT_CONNECT,                            &LTA_QIOiosb,                            ConnectAST, 0, 0, 0, 0, 0, 0, 0)) & 1))                lib$signal(status);        sys$hiber();}       /* END - main() *//***++****  FUNCTIONAL DESCRIPTION:****      This routine sets device characteristics of the LTA and TT devices.**      The HOSTSYNC, NOBRDCST, EIGHTBIT and PASTHRU characteristics are set** on the LTA device.  The ESCAPE and TTSYNC characteristics are cleared.****      The TTSYNC, HOSTSYNC, EIGHTBIT, and PASTHRU characteristics are set**      on the TT device.  The ESCAPE characteristic is cleared.  The TT**      characterisitcs are also saved for restoration at program exit.****--*/unsigned long   SetDeviceChars(void){        /*        ** Local Variables:        */        unsigned long   status,                        deviceChar[3];        /*        ** BEGIN:        **        ** Mask and set the characteristics of the LTA device.  Sense the        ** current characteristics, and mask in and set the new ones.        */        if (!((status = sys$qiow(                            0,                            LTAchannel,                            IO$_SENSEMODE,                            &LTA_QIOiosb, 0, 0,                            &deviceChar,                            DeviceCharBuffSize, 0, 0, 0, 0)) & 1))                lib$signal(status);        if (!(LTA_QIOiosb[0] & 1))                lib$signal(LTA_QIOiosb[0]);        deviceChar[1] =            (deviceChar[1] | (TT$M_HOSTSYNC | TT$M_NOBRDCST | TT$M_EIGHTBIT))     & ~TT$M_ESCAPE & ~TT$M_TTSYNC;        deviceChar[2] |= TT2$M_PASTHRU;        if (!((status = sys$qiow(                            0,                            LTAchannel,                            IO$_SETMODE,                            &LTA_QIOiosb, 0, 0,                            &deviceChar,                            DeviceCharBuffSize, 0, 0, 0, 0)) & 1))                lib$signal(status);        if (!(LTA_QIOiosb[0] & 1))                lib$signal(LTA_QIOiosb[0]);        /*        ** Repeat the procedure for TT device characteristics.  However, save        ** the current characteristics for restoration at program exit.        */        if (!((status = sys$qiow(                            0,                            TTchannel,                            IO$_SENSEMODE,                            &TT_QIOiosb, 0, 0,                            &SavedTTdeviceChar,                            DeviceCharBuffSize, 0, 0, 0, 0)) & 1))                lib$signal(status);        if (!(TT_QIOiosb[0] & 1))                lib$signal(TT_QIOiosb[0]);        deviceChar[0] = SavedTTdeviceChar[0];        deviceChar[1] = (SavedTTdeviceChar[1] |            (TT$M_TTSYNC | TT$M_HOSTSYNC | TT$M_EIGHTBIT)) & ~TT$M_ESCAPE;        deviceChar[2] = SavedTTdeviceChar[2] | TT2$M_PASTHRU;        if (!((status = sys$qiow(                            0,                            TTchannel,                            IO$_SETMODE,                            &TT_QIOiosb, 0, 0,                            &deviceChar,                            DeviceCharBuffSize, 0, 0, 0, 0)) & 1))                lib$signal(status);        if (!(TT_QIOiosb[0] & 1))                lib$signal(TT_QIOiosb[0]);        return(status);}       /* END - SetDeviceChars *//***++****  FUNCTIONAL DESCRIPTION:****      This routine is an AST which executes when the connect $QIO completes.**      First the IOSB is checked.  If the connection timed out or was aborted,**      simply end the session.  Any other abnormal status causes the program**      to exit.****      Otherwise the connection completed successfully and a read on the TT**      channel is posted.****--*/void    ConnectAST(){        /*        ** Local Variables:        */        unsigned long   status;        /*        ** BEGIN:        **        ** If the status in the IOSB indicates that the connection timed out        ** or aborted, call the session end routine.  Any other abnormal        ** status causes program exit.        */        if ((LTA_QIOiosb[0] == SS$_TIMEOUT) || (LTA_QIOiosb[0] == SS$_ABORT))                EndSession();        if (!(LTA_QIOiosb[0] & 1))                sys$exit(LTA_QIOiosb[0]);        /*        ** The connection completed successfully!  Post a read (with AST) on        ** the TT device and return.        */        if (!((status = sys$qio(                            0,                            TTchannel,                            IO$_READVBLK|IO$M_NOECHO,                            &TT_QIOiosb,                            TTreadChannelAST, 0,                            TTbuffer,                            1, 0, &ReadTerminatorMask, 0, 0)) & 1))                lib$signal(status);        return;}       /* END - ConnectAST *//***++****  FUNCTIONAL DESCRIPTION:****      This routine is an AST which executes when the first character read on**      the LTA channel completes.  It does a "flush" read of the channel to**      drain any data out of the ALTYPAHD buffer and writes the data to the**      TT channel.  It then posts another read on the channel.****--*/void    LTAreadChannelAST(void){        /*        ** Local Variables:        */        unsigned long   status;        /*        ** BEGIN:        **        ** If the status in the IOSB indicates channel hangup, simply end the        ** session.  Signal any other abnormal status.        */        if (LTA_QIOiosb[0] == SS$_HANGUP)                EndSession();        if (!(LTA_QIOiosb[0] & 1))                lib$signal(LTA_QIOiosb[0]);        /*        ** Do a "flush" read of the LTA device.  This is done by doing a timed        ** read with a 0 timeout.  There may or may not be any data to drain.        ** This method is more efficient than using single character reads.        */        if (!((status = sys$qiow(                            0,                            LTAchannel,                            IO$_READVBLK|IO$M_TIMED|IO$M_NOECHO,                            &LTA_QIOiosb, 0, 0,                            LTAbuffer+1,                            LTA_MAXBUF-1, 0,                            &ReadTerminatorMask, 0, 0)) & 1))                lib$signal(status);        if (!(LTA_QIOiosb[0] & 1) && (LTA_QIOiosb[0] != SS$_TIMEOUT))                lib$signal(LTA_QIOiosb[0]);        /*        ** The second word of the IOSB contains the number of characters        ** read.  Write the characters plus 1 for the initial read to the        ** TT device.        */        if (!((status = sys$qiow(                            0,                            TTchannel,                            IO$_WRITEVBLK,                            &TT_QIOiosb, 0, 0,                            LTAbuffer,                            LTA_QIOiosb[1]+1, 0, 0, 0, 0)) & 1))                lib$signal(status);        if (!(TT_QIOiosb[0] & 1))                lib$signal(TT_QIOiosb[0]);        /*        ** Post another read on the LTA device.        */        if (!((status = sys$qio(                            0,                            LTAchannel,                            IO$_READVBLK|IO$M_NOECHO,                            &LTA_QIOiosb,                            LTAreadChannelAST, 0,                            LTAbuffer,                            1, 0, &ReadTerminatorMask, 0, 0)) & 1))                lib$signal(status);        return;}       /* END - LTAreadChannelAST *//***++****  FUNCTIONAL DESCRIPTION:****      This routine is an AST which executes when the first character read on**      the TT channel completes.  It does a "flush" read of the channel to**      drain any data out of the TYPAHD buffer and writes the data to the**      LTA channel.  It then posts another read on the channel.****--*/void    TTreadChannelAST(void){        /*        ** Local Variables:        */        unsigned long   status;        /*        ** BEGIN:        **        ** If the user pressed the connection terminator character, do a LAT        ** disconnect $QIO and exit.        */        if (*TTbuffer == CONNECTION_TERMINATOR)        {                if (!((status = sys$qiow(                                    0,                                    LTAchannel,                                    IO$_TTY_PORT|IO$M_LT_DISCON,                                    &LTA_QIOiosb, 0, 0, 0, 0, 0, 0, 0, 0)) & 1))                        lib$signal(status);                if (!(LTA_QIOiosb[0] & 1))                        lib$signal(LTA_QIOiosb[0]);                return;        }        /*        ** Do a "flush" read of the TT device.  This is done by doing a timed        ** read with a 0 timeout.  There may or may not be any data to drain.        */        if (!((status = sys$qiow(                            0,                            TTchannel,                            IO$_READVBLK|IO$M_TIMED|IO$M_NOECHO,                            &TT_QIOiosb, 0, 0,                            TTbuffer+1,                            TT_MAXBUF-1, 0,                            &ReadTerminatorMask, 0, 0)) & 1))                lib$signal(status);        if (!(TT_QIOiosb[0] & 1) && (TT_QIOiosb[0] != SS$_TIMEOUT))                lib$signal(TT_QIOiosb[0]);        /*        ** The second word of the IOSB contains the number of characters        ** read.  Write the characters plus 1 for the initial read to the        ** TT device.        */        if (!((status = sys$qiow(                            0,                            LTAchannel,                            IO$_WRITEVBLK,                            &LTA_QIOiosb, 0, 0,                            TTbuffer,                            TT_QIOiosb[1]+1, 0, 0, 0, 0)) & 1))                lib$signal(status);        /*        ** If the status in the IOSB indicates channel hangup, simply end        ** the session.  Signal any other abnormal status.        */        if (LTA_QIOiosb[0] == SS$_HANGUP)                EndSession();        if (!(LTA_QIOiosb[0] & 1))                lib$signal(LTA_QIOiosb[0]);        /*        ** Post another read on the LTA device.        */        if (!((status = sys$qio(                            0,                            TTchannel,                            IO$_READVBLK|IO$M_NOECHO,                            &TT_QIOiosb,                            TTreadChannelAST, 0,                            TTbuffer,                            1, 0, &ReadTerminatorMask, 0, 0)) & 1))                lib$signal(status);        return;}       /* END - TTreadChannelAST *//***++****  FUNCTIONAL DESCRIPTION:****      This routine is the CTRL+Y AST for the LTA channel.  It executes when**      a hangup on the LTA channel is recognized (connection timed out or**      aborted).  It will call the session end routine if it hasn't already**      been called by ConnectAST.****      NOTE:   CTRL+Y ASTs for application ports will NOT execute when the**              connection is disconnected.****--*/void    LTAhangupHandler(void){        /*        ** BEGIN:        **        ** Call the session end routine and return.        */        EndSession();        return;}       /* END - LTAhanghupHandler *//***++****  FUNCTIONAL DESCRIPTION:****      This routine is executed at session end.  It will do a $QIO SENSEmode**      and search the resulting itemlist to find the reason for the LAT**      disconnect.  The reason for the disconnect is displayed on the**      terminal and the image exits.****--*/void    EndSession(void){        /*        ** Local Variables:        */        struct ITEM_ENTRY   *itemlistEntry;        unsigned long       status;        char                *senseItemlist = malloc(MAX_SENSE_ITEMLIST_SIZE),                            *itemlistEntryPointer;        /*        ** BEGIN:        **        ** Do the SENSEmode on the port.        */        if (!((status = sys$qiow(                            0,                            LTAchannel,                            IO$_TTY_PORT|IO$M_LT_SENSEMODE,                            &LTA_QIOiosb, 0, 0,                            senseItemlist,                            MAX_SENSE_ITEMLIST_SIZE,                            LAT$C_ENT_PORT|(LAT$M_SENSE_FULL << 0x10),                            0, 0, 0)) & 1))                lib$signal(status);        if (!(LTA_QIOiosb[0] & 1))                lib$signal(LTA_QIOiosb[0]);        /*        ** Set up two pointers used to traverse the itemlist.        */        itemlistEntry = (struct ITEM_ENTRY *) senseItemlist;        itemlistEntryPointer = senseItemlist;        /*        ** Search the itemlist for the LAT$_ITM_DISCONNECT_REASON code to find        ** out why the connection terminated.        */        while (itemlistEntry->LAT$R_ITM_CODE.LAT$W_ITEMCODE !=                LAT$_ITM_DISCONNECT_REASON)        {                /*                ** If the current itemcode being checked has a string value,                ** advance the pointer to the next itemcode by skipping                ** BCNT bytes plus 3 bytes for the BCNT byte itself and the                ** 2 byte itemcode.                */                if (itemlistEntry->                    LAT$R_ITM_CODE.LAT$R_ITM_BITS.LAT$V_STRING)                        itemlistEntryPointer +=                            itemlistEntry->LAT$R_ITEM_VALUE.                                LAT$R_ITEM_COUNTED_STRING.LAT$B_ITEM_BCNT + 3;                /*                ** If the current itemcode being checked has a scalar value,                ** advance the pointer to the next itemcode by skipping 6                ** bytes for the itemcode and the 4 byte scalar.                */                else                        itemlistEntryPointer += 6;                itemlistEntry = (struct ITEM_ENTRY *) itemlistEntryPointer;        }        /*        ** If the disconnect reason is a LAT reject code, print out the        ** text corresponding to the code and set the exit condition value        ** to SS$_NORMAL.        */        if (itemlistEntry->LAT$R_ITEM_VALUE.LAT$L_ITEM_SCALAR_VALUE <=            LATrejectTableSize)        {                printf("\nSession disconnected.  Reason: %s\n\n\n",                    LATrejectTable[ itemlistEntry->LAT$R_ITEM_VALUE.                                    LAT$L_ITEM_SCALAR_VALUE ]);                ExitConditionValue = SS$_NORMAL;        }        /*        ** The scalar value is a LAT facility message code.  Set the exit        ** condition value to be the scalar.  Upon image exit, the        ** corresponding LAT facility message will be displayed.        */        else                ExitConditionValue =                    itemlistEntry->LAT$R_ITEM_VALUE.LAT$L_ITEM_SCALAR_VALUE;        sys$exit(ExitConditionValue);}        /* END - EndSession *//***++****  FUNCTIONAL DESCRIPTION:****      This is the program exit handler which is executed upon image exit.**      It will cancel all pending I/O on the two channels and restore the**      TT channel characteristics.****--*/void    ExitHandler(void){        /*        ** Local Variables:        */        unsigned long   status;        /*        ** BEGIN:        **        ** Cancel I/O on the channels, reset terminal characteristics and        ** return.        */        if (!((status = sys$cancel(LTAchannel)) & 1))                lib$signal(status);        if (!((status = sys$cancel(TTchannel)) & 1))                lib$signal(status);        if (!((status = sys$qiow(                            0,                            TTchannel,                            IO$_SETMODE,                            &TT_QIOiosb, 0, 0,                            &SavedTTdeviceChar,                            DeviceCharBuffSize, 0, 0, 0, 0)) & 1))                lib$signal(status);        if (!(TT_QIOiosb[0] & 1))                lib$signal(TT_QIOiosb[0]);        return;}       /* END - ExitHandler */

The VAX MACRO program FULL_DUPLEX_TERMINAL.MAR (Example 5-2) showsseveral I/O operations using the full-duplex capabilities of theterminal. This program shows some important concepts about terminaldriver programming: assigning an I/O channel, performing full-duplexI/O operations, enabling Ctrl/C AST requests, and itemlist readoperations. The program is designed to run with a terminal set tofull-duplex mode.

The initialization code queues a read request to the terminal andenables Ctrl/C AST requests. The main loop then prints out a randommessage every three seconds. When you enter a message on the terminal,the read AST routine prints an acknowledgment message and queuesanother read request. If you press Ctrl/C, the associated AST routinecancels the I/O operation on the assigned channel and exits to thecommand interpreter.

Example 5-2 FULL_DUPLEX_TERMINAL.MAR Terminal Driver Programming Example

        .TITLE  FULL_DUPLEX TERMINAL PROGRAMMING EXAMPLE        .IDENT  /05/; ********************************************************************;;                         TERMINAL PROGRAM;; ********************************************************************        .SBTTL  DECLARATIONS        .DISABLE        GLOBAL;; Declare the external symbols and MACRO libraries.;        .EXTERNAL       LIB$GET_EF        .LIBRARY        'SYS$LIBRARY:LIB.MLB'        .LIBRARY        'SYS$LIBRARY:STARLET.MLB';; Define symbols;        $IODEF                  ; Define I/O function codes        $QIODEF                 ; Define QIO definition codes        $SSDEF                  ; Define the system service status codes        $TRMDEF                 ; Define itemlist read codes        $TTDEF                  ; Terminal characteristic definitions;; Define macros;        .SHOW        .MACRO  ITEM    LEN=0,CODE,VALUE        .WORD   LEN        .WORD   TRM$_'CODE'        .LONG   VALUE        .LONG   0        .ENDM   ITEM        .NOSHOW;; Declare exit handler control block;EXIT_HANDLER_BLOCK:        .LONG   0               ; System uses this for pointer        .LONG   EXIT_HANDLER    ; Address of exit handler        .LONG   1               ; Argument count for handler        .LONG   STATUS          ; Destination of status codeSTATUS: .BLKL   1               ; Status code from $EXIT;; Allocate terminal descriptor and channel number storage;TT_DESC:        .ASCID  /SYS$INPUT/     ; Logical name of terminalTT_CHAN:        .BLKW   1               ; TT channel number storage;; Define acknowledgment message.  This is done right above input buffer; so that we can concatenate the two together when the acknowledgment; message is issued.;ACK_MSG:        .ASCII  <CR><LF> /Following input acknowledged: /ACK_MSGLEN=.-ACK_MSG            ; Calculate length of message;; Allocate input buffer;IN_BUFLEN = 20                  ; Set length of bufferIN_BUF:        .BLKB   IN_BUFLEN       ; Allocate character bufferIN_IOSB:        .BLKQ   1               ; Input I/O status block;; Define out-of-band ast character mask;CNTRLA_MASK:        .LONG   0        .LONG   ^B0010          ; Control A mask;; Define old terminal characteristics buffer;OLDCHAR_BUF_LEN = 12OLDCHAR_BUF:        .BLKB   OLDCHAR_BUF_LEN;; Define new terminal characteristics buffer;NEWCHAR_BUF_LEN = 12NEWCHAR_BUF:        .BLKB   NEWCHAR_BUF_LEN;; Define carriage control symbols;        CR=^X0D                 ; Carriage return        LF=^X0A                 ; Line feed;; Define output messages;; Output messages are accessed by indexing into a table of; longwords with each message described by a message address and; message length;ARRAY:                          ; Table of message addresses and                                ; lengths        .LONG   10$             ; First message address        .LONG   15$             ; First message length        .LONG   20$        .LONG   25$        .LONG   30$        .LONG   35$        .LONG   40$        .LONG   45$;; Define messages;10$:    .ASCII            <CR><LF>/RED ALERT! RED ALERT!/15$=.-10$;20$:    .ASCII            <CR><LF>/ALL SYSTEMS GO/25$=.-20$;30$:    .ASCII            <CR><LF>/WARNING..INTRUDER ALARM/35$=.-30$;40$:    .ASCII            <CR><LF>/** SYSTEM OVERLOAD **/45$=.-40$;; Static QIO packet for message output using QIO$_G form;WRITE_QIO:        $QIO    EFN=SYNC_EFN, - ; QIO packet                FUNC=IO$_WRITEVBLK!IO$M_BREAKTHRU!IO$M_REFRESH, -                IOSB=SYNC_IOSB;; Declare the required I/O status blocks.;SYNC_IOSB::     .BLKQ   1       ; I/O status block for synchronous terminal processing.;; Declare the required event flags.;ASYNC_EFN::     .BLKL   1       ; Event flag for asynchronous terminal processing.SYNC_EFN        ==      WRITE_QIO + 4   ; Event flag for sync terminal processing.TIMER_EFN::     .BLKL   1       ; Event flag for timer processing.;; Timer storage;WAITIME:        .LONG   -10*1000*1000*3,-1     ; 3 second delta timeTIME:        .BLKQ   1               ; Current storage time used for                                ; random number        .PAGE        .SBTTL  START - MAIN ROUTINE        .ENABLE LOCAL_BLOCK;++;; Functional description:;; ********************************************************************;;                      Start program;; ********************************************************************;;       The following code performs initialization functions.;       It is assumed that the terminal is already in;       FULL-DUPLEX mode.;;       NOTE: When doing QIO_S calls, parameters P1 and P3-P6 should be;             passed by value, while P2 should be passed by reference.;; Input parameters:;       None;; Output parameters:;       None;;--        .ENTRY  START   ^M < >;               Get the required event flags.        PUSHAL  ASYNC_EFN        CALLS   # 1, G^ LIB$GET_EF      ; Get EFN for async terminal operations.        BLBC    R0, 10$                 ; Error - branch.        PUSHAL  SYNC_EFN        CALLS   # 1, G^ LIB$GET_EF      ; Get EFN for sync terminal operations.        BLBC    R0, 10$                 ; Error - branch.        PUSHAL  TIMER_EFN        CALLS   # 1, G^ LIB$GET_EF      ; Get EFN for timer operations.        BLBC    R0, 10$                 ; Error - branch.;               Initialize the terminal characteristics.        $ASSIGN_S       DEVNAM=TT_DESC,-; Assign terminal channel using                        CHAN=TT_CHAN    ; logical name and channel number        BLBC    R0, 10$                 ; Error - branch.        BSBW    CHANGE_CHARACTERISTICS  ; Change the characteristics of                                        ; terminal        BSBW    ENABLE_CTRLCAST         ; Allow Ctrl/C traps        BSBW    ENABLE_OUTBANDAST       ; Enable Ctrl/A out-of-band AST        BSBW    ENABLE_READ             ; Queue read        MOVZWL  TT_CHAN, WRITE_QIO+8    ; Insert channel into        BRB     LOOP                    ; static QIO packet10$:        BRW     ERROR;; This loop outputs a message based on a random number and then; delays for 3 seconds;LOOP:        $GETTIM_S      TIMADR=TIME      ; Get random time        BLBC    R0, 10$                 ; Error - branch.        EXTZV   #6, #2, TIME, R0        ; Load random bits into switch        MOVQ    ARRAY[R0], -            ; Load message address                WRITE_QIO+QIO$_P1       ; and size into QIO                                        ; packet;; Issue QIO write using packet defined in data area;        $QIOW_G WRITE_QIO        BLBC    R0, 10$                 ; QIO error - branch.        MOVZWL  SYNC_IOSB, R0           ; Get the terminal driver status.        BLBC    R0, 10$                 ; Terminal driver error - branch.;; Delay for 3 seconds before issuing next message;        $SETIMR_S       EFN=TIMER_EFN,- ; Timer service                        DAYTIM=WAITIME  ; will set event flag                                        ; in 3 seconds        BLBC    R0, 10$                 ; Error - branch.        $WAITFR_S       EFN=TIMER_EFN   ; Wait for event flag        BLBS    R0, LOOP                ; No error if set        BRB     10$                     ; Error - branch.        .DISABLE        LOCAL_BLOCK        .PAGE        .SBTTL  CHANGE_CHARACTERISTICS - CHANGE CHARACTERISTICS OF TERMINAL;++;; Functional description:;;       Routine to change the characteristics of the terminal.;; Input parameters:;       None;; Output parameters:;       R0 - status from $QIO call.;       R1 - R5 destroyed;;--;CHANGE_CHARACTERISTICS:        $QIOW_S EFN=SYNC_EFN, -         ; Get current terminal characteristics                CHAN=TT_CHAN, -                FUNC=#IO$_SENSEMODE, -                IOSB=SYNC_IOSB, -                P1=OLDCHAR_BUF, -                P2=#OLDCHAR_BUF_LEN        BLBC    R0, 10$                 ; Error if clear        MOVZWL  SYNC_IOSB, R0           ; Get the terminal driver status.        BLBC    R0, 10$                 ; Error - branch        $DCLEXH_S EXIT_HANDLER_BLOCK    ; Declare exit handler to reset                                        ; characteristics        BLBC    R0, 10$                 ; Error - branch.        MOVC3   #OLDCHAR_BUF_LEN, -     ; Move old characteristics into                OLDCHAR_BUF, -          ; new characteristics buffer                NEWCHAR_BUF        BISL2   #TT$M_NOBRDCST, -       ; Set nobroadcast bit                NEWCHAR_BUF+4           ; ...        $QIOW_S EFN=SYNC_EFN, -         ; Set current terminal characteristics                CHAN=TT_CHAN, -                FUNC=#IO$_SETMODE, -                IOSB=SYNC_IOSB, -                P1=NEWCHAR_BUF, -                P2=#NEWCHAR_BUF_LEN        BLBC    R0, 10$                 ; QIO error - branch.        MOVZWL  SYNC_IOSB, R0           ; Get the terminal driver status.        BLBC    R0, 10$                 ; Terminal driver error - branch.        RSB10$:        BRW     ERROR        .PAGE        .SBTTL  ENABLE_CTRLCAST - ENABLE Ctrl/C AST;++;; Functional description:;;       Routine to allow Ctrl/C recognition.;; Input parameters:;       None;; Output parameters:;       None;;--;ENABLE_CTRLCAST:        $QIOW_S EFN=SYNC_EFN, -                CHAN=TT_CHAN, -                FUNC=#IO$_SETMODE!IO$M_CTRLCAST, -                IOSB=SYNC_IOSB, -                P1=CTRLCAST, -          ; AST routine address                P3=#3                   ; User mode        BLBC    R0, 10$                 ; Error - branch.        MOVZWL  SYNC_IOSB, R0           ; Get the terminal driver status.        BLBC    R0, 10$                 ; Terminal driver error - branch.        RSB10$:        BRW     ERROR        .PAGE        .SBTTL  ENABLE_OUTBANDAST - ENABLE Ctrl/A AST;++;; Functional description:;;       Routine to allow CNTRL/A recognition.;; Input parameters:;       None;; Output parameters:;       None;ENABLE_OUTBANDAST:        $QIOW_S EFN=SYNC_EFN, -                CHAN=TT_CHAN, -                FUNC=#IO$_SETMODE!IO$M_OUTBAND, -                IOSB=SYNC_IOSB, -                P1=CTRLAAST, -          ; AST routine address                P2=#CNTRLA_MASK, -      ; Character mask                P3=#3                   ; User mode        BLBC    R0, 10$                 ; QIO error - branch.        MOVZWL  SYNC_IOSB, R0           ; Get the terminal driver status.        BLBC    R0, 10$                 ; Terminal driver error - branch.        RSB10$:        BRW     ERROR        .PAGE        .SBTTL  ENABLE_READ - QUEUE A READ TO THE TERMINAL.;++;; Functional description:;;       Routine to queue a read operation to the terminal.;; Input parameters:;       None;; Output parameters:;       None;; Define item list for itemlist read;ITEM_LST:        ITEM    0, MODIFIERS, -                 ; Convert lowercase to                TRM$M_TM_CVTLOW!TRM$M_TM_NOEDIT ; upper and inhibit line        ITEM    6, TERM,MASK_ADDR               ; editing                                                ; Set up terminator maskITEM_LEN        =       . - ITEM_LSTMASK_ADDR:        .LONG   1@^XD                   ; Terminator mask is                                        ; <CR>        .WORD   1@4                     ; and "$"ENABLE_READ:        $QIO_S  EFN=ASYNC_EFN, -        ; Must not be QIOW form or read will block                CHAN=TT_CHAN, -         ; process                FUNC=#IO$_READVBLK!IO$M_EXTEND, -                IOSB=IN_IOSB, -                ASTADR=READAST, -       ; AST routine to execute                P1=IN_BUF, -            ; on                P2=#IN_BUFLEN, -                P5=#ITEM_LST, -         ; Itemlist read address                P6=#ITEM_LEN            ; Itemlist read size        BLBC    R0, 10$                 ; QIO error - branch.; The queued read operation will not affect write operations due; to the fact that breakthru has been set for the write operations.        RSB10$:        BRW     ERROR        .PAGE        .SBTTL  READAST - AST ROUTINE FOR READ COMPLETION        .ENABLE LOCAL_BLOCK;++;; Functional description:;;       AST routine to execute on read completion.;; Input parameters:;       None;; Output parameters:;       None;;--;10$:        MOVZWL  IN_IOSB, R0             ; Get the terminal driver status20$:        BRW     ERROR                   ; Exit with error status.        .ENTRY  READAST         ^M < R2, R3, R4, R5 >   ; Procedure entry mask        BLBC    IN_IOSB, 10$            ; Terminal driver error - branch        MOVZWL  IN_IOSB+2, R0           ; Get number of characters read into R0        ADDL2   #ACK_MSGLEN, R0         ; Add size of fixed acknowledge message        $QIO_S  EFN=ASYNC_EFN, -        ; Issue acknowledge message                CHAN=TT_CHAN, -         ; Note, ACK must be asynchronous (QIO)                FUNC=#IO$_WRITEVBLK, -  ; and the terminal driver write status                P1=ACK_MSG, -           ; is ignored (no IOSB and AST routine).                P2=R0                   ; Specify IOSB and AST routine if output                                        ; must be displayed on the terminal.        BLBC    R0, 20$                 ; QIO error - branch;; Process read message;;        .;        .;        .;(user-provided code to decode command inserted here);        .;        .;        .        BSBW     ENABLE_READ            ; Queue next read        RET                             ; Return to mainline loop        .DISABLE        LOCAL_BLOCK        .PAGE        .SBTTL  CTRLAAST - AST ROUTINE FOR Ctrl/A        .SBTTL  CTRLCAST - AST ROUTINE FOR Ctrl/C        .SBTTL  ERROR - EXIT ROUTINE;++;; Functional description:;;       AST routine to execute when Ctrl/C or Ctrl/A is entered.;; Input parameters:;       None;; Output parameters:;       None;CTRLCAST::CTRLAAST::        .WORD   ^M < >                  ; Procedure entry mask        MOVL    #SS$_NORMAL, R0         ; Put success in R0ERROR::        $EXIT_S R0                      ; Exit        RSB        .PAGE        .SBTTL  EXIT_HANDLER - EXIT HANDLER ROUTINE;++;; Functional description:;;       Exit handler routine to execute when image exits.  It cancels;       any outstanding I/O on this channel and resets the terminal;       characteristics to their original state.;; Input parameters:;       None;; Output parameters:;       None;;--;        .ENTRY  EXIT_HANDLER    ^M< >        $CANCEL_S       CHAN=TT_CHAN    ; Flush any I/O on queue        $QIOW_S EFN=SYNC_EFN, -         ; Reset terminal characteristics                CHAN=TT_CHAN, -                FUNC=#IO$_SETMODE, -                IOSB=SYNC_IOSB, -                P1=OLDCHAR_BUF, -                P2=#OLDCHAR_BUF_LEN        BLBC    R0, 10$                 ; QIO error - branch.        MOVZWL  SYNC_IOSB, R0           ; Get the terminal driver status.10$:        RET        .END     START


Previous Next Contents Index