VB 2005 and BS2 -- why won't the signal stop after I close connection?
Here's a pretty basic question with probably a very easy answer.
I'm using the BoE - USB version
End goal: capture impressions from a press. The press will close a circuit each time there's an impression.
Currently, I'm simulating my press w/ one BS2 with the following code:
When I click "Stop," however, the counter in my program stops, but the red light keeps blinking telling me that the BoE is still sending the signal to the app. How do i tell the BS2 to stop running the code OR tell it to stop sending the info to through to the USB port?
Any help would be greatly appreciated - my more complex app is crashing when i hit stop if i keep sending a signal to the computer (impressions are still occurring), even if I 'Close' the connection...
I'm stuck.
TIA!
I'm using the BoE - USB version
End goal: capture impressions from a press. The press will close a circuit each time there's an impression.
Currently, I'm simulating my press w/ one BS2 with the following code:
' {$STAMP BS2}
' {$PBASIC 2.5}
Flash: 'subroutine labeled Flash
DEBUG "*"
HIGH 1 'turn on
PAUSE 20
LOW 1 'turn off
PAUSE 313 'wait 1/3 second
GOTO Flash 'go back to the rest of the program
and the second BS2 is capturing it that signal like so:
' {$STAMP BS2}
' {$PBASIC 2.5}
btnwrk VAR Byte
Btn PIN 0
Main:
BUTTON Btn, 1, 255, 20, btnwrk, 0, No_Press : DEBUG "*" 'send * to output for each impression
No_Press:
GOTO Main 'Start back at the beginning
I've got a simple VB .NET app that i'm using for testing:
Imports System
Imports System.IO.Ports.SerialPort
Imports System.IO.Ports
Imports System.Threading
Public Class Form1
Delegate Sub SetTextCallback(ByVal [text] As String) 'to change the text of Pause button w/o errors
Public WithEvents COMPort As New System.IO.Ports.SerialPort
Public Counter As Integer = 0
Public PortAvailable As Boolean = False
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
Dim ports As String() = GetPortNames()
' Check each available COM port for specified port
Dim port As String
For Each port In ports
If port = "COM5" Then
COMPort.PortName = "COM5"
COMPort.BaudRate = 2400
COMPort.DataBits = 8
COMPort.Parity = IO.Ports.Parity.None
COMPort.StopBits = IO.Ports.StopBits.One
PortAvailable = True
End If
Next port
If PortAvailable Then
Else
MsgBox("COM5 not available")
End
End If
End Sub
Private Sub SerialPort_DataReceived(ByVal sender As Object, ByVal e As System.IO.Ports.SerialDataReceivedEventArgs) Handles COMPort.DataReceived
Counter += 1
Call updateText(Counter)
If Counter Mod 200 = 0 Then
COMPort.Close()
COMPort.Open()
End If
End Sub
Private Sub updateText(ByVal [Text] As String)
If Me.lblComOut.InvokeRequired Then
Dim d As New SetTextCallback(AddressOf updateText)
Me.Invoke(d, New Object() {[Text]})
Else
Me.lblComOut.Text = [Text]
End If
End Sub
Private Sub btnOpen_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnOpen.Click
If COMPort.IsOpen = False Then
COMPort.Open()
End If
End Sub
Private Sub btnClose_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnClose.Click
If COMPort.IsOpen = True Then
COMPort.Close()
End If
End Sub
End Class
Currently, when I start the program up, I have to click start to start receiving the signal - perfect.When I click "Stop," however, the counter in my program stops, but the red light keeps blinking telling me that the BoE is still sending the signal to the app. How do i tell the BS2 to stop running the code OR tell it to stop sending the info to through to the USB port?
Any help would be greatly appreciated - my more complex app is crashing when i hit stop if i keep sending a signal to the computer (impressions are still occurring), even if I 'Close' the connection...
I'm stuck.
TIA!

