Solved

Serial Port Communication in Win32

Posted on 2002-07-18
7
1,094 Views
Last Modified: 2013-11-15
Hi,
I am not able to read write binary data on port.same code can read write text file.I am using Event thread when i am writing binary file on port and try to read it from port event is not trigger .What is problem?
0
Comment
Question by:dhirajbhise
  • 3
  • 3
7 Comments
 
LVL 32

Expert Comment

by:jhance
Comment Utility
The biggest problem at this point is your question.

You've said little more than you are having a problem with binary data on a serial port.  While I suppose it's possible that whatever system or operating system you are using cannot read binary data from a serial port, I think that someone would have noticed that in the past.

So we can discount that as a possibility.  That leaves us with YOUR code and the mistakes you are making.

Based on what you've said, the best I can do is:

"Fix whatever errors you are making and it will work."
0
 
LVL 1

Accepted Solution

by:
ris earned 50 total points
Comment Utility
well, I can tell from your question that you are waiting on some event that is triggered when you receive text data but not when you receive binary data.  It could be that a different event is triggered for binary data and you are not waiting on this event.  You should look into this aspect of the problem.  Without more details, I can't offer more advice at this time.

I think you will find that when asking questions on a bulletin board like this that you get much much much better results if you provide details.  The more details the better, and you can't provide too much information.
0
 

Author Comment

by:dhirajbhise
Comment Utility
HI,

I read your answer the problem is there are follwing event

EV_BREAK  => A break was detected on input.
 
EV_CTS    => The CTS (clear-to-send) signal changed state.
 
EV_DSR    => The DSR (data-set-ready) signal changed state.
 
EV_ERR    =>  A line-status error occurred. Line-status     errors are CE_FRAME, CE_OVERRUN, and CE_RXPARITY.
 
EV_RING   =>   A ring indicator was detected.
 
EV_RLSD   =>    The RLSD (receive-line-signal-detect) signal changed state.
 
EV_RXCHAR =>  A character was received and placed in the input buffer.
 
EV_RXFLAG =>  The event character was received and placed in the input buffer. The event character is specified in the device's DCB structure, which is applied to a serial port by using the SetCommState function.
 
EV_TXEMPTY => The last character in the output buffer was sent.

I have tried with three event but i am not able find out the event at which I will receive  binary data.I am not able to find out.I am using Win98 o/s.
0
Highfive Gives IT Their Time Back

Highfive is so simple that setting up every meeting room takes just minutes and every employee will be able to start or join a call from any room with ease. Never be called into a meeting just to get it started again. This is how video conferencing should work!

 

Author Comment

by:dhirajbhise
Comment Utility
I will giving Code With try to debug it and let me know

I have
CSerialPort.cpp
CSerialPort.h

/*
**      FILENAME                  CSerialPort.cpp
**
**      PURPOSE                        This class can read, write and watch one serial port.
**                                    It sends messages to its owner when something happends on the port
**                                    The class creates a thread for reading and writing so the main
**                                    program is not blocked.
*/
 
#include "stdafx.h"
#include "SerialPort.h"
#include "SerialCommunication.h"
#include "SerialCommunicationDoc.h"
#include "SerialCommunicationView.h"
#include "MainFrm.h"

#include <assert.h>

extern char *pRead;

//
// Constructor
//
CSerialPort::CSerialPort()
{
      m_hComm = NULL;
      // initialize overlapped structure members to zero
      m_ov.Offset = 0;
      m_ov.OffsetHigh = 0;
      // create events
      m_ov.hEvent = NULL;
      m_hWriteEvent = NULL;
      m_hShutdownEvent = NULL;
      m_szWriteBuffer = NULL;
      m_bThreadAlive = FALSE;
}

//
// Delete dynamic memory
//
CSerialPort::~CSerialPort()
{
      do
      {
            SetEvent(m_hShutdownEvent);
      } while (m_bThreadAlive);

      TRACE("Thread ended\n");
      CloseHandle(m_hComm);
      AfxMessageBox("OUT OF PORT-1");
      delete [] m_szWriteBuffer;
}


