Serial Read All Question

I have an app I’m working on that has an array of a subclassed Serial object. The purpose is pretty simple. The app monitors these serial ports for data available that is a barcode read from a barcode reader connected to an Ethernet serial device. The network serial devices are homed to a dedicated virtual server. When barcode data is available i attempted to use ReadAll and append the data to an array for processing at regular intervals. What I encountered is that when the DataAvailable event fired my code would only append the first character of the barcode and not until that append step completed did the DataAvailable fire again with the remaining characters of the barcode. I fixed the issue by checking to see if the DataAvailable string length was greater than 1 but I’d like a more reliable method. Some details, the devices sending the barcodes have several seconds between reads so the likelihood of getting two reads close together is low. Each Barcode has a carriage return after the last character but EndOfLine doesn’t recognize it.

I think what I have is a timing issue on the ReadAll. The act of checking the length provides enough miliseconds of wait time for all of the barcode string to be received. I’m looking for some suggestions on a better way to address the execution of the code in the DataAvailable event so I’m sure I get the full barcode read. It works now in testing as I have it coded, (below), but only with a couple devices being monitored so far. I worry that if I add a bunch more serial ports the app may very well fail and I’ll end up with more than one barcode or a barcode and a half, etc.

[code]Public Property DeviceName as String
Public Property NewData as String
Public Property DataCache as String

Sub DataAvailable() Handles DataAvailable
DataCache = DataCache + Me.ReadAll()
If Len(DataCache) > 1 Then
NewData = Me.DeviceName + Chr(9) + DataCache.Replace(EndOfLine,"")
DataCache = “”
SerialDataReceived.Append(NewData)
LogTransactions(NewData)
End If
End Sub[/code]

Any thoughts on what I should be doing instead ?

What about using serial.LookAhead and searching the string for the terminating character of the barcode. Basically ignore the buffer until you know you have a complete barcode and then pull it from the buffer and process it.

Also, if the barcodes are the same character length why not use that as a determining factor whether you have a complete bar code?

Are all these different bar code readers attached to a different serial port? If so, then each port will have it’s own DataAvailable event.

Hmmm… I haven’t tried serial.LookAhead. I’ll have to experiment with that. I wish String had an EndsWith method like Text. That would make looking for the carriage return so much easier.

I can’t guarantee the barcodes will always be the same length. They are calculated and sometimes vary in length from the the DateTime hex conversion that makes them unique.

Each Barcode reader has it’s own Network serial adapter and the serial objects are created as an array with their own data available event as you surmise.

But you don’t want EndsWith, because you could have more than one barcode in the buffer, or a barcode and a half as you say. Use InStr() to detect the carriage return and pull that much data out, then check for more.

dim s as string
dim n as integer

do 
   s = me.LookAhead
   n = instr(s, chr(13))
   if n > 0 then
      SerialDataReceived.Append me.read(n-1)
      s= me.read(1)  // skip the carriage return
   end
loop until n < 1

Thanks Tim. This sounds like a really solid approach. I’ll give it a go. I do have one question though. I’m only assuming that the end of line is a carriage return, Chr(13), but I haven’t really tested it and it’s possible that a Line Feed, Chr(10), might also be included. Isn’t it always safer to use EndOfLine instead of one, or the other or both characters or does InStr not work with EndOfLine?

Testing revealed that I needed to find and replace both the CR and LF characters. The code below is what I ended up using which takes a slightly different approach at removing the CR LF than than Tim’s code suggestion. I chose to read the barcode with it’s CR LF and then remove the unneeded characters from the data read before appending to an array for later processing and logging the data to a WebTextArea transaction log. Thanks for the feedback folks!

[code]Sub DataAvailable() Handles DataAvailable
Dim s,NewData As String
Dim n As Integer

Do
// LookAhead in the Serial buffer for a complete Barcode string to read
s = Me.LookAhead
// Find the starting character count for the CR LF combination Chr(13)+Chr(10)
n = InStr(s, Chr(13)+Chr(10))
If n > 0 Then
// Read the Barcode with the CR LF characters
s = Me.read(n+1)
// Concatenate the source Serial DeviceName with the Barcode separated by a Tab character and
// replace the CR LF combination Chr(13)+Chr(10) with an empty string
NewData = Me.DeviceName + Chr(9) + s.Replace(Chr(13)+Chr(10),"")
// Use the concatenated barcode data
SerialDataReceived.Append NewData
LogTransactions(NewData)
End If
Loop Until n < 1

End Sub[/code]

DeviceName is a property of my Serial SubClass “SerialData” that gets set along with other serial settings when the object gets created in the array of SerialData Objects.

n = InStr(s, Chr(13)+Chr(10))

can be replaced with

n=EndOfLine.Windows /// even if your platform is NOT Windows

just might make the code more readable, and no effect on performance