home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / THREAD.ZIP / TESTCOM.C < prev   
Text File  |  1992-10-31  |  24KB  |  462 lines

  1. /******************************************************************************/
  2. /*                                                                            */
  3. /*                                                                            */
  4. /*      Sample C Multi-Thread application                                     */
  5. /*                                                                            */
  6. /*      Written: 1/16/88                                                      */
  7. /*      Author : Sam Detweiler                                                */
  8. /*                                                                            */
  9. /*      Function: Any keys pressed will be passed UNFILTERED to the           */
  10. /*                async device driver. If you have a smart modem              */
  11. /*                you may dial phone numbers, or whatever.                    */
  12. /*                                                                            */
  13. /*                A great display of smooth screen update is                  */
  14. /*                HELP on IBM interal 1200 bauds modem                       */
  15. /*                                                                            */
  16. /*      The threads provide the following services                            */
  17. /*                                                                            */
  18. /*      1. comthread() reads from the async device driver                     */
  19. /*         into a circular buffer                                             */
  20. /*                                                                            */
  21. /*                                                                            */
  22. /*      2. kbdthread() reads the keyboard via KbdCharin (wait)                */
  23. /*         it processes both keystrokes and shift state changes               */
  24. /*                                                                            */
  25. /*         the keystroke record is read into a circular buffer                */
  26. /*         so that it need not be moved again.                                */
  27. /*                                                                            */
  28. /*      both threads 1 & 2 will wait on semiphores if their respective        */
  29. /*      circular buffers have become full.                                    */
  30. /*                                                                            */
  31. /*      3. Main thread                                                        */
  32. /*                                                                            */
  33. /*         opens "COM1"                                                       */
  34. /*         sets device operation characteristics                              */
  35. /*         sets baud rate                                                     */
  36. /*         sets line characteristics                                          */
  37. /*         sets keyboard to binary, shirt report on                           */
  38. /*         allocates circular buffers for keyboard and comm data              */
  39. /*         initializes shift state display status string                      */
  40. /*         starts threads for com and kbd processing                          */
  41. /*                                                                            */
  42. /*         does a DosMuxSemWait                                               */
  43. /*                on two semiphores                                           */
  44. /*                   1 - com thread data in buffer                            */
  45. /*                   2 - kbd thread data in buffer                            */
  46. /*                       if the keystroke is Ctrl-Z breaks loop               */
  47. /*                                                                            */
  48. /*                                                                            */
  49. /*                                                                            */
  50. /*                                                                            */
  51. /******************************************************************************/
  52. #define INCL_DOS
  53. #define INCL_DOSDEVIOCTL
  54. #define INCL_KBD
  55. #define INCL_VIO
  56. #include <os2.h>                /* include dos function declarations    */
  57. #include <stdlib.h>             /* include C memory mgmt defines        */
  58. #include <stdio.h>              /* include C memory mgmt defines        */
  59. #include <malloc.h>             /* include C memory mgmt defines        */
  60. #include <string.h>             /* include C memory mgmt defines        */
  61.  
  62. HFILE handle;                     /* COM1 file handle after open          */
  63.  
  64. unsigned DONE=0;                /* thread spin flag until <>0           */
  65.  
  66. #define Space ' '
  67. #define CtrlZ 0x1a
  68. #define ComData 0
  69. #define KeyData 1
  70. #define ASYNC_SETEXTENDEDBAUDRATE ASYNC_SETBAUDRATE+2
  71.  
  72. #define KeySize sizeof(KBDKEYINFO) /* size of keystroke data record */
  73.  
  74. char keystates[18];             /* shift status report string           */
  75. char keymask[]="ICNSAcLR";      /* mask of shift state flags            */
  76.  
  77.                 /* pointers to circular buffers */
  78.                 /* _start is address of first entry     */
  79.                 /* _end   is address of last  entry     */
  80.                 /* _last  is address of last entry removed    */
  81.                 /* _last is manipulated ONLY by main thread   */
  82.                 /* _next  is address of next position to add a record  */
  83.                 /* _last is manipulated ONLY by com and kbd threads   */
  84.  
  85. #define COMM_BUF_ENTRIES     2000   /* max entries in comm circular buffer */
  86. #define KEY_BUF_ENTRIES      200   /* max entries in keyboard circular buffer */
  87. #define THREAD_STACKSIZE 8192      /* size of thread program stack */
  88.  
  89.                 /* for communications buffer */
  90. UCHAR *combuf_start,*combuf_next,*combuf_last,*combuf_end;
  91.  
  92.                 /* for keyboard data record buffer */
  93. KBDKEYINFO *keybuf_start,*keybuf_next,*keybuf_last,*keybuf_end;
  94.  
  95. VIOMODEINFO md;                             /* current video mode data */
  96.  
  97. struct {char c,a;} attr;        /* char/attribute pair for VIO calls    */
  98.  
  99.                                 /* default line baud rate  */
  100. struct { unsigned long rate; char fraction;} mr={2400,0};
  101.  
  102. char lctrl[3]={8,0,0};          /* line control string                  */
  103.                                 /* 8 data bits, no parity, 1 stop       */
  104. char mo[2]={3,0xfd};            /* ENABLE DTR/RTS mode operation data   */
  105.  
  106.                                 /* semiphores for data in buffers       */
  107.                          /* when DosSemCleared will wake up main thread */
  108. HEV data_in_com_buf_sem,key_in_buf_sem;
  109.  
  110.                                 /* semiphores for data buffers full     */
  111.                    /* when DosSemCleared will wake up respective thread */
  112. HEV com_buf_full_sem,key_buf_full_sem;
  113.  
  114. HMUX MuxWaitSemHandle;
  115.  
  116.                                 /* DosMuxSemWait structure for main thread */
  117. SEMRECORD semlist[2];
  118.  
  119.  
  120. /******************************************************************************/
  121. /*                                                                            */
  122. /*      update shift state display line                                       */
  123. /*                                                                            */
  124. /******************************************************************************/
  125. void process_shiftstates(int x)
  126. {
  127. int m,i;
  128.             for(i=0,m=0x0080;i<8;i++,m>>=1)     /* loop thru low bits */
  129.               {
  130.               if(x & m)                         /* bit on ? */
  131.                 keystates[i*2]=keymask[i];      /* yes set indicator */
  132.               else
  133.                 keystates[i*2]=' ';             /* no, clear indicator */
  134.               }
  135.  
  136.             VioWrtCharStr(keystates,17,md.row,0,0); /* write indicator string */
  137. }
  138. /******************************************************************************/
  139. /*                                                                            */
  140. /*      Communications line handler thread                                    */
  141. /*                                                                            */
  142. /*      Reads data from Async Device driver receive buffer to local           */
  143. /*      application circular buffer                                           */
  144. /*                                                                            */
  145. /*      operation:                                                            */
  146. /*                                                                            */
  147. /*         do forever until DONE<>0                                           */
  148. /*            DosRead as much as room in buffer for                           */
  149. /*                      (last to end)                                         */
  150. /*                          OR (in case of buffer wrap)                       */
  151. /*                      (last to next)                                        */
  152. /*              if any bytes read                                             */
  153. /*               update next pointer with size read                           */
  154. /*               check for buffer wrap                                        */
  155. /*               DosSemClear main thread com_data_in_buf_sem semiphore        */
  156. /*               if buffer full DoSemWait for main thread to take some data   */
  157. /*                                                                            */
  158. /*         if DONE<>0                                                         */
  159. /*            DosExit thread                                                  */
  160. /*                                                                            */
  161. /******************************************************************************/
  162. VOID _Optlink comthread(PVOID f)
  163. {
  164. ULONG bytesread;
  165. ULONG len,i;
  166.  
  167.         DosSetPrty(PRTYS_THREAD,PRTYC_TIMECRITICAL,PRTYD_MINIMUM,0);
  168.         for(;!DONE;)                    /* loop til DONE <> 0 */
  169.           {
  170.           if(combuf_next>=combuf_last) /* check for remaining space in buffer*/
  171.             len=combuf_end-combuf_next;/* _last leading _next pointer */
  172.           else
  173.             len=combuf_last-combuf_next;/* _last trailing _next pointer */
  174.  
  175.                                         /* read as much as possible */
  176.           DosRead(handle,combuf_next,len,&bytesread);
  177.  
  178.           if(bytesread)                 /* make sure we actually read some */
  179.             {
  180.             combuf_next+=bytesread;   /* update _next pointer for data read */
  181.  
  182.             if(combuf_next>=combuf_end) /* if the buffer would wrap */
  183.               combuf_next=combuf_start; /* start at the front again */
  184.  
  185.             /* tell main thread data is available */
  186.  
  187.             if(combuf_next==combuf_last) /* if buffer full */
  188.               {
  189.               /* wait til main thread takes some */
  190.               DosResetEventSem(com_buf_full_sem,&i);
  191.               DosPostEventSem(data_in_com_buf_sem);
  192.               DosWaitEventSem(com_buf_full_sem,SEM_INDEFINITE_WAIT);
  193.               }
  194.             else
  195.               DosPostEventSem(data_in_com_buf_sem);
  196.             }
  197.           }
  198.         DosExit(0,0);                      /* DONE<>0 end thread */
  199. }
  200.  
  201. /******************************************************************************/
  202. /*                                                                            */
  203. /*      Keyboard buffer handler thread                                        */
  204. /*                                                                            */
  205. /*      Reads keystrokes and shift report records into local                  */
  206. /*      application circular buffer                                           */
  207. /*                                                                            */
  208. /*      operation:                                                            */
  209. /*                                                                            */
  210. /*         do forever until DONE<>0                                           */
  211. /*            KbdCharIn WAIT  for next keystroke/shift report                 */
  212. /*            if shift report (shows ONLY CHANGES since last report)          */
  213. /*              update user awareness string                                  */
  214. /*              write user awareness string to reserved last line of display  */
  215. /*            else                                                            */
  216. /*              if keystroke                                                  */
  217. /*                update _next pointer                                        */
  218. /*                check for buffer wrap                                       */
  219. /*                                                                            */
  220. /*         if DONE<>0                                                         */
  221. /*            DosExit thread                                                  */
  222. /*                                                                            */
  223. /******************************************************************************/
  224. VOID _Optlink kbdthread(PVOID f)
  225. {
  226. ULONG i;
  227.         for(;!DONE;)               /* loop in this thread til main says done */
  228.           {
  229.           KbdCharIn(keybuf_next,0,0);       /* get keystroke or status, wait */
  230.           if(keybuf_next->fbStatus & KBDTRF_SHIFT_KEY_IN)         /* shift status change */
  231.                                                 /* update shift state display */
  232.             process_shiftstates(keybuf_next->fsState);
  233.  
  234.           else
  235.             if(keybuf_next->fbStatus & KBDTRF_FINAL_CHAR_IN)       /* character returned */
  236.               {
  237.               keybuf_next++;                    /* say we had one */
  238.  
  239.               if(keybuf_next>=keybuf_end)       /* buffer wrap ? */
  240.                 keybuf_next=keybuf_start;       /* point to start */
  241.  
  242.  
  243.                                                 /* tell handler some data */
  244.  
  245.               if(keybuf_next==keybuf_last)      /* about to overlay start? */
  246.                 {
  247.                                                 /* so wait til some removed */
  248.                 DosResetEventSem(key_buf_full_sem,&i);
  249.                 DosPostEventSem(key_in_buf_sem);
  250.                 DosWaitEventSem(key_buf_full_sem,SEM_INDEFINITE_WAIT);
  251.                 }
  252.               else
  253.                 DosPostEventSem(key_in_buf_sem);
  254.  
  255.               }
  256.           }
  257.         DosExit(0,0);                           /* DONE<>0 end thread */
  258. }
  259.  
  260. /******************************************************************************/
  261. /*                                                                            */
  262. /*      insures last line (shift state disply line) will not                  */
  263. /*      be overwritten by data                                                */
  264. /*                                                                            */
  265. /******************************************************************************/
  266. void protect_lastline(VOID)
  267. {
  268. USHORT  cursor_row,cursor_col;
  269.         VioGetCurPos(&cursor_row,&cursor_col,0); /* get cursor position */
  270.         if(cursor_row==md.row)                   /* on last line? */
  271.           {                                      /* yes, scroll screen 1 line */
  272.           VioScrollUp(0,0,md.row-1,md.col,1,(PCHAR)&attr,0);
  273.                                                  /* move cursor up one line */
  274.           VioSetCurPos(cursor_row-1,cursor_col,0);
  275.           }
  276. }
  277. /******************************************************************************/
  278. /*                                                                            */
  279. /*      Main Thread                                                           */
  280. /*                                                                            */
  281. /*      does ALL OUTPUT and INPUT processing                                  */
  282. /*      writes to display and async device driver                             */
  283. /*                                                                            */
  284. /*                                                                            */
  285. /*                                                                            */
  286. /******************************************************************************/
  287. main(int argc, char *argv[])
  288. {
  289. ULONG act,br,rc,i,ce,keytid,comtid,sem_index,cursor_row,cursor_col;
  290. unsigned m;
  291. char r,ch,*comstack,*keystack;
  292. KBDKEYINFO y;
  293. KBDINFO kbstat;
  294. char *comname;
  295. DCBINFO dcb;
  296.                         /*                                              */
  297.                         /*   Open COM1, if is exists, no sharing        */
  298.                         /*                                              */
  299.         if(argc>1)
  300.           comname=argv[1];
  301.         else
  302.           comname="COM2";
  303.         rc=DosOpen(comname,&handle,&act,0L,0,0x01,0x92,0L);
  304.  
  305.                         /* get device characteristics block             */
  306.         i=sizeof(dcb);
  307.         rc=DosDevIOCtl(handle,IOCTL_ASYNC,ASYNC_GETDCBINFO, NULL, 0, NULL,(PVOID)&dcb,sizeof(dcb),&i);
  308.  
  309.                         /* set read timeout  to 20 second  */
  310.         dcb.usReadTimeout=20000;
  311.                         /* set write timeout as small as possible */
  312.         dcb.usWriteTimeout=0;
  313.                         /* Turn on DTR       */
  314.         dcb.fbCtlHndShake = MODE_DTR_CONTROL;
  315.  
  316.                         /* Turn on RTS       */
  317.         dcb.fbFlowReplace = MODE_RTS_CONTROL;
  318.  
  319.                         /* Set WAIT_For_Something read processing   */
  320.         dcb.fbTimeout = MODE_WAIT_READ_TIMEOUT;
  321.  
  322.                         /* update device characteristics                   */
  323.         i=sizeof(dcb);
  324.         rc=DosDevIOCtl(handle,IOCTL_ASYNC,ASYNC_SETDCBINFO,(PVOID)&dcb,sizeof(dcb),&i, NULL, 0, NULL);
  325.  
  326.         if(argc>2)
  327.           {
  328.           mr.rate=atol(argv[2]);              /* Set Baud rate                                   */
  329.           } /* end if */
  330.  
  331.         i=mr.rate>=19200?sizeof(mr):sizeof(USHORT);
  332.  
  333.         rc=DosDevIOCtl(handle,IOCTL_ASYNC,mr.rate>19200?ASYNC_SETEXTENDEDBAUDRATE:ASYNC_SETBAUDRATE,(PVOID)&mr,i,&i, NULL, 0, NULL);
  334.  
  335.                         /* Set 8 data bits, No parity, 1 stop bit          */
  336.         i=sizeof(lctrl);
  337.         rc=DosDevIOCtl(handle,IOCTL_ASYNC,ASYNC_SETLINECTRL,(PVOID)&lctrl,sizeof(lctrl),&i, NULL, 0, NULL);
  338.  
  339.                         /* Make sure DTR and RTS are on                    */
  340.         i=sizeof(mo);
  341.         rc=DosDevIOCtl(handle,IOCTL_ASYNC,ASYNC_SETMODEMCTRL,(PVOID)&mo,sizeof(mo),&i, &ce, sizeof(ce), &i);
  342.  
  343.                         /* allocate keystoke circular buffer */
  344.         if(!(keybuf_start=keybuf_next=keybuf_last=malloc(KEY_BUF_ENTRIES*KeySize)))
  345.            exit(printf("Out of storage kbdbuf\n"));
  346.  
  347.                         /* allocate communicaition circular buffer */
  348.         if(!(combuf_start=combuf_next=combuf_last=malloc(COMM_BUF_ENTRIES)))
  349.            exit(printf("Out of storage combuf\n"));
  350.  
  351.         combuf_end=combuf_start+COMM_BUF_ENTRIES;/* set end of buffer pointers */
  352.         keybuf_end=keybuf_start+KEY_BUF_ENTRIES;
  353.  
  354.         attr.a=0x07;                    /* set scroll attribute */
  355.         attr.c=Space;                   /* set scroll data byte */
  356.         VioScrollUp(0,0,-1,-1,-1,(PCHAR)&attr,0); /* clear screen */
  357.  
  358.         VioSetCurPos(0,0,0);            /* set cursor, top left corner */
  359.  
  360.         md.cb=12;                       /* set mode data length */
  361.         rc=VioGetMode(&md,0);           /* get video mode data */
  362.         md.row--;                       /* make 0 relative */
  363.         md.col--;                       /* make 0 realtive */
  364.  
  365.         kbstat.cb=10;                   /* keyboard status data length */
  366.         rc=KbdGetStatus(&kbstat,0);     /* get keyboard status data */
  367.  
  368.         /* set shift report on, Binary (raw mode) */
  369.         kbstat.fsMask= KEYBOARD_ECHO_OFF | KEYBOARD_BINARY_MODE | KEYBOARD_SHIFT_REPORT;
  370.  
  371.         memset(keystates,Space,sizeof(keystates)-1);       /* clear shift status line */
  372.  
  373.         process_shiftstates(kbstat.fsState);/* update shift state display */
  374.  
  375.         rc=KbdSetStatus(&kbstat,0);     /* set keyboard status now */
  376.  
  377.                                         /* set MuxSemWait semiphores */
  378.         DosCreateEventSem((PSZ)NULL,&data_in_com_buf_sem,0,0);
  379.         DosCreateEventSem((PSZ)NULL,&key_in_buf_sem,0,0);
  380.         DosCreateEventSem((PSZ)NULL,&com_buf_full_sem,0,0);
  381.         DosCreateEventSem((PSZ)NULL,&key_buf_full_sem,0,0);
  382.         memset(&semlist,0,sizeof(semlist));
  383.         semlist[0].hsemCur=(HSEM)data_in_com_buf_sem;
  384.         semlist[0].ulUser=ComData;
  385.         semlist[1].hsemCur=(HSEM)key_in_buf_sem;
  386.         semlist[1].ulUser=KeyData;
  387.         DosCreateMuxWaitSem((PSZ)NULL,&MuxWaitSemHandle,2,(PSEMRECORD)&semlist,DCMW_WAIT_ANY);
  388.  
  389.                                         /* create kbd thread */
  390.         _beginthread(kbdthread,NULL,THREAD_STACKSIZE,NULL);
  391.  
  392.                                         /* create com thread */
  393.         _beginthread(comthread,NULL,THREAD_STACKSIZE,NULL);
  394.  
  395.         printf("Enter your Modem commands now (NoWait Mode)\n");
  396.  
  397.         for(;;)
  398.           {                   /* wait for one of two semiphores to be cleared */
  399.           DosWaitMuxWaitSem(MuxWaitSemHandle,SEM_INDEFINITE_WAIT,&sem_index);
  400.  
  401.           switch(sem_index)   /* semindex tells which one cleared */
  402.              {
  403.              case ComData:    /* com data in buffer */
  404.  
  405.                   protect_lastline();  /* make sure we don't write on last line */
  406.                                            /* reset semiphore so we will wait */
  407.                   DosResetEventSem(data_in_com_buf_sem,&i);
  408.  
  409.                   VioWrtTTY(combuf_last++,1,0); /* write data to screen */
  410.  
  411.                   if(combuf_last>=combuf_end)   /* buffer wrap? */
  412.                     combuf_last=combuf_start;   /* point to start */
  413.  
  414.                   if(combuf_last!=combuf_next)  /* buffer empty? */
  415.                                        /* NO, reset semiphore so we don' wait */
  416.                     DosPostEventSem(data_in_com_buf_sem);
  417.  
  418.                                               /* clear buffer full semiphore */
  419.                                              /* in case the thread is waiting */
  420.                   DosPostEventSem(com_buf_full_sem);
  421.  
  422.                   break;                        /* done */
  423.              case KeyData:      /* keystroke in buffer */
  424.                                 /* get then character code */
  425.                   ch=(keybuf_last++)->chChar;
  426.  
  427.                   DosResetEventSem(key_in_buf_sem,&i);
  428.  
  429.                   if(ch==CtrlZ)  /* is it Ctrl-Z */
  430.                     break;       /* yes, end processing */
  431.  
  432.                   protect_lastline();  /* make sure we don't write on last line */
  433.  
  434.                   VioWrtTTY(&ch,1,0);  /* write data to screen */
  435.  
  436.                   rc=DosWrite(handle,&ch,1,&br);  /* write data to device */
  437.  
  438.                   if(keybuf_last>=keybuf_end)     /* buffer wrap ? */
  439.                     keybuf_last=keybuf_start;     /* set back to start */
  440.  
  441.                   if(keybuf_last!=keybuf_next)    /* buffer empty? */
  442.                                            /* reset semiphore so we will wait */
  443.                     DosPostEventSem(key_in_buf_sem);
  444.  
  445.                                               /* clear buffer full semiphore */
  446.                                              /* in case the thread is waiting */
  447.                   DosPostEventSem(key_buf_full_sem);
  448.  
  449.                   break;                        /* keyboard done */
  450.  
  451.              default:                           /* SHOULDN'T get here */
  452.                   printf("oops, index is %d\n",sem_index);
  453.                   break;
  454.              }
  455.           if(ch==CtrlZ)                         /* Ctrl-Z keystroke? */
  456.              break;                             /* end loop */
  457.           }
  458.         DONE=1;                                 /* set done <> 0 */
  459.         DosClose(handle);                       /* close COM1 */
  460.         DosExit(1,0);                           /* and exit */
  461. }
  462.