Solved

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

Posted on 2011-03-24
3
1,148 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 250 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

On Demand Webinar: Networking for the Cloud Era

Did you know SD-WANs can improve network connectivity? Check out this webinar to learn how an SD-WAN simplified, one-click tool can help you migrate and manage data in the cloud.

Question has a verified solution.

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

If you're writing a .NET application to connect to an Access .mdb database and use pre-existing queries that require parameters, you've come to the right place! Let's say the pre-existing query(qryCust) in Access takes a Date as a parameter and l…
1.0 - Introduction Converting Visual Basic 6.0 (VB6) to Visual Basic 2008+ (VB.NET). If ever there was a subject full of murkiness and bad decisions, it is this one!   The first problem seems to be that people considering this task of converting…
Add bar graphs to Access queries using Unicode block characters. Graphs appear on every record in the color you want. Give life to numbers. Hopes this gives you ideas on visualizing your data in new ways ~ Create a calculated field in a query: …
Sometimes it takes a new vantage point, apart from our everyday security practices, to truly see our Active Directory (AD) vulnerabilities. We get used to implementing the same techniques and checking the same areas for a breach. This pattern can re…

623 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