home *** CD-ROM | disk | FTP | other *** search
/ Power-Programmierung / CD1.mdf / magazine / drdobbs / 1989 / 02 / stevens.asc < prev    next >
Text File  |  1989-01-04  |  10KB  |  394 lines

  1. _C Programming Column_
  2. by Al Stevens
  3.  
  4. [LISTING ONE]
  5.  
  6. /* ---------- serial.h ---------------
  7.  * Serial Port Definitions
  8.  */
  9. extern int ticker, COMPORT;
  10. extern char *nextin, *nextout;
  11. /* ----------- serial prototypes ----------- */
  12. void initcomport(void);
  13. int readcomm(void);
  14. int writecomm(int);
  15. void clear_serial_queue(void);
  16. /* -------- timer prototypes --------- */
  17. void sleep(unsigned);
  18. int set_timer(unsigned);
  19. void intercept_timer(void);
  20. void restore_timer(void);
  21. void restore_serialint(void);
  22. /* ----------------- macros ------------------- */
  23. #define comstat() (inp(LINESTATUS))
  24. #define input_char_ready() (nextin!=nextout)
  25. #define timed_out() (ticker==0)
  26. #define set_timer(secs) ticker=secs*182/10+1
  27. #define XON  17
  28. #define XOFF 19
  29. /* ---------------- serial port addresses ----------------- */
  30. /* - 8250 UART base port address:  COM1 = 3f8, COM2 = 2f8 - */
  31. #define BASEPORT    (0x3f8-((COMPORT-1)<<8)) 
  32. #define TXDATA       BASEPORT      /* transmit data         */
  33. #define RXDATA       BASEPORT      /* receive data          */
  34. #define DIVLSB       BASEPORT      /* baud rate divisor lsb */
  35. #define DIVMSB      (BASEPORT+1)   /* baud rate divisor msb */
  36. #define INTENABLE   (BASEPORT+1)   /* interrupt enable      */
  37. #define INTIDENT    (BASEPORT+2)   /* interrupt ident'n     */
  38. #define LINECTL     (BASEPORT+3)   /* line control          */
  39. #define MODEMCTL    (BASEPORT+4)   /* modem control         */
  40. #define LINESTATUS  (BASEPORT+5)   /* line status           */
  41. #define MODEMSTATUS (BASEPORT+6)   /* modem status          */
  42. /* --------------- serial interrupt stuff ------------------ */
  43. #define IRQ     (4-(COMPORT-1))     /* 0-7 = IRQ0-IRQ7       */
  44. #define COMINT  (12-(COMPORT-1))    /* interrupt vector 12/11*/
  45. #define COMIRQ  (~(1 << IRQ))
  46. #define PIC01   0x21 /*8259 Programmable Interrupt Controller*/
  47. #define PIC00   0x20 /* "      "              "        "     */
  48. #define EOI     0x20 /* End of Interrupt command             */
  49. #define TIMER   0x1c /* PC timer interrupt vector            */
  50. /* --------------- line status register values ------------- */
  51. #define XMIT_DATA_READY    0x20
  52. /* ------------ modem control register values -------------- */
  53. #define DTR   1
  54. #define RTS   2
  55. #define OUT2  8
  56. /* ----------- interrupt enable register signals ------------ */
  57. #define DATAREADY 1
  58. /* ------------- serial input interrupt buffer -------------- */
  59. #define BUFSIZE 1024
  60. #define SAFETYLEVEL (BUFSIZE/4)
  61. #define THRESHOLD (SAFETYLEVEL*3)
  62. #ifndef TRUE
  63. #define TRUE 1
  64. #define FALSE 0
  65. #endif
  66.  
  67.  
  68. [LISTING TWO]]
  69.  
  70. /* ---------- serial.c ---------------
  71.  * Serial Port Communications Functions
  72.  */
  73. #include <stdio.h>
  74. #include <conio.h>
  75. #include <dos.h>
  76. #include "serial.h"
  77.  
  78. #if COMPILER == MSOFT
  79. #define getvect _dos_getvect
  80. #define setvect _dos_setvect
  81. #endif
  82.  
  83. char recvbuff[BUFSIZE];
  84. char *nextin = recvbuff;
  85. char *nextout = recvbuff;
  86. int buffer_count;
  87. int COMPORT  = 1;    /* COM1 or COM2                  */
  88. int PARITY   = 0;    /* 0 = none, 1 = odd, 2 = even   */
  89. int STOPBITS = 1;    /* 1 or 2                        */
  90. int WORDLEN  = 8;    /* 7 or 8                        */
  91. int BAUD     = 1200; /* 110,150,300,600,1200,2400     */
  92. int TIMEOUT  = 10;   /* number of seconds to time out */
  93. int xonxoff_enabled = TRUE;
  94. static int waiting_for_XON;
  95. static int waiting_to_send_XON;
  96. int ticker;
  97.  
  98. /* ----- the com port initialization parameter byte ------ */
  99. static union    {
  100.     struct {
  101.         unsigned wordlen  : 2;
  102.         unsigned stopbits : 1;
  103.         unsigned parity   : 3;
  104.         unsigned brk      : 1;
  105.         unsigned divlatch : 1;
  106.     } initbits;
  107.     char initchar;
  108. } initcom;
  109. static void (interrupt far *oldtimer)(void);
  110. static void interrupt far newtimer(void);
  111. static void (interrupt far *oldcomint)(void);
  112. static void interrupt far newcomint(void);
  113.  
  114. /* -------- initialize the com port ----------- */
  115. void initcomport(void)
  116. {
  117.     initcom.initbits.parity   = PARITY == 2 ? 3 : PARITY;
  118.     initcom.initbits.stopbits = STOPBITS-1;
  119.     initcom.initbits.wordlen  = WORDLEN-5;
  120.     initcom.initbits.brk      = 0;
  121.     initcom.initbits.divlatch = 1;
  122.     outp(LINECTL, initcom.initchar);
  123.     outp(DIVLSB, (char) ((115200L/BAUD) & 255));
  124.     outp(DIVMSB, (char) ((115200L/BAUD) >> 8));
  125.     initcom.initbits.divlatch = 0;
  126.     outp(LINECTL, initcom.initchar);
  127. /* ------ hook serial interrupt vector --------- */
  128.     if (oldcomint == NULL)
  129.         oldcomint = getvect(COMINT);
  130.     setvect(COMINT, newcomint);
  131.     outp(MODEMCTL, (inp(MODEMCTL) | DTR | RTS | OUT2));
  132.     outp(PIC01, (inp(PIC01) & COMIRQ));
  133.     outp(INTENABLE, DATAREADY);
  134.     outp(PIC00, EOI);
  135. /* ----- flush any old interrupts ------ */
  136.     inp(RXDATA);
  137.     inp(INTIDENT);
  138.     inp(LINESTATUS);
  139.     inp(MODEMSTATUS);
  140. }
  141.  
  142. /* ------ restore the serial interrupt vector ---------- */
  143. void restore_serialint(void)
  144. {
  145.     if (oldcomint)
  146.         setvect(COMINT, oldcomint);
  147. }
  148.  
  149. /* ------- clear the serial input buffer --------- */
  150. void clear_serial_queue(void)
  151. {
  152.     nextin = nextout = recvbuff;
  153.     buffer_count = 0;
  154. }
  155.  
  156. /* ---- serial input interrupt service routine ------- */
  157. static void interrupt far newcomint(void)
  158. {
  159.     int c;
  160.     outp(PIC00,EOI);
  161.     if (nextin == recvbuff+BUFSIZE)
  162.         nextin = recvbuff;           /* circular buffer */
  163.     c = inp(RXDATA);              /* read the input  */
  164.     if (xonxoff_enabled)
  165.         if (c == XOFF)               /* test XON        */
  166.             waiting_for_XON = 1;
  167.         else if (c == XON)           /* test XOFF       */
  168.             waiting_for_XON = 0;
  169.     if (!xonxoff_enabled || (c != XON && c != XOFF))    {
  170.         *nextin++ = (char) c;        /* put char in buff*/
  171.         buffer_count++;
  172.     }
  173.     if (xonxoff_enabled && !waiting_to_send_XON &&
  174.             buffer_count > THRESHOLD)    {
  175.         while ((inp(LINESTATUS) & XMIT_DATA_READY) == 0)
  176.             ;
  177.         outp(TXDATA, XOFF);          /* send XOFF        */
  178.         waiting_to_send_XON = 1;
  179.     }
  180. }
  181.  
  182. /* ---- read a character from the input buffer ----- */
  183. int readcomm(void)
  184. {
  185.     set_timer(TIMEOUT);
  186.     while (!input_char_ready())
  187.         if (timed_out())
  188.             return FALSE;
  189.     if (nextout == recvbuff+BUFSIZE)
  190.         nextout = recvbuff;
  191.     --buffer_count;
  192.     if (waiting_to_send_XON && buffer_count < SAFETYLEVEL) {
  193.         waiting_to_send_XON = 0;
  194.         writecomm(XON);
  195.     }
  196.     return *nextout++;
  197. }
  198.  
  199. /* ---- write a character to the comm port ----- */
  200. int writecomm(int c)
  201. {
  202.     while (waiting_for_XON)
  203.         ;
  204.     set_timer(TIMEOUT);
  205.     while ((inp(LINESTATUS) & XMIT_DATA_READY) == 0)
  206.         if (timed_out())
  207.             return FALSE;
  208.     outp(TXDATA, c);
  209.     return TRUE;
  210. }
  211.  
  212. /* ---- intercept the timer interrupt vector ----- */
  213. void intercept_timer(void)
  214. {
  215.     if (oldtimer == NULL)    {
  216.         oldtimer = getvect(TIMER);
  217.         setvect(TIMER, newtimer);
  218.     }
  219. }
  220.  
  221. /* ---------- sleep for n seconds ------------ */
  222. void sleep(unsigned secs)
  223. {
  224.     set_timer(secs);
  225.     while (!timed_out())
  226.         ;
  227. }
  228.  
  229. /* ---- restore timer interrupt vector ------- */
  230. void restore_timer()
  231. {
  232.     if (oldtimer)
  233.         setvect(TIMER, oldtimer);
  234. }
  235.  
  236. /* ------ ISR to count timer ticks ------- */
  237. static void interrupt far newtimer()
  238. {
  239.     (*oldtimer)();
  240.     if (ticker)
  241.         --ticker;
  242. }
  243.  
  244.  
  245.  
  246. [LISTING THREE]
  247.  
  248. /* -------- modem.h ------------ 
  249.  * Modem Definitions
  250.  */
  251. /* -------- Hayes modem control strings --------- */
  252. #define RESETMODEM "ATZ\r~"
  253. #define INITMODEM  "ATE0M1S7=60S11=55V1X3S0=0\r~"
  254. #define HANGUP     "~+++~ATH0\r~ATS0=0\r~"
  255. #define ANSWER     "ATS0=1\r~"
  256. /* --------- prototypes ---------- */
  257. void initmodem(void);
  258. void placecall(void);
  259. void answercall(void);
  260. void disconnect(void);
  261. void release_modem(void);
  262.  
  263.  
  264. [LISTING FIVE]
  265.  
  266. /* ------------ modem.c --------- */
  267.  
  268. #include <dos.h>
  269. #include <conio.h>
  270. #include "serial.h"
  271. #include "modem.h"
  272.  
  273. char DIAL[] = "ATDT";
  274. char PHONENO[21];
  275.  
  276. int direct_connection;    /* true if connected without a modem */
  277.  
  278. /* ----------- write a command to the modem ------------ */
  279. static void modout(char *s)
  280. {
  281.     while(*s)    {
  282.         if (*s == '~')
  283.             sleep(1);
  284.         else if (!writecomm(*s))
  285.             break;
  286.         s++;
  287.     }
  288. }
  289.  
  290. /* ----------- initialize the modem ---------- */
  291. void initmodem(void)
  292. {
  293.     intercept_timer();
  294.     initcomport();
  295.     if (!direct_connection)    {
  296.         modout(RESETMODEM);
  297.         modout(INITMODEM);
  298.     }
  299. }
  300.  
  301. /* -------- release the modem --------- */
  302. void release_modem(void)
  303. {
  304.     if (!direct_connection)
  305.         modout(RESETMODEM);
  306.     restore_timer();
  307.     restore_serialint();
  308. }
  309.  
  310. /* ----------- place a call -------------- */
  311. void placecall(void)
  312. {
  313.     if (!direct_connection)    {
  314.         modout(DIAL);
  315.         modout(PHONENO);
  316.         modout("\r");
  317.         clear_serial_queue();
  318.     }
  319. }
  320.  
  321. /* ------------- answer a call ------------ */
  322. void answercall(void)
  323. {
  324.     if (!direct_connection)    {
  325.         modout(ANSWER);
  326.         clear_serial_queue();
  327.     }
  328. }
  329.  
  330. /* ------------ disconnect the call ----------------- */
  331. void disconnect(void)
  332. {
  333.     if (!direct_connection)    {
  334.         modout(HANGUP);
  335.         clear_serial_queue();
  336.     }
  337. }
  338.  
  339.  
  340.  
  341. [LISTING SIX]
  342.  
  343. ; ------------- keyhit.asm ---------------
  344. ;
  345. ; Use this in MSC C programs in place of kbhit
  346. ; This function avoids Ctrl-Break aborts
  347. ;
  348. _text   segment para public 'code'
  349. assume  cs:_text
  350. public  _keyhit
  351. _keyhit proc    near
  352.         mov     ah,1
  353.         int     16h
  354.         mov     ax,1
  355.         jnz     keyret
  356.         mov     ax,0
  357. keyret: ret
  358. _keyhit endp
  359. _text   ends
  360.         end
  361.  
  362.  
  363.  
  364. [LISTING SEVEN]
  365.  
  366. tinycomm (serial.h, modem.h)
  367. modem (serial.h, modem.h)
  368. serial (serial.h)
  369.  
  370.  
  371. [LISTING EIGHT]
  372.  
  373.  
  374. #  TINYCOMM.MAK: make file for TINYCOMM.EXE with Microsoft C/MASM
  375. #
  376.  
  377. .c.obj:
  378.     cl /DMSOFT=1 /DCOMPILER=MSOFT -c -W3 -Gs $*.c
  379.  
  380. tinycomm.obj : tinycomm.c serial.h modem.h window.h
  381.  
  382. modem.obj : modem.c serial.h modem.h
  383.  
  384. serial.obj : serial.c serial.h
  385.  
  386. keyhit.obj : keyhit.asm
  387.     masm /MX keyhit;
  388.  
  389. tinycomm.exe : tinycomm.obj modem.obj serial.obj keyhit.obj 
  390.     link tinycomm+modem+serial+keyhit,tinycomm,,\lib\slibce
  391.  
  392.  
  393.  
  394.