Проблема, как вы уже догадались, в том, что событие DataReceived возникает, как только данные получены через последовательный порт. Там может быть не полная запись там; объект SerialPort не имеет ни малейшего представления о том, что вы считаете «достаточным» для того, чтобы данные были значимыми или работоспособными.
Обычным решением является сохранение другого «буфера» полученных данных, содержащего любые данные, которые вы определили как неполные. Когда данные поступают через порт и ваше событие запускается, оно должно сначала взять то, что находится в буфере, и добавить его к тому, что вы уже получили. Затем вы должны начать с начала этого буфера данных и проверить полученные данные, ища известные шаблоны атомарных «кусочков» данных, которые имеют для вас значение; например, скажем, первое, что вы получите, это "ID: 12"
. Вы берете это, помещаете это в буфер, затем сканируете буфер, ища образец, определенный регулярным выражением "ID: \d*? "
. Поскольку в вашем буфере нет конечного пробела, ваш шаблон не может найти ничего значащего, и вы теперь знаете, что не получили полное сообщение.
Затем при следующем вызове события DataReceived вы извлекаете "453 Sta"
из последовательного буфера. Вы добавляете его к тому, что у вас уже есть, и получаете "ID:12453 Sta"
, а когда вы применяете регулярное выражение, вы получаете совпадение «ID: 12345». Вы передаете это в метод для дальнейшей обработки (возможно, вывод на консоль) и удаляете ту же строку в начале буфера, оставляя «Sta». При повторном сканировании вы не найдете ничего более интересного, поэтому вы оставляете то, что у вас есть, и цикл повторяется, пока данные продолжают поступать. Очевидно, вы будете тестировать больше шаблонов, чем просто шаблон идентификатора; Вы можете искать всю «строку», которую ожидаете получить, например, "ID: \d*? State: \w{2} "
. Вы даже можете хранить данные в своем буфере, пока у вас не будет обеих строк для записи: "ID:\d*? State:\w{2} Zip:\d{5} StreetType:\w*? "
.
В любом случае вам нужно будет определить, являются ли полученные данные либо надежно «фиксированной длины» (то есть каждая строка определенного типа всегда будет иметь одинаковое количество байтов или символов), либо надежно «разделены» ( Это означает, что будет какой-либо символ или комбинация символов, которая всегда разделяет важные элементы данных). Если ни один из этих способов не применим, может быть очень трудно разобрать данные на отдельные поля.
Вот пример, основанный на том, что у вас уже есть:
private static StringBuilder receiveBuffer = new StringBuilder();
private static void Port_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
SerialPort spL = (SerialPort) sender;
int bufSize = 20;
Byte[] dataBuffer = new Byte[bufSize];
Console.WriteLine("Data Received at"+DateTime.Now);
Console.WriteLine(spL.Read(dataBuffer, 0, bufSize));
string s = System.Text.ASCIIEncoding.ASCII.GetString(dataBuffer);
//here's the difference; append what you have to the buffer, then check it front-to-back
//for known patterns indicating fields
receiveBuffer.Append(s);
var regex = new Regex(@"(ID:\d*? State:\w{2} Zip:\d{5} StreetType:\w*? )");
Match match;
do{
match = regex.Match(receiveBuffer.ToString());
if(match.Success)
{
//"Process" the significant chunk of data
Console.WriteLine(match.Captures[0].Value);
//remove what we've processed from the StringBuilder.
receiveBuffer.Remove(match.Captures[0].Index, match.Captures[0].Length);
}
} while (match.Success);
}