home *** CD-ROM | disk | FTP | other *** search
/ Shareware Overload / ShartewareOverload.cdr / comm / jmodem.zip / JMODEM_A.C < prev    next >
Text File  |  1990-06-20  |  36KB  |  557 lines

  1. /****************************************************************************/
  2. /*    FILE JMODEM_A.C                                                       */
  3. /*                                                                          */
  4. /*    The JMODEM protocol            MicroSoft (r)  'C' V5.1                */
  5. /*    Created 03-FEB-1990            Richard B. Johnson                     */
  6. /*                                   405 Broughton Drive                    */
  7. /*                                   Beverly, Massachusetts 01915           */
  8. /*                                   BBS (508) 922-3166                     */
  9. /*                                                                          */
  10. /*    An external protocol for high-speed data transmission.                */
  11. /*                                                                          */
  12. /*    This is the MAIN module                                               */
  13. /*    The required modules are:                                             */
  14. /*    JMODEM.H    (function prototypes and structures)                      */
  15. /*    UART.H      (8250 UART parameters)                                    */
  16. /*    SCREEN.H    (function protypes and structures for the screen)         */
  17. /*    JMODEM_A.C  (this module)                                             */
  18. /*    JMODEM_B.C  (memory allocation and input parsing)                     */
  19. /*    JMODEM_C.C  (all file I/O)                                            */
  20. /*    JMODEM_D.C  (encode/decode and CRC routines)                          */
  21. /*    JMODEM_E.C  (communications I/O routines)                             */
  22. /*    JMODEM_F.C  (the screen I/O routines)                                 */
  23. /*    JMODEM.     (The MAKE file )                                          */
  24. /*                                                                          */
  25. /*    This program requires about 67k of free RAM to execute properly.      */
  26. /*    If you have 66k or less, it will execute, but the screens will        */
  27. /*    not be written or replaced properly. If you have only 64k, the        */
  28. /*    program will exit with an error message.                              */
  29. /*                                                                          */
  30. /*    Revision History:                                                     */
  31. /*    V3.00   Beta test                  11-FEB-1990   Richard B. Johnson   */
  32. /*    V3.01   First release              18-FEB-1990   Richard B. Johnson   */
  33. /*    V3.02   Revised                    19-FEB-1990   Richard B. Johnson   */
  34. /*                                                                          */
  35. /*      (1)   A bug in MicroSoft _calloc()  allocates overlapping           */
  36. /*            buffers so data files were getting corrupted. I had           */
  37. /*            used both _calloc() and _malloc() at the same time and        */
  38. /*            they didn't like it. I changed the memory allocation          */
  39. /*            to _malloc() only and it seems to work okay.                  */
  40. /*                                                                          */
  41. /*      (2)   While debugging, I found some structures I didn't need and    */
  42. /*            removed them. Changed some code to accommodate.               */
  43. /*                                                                          */
  44. /*      (3)   Added a file-size during downloads.                           */
  45. /*                                                                          */
  46. /*      (4)   Changed code in the data encoding (compression) routine       */
  47. /*            in an attempt to speed it up.                                 */
  48. /*                                                                          */
  49. /*    V3.03   Revised                   20-FEB-1990  Richard B. Johnson     */
  50. /*                                                                          */
  51. /*      (5)   Fixed bug in compression routine where the loop wasn't        */
  52. /*            terminating properly, adding random characters. Bug was       */
  53. /*            created during V3.02 change.                                  */
  54. /*                                                                          */
  55. /*    V3.04   Revised                   27-FEB-1990  Richard B. Johnson     */
  56. /*                                                                          */
  57. /*      (1)   Modified the block-size routine and the receive-block         */
  58. /*            routine in an attempt to improve the noise immunity.          */
  59. /*            Does not abort even if you whistle into the telephone         */
  60. /*            during uploads and downloads. Waits 5 seconds to clear        */
  61. /*            the interrupt buffer when a bad block-size is received.       */
  62. /*                                                                          */
  63. /*      (2)   Added a 1/2 second wait for modem status when opening         */
  64. /*            channel. This might accommodate slow modems response to       */
  65. /*            RTS.                                                          */
  66. /*                                                                          */
  67. /*    V3.05   Revised                   22-MAR-1990  Richard B. Johnson     */
  68. /*                                                                          */
  69. /*      (1)   Removed _sprintf() runtime library calls to shorten           */
  70. /*            the code. Saved about 4k.                                     */
  71. /*                                                                          */
  72. /*      (2)   Removed extra spaces in the signon-logo to shorten            */
  73. /*            the program size.                                             */
  74. /*                                                                          */
  75. /*      (3)   Changed the method of creating a fixed-length string          */
  76. /*            for both the block size and cps numbers which saved about     */
  77. /*            800 bytes of program size.                                    */
  78. /*                                                                          */
  79. /*      (4)   Changed numerous array indexes in JMODEM_F.C to pointers      */
  80. /*            to reduce code size. Saved a few hundred bytes and should     */
  81. /*            improve speed of screen output.                               */
  82. /*                                                                          */
  83. /*      (5)   Created a local _puts() routine which saved over 6k from the  */
  84. /*            MicroSoft C runtime library version. (JMODEM_F.C)             */
  85. /*                                                                          */
  86. /*    V3.06   Revised                   07-APR-1990  Richard B. Johnson     */
  87. /*                                                                          */
  88. /*      (1)   Put the filename text into the syst structure as a pointer    */
  89. /*            to char. This allowed me to save 56 bytes of code and now     */
  90. /*            only two parameters are passed to the _screen() function.     */
  91. /*                                                                          */
  92. /*      (2)   Modified the syst structure and supporting code.              */
  93. /*                                                                          */
  94. /*      (3)   Moved all external data and functions to the JMODEM.H file.   */
  95. /*                                                                          */
  96. /*      (4)   Moved _disp() "usage" module to JMODEM_F.C                    */
  97. /*                                                                          */
  98. /*      (5)   Changed arrays in JMODEM_B.C to pointers to reduce code-      */
  99. /*            size. Eliminated _strcpy() from the command-line parsing      */
  100. /*            routines. Brought the code-size to less than 12,000 bytes.    */
  101. /*                                                                          */
  102. /*      (6)   Reduced the code-size in the _encode(), _decode(), and        */
  103. /*            _crc() routines in JMODEM_D.C. Removed shifts to improve      */
  104. /*            speed and replaced the shifts with pointers for altering      */
  105. /*            portions of the strings.                                      */
  106. /*                                                                          */
  107. /*      (7)   Made a _cancel() routine in JMODEM_A.C to send ^Xes upon      */
  108. /*            abort.                                                        */
  109. /*                                                                          */
  110. /*      (8)   Removed the bit being set "OUT 1" via the modem-control       */
  111. /*            register in the "open" routine in JMODEM_E.C. This was        */
  112. /*            causing some internal modems to lock up as they use this      */
  113. /*            bit for something. "OUT 2" is used to enable IRQ on most      */
  114. /*            clone RS-232 boards and modems. The Heathkit HZ-100 boards    */
  115. /*            will probably not work anymore because they use "OUT 1".      */
  116. /*                                                                          */
  117. /*                                                                          */
  118. /*    V3.07   Revised                   03-MAY-1990  Richard B. Johnson     */
  119. /*                                                                          */
  120. /*      (1)   Rewrote code to remove the requirement for a file buffer.     */
  121. /*            This means that this buffer does not need to be allocated,    */
  122. /*            saving about 8k of RAM at run-time.  ( JMODEM_A.C )           */
  123. /*                                                                          */
  124. /*            Program now only requires 52k of free RAM to execute okay.    */
  125. /*                                                                          */
  126. /*      (2)   Changed the header file, JMODEM.H, and function calling       */
  127. /*            procedures to file_io() and screen() to allow variable-       */
  128. /*            length parameter-lists. This eliminates the requirement       */
  129. /*            to pass a NULL as a place-holder on procedures that don't     */
  130. /*            always require all possible parameters to be passed. This     */
  131. /*            saved about 50 bytes of code.                                 */
  132. /*                                                                          */
  133. /*      (3)   Changed the "Usage" prompt and code to reduce program size.   */
  134. /*            Saved about 60 bytes.                                         */
  135. /*                                                                          */
  136. /*      (4)   Changed keyboard break interrupt in JMODEM_E.C so it sets     */
  137. /*            the global timer to zero as well as setting the abort flag.   */
  138. /*                                                                          */
  139. /****************************************************************************/
  140. #include <stdlib.h>                     /* Used for _free()                 */
  141. #include <stdio.h>                      /* Used for NULL value              */
  142. #include <string.h>                     /* Used for _memcpy()               */
  143. #include <time.h>                       /* Used for absolute time           */
  144. #include "jmodem.h"                     /* JMODEM primatives                */
  145. /****************************************************************************/
  146. /*                   Global pointers and allocation                         */
  147. /****************************************************************************/
  148. unsigned short user_abort = 0;          /* Global user abort flag           */
  149. unsigned char *int_buffer;              /* Pointer to interrupt buffer      */
  150. SYS syst;                               /* Structure for JMODEM status      */
  151. /****************************************************************************/
  152. /*                               C O D E                                    */
  153. /****************************************************************************/
  154. short main (short argc,  char *argv[])
  155. {
  156.     unsigned char *in_buffer;             /* Pointer to input buffer        */
  157.     unsigned char *out_buffer;            /* Pointer to output buffer       */
  158.     unsigned char *comp_buffer;           /* Pointer to compression buffer  */
  159.     register unsigned char *io_ptr;       /* Select buffers to use for I/O  */
  160.     register JBUF *buff;                  /* A pointer for the JMODEM block */
  161.     unsigned char *file_name;             /* Filename                       */
  162.     unsigned char function;               /* Receive, Transmit              */
  163.     time_t start;                         /* Start time                     */
  164.     time_t finish;                        /* End time                       */
  165. #ifdef FTIME                              /* Floating point timer           */
  166.     double dat_tmp;                       /* Temporary variable for time    */
  167. #endif
  168.     unsigned short status=0;              /* TX and RX status               */
  169.     unsigned short tries;                 /* Attempts to send a file        */
  170.     unsigned short cmp_size;              /* Size after compression         */
  171.     unsigned short data_written;          /* Data written to the file       */
  172.     unsigned short data_read;             /* Data read from the file        */
  173.     short handle;                         /* For file I/O                   */
  174.  
  175.     if (!(file_name = get_inp (argc, argv))) /* Get file name               */
  176.     {
  177.         disp();                              /* Display usage message       */
  178.         return JM_FNF;
  179.     }
  180.     if (!(function = get_fun (argc, argv)))  /* Get function 'R' or 'S'     */
  181.     {
  182.         disp();                              /* Display usage message       */
  183.         return JM_CMD;
  184.     }
  185.     if (!(port = get_port (argc, argv)))     /* Get port '1 to 4 '          */
  186.     {
  187.         disp();                              /* Display usage message       */
  188.         return JM_CMD;
  189.     }
  190. /****************************************************************************/
  191. /*                          Allocate buffers                                */
  192. /****************************************************************************/
  193.     in_buffer = allocate_memory(DAT_LEN);  /* Get some memory for input     */
  194.     if (!in_buffer)
  195.         return JM_MEM;                     /* No memory available           */
  196.     out_buffer = allocate_memory(DAT_LEN); /* Get some memory for output    */
  197.     if (!out_buffer)
  198.         return JM_MEM;                     /* No memory available           */
  199.     comp_buffer=allocate_memory(DAT_LEN);  /* Get memory for compression    */
  200.     if (!comp_buffer)
  201.         return JM_MEM;                     /* No memory available           */
  202.     int_buffer =allocate_memory(DAT_LEN);  /* Memory for interrupt buffer   */
  203.     if (!int_buffer)
  204.         return JM_MEM;                     /* No memory available           */
  205. /****************************************************************************/
  206.     screen (SCR_SGN);                      /* Write signon screen           */
  207.     syst.s_len = BLK_SIZ;                  /* Set beginning block size      */
  208.     syst.s_byt = 0;                        /* Set bytes handled             */
  209.     syst.s_blk = 0;                        /* Starting block                */
  210.     syst.s_sta = okay;                     /* Starting status               */
  211.     switch(function)                       /* Functions are TX and RX       */
  212.     {
  213. /****************************************************************************/
  214. /*                          Receive JMODEM file                             */
  215. /****************************************************************************/
  216.     case 'R':
  217.         {
  218.             if (!file_io(CREATE, &handle, file_name) )
  219.             {
  220.                 buff = (JBUF *) in_buffer;            /* Assign type JBUF   */
  221.                 open_chan(port);                      /* Open com channel   */
  222.                 screen (SCR_STA);                     /* Write status block */
  223.                 status = rx_sync();                   /* Synchronize        */
  224.                 if (!status)
  225.                     screen (SCR_SYR);
  226.                 data_written = 0xFFFF;
  227.                 tries = 10;                          /* Attempts to receive */
  228.                 while (    (data_written)            /* Write file okay     */
  229.                         && (!user_abort )            /* No break key        */
  230.                         && (!status     )            /* Recev block okay    */
  231.                         && (tries--)    )            /* 10 retries          */
  232.                 {
  233.                     time(&start);                    /* Get starting time   */
  234.                     screen (SCR_SYS,&syst);          /* Show status block   */
  235.                     status = recv_blk (              /* Receive data-block  */
  236.                              &syst.s_len,            /* Block length        */
  237.                              in_buffer);             /* Input buffer        */
  238.                     if (status)                      /* If bad              */
  239.                         break;                       /* Abort the WHILE     */
  240.                     if( (!(calc_crc( GET_CRC,        /* Calculate CRC       */
  241.                           syst.s_len,                /* Amount to check     */
  242.                           in_buffer) ))              /* Receiver buffer     */
  243.                       && ( buff->blk_num ==          /* Check block also    */
  244.                          (unsigned char)
  245.                          (syst.s_blk +1)))           /* Block number        */
  246.                     {
  247.                         syst.s_sta = okay;           /* Text pointer        */
  248.                         tries=10;                    /* Reset count         */
  249.                         syst.s_len -= OVRHD;         /* Subtract overhead   */
  250.                         *out_buffer = ACK;           /* Good                */
  251.                         write_chan(1,out_buffer);    /* Send the ACK        */
  252.                         io_ptr = &buff->blk_dat;     /* Assume normal data  */
  253.  
  254.                         if ( (buff->blk_typ & COMP) == COMP)
  255.                         {                            /* If data compressed  */
  256.                              syst.s_len = decode (   /* Decode the data     */
  257.                                       syst.s_len,    /* Data-block length   */
  258.                                      &buff->blk_dat, /* Where to start      */
  259.                                      comp_buffer);   /* Where to put data   */
  260.                              io_ptr = comp_buffer;   /* Point to data       */
  261.                         }
  262.                         data_written = file_io(WRITE, /* Write to file      */
  263.                                          &handle,     /* File handle        */
  264.                                          io_ptr ,     /* Where data is      */
  265.                                          syst.s_len); /* Amount to write    */
  266.                         syst.s_byt += data_written;   /* Total bytes        */
  267.                         syst.s_blk++;                 /* Block number       */
  268.                         time(&finish);                /* Get end time       */
  269.                         if (finish - start)           /* Check div/0        */
  270.                         {
  271. #ifdef FTIME
  272.                             dat_tmp = (double) data_written;
  273.                             syst.s_cps = (short) (dat_tmp /
  274.                                                difftime(finish,start));
  275. #else
  276.                             syst.s_cps = (short)      /* Calc Block CPS     */
  277.                             (data_written / (finish - start) );
  278. #endif
  279.                         }
  280.                                                        /* Check end-of-file */
  281.                         if ( (buff->blk_typ & EOF_) == EOF_)
  282.                         {
  283.                             file_io(CLOSE,&handle);   /* Close file         */
  284.                             close_chan(port);         /* Close the port     */
  285.                             status = JM_NRM;          /* Set status         */
  286.                             goto cleanup;             /* exit routine       */
  287.                         }
  288.                     }
  289.                     else
  290.                     {
  291.                         *out_buffer = NAK;            /* Bad block          */
  292.                         syst.s_sta = retry;           /* Char pointer       */
  293.                         write_chan(1,out_buffer);     /* Send the NAK       */
  294.                      }
  295.                 }
  296.                 close_chan(port);                     /* Aborted            */
  297.                 file_io( DELETE, &handle, file_name); /* Delete bad file    */
  298.                 status = JM_ABT;
  299.                 break;                                /* Exit if() {}       */
  300.             }
  301.             else                                      /* Can't create file  */
  302.             {
  303.                 status = JM_CRE;
  304.                 break;                                /* Exit while() {}    */
  305.             }
  306.         }
  307. /****************************************************************************/
  308. /*                          Send JMODEM file                                */
  309. /****************************************************************************/
  310.     case 'S':   /* Send JMODEM file */
  311.         {
  312.             if (!file_io(OPEN_READ, &handle, file_name) )
  313.             {
  314.                 buff = (JBUF *)out_buffer;            /* Assign type JBUF   */
  315.                 syst.s_byt = 0;                       /* Restore byte count */
  316.                 open_chan(port);                      /* Open COM port      */
  317.                 screen (SCR_STA);                     /* Write status block */
  318.                 status = tx_sync();                   /* Synchronize        */
  319.                 if (!status)
  320.                     screen (SCR_SYT);
  321.                 while  ( (!user_abort)                /* Ctrl - break       */
  322.                        && (!status) )                 /* sent okay          */
  323.                 {
  324.                     time(&start);                     /* Get starting time  */
  325.                     data_read = file_io( READ,        /* Read a record      */
  326.                                       &handle,        /* File pointer       */
  327.                                       &buff->blk_dat, /* Where to put data  */
  328.                                       syst.s_len );   /* Amount to read     */
  329.                     if (!data_read)                   /* Past end of file   */
  330.                         break;
  331.                     syst.s_byt += (long) data_read;   /* Running count      */
  332.                     screen (SCR_SYS,&syst);           /* Show status block  */
  333.                     buff->blk_num = (unsigned char)
  334.                                      ++syst.s_blk;    /* Block number       */
  335.                     buff->blk_typ = NORM;             /* Assume Normal      */
  336.                     buff->len = (data_read+OVRHD);    /* Length of block    */
  337.                     if (data_read != syst.s_len)      /* Less than request  */
  338.                         buff->blk_typ |= EOF_;        /* Its end of file    */
  339.                     cmp_size = encode (data_read,     /* Encode size        */
  340.                                       &buff->blk_dat, /* Source             */
  341.                                       comp_buffer);   /* Destination        */
  342.                     if ( cmp_size  < data_read  )     /* If compressed      */
  343.                     {
  344.                         buff->len = (cmp_size+OVRHD); /* Length of block    */
  345.                         buff->blk_typ |= COMP;        /* Show compressed    */
  346.                         memcpy (&buff->blk_dat,       /* Start of data      */
  347.                                    comp_buffer,       /* Copy from here     */
  348.                                    cmp_size);         /* This much          */
  349.                     }
  350.                     calc_crc(SET_CRC,                 /* Calculate CRC      */
  351.                             buff->len ,               /* Length of block    */
  352.                             out_buffer);              /* Where data is      */
  353.                     status = send_blk(                /* Send the block     */
  354.                              buff->len,               /* Block length       */
  355.                              &syst,                   /* Read block ptr.    */
  356.                              out_buffer);             /* Buffer pointer     */
  357.                     time(&finish);                    /* Get end time       */
  358.                     if (finish - start)               /* Check div/0        */
  359.                     {
  360. #ifdef FTIME
  361.                         dat_tmp = (double) data_read;
  362.                         syst.s_cps = (short) (dat_tmp /
  363.                                          difftime(finish,start));
  364. #else
  365.                         syst.s_cps = (short)          /* Calc Block CPS     */
  366.                         (data_read / (finish - start) );
  367. #endif
  368.                     }
  369.                     if ( buff->blk_typ == EOF_)       /* Last record        */
  370.                         break;
  371.                 }
  372.                 syst.s_sta = done;                    /* Assume normal      */
  373.                 if (status)
  374.                 {
  375.                     cancel();                         /* Send ^Xes          */
  376.                     syst.s_sta = abrt;                /* Was aborted        */
  377.                 }
  378.                 close_chan(port);                     /* Close the port     */
  379.                 file_io(CLOSE, &handle);              /* Close the file     */
  380.                 screen (SCR_SYS,&syst);               /* Show status block  */
  381.             }
  382.             else                                      /* File not found     */
  383.             {
  384.                 status = JM_FNF;
  385.             }
  386.         break;                                        /*   End of CASE 'S'  */
  387.         }
  388.     }
  389.     cleanup:
  390.     free (in_buffer);                                 /* Free  buffers      */
  391.     free (out_buffer);
  392.     free (comp_buffer);
  393.                               /* Two-second timer to display error messages */
  394.     if (status != JM_NRM)
  395.     {
  396.         time(&finish);                               /* Get system clock    */
  397.         finish += 2;                                 /* Add two seconds     */
  398.         start = 0;
  399.         while ( finish > start )                     /* Wait until the same */
  400.             time(&start);
  401.     }
  402.     screen (SCR_END);                                /* Clear the screen    */
  403.     return status;                                   /* Normal exit         */
  404. }
  405. /****************************************************************************/
  406. /*                          Send the JMODEM block                           */
  407. /****************************************************************************/
  408. unsigned short send_blk (blk_len, sys_ptr, buffer)
  409. unsigned short blk_len;
  410. register SYS *sys_ptr;
  411. register unsigned char *buffer;
  412. {
  413.     unsigned char ack_buf;                /* Buffer for ACK/NAK             */
  414.     unsigned short tries = 10;            /* Attempts to send the block     */
  415.     while ((tries--) && (!user_abort))
  416.     {
  417.         write_chan(blk_len,buffer);       /* Send the JMODEM block          */
  418.         flush();                          /* Clear back channel noise       */
  419.         do
  420.         {
  421.             ack_buf = NULL;               /* Clear the return buffer        */
  422.             read_chan(1,&ack_buf);        /* Receive a response             */
  423.         } while ( (ack_buf != ACK)        /* Stay in loop until we          */
  424.                && (ack_buf != CAN)        /*  ... get something useful      */
  425.                && (ack_buf != NAK)        /* This helps re-sync in noise    */
  426.                && (ack_buf ==NULL)
  427.                && (!user_abort) );
  428.  
  429.         if ( (ack_buf == CAN)
  430.            || user_abort )                /* Check for an abort             */
  431.             break;                        /* User aborted                   */
  432.         if (ack_buf == ACK)               /* If good block                  */
  433.         {
  434.             if (tries == 9)               /* If no retries                  */
  435.             {
  436.                 sys_ptr->s_len += 512;    /* Increase block-size            */
  437.                 if (sys_ptr->s_len > DAT_MAX) /* If too large               */
  438.                     sys_ptr->s_len = DAT_MAX;
  439.             }
  440.             else
  441.             {
  442.                 tries = 9 - tries;        /* Use for divisor                */
  443.                 sys_ptr->s_len =          /* Update block length            */
  444.                 sys_ptr->s_len / tries;   /* Div block size                 */
  445.             if (sys_ptr->s_len < 0x40)    /* If less than minimum           */
  446.                 sys_ptr->s_len = 0x40;    /* Set to minimum                 */
  447.             }
  448.         sys_ptr->s_sta = okay;            /* Show status is okay            */
  449.         return JM_NRM;                    /* Show good                      */
  450.         }
  451.     sys_ptr->s_sta = retry;               /* Show a retry                   */
  452.     screen (SCR_SYS, sys_ptr);            /* Write to screen                */
  453.     }
  454.     cancel();                             /* Send cancel (^Xes)             */
  455.     return JM_ABT;                        /* Abort local program            */
  456. }
  457. /****************************************************************************/
  458. /*                        Receive the JMODEM block                          */
  459. /****************************************************************************/
  460. unsigned short recv_blk (blk_len, buffer)
  461. unsigned short *blk_len;                  /* Pointer to the block-length    */
  462. register unsigned char *buffer;           /* Pointer to the buffer          */
  463. {
  464.     register JBUF *buff;                  /* Pointer type JBUF              */
  465.     unsigned char nak_buf;                /* Buffer for ACK/NAK             */
  466.     unsigned short tries = 10;            /* Attempts to receive the block  */
  467.     unsigned short ret_val;               /* Block length returned          */
  468.     buff = (JBUF * )buffer;               /* Assign pointer type JBUF       */
  469.  
  470.     while ((tries--) && (!user_abort))
  471.     {
  472.         ret_val = read_chan(2,buffer);    /* Receive the block size         */
  473.         if (ret_val == 2)                 /* If we received the length      */
  474.         {
  475.             *blk_len = buff->len;         /* So caller knows size           */
  476.             if (*blk_len > DAT_LEN)       /* If way out of line             */
  477.                 break;                    /* NAK it                         */
  478.             ret_val = read_chan(          /* Get more data                  */
  479.                       (*blk_len)-2 ,      /* Size to read                   */
  480.                       &buff->blk_typ);    /* Where to put it                */
  481.             if (ret_val == (*blk_len)-2)  /* If we got what we requested    */
  482.                 return JM_NRM;
  483.         }
  484.     if (buff->blk_typ == CAN)             /* If transmitter sent ^Xes       */
  485.         break;                            /* The other side has aborted     */
  486.     read_chan (DAT_LEN,buffer);           /* Make sure other end stops      */
  487.     nak_buf = NAK;                        /* Get a NAK                      */
  488.     write_chan(1,&nak_buf);               /* Send to remote                 */
  489.     flush();                              /* Flush the buffer               */
  490.     }
  491.     cancel();                             /* Send cancel (^Xes)             */
  492.     return JM_ABT;                        /* Abort local program            */
  493. }
  494. /****************************************************************************/
  495. /*                         Synchronize during receive                       */
  496. /****************************************************************************/
  497. unsigned short rx_sync()
  498. {
  499.     unsigned char ack_nak;                /* Single byte buffer for ACK/NAK */
  500.     flush();                              /* Clear the interrupt buffer     */
  501.     while (!user_abort)
  502.     {
  503.         ack_nak = NULL;                   /* Clear the buffer               */
  504.         read_chan(1,&ack_nak);            /* Receive ACK, NAK, or SYN       */
  505.         if (ack_nak == CAN)               /* If a ^X                        */
  506.             break;
  507.         if ( ack_nak == ACK )             /* If a good response             */
  508.             return JM_NRM;                /* Show handshake                 */
  509.         if ( ack_nak == NAK )             /* If a good response             */
  510.         {
  511.             ack_nak = ACK;
  512.             write_chan(1,&ack_nak);       /* Send a ACK response            */
  513.             return JM_NRM;
  514.          }
  515.          ack_nak = NAK;
  516.          write_chan(1,&ack_nak);          /* Keep sending MAKs              */
  517.     }
  518.     cancel();                             /* Send cancel (^Xes)             */
  519.     return JM_ABT;
  520. }
  521. /****************************************************************************/
  522. /*                           Send ^Xes to cancel                            */
  523. /****************************************************************************/
  524. void cancel()
  525. {
  526.     unsigned char buffer = CAN;
  527.     short xes = 6;
  528.  
  529.     user_abort=0;                         /* Reset flag so write_chan works */
  530.     while(xes--)
  531.         write_chan(1,&buffer);
  532. }
  533. /****************************************************************************/
  534. /*                         Synchronize during transmit                      */
  535. /****************************************************************************/
  536. unsigned short tx_sync()
  537. {
  538.     unsigned short ret_val;
  539.     ret_val = rx_sync();                /* Call same routine for receive    */
  540.     if (ret_val)                        /* If no success                    */
  541.         return ret_val;                 /* Abort routines                   */
  542.     flush();                            /* Else flush the input buffer      */
  543.     timer = 5;                          /* 5 timer-ticks to wait            */
  544.     while (timer);                      /* Wait for timer                   */
  545.     return JM_NRM;                      /* Normal return                    */
  546. }
  547. /****************************************************************************/
  548. /*     Dummy _setenvp procedure to replace the large library module         */
  549. /****************************************************************************/
  550. #ifdef NOENV                            /* If a compiler command        */
  551. void _setenvp(void);                    /* Dummy routine prototype      */
  552. void _setenvp()                         /* Dummy routine                */
  553. {}
  554. #endif
  555. /****************************************************************************/
  556. /************************ E N D  O F   M O D U L E **************************/
  557.