Solved

How to make Threads and how to use them in a serial communication program

Posted on 1998-01-13
5
243 Views
Last Modified: 2013-11-20
I 'm trying to make a ReadThread for reading from port COM3 butit does not work. I want to use the WaitCommEvent,read the buffer and save in to a file or display to the monitor.
Can someone explain me how to do it?
0
Comment
Question by:hercules120197
  • 2
  • 2
5 Comments
 

Author Comment

by:hercules120197
ID: 1313965
Adjusted points to 50
0
 
LVL 1

Expert Comment

by:JamieR
ID: 1313966
You need to:

Open the comm port using CreateFile
Then create the read thread.
return

The thread procedure should:

(loop while not exiting)
{
  Starting reading a single byte from the port.
  Do whatever you want to do with the data
}

I would suggest that you don't use WaitCommEvent as you can just do a blocking read from your read thread.

Jamie
0
 

Author Comment

by:hercules120197
ID: 1313967
I need an example because i tried to make a read thread but i does not work.
0
 
LVL 1

Accepted Solution

by:
JamieR earned 50 total points
ID: 1313968
There's an example called TTY in the Win32 SDK samples but it's fairly crude.

0
 

Expert Comment

by:mdaly
ID: 1313969
Hello,  I am an embedded systems and Visual C++ programmer.  I had to make a thread that was able to take transmit requests and then receive a response. The tricky part was that this thread also had to receive unsolicited data (unexpected data). Here is a load of code that is currently running very efficiently on my system.  Also,  I had alot of trouble making this work, not because of MFC but simply because communications is very specialized and takes alot of designed and thought(timming issues can be murderous).  Good luck.

