Still celebrating National IT Professionals Day with 3 months of free Premium Membership. Use Code ITDAY17

x
?
Solved

VB.NET - SerialPort - Trouble with thread delegation with controls

Posted on 2011-03-24
3
Medium Priority
?
1,159 Views
Last Modified: 2012-05-11
I have been trying to program an interface to a serial controller.  This program will send a series of commands to the controller, waiting for each response and execute code based on the response of the controller.  I am getting the following error then the program received the second of four responses from the controller.  I think it has to do with the thread delegation but I am not sure how to fix it.  PLEASE HELP!

System.IndexOutOfRangeException was unhandled
  Message="Index was outside the bounds of the array."
  Source="System.Windows.Forms"
  StackTrace:
       at System.Windows.Forms.Control.MarshaledInvoke(Control caller, Delegate method, Object[] args, Boolean synchronous)
       at System.Windows.Forms.Control.Invoke(Delegate method, Object[] args)
       at WindowsApplication2.Form1.SerialPort1_DataReceived(Object sender, SerialDataReceivedEventArgs e) in C:\Users\tnowacoski\Documents\My Projects\WindowsApplication2\WindowsApplication2\Form1.vb:line 50
       at System.IO.Ports.SerialPort.CatchReceivedEvents(Object src, SerialDataReceivedEventArgs e)
       at System.IO.Ports.SerialStream.EventLoopRunner.CallReceiveEvents(Object state)
       at System.Threading._ThreadPoolWaitCallback.WaitCallback_Context(Object state)
       at System.Threading.ExecutionContext.runTryCode(Object userData)
       at System.Runtime.CompilerServices.RuntimeHelpers.ExecuteCodeWithGuaranteedCleanup(TryCode code, CleanupCode backoutCode, Object userData)
       at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state)
       at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
       at System.Threading._ThreadPoolWaitCallback.PerformWaitCallbackInternal(_ThreadPoolWaitCallback tpWaitCallBack)
       at System.Threading._ThreadPoolWaitCallback.PerformWaitCallback(Object state)

Here is the code:
Public Class Form1
    Dim tTicks As Integer
    Public Delegate Sub SerialDelegate()


    Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
        Dim SawPrintText() As String = txtScan.Text.Split(",")
        lblTopRail.Text = SawPrintText(9)
        lblBottomRail.Text = SawPrintText(10)
        btnPrint.Focus()
    End Sub

    Private Sub btnPrint_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnPrint.Click
        If SerialPort1.IsOpen Then
            SerialPort1.Close()
        End If
        Try
            With SerialPort1
                .PortName = "COM3"
                .BaudRate = 115000
                .Parity = IO.Ports.Parity.None
                .DataBits = 8
                .StopBits = IO.Ports.StopBits.One
            End With
            SerialPort1.Open()
            lblReady.Text = "Setting Up Printer - Wait!"
            Timer1.Interval = 1000
            Timer1.Enabled = True
        Catch ex As Exception
        End Try
        SerialSend("01")
    End Sub

    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        tTicks = 0
    End Sub

    Private Sub Timer1_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Timer1.Tick
        If tTicks < 10 Then
            tTicks = tTicks + 1
            txtTimer.Text = tTicks
        Else
            Timer1.Stop()
            Timer1.Enabled = False
        End If

    End Sub

    Private Sub SerialPort1_DataReceived(ByVal sender As Object, ByVal e As System.IO.Ports.SerialDataReceivedEventArgs) Handles SerialPort1.DataReceived
        chkStatus.Invoke(New SerialDelegate(AddressOf ProcessResponse), New Object() {})
    End Sub

    Private Sub ProcessResponse()
        Dim strResponse() As String = SerialPort1.ReadExisting.Split(",")
        If strResponse(1) = "0" Then
            Select Case strResponse(0)
                Case "01"
                    chkStatus.SetItemChecked(0, True)
                    SerialSend("30,1,0," & lblTopRail.Text)
                Case "30"
                    If strResponse(2) = "1" Then
                        chkStatus.SetItemChecked(1, True)
                        SerialSend("30,2,0," & lblBottomRail.Text)
                    ElseIf strResponse(2) = "2" Then
                        chkStatus.SetItemChecked(2, True)
                        SerialSend("07,1")
                    End If
                Case "07"
                    chkStatus.SetItemChecked(3, True)
                    SerialPort1.Close()
            End Select
        End If
    End Sub

    Private Sub SerialSend(ByVal SStr As String)
        Try
            SerialPort1.Write(SStr & vbCr)
        Catch ex As Exception

        End Try
    End Sub
