-
Jan 12th, 2018, 03:11 PM
#1
Thread Starter
Lively Member
tochararray from string and failed...
Guys,
totally new in vb.net... migrated from 6....
OK, so I am planning to receive the string from my arduino.. arduino sends:
Code:
&1;0;0;0;0;0;1;0;0;0;$
and I can read that in a text box easily. Bascally it is sending the GPIO status of the arduino with wrapper for start and stop .
Code:
Function ReceiveGPIOSerialData() As String
Dim IncomingGPIO As String
Try
IncomingGPIO = globalConfig.GPIOSerialPort.ReadExisting()
If IncomingGPIO Is Nothing Then
Return "nothing" & vbCrLf
Else
Return IncomingGPIO
End If
Catch ex As TimeoutException
Return "Error: GPIO Port read timed out."
End Try
End Function
Now,
Code:
Private Sub timerSerialPoll_Tick(sender As Object, e As EventArgs) Handles timerSerialPoll.Tick
receivedGPIOData = ReceiveGPIOSerialData()
txtOutput.Text &= receivedGPIOData
txtgpioout.Text = receivedGPIOData 'for dev debug
End Sub
polls for the serial data and displays it nicely. But as said, i need to get the individual of them, like if start with & then for GPIOdata[1] = 1 and so on... so from this string, I need to split out each int values... any idea how?? I failed to use the substring for no reason...
-
Jan 12th, 2018, 03:42 PM
#2
Re: tochararray from string and failed...
If you want to split a string
Code:
Dim str As String = "a;b;c"
Dim arr As String() = str.Split(";"c)
MessageBox.Show(arr.Count.ToString)
-
Jan 12th, 2018, 03:42 PM
#3
Re: tochararray from string and failed...
One way is to use SubString to remove the first and last characters, then split the remaining text on semi-colons, eg:
Code:
Dim GPIOdata as String() = receivedGPIOData.SubString(1, receivedGPIOData.Length -2).Split(";"c)
-
Jan 12th, 2018, 03:49 PM
#4
Thread Starter
Lively Member
Re: tochararray from string and failed...
Originally Posted by wes4dbt
If you want to split a string
Code:
Dim str As String = "a;b;c"
Dim arr As String() = str.Split(";"c)
MessageBox.Show(arr.Count.ToString)
exactly... then i changed it to:
Code:
Private Sub timerSerialPoll_Tick(sender As Object, e As EventArgs) Handles timerSerialPoll.Tick
Dim i As Integer
Dim GPIOdata() As String
receivedGPIOData = ReceiveGPIOSerialData()
txtOutput.Text &= receivedGPIOData
txtgpioout.Text = receivedGPIOData 'for dev debug
Dim dataStrArray As String() = receivedGPIOData.Split(New Char() {";"c})
'GPIOdata = receivedGPIOData.Split(New Char() {";"c})
For i = 0 To dataStrArray.Length - 1
GPIOdata(i) = dataStrArray(i)
Next
If StrComp(GPIOdata(0), "&1", CompareMethod.Text) = 0 Then
lblStatus.Text = "OK"
End If
If StrComp(GPIOdata(6), "1", CompareMethod.Text) = 0 Then
lblStatus.Text = "Door Closed"
End If
End Sub
But now only first one i can read, not the whole... but i need the whole and then I can make my status elaborations... idas??
-
Jan 12th, 2018, 04:31 PM
#5
Re: tochararray from string and failed...
Not sure what your saying.
But now only first one i can read, not the whole..
The "first one" what??
The "whole" what???
-
Jan 12th, 2018, 06:10 PM
#6
Re: tochararray from string and failed...
You can write that more simply with just .Split(";"c). You don't need that New Char() stuff in there.
What's the point of the GPIOdata array? All you are doing is copying one array into the other. Why not just use one and skip the copying?
I also don't know what it is you can't do, but the code is suggestive. For one thing, you don't need to split the string at all based on the code you showed. After all, the array is only local, so nothing outside that event handler can get to any of the data, and all you do inside the event handler is look for what amounts to two items. You could use String.StartsWith("&1") in place of the first check, and a SubString in place of the other, and skip the Split entirely.
Therefore, it seems like what you really want is something more than just looking at the first two characters, and one other in the string. Perhaps that is what the question is that you are getting at, but I still can't say I understand what result you ultimately want.
My usual boring signature: Nothing
-
Jan 12th, 2018, 09:42 PM
#7
Thread Starter
Lively Member
Re: tochararray from string and failed...
Originally Posted by Shaggy Hiker
Therefore, it seems like what you really want is something more than just looking at the first two characters, and one other in the string. Perhaps that is what the question is that you are getting at, but I still can't say I understand what result you ultimately want.
NO!!
Basically
Code:
&1;0;0;0;0;0;1;0;0;0;$
is the output sent from my arduino serial. ecept the first 2 char, &1, rest until $ is the gpio pin status.. if gpio pin reads high it sends 1, if low, it sends 0. i need to read these values. Then i have to put each gpio status into it's own variable as then i can do my manipulation in the app. in arduino, i have read all the values of gpio using a char array, data[10], for pin 1 = data[0] and so on. Now in vb, i need them back as that way, so i can get them individually. comma /semicolon deliminated data is the best method for me to send data here. Thus now i need to get them back as individually. Hence i tried to split... Ideas???
Mishu~
-
Jan 12th, 2018, 09:53 PM
#8
Thread Starter
Lively Member
Re: tochararray from string and failed...
even
Code:
Private Sub timerSerialPoll_Tick(sender As Object, e As EventArgs) Handles timerSerialPoll.Tick
Dim i As Integer
'Dim GPIOdata() As String
receivedGPIOData = ReceiveGPIOSerialData()
txtOutput.Text &= receivedGPIOData
txtgpioout.Text = receivedGPIOData 'for dev debug
Dim GPIOdata As String() = receivedGPIOData.Substring(1, receivedGPIOData.Length - 2).Split(";"c)
'GPIOdata = receivedGPIOData.Split(New Char() {";"c})
If StrComp(GPIOdata(0), "&1", CompareMethod.Text) = 0 Then
lblStatus.Text = "OK"
End If
If StrComp(GPIOdata(6), "1", CompareMethod.Text) = 0 Then
lblStatus.Text = "Door Closed"
End If
End Sub
is not helping
in vb6 i have done this with full success and it was based on ethernet...
Code:
Private Sub socket1_DataArrival(ByVal bytesTotal As Long)
Dim InBuffer As String, rcvdString() As String
localTimestamp = Format(Now, "dd/MM/yy hh:mm:ss AM/PM")
socket1.GetData InBuffer, vbString
rcvdString() = Split(InBuffer, ";")
txtDebug.Text = txtDebug.Text + localTimestamp + ">>" + InBuffer + vbCrLf
txtDebug.SelStart = Len(txtDebug.Text)
indoorTemp = Int(rcvdString(0))
finsTemp = Int(rcvdString(1))
outTemp = Int(rcvdString(2))
targetTemp = Int(rcvdString(3))
If (StrComp(rcvdString(4), "C0", vbTextCompare) = 0) Then
compressorOn = False
ElseIf (StrComp(rcvdString(4), "C1", vbTextCompare) = 0) Then
compressorOn = True
End If
If (StrComp(rcvdString(5), "F0", vbTextCompare) = 0) Then
indoorFanOn = False
ElseIf (StrComp(rcvdString(5), "F1", vbTextCompare) = 0) Then
indoorFanOn = True
End If
If (StrComp(rcvdString(6), "D0", vbTextCompare) = 0) Then
defrostOn = False
ElseIf (StrComp(rcvdString(6), "D1", vbTextCompare) = 0) Then
defrostOn = True
End If
Call showData
End Sub
-
Jan 12th, 2018, 10:03 PM
#9
Re: tochararray from string and failed...
'&1;0;0;0;0;0;1;0;0;0;$
Dim GPIOdata As String() = receivedGPIOData.Substring(3, receivedGPIOData.Length - 2).Split(";"c)
- Coding Examples:
- Features:
- Online Games:
- Compiled Games:
-
Jan 12th, 2018, 10:57 PM
#10
Thread Starter
Lively Member
Re: tochararray from string and failed...
Originally Posted by .paul.
'&1;0;0;0;0;0;1;0;0;0;$
Dim GPIOdata As String() = receivedGPIOData.Substring(3, receivedGPIOData.Length - 2).Split(";"c)
and the gentleman is saying:
System.ArgumentOutOfRangeException: 'Index and length must refer to a location within the string.
Parameter name: length'
Here is the full code:
Code:
Private Sub timerSerialPoll_Tick(sender As Object, e As EventArgs) Handles timerSerialPoll.Tick
Dim i As Integer
'Dim GPIOdata() As String
receivedGPIOData = ReceiveGPIOSerialData()
txtOutput.Text &= receivedGPIOData
txtgpioout.Text = receivedGPIOData 'for dev debug
Dim GPIOdata As String() = receivedGPIOData.Substring(3, receivedGPIOData.Length - 2).Split(";"c)
'GPIOdata = receivedGPIOData.Split(";"c)
'GPIOdata = Split(receivedGPIOData, ";")
For i = 0 To UBound(GPIOdata)
Console.WriteLine(GPIOdata(i))
Next i
If StrComp(GPIOdata(0), "&1", CompareMethod.Text) = 0 Then
lblStatus.Text = "OK"
End If
If StrComp(GPIOdata(6), "1", CompareMethod.Text) = 0 Then
lblStatus.Text = "OK"
End If
End Sub
-
Jan 12th, 2018, 10:58 PM
#11
Re: tochararray from string and failed...
I feel like, in this thread, we're making the foolish assumption that your serial port code is reading all the data correctly. But there's definitely some language barrier.
You say the code in #8 "is not helping". What does that mean? Is the right thing displayed in txtOutput? If not, then the parsing code doesn't matter, you aren't reading the right data.
If it is right, what is inside the GPIOdata array? Is that what you expect? If not, that's the part of the code we'll focus on.
I'm assuming the problem is you expect the StrCmp() to find "&1" at the start. But.
Code:
receivedGPIOData.Substring(1, receivedGPIOData.Length - 2).Split(";"c)
Don't cram everything onto one line. It hides things from you and makes debugging harder. Let's break it apart.
Code:
Dim dataLength As Integer = receivedGPIOData.Length
Dim trimmedData As String = receivedGPIOData.Substring(1, dataLength - 2)
Dim tokens() As String = trimmedData.Split(";"c)
Now, let's say this is your input string, for simplicity:
OK. So.
dataLength will be 8.
Let's work out the next line:
Code:
Dim trimmedData As String = receivedGPIOData.Substring(1, dataLength - 2)
Dim trimmedData As String = receivedGPIOData.Substring(1, 8 - 2)
Dim trimmedData As String = receivedGPIOData.Substring(1, 6)
Dim trimmedData As String = "&1;0;0;".Substring(1, 6)
Dim trimmedData As String = "1;0;0;"
Now let's see what tokens() becomes:
Code:
Dim tokens() As String = trimmedData.Split(";"c)
Dim tokens() As String = "1;0;0;".Split(";"c)
Dim tokens() As String = { "1", "0", "0" }
Oh. Since the Substring() took the & off the front, you won't find "&1" as the first token. So when you get to:
Code:
If StrComp(GPIOdata(0), "&1", CompareMethod.Text) = 0 Then
It fails.
You should either make StrComp() look for "1" (but you shouldn't use StrComp()) or change your code to not take away the &:
Code:
Dim dataLength As Integer = receivedGPIOData.Length
Dim trimmedData As String = receivedGPIOData.Substring(0, dataLength - 1)
Dim tokens() As String = trimmedData.Split(";"c)
This answer is wrong. You should be using TableAdapter and Dictionaries instead.
-
Jan 12th, 2018, 11:06 PM
#12
Thread Starter
Lively Member
Re: tochararray from string and failed...
okey, great intro... great approach... i liked it and thanks...
now, updated this to
Code:
Private Sub timerSerialPoll_Tick(sender As Object, e As EventArgs) Handles timerSerialPoll.Tick
'Dim i As Integer
'Dim GPIOdata() As String
receivedGPIOData = ReceiveGPIOSerialData()
txtOutput.Text &= receivedGPIOData
txtgpioout.Text = receivedGPIOData 'for dev debug
Dim GPIOdata As String() = receivedGPIOData.Substring(1, receivedGPIOData.Length - 2).Split(";"c)
'GPIOdata = receivedGPIOData.Split(";"c)
'GPIOdata = Split(receivedGPIOData, ";")
If StrComp(GPIOdata(0), "1", CompareMethod.Text) = 0 Then
lblStatus.Text = "OK"
End If
If StrComp(GPIOdata(6), "1", CompareMethod.Text) = 0 Then
lblStatus.Text = "Door Open"
End If
End Sub
and still getting the same error "System.ArgumentOutOfRangeException: 'startIndex cannot be larger than length of string.
Parameter name: startIndex' "
-
Jan 12th, 2018, 11:12 PM
#13
Thread Starter
Lively Member
Re: tochararray from string and failed...
It works... if i put the value manually, then it gives perfect... seeems somehow Serial read is not giving the whole damn thing perfectly...
So now I need to focus on there actually... how???
Code:
Function ReceiveGPIOSerialData() As String
Dim IncomingGPIO As String
Try
IncomingGPIO = globalConfig.GPIOSerialPort.ReadExisting()
If IncomingGPIO Is Nothing Then
Return "nothing" & vbCrLf
Else
Return IncomingGPIO
End If
Catch ex As TimeoutException
Return "Error: GPIO Port read timed out."
End Try
End Function
Private Sub timerSerialPoll_Tick(sender As Object, e As EventArgs) Handles timerSerialPoll.Tick
'Dim i As Integer
'Dim GPIOdata() As String
receivedGPIOData = ReceiveGPIOSerialData()
txtOutput.Text &= receivedGPIOData
txtgpioout.Text = receivedGPIOData 'for dev debug
'receivedGPIOData = "&1;0;0;0;0;0;1;0;0;0;$"
Dim GPIOdata As String() = receivedGPIOData.Substring(1, receivedGPIOData.Length - 2).Split(";"c)
'GPIOdata = receivedGPIOData.Split(";"c)
'GPIOdata = Split(receivedGPIOData, ";")
If StrComp(GPIOdata(0), "1", CompareMethod.Text) = 0 Then
lblStatus.Text = "OK"
End If
If StrComp(GPIOdata(6), "1", CompareMethod.Text) = 0 Then
lblStatus.Text = "Door Open"
End If
End Sub
is the serial port part... and arduino is sending them with a "serial.println()"...
-
Jan 12th, 2018, 11:44 PM
#14
Re: tochararray from string and failed...
So you need to validate your Serial read data before splitting it and assigning it to an array
- Coding Examples:
- Features:
- Online Games:
- Compiled Games:
-
Jan 13th, 2018, 09:27 AM
#15
Thread Starter
Lively Member
Re: tochararray from string and failed...
Originally Posted by .paul.
So you need to validate your Serial read data before splitting it and assigning it to an array
Any help on that??? I am reading it though... and can see a full form of what arduino is sending... It's an old topic though, I know serial just sends things... And thus I also added the bracketing like & and $ but still I need to put the whole thing inside a single shot... in arduino we use ReadStringUntil("\n") but here in vb.net, i dont know what to do...
-
Jan 13th, 2018, 11:51 AM
#16
Thread Starter
Lively Member
Re: tochararray from string and failed...
this is now working... just that sometimes it is giving error... like the before, same error... it looks like sometimes it misses the reading...
Serial.readline() was the key... now if I could make it without timer, rather kind if event driven, if serial buffer has something... then hope this will be OK...
Help here???
-
Jan 13th, 2018, 05:52 PM
#17
Re: tochararray from string and failed...
- Coding Examples:
- Features:
- Online Games:
- Compiled Games:
-
Jan 14th, 2018, 05:39 AM
#18
Thread Starter
Lively Member
Re: tochararray from string and failed...
Originally Posted by .paul.
Yeah!! I also foudn it... but there are some people saying that this is not the good idea... So what is your opinion???
Mishu~
-
Jan 14th, 2018, 06:04 AM
#19
Re: tochararray from string and failed...
Using an event is the correct way to go...
A timer keeps ticking away regardless of whether any data has been received, whereas an event fires only when data has been received
- Coding Examples:
- Features:
- Online Games:
- Compiled Games:
-
Jan 14th, 2018, 07:55 AM
#20
Thread Starter
Lively Member
Re: tochararray from string and failed...
Originally Posted by .paul.
Using an event is the correct way to go...
A timer keeps ticking away regardless of whether any data has been received, whereas an event fires only when data has been received
yeppp!! Indeed!!!
But the worst part happened here... it hangs... yes, it gives output... but then 2 errors... any one of them... whatever they are, i have also found eventually the app gets hang and other buttons does not work. thus decided to use threading for serial read, so the button will be here. [button will send command via serial too].
Now,
Code:
System.ArgumentOutOfRangeException: 'startIndex cannot be larger than length of string.
Parameter name: startIndex'
is what is the error for the threaded subroutine
Code:
Private Sub SerialPoll()
'Dim i As Integer
'Dim GPIOdata As String
receivedGPIOData = ReceiveGPIOSerialData()
txtOutput.Text &= receivedGPIOData
txtgpioout.Text = receivedGPIOData 'for dev debug
'receivedGPIOData = "&1;0;0;0;0;0;1;0;0;0;$"
Dim GPIOdata As String() = receivedGPIOData.Substring(1, receivedGPIOData.Length - 2).Split(";"c)
'GPIOdata = receivedGPIOData.Substring(1, receivedGPIOData.Length - 2).Split(";"c)
'GPIOdata = Split(receivedGPIOData, ";")
If StrComp(GPIOdata(0), "1", CompareMethod.Text) = 0 Then
lblStatus.Text = "OK"
End If
'If StrComp(GPIOdata(6), "1", CompareMethod.Text) = 0 Then
'lblStatus.Text = "Door Close"
'End If
'If StrComp(receivedGPIOData, "DRCLS", CompareMethod.Text) = 0 Then
'lblStatus.Text = "Door Close"
'End If
End Sub
with function:
Code:
Function ReceiveGPIOSerialData() As String
Dim IncomingGPIO As String
Try
'IncomingGPIO = globalConfig.GPIOSerialPort.ReadLine()
IncomingGPIO = globalConfig.GPIOSerialPort.ReadExisting()
If IncomingGPIO Is Nothing Then
Return "nothing" & vbCrLf
Else
Return IncomingGPIO
End If
Catch ex As TimeoutException
Return "Error: GPIO Port read timed out."
End Try
End Function
Now, yes, if we need to avoid timer and go for event based, I need a really guidance as microsoft guidance is like a clumsy to me... [head is jammed].
Pathetic situation here...
-
Jan 14th, 2018, 10:44 AM
#21
Thread Starter
Lively Member
Re: tochararray from string and failed...
Here is the code pieces:
Code:
Private Sub frmMain_Load(sender As Object, e As EventArgs) Handles MyBase.Load
timerSerialPoll.Enabled = False
globalFunc.loadConfig()
lblConfig.Text = "GSM port:" + globalConfig.GSMport + " GPIO Port:" + globalConfig.GPIOport 'for debug only.
'Me.CheckForIllegalCrossThreadCalls = False
AddHandler globalConfig.GPIOSerialPort.DataReceived, AddressOf DataReceivedHandler
End Sub
Code:
Private Sub btnConnect_Click(sender As Object, e As EventArgs) Handles btnConnect.Click
'thread = New System.Threading.Thread(AddressOf SerialPoll)
'thread.Start()
If (globalConfig.GSMSerialPort.IsOpen) Then
globalConfig.GSMSerialPort.Close()
End If
If (globalConfig.GPIOSerialPort.IsOpen) Then
globalConfig.GPIOSerialPort.Close()
End If
globalConfig.CommPortSetup()
'My.Computer.Ports.OpenSerialPort(port)
Try
'globalConfig.GSMSerialPort.Open()
globalConfig.GPIOSerialPort.Open()
btnConnect.Visible = False
lblConnStat.Text = "Connected"
timerSerialPoll.Enabled = True
Catch ex As Exception
'globalConfig.GSMSerialPort.Close()
globalConfig.GPIOSerialPort.Close()
timerSerialPoll.Enabled = False
lblConnStat.Text = "Disconnected"
btnConnect.Visible = True
MessageBox.Show(ex.Message)
End Try
Code:
Private Shared Sub DataReceivedHandler(sender As Object, e As SerialDataReceivedEventArgs)
Dim sp As SerialPort = CType(sender, SerialPort)
Dim indata As String = sp.ReadExisting()
Console.WriteLine("Data Received:")
Console.Write(indata)
End Sub
now, i want to use these:
Code:
txtOutput.Text &= receivedGPIOData
txtgpioout.Text = receivedGPIOData 'for dev debug
'receivedGPIOData = "&1;0;0;0;0;0;1;0;0;0;$"
Dim GPIOdata As String() = receivedGPIOData.Substring(1, receivedGPIOData.Length - 2).Split(";"c)
'GPIOdata = receivedGPIOData.Substring(1, receivedGPIOData.Length - 2).Split(";"c)
'GPIOdata = Split(receivedGPIOData, ";")
If StrComp(GPIOdata(0), "1", CompareMethod.Text) = 0 Then
lblStatus.Text = "OK"
End If
'If StrComp(GPIOdata(6), "1", CompareMethod.Text) = 0 Then
'lblStatus.Text = "Door Close"
'End If
[here the receivedGPIOData will be replaced by appropriate variable, indata ]
but can't.... any assistance??
-
Jan 15th, 2018, 06:41 AM
#22
Thread Starter
Lively Member
Re: tochararray from string and failed...
Guysm I'm avoiding any multithereading and event handlers... sticking with the timer tick. Now, normally I can see the data coming to me... that part is fully OK. The problem is after i try to make the substring, it does not work. Not just like thhat way...
I have a button to send a Serial command. When I send that command, and then when the vb again receives the data, it gives an error...
Here is the codes::
Code:
Private Sub timerSerialPoll_Tick(sender As Object, e As EventArgs) Handles timerSerialPoll.Tick
'globalFunc.connectSerial()
serialPoll()
'globalConfig.GPIOSerialPort.Close()
End Sub
Private Sub serialPoll()
'Dim i As Integer
receivedGPIOData = ReceiveGPIOSerialData()
txtOutput.Text &= receivedGPIOData
'receivedGPIOData = "&1;0;0;0;0;0;1;0;0;0;$"
'Dim GPIOdata As String() = receivedGPIOData.Substring(1, receivedGPIOData.Length - 2).Split(";"c)
'GPIOdata = receivedGPIOData.Split(";"c)
'GPIOdata = Split(receivedGPIOData, ";")
processGPIO()
'If StrComp(GPIOdata(0), "1", CompareMethod.Text) = 0 Then
'lblStatus.BackColor = Color.Green
'End If
'If StrComp(GPIOdata(6), "1", CompareMethod.Text) = 0 Then
'lblStatus.Text = "Door Close"
'End If
End Sub
Private Sub processGPIO()
Dim GPIOdata As String
Dim doorOpenStat As Boolean
GPIOdata = receivedGPIOData.Substring(1, 1)
doorOpenStat = GPIOdata
txtgpioout.Text = GPIOdata 'for dev debug
If doorOpenStat = True Then
lblStatus.Text = "Door Closed"
End If
End Sub
Private Sub btnDooorClose_Click(sender As Object, e As EventArgs) Handles btnDooorClose.Click
Dim cmd As String
cmd = "close" + vbLf
globalConfig.GPIOSerialPort.Write(cmd)
Thread.Sleep(1000)
End Sub
and the error is:
Code:
System.ArgumentOutOfRangeException: 'startIndex cannot be larger than length of string.
Parameter name: startIndex'
plz, i need the support...
-
Jan 15th, 2018, 11:52 AM
#23
Re: tochararray from string and failed...
Time to do a bit of debugging.
You didn't tell us which line the exception happens on, but it seems like the only one that isn't commented out, which can deliver THAT error, would be this one:
GPIOdata = receivedGPIOData.Substring(1, 1)
If that isn't the line with the error, then please tell us which it is. However, assuming that is the line with the error, then the error means that the string is a LOT shorter than you are expecting. This is where the debugging comes into it, as there could be 0 or 1 characters in receivedGPIOData, and which of those two it is would be quite important to know.
So, if that is the line that is causing the exception, then put a breakpoint on the line. When execution stops on the breakpoint, take a look at what receivedGPIOData holds. Almost certainly, it will be empty. That's the more likely result, but also the more boring one. If it is NOT empty, then what does it hold? That character would be telling.
If the string IS empty, then the problem is in ReceiveGPIOSerialData(), as that isn't returning what you want it to return. This may be happening EVERY time, or possibly just every now and then, or every other time, or some other pattern. You'd have to run the program a few times with a breakpoint in that function to see which it is.
After looking back a few posts, I found the function body. You need to put a breakpoint in that function and see what the method is returning. I suspect that you'd learn more from that than from anything else.
My usual boring signature: Nothing
-
Jan 15th, 2018, 12:55 PM
#24
Re: tochararray from string and failed...
It's sort of mental to try and avoid event handlers or multithreading. It's one of the tools you have to be ready to use with a serial port.
Getting serial data is not too much unlike getting network data and way less reliable than getting file data. Let's talk about it.
If I want to read "a file", it's easy. I ask Windows for the bytes from the file. I can ask in advance how many bytes there are, and ask for chunks of it if I want to. The only way this goes wrong tends to be situations where a file is deleted while you're using it or if the storage device explodes. They're rare enough we pretend they don't exist.
If I want to read data from the network, there are a million things that can go wrong. "The connection is closed" might mean something went wrong and I lost the connection, or it might mean the other side sent me all it wanted to send. If I get some data, it might be all of the data for that particular transaction, or it might just be some of the data that was interrupted by the connection dropping. The serial port is just like the network.
So when working with these unreliable data streams, we use protocols. Protocols are a set of rules about how data is transferred between two computers. If everyone follows the rules, we can tell the difference between "the connection was closed because there is no more data" and "the connection was terminated before everything was transferred".
HTTP has that kind of protocol. Every transaction begins with headers. Each header must be a name-value pair terminated with CRLF. The headers are finished when a line is CRLF with no header. Generally, you get the headers all in one packet. But sometimes they're big enough you get them in chunks. If you get a chunk that ends with "Content-Enco", you know it's not the end of the headers because there's no CRLF terminator. So you wait for more data. Or, if the connection closes, you know something went wrong.
The headers might include a Content-Length that tells you how many bytes to expect. They probably also include a Content-Encoding that can, in some cases, indicate a different way to describe the length of the data will be used. In either of these cases, since you're told the length to expect ahead of time, you know if you expected 300 bytes and only have 298 you should wait for more data. You also know if the connection terminates after 128 bytes, something went wrong. Sometimes there's no indication of length, and that's the worst case: you have to take the data and interpret any closed connection as "the end".
It turns out this makes event-based and multithreaded approaches to device I/O more natural. Why?
Let's work with a really simple protocol similar to yours. All messages are semicolon-delimited arrays that end with "$". This means I can tell lots of things apart:
A complete message:
This has the "$" at the end, so I know it's a fully completed message.
An incomplete message:
I don't have a $ here, so I know this isn't all of the data. I have to wait to get more.
Multiple messages:
This has one complete message { 1, 2, 3 }. But there's part of another message that starts with { 7, 8, ??? } at the end. I can split out the first message and hold on to the "extra" data. This happens. It happens if the device sends 2 messages so close together they both (partially) happen between two timer ticks.
So we can take two approaches. One uses ReadExisting() like you are using, the other uses events to process data as it comes in.
With ReadExisting()
Code:
* let previous_data be an empty string.
* on_timer():
* let current_data = ReadExisting()
* if current_data is empty/Nothing then quit.
* let all_data = previous_data + current_data
* let messages be the result of finding all "complete" messages in all_data.
* for each message in messages:
* Process(message)
* let previous_data be all current_data past the last complete message.
This is a little sticky to demonstrate in VB code because there's enough string manipulation to lose sight of the goal.
It handles an "empty" case by quitting if ReadExisting() doesn't return anything.
It handles the incomplete message I used as an example. Process() will get the data { 1, 2, 3 }. It stores "7;8" in previous_data. On the next timer tick, maybe ";9$" will have arrived. That means we'll do this:
Code:
* on_timer():
* current_data = ";9$"
* all_data = "7;8" + ";9$"
* messages = { "7;8;9$" }
* Process({ 7, 8, 9 })
* all_data = ""
Right now, your code expects it will ONLY get complete messages and that there will ALWAYS be a complete message every timer tick. Both of those assumptions are false, because that's what the errors you are getting indicate. You need your code to expect both of these cases, and I've just provided a pretty good example.
Personally, I think the implementation is cleaner with event-based logic rather than timer ticks, but the core logic of "how do I safely read" is the same.
This answer is wrong. You should be using TableAdapter and Dictionaries instead.
-
Jan 15th, 2018, 12:56 PM
#25
Re: tochararray from string and failed...
I suggest turning option script on for starters. Then learn the difference between a sub and a function.
-
Jan 17th, 2018, 07:40 AM
#26
Thread Starter
Lively Member
Re: tochararray from string and failed...
Originally Posted by Sitten Spynne
It's sort of mental to try and avoid event handlers or multithreading. It's one of the tools you have to be ready to use with a serial port.
......
......
Personally, I think the implementation is cleaner with event-based logic rather than timer ticks, but the core logic of "how do I safely read" is the same.
Sir, First of all, you opened up a whole big ideas... and thanks for that large tutorial. This really helps me to understand so many things...
Okey, so now let me explain a bit more: I'm here making a system where I need to read the GPIO status from an arduino. Based on that I will issue command... The string coming from arduino tells the status of the whole device...
is my string Here "<" is the header and ">" is the message footer, bracketing the whole hing as described earlier. The first bit is for device status... then next nits for different status of each GPIO. Now, as I will need only 1/0 only, then i have decided to make it more short and to make it like this. Always the first bit have to be 1 as 1 means the device is actually UP and running. Thus I will at worst case receive <10000....> but never <0000....>
Now, I am using the GPIOSerialPort.ReadLine() because my arduino is sending me Strings with CRLF. (Serial.println()). Thus in other sense, All I am reading is just a string upto CRLF. But still I face the same issue, same error. Yes, this happens when my arduino starts 1 min before the app. And that is the problem, as in real life, arduino will start on power, (and technically i cant add any delay of 2 mins for safety)and then the problem is not solving...
Event driven I will also need as I have to read from a gprs modem, but i will come to that part later on a different thread probably. But first thing first here...
And below is the code:
Code:
Private Sub frmMain_Load(sender As Object, e As EventArgs) Handles MyBase.Load
frmGSMDbg.Show()
frmGSMDbg.Visible = False
Thread.Sleep(2000)
RTC.Enabled = True
globalFunc.loadConfig()
globalFunc.connectSerial()
ReceiveGPIOSerialData() 'intentional reading at startup for clearing any inbuffer
Thread.Sleep(2000)
Dim cmd As String
cmd = "close" + vbLf
globalConfig.GPIOSerialPort.Write(cmd)
Thread.Sleep(500)
timerGPIOPoll.Enabled = True
lblConfig.Text = "GSM port:" + globalConfig.GSMport + " GPIO Port:" + globalConfig.GPIOport 'for debug only.
End Sub
Code:
Function ReceiveGPIOSerialData() As String
Dim IncomingGPIO As String
Try
IncomingGPIO = globalConfig.GPIOSerialPort.ReadLine()
If IncomingGPIO Is Nothing Then
Return "nothing" & vbCrLf
Else
Return IncomingGPIO
End If
Catch ex As TimeoutException
Return "Error: GPIO Port read timed out."
End Try
End Function
Code:
Private Sub GPIOPoll()
receivedGPIOData = ""
receivedGPIOData = ReceiveGPIOSerialData()
Thread.Sleep(50)
txtOutput.Text &= receivedGPIOData + vbCrLf 'debug
processGPIOData()
End Sub
Private Sub processGPIOData()
Dim GPIOData As String
If (receivedGPIOData.Substring(0, 1) Like "<" And receivedGPIOData.Substring(11, 1) Like ">") Then
GPIOData = receivedGPIOData.Substring(1, 1) 'first value, represents IOC Status
IOCStatus = GPIOData
GPIOData = receivedGPIOData.Substring(6, 1) '6th valule, represents Door is Closing [0 means here undefined]
doorClosingStat = GPIOData
GPIOData = receivedGPIOData.Substring(7, 1) '7th valule, represents Door is Closed [0 means here undefined]
doorCloseStat = GPIOData
txtgpioout.Text = receivedGPIOData 'for dev debug
If IOCStatus = True Then
lblIOCLink.BackColor = Color.Green
Else lblIOCLink.BackColor = Color.Red
End If
If doorClosingStat = True Then
lblStatus.Text = "Door Closing"
End If
If doorCloseStat = True Then
lblStatus.Text = "Door Closed"
End If
Else
lblStatus.Text = "Polling..."
End If
End Sub
Code:
Private Sub timerGPIOPoll_Tick(sender As Object, e As EventArgs) Handles timerGPIOPoll.Tick
GPIOPoll()
End Sub
So from this point of view, i hope i will get some assistance as always... how exactly i can fix it...
Posting Permissions
- You may not post new threads
- You may not post replies
- You may not post attachments
- You may not edit your posts
-
Forum Rules
|
Click Here to Expand Forum to Full Width
|