bugst / go-serial

A cross-platform serial library for go-lang.
BSD 3-Clause "New" or "Revised" License
622 stars 191 forks source link

Windows port.Read() returns wrong count of readed bytes in OVERLAPPED mode #17

Closed albenik closed 7 years ago

albenik commented 7 years ago

See: https://msdn.microsoft.com/ru-ru/library/windows/desktop/aa365467(v=vs.85).aspx

lpNumberOfBytesRead [out, optional] A pointer to the variable that receives the number of bytes read when using a synchronous hFile parameter. ReadFile sets this value to zero before doing any work or error checking. Use NULL for this parameter if this is an asynchronous operation to avoid potentially erroneous results. This parameter can be NULL only when the lpOverlapped parameter is not NULL. For more information, see the Remarks section.

I my case alwaysn=1 so, all checks on this value now broken.

cmaglie commented 7 years ago

Can you post a test program that shows the error?

albenik commented 7 years ago

A little bit later. I have not time now to prepare working test.

cmaglie commented 7 years ago

The documentation is not really clear, in the "Remarks" sections it says:

The lpNumberOfBytesRead parameter should be set to NULL. Use the GetOverlappedResult function to get the actual number of bytes read. If the hFile parameter is associated with an I/O completion port, you can also get the number of bytes read by calling the GetQueuedCompletionStatus function.

The use of word "should" instead of "must" makes me think that setting the parameter to NULL is not the only option available, in fact, I've based my code on the following document:

https://msdn.microsoft.com/en-us/library/ff802693.aspx

That explicitly states:

The I/O operation may or may not be completed immediately. It is an error for an application to assume that a request for an overlapped operation always yields an overlapped operation. If an operation is completed immediately, an application needs to be ready to continue processing normally. The second part of an overlapped operation is to detect its completion. Detecting completion of the operation involves waiting for the event handle, checking the overlapped result, and then handling the data.

and finally if you look at the example:

DWORD dwRead;
BOOL fWaitingOnRead = FALSE;
OVERLAPPED osReader = {0};

// Create the overlapped event. Must be closed before exiting
// to avoid a handle leak.
osReader.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);

if (osReader.hEvent == NULL)
   // Error creating overlapped event; abort.

if (!fWaitingOnRead) {
   // Issue read operation.
   if (!ReadFile(hComm, lpBuf, READ_BUF_SIZE, &dwRead, &osReader)) {  <----
      if (GetLastError() != ERROR_IO_PENDING)     // read not delayed?
         // Error in communications; report it.
      else
         fWaitingOnRead = TRUE;
   }
   else {    
      // read completed immediately
      HandleASuccessfulRead(lpBuf, dwRead);  <----
    }
}

it actually use the parameter &dwRead to get the number of bytes read when the ReadFile function completes the operation immediately.

albenik commented 7 years ago

My mistake, sorry! There is no problem with software. Just with hardware and my hands. The problem was that my device transmits one byte STX and then a little bit after body. So Read returns me exactly one byte even I reserved larger buffer.

cmaglie commented 7 years ago

oh, great that you figured out! The new MSDN docs about Overlapped IO are not clear and really needs a proof-reading.