//
//InitPort
//
BOOL CSerialPort::InitPort(CWnd* pPortOwner)      
{
      UINT  portnr=1;
      UINT  baud=      115000;
      char  parity='N';
      UINT  databits=8;
      UINT  stopbits=1;
      DWORD dwCommEvents=EV_RXCHAR | EV_CTS | EV_BREAK;
      UINT  writebuffersize=2048;

      assert(pPortOwner != NULL);
      // if the thread is alive: Kill
      if (m_bThreadAlive)
      {
            do
            {
                  SetEvent(m_hShutdownEvent);
            } while (m_bThreadAlive);
            TRACE("Thread ended\n");
      }

      // create events
      if (m_ov.hEvent != NULL)
            ResetEvent(m_ov.hEvent);
      m_ov.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);

      if (m_hWriteEvent != NULL)
            ResetEvent(m_hWriteEvent);
      m_hWriteEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
      
      if (m_hShutdownEvent != NULL)
            ResetEvent(m_hShutdownEvent);
      m_hShutdownEvent = CreateEvent(NULL, TRUE, FALSE, NULL);

      // initialize the event objects
      m_hEventArray[0] = m_hShutdownEvent;      // highest priority
      m_hEventArray[1] = m_ov.hEvent;
      m_hEventArray[2] = m_hWriteEvent;

      // initialize critical section
      InitializeCriticalSection(&m_csCommunicationSync);
      
      // set buffersize for writing and save the owner
      m_pOwner = pPortOwner;
      
      m_nPortNr = portnr;

      m_nWriteBufferSize = writebuffersize;
      m_dwCommEvents = dwCommEvents;

      BOOL bResult = FALSE;
      char *szPort = new char[50];
      char *szBaud = new char[50];

      // now it critical!
      EnterCriticalSection(&m_csCommunicationSync);

      // if the port is already opened: close it
      if (m_hComm != NULL)
      {
            CloseHandle(m_hComm);
            m_hComm = NULL;
      }

      // prepare port strings
      szPort="COM1";
      
      sprintf(szBaud, "baud=%d parity=%c data=%d stop=%d", baud, parity, databits, stopbits);
      // get a handle to the port
      m_hComm = CreateFile(szPort,                                    // communication port string (COMX)
                                   GENERIC_READ | GENERIC_WRITE,      // read/write types
                                   0,                                                // comm devices must be opened with exclusive access
                                   NULL,                                          // no security attributes
                                   OPEN_EXISTING,                              // comm devices must use OPEN_EXISTING
                                   FILE_FLAG_OVERLAPPED|FILE_FLAG_NO_BUFFERING,                  // Async I/O
                                   0);                                          // template must be 0 for comm devices
      // set the timeout values
m_CommTimeouts.ReadIntervalTimeout = MAXDWORD;            
m_CommTimeouts.ReadTotalTimeoutMultiplier = MAXDWORD;
m_CommTimeouts.ReadTotalTimeoutConstant=1000; m_CommTimeouts.WriteTotalTimeoutMultiplier=1000;
m_CommTimeouts.WriteTotalTimeoutConstant = 1000;

      if (SetCommTimeouts(m_hComm, &m_CommTimeouts))
      {                                      
            if (SetCommMask(m_hComm, dwCommEvents))
            {
                  if (GetCommState(m_hComm, &m_dcb))
                  {
                        m_dcb.fRtsControl = RTS_CONTROL_ENABLE;            // set RTS bit high!
                        if (BuildCommDCB(szBaud, &m_dcb))
                        {
                              if (SetCommState(m_hComm, &m_dcb))
                                    ; // normal operation... continue
                              else
                                    ProcessErrorMessage("SetCommState()");
                        }
                        else
                              ProcessErrorMessage("BuildCommDCB()");
                  }
                  else
                        ProcessErrorMessage("GetCommState()");
            }
            else
                  ProcessErrorMessage("SetCommMask()");
      }
      else
            ProcessErrorMessage("SetCommTimeouts()");

      // flush the port
      PurgeComm(m_hComm, PURGE_RXCLEAR | PURGE_TXCLEAR | PURGE_RXABORT | PURGE_TXABORT);

      // release critical section
      LeaveCriticalSection(&m_csCommunicationSync);

      TRACE("Initialisation for communicationport %d completed.\nUse Startmonitor to communicate.\n", portnr);
      
      return TRUE;
}