Comments
Otherwise send a message to STAMP2 when you click the Stop button. Stamp 2 will need to look for the message and turn off/on accordingly.
additionally, if i do just "turn off the stamp," when i turn it back on, it goes right back to what it was doing. The only way to get it to stop is to unplug the usb cable, and plug it back in.
what is the code to turn off / on the stamp? that is more or less what i'm looking for.
Jeff T.
As a complete self-proclaimed rookie, and being under a relative time-crunch, how would i do something like the following:
IF SERIN ... [DEC 1]
loop and output for each impression -- probably use similar BUTTON code that i currently have
UNTIL SERIN [DEC 2]
basically, once it receives a 1, look for button presses until it receives a 2, then wait for the next 1...
Any push in the right direction (or flat out code) would be greatly appreciated... they're wanting this thing done as quick as possible (and they asked the new guy whom they knew had no experience with EEPROMs to do it..)
EDIT:
forgot to mention that i've looked at the Nuts & Volts chapter on Serin & Serout dmystified, as well as several other pages, but am running out of time on this.. I am trying to learn, promise!
' {$STAMP BS2p} ' {$PBASIC 2.5} result VAR Byte ' Initialize to ASCII "0" result = $30 Main: ' Wait 5 seconds for inout from the PC ' jump to no data if we timeout ' else send an acknowledge "!" to let the PC know we ' received the data. ' Also echo the command. SERIN 16, 1021, 5000, No_Data, [result] SEROUT 16, 1021, ["!"] SEROUT 16, 1021, [result] No_Data: 'Process if result equals "1" or ASCII $31 IF result = $31 THEN SEROUT 16, 1021, ["HELLO", CR] ENDIF GOTO MainThe VB logic needs to resend 0x30 (anything other than 0x31) if the acknowledge character is not received within some period of time (timeout). Once "!" is received then proceed to close the port. The STAMP does not handle parallel tasks. It could be working on something else when the VB app sends the stop command.
When you open the port, send 0x31 until the "!" is received.
Notice the PBasic logic is echoing the command. That's because you're listening for the Data_ Received event which is executing on a secondary thread. When you see a "!" the next byte is the last command. I'd roll up a listener (delegate) in the button close/open event and fire off an event when the "!" is received. You can also save the state of which button was pressed, then when you see the "!", read the state and handle.
You could poll the serial port over using the SerialPort.DataReceived event. Polling will be a little easier.
[Edit]: This is .NET source I used for testing cross platform serial port communication. It uses a timer to poll the serial port because Mono (on Linux) does not implement the DataReceived event. It's C# though.
Private Sub SerialPort_DataReceived(ByVal sender As Object, ByVal e As System.IO.Ports.SerialDataReceivedEventArgs) Handles COMPort.DataReceived Counter += 1 Call updateText(Counter) If Counter Mod 200 = 0 Then COMPort.Close() COMPort.Open() End If End SubI'm guessing that you're closing the port after 200 DataReceived events to clear the receive buffer? You're asking for trouble. Also there is not guarantee that impression count = DataReceived count. Consider reading the buffer and making a decision on the data received.
Thanks again for all the help! again, being a rookie in a new game is always difficult.
Anyway, the .NET and PBasic code provided has what you need to complete the project. Did you, by chance, run the code?
If I run into anything else, I'll post back.
again, the help is MUCH appreciated!
EDIT - I got pulled onto a more pressing project -- i haven't been working on this non-stop since my last post.. just throwin' that out there...
here's my stop code, though:
Private Sub btnStop_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnStop.Click Dim wrt As Byte = 0 If COMPort.IsOpen = True Then While (True) COMPort.WriteLine(wrt) Thread.Sleep(50) If COMPort.ReadExisting.ToString.Contains("!") Then Exit While End While COMPort.Close() End If End Suband here's my BASIC stamp:
' {$STAMP BS2} ' {$PBASIC 2.5} result VAR Byte recdResult VAR Byte result2 VAR Byte btnwrk VAR Byte Btn PIN 0 red PIN 10 green PIN 11 result = 0 result2 = 1 ' Flash LEDs HIGH red PAUSE 250 LOW red PAUSE 250 HIGH green PAUSE 250 LOW green Main: SERIN 16, 16468, 2, StartCounting, [DEC result] recdResult = result result = 0 SEROUT 16, 16468, ["!"] StartCounting: 'Process if result equals "1" or ASCII $31 IF recdResult = 1 THEN LOW red HIGH green 'SEROUT 16, 1021, [38] BUTTON Btn, 1, 255, 20, btnwrk, 0, No_Press : DEBUG "*" 'send * to output for each impression No_Press: GOTO Main ENDIF IF recdResult = 0 THEN LOW green HIGH red 'SEROUT 16, 16468, ["!"] ENDIF GOTO MainAny thoughts as to what may causing this, and a good solution to bypass it w/out a msgbox? I've tried a thread.sleep(4000), but it doesn't help... I'm sure i could do a loop for a few seconds, but that seems like a bad work-around.
Thanks!
I'm guessing you're having a problem understanding multi-threaded applications. It's hard to tell with out seeing all your code.
Change the baud to 2400 max (16780) and remove the DEC formatter from [DEC result].
Imports System Imports System.IO.Ports.SerialPort Imports System.IO.Ports Imports System.Threading Public Class Form1 Delegate Sub SetTextCallback(ByVal [text] As String) 'to change the text with threadging Public WithEvents COMPort As New System.IO.Ports.SerialPort Public Counter As Integer = 0 Public PortAvailable As Boolean = False Public StampReturned As String = "" Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load Dim ports As String() = GetPortNames() Dim com As String = "COM4" ' Check each available COM port for specified port Dim port As String For Each port In ports If port = com Then COMPort.PortName = com COMPort.BaudRate = 9600 COMPort.DataBits = 8 COMPort.Parity = IO.Ports.Parity.None COMPort.StopBits = IO.Ports.StopBits.One PortAvailable = True End If Next port If PortAvailable Then Else MsgBox(com & " not available") End End If End Sub Private Sub SerialPort_DataReceived(ByVal sender As Object, ByVal e As System.IO.Ports.SerialDataReceivedEventArgs) Handles COMPort.DataReceived If COMPort.ReadExisting.ToString.Contains("!") = False Then Call updateText2(COMPort.ReadExisting.ToString) Counter += 1 Call updateText(Counter) If Counter Mod 200 = 0 Then COMPort.DiscardInBuffer() COMPort.DiscardOutBuffer() End If End If End Sub Private Sub updateText(ByVal [Text] As String) If Me.lblComOut.InvokeRequired Then Dim d As New SetTextCallback(AddressOf updateText) Me.Invoke(d, New Object() {[Text]}) Else Me.lblComOut.Text = [Text] End If End Sub Private Sub updateText2(ByVal [Text] As String) If Me.TextBox1.InvokeRequired Then Dim d As New SetTextCallback(AddressOf updateText2) Me.Invoke(d, New Object() {[Text]}) Else Me.TextBox1.Text = [Text] End If End Sub Private Sub btnStop_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnStop.Click Dim wrt As Byte = 0 If COMPort.IsOpen = True Then While (True) COMPort.WriteLine(wrt) Thread.Sleep(5) If COMPort.ReadExisting.ToString.Contains("!") Then Exit While End While 'Thread.Sleep(2000) If COMPort.IsOpen = True Then MsgBox("here") COMPort.Close() End If End If End Sub Private Sub btnGo_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnGo.Click If COMPort.IsOpen = False Then COMPort.Open() End If Dim wrt As Byte = 1 If COMPort.IsOpen = True Then While (True) COMPort.WriteLine(wrt) Thread.Sleep(5) If COMPort.ReadExisting.ToString.Contains("!") Then Exit While End While End If End Sub End Classand the stamp:
' {$STAMP BS2} ' {$PBASIC 2.5} result VAR Byte recdResult VAR Byte result2 VAR Byte btnwrk VAR Byte Btn PIN 0 red PIN 10 green PIN 11 result = 0 result2 = 1 ' Flash LEDs HIGH red PAUSE 250 LOW red PAUSE 250 HIGH green PAUSE 250 LOW green Main: SERIN 16, 16468, 2, StartCounting, [DEC result] recdResult = result result = 0 SEROUT 16, 16468, ["!"] 'message received StartCounting: 'Process if result equals "1" or ASCII $31 IF recdResult = 1 THEN LOW red HIGH green 'SEROUT 16, 1021, [38] BUTTON Btn, 1, 255, 20, btnwrk, 0, No_Press : SEROUT 16, 16468, ["*"] 'send * to output for each impression No_Press: GOTO Main ENDIF IF recdResult = 0 THEN LOW green HIGH red ENDIF GOTO MainEverything is working as expected now, except the stop - I'll look more into the multi-threading, as i agree that this is probably where i'm having my issues.
like i said, the counter works as expected, just closing the connection doesn't... if I comment out the "COMPort.Close()" line, it works fine, still... but wouldn't that be bad form to leave the connection open like that? seems like a bad idea. I'd much rather open and close the connection for each use.
As far as 2010, i'm pretty sure we have a copy i can use for testing under our ActionPack. I'll check. and converting from C# to VB.NET isn't an issue...
Thanks again for all your help.
1) Counter is counting the number of DataReceived events not the number of impressions from a press!
2) You're receiving data but not reading the data, just plopping it on the screen.
3) The DataReceived handler is operating on a secondary thread while the btnStop_Click handler is invoked for the primary thread.
Clicking the Stop button invokes a write to the serial port from the primary thread. The primary is put to sleep for 5ms but DataReceived handler is not asleep!
for example
Dim Port_Closing As Boolean=True
When you open the port:-
Port_Closing=False
In you Data Received event:-
If Not Port_Closing Then
****Do your receiving here****
End If
And when you close the port:
Port_Closing=True
add a short delay here to allow time for everything to finish
Jeff T.
2) This is my test app - I don't actually care "what" the information is during the DataRecieved handler - but if there is data recieved, i'm counting it as an impression, adding 1 to a variable, then every 250, writing it out to a database, with a final count written out when the stop button is pushed. - the data doesn't have to be perfect, but it needs to be closer than what they're getting now (which isn't counting any waste at all...)
3) -- let's focus on this one, as it appears to be the bulk of the issue. I'm not very familiar with threading, so my question is how do you know that it's on a secondary thread? Any thoughts on how I would resolve this mistake?
I tried your suggestion w/ the PortClosing boolean, but it still locks, even with a 5 second sleep after i set the boolean to true and before i attempt to close the port.
Private Sub SerialPort_DataReceived(ByVal sender As Object, ByVal e As System.IO.Ports.SerialDataReceivedEventArgs) Handles COMPort.DataReceived If COMPort.ReadExisting.ToString.Contains("!") = False And PortClosing = False Then Call updateText2(COMPort.ReadExisting.ToString) Counter += 1 Call updateText(Counter) If Counter Mod 200 = 0 Then COMPort.DiscardInBuffer() COMPort.DiscardOutBuffer() End If ElseIf PortClosing = True Then COMPort.DiscardInBuffer() COMPort.DiscardOutBuffer() End If End Sub Private Sub btnStop_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnStop.Click Dim wrt As Byte = 0 If COMPort.IsOpen = True Then While (True) COMPort.WriteLine(wrt) Thread.Sleep(5) If COMPort.ReadExisting.ToString.Contains("!") Then Exit While End While PortClosing = True Thread.Sleep(5000) If COMPort.IsOpen = True Then 'MsgBox("here") COMPort.Close() End If End If End Sub Private Sub btnGo_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnGo.Click PortClosing = False {snip} End Subi'm sure it's still the multi-threading issue - i just don't know how to resolve it.
Thanks.
Remember to assign the COMPort.DataReceived delegate to SerialPort_DataReceived when the Open button is clicked.