home *** CD-ROM | disk | FTP | other *** search
/ ftp.wwiv.com / ftp.wwiv.com.zip / ftp.wwiv.com / pub / INTERNET / UPC2S1.ZIP / ULIB.C < prev    next >
C/C++ Source or Header  |  1993-10-03  |  22KB  |  608 lines

  1. /*--------------------------------------------------------------------*/
  2. /*    u l i b . c                                                     */
  3. /*                                                                    */
  4. /*    Serial port interface to COMMFIFO.ASM for MS-DOS                */
  5. /*--------------------------------------------------------------------*/
  6.  
  7. /*--------------------------------------------------------------------*/
  8. /*    Changes Copyright (c) 1989-1993 by Kendra Electronic            */
  9. /*    Wonderworks.                                                    */
  10. /*                                                                    */
  11. /*    All rights reserved except those explicitly granted by the      */
  12. /*    UUPC/extended license agreement.                                */
  13. /*--------------------------------------------------------------------*/
  14.  
  15. /*--------------------------------------------------------------------*/
  16. /*                          RCS Information                           */
  17. /*--------------------------------------------------------------------*/
  18.  
  19. /*
  20.  *    $Id: ulib.c 1.18 1993/10/03 22:09:09 ahd Exp $
  21.  *
  22.  *    $Log: ulib.c $
  23.  * Revision 1.18  1993/10/03  22:09:09  ahd
  24.  * Use unsigned long to display speed
  25.  *
  26.  * Revision 1.17  1993/09/29  13:18:06  ahd
  27.  * Use new dummy setprty function
  28.  *
  29.  * Revision 1.16  1993/09/27  04:04:06  ahd
  30.  * Normalize references to modem speed to avoid incorrect displays
  31.  *
  32.  * Revision 1.15  1993/09/27  00:45:20  ahd
  33.  * Cosmetic clean up
  34.  *
  35.  * Revision 1.14  1993/09/25  03:07:56  ahd
  36.  * Add dummy priority function
  37.  *
  38.  * Revision 1.13  1993/07/11  14:38:32  ahd
  39.  * Correct routine names in displayed messages
  40.  *
  41.  * Revision 1.12  1993/05/30  15:25:50  ahd
  42.  * Multiple driver support
  43.  *
  44.  * Revision 1.11  1993/05/30  00:08:03  ahd
  45.  * Multiple communications drivers support
  46.  * Don't lock port if not in multi-task mode
  47.  * Break trace functions out of ulib.c into commlib.c
  48.  *
  49.  * Revision 1.10  1993/05/09  03:41:47  ahd
  50.  * Make swrite accept constant input strings
  51.  *
  52.  * Revision 1.9  1993/04/11  00:33:54  ahd
  53.  * Global edits for year, TEXT, etc.
  54.  *
  55.  * Revision 1.8  1993/04/05  04:35:40  ahd
  56.  * Set/clear abort processing flags in modem.c
  57.  *
  58.  * Revision 1.7  1993/01/23  19:08:09  ahd
  59.  * Don't attempt to detect lost carrier in sread()
  60.  *
  61.  * Revision 1.6  1992/12/30  05:27:11  plummer
  62.  * MS C compile fixes
  63.  * Add CD() to sread
  64.  *
  65.  * Revision 1.5  1992/12/12  16:12:13  ahd
  66.  * Include header file for definition for memory avail routines
  67.  *
  68.  * Revision 1.4  1992/12/07  02:43:20  ahd
  69.  * Improve error message when low memory prevents COMM port install
  70.  *
  71.  * Revision 1.3  1992/11/29  22:09:10  ahd
  72.  * Use sopen() rather than FOPEN() to avoid retries on comm port
  73.  *
  74.  * Revision 1.2  1992/11/21  06:17:42  ahd
  75.  * Delete old (pre-COMMFIFO) autobaud function
  76.  *
  77.  */
  78.  
  79. /*--------------------------------------------------------------------*/
  80. /*                        System include files                        */
  81. /*--------------------------------------------------------------------*/
  82.  
  83. #include <fcntl.h>
  84. #include <io.h>
  85. #include <stdio.h>
  86. #include <stdlib.h>
  87. #include <string.h>
  88. #include <time.h>
  89. #include <share.h>
  90.  
  91. #ifdef __TURBOC__
  92. #include <alloc.h>
  93. #endif
  94.  
  95. /*--------------------------------------------------------------------*/
  96. /*                    UUPC/extended include files                     */
  97. /*--------------------------------------------------------------------*/
  98.  
  99. #include "lib.h"
  100. #include "hlib.h"
  101. #include "ulib.h"
  102. #include "comm.h"
  103. #include "ssleep.h"
  104. #include "catcher.h"
  105. #include "commlib.h"
  106.  
  107. /*--------------------------------------------------------------------*/
  108. /*                        Internal prototypes                         */
  109. /*--------------------------------------------------------------------*/
  110.  
  111. static void ShowModem( void );
  112.  
  113. /*--------------------------------------------------------------------*/
  114. /*                          Global variables                          */
  115. /*--------------------------------------------------------------------*/
  116.  
  117. static unsigned short current_bps;
  118. static char current_direct;
  119. static boolean carrierdetect;
  120.  
  121. currentfile();
  122.  
  123. /* IBM-PC I/O routines */
  124.  
  125. /* "DCP" a uucp clone. Copyright Richard H. Lamb 1985,1986,1987 */
  126.  
  127. /*************** BASIC I/O ***************************/
  128. /* Saltzers serial package (aka Info-IBMPC COM_PKG2):
  129.  * Some notes:  When packets are flying in both directions, there seems to
  130.  * be some interrupt handling problems as far as receiving.  Checksum errors
  131.  * may therefore occur often even though we recover from them.  This is
  132.  * especially true with sliding windows.  Errors are very few in the VMS
  133.  * version.  RH Lamb
  134.  */
  135.  
  136. #define  STOPBIT  1
  137.  
  138. static int com_handle;
  139. static boolean hangup_needed = TRUE;
  140.  
  141. /*--------------------------------------------------------------------*/
  142. /*    n o p e n l i n e                                               */
  143. /*                                                                    */
  144. /*    Open the serial port for I/O                                    */
  145. /*--------------------------------------------------------------------*/
  146.  
  147. int nopenline(char *name, BPS bps, const boolean direct)
  148. {
  149.    int   value;
  150.  
  151.    if (portActive)              /* Was the port already active?     */
  152.       closeline();              /* Yes --> Shutdown it before open  */
  153.  
  154.    printmsg(15, "openline: %s, %lu", name, bps);
  155.  
  156.    current_direct = (char) (direct ? 'D' : 'M') ;
  157.  
  158.    if (sscanf(name, "COM%d", &value) != 1)
  159.    {
  160.       printmsg(0,"Communications port must be format COMx, was %s",
  161.                 name);
  162.       panic();
  163.    }
  164.  
  165.    if ( bflag[F_MULTITASK] )
  166.    {
  167.       com_handle = sopen( name, O_BINARY | O_RDWR, SH_DENYRW );
  168.                                  /* Used soly for lock abilities  */
  169.       if ( com_handle == -1 )
  170.       {
  171.          printerr( name );
  172.          return 1;
  173.       }
  174.    }
  175.  
  176.    select_port(value);
  177.    save_com();
  178.  
  179.    if (!install_com())
  180.    {
  181.       printmsg(0,"Communications handler install failed; "
  182.                   "probable cause ... memory shortage.");
  183.  
  184. #ifdef __TURBOC__
  185.       printmsg(0,"FAR DOS Memory free = %ld bytes",
  186.                   farcoreleft() );
  187. #endif
  188.  
  189.       return 1;
  190.    }
  191.  
  192.    current_bps = bps;
  193.    open_com(current_bps, current_direct, 'N', STOPBIT, 'D');
  194.    dtr_on();
  195.    ssleep(2);                 /* Wait two seconds as required by V.24   */
  196.    carrierdetect = FALSE;     /* No modem connected yet                 */
  197.  
  198.    traceStart( name );
  199.  
  200.    portActive = TRUE;     /* record status for error handler */
  201.  
  202.    return 0;
  203.  
  204. } /* nopenline */
  205.  
  206. /*--------------------------------------------------------------------*/
  207. /*    n s r e a d                                                     */
  208. /*                                                                    */
  209. /*    Read from the serial port                                       */
  210. /*                                                                    */
  211. /*    Non-blocking read essential to "g" protocol.  See               */
  212. /*    "dcpgpkt.c" for description.  This all changes in a             */
  213. /*    multi-tasking system.  Requests for I/O should get queued       */
  214. /*    and an event flag given.  Then the requesting process (e.g.     */
  215. /*    gmachine()) waits for the event flag to fire processing         */
  216. /*    either a read or a write.  Could be implemented on VAX/VMS      */
  217. /*    or DG but not MS-DOS.                                           */
  218. /*--------------------------------------------------------------------*/
  219.  
  220. unsigned int nsread(char *input,
  221.                     unsigned int wanted,
  222.                     unsigned int timeout)
  223. {
  224.    time_t start;
  225.  
  226.    hangup_needed = TRUE;
  227.  
  228.    start = time(nil(time_t)); /* Remember when we started processing */
  229.  
  230. /*--------------------------------------------------------------------*/
  231. /*                  Report the current modem status                   */
  232. /*--------------------------------------------------------------------*/
  233.  
  234.    ShowModem();
  235.  
  236. /*--------------------------------------------------------------------*/
  237. /*             Now actually try to read a buffer of data              */
  238. /*--------------------------------------------------------------------*/
  239.  
  240.    for ( ; ; )
  241.    {
  242.       unsigned int pending;
  243.       pending = r_count_pending();
  244.  
  245.       if ( terminate_processing )
  246.       {
  247.          static boolean recurse = FALSE;
  248.          if ( ! recurse )
  249.          {
  250.             printmsg(2,"nsread: User aborted processing");
  251.             recurse = TRUE;
  252.          }
  253.          return 0;
  254.       }
  255.  
  256.       printmsg(20, "nsread: pending=%d, wanted=%d", pending, wanted);
  257.  
  258.       if (pending >= wanted) {   /* got enough in the buffer? */
  259.          unsigned int i;
  260.  
  261.          char *buffer = input;
  262.  
  263.          for (i = 0; i < wanted; i++)
  264.          {
  265.             int Received;
  266.  
  267.             Received = receive_com();       /* Get character from com port */
  268.             if ( Received < 0 )
  269.             {
  270.                 printmsg( 10, "nsread: recv error" );
  271.                 return 0;                   /* Indicate carrier loss */
  272.             }
  273.             *buffer++ = (char) Received;
  274.             if ( debuglevel >= 19 )
  275.                printmsg( 19, "nsread: char = %c", Received );
  276.          }
  277.  
  278.          traceData( input, wanted, FALSE );
  279.  
  280.          return pending;
  281.  
  282.       } else {
  283.          time_t   now     = time(nil(time_t));
  284.          time_t   elapsed = now - start;
  285.  
  286.          if (elapsed >= ((time_t) timeout))
  287.             return pending;
  288.  
  289.          ddelay(0);                    /* Surrender our time slice   */
  290.  
  291.       } /* else */
  292.    } /* for ( ; ; ) */
  293.  
  294. } /* nsread */
  295.  
  296. /*--------------------------------------------------------------------*/
  297. /*    n s w r i t e                                                   */
  298. /*                                                                    */
  299. /*    Write to the serial port                                        */
  300. /*--------------------------------------------------------------------*/
  301.  
  302. int nswrite(const char *input, unsigned int len)
  303. {
  304.    unsigned int i;
  305.    char *data = (char *) input;
  306.  
  307.    hangup_needed = TRUE;
  308.  
  309. /*--------------------------------------------------------------------*/
  310. /*                      Report our modem status                       */
  311. /*--------------------------------------------------------------------*/
  312.  
  313.   ShowModem();
  314.  
  315. /*--------------------------------------------------------------------*/
  316. /*    Introduce a little flow control - Actual line pacing is         */
  317. /*    handled at a lower level                                        */
  318. /*--------------------------------------------------------------------*/
  319.  
  320.    if ( s_count_free() < (int) len )
  321.    {
  322.       int spin = 0;
  323.       static int const max_spin = 20;
  324.  
  325.       int queue_size = s_count_size();
  326.       int queue_free = s_count_free();
  327.  
  328.       if ( (int) len > queue_size )
  329.       {
  330.          printmsg(0,"nswrite: Transmit buffer overflow; buffer size %d, "
  331.                     "needed %d",
  332.                queue_size,len);
  333.          panic();
  334.       }
  335.  
  336.       while( ((int)len > queue_free) && (spin < max_spin) )
  337.       {
  338.          int wait;
  339.          int needed;
  340.          int new_free;
  341.  
  342.          needed = max(queue_size/2, ((int)len)-queue_free);
  343.                               /* Minimize thrashing by requiring
  344.                                  big chunks */
  345.  
  346.          wait = (int) ((long) needed * 10000L / (long) current_bps);
  347.                               /* Compute time in milliseconds
  348.                                  assuming 10 bits per byte           */
  349.  
  350.          printmsg(4,"nswrite: Waiting %d ms for %d bytes in queue"
  351.                      ", pass %d",
  352.                      wait, needed, spin);
  353.  
  354.          ddelay( wait );      /* Actually perform the wait           */
  355.  
  356.          new_free = s_count_free();
  357.  
  358.          if ( new_free == queue_free )
  359.             spin++;           /* No progress, consider timing out    */
  360.          else
  361.             queue_free = new_free;
  362.                               /* Update our progress                 */
  363.  
  364.       } /* while( (len > queue_free) && spin ) */
  365.  
  366.       if ( queue_free < (int) len )
  367.       {
  368.          printmsg(0,"nswrite: Buffer overflow, needed %d bytes"
  369.                      " from queue of %d",
  370.                      len, queue_size);
  371.       } /* if ( queue_free < len ) */
  372.       return 0;
  373.  
  374.    } /* if ( s_count_free() < len ) */
  375.  
  376. /*--------------------------------------------------------------------*/
  377. /*            Send the data to the communications package             */
  378. /*--------------------------------------------------------------------*/
  379.  
  380.    for (i = 0; i < len; i++)
  381.       send_com(*data++);
  382.  
  383.    traceData( input, len, TRUE );
  384.  
  385. /*--------------------------------------------------------------------*/
  386. /*              Return byte count transmitted to caller               */
  387. /*--------------------------------------------------------------------*/
  388.  
  389.    return len;
  390.  
  391. } /* nswrite */
  392.  
  393. /*--------------------------------------------------------------------*/
  394. /*    n s s e n d b r k                                               */
  395. /*                                                                    */
  396. /*    Send a break signal out the serial port                         */
  397. /*--------------------------------------------------------------------*/
  398.  
  399. void nssendbrk(unsigned int duration)
  400. {
  401.  
  402.    printmsg(12, "nssendbrk: %d", duration);
  403.  
  404.    break_com();
  405.  
  406. } /* nssendbrk */
  407.  
  408. /*--------------------------------------------------------------------*/
  409. /*    n c l o s e l i n e                                             */
  410. /*                                                                    */
  411. /*    Close the serial port down                                      */
  412. /*--------------------------------------------------------------------*/
  413.  
  414. void ncloseline(void)
  415. {
  416.    int far *stats;
  417.  
  418.    if (!portActive)
  419.       panic();
  420.  
  421.    portActive = FALSE;        /* Flag port closed for error handler  */
  422.  
  423.    dtr_off();
  424.    ddelay(500);               /* Required for V.24             */
  425.    close_com();
  426.    restore_com();
  427.  
  428.    if ( bflag[F_MULTITASK] )
  429.       close( com_handle );
  430.  
  431.    traceStop();
  432.  
  433.    stats = com_errors();
  434.    printmsg(3, "Buffer overflows: %-4d", stats[COM_EOVFLOW]);
  435.    printmsg(3, "Receive overruns: %-4d", stats[COM_EOVRUN]);
  436.    printmsg(3, "Break characters: %-4d", stats[COM_EBREAK]);
  437.    printmsg(3, "Framing errors:   %-4d", stats[COM_EFRAME]);
  438.    printmsg(3, "Parity errors:    %-4d", stats[COM_EPARITY]);
  439.    printmsg(3, "Transmit errors:  %-4d", stats[COM_EXMIT]);
  440.    printmsg(3, "DSR errors:       %-4d", stats[COM_EDSR]);
  441.    printmsg(3, "CTS errors:       %-4d", stats[COM_ECTS]);
  442.  
  443. } /*closeline*/
  444.  
  445. /*--------------------------------------------------------------------*/
  446. /*    n h a n g u p                                                   */
  447. /*                                                                    */
  448. /*    Hangup the telephone by dropping DTR.  Works with HAYES and     */
  449. /*    many compatibles.                                               */
  450. /*    14 May 89 Drew Derbyshire                                       */
  451. /*--------------------------------------------------------------------*/
  452.  
  453. void nhangup( void )
  454. {
  455.       if (!hangup_needed)
  456.          return;
  457.  
  458.       hangup_needed = FALSE;
  459.       dtr_off();              /* Hang the phone up                         */
  460.       ddelay(500);            /* Really only need 250 milliseconds         */
  461.       dtr_on();               /* Bring the modem back on-line              */
  462.       ddelay(2000);           /* Now wait for the poor thing to recover    */
  463.                               /* two seconds is required by V.24           */
  464.       printmsg(3,"nhangup: complete.");
  465.       carrierdetect = FALSE;  /* No modem connected yet                    */
  466.  
  467. } /* nhangup */
  468.  
  469. /*--------------------------------------------------------------------*/
  470. /*    n S I O S p e e d                                               */
  471. /*                                                                    */
  472. /*    Re-specify the speed of an opened serial port                   */
  473. /*                                                                    */
  474. /*    Dropped the DTR off/on calls because this makes a Hayes drop    */
  475. /*    the line if configured properly, and we don't want the modem    */
  476. /*    to drop the phone on the floor if we are performing             */
  477. /*    autobaud.                                                       */
  478. /*                                                                    */
  479. /*    (Configured properly = standard method of making a Hayes        */
  480. /*    hang up the telephone, especially when you can't get it into    */
  481. /*    command state because it is at the wrong speed or whatever.)    */
  482. /*--------------------------------------------------------------------*/
  483.  
  484. void nSIOSpeed(BPS bps)
  485. {
  486.  
  487.    printmsg(4,"SIOSspeed: Changing port speed from %lu BPS to %lu BPS",
  488.                (unsigned long) current_bps, (unsigned long) bps);
  489.    current_bps = bps;
  490.    ioctl_com(0, current_bps);
  491.  
  492.    ShowModem();
  493.  
  494. } /* nSIOSpeed */
  495.  
  496. /*--------------------------------------------------------------------*/
  497. /*    n f l o w c o n t r o l                                         */
  498. /*                                                                    */
  499. /*    Enable/Disable in band (XON/XOFF) flow control                  */
  500. /*--------------------------------------------------------------------*/
  501.  
  502. void nflowcontrol( boolean flow )
  503. {
  504.    printmsg(4,"flowcontrol: Closing port");
  505.    close_com();
  506.    ShowModem();
  507.    printmsg(4,"flowcontrol: Opening port to %sable flow control",
  508.                flow ? "en" : "dis");
  509.    open_com(current_bps, current_direct, 'N', STOPBIT, flow ? 'E' : 'D');
  510.    ShowModem();
  511.  
  512. } /* nflowcontrol */
  513.  
  514. /*--------------------------------------------------------------------*/
  515. /*    n G e t S p e e d                                               */
  516. /*                                                                    */
  517. /*    Report current speed of communications connection               */
  518. /*--------------------------------------------------------------------*/
  519.  
  520. BPS nGetSpeed( void )
  521. {
  522.  
  523.    return current_bps;
  524.  
  525. } /* nGetSpeed */
  526.  
  527. /*--------------------------------------------------------------------*/
  528. /*    n C D                                                           */
  529. /*                                                                    */
  530. /*    Report if we have carrier detect and lost it                    */
  531. /*--------------------------------------------------------------------*/
  532.  
  533. boolean nCD( void )
  534. {
  535.    boolean online = carrierdetect;
  536.  
  537.    ShowModem();
  538.    carrierdetect = is_cd_high();
  539.  
  540. /*--------------------------------------------------------------------*/
  541. /*    If we previously had carrier detect but have lost it, we        */
  542. /*    report it was lost.  If we do not yet have carrier detect,      */
  543. /*    we return success because we may not have connected yet.        */
  544. /*--------------------------------------------------------------------*/
  545.  
  546.    if (online)
  547.       return carrierdetect && is_dsr_high();
  548.    else
  549.       return is_dsr_high();
  550.  
  551. } /* nCD */
  552.  
  553. /*--------------------------------------------------------------------*/
  554. /*    S h o w M o d e m                                               */
  555. /*                                                                    */
  556. /*    Report current modem status                                     */
  557. /*--------------------------------------------------------------------*/
  558.  
  559. #define mannounce(flag, bits, text ) ((flag & bits) ? text : "" )
  560.  
  561. static void ShowModem( void )
  562. {
  563.    static int old_status = 0xDEAD;
  564.    int status;
  565.  
  566.    if ( debuglevel < 4 )
  567.       return;
  568.  
  569.    status = modem_status();
  570.    if (status == old_status)
  571.       return;
  572.  
  573.    printmsg(0, "ShowModem: %#02x%s%s%s%s%s%s%s%s",
  574.       status,
  575.       mannounce(MDM_CD,   status, "\tCarrier Detect"),
  576.       mannounce(MDM_RI,   status, "\tRing Indicator"),
  577.       mannounce(MDM_DSR,  status, "\tData Set Ready"),
  578.       mannounce(MDM_CTS,  status, "\tClear to Send"),
  579.       mannounce(MDM_CDC,  status, "\tCD changed"),
  580.       mannounce(MDM_TRI,  status, "\tRI went OFF"),
  581.       mannounce(MDM_DSRC, status, "\tDSR changed"),
  582.       mannounce(MDM_CTSC, status, "\tCTS changed"));
  583.    old_status = status;
  584.  
  585. } /* ShowModem */
  586.  
  587. #ifdef __TURBOC__
  588. #pragma argsused
  589. #endif
  590.  
  591. /*--------------------------------------------------------------------*/
  592. /*       s e t P r t y                                                */
  593. /*                                                                    */
  594. /*       No operation under DOS                                       */
  595. /*--------------------------------------------------------------------*/
  596.  
  597. void setPrty( const KEWSHORT priorityIn, const KEWSHORT prioritydeltaIn )
  598. {
  599. }
  600.  
  601. /*--------------------------------------------------------------------*/
  602. /*       r e s e t P r t y                                            */
  603. /*                                                                    */
  604. /*       No operation under DOS                                       */
  605. /*--------------------------------------------------------------------*/
  606.  
  607. void resetPrty( void ) { }
  608.