home *** CD-ROM | disk | FTP | other *** search
/ Power-Programmierung / CD1.mdf / magazine / drdobbs / 1991 / 10 / embedcp / code / comm.c < prev    next >
C/C++ Source or Header  |  1991-05-27  |  6KB  |  218 lines

  1. // MIOTDREM - Async link routines
  2. // ------------------------------
  3. //
  4. // Copyright (c) 1991, Stuart G. Phillips.  All rights reserved.
  5. //
  6. // Permission is granted for non-commercial use of this software.
  7. // You are expressly prohibited from selling this software in any form,
  8. // distributing it with another product, or removing this notice.
  9. // THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
  10. // IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
  11. // WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
  12. // PURPOSE.
  13. //
  14. // This module contains the routines that handle the async link between
  15. // MIO and TD.
  16. //
  17. //
  18.  
  19.  
  20. #include "miotdr.h"
  21. #include "mio.h"
  22. #include "8530.h"
  23.  
  24. // #define SERIAL_DEBUG to include status of the communications
  25. // activity.  Useful when porting to a new platform in order to
  26. // see what's going on !
  27.  
  28. #ifdef SERIAL_DEBUG
  29.  
  30. struct comm_region {    unsigned short status;
  31.                         unsigned short scc_status;
  32.                         unsigned short scc_special;
  33.                         unsigned short int_cnt;
  34.                         unsigned short rx_cnt;
  35.                         unsigned short tx_cnt;
  36.                         unsigned char  command;
  37.                    };
  38.  
  39. static struct comm_region *creg = (struct comm_region *)0x80;
  40.  
  41. #endif
  42.  
  43. // Static declarations
  44.  
  45. static void interrupt scc_int();
  46.  
  47. void send(unsigned char *buffer,
  48.           unsigned short length)
  49. {
  50.     // Send a packet of [length] bytes to the other end
  51.  
  52.     // Send the length and look for a NULL byte ack
  53.  
  54.     disable();
  55.  
  56.     scc_write(TDSCC|CMD,R1,0);          // Disable receive interrupts
  57.  
  58.     // Wait for TX Buffer emp
  59.     while (scc_read(TDSCC|CMD,R0) & Tx_BUF_EMP != Tx_BUF_EMP) ;
  60.  
  61.     scc_wdata(TDSCC|DATA,(unsigned char) length);
  62.  
  63. #ifdef SERIAL_DEBUG
  64.     creg->tx_cnt++;
  65. #endif
  66.  
  67.     while ((scc_read(TDSCC|CMD,R0) & Rx_CH_AV) != Rx_CH_AV) ;
  68.     (void) scc_rdata(TDSCC|DATA);       // Discard the NULL
  69.  
  70.     // Now send the data
  71.  
  72.     while (length--){
  73.         while ((scc_read(TDSCC|CMD,R0) & Tx_BUF_EMP) != Tx_BUF_EMP) ;
  74.         scc_wdata(TDSCC|DATA,*buffer++);
  75.  
  76. #ifdef SERIAL_DEBUG
  77.         creg->tx_cnt++;
  78. #endif
  79.     }
  80.  
  81.     scc_write(TDSCC|CMD,R1,INT_ALL_Rx); // Re-enable receive interrupts
  82.     enable();
  83. }
  84.  
  85.  
  86. void send_ack()
  87. {
  88.     // Send a NULL packet as an acknowledgment
  89.  
  90.     disable();
  91.  
  92.     while ((scc_read(TDSCC|CMD,R0) & Tx_BUF_EMP) != Tx_BUF_EMP) ;
  93.     scc_wdata(TDSCC|DATA,0);
  94.  
  95. #ifdef SERIAL_DEBUG
  96.     creg->tx_cnt++;
  97. #endif
  98.  
  99.     enable();
  100. }
  101.  
  102.  
  103. void comm_init()
  104. {
  105.     unsigned char data;
  106.  
  107.     // Set up SCC - this takes a while !
  108.  
  109.     scc_write(TDSCC|CMD,R9,FHWRES);     // Reset the SCC
  110.  
  111.     // Loop a while to let reset complete
  112.  
  113.     for (int i=0; i<256; i++) ;
  114.  
  115.     // Set SCC interrupt handler
  116.  
  117.     setvect(0x06,scc_int);
  118.  
  119.     // Set SCC interupt vector and enables
  120.  
  121.     scc_write(TDSCC|CMD,R2,0x06);
  122.     scc_write(TDSCC|CMD,R9,MIE);
  123.  
  124.     scc_write(TDSCC|CMD,R1,INT_ALL_Rx);
  125.  
  126.     // Set Async mode, 8 bits Tx/Rx, 1 stop bit, No parity
  127.  
  128.     scc_write(TDSCC|CMD,R5,DTR|Tx8|TxENAB|RTS);
  129.     scc_write(TDSCC|CMD,R3,Rx8|RxENABLE);
  130.  
  131.     // Set Baud rate generator constant
  132.     // Using 16x clock
  133.     //   9.6 Kbps       -   24  (0.16% error -   9615 bps)
  134.     //  19.2 Kbps       -   11  (0.16% error -  19230 bps)
  135.     //
  136.     // Using 1x clock
  137.     //  38.4 Kbps       -  102  (0.16% error -  38461 bps)
  138.     // 115.0 Kbps       -  32   (2.30% error - 117647 bps)
  139.  
  140.     scc_write(TDSCC|CMD,R4,X16CLK|SB1);
  141.     scc_write(TDSCC|CMD,R12,11);
  142.     scc_write(TDSCC|CMD,R13,0);
  143.  
  144.     // Set Baud rate generator source and enable
  145.  
  146.     scc_write(TDSCC|CMD,R11,RCBR|TCBR);
  147.     scc_write(TDSCC|CMD,R14,SSBR|BRSRC|BRENABL);
  148.  
  149.     // Enable 'slave' interupts
  150.  
  151.     data = inportb(IMKW);
  152.     outportb(IMKW,data&~(1 << IRQ7));
  153.  
  154.     enable();
  155. }
  156.  
  157.  
  158. static void interrupt scc_int()
  159. {
  160.     // Interrupts only on receive character or special status change
  161.     unsigned char status;
  162.     register unsigned char length;
  163.     register unsigned char *rxb = (unsigned char *)rx_buffer;
  164.  
  165.     status = scc_read(TDSCC|CMD,R0);
  166.     (void) scc_read(TDSCC|CMD,R1);
  167.  
  168. #ifdef SERIAL_DEBUG
  169.     creg->int_cnt++;
  170. #endif
  171.  
  172.     if (status & Rx_CH_AV){
  173.         length = scc_rdata(TDSCC|DATA);
  174.  
  175. #ifdef SERIAL_DEBUG
  176.         creg->status = length;
  177.         creg->rx_cnt++;
  178. #endif
  179.  
  180.         // A block of [length] bytes follows
  181.         // A zero count is treated specially - used in the initial handshake
  182.  
  183.         if (length == 0)
  184.             *rxb = TD_SYNC;
  185.         else {
  186.             // Send a NULL acknowledgement
  187.             while ((scc_read(TDSCC|CMD,R0) & Tx_BUF_EMP) != Tx_BUF_EMP) ;
  188.             scc_wdata(TDSCC|DATA,0);
  189.  
  190. #ifdef SERIAL_DEBUG
  191.             creg->tx_cnt++;
  192. #endif
  193.  
  194.             while (length--){
  195.                 while ((scc_read(TDSCC|CMD,R0) & Rx_CH_AV) != Rx_CH_AV) ;
  196.                 *rxb++ = scc_rdata(TDSCC|DATA);
  197.  
  198. #ifdef SERIAL_DEBUG
  199.                 creg->rx_cnt++;
  200. #endif
  201.             }
  202.         }
  203.  
  204.         msgq = (struct td_imsg *)rx_buffer;
  205.     }
  206.  
  207.     scc_write(TDSCC|CMD,R0,ERR_RES);        // Clear special status
  208.     scc_write(TDSCC|CMD,R0,RES_H_IUS);      // Reset so we can get next intr.
  209.     outportb(IMDW,ISEOI|IRQ7);              // Specific end of intr. to PIC
  210.  
  211.     // Check queued packet to determine if TD issued a stop command.
  212.     // If it did, assume that we're running as an interrupt to program
  213.     // under test - call mc_stop() to return control to MIOTDREM
  214.  
  215.     if (msgq->cmd == TD_STOP)
  216.         mc_stop();
  217. }
  218.