//
//  The CommThread Function.
//
UINT CSerialPort::CommThread(LPVOID pParam)
{
      // Cast the void pointer passed to the thread back to
      // a pointer of CSerialPort class
      CSerialPort *port = (CSerialPort*)pParam;
      
      // Set the status variable in the dialog class to
      // TRUE to indicate the0 thread is running.
      port->m_bThreadAlive = TRUE;      
            
      // Misc. variables
      DWORD BytesTransfered = 0;
      DWORD Event = 0;
      DWORD CommEvent = 0;
      DWORD dwError = 0;
      COMSTAT comstat;
      BOOL  bResult = TRUE;
      // Clear comm buffers at startup
      if (port->m_hComm)            // check if the port is opened
            PurgeComm(port->m_hComm, PURGE_RXCLEAR | PURGE_TXCLEAR | PURGE_RXABORT | PURGE_TXABORT);
      
      // begin forever loop.  This loop will run as long as the thread is alive.
      /***************************************************************************/
      //Dated 08/07/2002      
      //Right now FOR LOOP is ok.but Later we will have to change the Loop.
      /***************************************************************************/
      //
      for (;;)
      {
            bResult = WaitCommEvent(port->m_hComm, &Event, &port->m_ov);
            
            if (!bResult)  
            {
                  // If WaitCommEvent() returns FALSE, process the last error to determin
                  // the reason..
                  switch (dwError = GetLastError())
                  {
                  case ERROR_IO_PENDING:       
                        {
                              // This is a normal return value if there are no bytes
                              // to read at the port.
                              // Do nothing and continue
                              break;
                        }
                  default:
                        {
                              // All other error codes indicate a serious error has
                              // occured.  Process this error.
                              port->ProcessErrorMessage("WaitCommEvent()");
                              break;
                        }
                  }
            }
            else
            {
                  // If WaitCommEvent() returns TRUE, check to be sure there are
                  // actually bytes in the buffer to read.  
                  //
                  // If you are reading more than one byte at a time from the buffer
                  // (which this program does not do) you will have the situation occur
                  // where the first byte to arrive will cause the WaitForMultipleObjects()
                  // function to stop waiting.  The WaitForMultipleObjects() function
                  // resets the event handle in m_OverlappedStruct.hEvent to the non-signelead state
                  // as it returns.  
                  //
                  // If in the time between the reset of this event and the call to
                  // ReadFile() more bytes arrive, the m_OverlappedStruct.hEvent handle will be set again
                  // to the signeled state. When the call to ReadFile() occurs, it will
                  // read all of the bytes from the buffer, and the program will
                  // loop back around to WaitCommEvent().
                  //
                  // At this point you will be in the situation where m_OverlappedStruct.hEvent is set,
                  // but there are no bytes available to read.  If you proceed and call
                  // ReadFile(), it will return immediatly due to the async port setup, but
                  // GetOverlappedResults() will not return until the next character arrives.
                  //
                  // It is not desirable for the GetOverlappedResults() function to be in
                  // this state.  The thread shutdown event (event 0) and the WriteFile()
                  // event (Event2) will not work if the thread is blocked by GetOverlappedResults().
                  //
                  // The solution to this is to check the buffer with a call to ClearCommError().
                  // This call will reset the event handle, and if there are no bytes to read
                  // we can loop back through WaitCommEvent() again, then proceed.
                  // If there are really bytes to read, do nothing and proceed.
            
                  bResult = ClearCommError(port->m_hComm, &dwError, &comstat);
                  
                  if (comstat.cbInQue == 0)
                        continue;
            }      // end if bResult

            // Main wait function.  This function will normally block the thread
            // until one of nine events occur that require action.
            //**********************************************************************************************//
            //Dated : 08/07/2002
            //Check the Event on the WaitCommEvents      
            //
            //**********************************************************************************************//
            Event = WaitForMultipleObjects(3, port->m_hEventArray, FALSE, INFINITE);
            switch (Event)
            {
            case 0:
                  {
                        // Shutdown event.  This is event zero so it will be
                        // the higest priority and be serviced first.

                         port->m_bThreadAlive = FALSE;      // Kill this thread.  break is not needed, but makes me feel better.
                        AfxEndThread(100);
                        break;
                  }
            case 1:      // read event
                  {
                        GetCommMask(port->m_hComm, &CommEvent);
                        if (CommEvent & EV_CTS)
                              ::SendMessage(port->m_pOwner->m_hWnd, WM_COMM_CTS_DETECTED, (WPARAM) 0, (LPARAM) port->m_nPortNr);
                        if (CommEvent & EV_RXFLAG)
                              ::SendMessage(port->m_pOwner->m_hWnd, WM_COMM_RXFLAG_DETECTED, (WPARAM) 0, (LPARAM) port->m_nPortNr);
                        if (CommEvent & EV_BREAK)
                              ::SendMessage(port->m_pOwner->m_hWnd, WM_COMM_BREAK_DETECTED, (WPARAM) 0, (LPARAM) port->m_nPortNr);
                        if (CommEvent & EV_ERR)
                              ::SendMessage(port->m_pOwner->m_hWnd, WM_COMM_ERR_DETECTED, (WPARAM) 0, (LPARAM) port->m_nPortNr);
                        if (CommEvent & EV_RING)
                              ::SendMessage(port->m_pOwner->m_hWnd, WM_COMM_RING_DETECTED, (WPARAM) 0, (LPARAM) port->m_nPortNr);
                        if (CommEvent & EV_RXCHAR)
                        {
                              // Receive character event from port.
                              ReceiveChar(port, comstat);      
                        }
                        break;
                  }  
            case 2: // write event
                  {
                        // Write character event from port
                        WriteChar(port);
                        break;
                  }

            } // end switch

      } // close forever loop
      return 0;
}

