我想在.net中使用SerialPort類。SerialPort.BaseStream.ReadAsync缺少第一個字節
我選擇保持我的服務異步,所以我使用SerialPort.BaseStream
上的異步方法。
在我的異步方法中,我寫了一個字節[]到串口,然後開始讀取,直到我沒有收到任何更多的數據在毫秒,並返回該結果。
但是,問題是,我似乎錯過了所有答覆的第一個字節,而不是打開串口後的第一個答覆。
如果我在每次響應(讀取)後關閉端口,並在執行新請求(寫入)之前再次打開端口,則第一個字節不會丟失。但是,如果我在關閉後過早地打開端口,通常會導致"Access to the port 'COM4' is denied."
異常。對於每個寫入/讀取來說,打開/關閉似乎也是非常不必要的。
這基本上就是我的方法是這樣的:
private async Task<byte[]> SendRequestAsync(byte[] request)
{
// Write the request
await _serialPort.BaseStream.WriteAsync(request, 0, request.Length);
var buffer = new byte[BUFFER_SIZE];
bool receiveComplete = false;
var bytesRead = 0;
// Read from the serial port
do
{
var responseTask = _serialPort.BaseStream.ReadAsync(buffer, bytesRead, BUFFER_SIZE - bytesRead);
if (await Task.WhenAny(responseTask, Task.Delay(300)) == responseTask)
{
bytesRead += responseTask.Result;
}
else
receiveComplete = true;
} while (!receiveComplete);
var response = new byte[bytesRead];
Array.Copy(buffer, 0, response, 0, bytesRead);
return response;
}
有什麼明顯的錯誤在我這樣做的方式是什麼?有沒有更聰明的方法來異步實現相同?
在'WhenAny'或'WhenAll'後做'.Result'總讓我感到畏縮,我知道它永遠不應該有問題,但我仍然不喜歡它。我總是喜歡'bytesRead + = await responseTask',因爲任務完成,所以'await'沒有任何開銷,但是你得到了拋出的解包異常的優點,而不是從'.Result'獲得'AggregateException'如果你確實得到錯誤。 –
您確定300 ms超時後流中沒有字節嗎?你怎麼知道你錯過了第一個字節?這是第一個字節在某種特定方面?我問的原因是,也許前面的響應留下了一些字節,所以在第一次讀取之後,每次讀取實際上都包含第一個字節,但在前一個請求的剩餘字節之後。您可能需要在每次請求前刷新流。 –
我知道第一個字節缺失,因爲每個響應應該以ASCII字符'$'(NMEA消息)開始。我現在已經切換到使用同步API,但在後臺任務中運行它,它正在工作。雖然我不喜歡這個解決方案.. – Walkingsteak