Итак, я хочу подключиться к устройству через последовательный , который отправляет данные только тогда, когда все меняется с настройками на устройстве (измерительном устройстве). Я использую C# и. Net SerialPort
.
Я могу читать данные, и это выглядит довольно хорошо. Но есть несколько проблем, с которыми я столкнулся.
Я реализовал свой метод чтения (ReadExistingData()
), чтобы он постоянно использовал SerialDataReceivedEventHandler
при появлении новых данных. К сожалению, когда я читаю его таким образом (возможно, из-за разного размера пакета), он будет читаться очень хаотично, и поэтому мне нужно «поймать» первый инициирующий байт (здесь это 0xA5
). Это означает, что я всегда проверяю, является ли байт, который я только что получил, 0xA5
, и если это так, я читаю остальные.
Но я чувствую, что таким образом я пропускаю некоторые команды, которые мое устройство посылает мне, и это почему я не могу правильно отображать данные, только время от времени.
Примечание: устройство отправляет устройству время и значение. Значение отсрочено и отчасти неточно, но время всегда точно на месте. Другие параметры, которые он посылает, всегда отклоняются и, кажется, не распознаются и, следовательно, вообще не изменяются.
Для отображения данных я использую консоль в целях тестирования, и вся конструкция, кажется, очень реагирует на выходные данные консоли.
Вот небольшой фрагмент кода:
class Device
{
private int stdMessageLengthInBytes = 5;
public DeviceData processedData;
byte[] dataBuffer;
int receivedMessages = 0;
public Device()
{
// Initialize BaseClass (SerialPort derivative)
this.port = new System.IO.Ports.SerialPort();
// Initialize Device
this.data = new byte[stdMessageLengthInBytes];
this.processedData = new P8005_Data();
dataBuffer = new byte[stdMessageLengthInBytes];
}
// Is supposed to read the data from serial port
protected override void ReadExistingData()
{
// Check whether buffer is empty -> Try to catch a 0xA5
if (dataBuffer[0] == 0x00)
{
port.Read(dataBuffer, 0, 1);
}
// If no 0xA5 was catched, restart
if (dataBuffer[0] != 0xA5)
{
dataBuffer = new byte[stdMessageLengthInBytes]; // Reset buffer
return;
}
// Read next byte -> Command byte
port.Read(dataBuffer, 1, 1);
// If command was empty, restart
if (dataBuffer[1] == 0x00)
{
dataBuffer = new byte[stdMessageLengthInBytes]; // Reset buffer
return;
}
// If its time that is communicated: Read 3 bytes
if (dataBuffer[1] == 0x06)
{
// 4 ms delay seems to be needed otherwise it wont function correctly somehow
System.Threading.Thread.Sleep(5);
port.Read(dataBuffer, 2, 3);
// Write buffer to actual raw data byte array
this.data = dataBuffer;
dataBuffer = new byte[stdMessageLengthInBytes]; // Reset buffer
}
// Otherwise: Just read 2 bytes
System.Threading.Thread.Sleep(5); // Needed delay
port.Read(dataBuffer, 2, 2);
// Write buffer to actual raw data byte array
this.data = dataBuffer;
dataBuffer = new byte[stdMessageLengthInBytes]; // Reset buffer
}
// Method called by SerialDataReceivedEventHandler
protected override void DataReceivedOnComPort(object sender, SerialDataReceivedEventArgs e)
{
bool valid = false;
ReadExistingData(); // Read data from COM- Port
lock (processedData)
{
switch (data[1]) // Check command byte
{
// Time (3 btyes)
case (0x06):
processedData.currentTime = String.Format("{0:D2}:{1:D2}:{2:D2}", DecodeBcd(data[2]), DecodeBcd(data[3]), DecodeBcd(data[4]));
valid = true;
receivedMessages++;
break;
// Value (2 bytes)
case (0x0D):
double val = 0;
val += DecodeBcd(data[2]) * 100;
val += DecodeBcd(data[3]);
val /= 10;
processedData.currentValue = val;
valid = true;
receivedMessages++;
break;
// ... here are various other hex- code that represent a command from the device (2 btyes)
default:
valid = false;
break;
}
}
// only to check when
if (valid)
{
Console.WriteLine("Received Valid Messages: {0}", receivedMessages);
ConsoleOutput();
}
}
}
На заметку: Инициализация порта происходит в другом методе из базового класса и работает нормально.
Есть ли что я пропускаю? Как бороться с чем-то подобным? Есть ли какие-либо улучшения, которые помогут улучшить мою производительность? Я думал о потоке с блокировками, но я не думаю, что это решение как-то ... Или, может быть, все это просто проблема с консолью?
РЕДАКТИРОВАТЬ:
Я знаю, изменил мой код (как предложил @jdweng), чтобы я помещал все в буфер (в основном List<byte> mainBuffer
. Затем я беру все байты в буфере всякий раз, когда это возможно, и работаю с ними, просматривая его для 0xA5
. Когда один найден, я прочитайте команду и определите, как долго должно быть «сообщение» (время -> +3 байта, данные -> +2 байта, другое -> +1 байт). Затем я могу отработать эти сообщения (я поставил их в List<byte[]>
) и определите мой вывод на экран.
Однако даже после аутсорсинга обработки сообщений и обработки сообщений я все равно, похоже, пропускаю некоторые сообщения, поскольку некоторые действия просто не зарегистрированы и имеют большую задержку, или моя обработка неверна. Я могу думать о том, что, поскольку я блокирую свои mainBuffer
, возможно, некоторые данные не записываются в него.
Действительно ли это на этот раз критично? скую? Существует программное обеспечение, которое поставляется с устройством, и у него, похоже, нет таких больших проблем с задержкой и немного неправильными значениями ...