home *** CD-ROM | disk | FTP | other *** search
/ Microsoft Programmer's Library 1.3 / Microsoft-Programers-Library-v1.3.iso / sampcode / os2sdk / os2sdk12 / terminal / terminal.c < prev    next >
Encoding:
C/C++ Source or Header  |  1990-07-06  |  15.3 KB  |  595 lines

  1. /***
  2.  *
  3.  * TITLE 
  4.  *
  5.  *    terminal.c
  6.  *    Created by Microsoft Corporation 1987
  7.  *
  8.  * DESCRIPTION
  9.  *
  10.  *     This program emulates an ANSI terminal device. 
  11.  *
  12.  *     The device driver COM.SYS must be installed at IPL  (Initial Program
  13.  *     Load) by specifying the following in config.sys:
  14.  *        device = COM01.SYS
  15.  *
  16.  *    To run this program, type the following to the MS OS/2 prompt:
  17.  *
  18.  *        terminal [filename]
  19.  *
  20.  *     If a filename is specified, the initialisation of the COM port and
  21.  *     the MODEM will be performed as indicated in the file (creation of this
  22.  *     file is described in options.c). For more details on setting options
  23.  *    pertaining to the COM port and the MODEM, see options.c
  24.  *
  25.  *    To exit the terminal emulator, type ALT F1.
  26.  *
  27.  ***/
  28.  
  29. #define INCL_DOSSIGNALS
  30. #define INCL_SUB
  31. #define INCL_DOSFILEMGR
  32. #define INCL_DOSPROCESS
  33. #define INCL_DOSDEVICES
  34.  
  35. #include    <os2def.h>
  36. #include    <bse.h>
  37. #include    <stdio.h>
  38. #include    <malloc.h>
  39. #include    <string.h>
  40. #include     <memory.h>
  41. #include     <conio.h>
  42. #include     "term.h"
  43.  
  44. extern void get_options(int, char *[]);   /* get com port and modem options */
  45. extern void get_com_options(structComOptions *); /* get com options */
  46. extern make_modem_conn(void);          /* make modem connection */
  47. extern modem(void);       /* returns TRUE if modem connection was requested */
  48. extern void discon_modem(void);       /* disconnect modem */
  49.  
  50. void init_com_port(void);          /* initialise com port */
  51. void far read_com_port(void);          /* routine addr for a thread */
  52. void write_com_port(void);          /* routine addr for another thread */    
  53. void APIENTRY handle_signals(USHORT,USHORT); /* BREAK signals handler */
  54. void close_conn(void);              /*close modem connection & com port*/
  55. void far xit(void);            /* exit routine for this program */
  56.  
  57. char *ErrMsg[] = {
  58.         "VIOGETCONFIG",
  59.         "KBDSETSTATUS",
  60.                "OUT OF MEMORY",
  61.         "DOSCREATETHREAD",
  62.         "DOSCLOSE COMPORT",
  63.         "DOSDEVIOCTL SETDCB",
  64.         "DOSREAD",
  65.         "VIOWRTTTY",
  66.         "DOSOPEN: check if COM driver is installed",
  67.         "DOSDEVIOCTL SETBAUD",
  68.         "DOSDEVIOCTL SETLINECHAR",
  69.         "DOSDEVIOCTL GETDCB",
  70.         "KBDCHARIN",
  71.         "DOSWRITE",
  72.         "VIOWRTCHARSTRATT",
  73.         "VIOWRTNCELL",
  74.         "DOSEXITLIST ADD_ADDR",
  75.         "VIOSETCURPOS",
  76.         "VIOGETMODE",
  77.         "DOSDEVIOCTL FLUSH_XMIT_RECV_QUEUE",
  78.         "DOSDEVIOCTL GETCOM",
  79.         "DOSSETSIGHANDLER",
  80.         "DOSDEVIOCTL SETBREAKON",
  81.         "DOSDEVIOCTL SETBREAKOFF",
  82.                "INVALID SIGNAL",
  83.                "do_option: invalid option type",
  84.                "mod_option: invalid option type",
  85.                "show_option: invalid option type"
  86. };
  87. HFILE        FileHndl = (HFILE) NULL;    /* COM port file handle */
  88.  
  89. static char    ExitPgm = FALSE;    /* indicate if program should terminate */
  90. static int    ErrorNumber = -1,   /* used as index to ErrMsg array */
  91.         ReturnCode  = -1;   /* retcode from system/subsystem call */
  92.  
  93.  
  94.  
  95.  
  96. /***    main - entry point to TERMINAL program
  97.  *
  98.  *    This routine obtains the com port and the modem options from the file
  99.  *      (specified in the command line) or directly from the user. It opens and
  100.  *    initialises the com port. It sets up the modem connection (if one was
  101.  *    requested). It creates a thread which loops continuously waiting to 
  102.  *    receive data from the com port and writing it out to the display. It 
  103.  *    loops continuosly waiting for an input from the keyboard and writing 
  104.  *    it out to the com port. Both the loops terminate when the user presses 
  105.  *    ALT-F1. It closes the modem connection (if one was made), and the com 
  106.  *    port and then terminates.
  107.  *
  108.  *    main(argc, argv)
  109.  *
  110.  *    ENTRY    
  111.  *        argc - number of command line arguments
  112.  *        argv - pointer to an array of pointers (to command line args)
  113.  *
  114.  *    EXIT
  115.  *        the program terminates
  116.  *
  117.  *    WARNING
  118.  *
  119.  *    EFFECTS
  120.  *
  121.  ***/
  122.  
  123. main(argc,argv)
  124. int     argc;
  125. char     *argv[];
  126. {
  127.     UCHAR        *Stack1;         /* stack for a thread */
  128.     TID        ThreadID;
  129.     unsigned    RetCode,         /* return code */
  130.             Result = TRUE;
  131.     USHORT        NumBytes;         /* number of bytes to be written */
  132.     PFNSIGHANDLER    PrevAddress;
  133.     USHORT        PrevAction;
  134.     static KBDINFO OurKbdStatus =
  135.                                    {sizeof(OurKbdStatus),KBD_BITMASK,};
  136.  
  137.     /* get COM port and modem options */
  138.     get_options(argc, argv);    
  139.  
  140.     /* open and initialise COM port */
  141.     init_com_port();            
  142.  
  143.     /* establish xit() as the exit routine */
  144.     if ((RetCode = DosExitList(EXLST_ADD, (PFNEXITLIST)xit)) != 0)
  145.       error(ERR_DOSEXITLIST, RetCode);
  146.  
  147.     /* make modem connection if requested */
  148.     if (modem())
  149.       Result = make_modem_conn();    
  150.  
  151.     if (Result) {
  152.       /* allocate memory for separate thread execution */
  153.       if (!(Stack1 = (char *) _nmalloc(STACKSIZE)))
  154.         error(ERR_OUTOFMEMORY, NO_RETCODE);
  155.  
  156.       /* create a thread that will execute the read_com_port() */
  157.       Stack1 += STACKSIZE;
  158.       if ((RetCode = DosCreateThread(read_com_port, &ThreadID,
  159.                                          Stack1)) != 0)
  160.         error(ERR_DOSCREATETHREAD, RetCode);
  161.  
  162.       /* set the keyboard status */
  163.       if ((RetCode = KbdSetStatus(&OurKbdStatus,
  164.                                       RESERVED)) != 0) 
  165.         error(ERR_KBDSETSTATUS, RetCode);
  166.  
  167.       /* set signal handler for BREAK signal */
  168.       if ((RetCode = DosSetSigHandler(handle_signals,
  169.              &PrevAddress,
  170.              &PrevAction,
  171.              RECV_CTRL, BREAK)) != 0)
  172.         error(ERR_DOSSETSIGHANDLER, RetCode);
  173.  
  174.       /* display "connected" message */
  175.       printf("connected... \n");
  176.  
  177.       /* read chars from the keyboard and write to COM port */
  178.       write_com_port();
  179.     }    /* if (Result) */
  180. }
  181.  
  182.  
  183.  
  184.  
  185. /***    init_com_port - open the COM port and initialise line characteristics
  186.  *
  187.  *    This routine opens the com port. It sets the com port options 
  188.  *    BaudRate, DataBits, Parity and the StopBits. It sets the read timeout.
  189.  *    It enables the automatic transmit and receive flow control.
  190.  *
  191.  *    init_com_port()
  192.  *        
  193.  *    ENTRY
  194.  *        
  195.  *    EXIT
  196.  *        FileHndl = handle to com port
  197.  *
  198.  *    WARNING
  199.  *
  200.  *    EFFECTS
  201.  *
  202.  ***/
  203.  
  204. void init_com_port()
  205. {
  206.     USHORT        ActionTaken; /* action: file existed,created,replaced */
  207.     unsigned    RetCode;
  208.     structLineChar     sLineChar;    /* line characteristics */
  209.     structDCB    sDCB;        /* device control block information */
  210.     structComOptions sComOptions;
  211.  
  212.     get_com_options(&sComOptions);
  213.  
  214.     /* open the com port */
  215.     if ((RetCode = DosOpen(sComOptions.pPortName, &FileHndl,
  216.                                &ActionTaken, 0L, 0, 0x0001, 0x0042, 0L)) != 0)
  217.       error(ERR_DOSOPEN, RetCode);
  218.  
  219.     /* set the baud rate */
  220.     if ((RetCode = DosDevIOCtl(0L, &(sComOptions.iBaudRate),
  221.                        SETBAUD, SERIAL, FileHndl)) != 0)
  222.       error(ERR_IOCTLSETBAUD, RetCode);
  223.  
  224.     /* set Data Bits, Stop Bits, Parity */
  225.     sLineChar.DataBits = sComOptions.chDataBits; 
  226.         sLineChar.Parity   = sComOptions.chParity; 
  227.     sLineChar.StopBits = sComOptions.chStopBits;
  228.     if ((RetCode = DosDevIOCtl(0L, &sLineChar, SETLINECHAR,
  229.                        SERIAL, FileHndl)) != 0)
  230.       error(ERR_IOCTLSETLINECHAR, RetCode);
  231.  
  232.     /* get device control block info */
  233.     if ((RetCode = DosDevIOCtl(&sDCB, 0L, GETDCB, SERIAL,
  234.                                    FileHndl)) != 0)
  235.       error(ERR_IOCTLGETDCB, RetCode);
  236.  
  237.     sDCB.Flags2 |= 0x03;    /* enable auto Xmit and recv flow control */
  238.     sDCB.Flags3 &= 0xf9;    /* clear read timeout flags */
  239.     sDCB.Flags3 |= 0x04;    /* set wait for something read timeout */
  240.     sDCB.ReadTimeOut = READTIMEOUT;    /* set read timout value */
  241.  
  242.     /* set device control block info */
  243.     if ((RetCode = DosDevIOCtl(0L, &sDCB, SETDCB, SERIAL,
  244.                     FileHndl)) != 0)
  245.       error(ERR_IOCTLSETDCB, RetCode);
  246. }
  247.  
  248.  
  249.  
  250.  
  251. /***    write_com_port    - read chars from the keyboard and write to COM port
  252.  *
  253.  *    This routine loops continuosly waiting for a keyboard input and
  254.  *    writing it out to the com port. The loop terminates when the user
  255.  *    presses the ALT-F1.
  256.  *
  257.  *    write_com_port()
  258.  *
  259.  *    ENTRY
  260.  *
  261.  *    EXIT
  262.  *
  263.  *    WARNING
  264.  *
  265.  *    EFFECTS
  266.  *
  267.  ***/
  268.  
  269. void write_com_port()
  270. {
  271.     USHORT        NumBytes;    /* number of bytes actually written */
  272.     unsigned    RetCode;
  273.     char        OutBuffer;    /* output buffer */
  274.     KBDKEYINFO    OurKeyData;    /* struc to read a char from kbd */
  275.  
  276.  
  277.     while (!ExitPgm) {
  278.       /* read input from the keyboard */
  279.       if ((RetCode = KbdCharIn(&OurKeyData,
  280.                                    IOWAIT, RESERVED)) != 0) 
  281.         error(ERR_KBDCHARIN, RetCode);
  282.       OutBuffer = OurKeyData.chChar;
  283.       if ((OutBuffer == 0) || (OutBuffer == 0xE0)) {
  284.         OutBuffer = OurKeyData.chScan;
  285.         switch (OutBuffer) {
  286.           case DEL_SCAN  : OutBuffer = DEL_ASCII;
  287.                                break;
  288.           case ALT_F1    : ExitPgm = TRUE;
  289.                                break;
  290.               default        : break;
  291.             };
  292.             if (OutBuffer != ALT_F1) 
  293.           /* write the input from the keyboard to the com port */
  294.           if ((RetCode = DosWrite(FileHndl, &OutBuffer, 1,
  295.                                       &NumBytes)) != 0)
  296.         error(ERR_DOSWRITE, RetCode);
  297.       }
  298.           else {
  299.         /* write the input from the keyboard to the com port */
  300.         if ((RetCode = DosWrite(FileHndl, &OutBuffer, 1,
  301.                                     &NumBytes)) != 0)
  302.           error(ERR_DOSWRITE, RetCode);
  303.       };
  304.     };
  305. }
  306.  
  307.  
  308.  
  309.  
  310. /***     read_com_port - read chars from com port and display on CRT screen 
  311.  *
  312.  *     This routine is executed by a thread. It loops continuously waiting
  313.  *      to receive data from the com port and writing it out to the display.
  314.  *    The loop terminates when the user presses ALT-F1.
  315.  *
  316.  *    read_com_port()
  317.  *
  318.  *    ENTRY
  319.  *        FileHndl (handle to com port) setup
  320.  *
  321.  *    EXIT
  322.  *
  323.  *    WARNING
  324.  *
  325.  *    EFFECTS
  326.  *
  327.  ***/
  328.  
  329. void far read_com_port()
  330. {
  331.     USHORT        NumBytes;    /* number of bytes actually read */
  332.     unsigned    RetCode;
  333.     struct CharsInQue {     /*data ret'ned by get num chars in que IOCTL*/
  334.             unsigned     NumCharsInQue;
  335.             unsigned    SizeQue;
  336.     } sCharsInQue;
  337.     char        InBuffer[INBUFLENGTH];    /* input buffer  */
  338.  
  339.     while (!ExitPgm) {
  340.       /* get number of characters in receive queue */
  341.       if ((RetCode = DosDevIOCtl(&sCharsInQue, 0L, GETNUMCHARS,
  342.                                      SERIAL, FileHndl)) != 0)
  343.         setup_error_msg(ERR_IOCTLSETDCB, RetCode);
  344.  
  345.       if (sCharsInQue.NumCharsInQue == 0)
  346.          sCharsInQue.NumCharsInQue++;
  347.  
  348.       if ((RetCode = DosRead(FileHndl, InBuffer, sCharsInQue.NumCharsInQue,
  349.                                  &NumBytes)) != 0)
  350.         setup_error_msg(ERR_DOSREAD, RetCode);
  351.     
  352.       if (NumBytes) {
  353.         /* write to the tty display */
  354.         if ((RetCode = VioWrtTTY(InBuffer, NumBytes, RESERVED)) != 0)
  355.           setup_error_msg(ERR_VIOWRTTTY, RetCode);
  356.       }
  357.     }
  358. }
  359.  
  360.  
  361.  
  362.  
  363. /***    handle_signals  - handle BREAK signal
  364.  *
  365.  *    This routine is the handler for the BREAK signal. When the user presses
  366.  *    the BREAK key, this routine sends a BREAK on the com line.
  367.  *
  368.  *    handle_signals(SigArg, SigNumber)
  369.  *
  370.  *    ENTRY
  371.  *        SigArg - not used
  372.  *        SigNumber - signal number being processed
  373.  *
  374.  *    EXIT
  375.  *
  376.  *    WARNING
  377.  *
  378.  *    EFFECTS
  379.  *        Since this is a signal handler it must be declared FAR.
  380.  *
  381.  ***/
  382.  
  383. void APIENTRY handle_signals(SigArg, SigNumber)
  384. USHORT    SigArg,
  385.     SigNumber;
  386. {
  387.     unsigned    RetCode,
  388.             Status;
  389.     char        OutBuffer;
  390.  
  391.     switch (SigNumber) {
  392.     case BREAK :/* send BREAK to the com port */
  393.             if ((RetCode = DosDevIOCtl(&Status, 0L,
  394.                                        SETBREAKON, SERIAL, FileHndl)) != 0)
  395.                   error(ERR_IOCTLSETBREAKON, RetCode);
  396.             DosSleep(1L);
  397.             if ((RetCode = DosDevIOCtl(&Status, 0L,
  398.                                        SETBREAKOFF, SERIAL, FileHndl)) != 0)
  399.                   error(ERR_IOCTLSETBREAKOFF, RetCode);
  400.             break;
  401.     default    :
  402.             error(ERR_INVALIDSIGNAL, NO_RETCODE);
  403.             break;
  404.     }
  405. }
  406.  
  407.  
  408.  
  409.  
  410. /***    close_conn - close modem connection and the com port 
  411.  *
  412.  *    This routine closes the modem connection if one was made and then
  413.  *    closes the com port.
  414.  *
  415.  *    close_conn()
  416.  *
  417.  *    ENTRY
  418.  *
  419.  *    EXIT
  420.  *
  421.  *    WARNING
  422.  *
  423.  *    EFFECTS
  424.  *
  425.  ***/
  426.  
  427. void close_conn()
  428. {
  429.     int        RetCode;
  430.     static char     CloseMsg[] = "exiting terminal...";
  431.  
  432.     /* send closing message to the display */
  433.     if ((RetCode = VioWrtTTY(CloseMsg, sizeof(CloseMsg), RESERVED)) != 0)
  434.       print_err_msg(ErrMsg[ERR_VIOWRTTTY], RetCode);
  435.  
  436.     /* if modem connection was made, close it */
  437.     if (modem())
  438.       discon_modem();
  439.  
  440.     /* close the com port */
  441.     if ((RetCode = DosClose(FileHndl)) != 0)
  442.       print_err_msg(ErrMsg[ERR_DOSCLOSECOMPORT], RetCode);
  443. }
  444.  
  445.  
  446.  
  447.  
  448. /***        ERROR HANDLING
  449.  *
  450.  *    There are two error handling routines:
  451.  *        - error() which is invoked from the main thread
  452.  *        - setup_err_msg() which is invoked from the thread executing 
  453.  *          the read_com_port() routine
  454.  *    The two routines perform different functions (described below). This
  455.  *    is done so that if an error is encountered "simultaneously" in both 
  456.  *    the threads, there will be no race condition in error reporting.
  457.  *    
  458.  *    The following routines are also part of the error handling:
  459.  *        - xit() is a DosExitList routine
  460.  *        - print_err_msg() does the actual printing of the error message
  461.  *    
  462.  *    All the routines discussed above are defined below.
  463.  *
  464.  ***/
  465.  
  466.  
  467.  
  468. /***    error
  469.  *
  470.  *    This routine is invoked when there is an error. It prints an
  471.  *    an error message and calls DosExit.
  472.  *
  473.  *    error(ErrNum, RetCode)
  474.  *
  475.  *    ENTRY
  476.  *        ErrNum - error number (used as index to error message array)
  477.  *        RetCode - return code from a DOS system/subsystem call
  478.  *
  479.  *    EXIT
  480.  *            global variables ErrorNumber & ReturnCode still contain the
  481.  *        initial value of -1. At program termination (via DosExit call)
  482.  *        the DosExitList routine xit() is invoked (described below).
  483.  *        On return from xit(), this program will terminate.
  484.  *
  485.  *    WARNING
  486.  *
  487.  *    EFFECTS
  488.  *
  489.  ***/
  490.  
  491. error(ErrNum, RetCode)
  492. int  ErrNum;
  493. int  RetCode;
  494. {
  495.     print_err_msg(ErrMsg[ErrNum], RetCode);
  496.     DosExit(EXIT_PROCESS, 1);
  497. }
  498.  
  499.  
  500.  
  501.  
  502. /***    setup_error_msg - setup error message
  503.  *
  504.  *    Sets up the global ErrorNumber and ReturnCode. It then calls DosExit.
  505.  *
  506.  *    setup_error_msg(ErrNum, RetCode)
  507.  *
  508.  *    ENTRY
  509.  *        ErrNum - error number (used as index to error message array)
  510.  *        RetCode - return code from a DOS system/subsystem call
  511.  *
  512.  *    EXIT
  513.  *        global variables ErrorNumber & ReturnCode are setup. At 
  514.  *        program termination (via DosExit call) the DosExitList
  515.  *        routine xit() is invoked (described below). xit() will print
  516.  *        an error message. On return from xit(), this program will 
  517.  *        terminate.
  518.  *
  519.  *    WARNING
  520.  *
  521.  *    EFFECTS
  522.  *
  523.  ***/
  524.  
  525. setup_error_msg(ErrNum, RetCode)
  526. int    ErrNum,
  527.     RetCode;
  528. {
  529.     ErrorNumber = ErrNum;
  530.     ReturnCode  = RetCode;
  531.     DosExit(EXIT_PROCESS, 1);
  532. }
  533.  
  534.  
  535.  
  536.  
  537. /***    xit    - exit function executed at program termination
  538.  *
  539.  *    This is a DosExitList routine. It prints an error message if
  540.  *    the global variable ErrorNumber is non-negative.
  541.  *
  542.  *    xit()
  543.  *
  544.  *    ENTRY
  545.  *
  546.  *    EXIT
  547.  *        If ErrorNumber is non-negative, an error message is printed.
  548.  *        The program will then terminate.
  549.  *
  550.  *    WARNING
  551.  *
  552.  *    EFFECTS
  553.  *
  554.  ***/
  555.  
  556. void far xit(void)
  557. {
  558.     if (ErrorNumber != -1) 
  559.       print_err_msg(ErrMsg[ErrorNumber], ReturnCode);
  560.     close_conn();         /* close modem connection and the com port */
  561.     DosExitList(XFER, 0L);
  562. }
  563.  
  564.  
  565.  
  566.  
  567. /***    print_err_msg - print error mesage
  568.  *
  569.  *    This routine prints an error message and the returncode.
  570.  *
  571.  *    print_err_msg(Msg, Retcode)
  572.  *
  573.  *    ENTRY
  574.  *        Msg - error message string
  575.  *        Retcode - returncode from DOS system/subsystem call
  576.  *
  577.  *    EXIT
  578.  *
  579.  *    WARNING
  580.  *
  581.  *    EFFECTS
  582.  *
  583.  ***/
  584.  
  585. print_err_msg(Msg, RetCode)
  586. char    *Msg;
  587. int    RetCode;
  588.  
  589. {
  590.       printf("*** ERROR %s *** ", Msg);
  591.      if (RetCode != -1)
  592.       printf("ReturnCode = %d ", RetCode);
  593.     printf("\n");
  594. }
  595.