The problem is, as you may have guessed, that the event DataReceived is raised as soon as data has been received over the serial port. There may not be a complete record there; the SerialPort object has no clue what you consider to be "enough" data to be significant, or workable.
The usual solution is to maintain another "buffer" of received data, containing any data you have recognized as incomplete. When data comes in over the port and your event fires, it should first take what's in the buffer and append it to what you have already received. Then, you should start at the beginning of this data buffer and inspect the received data, looking for known patterns of atomic "chunks" of data that have meaning to you; for instance, say the first thing you receive is "ID: 12"
. You take this, put it in the buffer, then scan the buffer looking for a pattern defined by a regex "ID: \d*? "
. Because the trailing space is not present in your buffer, your pattern fails to find anything of meaning, and so you now know you haven't received a full message.
Then, on the next raising of the DataReceived event, you pull "453 Sta"
out of the serial buffer. You append it to what you already have and get "ID:12453 Sta"
, and when you apply the regex, you get the match "ID: 12345 ". You pass this into a method for further processing (display to the console, maybe), and remove the same string from the front of the buffer, leaving "Sta". Scanning again you don't find anything else of interest, so you leave what you have, and the cycle repeats aws data continues to come in. Obviously, you'll be testing more patterns than just the ID pattern; you may search for an entire "string" you expect to receive, such as "ID: \d*? State: \w{2} "
. You may even keep the data in your buffer until you have both strings for a record: "ID:\d*? State:\w{2} Zip:\d{5} StreetType:\w*? "
.
Either way, you will need to identify whether the data being received is either reliably "fixed-length" (meaning each string of a particular type will always have the same number of bytes or characters), or reliably "delimited" (meaning there will be some character or character combination that always separates significant elements of data). If neither of these apply, it may be very difficult to parse the data into single-field chunks.
Here's a sample based on what you have already:
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);
}