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

  1. /****************************************************************************/
  2. /*   FILE JMODEM_E.C                                                        */
  3. /*   Created 11-JAN-1990                 Richard B. Johnson                 */
  4. /*                                       405 Broughton Drive                */
  5. /*                                       Beverly, Massachusetts 01915       */
  6. /*                                       BBS (508) 922-3166                 */
  7. /*   open_chan();                                                           */
  8. /*   close_chan();                                                          */
  9. /*   read_chan();                                                           */
  10. /*   write_chan();                                                          */
  11. /*                      Communications I/O procedures                       */
  12. /*  These procedures will have to be replaced for JMODEM to execute on      */
  13. /*  a system other than a MS_DOS computer. They are VERY hardware-specific. */
  14. /*  These procedures are grouped so that they can be replaced as a unit.    */
  15. /*  You must replace the following:                                         */
  16. /*  (1) OPEN a communications channel.                                      */
  17. /*  (2) CLOSE the opened channel.                                           */
  18. /*  (3) READ [variable] bytes from the channel.                             */
  19. /*  (4) WRITE [variable] bytes to the channel.                              */
  20. /*                                                                          */
  21. /*  When attempting to READ bytes, some sort of time-out must be provided   */
  22. /*  within the routine to prevent a "wait-forever" syndrome.                */
  23. /*                                                                          */
  24. /*  VAX/VMS, QIO routines are ideal!                                        */
  25. /*                                                                          */
  26. /****************************************************************************/
  27. #include <stdio.h>                          /* For FILE structure           */
  28. #include <conio.h>                          /* For _inp() and _outp()       */
  29. #include <dos.h>                            /* For _enable() and _disable() */
  30. #include "jmodem.h"                         /* JMODEM equates               */
  31. #include "uart.h"                           /* 8250 UART equates            */
  32. #if defined (TURBOC)
  33.     #include <mem.h>
  34.     #define  _enable        enable
  35.     #define  _disable       disable
  36.     #define  _dos_setvect   setvect
  37.     #define  _dos_getvect   getvect
  38. #else
  39.     #include <memory.h>                     /* _memcpy();                   */
  40. #endif
  41. /****************************************************************************/
  42. /*                     Structures and templates                             */
  43. /****************************************************************************/
  44. typedef struct  {
  45.         unsigned short base;                /* Base port address            */
  46.         unsigned short mask;                /* Interrupt controller mask    */
  47.         unsigned short int_num;             /* Interrupt number             */
  48.         } PORTS;
  49.  
  50. const PORTS port_pars[] =
  51.                         {
  52.                         {
  53.                         0x3F8   ,           /* Base port address    COM1    */
  54.                         0xEF    ,           /* IRQ4 11101111B       COM1    */
  55.                         0x0C    ,           /* Interrupt number             */
  56.                         }       ,
  57.                         {
  58.                         0x2F8   ,           /* Base port address    COM2    */
  59.                         0xF7    ,           /* IRQ3 11110111B       COM2    */
  60.                         0x0B    ,           /* Interrupt number             */
  61.                         }       ,
  62.                         {
  63.                         0x3E8   ,           /* Base port address    COM3    */
  64.                         0xEF    ,           /* IRQ4 11101111B       COM3    */
  65.                         0x0C    ,           /* Interrupt number             */
  66.                         }       ,
  67.                         {
  68.                         0x2E8   ,           /* Base port address    COM4    */
  69.                         0xF7    ,           /* IRQ3 11110111B       COM4    */
  70.                         0x0B    ,           /* Interrupt number             */
  71.                         }
  72.                         };
  73. /****************************************************************************/
  74. /*                          Global allocation                               */
  75. /****************************************************************************/
  76. unsigned char *write_ptr;                    /* Interrupt buffer            */
  77. unsigned char *read_ptr;                     /* Interrupt buffer            */
  78. unsigned short port;                         /* Port number                 */
  79. unsigned short old_mask;                     /* Old interrupt control mask  */
  80. unsigned short old_ier;                      /* Old interrupt enable regis  */
  81. unsigned short old_stat;                     /* Modem status for flow-contr */
  82. unsigned short carrier;                      /* Carrier detect              */
  83. unsigned short timer;                        /* Global timer                */
  84. unsigned short hardware_port;                /* Physical port               */
  85. /****************************************************************************/
  86. /*                        Function prototypes                               */
  87. /****************************************************************************/
  88. void interrupt far fatal_abort(void);        /* Abort vector                */
  89. void interrupt far com_int(void);            /* Interrupt service routine   */
  90. void interrupt far tim_int(void);            /* Timer interrupt             */
  91. void (interrupt far *old_tim)();             /* Pointer to old timer intr.  */
  92. void (interrupt far *old_com)();             /* Pointer to old commu intr.  */
  93. void (interrupt far *old_brk)();             /* Pointer to old break key.   */
  94. /****************************************************************************/
  95. /*                 Open the communications channel                          */
  96. /*                                                                          */
  97. /*    Under MS-DOS this involves saving the com-port vector, interrupt      */
  98. /*    controller mask, and the user-tick timer vector.                      */
  99. /*    New vectors and masks and patched for the communications interrupt    */
  100. /*    service routine and the local timer. These vectors will be restored   */
  101. /*    within the CLOSE channel routine.                                     */
  102. /*                                                                          */
  103. /****************************************************************************/
  104. unsigned short open_chan (user_port)
  105. unsigned short user_port;                /* Port offset ( 0 - 3 )           */
  106. {
  107.     short i;
  108.     user_port--;                         /* Convert to an offset            */
  109.     flush();                             /* Initialize the interrupt buffer */
  110.     hardware_port =
  111.        port_pars[user_port].base;        /* Set hardware port               */
  112.     old_ier  = inp(hardware_port +IER);  /* Get interrupt enable regis      */
  113.     old_brk  = _dos_getvect(0x1B);       /* Get old break key vector        */
  114.     old_mask = inp(0x21);                /* Save old interrupt mask         */
  115.     old_tim  = _dos_getvect(0x1C);       /* Get old DOS timer-tick vector   */
  116.     old_com  = _dos_getvect(
  117.        port_pars[user_port].int_num);    /* Get old communications vector   */
  118.     _dos_setvect(0x1B,fatal_abort);      /* Set fatal abort vector (1)      */
  119.     _dos_setvect(0x23,fatal_abort);      /* Set fatal abort vector (2)      */
  120.     _dos_setvect(0x1C,tim_int);          /* Set new timer interrupt         */
  121.     _dos_setvect(
  122.        port_pars[user_port].int_num,     /* Set new communications vector   */
  123.        com_int);
  124.     outp(0x21,old_mask &
  125.        port_pars[user_port].mask);       /* Set interrupt enable mask       */
  126.     outp(hardware_port+MCR, MOD_ENA);    /* Turn on DTR, RTS, IRQ enable    */
  127.     outp(hardware_port+IER, IER_ERBFI);  /* Enable received data available  */
  128.     for (i=0; i<8; i++)                  /* Edge-triggering, read the ports */
  129.         inp(hardware_port + i);          /* Port to clear                   */
  130.     outp(0x20,0x20);                     /* Reset the hardware controller   */
  131.     timer=9;                             /* 1/2 second wait                 */
  132.     while (timer);                       /* Wait 1/2 second                 */
  133.     flush();                             /* Clear interrupt buffer again    */
  134.     i = inp(hardware_port+MSR);          /* Get current modem status        */
  135.     old_stat = i & MSR_CHK;              /* Get current modem control       */
  136.     carrier  = i & MSR_RLSD;             /* Get any modem carrier           */
  137.     return JM_NRM;
  138. }
  139. /****************************************************************************/
  140. /*                 Close the communications channel                         */
  141. /*                                                                          */
  142. /*    Under MS-DOS this involves restoring the interrupt vectors and        */
  143. /*    controller mask that was saved during the OPEN routine.               */
  144. /*                                                                          */
  145. /****************************************************************************/
  146. unsigned short close_chan (user_port)
  147. unsigned short user_port;
  148. {
  149.     outp(hardware_port+IER,old_ier);       /* Set old interrupt enable      */
  150.     outp(0x21,old_mask);                   /* Restore old interrupt mask    */
  151.     _dos_setvect(
  152.        port_pars[user_port].int_num,       /* Set old communications vector */
  153.        old_com);
  154.     _dos_setvect(0x1C,old_tim);            /* Set old timer interrupt       */
  155.     _dos_setvect(0x1B,old_brk);            /* Set old break interrupt       */
  156.     return JM_NRM;
  157. }
  158. /****************************************************************************/
  159. /*              Read from the communications channel                        */
  160. /*                                                                          */
  161. /*    This involves transferring data from the interrupt buffer and         */
  162. /*    maintaining the interrupt buffer pointers. A timeout is established.  */
  163. /*                                                                          */
  164. /****************************************************************************/
  165. unsigned short read_chan (bytes, buffer)
  166. unsigned short bytes;                    /* Bytes requested                 */
  167. register unsigned char *buffer;          /* Pointer to the user's buffer    */
  168. {
  169.     unsigned short count;                /* Byte count                      */
  170.     unsigned short avail;                /* Bytes available                 */
  171.     timer = TIMOUT;                      /* Set initial timeout value       */
  172.     count = bytes;                       /* Set byte-count                  */
  173.  
  174.     while (count && timer)               /* If byte request or no timeout   */
  175.     {
  176.         avail = write_ptr - read_ptr;    /* Bytes available                 */
  177.         if (avail)                       /* If bytes available              */
  178.         {
  179.             if (avail > count)           /* If more bytes than we need      */
  180.                 avail = count;           /* Take only what we need          */
  181.             memcpy (buffer   ,           /* User's buffer                   */
  182.                     read_ptr ,           /* Interrupt buffer pointer        */
  183.                     avail)   ;           /* Copy to user's buffer           */
  184.             count -= avail;              /* Update count                    */
  185.             read_ptr +=avail;            /* Update read pointer             */
  186.             buffer   +=avail;            /* Update write pointer            */
  187.             timer = TIMOUT;              /* Set new timer value             */
  188.         }
  189.         _disable();                      /* Clear interrupts                */
  190.         if (read_ptr == write_ptr)       /* If no bytes available           */
  191.             read_ptr = write_ptr         /* Initialize the interrupt buffer */
  192.                      = int_buffer;
  193.         _enable();                       /* Enable interrupts               */
  194.     }
  195.     return(bytes - count);               /* Actual characters received      */
  196. }
  197. /****************************************************************************/
  198. /*                      Flush the interrupt buffer                          */
  199. /****************************************************************************/
  200. void flush()
  201. {
  202.     _disable();
  203.     read_ptr = write_ptr = int_buffer;   /* Initialize the interrupt buffer */
  204.     _enable();
  205. }
  206. /****************************************************************************/
  207. /*                      Communications transmit routine                     */
  208. /*    Write 'bytes' bytes from buffer to the UART. Don't return until done  */
  209. /*    unless the carrier failed or the hardware broke.                      */
  210. /****************************************************************************/
  211. unsigned short write_chan (bytes, buffer)
  212. unsigned short bytes;                          /* Bytes to send             */
  213. register unsigned char *buffer;                /* Pointer to the buffer     */
  214. {
  215.     unsigned short status;
  216.     unsigned char *sav_sta;
  217.     unsigned char *old_sta;
  218.  
  219.     sav_sta = old_sta = syst.s_sta;           /* Save current status        */
  220.     timer = TIMOUT;
  221.     while ((bytes && timer) && !user_abort )  /* Bytes, no abort, no timout */
  222.     {
  223.         while (
  224.               ( status =                      /* Get modem status           */
  225.               ( inp (hardware_port+MSR)       /* from modem status register */
  226.                 & MSR_CHK )                   /* Check CTS and DSR only     */
  227.               ) != old_stat)                  /* If not the same as before  */
  228.         {                                     /* Flow control loop          */
  229.             if ( (status & MSR_RLSD )         /* ...check modem carrier     */
  230.                  != carrier)                  /* ... if not same as before  */
  231.                 {
  232.                     user_abort = 0x0FFFF;     /* Set the abort flag         */
  233.                     return JM_ABT;            /* ... and get out            */
  234.                 }
  235.             syst.s_sta = flow;                /* Set flow-control status    */
  236.             if ( syst.s_sta != old_sta )      /* If we haven't already      */
  237.             {
  238.                 screen (SCR_FLG,&syst);       /* Show flow-control status   */
  239.             old_sta = syst.s_sta;             /* Flag that we did it        */
  240.             }
  241.         }
  242.     syst.s_sta = sav_sta;                     /* Set previous status        */
  243.     if ( syst.s_sta != old_sta )
  244.         {
  245.             screen (SCR_FLG,&syst);           /* Show previous status       */
  246.         old_sta = syst.s_sta;                 /* Flag that we did it        */
  247.         }
  248.         status = inp(hardware_port+LSR);      /* Get line-status            */
  249.         if (status & LSR_THRE)                /* If TX holding reg empty    */
  250.         {
  251.             outp(hardware_port,*buffer++);    /* Send the byte              */
  252.             bytes--;                          /* Bump the byte-count        */
  253.             timer = TIMOUT;                   /* Set new timer-value        */
  254.         }
  255.     }
  256.     return JM_NRM;
  257. }
  258. /****************************************************************************/
  259. /*                Communications adapter hardware interrupt                 */
  260. /*    This is very simple because we interrupt on receive only. Since we    */
  261. /*    must wait until the entire block has been received and checked be-    */
  262. /*    for doing anything else, the transmitter is polled.                   */
  263. /*                                                                          */
  264. /****************************************************************************/
  265. void interrupt far com_int()
  266. {
  267.     *write_ptr = (unsigned char)
  268.         inp(hardware_port);                    /* Put byte in buffer        */
  269.     outp(0x20,0x20);                           /* Reset hardware controller */
  270.     if (write_ptr < int_buffer + DAT_LEN )     /* Check buffer for overflow */
  271.         write_ptr++;                           /* Bump pointer if room      */
  272. }
  273. /****************************************************************************/
  274. /*                            Timer interrupt                               */
  275. /*    A WORD (timer) gets decremented every timer-tick if it is not already */
  276. /*    zero. This is used to set time-out values in the communication pro-   */
  277. /*    cedures so that a "wait-forever" can't occur.                         */
  278. /*                                                                          */
  279. /****************************************************************************/
  280. void interrupt far tim_int()
  281. {
  282.     if (timer)                             /* If NZ                         */
  283.         timer--;                           /* Bump the timer                */
  284.     outp(0x20,0x20);                       /* Reset the hardware controller */
  285.     _enable();                             /* Allow network interrupts      */
  286. #if !defined (TURBOC)
  287.     _chain_intr(old_tim);                  /* Go to old timer-tick routine  */
  288. #endif
  289. }
  290. /****************************************************************************/
  291. /*                          A B O R T   trap                                */
  292. /*    Control-C and control-break vectors are set to point here so that     */
  293. /*    a user-break harmlessly sets a flag so that interrupt vectors may     */
  294. /*    properly restored upon program exit.                                  */
  295. /*                                                                          */
  296. /****************************************************************************/
  297. void interrupt far fatal_abort()
  298. {
  299.     user_abort = 0xFFFF;                              /* Set abort flag     */
  300.     timer = 0;                                        /* Provoke timout     */
  301. }
  302. /****************************************************************************/
  303. /******************** E N D   O F   M O D U L E *****************************/
  304.