//
// start comm watching
//
BOOL CSerialPort::StartMonitoring()
{
      if (!(m_Thread = AfxBeginThread(CommThread, this)))
            return FALSE;
      TRACE("Thread started\n");
      return TRUE;
}

//
// Restart the comm thread
//
BOOL CSerialPort::RestartMonitoring()
{
      TRACE("Thread resumed\n");
      m_Thread->ResumeThread();
      return TRUE;      
}

//
// Suspend the comm thread
//
BOOL CSerialPort::StopMonitoring()
{
      TRACE("Thread suspended\n");
      m_Thread->SuspendThread();
      return TRUE;      
}

//
// If there is a error, give the right message
//
void CSerialPort::ProcessErrorMessage(char* ErrorText)
{
      char *Temp = new char[200];

      LPVOID lpMsgBuf;
      FormatMessage(
            FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
            NULL,
            GetLastError(),
            MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
            (LPTSTR) &lpMsgBuf,
            0,
            NULL
      );

      sprintf(Temp, "WARNING:  %s Failed with the following error: \n%s\nPort: %d\n", (char*)ErrorText, lpMsgBuf, m_nPortNr);
      MessageBox(NULL, Temp, "Application Error", MB_ICONSTOP);

      LocalFree(lpMsgBuf);
      delete[] Temp;
}