End Class

Open in new window

0
Comment
Question by:tnowacoski
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 2
3 Comments
 
LVL 86

Expert Comment

by:Mike Tomlinson
ID: 35207065
Most likely the response was not what you expected.

At this line, you split, producing an array:

    Dim strResponse() As String = SerialPort1.ReadExisting.Split(",")

Down below you are assuming that it actually has certain indexes...attempting to access both index 1 and 2.

Use code like this to see if you can narrow down the problem:
Private Sub ProcessResponse()
        Dim response As String = SerialPort1.ReadExisting
        Dim strResponse() As String = response.Split(",")
        If strResponse.GetUpperBound(0) >= 1 Then
            If strResponse(1) = "0" Then
                Select Case strResponse(0)
                    Case "01"
                        chkStatus.SetItemChecked(0, True)
                        SerialSend("30,1,0," & lblTopRail.Text)

                    Case "30"
                        If strResponse.GetUpperBound(0) >= 2 Then
                            If strResponse(2) = "1" Then
                                chkStatus.SetItemChecked(1, True)
                                SerialSend("30,2,0," & lblBottomRail.Text)
                            ElseIf strResponse(2) = "2" Then
                                chkStatus.SetItemChecked(2, True)
                                SerialSend("07,1")
                            End If
                        Else
                            MessageBox.Show("No strResponse(2): " & response, "Unexpected input")
                        End If

                    Case "07"
                        chkStatus.SetItemChecked(3, True)
                        SerialPort1.Close()

                End Select
            End If
        Else
            MessageBox.Show("No strResponse(1): " & response, "Unexpected input")
        End If
    End Sub

Open in new window

0
 

Author Comment

by:tnowacoski
ID: 35209542
Thanks!  Was looking at that with a blind eye!
I will bump the points up to 500 if you can answer this?  Looking at the following code, everything works as expected but the program hangs on SerialPort1.Close(), no exceptions are caught.   Any ideas?

Imports System.Threading
Imports System
Imports System.IO
Imports System.Data

