Я включил предложение использовать событие DataReceived и сделать событие кода управляемым, а не зацикленным. Я обнаружил, что виртуальный последовательный порт все еще не работает для моих 21120 байтовых сообщений за одну операцию чтения. Более короткие длины сообщения сделаны правильно. Однако, когда я установил порог получения данных последовательного порта на 21119 байт и установил буфер чтения последовательного порта в 10 раз больше размера моего сообщения, я обнаружил, что
1. Событие DataReceived будет инициировано только с 12672 доступными байтами (не 21119) и тем же числом, возвращаемым при выполнении Read () для полного размера.
2. Если число байтов не равно моему порогу, если я не выполняю чтение в это время, дальнейшее событие DataReceived не инициируется
3. Но если (и только если) я прочитал 12672 байта, другое событие DataReceived приходит вместе с оставшимися 8448 байтами.
Я не знаю, почему это так. Дальнейшие комментарии приветствуются.
Однако я подумал, что поделюсь своим текущим кодом для блага других.
Некоторые переменные класса:
Private m_SerialPort As SerialPort = Nothing
Private Debug As Int16
Private m_CommandBuffer(COMMAND_BUFFER_SIZE) As Byte
Private m_ReturnBytes(RETURN_BUFFER_SIZE) As Byte
Private m_WaitingOnBytes As Int32
Private m_VSP_Offset As Int32 = 0
Private m_waitHandle As New System.Threading.ManualResetEvent(True) ' Initialize to signaled
Private m_waitHandle2 As New System.Threading.ManualResetEvent(False) ' Initialize to UN-signaled
Подпрограмма обработчика событий
Public Sub Handle_VSP_DataReceived_Dev(ByVal sender As System.Object, ByVal e As System.EventArgs)
Dim NumberBytes As Int32
If m_SerialPort.BytesToRead > 0 And m_SerialPort.BytesToRead >= m_WaitingOnBytes Then
' This handles the case where the event was triggered, there was data and its length matched
' or exceeded the requested amount.
System.Diagnostics.Debug.Print("DR-Dev: Bytes to read: " & m_SerialPort.BytesToRead & ", waiting for: " & m_WaitingOnBytes)
NumberBytes = m_SerialPort.Read(m_ReturnBytes, m_VSP_Offset, m_WaitingOnBytes)
System.Diagnostics.Debug.Print("DR-Dev: got " & NumberBytes & " bytes, released wait handle")
m_WaitingOnBytes = 0
m_waitHandle.Set() ' Release the wait handle so the thread running WriteReadVSPort can proceed
ElseIf m_SerialPort.BytesToRead > 0 And m_WaitingOnBytes > 0 Then
' Handle the case where the full request is not delivered. Note:
' This should not need to be done, but it seems that the
' Serial Port is sending the event before all the data is
' received and the threshold is crossed and then not
' sending another event until the buffer is read.
' So, here we do a partial read, if we are waiting on a
' read operation and adjust the offset and remaining bytes
' we are waiting for.
System.Diagnostics.Debug.Print("DR-Dev: Bytes to read: " & m_SerialPort.BytesToRead & ", waiting for: " & m_WaitingOnBytes)
NumberBytes = m_SerialPort.Read(m_ReturnBytes, m_VSP_Offset, m_WaitingOnBytes)
If NumberBytes = m_WaitingOnBytes Then
' We actually got all the data, though the serial port did not report it had it ready. Fine,
' proceed as above
System.Diagnostics.Debug.Print("DR-Dev: got " & m_WaitingOnBytes & " bytes, released wait handle")
m_WaitingOnBytes = 0
m_waitHandle.Set() ' Release the wait handle so the thread running WriteReadVSPort can proceed
Else ' Mark this as a partial read
System.Diagnostics.Debug.Print("DR-Dev: got partial " & NumberBytes & " while waiting for: " &
m_WaitingOnBytes & " bytes, continue to hold WriteReadVSPort")
m_WaitingOnBytes -= NumberBytes
m_VSP_Offset += NumberBytes
End If
End If
End Sub
Функция выполнения команды записи / чтения ответа
Public Function WriteReadVSPort(ByVal commandLength As Int32, ByVal returnLength As Int32) As Int32
Dim ExceptionOccurred As Boolean = False
Dim NumberBytes As Int32 = 0
Dim RetriesRemaining As Int32 = 4
Dim Finished As Boolean = False
' Important to set up for reading response before the command is written
' because another thread will handle the DataReceived event and process
' the received data without intervention from the thread executing
' this(subroutine.
m_VSP_Offset = 0
m_WaitingOnBytes = returnLength
' Set the DataReceived event threshold
m_SerialPort.ReceivedBytesThreshold = m_WaitingOnBytes - 1
' Set waitHandle so it will block the thread executing this routine until the data is received
m_waitHandle.Reset()
Try ' Writing
m_SerialPort.Write(m_CommandBuffer, 0, commandLength)
Catch exc As InvalidOperationException
MessageBox.Show("InvalidOperationException when writing to Serial Port COM" & -1 * DeviceContext, Application.ProductName)
ExceptionOccurred = True
Catch exc As TimeoutException
MessageBox.Show("TimeoutException when writing to Serial Port COM" & -1 * DeviceContext, Application.ProductName)
ExceptionOccurred = True
End Try
If Not ExceptionOccurred Then
Try ' Reading all done by Event Handler
' wait for event handler to complete its job, running in another thread
System.Diagnostics.Debug.Print("WR_VSP: waiting on waitHandle, bytes avail: " &
m_SerialPort.BytesToRead & ", want bytes: " & m_WaitingOnBytes)
If m_waitHandle.WaitOne(VSPtimeout) Then
' The WaitOne call returned True, meaning that Handle_VSP_DataReceived_Dev was able to receive all the requested data
System.Diagnostics.Debug.Print("WR_VSP: proceeding")
Else
' The WaitOne call timed out. Give it some retries before throwing an exception
While Not Finished And RetriesRemaining > 0
System.Threading.Thread.Sleep(VSPtimeout)
If m_SerialPort.BytesToRead > 0 And m_SerialPort.BytesToRead >= m_WaitingOnBytes Then
NumberBytes = m_SerialPort.Read(m_ReturnBytes, m_VSP_Offset, m_WaitingOnBytes)
System.Diagnostics.Debug.Print("WR_VSP: timeout mode, got " & m_WaitingOnBytes & " bytes")
Finished = True
Else
RetriesRemaining -= 1
End If
End While
If Not Finished Then
Throw New TimeoutException("Device failed to send the requested number of bytes.")
End If
End If
Catch exc As InvalidOperationException
MessageBox.Show("InvalidOperationException when reading from Serial Port COM" & -1 * DeviceContext, Application.ProductName)
ExceptionOccurred = True
Catch exc As TimeoutException
MessageBox.Show("TimeoutException when reading from Serial Port COM" & -1 * DeviceContext, Application.ProductName)
ExceptionOccurred = True
End Try
End If
If ExceptionOccurred Then
Return 1
Else
Return 0
End If
End Function