'
' Simple Serial Monitor V1.0.0.3
' A stand alone replacement for the Arduino Serial Monitor
' © Martyn Currey 2025
' https://www.martyncurrey.com/simple-serial-monitor/
'
' Originally developed as an example of using a serial port in VB.net
'
'
' Created in Visual Studio 2022  https://visualstudio.microsoft.com/vs/
' Visual Basic.Net (Framework).NET V4.8. The version with the drag & drop serial port :-)
' 

' Changes
'
' V1.0.0.1 Initial release
'
' V1.0.0.2
' Bug fix: baud rate not updating on app load
' added: save COM port
' the arrays used to store the combobox values are now global
' added a few local variable to help make the code a little bit more clearer
'
' V1.0.0.3
' Bug fix: fixed an issue when no saved settings file on start 
'
'
'
'


Imports System
Imports System.IO.Ports
Imports System.Reflection
Imports System.Windows.Forms.VisualStyles.VisualStyleElement
Imports System.Windows.Forms.VisualStyles.VisualStyleElement.Button
Imports System.Windows.Forms.VisualStyles.VisualStyleElement.ToolTip



Public Class SimpleSerial

    ' global variables. Sometimes bad, sometimes good, sometimes just what you need.



    ' saved settings file
    Dim filename As String = "simpleSerial.ini"

    Dim comPORT As String
    Dim serialPropertiesBoxOpen = False

    Dim MAIN_RichTextBox_textSize As Integer = 1

    ' colours used for the text in the main text box
    ' Black = received text
    ' Blue = sent text
    ' red = system message
    Dim colBlack As Color = Color.Black
    Dim colBlue As Color = Color.Blue
    Dim colRed As Color = Color.Red
    Dim colGreen As Color = Color.Green
    Dim lastMessageType As String = ""


    ' comPortListLength and oldComPortListLength are used to determine if the number of available com ports has changed
    ' when the new list length <> the old list length something has changed and the com port drop down list can be updated
    Dim comPortListLength As Integer = 0
    Dim oldComPortListLength As Integer = 0


    ' drop down comboBox values
    Dim baudRatesArray() As Integer = {300, 1200, 2400, 4800, 9600, 19200, 38400, 57600, 74880, 115200, 230400, 250000, 500000, 1000000, 2000000}
    Dim lineEndingsArray() As String = {"Both NL & CR", "No Line Ending", "Carriage Return", "New Line"}
    Dim dataBitsArray() As String = {"5 bits", "6 bits", "7 bits", "8 bits"}
    Dim parityOptionsArray() As String = {"None", "Odd", "Even"}
    Dim stopBitsArray As String() = {"1 bit", "2 bits"}
    Dim charEncodesArray() As String = {"Default", "UTF8", "Unicode", "ASCII", "UTF7", "UTF32"}



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

        ' Form1_Load(~) runs once when the app first loads

        ' minimum size for the app window
        Me.MinimumSize = New Size(520, 420)


        ' timers
        ' - Timer_checkSerialIn. used to check if there is any new data on the serial port
        ' - Timer_slide. used to slide the serial port settings port panel in and out
        ' - Timer_updateComPorts. used to check if the number of available com ports has changed

        ' set the timer intervals. This is already done in the form but no harm to redo it here.
        ' makes it easier to change

        Timer_checkSerialIn.Interval = 100
        Timer_updateComPorts.Interval = 500
        Timer_slide.Interval = 5

        Timer_checkSerialIn.Enabled = False
        Timer_slide.Enabled = False
        Timer_updateComPorts.Enabled = True

        ' serialProperties_GroupBox contains the serial port settings.
        ' it is hidden to one side when not in use.
        serialProperties_GroupBox.Left = Me.Width + 10
        serialProperties_GroupBox.Top = 30
        message1_LBL.Text = " "


        ' Reset the settings and then, if there are saved settings, overwrite them with the saved ones.

        ' this sets defaults settings values
        ResetSettings()

        ' check for saved settings
        If System.IO.File.Exists(filename) Then
            ' have saved settings file. Load the saved settings
            LoadSettings(filename)
        End If

    End Sub


    Private Sub MainForm_FormClosing(sender As Object, e As FormClosingEventArgs) Handles MyBase.FormClosing
        ' when the form closes save the settings
        saveSettings(filename)
    End Sub

    Private Sub ExitToolStripMenuItem_Click(sender As Object, e As EventArgs) Handles ExitToolStripMenuItem.Click
        ' if File -> Exit is clicked, close the program.
        ' calling me.close() will call MainForm_FormClosing(~)
        Me.Close()
    End Sub

    Private Sub onlineHelp_ToolStripMenuItem_Click(sender As Object, e As EventArgs) Handles onlineHelp_ToolStripMenuItem.Click
        Try
            Process.Start("https://www.martyncurrey.com/simple-serial-monitor/")
        Catch ex As Exception
            MsgBox("Can't load Web page" & vbCrLf & ex.Message)
        End Try
    End Sub

    Private Sub AboutToolStripMenuItem_Click(sender As Object, e As EventArgs) Handles AboutToolStripMenuItem.Click
        ' show the about form
        AboutBox1.Show()
    End Sub







    '   _____  ______  _____   _____            _          _____    ____   _____  _______ 
    '  / ____||  ____||  __ \ |_   _|    /\    | |        |  __ \  / __ \ |  __ \|__   __|
    ' | (___  | |__   | |__) |  | |     /  \   | |        | |__) || |  | || |__) |  | |   
    '  \___ \ |  __|  |  _  /   | |    / /\ \  | |        |  ___/ | |  | ||  _  /   | |   
    '  ____) || |____ | | \ \  _| |_  / ____ \ | |____    | |     | |__| || | \ \   | |   
    ' |_____/ |______||_|  \_\|_____|/_/    \_\|______|   |_|      \____/ |_|  \_\  |_|   
    ' and related
    '
    Private Sub connect_BTN_Click(sender As Object, e As EventArgs) Handles CONNECT_BTN.Click
        ' the connect button is used to connect and disconnect
        If (SerialPort1.IsOpen) Then
            DISCONNECT()
        Else
            CONNECT()
        End If
    End Sub


    Private Sub BAUD_ComboBox_SelectedIndexChanged(sender As Object, e As EventArgs) Handles BAUD_ComboBox.SelectedIndexChanged
        ' if a different com port is selected when there is an active serial connection the app will close the current connection
        ' and try to make a new one using the newly selected com port
        ' if there isn't an active connection nothing happens
        If (SerialPort1.IsOpen) Then
            DISCONNECT()
            CONNECT()
        End If
    End Sub


    Private Sub CONNECT()
        ' baud rate is taken from the comboBox selected item value.
        ' parity and stop bits are derived from the comboBox list index value of the selected item.

        ' Serial Parity
        '   index 0 = None
        '   index 1 = odd
        '   index 2 = even
        '
        ' Serial Stop Bits
        '   index 0 = One
        '   index 1 = Two

        ' com port is taken from the user selected item value
        comPORT = comPort_ComboBox.SelectedItem

        ' for the baud rate and com port I want the value of the item that is selected in the drop down list
        ' for data bits, parity and stops bits, VB uses an integer, SerialPort1.DataBits is an integer, this means
        ' as long as the drop down list uses the same order that VB serialport1.~ uses I can use the list index (also an integer). 
        ' sometimes the list index matches exactly what VB expects, for example SerialPort1.Parity = parityBit_ComboBox.SelectedIndex
        ' sometimes you need to change the index slightly, for example SerialPort1.DataBits = dataBits_ComboBox.SelectedIndex + 5

        'if a com port has been selected, try to open a channel
        If (comPORT <> "") Then

            SerialPort1.Close()
            SerialPort1.PortName = comPORT
            SerialPort1.BaudRate = BAUD_ComboBox.SelectedItem

            SerialPort1.DataBits = dataBits_ComboBox.SelectedIndex + 5
            SerialPort1.Parity = parityBit_ComboBox.SelectedIndex
            SerialPort1.StopBits = stopBits_ComboBox.SelectedIndex + 1

            SerialPort1.Handshake = Handshake.None

            If (encode_ComboBox.SelectedIndex = 0) Then
                SerialPort1.Encoding = System.Text.Encoding.Default
            ElseIf (encode_ComboBox.SelectedIndex = 1) Then
                SerialPort1.Encoding = System.Text.Encoding.UTF8

            ElseIf (encode_ComboBox.SelectedIndex = 2) Then
                SerialPort1.Encoding = System.Text.Encoding.Unicode

            ElseIf (encode_ComboBox.SelectedIndex = 3) Then
                SerialPort1.Encoding = System.Text.Encoding.ASCII

            ElseIf (encode_ComboBox.SelectedIndex = 4) Then
                SerialPort1.Encoding = System.Text.Encoding.UTF7

            ElseIf (encode_ComboBox.SelectedIndex = 5) Then
                SerialPort1.Encoding = System.Text.Encoding.UTF32
            Else
                SerialPort1.Encoding = System.Text.Encoding.Default
            End If

            SerialPort1.ReadTimeout = 500
            SerialPort1.WriteTimeout = 500
            SerialPort1.RtsEnable = True
            SerialPort1.DtrEnable = True

            ' SerialPort1.Open() may fail and if it fails without the try/catch the program will crash.
            Try
                SerialPort1.Open()
            Catch ex As Exception
                MsgBox("Failed to open  " & comPORT)
            End Try

            ' the serial port may or may not be open
            ' - if it is open, update the screen and the timers
            ' - if it is not open, print a system message in the main text box.
            If (SerialPort1.IsOpen) Then
                ' serial_connected = True
                CONNECT_BTN.BackColor = Color.FromArgb(128, 225, 128)
                SEND_Button.Enabled = True
                Timer_checkSerialIn.Enabled = True
                Timer_updateComPorts.Enabled = False
                AddSysMsgToMainTextBox("Serial port open" + vbCrLf, colRed, "yes")
            Else
                AddSysMsgToMainTextBox("Failed to open " & comPORT & vbCrLf, colRed, "yes")
            End If
        Else
            MsgBox("No COM port selected")
        End If
    End Sub


    Private Sub DISCONNECT()
        Timer_checkSerialIn.Enabled = False
        Timer_updateComPorts.Enabled = True
        SEND_Button.Enabled = False

        Try
            SerialPort1.Close()
        Catch ex As Exception
            MsgBox("Serial port already closed")
        End Try

        '  serial_connected = False
        CONNECT_BTN.BackColor = Color.FromArgb(255, 50, 50)

        AddSysMsgToMainTextBox("Serial port closed" + vbCrLf, colRed, "yes")

    End Sub


    Private Sub Timer_checkSerialIn_Tick(sender As Object, e As EventArgs) Handles Timer_checkSerialIn.Tick
        ' a timer is used to check for incoming serial data.
        ' when the timer ticks this routine is called.
        ' could be replaced with the serial received event.

        ' first things first, turn the timer off.
        ' can't have Timer_checkSerialIn_Tick(~) being called while we are still here
        ' otherwise we never get out - serious case of check serial inception 
        Timer_checkSerialIn.Enabled = False

        ' if you try to read from a serial port that is not open all sorts of bad things happen and the program crashes.
        ' so use a try/catch
        Dim tmpDataIn As String = ""
        If (SerialPort1.IsOpen) Then
            If (SerialPort1.BytesToRead > 0) Then
                Try
                    tmpDataIn = SerialPort1.ReadExisting()
                Catch ex As Exception
                    MsgBox("Error reading from the serial port")
                End Try
            End If

            ' if there is new received data add it to the main text box
            If (tmpDataIn <> "") Then
                addReceivedTextToMainTextBox(tmpDataIn, colBlack)
            End If

            ' and finally start the timer again.
            Timer_checkSerialIn.Enabled = True

        Else
            ' no serial port
            DISCONNECT()
            MsgBox("The serial port has unexpectedly closed")
        End If

    End Sub







    '                    _         _          _____                   _____              _        
    '                   | |       | |        / ____|                 |  __ \            | |       
    '  _   _  _ __    __| |  __ _ | |_  ___ | |      ___   _ __ ___  | |__) |___   _ __ | |_  ___ 
    ' | | | || '_ \  / _` | / _` || __|/ _ \| |     / _ \ | '_ ` _ \ |  ___// _ \ | '__|| __|/ __|
    ' | |_| || |_) || (_| || (_| || |_|  __/| |____| (_) || | | | | || |   | (_) || |   | |_ \__ \
    '  \__,_|| .__/  \__,_| \__,_| \__|\___| \_____|\___/ |_| |_| |_||_|    \___/ |_|    \__||___/
    '        | |                                                                                  
    '        |_|                                                                                  
    '
    Private Sub Timer_updateComPorts_Tick(sender As Object, e As EventArgs) Handles Timer_updateComPorts.Tick
        ' Timer_updateComPorts is active only when there isn't an active serial port
        ' it is used to see if there are any changes to the available com ports list

        updateCOMlist()
    End Sub

    Private Sub updateCOMlist()

        ' the previous number of available com ports is stored in oldComPortListLength
        ' the current number of available com ports is put in to comPortListLength
        ' if they are not equal then the com port list has changed and the COM port comboBox should be updated.

        comPortListLength = My.Computer.Ports.SerialPortNames.Count

        ' The com port drop down list is only updated if the number of available com ports has changed
        If (comPortListLength <> oldComPortListLength) Then

            oldComPortListLength = comPortListLength
            comPORT = comPort_ComboBox.SelectedItem
            comPort_ComboBox.Items.Clear()

            For Each sp As String In My.Computer.Ports.SerialPortNames
                comPort_ComboBox.Items.Add(sp)
            Next

            If (My.Computer.Ports.SerialPortNames.Contains(comPORT)) Then
                comPort_ComboBox.SelectedItem = comPORT
            Else
                comPORT = ""
                comPort_ComboBox.Text = "COM Port"
            End If

        End If

    End Sub







    '  __  __            _____  _   _     _______  ______ __   __ _______     ____    ____ __   __
    ' |  \/  |    /\    |_   _|| \ | |   |__   __||  ____|\ \ / /|__   __|   |  _ \  / __ \\ \ / /
    ' | \  / |   /  \     | |  |  \| |      | |   | |__    \ V /    | |      | |_) || |  | |\ V / 
    ' | |\/| |  / /\ \    | |  | . ` |      | |   |  __|    > <     | |      |  _ < | |  | | > <  
    ' | |  | | / ____ \  _| |_ | |\  |      | |   | |____  / . \    | |      | |_) || |__| |/ . \ 
    ' |_|  |_|/_/    \_\|_____||_| \_|      |_|   |______|/_/ \_\   |_|      |____/  \____//_/ \_\
    '

    Private Sub addReceivedTextToMainTextBox(text As String, c As Color)

        ' if the previous text/data was a system message without line end characters then print a newline before adding the new received data

        If (lastMessageType = "system") Then
            Dim currentPos As Integer = MAIN_RichTextBox.SelectionStart()
            If (currentPos > 0) Then
                If (MAIN_RichTextBox.Text.Chars(currentPos - 1) <> vbLf) Then
                    MAIN_RichTextBox.AppendText(vbLf)
                End If
            End If
        End If

        MAIN_RichTextBox.SelectionStart = MAIN_RichTextBox.Text.Length
        MAIN_RichTextBox.SelectionColor = c
        MAIN_RichTextBox.AppendText(text)
        scrollTextBox()
        lastMessageType = "received"
    End Sub


    Private Sub AddSysMsgToMainTextBox(Text As String, c As Color, NL As String)
        ' NL is used as a flag to say if the system message is to be displayed on a new line
        ' however, we don't want a new line if there is already one there. This would result in a blank line
        ' so only add the new line if the last character is not a new line.

        If (SYS_MSG_CheckBox.CheckState = 1) Then

            If (NL.ToUpper = "YES") Then
                Dim currentPos As Integer = MAIN_RichTextBox.SelectionStart()
                If (currentPos > 0) Then
                    If (MAIN_RichTextBox.Text.Chars(currentPos - 1) <> vbLf) Then
                        MAIN_RichTextBox.AppendText(vbLf)
                    End If
                End If
            End If

            MAIN_RichTextBox.SelectionStart = MAIN_RichTextBox.Text.Length
            ' change the text colour
            MAIN_RichTextBox.SelectionColor = c
            MAIN_RichTextBox.AppendText(Text)

            scrollTextBox()
            lastMessageType = "system"
        End If

    End Sub


    Private Sub scrollTextBox()
        ' scroll the text box the end
        If (SCROLL_CheckBox.CheckState = 1) Then
            MAIN_RichTextBox.SelectionStart = MAIN_RichTextBox.TextLength
            MAIN_RichTextBox.ScrollToCaret()
        End If
    End Sub


    Private Sub clear_BTN_Click_1(sender As Object, e As EventArgs) Handles clear_BTN.Click
        ' clear the main text box
        MAIN_RichTextBox.Text = ""
    End Sub


    Private Sub TEXT_SMALL_BUTTON_Click(sender As Object, e As EventArgs) Handles TEXT_SMALL_BUTTON.Click
        ' reduce the main text box font size
        If (MAIN_RichTextBox_textSize > 1) Then
            MAIN_RichTextBox_textSize = MAIN_RichTextBox_textSize - 1
        End If
        updateTextSize()
    End Sub

    Private Sub TEXT_BIG_BUTTON_Click(sender As Object, e As EventArgs) Handles TEXT_BIG_BUTTON.Click
        ' increase the main text box font size
        If (MAIN_RichTextBox_textSize < 5) Then
            MAIN_RichTextBox_textSize = MAIN_RichTextBox_textSize + 1
        End If
        updateTextSize()
    End Sub


    Private Sub updateTextSize()

        ' there are 5 sizes; 1 to 5.
        ' 1 is whatever the default size is (if you haven't changed anything it is courier new size 10)
        ' 5 is the largest

        Dim zoomFactor As Single = 0

        If (MAIN_RichTextBox_textSize = 1) Then
            fonSize_LBL.Text = "|----"
            zoomFactor = 1
        ElseIf (MAIN_RichTextBox_textSize = 2) Then
            fonSize_LBL.Text = "-|---"
            zoomFactor = 1.2
        ElseIf (MAIN_RichTextBox_textSize = 3) Then
            fonSize_LBL.Text = "--|--"
            zoomFactor = 1.4
        ElseIf (MAIN_RichTextBox_textSize = 4) Then
            fonSize_LBL.Text = "---|-"
            zoomFactor = 1.6
        ElseIf (MAIN_RichTextBox_textSize = 5) Then
            fonSize_LBL.Text = "----|"
            zoomFactor = 1.8

        End If

        ' using zoom, rather than changing the font, keeps the original formating (ie the coloured text)
        MAIN_RichTextBox.SelectAll()
        MAIN_RichTextBox.ZoomFactor = zoomFactor

    End Sub









    '   _____  ______  _   _  _____  
    '  / ____||  ____|| \ | ||  __ \ 
    ' | (___  | |__   |  \| || |  | |
    '  \___ \ |  __|  | . ` || |  | |
    '  ____) || |____ | |\  || |__| |
    ' |_____/ |______||_| \_||_____/ 
    ' 

    Private Sub SEND_Button_Click(sender As Object, e As EventArgs) Handles SEND_Button.Click
        ProcessSendText(SEND_RichTextBox.Text)
        SEND_RichTextBox.Text = ""
        SEND_RichTextBox.Select()
    End Sub

    Private Sub SEND_RichTextBox_KeyPress(sender As Object, e As KeyEventArgs) Handles SEND_RichTextBox.KeyUp

        ' TO STOP THE ANOYING BEEP SOUND WHEN THE ENTER KEY IS PRESSED I AM USING A MULTLINE TEXTBOX FOR SEND
        ' TO STOP THE SCROLL BARS FLASHING WHEN THE ENTER KEY IS PRESSED THEY HAVE BEEN DISABLED
        ' CAVEAT: THE ENTER KEY IS ADDED TO THE TEXTBOX CONTENTS AND NEEDS TO BE REMOVED

        ' has the enter key been pressed?
        If (e.KeyCode = Keys.Enter) Then

            ' when using a multiline rich-textbox, if the content length = 1 it means the content is a
            ' new line character only and it can be ignored. It means the user has pressed enter without
            ' entering anything in the SEND text box.
            ' you can see this is you uncomment the below

            ' however, if the content length > 1 it means there is actual content
            If (SEND_RichTextBox.Text.Length() > 1) Then

                ' Dim lastChar As String = SEND_RichTextBox.Text(SEND_RichTextBox.Text.Length - 1)
                ' Dim lastCharInAscii = Asc(lastChar)
                ' AddSysMsgToMainTextBox("length = " & SEND_RichTextBox.Text.Length(), colRed, "yes")
                ' AddSysMsgToMainTextBox("last char = " & lastChar, colRed, "yes")
                ' AddSysMsgToMainTextBox("last ASCII = " & lastCharInAscii, colRed, "yes")

                ' remove the last character (don't uncomment this)
                SEND_RichTextBox.Text = SEND_RichTextBox.Text.Substring(0, SEND_RichTextBox.Text.Length() - 1)
                ProcessSendText(SEND_RichTextBox.Text)

            Else
                Beep()
            End If

            ' we have finished with the key event and can now pretend it never happened.
            e.Handled = True
            e.SuppressKeyPress = True

            SEND_RichTextBox.Text = ""
            SEND_RichTextBox.Select()

        End If

    End Sub


    Private Sub ProcessSendText(textToSend As String)
        ' send only. Does not clear text box

        ' textToSend should never be blank but you never know. better to have a check.
        If (textToSend <> "") Then

            ' line end characters are based on the user selected preference
            ' index 0 = Both NL & CR
            ' index 1 = No Line Ending
            ' index 2 = Carriage Return
            ' index 3 = New Line

            Dim EOL As String = ""
            If (LE_ComboBox.SelectedIndex = 0) Then
                EOL = vbCrLf
            ElseIf (LE_ComboBox.SelectedIndex = 2) Then
                EOL = vbCr
            ElseIf (LE_ComboBox.SelectedIndex = 3) Then
                EOL = vbLf
            End If

            If (showSent_checkBox.CheckState = 1) Then
                AddSysMsgToMainTextBox(textToSend, colBlue, "yes")
            End If

            sendSerial(textToSend & EOL)

        End If

    End Sub


    Private Sub sendSerial(data As String)
        ' the part that actual sends the data is in it's own subroutine incase I expand the app later
        ' this could be converted to a function with a success/failure return

        ' anything serialport should be wrapped in a try/catch
        If (SerialPort1.IsOpen) Then
            Try
                SerialPort1.Write(data)
            Catch ex As Exception
                DISCONNECT()
                MsgBox("Error: failed to write to the serial port")
            End Try

        End If
    End Sub







    '  _____                   _     _____        _    _    _                      ____  
    ' |  __ \                 | |   / ____|      | |  | |  (_)                    / /\ \ 
    ' | |__) | ___  ___   ___ | |_ | (___    ___ | |_ | |_  _  _ __    __ _  ___ | |  | |
    ' |  _  / / _ \/ __| / _ \| __| \___ \  / _ \| __|| __|| || '_ \  / _` |/ __|| |  | |
    ' | | \ \|  __/\__ \|  __/| |_  ____) ||  __/| |_ | |_ | || | | || (_| |\__ \| |  | |
    ' |_|  \_\\___||___/ \___| \__||_____/  \___| \__| \__||_||_| |_| \__, ||___/| |  | |
    '                                                                  __/ |      \_\/_/ 
    '                                                                 |___/              

    Private Sub ResetSettings()


        BAUD_ComboBox.Items.Clear()
        BAUD_ComboBox.MaxDropDownItems = baudRatesArray.Length
        For Each baudRate As Integer In baudRatesArray
            BAUD_ComboBox.Items.Add(baudRate)
        Next
        BAUD_ComboBox.SelectedIndex = 4

        LE_ComboBox.Items.Clear()
        LE_ComboBox.MaxDropDownItems = lineEndingsArray.Length
        For Each lineEnd As String In lineEndingsArray
            LE_ComboBox.Items.Add(lineEnd)
        Next
        LE_ComboBox.SelectedIndex = 0


        ' the SEND button is enabled only when there is an active connection
        SEND_Button.Enabled = False
        CONNECT_BTN.BackColor = Color.FromArgb(255, 50, 50)

        dataBits_ComboBox.Items.Clear()
        dataBits_ComboBox.MaxDropDownItems = dataBitsArray.Length
        For Each dataBit As String In dataBitsArray
            dataBits_ComboBox.Items.Add(dataBit)
        Next
        dataBits_ComboBox.SelectedIndex = 3

        parityBit_ComboBox.Items.Clear()
        parityBit_ComboBox.MaxDropDownItems = dataBitsArray.Length
        For Each parity As String In parityOptionsArray
            parityBit_ComboBox.Items.Add(parity)
        Next
        parityBit_ComboBox.SelectedIndex = 0

        stopBits_ComboBox.Items.Clear()
        stopBits_ComboBox.MaxDropDownItems = stopBitsArray.Length
        For Each stopBit As String In stopBitsArray
            stopBits_ComboBox.Items.Add(stopBit)
        Next
        stopBits_ComboBox.SelectedIndex = 0

        encode_ComboBox.Items.Clear()
        encode_ComboBox.MaxDropDownItems = charEncodesArray.Length
        For Each charEncode As String In charEncodesArray
            encode_ComboBox.Items.Add(charEncode)
        Next
        encode_ComboBox.SelectedIndex = 0

    End Sub







    '  _                        _   _____        _    _    _                    
    ' | |                      | | / ____|      | |  | |  (_)                   
    ' | |      ___    __ _   __| || (___    ___ | |_ | |_  _  _ __    __ _  ___ 
    ' | |     / _ \  / _` | / _` | \___ \  / _ \| __|| __|| || '_ \  / _` |/ __|
    ' | |____| (_) || (_| || (_| | ____) ||  __/| |_ | |_ | || | | || (_| |\__ \
    ' |______|\___/  \__,_| \__,_||_____/  \___| \__| \__||_||_| |_| \__, ||___/
    '                                                                 __/ |     
    '                                                                |___/      
    '

    Private Sub LoadSettings(fn As String)

        ' App settings are saved in a text file


        ' another file check is not really required, there is a check before the LoadSettings() function is called, but it will make things easier should the app be extended in the future. 
        If System.IO.File.Exists(fn) Then


            Dim tmpInputLine As String = ""
            Dim foundPos As Integer = 0

            Dim comPortMsg As String = ""

            Dim fileReader As System.IO.StreamReader
            fileReader = My.Computer.FileSystem.OpenTextFileReader(fn)

            tmpInputLine = fileReader.ReadLine()

            While tmpInputLine <> "END"
                tmpInputLine = fileReader.ReadLine()

                foundPos = InStr(1, tmpInputLine, "=", CompareMethod.Text)

                If (foundPos > 0) Then
                    Dim tmpInputLineSplit() As String = Split(tmpInputLine, "=", -1, CompareMethod.Text)

                    ' tmpInputLineSplit
                    ' form size
                    ' all the local variables aren't really needed but they make the code easier to read.
                    ' and at least i didn't use global variables!

                    If (tmpInputLineSplit(0) = "size") Then
                        If (tmpInputLineSplit(1) <> "") Then
                            Dim tmpSize() As String = Split(tmpInputLineSplit(1), ",", -1, CompareMethod.Text)
                            Dim tmpWidth As Integer = Val(tmpSize(0))
                            Dim tmpHeight As Integer = Val(tmpSize(1))

                            If (tmpWidth >= 520 And tmpHeight >= 420) Then
                                Me.Width = tmpWidth
                                Me.Height = tmpHeight
                            End If
                        Else
                            ' this is not really required, 520x420 is the default start size.
                            Me.Width = 520
                            Me.Height = 420
                        End If
                    End If


                    ' baud rate    
                    ' if baud rate is not found the default will be 9600
                    If (tmpInputLineSplit(0) = "baud") Then
                        Dim baudRate As Integer = Val(tmpInputLineSplit(1))
                        Dim idx As Integer = Array.IndexOf(baudRatesArray, baudRate)
                        If (idx > -1) Then
                            BAUD_ComboBox.SelectedIndex = idx
                        Else
                            BAUD_ComboBox.SelectedIndex = 4
                        End If
                    End If


                    ' line end characters
                    If (tmpInputLineSplit(0) = "eol") Then
                        If (tmpInputLineSplit(1) <> "" And LE_ComboBox.Items.Contains(tmpInputLineSplit(1))) Then
                            LE_ComboBox.SelectedItem = tmpInputLineSplit(1)
                        Else
                            LE_ComboBox.SelectedItem = ""
                        End If
                    End If


                    ' COM port 
                    If (tmpInputLineSplit(0) = "COM") Then
                        updateCOMlist()

                        ' creating yet another local variable is not required but makes the code a little easier to read
                        Dim savedComPort As String = tmpInputLineSplit(1)

                        If (savedComPort <> "") Then

                            If (comPort_ComboBox.Items.Contains(savedComPort)) Then
                                comPort_ComboBox.SelectedItem = savedComPort
                            Else
                                comPortMsg = "Saved COM port (" & savedComPort & ") not available"
                            End If
                        Else
                            ' No saved COM port
                            ' You can create a message if you so desire The message will be displayed in the main window
                            ' comPortMsg = "No saved COM port"

                        End If

                    End If


                    If (tmpInputLineSplit(0) = "textsize") Then
                        If (tmpInputLineSplit(1) <> "") Then
                            Dim savedTextSize As Integer = Val(tmpInputLineSplit(1))

                            If (savedTextSize) >= 1 And Val(savedTextSize <= 5) Then
                                MAIN_RichTextBox_textSize = savedTextSize
                            Else
                                MAIN_RichTextBox_textSize = 2
                            End If
                        End If
                        updateTextSize()

                    End If


                    If (tmpInputLineSplit(0) = "sysmsg") Then
                        If (tmpInputLineSplit(1) = "yes") Then
                            SYS_MSG_CheckBox.CheckState = 1
                        ElseIf (tmpInputLineSplit(1) = "no") Then
                            SYS_MSG_CheckBox.CheckState = 0
                        Else
                            SYS_MSG_CheckBox.CheckState = 1
                        End If
                    End If

                    If (tmpInputLineSplit(0) = "scroll") Then
                        If (tmpInputLineSplit(1) = "yes") Then
                            SCROLL_CheckBox.CheckState = 1
                        ElseIf (tmpInputLineSplit(1) = "no") Then
                            SCROLL_CheckBox.CheckState = 0
                        Else
                            SCROLL_CheckBox.CheckState = 1
                        End If
                    End If

                    If (tmpInputLineSplit(0) = "showsent") Then
                        If (tmpInputLineSplit(1) = "yes") Then
                            showSent_checkBox.CheckState = 1
                        ElseIf (tmpInputLineSplit(1) = "no") Then
                            showSent_checkBox.CheckState = 0
                        Else
                            showSent_checkBox.CheckState = 1
                        End If
                    End If

                    If (tmpInputLineSplit(0) = "databits") Then
                        If (tmpInputLineSplit(1) <> "") Then
                            dataBits_ComboBox.SelectedItem = tmpInputLineSplit(1)
                        End If
                    End If

                    If (tmpInputLineSplit(0) = "parity") Then
                        If (tmpInputLineSplit(1) <> "") Then
                            parityBit_ComboBox.SelectedItem = tmpInputLineSplit(1)
                        End If
                    End If

                    If (tmpInputLineSplit(0) = "stopbits") Then
                        If (tmpInputLineSplit(1) <> "") Then
                            stopBits_ComboBox.SelectedItem = tmpInputLineSplit(1)
                        End If
                    End If


                End If
            End While
            fileReader.Close()

            AddSysMsgToMainTextBox("Previous settings loaded", colRed, "yes")
            If (comPortMsg <> "") Then
                AddSysMsgToMainTextBox(comPortMsg, colRed, "yes")
            End If


        End If  ' If System.IO.File.Exists(fn) Then

    End Sub







    '   _____                      _____        _    _    _                      ____  
    '  / ____|                    / ____|      | |  | |  (_)                    / /\ \ 
    ' | (___    __ _ __   __ ___ | (___    ___ | |_ | |_  _  _ __    __ _  ___ | |  | |
    '  \___ \  / _` |\ \ / // _ \ \___ \  / _ \| __|| __|| || '_ \  / _` |/ __|| |  | |
    '  ____) || (_| | \ V /|  __/ ____) ||  __/| |_ | |_ | || | | || (_| |\__ \| |  | |
    ' |_____/  \__,_|  \_/  \___||_____/  \___| \__| \__||_||_| |_| \__, ||___/| |  | |
    '                                                                __/ |      \_\/_/ 
    '                                                               |___/              



    Private Sub SaveSettings(fn As String)

        Dim tmpString As String = ""

        If (System.IO.File.Exists(fn) = False) Then
            System.IO.File.Create(fn).Dispose()
        End If

        Dim objWriter As New System.IO.StreamWriter(fn, False)

        objWriter.WriteLine("Simple Serial Monitor Settings")

        objWriter.WriteLine("size=" & Me.Width & "," & Me.Height)

        ' baud rate
        tmpString = BAUD_ComboBox.SelectedItem
        If (tmpString = "") Then
            tmpString = "9600"
        End If
        objWriter.WriteLine("baud=" & tmpString)

        'eol
        tmpString = LE_ComboBox.SelectedItem
        objWriter.WriteLine("eol=" & tmpString)

        ' COM port
        tmpString = comPort_ComboBox.SelectedItem
        objWriter.WriteLine("COM=" & tmpString)


        'main text box text size
        objWriter.WriteLine("textsize=" & MAIN_RichTextBox_textSize)

        If (SCROLL_CheckBox.CheckState = 1) Then
            objWriter.WriteLine("scroll=yes")
        Else
            objWriter.WriteLine("scroll=no")
        End If

        If (SYS_MSG_CheckBox.CheckState = 1) Then
            objWriter.WriteLine("sysmsg=yes")
        Else
            objWriter.WriteLine("sysmsg=no")
        End If

        If (showSent_checkBox.CheckState = 1) Then
            objWriter.WriteLine("showsent=yes")
        Else
            objWriter.WriteLine("showsent=no")
        End If

        tmpString = dataBits_ComboBox.SelectedItem
        objWriter.WriteLine("databits=" & tmpString)

        tmpString = parityBit_ComboBox.SelectedItem
        objWriter.WriteLine("parity=" & tmpString)

        tmpString = stopBits_ComboBox.SelectedItem
        objWriter.WriteLine("stopbits=" & tmpString)

        objWriter.WriteLine("END")
        objWriter.Close()

    End Sub

    Private Sub SCROLL_CheckBox_CheckedChanged(sender As Object, e As EventArgs)
        If (SCROLL_CheckBox.CheckState = 1) Then
            scrollTextBox()
        End If

    End Sub








    '   _____  ______  _______  _______  _____  _   _   _____   _____      _____          _   _  ______  _      
    '  / ____||  ____||__   __||__   __||_   _|| \ | | / ____| / ____|    |  __ \  /\    | \ | ||  ____|| |     
    ' | (___  | |__      | |      | |     | |  |  \| || |  __ | (___      | |__) |/  \   |  \| || |__   | |     
    '  \___ \ |  __|     | |      | |     | |  | . ` || | |_ | \___ \     |  ___// /\ \  | . ` ||  __|  | |     
    '  ____) || |____    | |      | |    _| |_ | |\  || |__| | ____) |    | |   / ____ \ | |\  || |____ | |____ 
    ' |_____/ |______|   |_|      |_|   |_____||_| \_| \_____||_____/     |_|  /_/    \_\|_| \_||______||______|
    ' 
    ' 

    ' clicking the settings button enables a timer
    ' the timer is used to slide the serial port settings panel in and out
    Private Sub Setting_BTN_Click(sender As Object, e As EventArgs) Handles setting_BTN.Click
        If (SerialPort1.IsOpen) Then
            message1_LBL.Text = "Changes will update when" & vbCrLf & "a new connection is made"
        Else
            message1_LBL.Text = " "
        End If

        Timer_slide.Enabled = True
    End Sub


    Private Sub SerialPropertiesClose_BTN_Click(sender As Object, e As EventArgs) Handles serialPropertiesClose_BTN.Click
        ' the CLOSE button is the settings panel has patent pending InstaClose functionality :-)
        serialProperties_GroupBox.Left = Me.Width + 10
        serialPropertiesBoxOpen = False
    End Sub


    Private Sub Timer_slide_Tick(sender As Object, e As EventArgs) Handles Timer_slide.Tick

        ' if the settings panel is not open, open it,  else close it.

        ' you could get rid of all this and just open and close the panel but where is the fun in that.

        ' living dangerously, I don't disable the timer while moving the settings panel.
        ' I am trusting that the windows PC/VB can move the panel 20 pixels before the timer fires again.
        ' of course, once the panel is in the fully opened or fully closed position I stop the timer so
        ' the panel doesn't move anymore.

        If (serialPropertiesBoxOpen = False) Then

            If (serialProperties_GroupBox.Left > (Me.Width - 280)) Then
                serialProperties_GroupBox.Left = serialProperties_GroupBox.Left - 20
            Else
                Timer_slide.Enabled = False
                serialPropertiesBoxOpen = True
                serialProperties_GroupBox.Left = Me.Width - 300
            End If

        Else

            If (serialProperties_GroupBox.Left < (Me.Width + 10)) Then
                serialProperties_GroupBox.Left = serialProperties_GroupBox.Left + 20
            Else
                Timer_slide.Enabled = False
                serialPropertiesBoxOpen = False
            End If

        End If

    End Sub






    '  _____   ______   _____  _____  ______ ______    __          __ _____  _   _  _____    ____ __          __
    ' |  __ \ |  ____| / ____||_   _||___  /|  ____|   \ \        / /|_   _|| \ | ||  __ \  / __ \\ \        / /
    ' | |__) || |__   | (___    | |     / / | |__       \ \  /\  / /   | |  |  \| || |  | || |  | |\ \  /\  / / 
    ' |  _  / |  __|   \___ \   | |    / /  |  __|       \ \/  \/ /    | |  | . ` || |  | || |  | | \ \/  \/ /  
    ' | | \ \ | |____  ____) | _| |_  / /__ | |____       \  /\  /    _| |_ | |\  || |__| || |__| |  \  /\  /   
    ' |_|  \_\|______||_____/ |_____|/_____||______|       \/  \/    |_____||_| \_||_____/  \____/    \/  \/    
    '

    Private Sub Form1_Resize(sender As Object, e As EventArgs) Handles Me.Resize

        ' not an elegant solution, everything is manually placed,  but it works.
        ' Might have been better to use one of the layout tools

        '  serialProperties_GroupBox
        If (serialPropertiesBoxOpen = True) Then
            serialProperties_GroupBox.Left = Me.Width - 300
        Else
            serialProperties_GroupBox.Left = Me.Width + 20
        End If


        MAIN_RichTextBox.Width = Me.Width - 40
        MAIN_RichTextBox.Height = Me.Height - 180
        MAIN_RichTextBox.Left = 10

        Dim baseOffset As Integer = 152

        SCROLL_CheckBox.Top = Me.Height - baseOffset
        TEXT_SMALL_BUTTON.Top = Me.Height - (baseOffset + 2)
        fonSize_LBL.Top = Me.Height - (baseOffset - 2)
        TEXT_BIG_BUTTON.Top = Me.Height - (baseOffset + 2)
        SYS_MSG_CheckBox.Top = Me.Height - baseOffset
        showSent_checkBox.Top = Me.Height - baseOffset

        clear_BTN.Left = Me.Width - 30 - clear_BTN.Width
        clear_BTN.Top = Me.Height - (baseOffset + 4)

        SEND_RichTextBox.Width = Me.Width - 124
        SEND_RichTextBox.Top = Me.Height - (baseOffset - 32)

        SEND_Button.Left = Me.Width - 30 - SEND_Button.Width
        SEND_Button.Top = Me.Height - (baseOffset - 31) ' 133

        baseOffset = 80
        BAUD_ComboBox.Top = Me.Height - baseOffset
        LE_ComboBox.Top = Me.Height - baseOffset
        comPort_ComboBox.Top = Me.Height - baseOffset
        CONNECT_BTN.Top = Me.Height - baseOffset

        setting_BTN.Top = Me.Height - baseOffset
        setting_BTN.Left = Me.Width - 30 - setting_BTN.Width

        scrollHandle.Left = Me.Width - 27
        scrollHandle.Top = Me.Height - 50

    End Sub


End Class