Public Class Form1
    Dim tTicks As Integer
    Private _flash As Boolean = False
    Private filePath As String = "C:\SawPrint.Log"
    Private fileStream As FileStream
    Private streamWriter As StreamWriter

    Public Delegate Sub SerialDelegate()


    Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnParse.Click
        Dim SawPrintText() As String = txtScan.Text.Split(",")
        lblTopRail.Text = SawPrintText(9)
        lblBottomRail.Text = SawPrintText(10)
        btnParse.Enabled = False
        btnPrint.Enabled = True
        btnPrint.Focus()
    End Sub

    Private Sub btnPrint_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnPrint.Click
        Me.Cursor = Cursors.WaitCursor
        If SerialPort1.IsOpen Then
            SerialPort1.Close()
        End If
        Try
            With SerialPort1
                .PortName = "COM3"
                .BaudRate = 115000
                .Parity = IO.Ports.Parity.None
                .DataBits = 8
                .StopBits = IO.Ports.StopBits.One
            End With
            SerialPort1.Open()
            lblReady.Text = "Setting Up Printer - Wait!"
            Me.Refresh()
            Timer1.Interval = 1000
            btnPrint.Enabled = False
            SerialSend("01")
        Catch ex As Exception
            MsgBox("Error Opening Port: " & ex.Message)
        End Try
    End Sub

    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        tTicks = 0
        _flash = True
        lblReady.ForeColor = Color.Red
    End Sub


    Private Sub SerialPort1_DataReceived(ByVal sender As Object, ByVal e As System.IO.Ports.SerialDataReceivedEventArgs) Handles SerialPort1.DataReceived
        chkStatus.Invoke(New SerialDelegate(AddressOf ProcessResponse), New Object() {})
    End Sub

    Private Sub ProcessResponse()
        Dim sndstring As String = String.Empty
        Dim rcvstring As String = SerialPort1.ReadExisting
        Dim strResponse() As String = rcvstring.Split(",")
        If strResponse(0) = "01" Then
            If strResponse(1) = "0" Then
                chkStatus.SetItemChecked(0, True)
                sndstring = "30,1,0," & Chr(34) & lblTopRail.Text & Chr(34)
                SerialSend(sndstring)
            End If
        ElseIf strResponse(0) = "30" Then
            If strResponse(1) = "0" Then
                chkStatus.SetItemChecked(1, True)
                If strResponse(2) = "1" Then
                    chkStatus.SetItemChecked(2, True)
                    sndstring = "30,2,0," & Chr(34) & lblBottomRail.Text & Chr(34)
                Else
                    sndstring = "07,1"
                End If
                SerialSend(sndstring)
            End If
        ElseIf strResponse(0) = "07" Then
            If RTrim(rcvstring.Substring(3, 1)) = "0" Then
                chkStatus.SetItemChecked(3, True)
                lblReady.ForeColor = Color.Green
                lblReady.Text = "Printer Ready!"
                Me.Cursor = Cursors.Default
                btnReset.Focus()
                ClosePort()
            End If
        Else
        End If
        Me.Refresh()
    End Sub
    Private Sub ClosePort()
        Try
            SerialPort1.Close()
        Catch ex As Exception
            MsgBox("Error Closing Port: " & ex.Message)
        End Try

    End Sub
    Private Sub SerialSend(ByVal SStr As String)
        Try
            SerialPort1.Write(SStr + vbCr)
        Catch ex As Exception
            MsgBox("Error Sending to Serial: " & ex.Message)
        End Try
    End Sub

    Private Sub btnReset_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnReset.Click
        Dim i As Integer
        lblReady.Text = "Printer Not Ready!"
        lblReady.ForeColor = Color.Red
        btnParse.Enabled = True
        btnPrint.Enabled = False
        lblTopRail.Text = String.Empty
        lblBottomRail.Text = String.Empty
        For i = 0 To 3
            chkStatus.SetItemChecked(i, False)
        Next
        txtScan.Text = String.Empty
        txtScan.Focus()
    End Sub

End Class

Open in new window

0
 
LVL 86

Accepted Solution

by:
Mike Tomlinson earned 1000 total points
ID: 35209598
Glad that was helpful.   =)

To be honest, I have ZERO experience with the SerialPort class.  =\

Looking at the docs, though:
http://msdn.microsoft.com/en-us/library/system.io.ports.serialport.close.aspx

It has this ominous sounding warning:

    "The best practice for any application is to wait for some amount of time after calling the Close method before attempting to call the Open method, as the port may not be closed instantly."

Maybe that has something to do with it?...
0

Featured Post

Free Tool: Subnet Calculator

The subnet calculator helps you design networks by taking an IP address and network mask and returning information such as network, broadcast address, and host range.

One of a set of tools we're offering as a way of saying thank you for being a part of the community.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Article by: Kraeven
Introduction Remote Share is a simple remote sharing tool, enabling you to see, add and remove remote or local shares. The application is written in VB.NET targeting the .NET framework 2.0. The source code and the compiled programs have been in…
It’s quite interesting for me as I worked with Excel using vb.net for some time. Here are some topics which I know want to share with others whom this might help. First of all if you are working with Excel then you need to Download the Following …
Have you created a query with information for a calendar? ... and then, abra-cadabra, the calendar is done?! I am going to show you how to make that happen. Visualize your data!  ... really see it To use the code to create a calendar from a q…
Want to learn how to record your desktop screen without having to use an outside camera. Click on this video and learn how to use the cool google extension called "Screencastify"! Step 1: Open a new google tab Step 2: Go to the left hand upper corn…

722 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question