/////////////////////////////////////////////////////////////////////
// Name:  CommThread
// Args:
// Rets:
// Info:  Thread used to handle the actual communications with
//        the external device
/////////////////////////////////////////////////////////////////////
void CommThread( void *ch )
{


   /* Open the Comm Port */
   Comm.hFile = CreateFile (
      "\\\\.\\COM2",     // address of name of the communications device
      GENERIC_READ | GENERIC_WRITE,          // access (read-write) mode
      0,                  // share mode
      NULL,               // address of security descriptor
      OPEN_EXISTING,      // how to create
      FILE_FLAG_OVERLAPPED,                  // file attributes
      NULL                // handle of file with attributes to copy
   );

   /* if open failed */
   if( Comm.hFile == INVALID_HANDLE_VALUE ) {
         FILE *test = fopen( "badhandle.txt", "w+" );
         fclose( test );

          _endthread();  /* exit thread - from _beginthread */
            return;
       
   }
   
     
   unsigned long   outnum;                  /* number of bytes sent */
   DWORD           dwEvtMask = EV_RXCHAR;  /* read characters mask */
   int             bytecnt = 0;       /* number of received bytes */
   char buf[10];                      /* store location for received bytes */
   unsigned long   bytes_read = 0;    /* number of bytes read on the last pass */
   unsigned long   pended_bytes = 0;  /* this var. has no definite use */
   DWORD           bresult;           /* return value of overlapped functions */
   char            dowait = 1;        /* flags used for a waitcommevent */
         

   /* reset the expected byte count */
   Comm.expected = 0;
   /* reset the number of bytes to transmit */
   Comm.numtx = 0;

   /* Create the comm interrupt event */
   Comm.o.hEvent = CreateEvent(0,1,0,"hevent");

   /* Set the Thread Active Event */
   SetEvent( Comm.upThread );

   /* Create the Wakeup Thread event */
   Comm.Wakeup = CreateEvent(0,1,0,"Wakeup");

   /* Create receive complete event */
   Comm.rxdone = CreateEvent(0,1,0,"rxdone");


   /* create data communications structure */
   DCB DataCom;
   /* get the current communications status */
   if( GetCommState( Comm.hFile, &DataCom ) != 0 )
   {
          /* fill the comm structure with baud-9600, Parity-N, Bits-8, StopBits-1 */
        DataCom.BaudRate = 9600;            // current baud rate
        DataCom.ByteSize = 8;             // number of bits/byte, 4-8
        DataCom.Parity = 0;               // 0-4=no,odd,even,mark,space
        DataCom.StopBits = 0;             // 0,1,2 = 1, 1.5, 2
      
        /* set the data communication structure to the current settings */
        if( SetCommState( Comm.hFile, &DataCom ) != 0 );
             
   }


   /* load array with events to wait for */
   HANDLE HArray[2];
   HArray[0] = Comm.o.hEvent;
   HArray[1] = Comm.Wakeup;


  /*----------------------------------------------------------------------------------------
   * Set the Communication timeouts - without this function a call to ReadFile or WriteFile
   * would lock up the Comm port indefinitly
   * - note:  this does not, thankfully, seem to effect the WaitCommEvent function
   *---------------------------------------------------------------------------------------- */
   COMMTIMEOUTS timeouts;

   timeouts.ReadIntervalTimeout = MAXDWORD;
   timeouts.ReadTotalTimeoutMultiplier = 0;
   timeouts.ReadTotalTimeoutConstant = 0;
   timeouts.WriteTotalTimeoutMultiplier = 0;
   timeouts.WriteTotalTimeoutConstant = 0;

      if (!SetCommTimeouts(Comm.hFile, &timeouts))
      {
         // Error setting timeouts.
            FILE *esc = fopen( "errsetcom.txt", "w+" );
            fclose( esc );
      }
   

   /* first while forever */
   while( 1 )
   {


        /* wait loop - second while forever */
            while (1)
            {
                  /* if the waitcommevent needs to posted */
                  if ( dowait )
                  {
                        /* set the wait-comm mask to kick when it sees an incomming character */
                        if( !SetCommMask( Comm.hFile, dwEvtMask ) )
                        {
                              /* report an error */
                              FILE *ecm = fopen( "errcomask.txt", "w+" );
                              fclose( ecm );
                        }

                        /* wait for the communications event */
                        if( !WaitCommEvent( Comm.hFile,       // handle of communications device
                                                       &dwEvtMask,  // address of variable for event that occurred
                                                      &Comm.o  // address of overlapped structure
 
                                                      ) )
                        {
                            /* nothing important here yet */                  
                        }
                  

                      /* Wait for a incoming data or a request for a Write data */
                      WaitForMultipleObjects( 2, HArray, FALSE, INFINITE );
                  }
      
                  /* if a request to send data */
                  if( WaitForSingleObject( Comm.Wakeup, 0 ) == WAIT_OBJECT_0 )
                              break;

              /* if the event was set by the wait-comm incoming data overlapped function */
                  if( WaitForSingleObject( Comm.o.hEvent, 0 ) == WAIT_OBJECT_0 )
                  {

                        /* see if the WaitCommEvent result was successfull, or an error occurred */
                        if( !GetOverlappedResult( Comm.hFile, &Comm.o, &pended_bytes, FALSE ) )
                        {
                                  /* report error */
                                    FILE *goot = fopen( "OverError.txt", "w+" );
                                    fclose( goot );

                        }

                        /* no solid reason for this functionallity, except to just keep track of
                         * what is happening - debug purposes */
                        if( pended_bytes > 0 )
                        {
                                  char bffs[20];
                                sprintf( bffs, "pendd%ld", pended_bytes );

                                    /* debug - report */
                                FILE *pbt = fopen( bffs, "w+" );
                                    fclose( pbt );
                        }

                        /* reset the WaitCommEvent event */
                        ResetEvent( Comm.o.hEvent );
                                                
                  }


                  /* set this so that the next pass post a new WaitCommEvent function */
                  dowait = 1;

                /* This loop will loop until no more bytes are left in the buffer.
                   * It will also direct the incomming data appropriately */
                  while( 1 )
                  {

                        /* Fetch one byte from the buffer */
                        if( !(bresult = ReadFile(
                           Comm.hFile,      // handle of file to read
                           buf,              // address of buffer that receives data  
                           1,              // number of bytes to read
                           &bytes_read,      // address of number of bytes read
                           &Comm.o           // address of structure for data
                           )) )  {
 

                              /* if in overlapped mode, then report an error.
                               * This should never happen because the comm timeout is 0 */
                              if(  (bresult = GetLastError()) == ERROR_IO_PENDING )
                              {
                                 /* wait a while for it to expire - although this should not happen
                                  * it could momentarily */
                                 if( WaitForSingleObject( Comm.o.hEvent, 1000 ) == WAIT_OBJECT_0 )
                                 {
                                       /* report what happened - debug reasons */
                                       FILE *wto = fopen( "waitout.txt", "w+" );
                                       fclose( wto );
                                 }
                                 else  {
                                    
                                       /* report error - overlapped should not have taken this long */
                                       FILE *uet = fopen( "unexpected.txt", "w+" );
                                       fclose( uet );

                                       continue;
                                 }
                              }

                              /* report some other error */
                              FILE *ste = fopen( "readerr.txt", "w+" );
                              fclose( ste );


                         }      
                    

                        /* if the byte was read from the buffer */
                         if( bytes_read >= 1 )
                         {
                              

                               /* buffer limit is 200 */
                               if( bytecnt <= 200 )
                                     /* store the received bytes */
                                     memcpy( &Comm.Recv_Buf[bytecnt], buf, bytes_read );
                           
                               /* add the number to the total number of received bytes */
                               bytecnt += bytes_read;
                               /* reset short term received bytes counter */
                               bytes_read = 0;

                               /* if this is unsolicited and the minimum amount has been received */
                               if( (Comm.expected == 0) & (bytecnt >= 7) )
                               {
                                     /* report for debug reasons */
                                     FILE *ftf = fopen( "unsolicited.txt", "w+" );
                                     fclose( ftf );

                                     /* more debug stuff */
                                     char resp[20];
                                     sprintf( resp, "rp%d,%d,%d,%d,%d,%d,%d", Comm.Recv_Buf[0], Comm.Recv_Buf[1], Comm.Recv_Buf[2], Comm.Recv_Buf[3], Comm.Recv_Buf[4], Comm.Recv_Buf[5], Comm.Recv_Buf[6] );
                                     FILE *ret = fopen( resp, "w+" );
                                     fclose( ret );

                                     /* shift bytes */
                                     //if (bytecnt <= 200) bytecnt = 200;
                                     //memmove( Comm.Recv_Buf+1, Comm.Recv_Buf, bytecnt );

                                     /* store the number of bytes received */
                                     Comm.numbytes = bytecnt;

                                     /* Check for a valid unsolicited message - do any processing  */
                                     Comm.CheckResponse();
                                     bytecnt = 0;  /* reset total bytecount */

                               }
                               /* if all the bytes have been received */
                               else if( (bytecnt >= (Comm.expected-1) ) & (Comm.expected > 0) )
                               {

                                     /* report full response count */
                                     FILE *ttg = fopen( "FullResponse.txt", "w+" );
                                     fclose( ttg );

                                     
                                     //if (bytecnt >= 200)  bytecnt = 200;
                                     //memmove( Comm.Recv_Buf+1, Comm.Recv_Buf, bytecnt );

                                     /* store the number of bytes received */
                                     Comm.numbytes = bytecnt;

                                     /* let whoever know that the message is in the bag */
                                     SetEvent( Comm.rxdone );

                                     /* reset counters */
                                     bytecnt = 0;
                                     Comm.expected = 0;
                                                                        
                               }
                                

                         } /* end if bytes_read > 0 */
                         else break;

                  }   /* end of third while forever */
                           
            } /* end second while forever */

            /* report the message is going out - debug */
            FILE *ytm = fopen( "gotowrite.txt", "w+" );
            fclose( ytm );

            /* Set the Communications mask for one purpose only - To stop the current
             * pending overlapped WaitCommEvent function - it will probably clash with
             * the WriteFile when it is called */
            dwEvtMask = EV_CTS;
            if( !SetCommMask( Comm.hFile, dwEvtMask ) )
            {
                  FILE *ecm = fopen( "errcomask.txt", "w+" );
                fclose( ecm );
            }
            dwEvtMask = EV_RXCHAR;

            /* wait for the WaitCommEvent function to signal its down */
            if( WaitForSingleObject( Comm.o.hEvent, 1000 ) != WAIT_OBJECT_0 )
            {
                  /* if WaitCommEvent never signaled,  WaitCommEvent will needed to be
                   * called again when the transmit is finished.  WriteFile will probably
                   * screw up the current WaitCommEvent.
                   * - This could cause unknown effects, but if it does happen we will
                   * at least recover */
                  dowait = 0;

                  /* report error - debug */
                  FILE *ecm = fopen( "nomask.txt", "w+" );
                fclose( ecm );
            }
            /* reset the WaitCommEvent */
            else ResetEvent( Comm.o.hEvent );

            /*----------------------------------------------------------------------------
             * Below is an algorithm flow used to send packets with a maximum size of
             * 24 bytes - if the requested transmit count is greater than split it up
             *---------------------------------------------------------------------------- */
            unsigned long nbytes = Comm.numtx;
            unsigned long byteoff = 0;

            /* if packet is larger then 24 bytes */
            if( nbytes > 24 ) Comm.numtx = 24;

            /* reset the wakeup event */
            ResetEvent( Comm.Wakeup );

            /* reorder bytes appropriately */
            DoByteOrder();
            
            /* this loop transmits large messages in packets of 24 */
            while( 1 )
            {
                  /* Transmit the request to the RTU */
                  if( !WriteFile( Comm.hFile, &Comm.outMsg[byteoff], Comm.numtx, &outnum, &Comm.o ) )
                  {
                        /* if WriteFile is pending */
                        if(  (bresult = GetLastError()) == ERROR_IO_PENDING )

                                /* Wait for it to finish */
                                if( WaitForSingleObject( Comm.o.hEvent, 30000 ) == WAIT_OBJECT_0 )
                                      ResetEvent( Comm.o.hEvent );
                  }

                  /* new offset in transmit buffer */
                  byteoff += Comm.numtx;
                  /* subtract from total bytes to send */
                  nbytes -= Comm.numtx;

                  /* if we are finished */
                  if( nbytes <= 0 )
                        break;  /* exit */

                  /* if there is still more then 24 bytes to transmit */
                  if( nbytes > 24 )
                        Comm.numtx = 24;  /* only send 24 */

                  /* otherwise just send the remaining number */
                  else Comm.numtx = nbytes;

                  
            }

            /* reset number of bytes to transmit - not really needed
             * I just put it there to protect the code from unexpected results */
            Comm.numtx = 0;

            /* Because of timing the timming issue, there is no time to go wait for an incoming
             * data event (WaitCommEvent).  The first part, if not all of the message has already
             * been received into the Comm buffer */
            dowait = 0;
            

   } /* end first while forever */
                  
   

   /* let every one else know that this thread is no longer active */
   CloseHandle(Comm.hFile);
   CloseHandle(Comm.o.hEvent);
   ResetEvent( Comm.upThread );
   CloseHandle( Comm.upThread );


   _endthread();
}




you have to organize all of the timing issues in your mind
0

Featured Post

Threat Intelligence Starter Resources

Integrating threat intelligence can be challenging, and not all companies are ready. These resources can help you build awareness and prepare for defense.

Join & Write a Comment

Suggested Solutions

In this article, I'll describe -- and show pictures of -- some of the significant additions that have been made available to programmers in the MFC Feature Pack for Visual C++ 2008.  These same feature are in the MFC libraries that come with Visual …
Have you tried to learn about Unicode, UTF-8, and multibyte text encoding and all the articles are just too "academic" or too technical? This article aims to make the whole topic easy for just about anyone to understand.
This video will show you how to get GIT to work in Eclipse.   It will walk you through how to install the EGit plugin in eclipse and how to checkout an existing repository.
This video gives you a great overview about bandwidth monitoring with SNMP and WMI with our network monitoring solution PRTG Network Monitor (https://www.paessler.com/prtg). If you're looking for how to monitor bandwidth using netflow or packet s…

708 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

14 Experts available now in Live!

Get 1:1 Help Now