locked
windows communication RRS feed

  • Question

  • hi there,

    I'm trying to understand this article: http://www.codeproject.com/KB/system/serial_com.aspx

    I don't exactly get how to be notified that some data is ready to be read (I'd like to use readAvailable()).

    I know I must use m_theCommPort.GetWaitForEvent() but then what ?

    Thanks

    Wednesday, May 25, 2011 9:15 AM

Answers

  • The windows application programming interface provide synchronization mechanism for  change the state explicitly using Event objects.  This article uses CreateEvent in init function and set/reset the events using CSerialCommHelper ::SetDataReadEvent()  function.

     

    You can check with the following MSDN sample for understand about Event object.

    http://msdn.microsoft.com/en-us/library/ms686915%28VS.85%29.aspx

     

    Note: This sample uses threading and Event for synchronization.


    Thanks and Regards Selvam http://www15.brinkster.com/selvamselvam/
    • Marked as answer by Eric Battalio Monday, October 1, 2012 5:33 PM
    Wednesday, May 25, 2011 9:30 AM
  • From the main thread you use PostThreadMessage when you want a serial thread to do something, like open the port or write to the port.  Pass a pointer to heap data to be sent, every time you want to output to the port. We covered this in your other question.  The thread message handler function calls a CSerialPort function to write.

    To receive data you probably should use another thread.  Put a loop in it that calls ReadFile and sends any received data to the main thead (PostMessage to a window in the main thead.)  Then loops around to try and read more.

     

    • Marked as answer by BobbyQ Monday, May 30, 2011 12:25 PM
    Friday, May 27, 2011 4:33 AM
  • Yes, I use the term heap data to emphasize that a pointer passed to another thread should be a pointer to something allocated in the heap with "new" to be sure no synchronization is needed.

    Using ReadFile in an infinite loop does not waste time.  ReadData efficiently suspends the calling thread until the operation completes.  That's the same thing that WaitCommEvent does, so using WaitCommEvent is redundant if all you need to wait for is data.

    Unfortunately, the Naughter code does not use multithreading. So it is a nice MFC example of how to use the serial port functions but it does not show how to integrate it with a GUI. The MSDN code does use multithreading and integrate with a GUI. So you need a bit of each.

    You can only open the port in one place at a time so the the handle must be shared. The thread that opens the port can use operator HANDLE to get the open handle. Then that handle must be sent to another thread and used with the Attach function to give the handle to a second instance of the CSerialPort.  (And to read and write concurrently you need two instances because they each must have their own m_hEvent.)

     

    • Marked as answer by BobbyQ Monday, May 30, 2011 12:25 PM
    Friday, May 27, 2011 2:07 PM
  • The code to transfer the hPort looks fine.

    If you want the thread function to be part of a class you must declare the function as static.

    class CSendingThread
    {
    public:
    static UINT ThreadFunc(LPVOID pParam);
    UINT NonstaticThreadFunc();
    };

    Now a static function cannot access nonstatic class members so to work around this pass the 'this' pointer as the pParam:

    void CSendingThread::StartThread()
    {

    AfxBeginThread(ThreadFunc, this);

    }

    UINT CSendingThread::ThreadFunc(LPVOID pParam)
    {  CSendingThread* pthis = (CSendingThread*) pParam;
        return pthis->NonstaticThreadFunc();
    }

    UINT CSendingThread::NonstaticThreadFunc()
    {
      ... in here it can access ordinary member variables and functions.

    }

    • Marked as answer by BobbyQ Monday, May 30, 2011 12:25 PM
    Saturday, May 28, 2011 1:36 PM
  • The most efficient way to synchronize access to data shared between threads is to call InitializeCriticalSection on a global CRITICAL_SECTION object during program initialization. Then all threads that access the shared data must do

    EnterCriticalSection(&cs);
    ... access the shared data here
    LeaveCriticalSection(&cs);

    Buffering the received data and parsing it will take almost no time compared to the serial port I/O operation.  I would just put that code inside the loop that calls ReadFile.  The serial driver is still receiving and accumulating incoming bytes while you do your buffering and parsing.

     

     

    • Marked as answer by BobbyQ Monday, May 30, 2011 12:25 PM
    Saturday, May 28, 2011 9:08 PM
  • The GUI thread does nothing (it is suspended) except when messages arrive in its message queue. So your only choices are to PostMessage from the secondary thread when you want to update with new data, or to use SetTimer in the GUI thread and process the WM_TIMER message.
    • Marked as answer by BobbyQ Monday, May 30, 2011 12:26 PM
    Sunday, May 29, 2011 2:10 PM