//
// Write a character.
//
void CSerialPort::WriteChar(CSerialPort* port)
{
      BOOL bWrite = TRUE;
      BOOL bResult = TRUE;

      DWORD BytesSent = 0;
      ResetEvent(port->m_hWriteEvent);
      // Gain ownership of the critical section
      EnterCriticalSection(&port->m_csCommunicationSync);
      if (bWrite)
      {
            // Initailize variables
            port->m_ov.Offset = 0;
            port->m_ov.OffsetHigh = 0;

            // Clear buffer
            PurgeComm(port->m_hComm, PURGE_RXCLEAR | PURGE_TXCLEAR |
                          PURGE_RXABORT | PURGE_TXABORT);

            bResult = WriteFile(port->m_hComm,                                          // Handle to COMM Port
                                          port->m_szWriteBuffer,                              // Pointer to message buffer in calling finction
                                          strlen((char*)port->m_szWriteBuffer),      // Length of message to send
                                          &BytesSent,                                                // Where to store the number of bytes sent
                                          &port->m_ov);                                          // Overlapped structure

            // deal with any error codes
            if (!bResult)  
            {
                  DWORD dwError = GetLastError();
                  switch (dwError)
                  {
                        case ERROR_IO_PENDING:
                              {
                                    // continue to GetOverlappedResults()
                                    BytesSent = 0;
                                    bWrite = FALSE;
                                    break;
                              }
                  default:
                              {
                                    // all other error codes
                                    port->ProcessErrorMessage("WriteFile()");
                              }
                  }
            }
            else
            {
                  LeaveCriticalSection(&port->m_csCommunicationSync);
            }
      } // end if(bWrite)

      if (!bWrite)
      {
            bWrite = TRUE;
      
            bResult = GetOverlappedResult(port->m_hComm,      // Handle to COMM port
                                                        &port->m_ov,            // Overlapped structure
                                                        &BytesSent,            // Stores number of bytes sent
                                                        TRUE);                   // Wait flag

            LeaveCriticalSection(&port->m_csCommunicationSync);

            // deal with the error code
            if (!bResult)  
            {
                  port->ProcessErrorMessage("GetOverlappedResults() in WriteFile()");
            }      
      } // end if (!bWrite)

      // Verify that the data size send equals what we tried to send
      if (BytesSent != strlen((char*)port->m_szWriteBuffer))
      {
            TRACE("WARNING: WriteFile() error.. Bytes Sent: %d; Message Length: %d\n", BytesSent, strlen((char*)port->m_szWriteBuffer));
      }
}

//
// Character received. Inform the owner
//
void CSerialPort::ReceiveChar(CSerialPort* port, COMSTAT comstat)
{
      BOOL  bRead;
      BOOL  bResult;
      DWORD dwError;
      DWORD BytesRead;      
      
      bResult = ClearCommError(port->m_hComm, &dwError, &comstat);
      
      BytesRead = (DWORD) comstat.cbInQue;
      char buff[3000];
      memset(buff,0,sizeof(buff));
      if(!ReadFile(port->m_hComm,      // Port handle
                  buff,                        // Pointer to data to be read
                  3000,                        // Number of bytes to read
                  &BytesRead,                  // Pointer to number of bytes
                                                // read
                  NULL                        
      ))
      {
             bRead = FALSE;
            AfxMessageBox("COM Port Read Error");
      }
      pRead= (char*)malloc (sizeof(buff));
      memset(pRead, 0, sizeof(pRead));
       strcpy(pRead,buff);
/*
      BOOL  bRead = TRUE;
      BOOL  bResult = TRUE;
      DWORD dwError = 0;
      DWORD BytesRead = 0;

      char buff[3000];
      memset(buff,0,sizeof(buff));
      if(!ReadFile(port->m_hComm,      // Port handle
                  buff,                        // Pointer to data to be read
                  3000,                        // Number of bytes to read
                  &BytesRead,                  // Pointer to number of bytes
                                                // read
                  NULL                        
      ))
      {
             bRead = FALSE;
            AfxMessageBox("COM Port Read Error");
      }
      pRead= (char*)malloc (sizeof(buff));
      memset(pRead, 0, sizeof(pRead));
       strcpy(pRead,buff);
      */
      if (!bRead)  
      {
            bRead = TRUE;
            bResult = GetOverlappedResult(port->m_hComm,      // Handle to COMM port
                                                        &port->m_ov,            // Overlapped structure
                                                        &BytesRead,            // Stores number of bytes read
                                                        TRUE);                   // Wait flag
            if (!bResult)  
            {
                  port->ProcessErrorMessage("GetOverlappedResults() in ReadFile()");
            }      
      }
      // close if (!bRead)            
      LeaveCriticalSection(&port->m_csCommunicationSync);
      // notify parent that a byte was received
      ::SendMessage((port->m_pOwner)->m_hWnd, WM_COMM_RXCHAR, (WPARAM)buff,(LPARAM) port->m_nPortNr);
}

