hsano6294
asked on
Reading asynchronous serial port data in VB 2005
Hello everyone,
I'm developing a driver that sends out text commands via serial port to an instrument. When that instrument is finished executing the command, or an error results, it will send back a text result. I expect this message will be less than 15 characters long.
1) I'm able to send out the commands and have the instrument respond, but am having difficulty capturing the Event and the message, as I'm new to Serial Communication and Event Handling. I've attached the code I've written.
2) What is the best way to wait for a response, with a given timeout value? Each command should be followed by a response, successful or not.
3) Is it better to open the COM port once or open and close it before/after each command?
Thanks!
Haj
I'm developing a driver that sends out text commands via serial port to an instrument. When that instrument is finished executing the command, or an error results, it will send back a text result. I expect this message will be less than 15 characters long.
1) I'm able to send out the commands and have the instrument respond, but am having difficulty capturing the Event and the message, as I'm new to Serial Communication and Event Handling. I've attached the code I've written.
2) What is the best way to wait for a response, with a given timeout value? Each command should be followed by a response, successful or not.
3) Is it better to open the COM port once or open and close it before/after each command?
Thanks!
Haj
Module Module1
Sub Main()
Dim strCommand As String
Dim CtrlJ As New Char
Dim strReset As String ' Reset command
Dim strPlateRequest As String ' Plate request command
Dim strPlateReturn As String ' Plate return command
Dim strReturnValue As String ' Post-command status returned from Q-Stack
' Commands have a <LF> (Ctrl-J or ASCII (10)) before and after.
CtrlJ = Chr(10) ' Ctrl-J = Linefeed (ASCII)
strReset = CtrlJ & "AK5=1" & CtrlJ
strPlateRequest = CtrlJ & "AK3=1" & CtrlJ
strPlateReturn = CtrlJ & "AK4=1" & CtrlJ
strCommand = strReset ' Subsitute any of the commands for testing purposes
OutToCOM4(strCommand, False)
strReturnValue = ""
InFromCOM4(strReturnValue) ' Wait for status from instrument before proceeding
MsgBox(strReturnValue)
End Sub
Public Sub OutToCOM4(ByVal serialData As String, _
ByVal useLineTermination As Boolean)
Dim com4Port As IO.Ports.SerialPort = Nothing
Try
' ---- Access the port.
com4Port = My.Computer.Ports.OpenSerialPort("COM4", 9600, IO.Ports.Parity.None, 8, IO.Ports.StopBits.One)
' COM Port, baud rate, parity, data bits, stop bits
' ---- Write the data.
If (useLineTermination = True) Then
com4Port.WriteLine(serialData)
Else
com4Port.Write(serialData)
End If
' ---- Finished with the port.
com4Port.Close()
Catch ex As Exception
MsgBox("Error writing data to serial port: " & _
ex.Message)
Finally
If (com4Port IsNot Nothing) Then com4Port.Dispose()
com4Port = Nothing
End Try
End Sub
Public Sub InFromCOM4(ByVal returnData As String)
Dim com4Port As IO.Ports.SerialPort = Nothing
Try
' ---- Access the port.
com4Port = My.Computer.Ports.OpenSerialPort("COM4", 9600, IO.Ports.Parity.None, 8, IO.Ports.StopBits.One)
' COM Port, baud rate, parity, data bits, stop bits
' ---- Wait for incoming data.
'--->>> What is the best way to wait for incoming data? <<<---
' ---- Read the data.
'--->>> returnData = com4Port.??? ' How do I capture the incoming data? <<<---
' ---- Finished with the port.
com4Port.Close()
Catch ex As Exception
MsgBox("Error reading data from serial port: " & _
ex.Message)
Finally
If (com4Port IsNot Nothing) Then com4Port.Dispose()
com4Port = Nothing
End Try
End Sub
End Module
ASKER
AkisC,
Sorry for the delay. The production system just became available to me.
1) Can your DataReceived subroutine handle ReadLine as well as ReadByte?
2) What do I put in my main routine that sent out my WriteLine string and is waiting for the response? The response may take as long as 45 seconds before the mechanical components finish moving. Do I put the main program in a loop waiting for the event? And does the serial port need to be declared with a special option to handle the event?
Thanks!
Haj
Sorry for the delay. The production system just became available to me.
1) Can your DataReceived subroutine handle ReadLine as well as ReadByte?
2) What do I put in my main routine that sent out my WriteLine string and is waiting for the response? The response may take as long as 45 seconds before the mechanical components finish moving. Do I put the main program in a loop waiting for the event? And does the serial port need to be declared with a special option to handle the event?
Thanks!
Haj
ASKER CERTIFIED SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
ASKER
Thanks for your help AkisC. My apologies- the system just deployed to the customer and we are in the middle of final integration and installation. I used portions of your suggestions in the final solution. There were additional issues that arose related to how the instrument communicates with its own internal components.
I have attached key portions of the code.
Thanks again, and my apologies for not posting this in a more timely manner.
I have attached key portions of the code.
Thanks again, and my apologies for not posting this in a more timely manner.
Private WithEvents _serialPort As IO.Ports.SerialPort
Friend Function Send(ByVal Data As String) As String
' Function will return to calling method as soon as it receives the processed return message.
Dim returnMessage As String = String.Empty
Try
'Read the port buffer, timeout is set in New
Dim received As String = String.Empty
Try
_serialPort.Write(Data)
' Read incoming reply
Dim incomingMessage As String = String.Empty
Dim _continue As Boolean = True
Do
Thread.Sleep(30) ' Wait 30 msec before checking cmdIndex
If cmdIndex = 0 Then 'key at beginning, received processed message from DataReceived
returnMessage = inMessageBuffer
Return returnMessage ' Return before another incoming message disrupts things
_continue = False
End If
Loop While (_continue)
Catch ex As Exception
'return has timed out - received will be blank
Throw
End Try
Catch ex As Exception
Throw
End Try
Return returnMessage
End Function
-------------------------------
' Event Handler for incoming data
Private Sub DataReceived( _
ByVal sender As Object, _
ByVal e As System.IO.Ports.SerialDataReceivedEventArgs) _
Handles _serialPort.DataReceived
Dim ValidMessage As Boolean = False
inMessage = _serialPort.ReadLine
inMessageBuffer = String.Empty
cmdIndex = -999
' Dim key As String = "P"
cmdIndex = inMessage.IndexOf(cmdKey)
'If cmdIndex < 0 Then ' key not found, check if valid reply is embedded
If (inMessage.Contains("PDCOMP")) Then ' Destack complete
inMessageBuffer = "PDCOMP"
cmdIndex = 0
ValidMessage = True
ElseIf (inMessage.Contains("PMCOMP")) Then ' MoveToStation or ReRead complete
inMessageBuffer = "PMCOMP"
cmdIndex = 0
ValidMessage = True
ElseIf ' check for other valid return messages
End If
'End If
If (ValidMessage) Then
ClosePort() ' Call ClosePort to immediately close serial port and prevent additional traffic from interrupting post-processing.
End If
End Sub
-------------------------------
Friend Sub ClosePort()
Try
'Close serial port
If (_serialPort IsNot Nothing) AndAlso _serialPort.IsOpen Then
_serialPort.Close()
Else
' Port is not open
End If
Catch ex As Exception
Throw
End Try
End Sub
Hi hsano6294
Nice you got it working!
If you face any issues let me know
Nice you got it working!
If you face any issues let me know
Let's say you have named your SerialPort control mySerialPort
You capture the data within the DataReceived sub
Open in new window