All replies

  • The windows application programming interface provide synchronization mechanism for  change the state explicitly using Event objects.  This article uses CreateEvent in init function and set/reset the events using CSerialCommHelper ::SetDataReadEvent()  function.

     

    You can check with the following MSDN sample for understand about Event object.

    http://msdn.microsoft.com/en-us/library/ms686915%28VS.85%29.aspx

     

    Note: This sample uses threading and Event for synchronization.


    Thanks and Regards Selvam http://www15.brinkster.com/selvamselvam/
    • Marked as answer by Eric Battalio Monday, October 1, 2012 5:33 PM
    Wednesday, May 25, 2011 9:30 AM
  • So in practical terms, after having the init function (which uses createEvent), I must use m_theCommPort.GetWaitForEvent(), and then use SetDataReadEvent? I don't really understand how this works together. Can you be a little bit more explicit please ?

    Thanks
    Wednesday, May 25, 2011 9:45 AM
  • I think, if you start with MSDN example, will help you understand better.

    I haven't go though full code in  that article. But, the following code create event.

    m_hDataRx = CreateEvent(0,0,0,0);
    
    m_hDataRx = CreateEvent(NULL, // LPSECURITY_ATTRIBUTES - default security
       FALSE, // auto-reset event object, and system automatically resets the event state to nonsignaled after a single waiting thread has been released
       FALSE, // nonsignaled state
       FALSE); // created without a name
    
    

    The SetDataReadEvent function uses m_hDataRx for make specified event object to the signaled state.  This function called from CSerialCommHelper::ThreadFn for set signaled state. It uses many Events( m_hThreadTerm = CreateEvent(0,0,0,0); and m_hThreadStarted = CreateEvent(0,0,0,0);) for single the thread start and termination.

     

    The SetEvent and ResetEvent Functions uses for sets the specified event object to the signaled state and nonsignaled state

     


    Thanks and Regards Selvam http://www15.brinkster.com/selvamselvam/
    Wednesday, May 25, 2011 10:07 AM
  • I'm sorry but I'm lost.
    From what I understand, Windows can inform me when some data (a byte or more) has arrived, so that I can read it.
    For windows to tell me that, I have to use m_theCommPort.GetWaitForEvent().

    But then there must be a callback function of some kind to tell the program what to do when the event is sent, right ?

    I don't really understand the series of commands I have to issue in order to

    1. set a notification when a byte has arrived

    2. Read the byte when the notification has been received.


    Thanks


    • Edited by BobbyQ Wednesday, May 25, 2011 11:57 PM
    Wednesday, May 25, 2011 10:51 AM
  • I think the answer to "1." is m_theCommPort.GetWaitForEvent() and part of the answer to 2. is readAvailable() but I'm not sure.

    Can you help me please ?


    Thanks

    Wednesday, May 25, 2011 11:57 PM
  •  m_theCommPort.GetWaitForEvent() used for notification for data available. This event is an auto reset evenet. So, system automatically resets the event state to nonsignaled.

     


    Thanks and Regards Selvam http://www15.brinkster.com/selvamselvam/
    Thursday, May 26, 2011 5:26 AM
  • But where is the code that is executed when the notification comes ??
    Thursday, May 26, 2011 10:14 AM
  • I'm sorry to insist but I still don't understand how to do that.
    Thursday, May 26, 2011 2:09 PM
  • I'm sorry but I feel like you're not answering my question, but it's probably just because I don't really understand what's going on.

    What I'd like to do is to make some action when a byte arrives, using the classes that were in the link above. I still don't know the whole procedure to achieve that.

    Could you explain the whole procedure to me step by step, I think I'm missing something. In particular, I don't understand where to add the code I'd like to execute when it arrives.

    Maybe someone else could try to explain that ?

    Thanks a lot.

    Thursday, May 26, 2011 3:50 PM
  • I'm sorry but I feel like you're not answering my question, but it's probably just because I don't really understand what's going on.
     
    What I'd like to do is to make some action when a byte arrives, using the classes that were in the link above. I still don't know the whole procedure to achieve that.
     
    Could you explain the whole procedure to me step by step, I think I'm missing something. In particular, I don't understand where to add the code I'd like to execute when it arrives.
     
    Maybe someone else could try to explain that ?
    The problem is that you are asking very general questions, and not giving a very clear idea of what you are trying to do.
     
    Foorums are not the place for tutorials. You need a web site or book for that.
     

    David Wilkinson | Visual C++ MVP
    Thursday, May 26, 2011 3:57 PM
  • I don't think it's a very general question, it's on the contrary very specific: I'd like to know what changes to make to the code so that I can execute a specific function when a byte arrives to the port. I don't think it's too vague.
    I sincerely apologize though if I didn't explain myself clearly about what I mean to do. I didn't want to bore you with all the details either. Feel free to ask if you need any more details.


    What I'm trying to do is a serial communication. I chose the code in the link above because it is well explained and seems to do what I want. What I need to do is to regularly send and receive data through that communication. For that, I need a thread for sending and another one for receiving. The sending part must be regular (timer), whilst the receiving data is dealt as soon it arrives. My question in this thread regards the receiving part. I'd like to make an action (the data received is an update about the state of a tool, so the action I need to do is to update a structure or a class that contains the information related to that tool) when that byte arrives.

    So my question is, how can I execute a specific function when a byte arrives to the com port.


    Maybe you understand my question better now. I hope you'll be able to help me.

    Thanks


    Thursday, May 26, 2011 4:07 PM
  • I took a look at the code in the referenced codeproject article. You're asking questions about code that I doubt anybody here has used, and it is flawed code. Its biggest problem is the premise that it makes any sense to call the serial port asking for only one byte. The serial port Windows driver has a buffer, and the proper way to use it is to take all the data it will give you.  A second problem with the approach is the premise that you have to wait for the EV_RXCHAR event before calling ReadFile. Both of these design problems result in very inefficient code, and possibly loss of data due to the slowness.

    ReadFile is designed to wait for the data, or a read timeout.  Or if you are using overlapped operation you wait for the result with GetOverlappedResult.  So you typically would just call ReadFile with a roomy buffer. When the operation completes you do something with all the data you received.  (Typically, post it to the main thread using PostMessage.)

    This article is the essential seminal reference to how to do it:

    http://msdn.microsoft.com/en-us/library/ms810467.aspx

    This widely used CSerialPort class by Naughter is a modernized MFC version:

    http://www.naughter.com/serialport.html

    Forget about EV_RXCHAR and let ReadFile do all the work. If you need concurrent reading and writing you must use overlapped I/O. And if you are writing a GUI you must use multithreading because the ReadFile operation is blocking.

     

     

    Thursday, May 26, 2011 11:36 PM
  • hello, thanks for answering.

    I liked the way the link explained it step by step, as opposed to naughter where it seems harder to understand. But okay I'll use this one since you think it's better, and in case you think it answers to the architecture I'm trying to create (the one described in my previous message, in the second paragraph). I have no idea though how to incorporate that naughter project into my own code. For example, what files do I need to copy to my own project ?

    thanks

    Friday, May 27, 2011 1:37 AM
  • That's an easy one. The Naughter code you need is in SerialPort.h and SerialPort.cpp. 

    I would use it by putting a CSerialPort member in a thread class.

    Friday, May 27, 2011 3:27 AM
  • Okay :).
    How do I use it though if I want to send or receive data ?
    Friday, May 27, 2011 4:06 AM
  • From the main thread you use PostThreadMessage when you want a serial thread to do something, like open the port or write to the port.  Pass a pointer to heap data to be sent, every time you want to output to the port. We covered this in your other question.  The thread message handler function calls a CSerialPort function to write.

    To receive data you probably should use another thread.  Put a loop in it that calls ReadFile and sends any received data to the main thead (PostMessage to a window in the main thead.)  Then loops around to try and read more.

     

    • Marked as answer by BobbyQ Monday, May 30, 2011 12:25 PM
    Friday, May 27, 2011 4:33 AM
  • By heap data you just mean a regular pointer to a class instance that has been created using "new", right ?

    The thing I don't understand is that you seem to think that this naughter approach is better than the link above, but from my newbie point of view it's the opposite: isn't it better to have a notification when data is available, rather than continuously waste time to see if there is data available in an infinite loop ?

    Also, which function should I use to modify the default properties of the serial communication ? (such as the baud rate, the parity bit, etc.)

    Friday, May 27, 2011 5:19 AM
  • I found out that there is a documentation attached, so that answers the last question of my previous post. But I have a new question, how can I use the communication that was opened in the main thread from another thread ? Should I use the function CSerialPort::operator HANDLE ? If so, how to use it ?

    Or maybe I should just pass a pointer to the SerialPort instance ? This object won't be deleted once the end of the block who created is reached, will it ?

    Thanks.

    Friday, May 27, 2011 11:32 AM
  • Yes, I use the term heap data to emphasize that a pointer passed to another thread should be a pointer to something allocated in the heap with "new" to be sure no synchronization is needed.

    Using ReadFile in an infinite loop does not waste time.  ReadData efficiently suspends the calling thread until the operation completes.  That's the same thing that WaitCommEvent does, so using WaitCommEvent is redundant if all you need to wait for is data.

    Unfortunately, the Naughter code does not use multithreading. So it is a nice MFC example of how to use the serial port functions but it does not show how to integrate it with a GUI. The MSDN code does use multithreading and integrate with a GUI. So you need a bit of each.

    You can only open the port in one place at a time so the the handle must be shared. The thread that opens the port can use operator HANDLE to get the open handle. Then that handle must be sent to another thread and used with the Attach function to give the handle to a second instance of the CSerialPort.  (And to read and write concurrently you need two instances because they each must have their own m_hEvent.)

     

    • Marked as answer by BobbyQ Monday, May 30, 2011 12:25 PM
    Friday, May 27, 2011 2:07 PM
  • ok,thanks.
    What's the syntax to use the operator HANDLE?

    Should I use this syntax to pass the handle to the sending thread ?

        HANDLE hPort = HANDLE(m_SerialPort);
        m_pSendingThread->PostThreadMessage(UWM_SERIALPORT, (WPARAM) hPort, 0);

    and then in the SendingThread class:

    ON_THREAD_MESSAGE(UWM_SERIALPORT, OnPortInit)

    void CSendingThread::OnPortInit (WPARAM wparam, LPARAM lparam){
        HANDLE hPort = (HANDLE) wparam;
        m_SerialPort = new CSerialPort();
        m_SerialPort->Attach(hPort);
    }

     

     

    I'm also having trouble with the way to create a receiving thread:

    In order to compartmentalize the code, I think it's better to create a class that handles the receiving part.
    I'd like to use a worker thread this time.
    I'm really confused because I feel like the "controlling function" can't be part of a class. Is that correct ? It's part of what then ? (is it a global function, available from anywhere in the code, as opposed to only in that file?)
    Thanks



    Saturday, May 28, 2011 6:44 AM
  • The code to transfer the hPort looks fine.

    If you want the thread function to be part of a class you must declare the function as static.

    class CSendingThread
    {
    public:
    static UINT ThreadFunc(LPVOID pParam);
    UINT NonstaticThreadFunc();
    };

    Now a static function cannot access nonstatic class members so to work around this pass the 'this' pointer as the pParam:

    void CSendingThread::StartThread()
    {

    AfxBeginThread(ThreadFunc, this);

    }

    UINT CSendingThread::ThreadFunc(LPVOID pParam)
    {  CSendingThread* pthis = (CSendingThread*) pParam;
        return pthis->NonstaticThreadFunc();
    }

    UINT CSendingThread::NonstaticThreadFunc()
    {
      ... in here it can access ordinary member variables and functions.

    }

    • Marked as answer by BobbyQ Monday, May 30, 2011 12:25 PM
    Saturday, May 28, 2011 1:36 PM
  • ok, thanks.
    I now want to implement the receiving thread, which uses ReadFile in an infinite loop, analyzes the byte stream and decomposes it into packets of a known protocol, extracts the information from the packet, and sends the result to the main thread, by updating a structure of the main thread.

    In order to learn something different, I'd like to use thread safety mechanisms to update the structure of the main thread, rather than sending the updated information through a postMessage, just like I did for sending the handle to the sending thread.

    So, if you think it's not too bad for the application to use thread safety mechanisms rather than posting messages, and if it's just a matter of preferences for the developer, then how exactly can I do that ?

     

    And as far as the parsing of the byte stream is concerned, I think what I should do is add the buffer read by ReadData to a byte queue, and have another thread check on that queue to parse a full packet (the packet is not of fixed size, but the first byte indicates the packet length, so this fourth thread (1 main, 1 for sending, 1 for receiving, and this one for checking the queue) can gather the bytes accumulated when there are enough of them to constitute a packet. Don't you think that's the best way ?

    If you think it is, then how can I efficiently check that queue ? As far as the receiving was concerned, you said that ReadFile was blocking, so there was no performance loss by making an infinite loop. Is there a similar mechanism to check the queue for new elements added to it ?

    Thanks

     


    Saturday, May 28, 2011 3:53 PM
  • The most efficient way to synchronize access to data shared between threads is to call InitializeCriticalSection on a global CRITICAL_SECTION object during program initialization. Then all threads that access the shared data must do

    EnterCriticalSection(&cs);
    ... access the shared data here
    LeaveCriticalSection(&cs);

    Buffering the received data and parsing it will take almost no time compared to the serial port I/O operation.  I would just put that code inside the loop that calls ReadFile.  The serial driver is still receiving and accumulating incoming bytes while you do your buffering and parsing.

     

     

    • Marked as answer by BobbyQ Monday, May 30, 2011 12:25 PM
    Saturday, May 28, 2011 9:08 PM
  • Thank you.

    How can I call InitializeCriticalSection on a global CRITICAL_SECTION object during program initialization ?

    I was also wondering how I could update the Gui after I've updated the structure from the worker thread. Can it be refreshed regularly ? If the only solution is to send a message to the gui message map, saying the structure has been updated, then I might as well send the structure itself instead, and there would be no need for the critical sections... but I can use a timer that regularly does update(false), or maybe there's a better way ?
    Sunday, May 29, 2011 7:56 AM
  • The GUI thread does nothing (it is suspended) except when messages arrive in its message queue. So your only choices are to PostMessage from the secondary thread when you want to update with new data, or to use SetTimer in the GUI thread and process the WM_TIMER message.
    • Marked as answer by BobbyQ Monday, May 30, 2011 12:26 PM
    Sunday, May 29, 2011 2:10 PM
  • okay, I'll use the postMessage then. Thanks for your advice.

    Sunday, May 29, 2011 3:35 PM