-
Re: SerialPort VB.NET : Write/buffer/timing and Data Received Event (VS2010 and VS200
Quote:
Originally Posted by
dbasnett
Generally when I have a problem I try to make the simplest test case that shows the problem. If it takes a loop with 50 then so be it, though I would prefer less.
The code I provided made assumed that every command caused a response, but since it doesn't...
edit: Can you explain the format of the commands?
I removed the loop and got back to what I had. I hope I did not left too many errors with my loop removal.
The code is thus intended for one unique position, here X=20,Y=10.
The commands are explained in comments in the code.
Thank you again !
Here is the code which is mainly yours in the end. I added : just a bunch of commands and a string verification + a label update to check I was in the right place of the IF condition during the string verification:
Code:
Option Strict On
' All the imports are not usueful yet, but I need them afterwards
Imports System
Imports System.Threading
Imports System.IO
Imports System.IO.Ports
Public Class SerialPortwBv2
Private Sub Form1_Shown(ByVal sender As Object, ByVal e As EventArgs) Handles Me.Shown
'
'Port setup and open
'
Dim p() As String = IO.Ports.SerialPort.GetPortNames 'Array p contains ports visible to the system
'Settings here
With SerialPort1
.PortName = "COM1"
.Encoding = System.Text.Encoding.GetEncoding(28591)
.DtrEnable = True
.RtsEnable = True '>>>>>>>>> As pointed out by Mc_VB, maybe this should be enabled /setup ?
.Parity = IO.Ports.Parity.None
.StopBits = IO.Ports.StopBits.One
.DataBits = 8
.BaudRate = 19200
End With
Try
SerialPort1.Open()
isopen.Set()
BackgroundWorker1.WorkerReportsProgress = True
BackgroundWorker1.WorkerSupportsCancellation = True
BackgroundWorker1.RunWorkerAsync()
Catch ex As Exception
RichTextBox1.AppendText(ex.Message & Environment.NewLine)
End Try
' coloured indicator for the serialport connection
rtb_ONOFF.BackColor = Color.DarkGreen
End Sub
Dim sc As Threading.Thread
Private Sub btnSendMultiple_Click(ByVal sender As Object, ByVal e As EventArgs) Handles btnSendMultiple.Click
btnSendMultiple.Enabled = False
sc = New Threading.Thread(AddressOf SendCmds)
sc.IsBackground = True
sc.Start()
End Sub
Dim cmdDone As New Threading.AutoResetEvent(True)
Private Sub SendCmds()
' Command definition
line_1 = "1TP?;2TP?;WT500;" ' What is the X Position ? ; What is the Y Position ? ; Wait 500ms
line_2 = "1PA20;" ' GoTo 20 on axis X ;
line_3 = "2PA10;" ' GoTo 10 on axis Y ;
line_4 = "1WS;2WS;WT500;" ' Wait for Axis X to stop ; Wait for axis Y to stop ; Wait 500ms
line_5 = "1TP?;2TP?;1MD?;2MD?;WT2000;" ' Position X ? ; Position Y ? ; Has axis X stopped ? ; Has axis Y stopped ? ; Wait 2 secs
' Final command lines to send to the controller (total number of lines to be tested...):
line_A = line_1 & line_2 & line_3 & line_4 & line_5
Try
If isopen.WaitOne(0) AndAlso SerialPort1.IsOpen Then
cmdDone.WaitOne()
SerialPort1.Write(line_A & vbCrLf)
End If
Catch ex As TimeoutException
MessageBox.Show(ex.Message)
Catch ex As InvalidOperationException
MessageBox.Show(ex.Message)
Catch ex As UnauthorizedAccessException
MessageBox.Show(ex.Message)
End Try
isopen.Set()
End Sub
Private Sub btnDisconnect_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnDisconnect.Click
'close port
isopen.WaitOne()
SerialPort1.Close()
rtb_ONOFF.BackColor = Color.Red
End Sub
Dim isopen As New Threading.AutoResetEvent(False)
Dim dataByts As New List(Of Byte)
Dim dataLock As New Object
Dim dataAvailable As New Threading.AutoResetEvent(False)
Private Sub SerialPort1_DataReceived(ByVal sender As Object, ByVal e As IO.Ports.SerialDataReceivedEventArgs) Handles SerialPort1.DataReceived
Dim br As Integer = SerialPort1.BytesToRead '# of bytes to read
If br > 0 Then
Dim b(br - 1) As Byte 'create buffer to read the data
Try
br = SerialPort1.Read(b, 0, b.Length) 'read the bytes, note non-blocking
If br < b.Length Then 'adjust length if required
Array.Resize(b, br)
End If
'add bytes just read to list
Threading.Monitor.Enter(dataLock)
dataByts.AddRange(b)
Threading.Monitor.Exit(dataLock)
dataAvailable.Set()
Catch ex As Exception
'exception handling
End Try
End If
End Sub
Const LF As Byte = 10 ' byte code for LF char
Private Sub BackgroundWorker1_DoWork(ByVal sender As Object, ByVal e As System.ComponentModel.DoWorkEventArgs) Handles BackgroundWorker1.DoWork
Do
If BackgroundWorker1.CancellationPending Then Exit Do
Dim idxLF As Integer = dataByts.IndexOf(LF) 'get the index of the LF
If idxLF >= 0 Then
'do we have a LF ?
'If yes, get the message from controller
Dim s As String
Threading.Monitor.Enter(dataLock)
s = System.Text.Encoding.GetEncoding(28591).GetChars(dataByts.ToArray, 0, idxLF - 1)
dataByts.RemoveRange(0, idxLF + 1) 'remove the message from the buffer
Threading.Monitor.Exit(dataLock)
BackgroundWorker1.ReportProgress(1, s)
Else
'wait for more data
dataAvailable.WaitOne()
End If
Loop
End Sub
Private Sub BackgroundWorker1_ProgressChanged(ByVal sender As Object, ByVal e As System.ComponentModel.ProgressChangedEventArgs) Handles BackgroundWorker1.ProgressChanged
'This code run on UI
Dim s As String = DirectCast(e.UserState, String) 'get message
RichTextBox1.AppendText(s & Environment.NewLine)
' RETURN STRING VERIFICATION:
' 4 and 2 char from the END we SHOULD FIND a "1" meaning both axis motion status are = 1, ie: STOPPED.
'If I use "s" instead of "s1" it has to few chars at the beginning so I get an error with the Length minus 2 or 4 chars:
Dim s1 As String
s1=RichTextBox1.Text
If s1.substring(s1.Length-2,1)="1" AndAlso s1.substring(s1.Length-4,1)="1" Then
'motion complete:
updateText("MOTION STATUS HAS BEEN VERIFIED=1")
'I Don't think it's the right place to set the WaitHandle, but it made sense to put it only after the string is verified:
'I GUESS THE LINK TO THE GRAB_IMAGE WILL BE HERE
cmdDone.Set()
Else
'motion NOT complete:
updateText("MOTION NOT COMPLETE")
End If
End Sub
Delegate Sub SetTextCallback(ByVal [text] As String)
Public Sub updateText(ByVal [text] As String)
If Me.Label1.InvokeRequired Then
Dim x As New SetTextCallback(AddressOf updateText)
Me.Invoke(x, New Object() {(text)})
Else
Me.Label1.Text &= [text] & vbCrLf
End If
End Sub
Private Sub SerialPort1_ErrorReceived(ByVal sender As Object, _
ByVal e As IO.Ports.SerialErrorReceivedEventArgs) Handles SerialPort1.ErrorReceived
Debug.WriteLine("ER " & e.EventType.ToString)
End Sub
Private Sub SerialPort1_PinChanged(ByVal sender As Object, _
ByVal e As IO.Ports.SerialPinChangedEventArgs) Handles SerialPort1.PinChanged
Debug.WriteLine("PC " & e.EventType.ToString)
End Sub
End Class
-
Re: SerialPort VB.NET : Write/buffer/timing and Data Received Event (VS2010 and VS200
Many posts ago we resolved the issues with serialport communications. (One thing, you still do not have handshaking set.)
What we are left with is the protocol of the controller. Some things confuse me.
Does the controller execute one command at a time. i.e. If you tell it to move is the next command delayed until it completes the movement?
What is the purpose of the wait commands? It seems like they are for writing programs on the controller and serve no purpose if you are doing remote control.
Let me ask this again. Is the purpose of this application to move the device to a certain location and then take an image? Is there anything else?
-
Re: SerialPort VB.NET : Write/buffer/timing and Data Received Event (VS2010 and VS200
Quote:
Originally Posted by
dbasnett
Many posts ago we resolved the issues with serialport communications. (One thing, you still do not have handshaking set.)
And I thank you for that big step !
What we are left with is the protocol of the controller.
Some things confuse me.
ME too, I hope this controller has no random behaviour because there are some issue with timings.
Does the controller execute one command at a time. i.e. If you tell it to move is the next command delayed until it completes the movement?
No. That's the purpose of "1WS;" for example, ie: wait for axis 1 to stop before next command. Or if I write "1PA20;2PA10;" the motion of both axis is almost started at the same time, not sequential at all.
What is the purpose of the wait commands? It seems like they are for writing programs on the controller and serve no purpose if you are doing remote control.
If I don't put a wait 500ms, the next couple of commands are processed too quickly and when I ask the position for example, the axis has not reach its destination.
Let me ask this again. Is the purpose of this application to move the device to a certain location and then take an image? Is there anything else?
Yes it the sole purpose. Move to position N, grab a frame, process this frame, move to position N+1, etc...
Answered in between the quotes.
-
Re: SerialPort VB.NET : Write/buffer/timing and Data Received Event (VS2010 and VS200
Hi Liam, there are a couple of things I don't understand and I am hoping you will enlighten me.
The following code snippet builds the final command string if I understand correctly.
Quote:
' Command definition
line_1 = "1TP?;2TP?;WT500;" ' What is the X Position ? ; What is the Y Position ? ; Wait 500ms
line_2 = "1PA20;" ' GoTo 20 on axis X ;
line_3 = "2PA10;" ' GoTo 10 on axis Y ;
line_4 = "1WS;2WS;WT500;" ' Wait for Axis X to stop ; Wait for axis Y to stop ; Wait 500ms
line_5 = "1TP?;2TP?;1MD?;2MD?;WT2000;" ' Position X ? ; Position Y ? ; Has axis X stopped ? ; Has axis Y stopped ? ; Wait 2 secs
' Final command lines to send to the controller (total number of lines to be tested...):
line_A = line_1 & line_2 & line_3 & line_4 & line_5
1TP?,2TP?,1MD? and 2MD? are all commands that will respond yet I don't see where the response is being handled, are they used somewhere in a decision loop? In a loop x 50 there would be 300 such responses.
If the above is in a loop 1TP? and 2TP? are requested twice in succession, would this be necessary?
The command line has a ~3 second total delay which means any commands that follow cannot be processed for 3 seconds, so for 3 seconds the buffer fills unless the flow control is working correctly. This comment is more of a "thinking out loud" moment, it is something I could see as being potential problem. Are all the delays needed.
Do you have a sequence of operation, I see it like this, would this be right?
1./ transmit next move (1PAnn;2PAnn <CR>) //transmit command
2./ loop until the move is done (1MD?;2MD? <CR>) //transmit command, no timer needed just keep sending until true is received
3./ process response (true/false) //receive response
4./ false goto #2
5./ check position (1TP?;2TP <CR>) //transmit command
6./ if position is correct aquire image //receive response
7./ if not completed goto #1
I wrote this before I realized the question about the time delays had been asked but I have left it as is. I saw where you were using delays to wait for a response, using the above sequence would this not eliminate the need for the timers?
-
Re: SerialPort VB.NET : Write/buffer/timing and Data Received Event (VS2010 and VS200
Quote:
Originally Posted by
Mc_VB
Hi Liam, there are a couple of things I don't understand and I am hoping you will enlighten me.
The following code snippet builds the final command string if I understand correctly.
1TP?,2TP?,1MD? and 2MD? are all commands that will respond yet I don't see where the response is being handled, are they used somewhere in a decision loop? In a loop x 50 there would be 300 such responses.
I check 1md and 2md responses. for the moment tp? are just displayed so i can check the accuracy of the motion.
If the above is in a loop 1TP? and 2TP? are requested twice in succession, would this be necessary?
one before motion, the other after the motion, bringing the start and destination position of the motion resp. But of course in a loop, there's one too many.
The command line has a ~3 second total delay which means any commands that follow cannot be processed for 3 seconds, so for 3 seconds the buffer fills unless the flow control is working correctly. This comment is more of a "thinking out loud" moment, it is something I could see as being potential problem. Are all the delays needed?
good question and one of the dark area for me...
Do you have a sequence of operation, I see it like this, would this be right?
1./ transmit next move (1PAnn;2PAnn <CR>) //transmit command
2./ loop until the move is done (1MD?;2MD? <CR>) //transmit command, no timer needed just keep sending until true is received
3./ process response (true/false) //receive response
4./ false goto #2
5./ check position (1TP?;2TP <CR>) //transmit command
6./ if position is correct aquire image //receive response
7./ if not completed goto #1
I wrote this before I realized the question about the time delays had been asked but I have left it as is. I saw where you were using delays to wait for a response, using the above sequence would this not eliminate the need for the timers?
Well, I like ur way of thinking in the command sequence, maybe it's more solid with the controller behaviour/results that way.I did not try it yet :)
answers before I hit the sack !
-
Re: SerialPort VB.NET : Write/buffer/timing and Data Received Event (VS2010 and VS200
Thinking out loud... Maybe the answer is to build a class that is the controller, or at least mimics the behavior. This class would have only a couple of commands(methods), like Stop and Move. It would mimic the behavior that McVb suggested and be in control of the SerialPort totally.
-
Re: SerialPort VB.NET : Write/buffer/timing and Data Received Event (VS2010 and VS200
Quote:
Originally Posted by
dbasnett
Thinking out loud... Maybe the answer is to build a class that is the controller, or at least mimics the behavior. This class would have only a couple of commands(methods), like Stop and Move. It would mimic the behavior that McVb suggested and be in control of the SerialPort totally.
It seems a good idea, to go along the actions of the controller with several methods. Just that a class construction seems a tad out of my reach in terms of coding capacity atmo, even if it's maybe not that difficult to understand in the end...
The only tweak I would see with the sequence Mc_vb proposed is with the position checking. The axis move with an accurate position of 3 digits after the decimal (20.000). And we have an acceptance on this position, ie: 19.996 is allright for example (difference <0.005). Otherwise the order of commands seems perfect.
-
Re: SerialPort VB.NET : Write/buffer/timing and Data Received Event (VS2010 and VS200
Hi,
I'm doing just what mc_VB proposed right now (and for the last 2 days of last week). I've sequenced it with buttons for the user to click: each method has its own button (move, verify motion stop, verify position, grab image) and I just disable/enable the buttons for the user atmo.
I just have a practical VB/.NET question here :) :
- I'd like to update a control of the UI outside the UI , but not just the text (for exemple the background colour of a ritchtextbox, or sthg else). I managed to do it with the text by creating a function named updateText, using a Delegate sub and an InvokeRequired on the text zone. I'd like to find an example of passing other input parameters than just text from outside de UI which created the control.
To put it in the context of my application:
In the Data Received event I either check for a "1" char at the end of a string which length is < 3 (just asked for both "MD?" commands, answer is "11" or "00" or "10" / "01", so strictly inferior to 3 characters) or I get the position from a longer string (answer is maybe "15.000<Cr>-5.000" which is always > 3 char long).
- In the first case I would like to put a visual mark on the UI , fro example the back colour of a rtb to GREEN, with the "OK" mention in it (for the text part I found a way)
- In the second case, I'd like to pass the positions (after parsing) from the DataReceived Event to the UI thread to compare them with the expected positions
What's the quickest method and best approach to these two tasks ? (I used the background worker and the progresschanged event before, but maybe we should do something more appropriate)
Thx !
[EDITED] I kinda answered my questions this morning :) But would still like to see your inputs on this if possible.
With:
Code:
Me.Invoke( New Eventhandler(AddressOf DoPOSITIONUpdate))
Placed in the Datareceived
and the sub declaration:
Code:
Public Sub DoPOSITIONUpdate (ByVal sender As Object, ByVal e As System.EventArgs)
txtRETURNS.text= AnalyzedString
' parsing...
txtPOSX.text = ParsedPart1
txtPOSY.text = ParsedPart2
' Comparing strings...
if ABS(ParsedPart1 - XexpectedValue) < 0.006 AndAlso ABS(ParsedPart2 - YexpectedValue) < 0.006 then
' position is ok
else
'error
End Sub
-
Re: SerialPort VB.NET : Write/buffer/timing and Data Received Event (VS2010 and VS200
The reason I didn't put an Invoke in the DataReceived was because only one SerialPort event can fire at a time. For this app it probably won't make a difference.
-
Re: SerialPort VB.NET : Write/buffer/timing and Data Received Event (VS2010 and VS200
OK, thanks for the technical explanation dbasnett !
1. And what's the difference between Encoding.Getchars() and Encoding.GetString() methods ? (further down in the code, you used a bytes[ ] to Array of Char conversion with GetChars() )
2. I'm removing the part where the code checks for a LineFeed and cuts the bytes sequence at this point to get a string. I'm doing this because I now send only two commands, get the result, analyse the response and go to next step (as hinted by mc_VB).
Thus, I need the entire response now and to not cut the array at the first LF found (as we did before). Is it better to provide the length of the bytes Array in GetChars() along the array and the start index ? Or can we just give the GetChars() method the bytes array as a single argument ?
-
Re: SerialPort VB.NET : Write/buffer/timing and Data Received Event (VS2010 and VS200
Quote:
Originally Posted by
LiamC
OK, thanks for the technical explanation dbasnett !
1. And what's the difference between Encoding.Getchars() and Encoding.GetString() methods ? (further down in the code, you used a bytes[ ] to Array of Char conversion with GetChars() )
2. I'm removing the part where the code checks for a LineFeed and cuts the bytes sequence at this point to get a string. I'm doing this because I now send only two commands, get the result, analyse the response and go to next step (as hinted by mc_VB).
Thus, I need the entire response now and to not cut the array at the first LF found (as we did before). Is it better to provide the length of the bytes Array in GetChars() along the array and the start index ? Or can we just give the GetChars() method the bytes array as a single argument ?
1. GetChars is slightly faster in some cases. You can use either one for this.
2. If you are expecting multiple responses why not leave the code as is and add each response to a list of string. When the count of the list matches the desired amount, two in this case, process the list and then clear it. On the other hand if you know exactly what the string length will be every time you could do it your way.
-
Re: SerialPort VB.NET : Write/buffer/timing and Data Received Event (VS2010 and VS200
Ha, nice catch on the 2nd answer, I prefer your way !
Because I don't know exactly the length...And this is why: this stupid controler responds "20.000" for a position, "0.000" for another position and "-15.000" for a third one. Resulting in 3 different lengths of string...
This afternoon I was trying to parse the two combined answers at specific chars positions: find the first "CR" char, cut the first string. Then, find the first "LF" char, that is where the second position string should be starting, and cut when the second "CR" is found.
I don't know how to optimize this without going your way with the 2 counts in a list.
-
Re: SerialPort VB.NET : Write/buffer/timing and Data Received Event (VS2010 and VS200
So long as you know the order one list should suffice.
-
Re: SerialPort VB.NET : Write/buffer/timing and Data Received Event (VS2010 and VS200
Yes, one list with two items that I add, each being a response of the controler.
(Here I'm at home atmo) I just recall that the SerialPort.Read() was done by counting bytes to read and then putting these bytes in a list (and added with dataByts.AddRange(b) ).This would later be converted with GetChars() to a string.
Is there another way I can separate the 2 incoming commands responses other than look for a Cr/Lf within the bytes "stream" because I can only see this as the way to go ?
-
Re: SerialPort VB.NET : Write/buffer/timing and Data Received Event (VS2010 and VS200
I am lost. Didn't you have the code working were each response was already a separate string? If you send one of your two commands, get the response and store it in a List(Of String), then the second, and store it in the list what else do you need?
-
Re: SerialPort VB.NET : Write/buffer/timing and Data Received Event (VS2010 and VS200
Quote:
Originally Posted by
dbasnett
I am lost. Didn't you have the code working were each response was already a separate string? If you send one of your two commands, get the response and store it in a List(Of String), then the second, and store it in the list what else do you need?
Again I typed a fast message from home and it wasn't very clear, my apologies.
I separated the methods, ie: each method is in the click event of a button for the user of the optical experiment. But one method contains several commands: "1MD?;2MD?;" or "1PA10;2PA-5;" for example.
So in my earlier message what I meant was that I was getting 2 responses, one for each command contained in the method.
Now I'm separating the commands, ie: one serialport.write() for each command that triggers a response (SerialPort.Write("1MD?;") and Serialport.Write("2MD?;") later, for example).
With this, I can still use the "LF" separator as a way to parse the command response from the message sent back by the controler and then populate a list as you said.
I then will wait for the list.count to be >1 (wait for the second message, am I correct ?) to go further and compare both list(0) and list(1) with the positions we were waiting for.
These positions are stored in a datatable.
Is it clearer ?
-
Re: SerialPort VB.NET : Write/buffer/timing and Data Received Event (VS2010 and VS200
-
Re: SerialPort VB.NET : Write/buffer/timing and Data Received Event (VS2010 and VS200
Quote:
Originally Posted by
dbasnett
Yes it is.
Does it seem like a correct way to work on ?
I will have access to the controller and cameras this afternoon and will do some tests of what I've written in VB.
-
Re: SerialPort VB.NET : Write/buffer/timing and Data Received Event (VS2010 and VS200
With your mc_vb approach and this, yes.
-
Re: SerialPort VB.NET : Write/buffer/timing and Data Received Event (VS2010 and VS200
In the case were we would only use one serialport.write to avoid 2 iterations of serialdata received event, how would you parse a string like this one:
Code:
response = 20.000{CR}{LF}0.000{CR}{LF}
knowing that the number of useful characters (positions) can change the next time a response is triggered by a user click on the "verify position" button ?
-
Re: SerialPort VB.NET : Write/buffer/timing and Data Received Event (VS2010 and VS200
Quote:
Originally Posted by
LiamC
In the case were we would only use one serialport.write to avoid 2 iterations of serialdata received event, how would you parse a string like this one:
Code:
response = 20.000{CR}{LF}0.000{CR}{LF}
knowing that the number of useful characters (positions) can change the next time a response is triggered by a user click on the "verify position" button ?
Food for thought
Code:
'test message
Dim response As String = "20.0" & vbCrLf & "10.123" & vbCrLf
'I picked 255 because it is not normally an ASCII value seen
response = response.Replace(vbCrLf, Chr(255)) 'change the two character CRLF to a single char
Dim parts() As String = response.Split(New Char() {Chr(255)}, StringSplitOptions.RemoveEmptyEntries)
For Each p As String In parts
Debug.WriteLine(p)
Next
-
Re: SerialPort VB.NET : Write/buffer/timing and Data Received Event (VS2010 and VS200
Hi !
Testing this as soon as I can on the controler. I really like the thinking behind the split/parse action !
I hope I can be as good "a sponge" in the technical domain as usual to absorb all the knowledge and tricks you explained here along the topic ! ;)
-
Re: SerialPort VB.NET : Write/buffer/timing and Data Received Event (VS2010 and VS200
OK, it worked fine and for the first message (verify the state of the motion) it spared a trigger to the serialport data event.
-
Re: SerialPort VB.NET : Write/buffer/timing and Data Received Event (VS2010 and VS200
Hi Everybody,
I'm close to the final UI that I wanted with nearly everything functionning, so a big thank you to both persons participating and helping here !
I will put a screen capture of the UI with translated text (FR to ENG) to give an overview of where it is at now :)
Cheers,
-
Re: SerialPort VB.NET : Write/buffer/timing and Data Received Event (VS2010 and VS200
Well done, writing an interface for 1 or 2 servos is quite an achievement. I think the code provided by dbasnett is flexible enough to be adapted for further applications using the Newport controller. Your project has certainly held my interest and I am glad you have succeeded.
-
Re: SerialPort VB.NET : Write/buffer/timing and Data Received Event (VS2010 and VS200
Quote:
Originally Posted by
Mc_VB
Well done, writing an interface for 1 or 2 servos is quite an achievement...I am glad you have succeeded.
Agreed!!! Congrats. Remember to mark this resolved.
-
Re: SerialPort VB.NET : Write/buffer/timing and Data Received Event (VS2010 and VS200
Quote:
Originally Posted by
dbasnett
Agreed!!! Congrats. Remember to mark this resolved.
Thank you dbasnett and Mc_VB !
I've been asked to tweak some things and re arrange the interface a bit, so still working on it !
I'm facing another situation I'd like to put behind me :) :
Let's say there is a sequence of bytes (array) with only twice the double char "vbCrLf". How to handle the ENDOFARRAY with GetChars(byteArray,0, ENDOFARRAY) in the conversion between bytes and string of chars ?
I'd like to be sure I'm not letting more info than necessary in the converted string as I'm checking other things with it. Thus, I'd like to cut the conversion at the second vbCrLf index of the byte array.
From my point of view, I was thinking of something that would look for the vbCrLf and then choose the position of Lf with the greater index of the two.
-
Re: SerialPort VB.NET : Write/buffer/timing and Data Received Event (VS2010 and VS200
Quote:
Originally Posted by
LiamC
...From my point of view, I was thinking of something that would look for the vbCrLf and then choose the position of Lf with the greater index of the two.
Take a look at this code which is the code from the backgroundworker slightly modified to find the second LF. Note that I added some debug statements.
Code:
Dim idxLF As Integer = dataByts.IndexOf(LF) 'get the index of the first LF
If idxLF >= 0 AndAlso idxLF + 1 < dataByts.Count Then
Debug.WriteLine(idxLF)
'there is one LF and there might be another
idxLF = dataByts.IndexOf(LF, idxLF + 1) 'get the index of the second LF
Debug.WriteLine(idxLF)
If idxLF >= 0 Then
'do we have a second LF ?
'If yes, get the message from controller
Dim s As String
Threading.Monitor.Enter(dataLock)
s = System.Text.Encoding.GetEncoding(28591).GetChars(dataByts.ToArray, 0, idxLF - 1)
dataByts.RemoveRange(0, idxLF + 1) 'remove the message from the buffer
Threading.Monitor.Exit(dataLock)
'etc
End If
End If
-
Re: SerialPort VB.NET : Write/buffer/timing and Data Received Event (VS2010 and VS200
OK, thank you !
Didn't think that idxLf+1 "inside" the indexOf() was going to be the answer, will test that.
-
Re: SerialPort VB.NET : Write/buffer/timing and Data Received Event (VS2010 and VS200
Quote:
Originally Posted by
dbasnett
Take a look at this code which is the code from the backgroundworker slightly modified to find the second LF. Note that I added some debug statements.
Code:
Dim idxLF As Integer = dataByts.IndexOf(LF) 'get the index of the first LF
If idxLF >= 0 AndAlso idxLF + 1 < dataByts.Count Then
Debug.WriteLine(idxLF)
'there is one LF and there might be another
idxLF = dataByts.IndexOf(LF, idxLF + 1) 'get the index of the second LF
Debug.WriteLine(idxLF)
If idxLF >= 0 Then
'do we have a second LF ?
'If yes, get the message from controller
Dim s As String
Threading.Monitor.Enter(dataLock)
s = System.Text.Encoding.GetEncoding(28591).GetChars(dataByts.ToArray, 0, idxLF - 1)
dataByts.RemoveRange(0, idxLF + 1) 'remove the message from the buffer
Threading.Monitor.Exit(dataLock)
'etc
End If
End If
I don't get why there is a if index>=0 inside an IF statement that already has "IF index>=0" in it, because the index can only get larger with the line:
Code:
idxLF = dataByts.IndexOf(LF, idxLF + 1) 'get the index of the second LF
I'm asking that because I have an issue :
With the SECOND debug.writeline(idxLF) I sometimes get a value for the index = to “-1” which of course causes the program to stop as it isn’t >=0. This occurs when I click rapidly on my “VERIFY POSITION” button after the move is over (it's the button that triggers the response with coordinates in it). Whereas when I wait like 5sec, it doesn’t happen and I get the expected value (like 15 or 16, as it’s the index of the second vbCrLf of the return string).
-
Re: SerialPort VB.NET : Write/buffer/timing and Data Received Event (VS2010 and VS200
Quote:
Originally Posted by
LiamC
I don't get why there is a if index>=0 inside an IF statement that already has "IF index>=0" in it, because the index can only get larger with the line:
Code:
idxLF = dataByts.IndexOf(LF, idxLF + 1) 'get the index of the second LF
I'm asking that because I have an issue :
With the SECOND debug.writeline(idxLF) I sometimes get a value for the index = to “-1” which of course causes the program to stop as it isn’t >=0. This occurs when I click rapidly on my “VERIFY POSITION” button after the move is over (it's the button that triggers the response with coordinates in it). Whereas when I wait like 5sec, it doesn’t happen and I get the expected value (like 15 or 16, as it’s the index of the second vbCrLf of the return string).
The code is written this way because you wanted two LF's (two responses) before proceeding. There is nothing in the code to cause the program to stop that I can see. This assumes that you are testing what I posted.
-
Re: SerialPort VB.NET : Write/buffer/timing and Data Received Event (VS2010 and VS200
Quote:
Originally Posted by
dbasnett
The code is written this way because you wanted two LF's (two responses) before proceeding. There is nothing in the code to cause the program to stop that I can see. This assumes that you are testing what I posted.
Yes, that's exactly how it works.
The only worry is an index sometimes equal to -1 and I don't know where it comes from. Is it a default value when it cannot find a LF ?
If the only char is indeed a vbCrLf, the index would be 1 and will thus proceed the string, is it correct ?
-
Re: SerialPort VB.NET : Write/buffer/timing and Data Received Event (VS2010 and VS200
http://msdn.microsoft.com/en-us/library/e4w08k17.aspx
for your answer. Does the code provided supply a string with two responses?
-
Re: SerialPort VB.NET : Write/buffer/timing and Data Received Event (VS2010 and VS200
Quote:
Originally Posted by
dbasnett
Thanks for the link, I sometimes check on MSDN but did not have a look this time, my bad as the answer is quite clear: the "-1" as a result of IndexOf(LF) does come from the fact the second LF wasn't found in one response. I think I have to look back to the changes I made to your code (I think it was around the part where there was the WaitOne() in an Else condition/loop: waiting for enough data). I may have made a mistake with a tweak. This error does not occur often, that's why it's bugging me...It may come from a string length change or something like that, because I can go through 20 steps of the loops before the "-1" is returned.
-
Re: SerialPort VB.NET : Write/buffer/timing and Data Received Event (VS2010 and VS200
Remember that you will receive the data you expect in pieces normally. This goes back to what we discussed near the beginning of this thread.
-
Re: SerialPort VB.NET : Write/buffer/timing and Data Received Event (VS2010 and VS200
Hi !
I'm still within the subject of this thread but on slightly different things, so I'm posting this here:
I have a form (form1.vb) with 2 buttons, the first button (let's say it's called btnMOVE) runs on UI thread and is doing several small operations. The second button (btnIMAGE) runs on the "worker" thread (GRABthread) which starts when I click on this button.
In the GRAB thread, a longer , heavier operation is performed. I managed to update the status of controls (buttons/textbox) with this kind of code (here it can pass a button from enabled state to disabled and also from disabled to enabled):
Code:
Delegate Sub ChangeStatusBtnDel (ByVal btn As Button, ByVal Bool3 As Boolean)
Code:
Public sub ChangeStatusOfBtn (ByVal btn As Button, ByVal Bool3 As Boolean)
If btn.InvokeRequired Then
Dim BTNDel As New ChangeStatusOfBtnDel (AddressOf ChangeStatusOfBtn)
Me.invoke (BTNDel, New Object() {btn, Bool3})
Else
btn.Enabled=Bool3
End If
End Sub
And then I call the method with the 2 arguments (nameof button, state I want it to be (True/False) ).
Now here's my issue at the moment:
I have another form (progressdialog.vb) containing a progressbar in a indeterminate mode :
Code:
progresbar1.style= Progressbar1.marquee
This is then supposed to be shown as a dialogbox (showdialog() ) during the worker thread running (GRABthread) in order to prevent a user to click on the form while the 2nd thread is running and to display information about its "occupied state" (and show the user it is running and that nothing has crashed or stopped)
As it's done from another thread, I need to close this form (and the progressbar) when the GRABthread finishes. I haven't succeeded in doing so. I tried this to no avail:
Code:
Progresdialog.Invoke(New Action(AddressOf Progressdialog.close))
The error is (translation from FR to ENGLISH) : "impossible to call invoke or beginInvoke on a control as long as the handle of the window has not been created".
Whereas this worked:
Code:
Me.Invoke(New MethodInvoker (AddressOf Me.close))
And closed all the opened forms.
What is required to have a close action on a specific form (shown as dialogbox) from another thread ?
-
Re: SerialPort VB.NET : Write/buffer/timing and Data Received Event (VS2010 and VS200
Ok, my bad...
I created the form ProgressDialog.vb and did not have that line in the code !!!
Code:
Dim ProgForm as New ProgressDialog
Of course, now this:
Code:
ProgForm.Invoke ( New MethodInvoker(AddressOf ProgForm.Close))
is working....
-
Re: SerialPort VB.NET : Write/buffer/timing and Data Received Event (VS2010 and VS200
Hi again :)
I have another question:
If I have to restart a task by clicking the same button again (and several times) how to manage the thread.start part ? To take the above example, a button starts a task, at some point we move to another thread to perform another task. but I need to perform this task several times, so let's says I need the operator to click again on the same button. So the sequence finds the thread.start() line again, dnd the error thrown is that it cannot (RE)start a thread that has stopped.
-
Re: SerialPort VB.NET : Write/buffer/timing and Data Received Event (VS2010 and VS200
We are off topic and a new thread should be started in the forum. You can reference this thread if needed. Take a look at the following code(create a new project with one button):
Code:
Dim somethd As Threading.Thread
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Button1.Enabled = False
If IsNothing(somethd) OrElse Not somethd.IsAlive Then
somethd = New Threading.Thread(AddressOf something)
somethd.IsBackground = True
somethd.Start()
Else
Stop 'should not happen
End If
End Sub
Dim anotherthrd As Threading.Thread
Private Sub something()
Debug.WriteLine("1")
'simulate some long running
Threading.Thread.Sleep(2000) '2 seconds
'end simulation
anotherthrd = New Threading.Thread(AddressOf another)
anotherthrd.IsBackground = True
anotherthrd.Start()
anotherthrd.Join() 'wait for other thread to end
Debug.WriteLine("4")
somethingended()
End Sub
Private Sub another()
Debug.WriteLine("2")
'simulate some long running
Threading.Thread.Sleep(2000) '2 seconds
'end simulation
Debug.WriteLine("3")
End Sub
Delegate Sub somethingendeddel()
Private Sub somethingended()
Debug.WriteLine("5")
If Me.InvokeRequired Then
Me.Invoke(New somethingendeddel(AddressOf somethingended))
Else
Button1.Enabled = True
End If
End Sub
-
Re: SerialPort VB.NET : Write/buffer/timing and Data Received Event (VS2010 and VS200
Quote:
Originally Posted by
dbasnett
We are off topic and a new thread should be started in the forum. You can reference this thread if needed. Take a look at the following code(create a new project with one button):
Code:
Dim somethd As Threading.Thread
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Button1.Enabled = False
If IsNothing(somethd) OrElse Not somethd.IsAlive Then
somethd = New Threading.Thread(AddressOf something)
somethd.IsBackground = True
somethd.Start()
Else
Stop 'should not happen
End If
End Sub
Dim anotherthrd As Threading.Thread
Private Sub something()
Debug.WriteLine("1")
'simulate some long running
Threading.Thread.Sleep(2000) '2 seconds
'end simulation
anotherthrd = New Threading.Thread(AddressOf another)
anotherthrd.IsBackground = True
anotherthrd.Start()
anotherthrd.Join() 'wait for other thread to end
Debug.WriteLine("4")
somethingended()
End Sub
Private Sub another()
Debug.WriteLine("2")
'simulate some long running
Threading.Thread.Sleep(2000) '2 seconds
'end simulation
Debug.WriteLine("3")
End Sub
Delegate Sub somethingendeddel()
Private Sub somethingended()
Debug.WriteLine("5")
If Me.InvokeRequired Then
Me.Invoke(New somethingendeddel(AddressOf somethingended))
Else
Button1.Enabled = True
End If
End Sub
Thank you, this helped especially this " If IsNothing(somethd) OrElse Not somethd.IsAlive Then" !
-
Re: [RESOLVED] SerialPort VB.NET : Write/buffer/timing and Data Received Event (VS201
Great topic, could post final code for study LiamC ?
Thanks
-
Re: [RESOLVED] SerialPort VB.NET : Write/buffer/timing and Data Received Event (VS201
dbasnett,
First of all I would like to thank you. I have been programming for a few years now and I feel I have learned more from reading your posts on this thread regarding serial communications than I have in all my years of programming. I am new to this forum so forgive me if this post would be better served in a new thread, but I am using your base code that you provide for this example and I am running into a few minor problems that I was hoping you could help me with. I will start by just explaining the problems and if needed I can post my code, but first I will provide some details on my setup.
I am communicating with approximately 12 different devices over RS485. These devices are from 4 different manufacturers, so they each have slightly different timings in terms of how long it takes them to respond to a specific message. The way I would like this program to work would be to constantly send commands to these devices and once a response is received, send the next command in line. I would like this to happen indefinitely until I manually end the communications. This constant communication would run normally for approximately 7 days at a time before it would be ended, and its very important that if any interruption in communication occurs, it resume immediately.
1. The first problem is similar to a problem that i believe LiamC had at some point. I can communicate no problem with any one of these devices at a time using a single command. When I try to add in multiple commands, sometimes the communication just stops, and I believe this is due to timing on the devices response, because I can get rid of this issue by placing a system.threading.thread.sleep(20) command before I call the cmdDone.Set. I also believe this is the case because on another type of device this issue doesn't exist, even if I send 20 or 30 commands at a time, but this devices response time is much quicker than the device I am having issues with. I can live with using this delay, however, the way I understand the code is that this timing should not matter, because I am sending a command, waiting for a response, dealing with that response, and then sending the next command. I also can't figure out an efficient way for these communications to resume once they cease up.
2. The second problem I am having is related to how to handle to responses of the data. This is easy when you just have one set of data coming in and you can place all of the data into a textbook or a richtextbox, but how would you suggest placing the data into specific controls, for example the result of the first command needs to be in textbook 1, and the result of the second command needs to be in textbook 2 and so on...I am handling this fine now using a variable that is related to the send command so based on which command I receive it handles the data accordingly and so far no issues, however, I don't believe this is the best way to handle this, because I am assuming the commands will always be sent in the exact order which makes me a little nervous when the communications are interrupted.
Again,
Thanks dbasnett. I have learned a lot from you and hope to continue to do so.