//
// Write a string to the port
//
void CSerialPort::WriteToPort(char* string)
{            
      assert(m_hComm != 0);
      m_szWriteBuffer = new char[strlen(string)];
      memset(m_szWriteBuffer,0,strlen(m_szWriteBuffer));
      strcpy(m_szWriteBuffer, string);
      // set event for write
      SetEvent(m_hWriteEvent);
}

//
// Return the device control block
//
DCB CSerialPort::GetDCB()
{
      return m_dcb;
}

//
// Return the communication event masks
//
DWORD CSerialPort::GetCommEvents()
{
      return m_dwCommEvents;
}
//
// Return the output buffer size
//
DWORD CSerialPort::GetWriteBufferSize()
{
      return m_nWriteBufferSize;
}



0
 

Author Comment

by:dhirajbhise
Comment Utility
Let me know the problem with the code.
 
0
 
LVL 1

Expert Comment

by:ris
Comment Utility
I see one seeming insignificant problem off the bat: shouldn't it be "COM1:" instead of "COM1" in CSerialPort::InitPort()?  If it actually opens the port, then I guess it must work OK.  Or did it create you a file called "c:\COM1" or "%WorkingDirectory%\COM1"?  Since a handle to a file is the same as a handle to a device, you'd be surprised how much you can do to a file handle that you think you are really doing to a hardware device until you start noticing the weird error return values in your DeviceIoControl and Comm functions...

Also, I can't find where you ever SetEvent() on CSerialPort::m_ov.hEvent.  First, I think you should rename that variable because it is hardly a descriptive identifier.  What is that event used for?  You don't even have a comment explaining what that event is, but I assume it has something to do with receiving a read event on the serial port?  Which is the event you are having trouble detecting, right?  Perhaps a better name would be hComEvent or hReadEvent.  I don't follow how your code translates the com events for RXCHAR, etc into setting the windows OS event m_oc.hEvent.  Could you explain this and point out which functions, etc, in your code handle this aspect?  I would expect you to need an additional thread to watch got a com event and SetEvent(m_ov.hEvent) on the appropriate events, but I don't see one.

One thing you can do is when you SetCommMask, use all of the events instead of just the 4 or so that you have selected.  Or just use a bitmask of all ones, like 0xFFFFFFFF.  At least then you'll get all the events that are triggered.  You could write out a log of them, or TRACE which events you receive, to see in practicality which events you really need to watch for.

EV_RXCHAR and/or EV_DSR should be signaled whether you receive binary data or ASCII data, so if those are the events you are watching for, then you are at least on the right track.

Aside from that, you have a lot of code that you have asked us to debug without giving a very clear description of the problem.  Could you narrow down your problem by describing the code path that you see and where you think the problem occurs?  Something like "I get into CSerialPort::CommThread and where it calls Event = WaitForMultipleObjects(3, port->m_hEventArray, FALSE, INFINITE);, I never get event case 1: the read event."

Have I read your problem correctly?  I hope some of this information helps.
0
 
LVL 1

Expert Comment

by:ris
Comment Utility
I wrote:
>>>>>>>>> I see one seeming insignificant problem off the bat: shouldn't it be "COM1:" instead of "COM1"

clarification: Note the missing colon ':'
0

Featured Post

What Should I Do With This Threat Intelligence?

Are you wondering if you actually need threat intelligence? The answer is yes. We explain the basics for creating useful threat intelligence.

Join & Write a Comment

If your app took Google’s lash recently, here are the 5 most likely reasons.
In our personal lives, we have well-designed consumer apps to delight us and make even the most complex transactions simple. Many enterprise applications, however, are a bit behind the times. For an enterprise app to be successful in today's tech wo…
Using Adobe Premiere Pro, the viewer will learn how to set up a sequence with proper settings, importing pictures, rendering, and exporting the finished product.
The viewer will be introduced to the member functions push_back and pop_back of the vector class. The video will teach the difference between the two as well as how to use each one along with its functionality.

763 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

10 Experts available now in Live!

Get 1:1 Help Now