
'
'
'      _                      _____               _                _  _              
'     | |                    / ____|             | |              | || |             
'   __| | _ __  ___   _ __  | |      ___   _ __  | |_  _ __  ___  | || |  ___  _ __    
'  / _` || '__|/ _ \ | '_ \ | |     / _ \ | '_ \ | __|| '__|/ _ \ | || | / _ \| '__|   
' | (_| || |  | (_) || |_) || |____| (_) || | | || |_ | |  | (_) || || ||  __/| |     
'  \__,_||_|   \___/ | .__/  \_____|\___/ |_| |_| \__||_|   \___/ |_||_| \___||_|        
'                    | |                                                                               
'                    |_|                                                                               
'
'
' 
' Release 2023.1.1.1.4
' 2023-001
' Removed link to the online forum
' Updated the copyright year to 2023
'
'
'
' 2021-07 - 017
' Release 2021.1.1.1.3
' Bug fix: Corrected the codes used to turn the valves off in the closeValves function.
' closeValves() sends commands when the serial port is open. If the port is closed nothing is sent.
' closeValves() is called:
'  - at closeProgrqam()
'  - at disconnect()
'  - at SETTINGS_Leave
'
'
' 2021-07 - 016
' Look at drop times check
' loop mode limits
' changed the drop size limit from 999 to 9999. I can't remember if there was a reason it was set to 999 or if it was an over sight.
' Remove the need to correct drop times errors before allowing to make drops
' 
' 
' 
' 2021-05
' update CT. Added SYNC control.  OFF => ON => SYNC => BULB 
' BULB now uses the post shot offset only
' Settings tab: Removed the seperate CT BULB button 
' Settings tab: Moved the loop mode controls
' Loop Page: Changed the behavior of the Loop Mode START btn 
' Loop Page: Added copy values function. Copy the current values to the main drop data
' check drop data no longer checks drops that are turned off.
' Bug Fix: wrong number of drops when drop turned off
'
'
'
' 2020-09-09 - 2020_002_001
' Changed the camera trigger button. OFF => ON => BULB and removed the seperate BULB button
' Updated the graph to show times based on drops rather than valves
' removed debug button status from save function
'
' 2020-03-10 - 2020_001_001 Build 0.0.0.1
' Corrected delta values not showing correctly on the Loop Page
' Moved the SIZE and STOP columns around on the Loop Page
'
' 2019-12-01 - 2019_006_001 Build 0.0.0.1
' changed loop mode wait time to seconds 1-99
' disabled the maximize button
' added a forum link to the Help menu
' updated the copyright notice to 2020
'
' 2019-04-20 - 2019_005 Build 0.0.0.1
' Added FT3
' dropController V3 requires firmare 2019_V3_005_01 or higher
'
' 2019-02-06 - 2019_004 Build 0.0.0.1
' First release combined app.  Now compatible with V2 and V3 devices (need firmware update on device)
'
'

'
'
' Reminders
' Set version in AssemblyInfo.vb file
' 





Imports System
Imports System.IO
Imports System.IO.Ports
Imports System.Reflection
Imports System.Drawing
Imports System.Text
Imports Microsoft.Win32



Public Class MainForm



    Dim versionNumber As Version
    Dim versionString As String = ""

    Dim numValves As Integer = 6
    Dim numDrops As Integer = 9

    Dim comPORT As String
    Dim receivedData As String = ""


    Dim greyedOut As Color = Me.BackColor

    ' arrays to hold the various objects/elements
    Dim RowLabels As Label() = New Label() {}
    Dim drop_onOff_BTNS As Button() = New Button() {}
    Dim SolCBs As ComboBox() = New ComboBox() {}
    Dim StartTimes As TextBox() = New TextBox() {}
    Dim StartIncDecBtns As Button() = New Button() {}
    Dim StartIncDecVals As TextBox() = New TextBox() {}
    Dim Sizes As TextBox() = New TextBox() {}
    Dim SizeIncDecBtns As Button() = New Button() {}
    Dim SizeIncDecVals As TextBox() = New TextBox() {}

    Dim dropOnOff() As String = {"", "", "", "", "", "", "", "", "", ""}
    Dim dropSol() As Long = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
    Dim dropStartTime() As Long = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
    Dim dropStartTimeDelta() As String = {"", "", "", "", "", "", "", "", "", ""}
    Dim dropStartTimeDeltaVal() As Long = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
    Dim dropSize() As Long = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
    Dim dropSizeDelta() As String = {"", "", "", "", "", "", "", "", "", ""}
    Dim dropSizeDeltaVal() As Long = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}

    Dim FT1_StartTime As Long = 0
    Dim FT2_StartTime As Long = 0
    Dim FT3_StartTime As Long = 0
    Dim CT_StartTime As Long = 0
    Dim FT1_Size As Long = 0
    Dim FT2_Size As Long = 0
    Dim FT3_Size As Long = 0
    Dim CT_Size As Long = 0

    'Loop Mode
    Dim sequenceAborted As Boolean = False


    ' debug
    Dim DEBUG_MASTER As Boolean = False
    Dim useDebugLogFile As Boolean = False

    Dim widthDebug As Integer = 1110
    Dim widthNormal As Integer = 844

    '


    ' __  __
    '|  \/  |                    
    '| \  / |  ___  _ __   _   _ 
    '| |\/| | / _ \| '_ \ | | | |
    '| |  | ||  __/| | | || |_| |
    '|_|  |_| \___||_| |_| \__,_|
    '

    Private Sub AboutToolStripMenuItem_Click(sender As Object, e As EventArgs) Handles AboutToolStripMenuItem.Click
        AboutBox1.ShowDialog()
    End Sub

    Private Sub OnlineHelpToolStripMenuItem_Click(sender As Object, e As EventArgs) Handles OnlineHelpToolStripMenuItem.Click
        Try
            Process.Start("https://www.dropcontroller.com")
        Catch ex As Exception
            MsgBox("Can't load Web page" & vbCrLf & ex.Message)
        End Try
    End Sub


    'Private Sub ToolStripMenuItem1_Click(sender As Object, e As EventArgs)
    'Try
    '       Process.Start("https://www.dropcontroller.com/forums/")
    'Catch ex As Exception
    '       MsgBox("Can't load Web page" & vbCrLf & ex.Message)
    'End Try
    'End Sub



    Private Sub MainForm_FormClosing(sender As Object, e As FormClosingEventArgs) Handles MyBase.FormClosing
        debug("Close X selected")
        CloseProgram()
    End Sub

    Private Sub ExitButton_BTN_Click(sender As Object, e As EventArgs) Handles ExitToolStripMenuItem.Click
        debug("Menu Exit selected")
        Me.Close()
    End Sub

    ' mode, 1, 2 , 3
    '  Resume 1 	
    ' The operating system Is about To Resume from a suspended state.    

    ' StatusChange 	2 	
    ' A power mode status notification Event has been raised by the operating system. This might indicate a weak Or charging battery, a transition between AC power And battery, Or another change In the status Of the system power supply.

    ' Suspend 	3 	
    ' The operating system Is about To be suspended.

    Private Sub SystemEvents_PowerModeChanged(ByVal sender As Object, ByVal e As PowerModeChangedEventArgs)

        debug("e.mode = " & e.Mode)

        Select Case e.Mode


            Case PowerModes.Suspend
                debug("suspend = " & Now)
                'txtSuspend.Text = Now

            Case PowerModes.Resume
                ' txtResume.Text = Now
                debug("resume = " & Now)

        End Select

    End Sub




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

    Private Sub MainForm_Load(sender As Object, e As EventArgs) Handles MyBase.Load


        AddHandler SystemEvents.PowerModeChanged, AddressOf SystemEvents_PowerModeChanged

        Me.FormBorderStyle = FormBorderStyle.FixedSingle
        MaximizeBox = False


        If (DEBUG_MASTER = True) Then
            turnDebugOn()
            If (useDebugLogFile) Then openDebugLogFile()
        Else
            turnDebugOff()
        End If

        debug(vbCrLf & "Program start" & vbCrLf)


        ' Lazy programing. I do not use element(0) in arrays. 
        ' copy the object reference in to arrays
        RowLabels = {D1Row_LBL, D1Row_LBL, D2Row_LBL, D3Row_LBL, D4Row_LBL, D5Row_LBL, D6Row_LBL, D7Row_LBL, D8Row_LBL, D9Row_LBL}
        drop_onOff_BTNS = {drop1_onOff_Btn, drop1_onOff_Btn, drop2_onOff_Btn, drop3_onOff_Btn, drop4_onOff_Btn, drop5_onOff_Btn, drop6_onOff_Btn, drop7_onOff_Btn, drop8_onOff_Btn, drop9_onOff_Btn}
        SolCBs = {D1Sol_CB, D1Sol_CB, D2Sol_CB, D3Sol_CB, D4Sol_CB, D5Sol_CB, D6Sol_CB, D7Sol_CB, D8Sol_CB, D9Sol_CB}
        StartTimes = {D1StartTime_TB, D1StartTime_TB, D2StartTime_TB, D3StartTime_TB, D4StartTime_TB, D5StartTime_TB, D6StartTime_TB, D7StartTime_TB, D8StartTime_TB, D9StartTime_TB}
        StartIncDecBtns = {D1StartIncDec_BTN, D1StartIncDec_BTN, D2StartIncDec_BTN, D3StartIncDec_BTN, D4StartIncDec_BTN, D5StartIncDec_BTN, D6StartIncDec_BTN, D7StartIncDec_BTN, D8StartIncDec_BTN, D9StartIncDec_BTN}
        StartIncDecVals = {D1StartIncVal_TB, D1StartIncVal_TB, D2StartIncVal_TB, D3StartIncVal_TB, D4StartIncVal_TB, D5StartIncVal_TB, D6StartIncVal_TB, D7StartIncVal_TB, D8StartIncVal_TB, D9StartIncVal_TB}
        Sizes = {D1Size_TB, D1Size_TB, D2Size_TB, D3Size_TB, D4Size_TB, D5Size_TB, D6Size_TB, D7Size_TB, D8Size_TB, D9Size_TB}
        SizeIncDecBtns = {D1SizeIncDec_BTN, D1SizeIncDec_BTN, D2SizeIncDec_BTN, D3SizeIncDec_BTN, D4SizeIncDec_BTN, D5SizeIncDec_BTN, D6SizeIncDec_BTN, D7SizeIncDec_BTN, D8SizeIncDec_BTN, D9SizeIncDec_BTN}
        SizeIncDecVals = {D1SizeIncVal_TB, D1SizeIncVal_TB, D2SizeIncVal_TB, D3SizeIncVal_TB, D4SizeIncVal_TB, D5SizeIncVal_TB, D6SizeIncVal_TB, D7SizeIncVal_TB, D8SizeIncVal_TB, D9SizeIncVal_TB}


        ' set device version 3 as the default. Only used if there are no data files
        If Version_ComboBox.Items.Count > 0 Then
            Version_ComboBox.SelectedIndex = 1    ' The first item has index 0 '
        End If


        ' hide the loopPage
        Me.Height = 600

        versionNumber = Assembly.GetExecutingAssembly().GetName().Version
        '  versionString = "dropController build " & versionNumber.ToString()
        Me.Text = "dropController"


        ' About page
        About05_LBL.Text = "App version: " & versionNumber.ToString() & vbCrLf
        'About05_LBL.Text = About05_LBL.Text + vbCrLf & "Compatible with:" & vbCrLf & "- device V2 with sketch 2019_V2_001 or higher." & vbCrLf & "- device V3 with sketch 2019_V3_005_01 or higher."


        GroupBox1.Visible = False
        GroupBox1.Location = New Point(12, 40)
        GroupBox1.BringToFront()

        TestConnection_BTN.Enabled = False

        loadSettings()


        loadDropData()

        If (Version_ComboBox.Text = "2") Then
            FT2_OnOff_BUTTON.Text = "OFF"
            FT3_OnOff_BUTTON.Text = "OFF"
        End If

        UpdateRows()
        updateLoopElements()

        startBTNoff()
        PopulateCOMport()

        debug("Initialised and ready to start" & vbCrLf)


    End Sub




    Private Sub CloseProgram()
        debug("Program closing")
        closeValves()
        saveSettings()
        saveDropData()
        disconnect()

        If (useDebugLogFile) Then
            closeDebugLogFile()
        End If


    End Sub














    '  _____                                  _            
    ' / ____|                                | |              
    '| |      ___   _ __   _ __    ___   ___ | |_    
    '| |     / _ \ | '_ \ | '_ \  / _ \ / __|| __|  
    '| |____| (_) || | | || | | ||  __/| (__ | |_   
    ' \_____|\___/ |_| |_||_| |_| \___| \___| \__|                                                            
    '                                                                                                                               
    ' After connecting wait for the user to click the start button
    '

#Region "Connect & Disconnect"

    Private Sub RefreshCOM_BTN_Click_1(sender As Object, e As EventArgs) Handles refreshCOM_BTN.Click
        PopulateCOMport()
    End Sub


    Private Sub PopulateCOMport()
        COMport_CB.Text = ""
        COMport_CB.Items.Clear()
        For Each sp As String In My.Computer.Ports.SerialPortNames
            COMport_CB.Items.Add(sp)
        Next

        debug("COM port list updated")

    End Sub


    Private Sub Connect_BTN_Click_1(sender As Object, e As EventArgs) Handles connect_BTN.Click
        debug("connect_BTN_Click")
        debug("  SerialPort1.IsOpen= " & SerialPort1.IsOpen)


        If (connect_BTN.Text = "Connect" And SerialPort1.IsOpen) Then
            debug("  BTN.text = Connect & serial port is already open")
        End If



        If (connect_BTN.Text = "Connect") Then


            If (COMport_CB.SelectedItem = "") Then
                connect_BTN.Text = "Connect"
                debug("  ERROR: No COM port selected")
                MsgBox("Select a COM port first", , "ERROR")

            Else

                connect_BTN.Text = "Connecting..."
                connect_BTN.Enabled = False

                ' the timer takes care of the next bit
                ' without a timer, the button text change is too fast (or does not happen)
                timer_updateConnectButton.Enabled = True

            End If

        ElseIf (connect_BTN.Text = "Dis-connect") Then
            disconnect()
        End If

    End Sub



    Private Sub Timer_updateConnectButton_Tick(sender As Object, e As EventArgs) Handles timer_updateConnectButton.Tick

        ' this is used to change the CONNECT BUTTON text to "Connecting..."
        ' without a timer the text does not change.  The timer is set to 100ms

        timer_updateConnectButton.Enabled = False

        debug("timer_updateConnectButton_Tick")
        If (SerialPort1.IsOpen) Then
            debug("  Error: " & comPORT & " already open")
        End If


        comPORT = COMport_CB.SelectedItem

        If (Not SerialPort1.IsOpen) Then

            SerialPort1.PortName = comPORT
            SerialPort1.BaudRate = 9600
            SerialPort1.DataBits = 8
            SerialPort1.Parity = Parity.None
            SerialPort1.StopBits = StopBits.One
            SerialPort1.Handshake = Handshake.None
            SerialPort1.Encoding = System.Text.Encoding.Default
            SerialPort1.ReadTimeout = 10000

            'Arduino Leonardo
            ' Not really sure if I need to separate this bit or just include for all models

            If (SET_LEO_BUT.Text = "ON") Then
                SerialPort1.DtrEnable = True
                SerialPort1.RtsEnable = True
            End If

            ' check if device is avaiable: 
            Try
                SerialPort1.Open()
            Catch ex As Exception
                connect_BTN.Text = "Connect"
                connect_BTN.Enabled = True

                debug("  Failed to open" & comPORT)
                debug("  - Error = " & ex.Message)
                MsgBox("Error. Cannot open COM port: " & ex.Message, MsgBoxStyle.Critical, "ERROR")
            End Try


        Else
            debug("  Error: " & comPORT & " already open")
        End If




        If (SerialPort1.IsOpen) Then

            SerialPort1.DiscardInBuffer()
            receivedData = ""

            debug("COM " & comPORT & " opened")


            'See if the dropController is there - send HELLO message and wait for a reply
            sendCommandToDropController("[HELLO]")
            debug("HELLO sent" & vbCrLf)


            ' start checkSerialData timer
            ' start connection timeout timer
            ' wait for a reply from the dropController or timeout if no reply received

            Timer_recieveSerialDataOn()
            Timer_ConnectionTimeoutON()


        End If

    End Sub






    Private Sub Timer_checkConnect_Tick(sender As Object, e As EventArgs) Handles Timer_ConnectionTimeout.Tick

        ' if this fires the HELLO message has not been  received
        ' show error message
        ' reset the buttons etc

        Timer_ConnectionTimeoutOFF()

        connect_BTN.Text = "Connect"
        debug("HELLO reply message not received from the dropController")
        MsgBox("ERROR!" & vbCrLf & "Cannot connect to the dropController")


        If (SerialPort1.IsOpen) Then
            SerialPort1.Close()
            debug("Serial port closed")
        End If

        populateCOMport()
        connect_BTN.Enabled = True

    End Sub





    Private Sub disconnect()
        'close the connection a reset the button and timer labels

        Timer_ConnectionTimeoutOFF()


        If (SerialPort1.IsOpen) Then
            sendCommandToDropController("[BYE]")
            'SerialPort1.Write("<BYE>")
            closeValves()
            receivedData = ""
            SerialPort1.DiscardInBuffer()
            SerialPort1.Close()
            debug("COM port closed")
        End If

        connect_BTN.Text = "Connect"
        COMport_CB.Enabled = True
        refreshCOM_BTN.Enabled = True
        startBTNoff()
        'PopulateCOMport()

        TestConnection_BTN.Enabled = False
        disableValveDrainButtons()
        'connected = False



    End Sub


    Private Sub TestConnection_BTN_Click(sender As Object, e As EventArgs) Handles TestConnection_BTN.Click
        TestConnection_BTN.Text = "Checking..."
        TestConnection_BTN.Enabled = False
        sendCommandToDropController("[AYT]")
        Timer_TestConnection_TimeoutON()
    End Sub



    Private Sub Timer_TestConnection_Timeout_Tick(sender As Object, e As EventArgs) Handles Timer_TestConnection_Timeout.Tick
        Timer_TestConnection_TimeoutOFF()

        MsgBox("No reply received", , "Check Connection")
        TestConnection_BTN.Text = "Test Connection"
        TestConnection_BTN.Enabled = True

    End Sub






#End Region 'Region "Connect & Disconnect"














    ' _                        _        _                           _         _         
    '| |                      | |      | |                         | |       | |        
    '| |      ___    __ _   __| |    __| | _ __  ___   _ __      __| |  __ _ | |_  __ _ 
    '| |     / _ \  / _` | / _` |   / _` || '__|/ _ \ | '_ \    / _` | / _` || __|/ _` |
    '| |____| (_) || (_| || (_| |  | (_| || |  | (_) || |_) |  | (_| || (_| || |_| (_| |
    '|______|\___/  \__,_| \__,_|   \__,_||_|   \___/ | .__/    \__,_| \__,_| \__|\__,_|
    '                                                 | |                               
    '                                                 |_|                               
    '
    Private Sub loadDropData()
        debug(vbCrLf & "Enter load drop data")

        Dim filename As String = "dropData.txt"
        Dim tmp As String = ""
        Dim foundPos As Integer = 0

        If My.Computer.FileSystem.FileExists(filename) Then
            debug(" - dropData file found")
        Else
            debug(" - dropData file not found")
        End If


        If Not System.IO.File.Exists(filename) Then
            ' file does not exist create new file

            debug(" - dropData file does not exist. Creating a new file.")
            saveDropData()
        End If


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


        ' file header
        tmp = fileReader.ReadLine()

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

            debug("  dropData loaded = " & tmp)


            'if tmp contains "|" then parse
            foundPos = InStr(1, tmp, "|", CompareMethod.Text)

            If (foundPos > 0) Then
                Dim tmpSplit() As String = Split(tmp, "|", -1, CompareMethod.Text)

                'numDrops|2
                If (tmpSplit(0) = "numDrops") Then
                    Dim tmpVal As Integer = Val(tmpSplit(1))
                    If (tmpVal >= 1 And tmpVal <= 9) Then
                        NumDrops_CB.Text = " " & tmpSplit(1)
                    Else
                        NumDrops_CB.Text = numDrops
                    End If

                End If


                'FT1|1234|INC|000|OFF
                If (tmpSplit(0) = "FT1") Then

                    If (Val(tmpSplit(1) >= 0 And Val(tmpSplit(1)) <= 9999)) Then
                        FT1_Time_TB.Text = tmpSplit(1)
                    Else
                        FT1_Time_TB.Text = "0000"
                    End If

                    If (tmpSplit(1) = "INC" Or tmpSplit(2) = "DEC") Then
                        FT1_IncDec_BTN.Text = tmpSplit(2)
                    Else
                        FT1_IncDec_BTN.Text = "INC"
                    End If

                    If (Val(tmpSplit(3) >= 0 And tmpSplit(3) <= 999)) Then
                        FT1_IncDecTime_TB.Text = tmpSplit(3)
                    Else
                        FT1_IncDecTime_TB.Text = "000"
                    End If

                    If (tmpSplit(4) = "ON" Or tmpSplit(4) = "OFF") Then
                        FT1_OnOff_BUTTON.Text = tmpSplit(4)
                    Else
                        FT1_OnOff_BUTTON.Text = "OFF"
                    End If

                End If



                'FT2|1234|INC|000|OFF
                If (tmpSplit(0) = "FT2") Then

                    If (Val(tmpSplit(1) >= 0 And Val(tmpSplit(1)) <= 9999)) Then
                        FT2_Time_TB.Text = tmpSplit(1)
                    Else
                        FT2_Time_TB.Text = "0000"
                    End If

                    If (tmpSplit(1) = "INC" Or tmpSplit(2) = "DEC") Then
                        FT2_IncDec_BTN.Text = tmpSplit(2)
                    Else
                        FT2_IncDec_BTN.Text = "INC"
                    End If

                    If (Val(tmpSplit(3) >= 0 And tmpSplit(3) <= 999)) Then
                        FT2_IncDecTime_TB.Text = tmpSplit(3)
                    Else
                        FT2_IncDecTime_TB.Text = "000"
                    End If

                    If (tmpSplit(4) = "ON" Or tmpSplit(4) = "OFF") Then
                        FT2_OnOff_BUTTON.Text = tmpSplit(4)
                    Else
                        FT2_OnOff_BUTTON.Text = "OFF"
                    End If

                End If


                'FT3|1234|INC|000|OFF
                If (tmpSplit(0) = "FT3") Then

                    If (Val(tmpSplit(1) >= 0 And Val(tmpSplit(1)) <= 9999)) Then
                        FT3_Time_TB.Text = tmpSplit(1)
                    Else
                        FT3_Time_TB.Text = "0000"
                    End If

                    If (tmpSplit(1) = "INC" Or tmpSplit(2) = "DEC") Then
                        FT3_IncDec_BTN.Text = tmpSplit(2)
                    Else
                        FT3_IncDec_BTN.Text = "INC"
                    End If

                    If (Val(tmpSplit(3) >= 0 And tmpSplit(3) <= 999)) Then
                        FT3_IncDecTime_TB.Text = tmpSplit(3)
                    Else
                        FT3_IncDecTime_TB.Text = "000"
                    End If

                    If (tmpSplit(4) = "ON" Or tmpSplit(4) = "OFF") Then
                        FT3_OnOff_BUTTON.Text = tmpSplit(4)
                    Else
                        FT3_OnOff_BUTTON.Text = "OFF"
                    End If

                End If




                'CT|0250|INC|000

                ' objWriter.WriteLine("CT|" & CT_BUTTON.Text & "|" & CT_StartTime_TB.Text & "|" & CT_IncDec_BTN.Text & "|" & CT_IncDecTime_TB.Text)
                If (tmpSplit(0) = "CT") Then
                    CT_BUTTON.Text = tmpSplit(1)
                    CT_StartTime_TB.Text = tmpSplit(2)
                    CT_IncDec_BTN.Text = tmpSplit(3)
                    CT_IncDecTime_TB.Text = tmpSplit(4)
                End If

                'Drop1|ON| 1|0000|INC|000|0000|INC|000
                If (Microsoft.VisualBasic.Strings.Left(tmpSplit(0), 4) = "Drop") Then
                    Dim i As Integer = Val(Microsoft.VisualBasic.Strings.Right(tmpSplit(0), 1))
                    drop_onOff_BTNS(i).Text = tmpSplit(1)
                    SolCBs(i).Text = tmpSplit(2)
                    StartTimes(i).Text = tmpSplit(3)
                    StartIncDecBtns(i).Text = tmpSplit(4)
                    StartIncDecVals(i).Text = tmpSplit(5)
                    Sizes(i).Text = tmpSplit(6)
                    SizeIncDecBtns(i).Text = tmpSplit(7)
                    SizeIncDecVals(i).Text = tmpSplit(8)
                End If

            End If
        End While
        fileReader.Close()

        debug("Exit load drop data")

        formatValues()
        updateSidePanel()

    End Sub








    '  _____                           _                           _         _         
    ' / ____|                         | |                         | |       | |        
    '| (___    __ _ __   __ ___     __| | _ __  ___   _ __      __| |  __ _ | |_  __ _ 
    ' \___ \  / _` |\ \ / // _ \   / _` || '__|/ _ \ | '_ \    / _` | / _` || __|/ _` |
    ' ____) || (_| | \ V /|  __/  | (_| || |  | (_) || |_) |  | (_| || (_| || |_| (_| |
    '|_____/  \__,_|  \_/  \___|   \__,_||_|   \___/ | .__/    \__,_| \__,_| \__|\__,_|
    '                                                | |                               
    '                                                |_|                               
    '
    Private Sub saveDropData()

        debug(vbCrLf & "Enter saveDropData()")

        formatValues()

        Dim objCurrentDate As Date = DateTime.Today
        Dim currentDate As String = Format(objCurrentDate, "dd/MM/yyyy")
        Dim objCurrentTime As Date = TimeOfDay
        Format(DateTime.Today, "dd/MM/yyyy")

        Dim tmpVar As Long = 0


        Dim filename As String = "dropData.txt"
        If (System.IO.File.Exists(filename) = False) Then
            System.IO.File.Create(filename).Dispose()
        End If

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

        objWriter.WriteLine("dropController: Drop data file")
        objWriter.WriteLine("Saved: " & currentDate & " " & objCurrentTime)
        objWriter.WriteLine("numDrops|" & Val(NumDrops_CB.Text))

        objWriter.WriteLine("CT|" & CT_BUTTON.Text & "|" & CT_StartTime_TB.Text & "|" & CT_IncDec_BTN.Text & "|" & CT_IncDecTime_TB.Text)

        objWriter.WriteLine("FT1|" & FT1_Time_TB.Text & "|" & FT1_IncDec_BTN.Text & "|" & FT1_IncDecTime_TB.Text & "|" & FT1_OnOff_BUTTON.Text)
        objWriter.WriteLine("FT2|" & FT2_Time_TB.Text & "|" & FT2_IncDec_BTN.Text & "|" & FT2_IncDecTime_TB.Text & "|" & FT2_OnOff_BUTTON.Text)
        objWriter.WriteLine("FT3|" & FT3_Time_TB.Text & "|" & FT3_IncDec_BTN.Text & "|" & FT3_IncDecTime_TB.Text & "|" & FT3_OnOff_BUTTON.Text)

        Dim fileString As String = ""
        fileString = "Drop -s-start-ID-val-size- ID-val "
        objWriter.WriteLine(fileString)


        For i As Integer = 1 To numDrops
            fileString = "Drop" & i & "|" & drop_onOff_BTNS(i).Text & "|" & Val(SolCBs(i).Text) & "|" & StartTimes(i).Text & "|" & StartIncDecBtns(i).Text & "|" & StartIncDecVals(i).Text & "|" & Sizes(i).Text & "|" & SizeIncDecBtns(i).Text & "|" & SizeIncDecVals(i).Text
            objWriter.WriteLine(fileString)
        Next

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


        debug("  numDrops|" & Val(NumDrops_CB.Text))
        debug("  FT1|" & FT1_Time_TB.Text & "|" & FT1_IncDec_BTN.Text & "|" & FT1_IncDecTime_TB.Text & "|" & FT1_OnOff_BUTTON.Text)
        debug("  FT2|" & FT2_Time_TB.Text & "|" & FT2_IncDec_BTN.Text & "|" & FT2_IncDecTime_TB.Text & "|" & FT2_OnOff_BUTTON.Text)
        debug("  FT3|" & FT3_Time_TB.Text & "|" & FT3_IncDec_BTN.Text & "|" & FT3_IncDecTime_TB.Text & "|" & FT3_OnOff_BUTTON.Text)

        debug("  CT|" & CT_StartTime_TB.Text & "|" & CT_IncDec_BTN.Text & "|" & CT_IncDecTime_TB.Text)
        For i As Integer = 1 To 9
            fileString = "  Drop" & i & "|" & SolCBs(i).Text & "|" & StartTimes(i).Text & "|" & StartIncDecBtns(i).Text & "|" & StartIncDecVals(i).Text & "|" & Sizes(i).Text & "|" & SizeIncDecBtns(i).Text & "|" & SizeIncDecVals(i).Text
            debug(fileString)
        Next
        debug("Exit saveDropData()")

    End Sub












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

#Region "MAIN PANEL"


    Private Sub drop1_onOff_Btn_Click(sender As Object, e As EventArgs) Handles drop1_onOff_Btn.Click
        If (drop1_onOff_Btn.Text = "ON") Then
            drop1_onOff_Btn.Text = "OFF"
        Else
            drop1_onOff_Btn.Text = "ON"
        End If
        UpdateRows()
    End Sub

    Private Sub drop2_onOff_Btn_Click(sender As Object, e As EventArgs) Handles drop2_onOff_Btn.Click
        If (drop2_onOff_Btn.Text = "ON") Then
            drop2_onOff_Btn.Text = "OFF"
        Else
            drop2_onOff_Btn.Text = "ON"
        End If
        UpdateRows()
    End Sub

    Private Sub drop3_onOff_Btn_Click(sender As Object, e As EventArgs) Handles drop3_onOff_Btn.Click
        If (drop3_onOff_Btn.Text = "ON") Then
            drop3_onOff_Btn.Text = "OFF"
        Else
            drop3_onOff_Btn.Text = "ON"
        End If
        UpdateRows()
    End Sub

    Private Sub drop4_onOff_Btn_Click(sender As Object, e As EventArgs) Handles drop4_onOff_Btn.Click
        If (drop4_onOff_Btn.Text = "ON") Then
            drop4_onOff_Btn.Text = "OFF"
        Else
            drop4_onOff_Btn.Text = "ON"
        End If
        UpdateRows()
    End Sub

    Private Sub drop5_onOff_Btn_Click(sender As Object, e As EventArgs) Handles drop5_onOff_Btn.Click
        If (drop5_onOff_Btn.Text = "ON") Then
            drop5_onOff_Btn.Text = "OFF"
        Else
            drop5_onOff_Btn.Text = "ON"
        End If
        UpdateRows()
    End Sub

    Private Sub drop6_onOff_Btn_Click(sender As Object, e As EventArgs) Handles drop6_onOff_Btn.Click
        If (drop6_onOff_Btn.Text = "ON") Then
            drop6_onOff_Btn.Text = "OFF"
        Else
            drop6_onOff_Btn.Text = "ON"
        End If
        UpdateRows()
    End Sub

    Private Sub drop7_onOff_Btn_Click(sender As Object, e As EventArgs) Handles drop7_onOff_Btn.Click
        If (drop7_onOff_Btn.Text = "ON") Then
            drop7_onOff_Btn.Text = "OFF"
        Else
            drop7_onOff_Btn.Text = "ON"
        End If
        UpdateRows()
    End Sub

    Private Sub drop8_onOff_Btn_Click(sender As Object, e As EventArgs) Handles drop8_onOff_Btn.Click
        If (drop8_onOff_Btn.Text = "ON") Then
            drop8_onOff_Btn.Text = "OFF"
        Else
            drop8_onOff_Btn.Text = "ON"
        End If
        UpdateRows()
    End Sub

    Private Sub drop9_onOff_Btn_Click(sender As Object, e As EventArgs) Handles drop9_onOff_Btn.Click
        If (drop9_onOff_Btn.Text = "ON") Then
            drop9_onOff_Btn.Text = "OFF"
        Else
            drop9_onOff_Btn.Text = "ON"
        End If
        UpdateRows()
    End Sub



    Private Sub D1Sol_CB_SelectedIndexChanged(sender As Object, e As EventArgs)
        D1Sol_CB.ForeColor = Color.Black
    End Sub

    Private Sub D2Sol_CB_SelectedIndexChanged(sender As Object, e As EventArgs)
        D2Sol_CB.ForeColor = Color.Black
    End Sub

    Private Sub D3Sol_CB_SelectedIndexChanged(sender As Object, e As EventArgs)
        D3Sol_CB.ForeColor = Color.Black
    End Sub

    Private Sub D4Sol_CB_SelectedIndexChanged(sender As Object, e As EventArgs)
        D4Sol_CB.ForeColor = Color.Black
    End Sub

    Private Sub D5Sol_CB_SelectedIndexChanged(sender As Object, e As EventArgs)
        D5Sol_CB.ForeColor = Color.Black
    End Sub

    Private Sub D6Sol_CB_SelectedIndexChanged(sender As Object, e As EventArgs)
        D6Sol_CB.ForeColor = Color.Black
    End Sub

    Private Sub D7Sol_CB_SelectedIndexChanged(sender As Object, e As EventArgs)
        D7Sol_CB.ForeColor = Color.Black
    End Sub

    Private Sub D8Sol_CB_SelectedIndexChanged(sender As Object, e As EventArgs)
        D8Sol_CB.ForeColor = Color.Black
    End Sub

    Private Sub D9Sol_CB_SelectedIndexChanged(sender As Object, e As EventArgs)
        D9Sol_CB.ForeColor = Color.Black
    End Sub




    Private Sub updateIncDec_BTN(ByVal theClickedButton As Button)
        If (theClickedButton.Text = "OFF") Then
            theClickedButton.Text = "INC"
        ElseIf (theClickedButton.Text = "INC") Then
            theClickedButton.Text = "DEC"
        ElseIf (theClickedButton.Text = "DEC") Then
            theClickedButton.Text = "OFF"
        End If


        Dim tmpBTN As Button = DirectCast(theClickedButton, Button)
        Dim name As String = tmpBTN.Name
        debug(name & " changed to " & theClickedButton.Text)

        UpdateRows()

    End Sub


    Private Sub D1StartIncDec_BTN_Click(sender As Object, e As EventArgs) Handles D1StartIncDec_BTN.Click
        updateIncDec_BTN(sender)
    End Sub

    Private Sub D1SizeIncDec_BTN_Click(sender As Object, e As EventArgs) Handles D1SizeIncDec_BTN.Click
        updateIncDec_BTN(sender)
    End Sub

    Private Sub D2StartIncDec_BTN_Click(sender As Object, e As EventArgs) Handles D2StartIncDec_BTN.Click
        updateIncDec_BTN(sender)
    End Sub

    Private Sub D2SizeIncDec_BTN_Click(sender As Object, e As EventArgs) Handles D2SizeIncDec_BTN.Click
        updateIncDec_BTN(sender)
    End Sub

    Private Sub D3StartIncDec_BTN_Click(sender As Object, e As EventArgs) Handles D3StartIncDec_BTN.Click
        updateIncDec_BTN(sender)
    End Sub

    Private Sub D3SizeIncDec_BTN_Click(sender As Object, e As EventArgs) Handles D3SizeIncDec_BTN.Click
        updateIncDec_BTN(sender)
    End Sub

    Private Sub D4StartIncDec_BTN_Click(sender As Object, e As EventArgs) Handles D4StartIncDec_BTN.Click
        updateIncDec_BTN(sender)
    End Sub

    Private Sub D4SizeIncDec_BTN_Click(sender As Object, e As EventArgs) Handles D4SizeIncDec_BTN.Click
        updateIncDec_BTN(sender)
    End Sub

    Private Sub D5StartIncDec_BTN_Click(sender As Object, e As EventArgs) Handles D5StartIncDec_BTN.Click
        updateIncDec_BTN(sender)
    End Sub

    Private Sub D5SizeIncDec_BTN_Click(sender As Object, e As EventArgs) Handles D5SizeIncDec_BTN.Click
        updateIncDec_BTN(sender)
    End Sub

    Private Sub D6StartIncDec_BTN_Click(sender As Object, e As EventArgs) Handles D6StartIncDec_BTN.Click
        updateIncDec_BTN(sender)
    End Sub

    Private Sub D6SizeIncDec_BTN_Click(sender As Object, e As EventArgs) Handles D6SizeIncDec_BTN.Click
        updateIncDec_BTN(sender)
    End Sub

    Private Sub D7StartIncDec_BTN_Click(sender As Object, e As EventArgs) Handles D7StartIncDec_BTN.Click
        updateIncDec_BTN(sender)
    End Sub

    Private Sub D7SizeIncDec_BTN_Click(sender As Object, e As EventArgs) Handles D7SizeIncDec_BTN.Click
        updateIncDec_BTN(sender)
    End Sub

    Private Sub D8StartIncDec_BTN_Click(sender As Object, e As EventArgs) Handles D8StartIncDec_BTN.Click
        updateIncDec_BTN(sender)
    End Sub

    Private Sub D8SizeIncDec_BTN_Click(sender As Object, e As EventArgs) Handles D8SizeIncDec_BTN.Click
        updateIncDec_BTN(sender)
    End Sub

    Private Sub D9StartIncDec_BTN_Click(sender As Object, e As EventArgs) Handles D9StartIncDec_BTN.Click
        updateIncDec_BTN(sender)
    End Sub

    Private Sub D9SizeIncDec_BTN_Click(sender As Object, e As EventArgs) Handles D9SizeIncDec_BTN.Click
        updateIncDec_BTN(sender)
    End Sub


#End Region 'Region "MAIN PANEL"











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

#Region "ValidateUserInput"


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

    Private Sub formatTB(ByVal TB As TextBox, numDigits As Integer)
        If (numDigits = 2) Then
            TB.Text = Format(Val(TB.Text), "00")
        ElseIf (numDigits = 3) Then
            TB.Text = Format(Val(TB.Text), "000")
        ElseIf (numDigits = 4) Then
            TB.Text = Format(Val(TB.Text), "0000")
        End If

        Dim tmpTB As TextBox = DirectCast(TB, TextBox)
        Dim name As String = tmpTB.Name
        debug(name & " changed to " & TB.Text)
    End Sub


    Private Sub D1StartTime_TB_Leave(sender As Object, e As EventArgs) Handles D1StartTime_TB.Leave
        formatTB(sender, 4)
    End Sub

    Private Sub D2StartTime_TB_Leave(sender As Object, e As EventArgs) Handles D2StartTime_TB.Leave
        formatTB(sender, 4)
    End Sub

    Private Sub D3StartTime_TB_Leave(sender As Object, e As EventArgs) Handles D3StartTime_TB.Leave
        formatTB(sender, 4)
    End Sub

    Private Sub D4StartTime_TB_Leave(sender As Object, e As EventArgs) Handles D4StartTime_TB.Leave
        formatTB(sender, 4)
    End Sub

    Private Sub D5StartTime_TB_Leave(sender As Object, e As EventArgs) Handles D5StartTime_TB.Leave
        formatTB(sender, 4)
    End Sub

    Private Sub D6StartTime_TB_Leave(sender As Object, e As EventArgs) Handles D6StartTime_TB.Leave
        formatTB(sender, 4)
    End Sub

    Private Sub D7StartTime_TB_Leave(sender As Object, e As EventArgs) Handles D7StartTime_TB.Leave
        formatTB(sender, 4)
    End Sub

    Private Sub D8StartTime_TB_Leave(sender As Object, e As EventArgs) Handles D8StartTime_TB.Leave
        formatTB(sender, 4)
    End Sub

    Private Sub D9StartTime_TB_Leave(sender As Object, e As EventArgs) Handles D9StartTime_TB.Leave
        formatTB(sender, 4)
    End Sub

    Private Sub D1Size_TB_Leave(sender As Object, e As EventArgs) Handles D1Size_TB.Leave
        formatTB(sender, 4)
    End Sub
    Private Sub D2Size_TB_Leave(sender As Object, e As EventArgs) Handles D2Size_TB.Leave
        formatTB(sender, 4)
    End Sub
    Private Sub D3Size_TB_Leave(sender As Object, e As EventArgs) Handles D3Size_TB.Leave
        formatTB(sender, 4)
    End Sub
    Private Sub D4Size_TB_Leave(sender As Object, e As EventArgs) Handles D4Size_TB.Leave
        formatTB(sender, 4)
    End Sub
    Private Sub D5Size_TB_Leave(sender As Object, e As EventArgs) Handles D5Size_TB.Leave
        formatTB(sender, 4)
    End Sub
    Private Sub D6Size_TB_Leave(sender As Object, e As EventArgs) Handles D6Size_TB.Leave
        formatTB(sender, 4)
    End Sub
    Private Sub D7Size_TB_Leave(sender As Object, e As EventArgs) Handles D7Size_TB.Leave
        formatTB(sender, 4)
    End Sub
    Private Sub D8Size_TB_Leave(sender As Object, e As EventArgs) Handles D8Size_TB.Leave
        formatTB(sender, 4)
    End Sub
    Private Sub D9Size_TB_Leave(sender As Object, e As EventArgs) Handles D9Size_TB.Leave
        formatTB(sender, 4)
    End Sub



    Private Sub D1StartIncVal_TB_Leave(sender As Object, e As EventArgs) Handles D1StartIncVal_TB.Leave
        formatTB(sender, 3)
    End Sub
    Private Sub D2StartIncVal_TB_Leave(sender As Object, e As EventArgs) Handles D2StartIncVal_TB.Leave
        formatTB(sender, 3)
    End Sub
    Private Sub D3StartIncVal_TB_Leave(sender As Object, e As EventArgs) Handles D3StartIncVal_TB.Leave
        formatTB(sender, 3)
    End Sub
    Private Sub D4StartIncVal_TB_Leave(sender As Object, e As EventArgs) Handles D4StartIncVal_TB.Leave
        formatTB(sender, 3)
    End Sub
    Private Sub D5StartIncVal_TB_Leave(sender As Object, e As EventArgs) Handles D5StartIncVal_TB.Leave
        formatTB(sender, 3)
    End Sub
    Private Sub D6StartIncVal_TB_Leave(sender As Object, e As EventArgs) Handles D6StartIncVal_TB.Leave
        formatTB(sender, 3)
    End Sub
    Private Sub D7StartIncVal_TB_Leave(sender As Object, e As EventArgs) Handles D7StartIncVal_TB.Leave
        formatTB(sender, 3)
    End Sub
    Private Sub D8StartIncVal_TB_Leave(sender As Object, e As EventArgs) Handles D8StartIncVal_TB.Leave
        formatTB(sender, 3)
    End Sub
    Private Sub D9StartIncVal_TB_Leave(sender As Object, e As EventArgs) Handles D9StartIncVal_TB.Leave
        formatTB(sender, 3)
    End Sub



    Private Sub D1SizeIncVal_TB_Leave(sender As Object, e As EventArgs) Handles D1SizeIncVal_TB.Leave
        formatTB(sender, 3)
    End Sub
    Private Sub D2SizeIncVal_TB_Leave(sender As Object, e As EventArgs) Handles D2SizeIncVal_TB.Leave
        formatTB(sender, 3)
    End Sub
    Private Sub D3SizeIncVal_TB_Leave(sender As Object, e As EventArgs) Handles D3SizeIncVal_TB.Leave
        formatTB(sender, 3)
    End Sub
    Private Sub D4SizeIncVal_TB_Leave(sender As Object, e As EventArgs) Handles D4SizeIncVal_TB.Leave
        formatTB(sender, 3)
    End Sub
    Private Sub D5SizeIncVal_TB_Leave(sender As Object, e As EventArgs) Handles D5SizeIncVal_TB.Leave
        formatTB(sender, 3)
    End Sub
    Private Sub D6SizeIncVal_TB_Leave(sender As Object, e As EventArgs) Handles D6SizeIncVal_TB.Leave
        formatTB(sender, 3)
    End Sub
    Private Sub D7SizeIncVal_TB_Leave(sender As Object, e As EventArgs) Handles D7SizeIncVal_TB.Leave
        formatTB(sender, 3)
    End Sub
    Private Sub D8SizeIncVal_TB_Leave(sender As Object, e As EventArgs) Handles D8SizeIncVal_TB.Leave
        formatTB(sender, 3)
    End Sub
    Private Sub D9SizeIncVal_TB_Leave(sender As Object, e As EventArgs) Handles D9SizeIncVal_TB.Leave
        formatTB(sender, 3)
    End Sub


    Private Sub FT1_Time_TB_Leave(sender As Object, e As EventArgs) Handles FT1_Time_TB.Leave
        formatTB(sender, 4)
    End Sub
    Private Sub FT1_IncDecTime_TB_Leave(sender As Object, e As EventArgs) Handles FT1_IncDecTime_TB.Leave
        formatTB(sender, 3)
    End Sub

    Private Sub FT2_Time_TB_Leave(sender As Object, e As EventArgs) Handles FT2_Time_TB.Leave
        formatTB(sender, 4)
    End Sub
    Private Sub FT2_IncDecTime_TB_Leave(sender As Object, e As EventArgs) Handles FT2_IncDecTime_TB.Leave
        formatTB(sender, 3)
    End Sub

    Private Sub FT3_Time_TB_Leave(sender As Object, e As EventArgs) Handles FT3_Time_TB.Leave
        formatTB(sender, 4)
    End Sub
    Private Sub FT3_IncDecTime_TB_Leave(sender As Object, e As EventArgs) Handles FT3_IncDecTime_TB.Leave
        formatTB(sender, 3)
    End Sub



    Private Sub ShutterTriggerTime_TB_Leave(sender As Object, e As EventArgs) Handles CT_StartTime_TB.Leave
        formatTB(sender, 4)
    End Sub
    Private Sub ShutterTriggerIncDecTime_TB_Leave(sender As Object, e As EventArgs) Handles CT_IncDecTime_TB.Leave
        formatTB(sender, 3)
    End Sub

    Private Sub LP_waitTimeVal_TB_Leave(sender As Object, e As EventArgs) Handles LP_waitTimeVal_TB.Leave
        formatTB(sender, 2)
    End Sub



    Private Sub mirrorLockupTime_TB_Leave(sender As Object, e As EventArgs) Handles mirrorLockupTime_TB.Leave
        formatTB(sender, 4)
    End Sub


    Private Sub FT1_Pulse_TB_Leave(sender As Object, e As EventArgs) Handles FT1_Pulse_TB.Leave
        formatTB(sender, 3)
    End Sub
    Private Sub FT2_Pulse_TB_Leave(sender As Object, e As EventArgs) Handles FT2_Pulse_TB.Leave
        formatTB(sender, 3)
    End Sub
    Private Sub FT3_Pulse_TB_Leave(sender As Object, e As EventArgs) Handles FT3_Pulse_TB.Leave
        formatTB(sender, 3)
    End Sub

    Private Sub CAM_Pulse_TB_Leave(sender As Object, e As EventArgs) Handles CT_Pulse_TB.Leave
        formatTB(sender, 3)
    End Sub

    Private Sub BulbStartOffset_Time_TB_Leave(sender As Object, e As EventArgs) Handles BulbStartOffset_Time_TB.Leave
        formatTB(sender, 4)
    End Sub

    Private Sub BulbStopOffset_Time_TB_Leave(sender As Object, e As EventArgs) Handles BulbStopOffset_Time_TB.Leave
        formatTB(sender, 4)
    End Sub













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

    ' allow only numeric characters

    Private Sub D1StartTime_TB_KeyPress(sender As Object, e As KeyPressEventArgs) Handles D1StartTime_TB.KeyPress
        If Asc(e.KeyChar) <> 13 AndAlso Asc(e.KeyChar) <> 8 AndAlso Not IsNumeric(e.KeyChar) Then
            e.Handled = True
        End If
    End Sub
    Private Sub D2StartTime_TB_KeyPress(sender As Object, e As KeyPressEventArgs) Handles D2StartTime_TB.KeyPress
        If Asc(e.KeyChar) <> 13 AndAlso Asc(e.KeyChar) <> 8 AndAlso Not IsNumeric(e.KeyChar) Then
            e.Handled = True
        End If
    End Sub
    Private Sub D3StartTime_TB_KeyPress(sender As Object, e As KeyPressEventArgs) Handles D3StartTime_TB.KeyPress
        If Asc(e.KeyChar) <> 13 AndAlso Asc(e.KeyChar) <> 8 AndAlso Not IsNumeric(e.KeyChar) Then
            e.Handled = True
        End If
    End Sub
    Private Sub D4StartTime_TB_KeyPress(sender As Object, e As KeyPressEventArgs) Handles D4StartTime_TB.KeyPress
        If Asc(e.KeyChar) <> 13 AndAlso Asc(e.KeyChar) <> 8 AndAlso Not IsNumeric(e.KeyChar) Then
            e.Handled = True
        End If
    End Sub
    Private Sub D5StartTime_TB_KeyPress(sender As Object, e As KeyPressEventArgs) Handles D5StartTime_TB.KeyPress
        If Asc(e.KeyChar) <> 13 AndAlso Asc(e.KeyChar) <> 8 AndAlso Not IsNumeric(e.KeyChar) Then
            e.Handled = True
        End If
    End Sub
    Private Sub D6StartTime_TB_KeyPress(sender As Object, e As KeyPressEventArgs) Handles D6StartTime_TB.KeyPress
        If Asc(e.KeyChar) <> 13 AndAlso Asc(e.KeyChar) <> 8 AndAlso Not IsNumeric(e.KeyChar) Then
            e.Handled = True
        End If
    End Sub
    Private Sub D7StartTime_TB_KeyPress(sender As Object, e As KeyPressEventArgs) Handles D7StartTime_TB.KeyPress
        If Asc(e.KeyChar) <> 13 AndAlso Asc(e.KeyChar) <> 8 AndAlso Not IsNumeric(e.KeyChar) Then
            e.Handled = True
        End If
    End Sub
    Private Sub D8StartTime_TB_KeyPress(sender As Object, e As KeyPressEventArgs) Handles D8StartTime_TB.KeyPress
        If Asc(e.KeyChar) <> 13 AndAlso Asc(e.KeyChar) <> 8 AndAlso Not IsNumeric(e.KeyChar) Then
            e.Handled = True
        End If
    End Sub
    Private Sub D9StartTime_TB_KeyPress(sender As Object, e As KeyPressEventArgs) Handles D9StartTime_TB.KeyPress
        If Asc(e.KeyChar) <> 13 AndAlso Asc(e.KeyChar) <> 8 AndAlso Not IsNumeric(e.KeyChar) Then
            e.Handled = True
        End If
    End Sub



    Private Sub D1StartIncVal_TB_KeyPress(sender As Object, e As KeyPressEventArgs) Handles D1StartIncVal_TB.KeyPress
        If Asc(e.KeyChar) <> 13 AndAlso Asc(e.KeyChar) <> 8 AndAlso Not IsNumeric(e.KeyChar) Then
            e.Handled = True
        End If
    End Sub
    Private Sub D2StartIncVal_TB_KeyPress(sender As Object, e As KeyPressEventArgs) Handles D2StartIncVal_TB.KeyPress
        If Asc(e.KeyChar) <> 13 AndAlso Asc(e.KeyChar) <> 8 AndAlso Not IsNumeric(e.KeyChar) Then
            e.Handled = True
        End If
    End Sub
    Private Sub D3StartIncVal_TB_KeyPress(sender As Object, e As KeyPressEventArgs) Handles D3StartIncVal_TB.KeyPress
        If Asc(e.KeyChar) <> 13 AndAlso Asc(e.KeyChar) <> 8 AndAlso Not IsNumeric(e.KeyChar) Then
            e.Handled = True
        End If
    End Sub
    Private Sub D4StartIncVal_TB_KeyPress(sender As Object, e As KeyPressEventArgs) Handles D4StartIncVal_TB.KeyPress
        If Asc(e.KeyChar) <> 13 AndAlso Asc(e.KeyChar) <> 8 AndAlso Not IsNumeric(e.KeyChar) Then
            e.Handled = True
        End If
    End Sub
    Private Sub D5StartIncVal_TB_KeyPress(sender As Object, e As KeyPressEventArgs) Handles D5StartIncVal_TB.KeyPress
        If Asc(e.KeyChar) <> 13 AndAlso Asc(e.KeyChar) <> 8 AndAlso Not IsNumeric(e.KeyChar) Then
            e.Handled = True
        End If
    End Sub
    Private Sub D6StartIncVal_TB_KeyPress(sender As Object, e As KeyPressEventArgs) Handles D6StartIncVal_TB.KeyPress
        If Asc(e.KeyChar) <> 13 AndAlso Asc(e.KeyChar) <> 8 AndAlso Not IsNumeric(e.KeyChar) Then
            e.Handled = True
        End If
    End Sub
    Private Sub D7StartIncVal_TB_KeyPress(sender As Object, e As KeyPressEventArgs) Handles D7StartIncVal_TB.KeyPress
        If Asc(e.KeyChar) <> 13 AndAlso Asc(e.KeyChar) <> 8 AndAlso Not IsNumeric(e.KeyChar) Then
            e.Handled = True
        End If
    End Sub
    Private Sub D8StartIncVal_TB_KeyPress(sender As Object, e As KeyPressEventArgs) Handles D8StartIncVal_TB.KeyPress
        If Asc(e.KeyChar) <> 13 AndAlso Asc(e.KeyChar) <> 8 AndAlso Not IsNumeric(e.KeyChar) Then
            e.Handled = True
        End If
    End Sub
    Private Sub D9StartIncVal_TB_KeyPress(sender As Object, e As KeyPressEventArgs) Handles D9StartIncVal_TB.KeyPress
        If Asc(e.KeyChar) <> 13 AndAlso Asc(e.KeyChar) <> 8 AndAlso Not IsNumeric(e.KeyChar) Then
            e.Handled = True
        End If
    End Sub



    Private Sub D1Size_TB_KeyPress(sender As Object, e As KeyPressEventArgs) Handles D1Size_TB.KeyPress
        If Asc(e.KeyChar) <> 13 AndAlso Asc(e.KeyChar) <> 8 AndAlso Not IsNumeric(e.KeyChar) Then
            e.Handled = True
        End If
    End Sub
    Private Sub D2Size_TB_KeyPress(sender As Object, e As KeyPressEventArgs) Handles D2Size_TB.KeyPress
        If Asc(e.KeyChar) <> 13 AndAlso Asc(e.KeyChar) <> 8 AndAlso Not IsNumeric(e.KeyChar) Then
            e.Handled = True
        End If
    End Sub
    Private Sub D3Size_TB_KeyPress(sender As Object, e As KeyPressEventArgs) Handles D3Size_TB.KeyPress
        If Asc(e.KeyChar) <> 13 AndAlso Asc(e.KeyChar) <> 8 AndAlso Not IsNumeric(e.KeyChar) Then
            e.Handled = True
        End If
    End Sub
    Private Sub D4Size_TB_KeyPress(sender As Object, e As KeyPressEventArgs) Handles D4Size_TB.KeyPress
        If Asc(e.KeyChar) <> 13 AndAlso Asc(e.KeyChar) <> 8 AndAlso Not IsNumeric(e.KeyChar) Then
            e.Handled = True
        End If
    End Sub
    Private Sub D5Size_TB_KeyPress(sender As Object, e As KeyPressEventArgs) Handles D5Size_TB.KeyPress
        If Asc(e.KeyChar) <> 13 AndAlso Asc(e.KeyChar) <> 8 AndAlso Not IsNumeric(e.KeyChar) Then
            e.Handled = True
        End If
    End Sub
    Private Sub D6Size_TB_KeyPress(sender As Object, e As KeyPressEventArgs) Handles D6Size_TB.KeyPress
        If Asc(e.KeyChar) <> 13 AndAlso Asc(e.KeyChar) <> 8 AndAlso Not IsNumeric(e.KeyChar) Then
            e.Handled = True
        End If
    End Sub
    Private Sub D7Size_TB_KeyPress(sender As Object, e As KeyPressEventArgs) Handles D7Size_TB.KeyPress
        If Asc(e.KeyChar) <> 13 AndAlso Asc(e.KeyChar) <> 8 AndAlso Not IsNumeric(e.KeyChar) Then
            e.Handled = True
        End If
    End Sub
    Private Sub D8Size_TB_KeyPress(sender As Object, e As KeyPressEventArgs) Handles D8Size_TB.KeyPress
        If Asc(e.KeyChar) <> 13 AndAlso Asc(e.KeyChar) <> 8 AndAlso Not IsNumeric(e.KeyChar) Then
            e.Handled = True
        End If
    End Sub
    Private Sub D9Size_TB_KeyPress(sender As Object, e As KeyPressEventArgs) Handles D9Size_TB.KeyPress
        If Asc(e.KeyChar) <> 13 AndAlso Asc(e.KeyChar) <> 8 AndAlso Not IsNumeric(e.KeyChar) Then
            e.Handled = True
        End If
    End Sub



    Private Sub D1SizeIncVal_TB_KeyPress(sender As Object, e As KeyPressEventArgs) Handles D1SizeIncVal_TB.KeyPress
        If Asc(e.KeyChar) <> 13 AndAlso Asc(e.KeyChar) <> 8 AndAlso Not IsNumeric(e.KeyChar) Then
            e.Handled = True
        End If
    End Sub
    Private Sub D2SizeIncVal_TB_KeyPress(sender As Object, e As KeyPressEventArgs) Handles D2SizeIncVal_TB.KeyPress
        If Asc(e.KeyChar) <> 13 AndAlso Asc(e.KeyChar) <> 8 AndAlso Not IsNumeric(e.KeyChar) Then
            e.Handled = True
        End If
    End Sub
    Private Sub D3SizeIncVal_TB_KeyPress(sender As Object, e As KeyPressEventArgs) Handles D3SizeIncVal_TB.KeyPress
        If Asc(e.KeyChar) <> 13 AndAlso Asc(e.KeyChar) <> 8 AndAlso Not IsNumeric(e.KeyChar) Then
            e.Handled = True
        End If
    End Sub
    Private Sub D4SizeIncVal_TB_KeyPress(sender As Object, e As KeyPressEventArgs) Handles D4SizeIncVal_TB.KeyPress
        If Asc(e.KeyChar) <> 13 AndAlso Asc(e.KeyChar) <> 8 AndAlso Not IsNumeric(e.KeyChar) Then
            e.Handled = True
        End If
    End Sub
    Private Sub D5SizeIncVal_TB_KeyPress(sender As Object, e As KeyPressEventArgs) Handles D5SizeIncVal_TB.KeyPress
        If Asc(e.KeyChar) <> 13 AndAlso Asc(e.KeyChar) <> 8 AndAlso Not IsNumeric(e.KeyChar) Then
            e.Handled = True
        End If
    End Sub
    Private Sub D6SizeIncVal_TB_KeyPress(sender As Object, e As KeyPressEventArgs) Handles D6SizeIncVal_TB.KeyPress
        If Asc(e.KeyChar) <> 13 AndAlso Asc(e.KeyChar) <> 8 AndAlso Not IsNumeric(e.KeyChar) Then
            e.Handled = True
        End If
    End Sub
    Private Sub D7SizeIncVal_TB_KeyPress(sender As Object, e As KeyPressEventArgs) Handles D7SizeIncVal_TB.KeyPress
        If Asc(e.KeyChar) <> 13 AndAlso Asc(e.KeyChar) <> 8 AndAlso Not IsNumeric(e.KeyChar) Then
            e.Handled = True
        End If
    End Sub
    Private Sub D8SizeIncVal_TB_KeyPress(sender As Object, e As KeyPressEventArgs) Handles D8SizeIncVal_TB.KeyPress
        If Asc(e.KeyChar) <> 13 AndAlso Asc(e.KeyChar) <> 8 AndAlso Not IsNumeric(e.KeyChar) Then
            e.Handled = True
        End If
    End Sub
    Private Sub D9SizeIncVal_TB_KeyPress(sender As Object, e As KeyPressEventArgs) Handles D9SizeIncVal_TB.KeyPress
        If Asc(e.KeyChar) <> 13 AndAlso Asc(e.KeyChar) <> 8 AndAlso Not IsNumeric(e.KeyChar) Then
            e.Handled = True
        End If
    End Sub

    Private Sub FT1_Time_TB_KeyPress(sender As Object, e As KeyPressEventArgs) Handles FT1_Time_TB.KeyPress
        If Asc(e.KeyChar) <> 13 AndAlso Asc(e.KeyChar) <> 8 AndAlso Not IsNumeric(e.KeyChar) Then
            e.Handled = True
        End If
    End Sub

    Private Sub FT1_IncDecTime_TB_KeyPress(sender As Object, e As KeyPressEventArgs) Handles FT1_IncDecTime_TB.KeyPress
        If Asc(e.KeyChar) <> 13 AndAlso Asc(e.KeyChar) <> 8 AndAlso Not IsNumeric(e.KeyChar) Then
            e.Handled = True
        End If
    End Sub

    Private Sub FT2_Time_TB_KeyPress(sender As Object, e As KeyPressEventArgs) Handles FT2_Time_TB.KeyPress
        If Asc(e.KeyChar) <> 13 AndAlso Asc(e.KeyChar) <> 8 AndAlso Not IsNumeric(e.KeyChar) Then
            e.Handled = True
        End If
    End Sub

    Private Sub FT2_IncDecTime_TB_KeyPress(sender As Object, e As KeyPressEventArgs) Handles FT2_IncDecTime_TB.KeyPress
        If Asc(e.KeyChar) <> 13 AndAlso Asc(e.KeyChar) <> 8 AndAlso Not IsNumeric(e.KeyChar) Then
            e.Handled = True
        End If
    End Sub

    Private Sub FT3_Time_TB_KeyPress(sender As Object, e As KeyPressEventArgs) Handles FT3_Time_TB.KeyPress
        If Asc(e.KeyChar) <> 13 AndAlso Asc(e.KeyChar) <> 8 AndAlso Not IsNumeric(e.KeyChar) Then
            e.Handled = True
        End If
    End Sub

    Private Sub FT3_IncDecTime_TB_KeyPress(sender As Object, e As KeyPressEventArgs) Handles FT3_IncDecTime_TB.KeyPress
        If Asc(e.KeyChar) <> 13 AndAlso Asc(e.KeyChar) <> 8 AndAlso Not IsNumeric(e.KeyChar) Then
            e.Handled = True
        End If
    End Sub


    Private Sub ShutterTriggerTime_TB_KeyPress(sender As Object, e As KeyPressEventArgs) Handles CT_StartTime_TB.KeyPress
        If Asc(e.KeyChar) <> 13 AndAlso Asc(e.KeyChar) <> 8 AndAlso Not IsNumeric(e.KeyChar) Then
            e.Handled = True
        End If
    End Sub

    Private Sub ShutterTriggerIncDecTime_TB_KeyPress(sender As Object, e As KeyPressEventArgs) Handles CT_IncDecTime_TB.KeyPress
        If Asc(e.KeyChar) <> 13 AndAlso Asc(e.KeyChar) <> 8 AndAlso Not IsNumeric(e.KeyChar) Then
            e.Handled = True
        End If
    End Sub


    ' SETTINGS 

    Private Sub LP_waitTimeVal_TB_KeyPress(sender As Object, e As KeyPressEventArgs) Handles LP_waitTimeVal_TB.KeyPress
        If Asc(e.KeyChar) <> 13 AndAlso Asc(e.KeyChar) <> 8 AndAlso Not IsNumeric(e.KeyChar) Then
            e.Handled = True
        End If
    End Sub
    Private Sub mirrorLockupTime_TB_KeyPress(sender As Object, e As KeyPressEventArgs) Handles mirrorLockupTime_TB.KeyPress
        If Asc(e.KeyChar) <> 13 AndAlso Asc(e.KeyChar) <> 8 AndAlso Not IsNumeric(e.KeyChar) Then
            e.Handled = True
        End If
    End Sub

    Private Sub FT1_Pulse_TB_KeyPress(sender As Object, e As KeyPressEventArgs) Handles FT1_Pulse_TB.KeyPress
        If Asc(e.KeyChar) <> 13 AndAlso Asc(e.KeyChar) <> 8 AndAlso Not IsNumeric(e.KeyChar) Then
            e.Handled = True
        End If
    End Sub

    Private Sub FT2_Pulse_TB_KeyPress(sender As Object, e As KeyPressEventArgs) Handles FT2_Pulse_TB.KeyPress
        If Asc(e.KeyChar) <> 13 AndAlso Asc(e.KeyChar) <> 8 AndAlso Not IsNumeric(e.KeyChar) Then
            e.Handled = True
        End If
    End Sub
    Private Sub FT3_Pulse_TB_KeyPress(sender As Object, e As KeyPressEventArgs) Handles FT3_Pulse_TB.KeyPress
        If Asc(e.KeyChar) <> 13 AndAlso Asc(e.KeyChar) <> 8 AndAlso Not IsNumeric(e.KeyChar) Then
            e.Handled = True
        End If
    End Sub


    Private Sub CT_Pulse_TB_KeyPress(sender As Object, e As KeyPressEventArgs) Handles CT_Pulse_TB.KeyPress
        If Asc(e.KeyChar) <> 13 AndAlso Asc(e.KeyChar) <> 8 AndAlso Not IsNumeric(e.KeyChar) Then
            e.Handled = True
        End If
    End Sub




    '  _______           _     _____  _                                     _ 
    ' |__   __|         | |   / ____|| |                                   | |
    '    | |  ___ __  __| |_ | |     | |__    __ _  _ __    __ _   ___   __| |
    '    | | / _ \\ \/ /| __|| |     | '_ \  / _` || '_ \  / _` | / _ \ / _` |
    '    | ||  __/ >  < | |_ | |____ | | | || (_| || | | || (_| ||  __/| (_| |
    '    |_| \___|/_/\_\ \__| \_____||_| |_| \__,_||_| |_| \__, | \___| \__,_|
    '                                                       __/ |             
    '                                                      |___/              


    ' The below is probably not required since the user cannot enter non-numeric characters now

    Private Sub LP_waitTimeVal_TB_TextChanged(sender As Object, e As EventArgs) Handles LP_waitTimeVal_TB.TextChanged
        If (Val(LP_waitTimeVal_TB.Text) < 1) Then
            LP_waitTimeVal_TB.ForeColor = Color.Red
        Else
            LP_waitTimeVal_TB.ForeColor = Color.Black
        End If

    End Sub




    Private Sub mirrorLockupTime_TB_TextChanged(sender As Object, e As EventArgs) Handles mirrorLockupTime_TB.TextChanged
        If (Val(mirrorLockupTime_TB.Text) > 0) Then
            mirrorLockupTime_TB.ForeColor = Color.Black
        Else
            mirrorLockupTime_TB.ForeColor = Color.Red
        End If
    End Sub


    Private Sub flashPulseTime_TB_TextChanged(sender As Object, e As EventArgs) Handles FT1_Pulse_TB.TextChanged
        If (Val(FT1_Pulse_TB.Text) < 10) Then
            FT1_Pulse_TB.ForeColor = Color.Red
        Else
            FT1_Pulse_TB.ForeColor = Color.Black
        End If
    End Sub


    Private Sub FT2_Pulse_TB_TextChanged(sender As Object, e As EventArgs) Handles FT2_Pulse_TB.TextChanged
        If (Val(FT2_Pulse_TB.Text) < 10) Then
            FT2_Pulse_TB.ForeColor = Color.Red
        Else
            FT2_Pulse_TB.ForeColor = Color.Black
        End If
    End Sub
    Private Sub FT3_Pulse_TB_TextChanged(sender As Object, e As EventArgs) Handles FT3_Pulse_TB.TextChanged
        If (Val(FT3_Pulse_TB.Text) < 10) Then
            FT3_Pulse_TB.ForeColor = Color.Red
        Else
            FT3_Pulse_TB.ForeColor = Color.Black
        End If
    End Sub


    Private Sub CAM_Pulse_TB_TextChanged(sender As Object, e As EventArgs) Handles CT_Pulse_TB.TextChanged
        If (Val(CT_Pulse_TB.Text) < 10) Then
            CT_Pulse_TB.ForeColor = Color.Red
        Else
            CT_Pulse_TB.ForeColor = Color.Black
        End If
    End Sub





#End Region ' Region "ValidateUserInput"






    Private Sub formatValues()

        debug("Enter formatValues()")
        '  Dim StartTimes As TextBox() = New TextBox() {}
        '  StartTimes = {D1StartTime_TB, D1StartTime_TB, D2StartTime_TB, D3StartTime_TB, D4StartTime_TB, D5StartTime_TB, D6StartTime_TB, D7StartTime_TB, D8StartTime_TB, D9StartTime_TB}

        Dim mStartTimes As TextBox() = New TextBox() {D1StartTime_TB, D1StartTime_TB, D2StartTime_TB, D3StartTime_TB, D4StartTime_TB, D5StartTime_TB, D6StartTime_TB, D7StartTime_TB, D8StartTime_TB, D9StartTime_TB}
        Dim mStartIncDecVals As TextBox() = New TextBox() {D1StartIncVal_TB, D1StartIncVal_TB, D2StartIncVal_TB, D3StartIncVal_TB, D4StartIncVal_TB, D5StartIncVal_TB, D6StartIncVal_TB, D7StartIncVal_TB, D8StartIncVal_TB, D9StartIncVal_TB}
        Dim mSizes As TextBox() = New TextBox() {D1Size_TB, D1Size_TB, D2Size_TB, D3Size_TB, D4Size_TB, D5Size_TB, D6Size_TB, D7Size_TB, D8Size_TB, D9Size_TB}
        Dim mSizeIncDecVals As TextBox() = New TextBox() {D1SizeIncVal_TB, D1SizeIncVal_TB, D2SizeIncVal_TB, D3SizeIncVal_TB, D4SizeIncVal_TB, D5SizeIncVal_TB, D6SizeIncVal_TB, D7SizeIncVal_TB, D8SizeIncVal_TB, D9SizeIncVal_TB}


        Dim tmpVar As Long = 0

        For i As Integer = 1 To numDrops
            mStartTimes(i).Text = Format(Val(mStartTimes(i).Text), "0000")
            mStartIncDecVals(i).Text = Format(Val(mStartIncDecVals(i).Text), "000")
            mSizes(i).Text = Format(Val(mSizes(i).Text), "0000")
            mSizeIncDecVals(i).Text = Format(Val(mSizeIncDecVals(i).Text), "000")
        Next

        tmpVar = Val(LP_waitTimeVal_TB.Text)
        LP_waitTimeVal_TB.Text = Format(tmpVar, "00")

        tmpVar = Val(FT1_Time_TB.Text)
        FT1_Time_TB.Text = Format(tmpVar, "0000")
        tmpVar = Val(FT1_IncDecTime_TB.Text)
        FT1_IncDecTime_TB.Text = Format(tmpVar, "000")

        tmpVar = Val(FT2_Time_TB.Text)
        FT2_Time_TB.Text = Format(tmpVar, "0000")
        tmpVar = Val(FT2_IncDecTime_TB.Text)
        FT2_IncDecTime_TB.Text = Format(tmpVar, "000")

        tmpVar = Val(FT3_Time_TB.Text)
        FT3_Time_TB.Text = Format(tmpVar, "0000")
        tmpVar = Val(FT3_IncDecTime_TB.Text)
        FT3_IncDecTime_TB.Text = Format(tmpVar, "000")

        tmpVar = Val(CT_StartTime_TB.Text)
        CT_StartTime_TB.Text = Format(tmpVar, "0000")
        tmpVar = Val(CT_IncDecTime_TB.Text)
        CT_IncDecTime_TB.Text = Format(tmpVar, "000")

        BulbStartOffset_Time_TB.Text = Format(Val(BulbStartOffset_Time_TB.Text), "0000")
        BulbStopOffset_Time_TB.Text = Format(Val(BulbStopOffset_Time_TB.Text), "0000")

    End Sub










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



    Private Sub startBTNoff()
        debug("MainStart_BTN OFF")
        MainStart_BTN.Enabled = False
        MainStart_BTN.BackColor = Color.FromArgb(200, 220, 200)
    End Sub

    Private Sub startBTNon()
        debug("MainStart_BTN ON")
        MainStart_BTN.Enabled = True
        MainStart_BTN.BackColor = Color.FromArgb(128, 255, 128)
    End Sub





    Private Sub MainStart_BTN_Click_1(sender As Object, e As EventArgs) Handles MainStart_BTN.Click

        debug(vbCrLf & "MainStart_BTN clicked")

        formatValues()
        saveDropData()

        Dim goodToGo As Boolean = True
        Dim errMSG As String = ""


        errMSG = checkDropTimes()

        If (errMSG <> "") Then
            errMSG = "Problem with one or more times. You must correct the problem(s) before starting the drop sequence." & vbCrLf & errMSG & vbCrLf
            goodToGo = False
        End If



        If (Not dropTimesOverlap()) Then
            errMSG = errMSG & vbCrLf & "Some of the drop times overlap. Please correct." & vbCrLf
            goodToGo = False



        Else
            debug("  drop times are OK")
            receivedData = receivedData & GetSerialInData()
            receivedData = ""
        End If


        ' this should never be false. The START button is only active when connected.
        'If (Not connected) Then
        '    errMSG = errMSG & vbCrLf & vbCrLf & "Not connected to the dopController" & vbCrLf
        '    goodToGo = False
        'End If



        If (Not goodToGo) Then
            MsgBox(errMSG, , "ERROR!")
        End If

        If (goodToGo) Then
            debug("  goodToGo - makeDrop()")
            makeDrop()
        End If



    End Sub








    '       _                  _             _                         _    _                       
    '      | |                | |           | |                       | |  (_)                      
    '  ___ | |__    ___   ___ | | __      __| | _ __  ___   _ __      | |_  _  _ __ ___    ___  ___ 
    ' / __|| '_ \  / _ \ / __|| |/ /     / _` || '__|/ _ \ | '_ \     | __|| || '_ ` _ \  / _ \/ __|
    '| (__ | | | ||  __/| (__ |   <     | (_| || |  | (_) || |_) |    | |_ | || | | | | ||  __/\__ \
    ' \___||_| |_| \___| \___||_|\_\     \__,_||_|   \___/ | .__/      \__||_||_| |_| |_| \___||___/
    '                                                      | |                                      
    '                                                      |_|                                      
    '
#Region "check drop times"


    Function checkDropTimes() As String

        debug("Enter checkDropTimes()")

        ' check values.
        ' sol must be 1 to 6
        ' start must be 0-9999
        ' start inc/dec must be 0-999
        ' size must be 0-9999
        ' size inc/dec must be 0-999

        ' FT1 must be 0-9999
        ' FT2 must be 0-9999
        ' FT3 must be 0-9999
        ' shutter trigger must be 0-9999

        Dim err As Boolean = False
        Dim message As String = ""

        For i = 1 To numDrops

            ' Start time
            If (Val(StartTimes(i).Text) < 0 Or Val(StartTimes(i).Text) > 9999) Then
                StartTimes(i).ForeColor = Color.Red
                err = True
                message = message & "start time(s) out of range" & vbCrLf
                debug("  error in start time")
            Else
                StartTimes(i).ForeColor = Color.Black
            End If

            ' Start time inc/dec value
            If (Val(StartIncDecVals(i).Text) < 0 Or Val(StartIncDecVals(i).Text) > 999) Then
                StartIncDecVals(i).ForeColor = Color.Red
                err = True
                message = message & "Start time inc/dec value(s) out of range" & vbCrLf
                debug("  error in start time inc/dev value")
            Else
                StartIncDecVals(i).ForeColor = Color.Black
            End If

            ' Size time
            If (Val(Sizes(i).Text) < 0 Or Val(Sizes(i).Text) > 9999) Then
                Sizes(i).ForeColor = Color.Red
                err = True
                message = message & "Size value(s)  out of range" & vbCrLf
                debug("  error in size value")
            Else
                Sizes(i).ForeColor = Color.Black
            End If

            ' Size time inc/dec val
            If (Val(SizeIncDecVals(i).Text) < 0 Or Val(SizeIncDecVals(i).Text) > 999) Then
                SizeIncDecVals(i).ForeColor = Color.Red
                err = True
                message = message & "Size inc/dec value(s) out of range" & vbCrLf
                debug("  error in size inc/dev value")
            Else
                Sizes(i).ForeColor = Color.Black
            End If

        Next i


        'FT1 time
        If (Val(FT1_Time_TB.Text) < 0 Or Val(FT1_Time_TB.Text) > 9999) Then
            FT1_Time_TB.ForeColor = Color.Red
            err = True
            message = message & "FT1 value out of range" & vbCrLf
            debug("  error in FT1 time")
        Else
            FT1_Time_TB.ForeColor = Color.Black
        End If

        'FT1 time inc val
        If (Val(FT1_IncDecTime_TB.Text) < 0 Or Val(FT1_IncDecTime_TB.Text) > 999) Then
            FT1_IncDecTime_TB.ForeColor = Color.Red
            err = True
            message = message & "Flash trigger inc/dec value out of range" & vbCrLf
            debug("  error in flash trigger inc/dec time")
        Else
            FT1_IncDecTime_TB.ForeColor = Color.Black
        End If



        'FT2 time
        If (Val(FT2_Time_TB.Text) < 0 Or Val(FT2_Time_TB.Text) > 9999) Then
            FT2_Time_TB.ForeColor = Color.Red
            err = True
            message = message & "FT2 value out of range" & vbCrLf
            debug("  error in flash trigger time")
        Else
            FT2_Time_TB.ForeColor = Color.Black
        End If

        'FT2 time inc val
        If (Val(FT2_IncDecTime_TB.Text) < 0 Or Val(FT2_IncDecTime_TB.Text) > 999) Then
            FT2_IncDecTime_TB.ForeColor = Color.Red
            err = True
            message = message & "FT2 inc/dec value out of range" & vbCrLf
            debug("  error in FT2 inc/dec time")
        Else
            FT2_IncDecTime_TB.ForeColor = Color.Black
        End If


        'FT3 time
        If (Val(FT3_Time_TB.Text) < 0 Or Val(FT3_Time_TB.Text) > 9999) Then
            FT3_Time_TB.ForeColor = Color.Red
            err = True
            message = message & "FT3 value out of range" & vbCrLf
            debug("  error in flash trigger time")
        Else
            FT3_Time_TB.ForeColor = Color.Black
        End If

        'FT3 time inc val
        If (Val(FT3_IncDecTime_TB.Text) < 0 Or Val(FT3_IncDecTime_TB.Text) > 999) Then
            FT3_IncDecTime_TB.ForeColor = Color.Red
            err = True
            message = message & "FT3 inc/dec value out of range" & vbCrLf
            debug("  error in FT3 inc/dec time")
        Else
            FT3_IncDecTime_TB.ForeColor = Color.Black
        End If





        'Shutter trigger time
        If (Val(CT_StartTime_TB.Text) < 0 Or Val(CT_StartTime_TB.Text) > 9999) Then
            CT_StartTime_TB.ForeColor = Color.Red
            err = True
            message = message & "Camera trigger value out of range" & vbCrLf
            debug("  error in camera trigger time")
        Else
            CT_StartTime_TB.ForeColor = Color.Black
        End If

        'Shuuter trigger time inc time
        If (Val(CT_IncDecTime_TB.Text) < 0 Or Val(CT_IncDecTime_TB.Text) > 999) Then
            CT_IncDecTime_TB.ForeColor = Color.Red
            err = True
            message = message & "Camera trigger inc/dec value out of range" & vbCrLf
            debug("  error in camera trigger inc/dec time")
        Else
            CT_IncDecTime_TB.ForeColor = Color.Black
        End If


        'Loop timer time
        If (Val(LP_waitTimeVal_TB.Text) < 0 Or Val(LP_waitTimeVal_TB.Text) > 99) Then
            LP_waitTimeVal_TB.ForeColor = Color.Red
            err = True
            message = message & "Loop delay value out of range" & vbCrLf
            debug("  error in loop delay value")
        Else
            LP_waitTimeVal_TB.ForeColor = Color.Black
        End If


        debug("  checked values error = " & err)
        Return message

    End Function



    Private Function dropTimesOverlap() As Boolean

        UpdateDropDataArrays(1)

        Dim Sol_CB As ComboBox() = New ComboBox() {D1Sol_CB, D1Sol_CB, D2Sol_CB, D3Sol_CB, D4Sol_CB, D5Sol_CB, D6Sol_CB, D7Sol_CB, D8Sol_CB, D9Sol_CB}
        Dim StartTime As TextBox() = New TextBox() {D1StartTime_TB, D1StartTime_TB, D2StartTime_TB, D3StartTime_TB, D4StartTime_TB, D5StartTime_TB, D6StartTime_TB, D7StartTime_TB, D8StartTime_TB, D9StartTime_TB}
        Dim Size As TextBox() = New TextBox() {D1Size_TB, D1Size_TB, D2Size_TB, D3Size_TB, D4Size_TB, D5Size_TB, D6Size_TB, D7Size_TB, D8Size_TB, D9Size_TB}

        Dim dropError As Boolean = False
        Dim stopTimeJ As Long = 0
        Dim stopTimeI As Long = 0

        Dim i As Integer = 0
        Dim j As Integer = 0

        For i = 1 To 9
            StartTime(j).ForeColor = Color.Black
            StartTime(i).ForeColor = Color.Black
        Next i

        If (numDrops > 1) Then

            For j = 1 To numDrops - 1
                For i = 1 To numDrops

                    If (drop_onOff_BTNS(i).Text = "ON" And drop_onOff_BTNS(j).Text = "ON") Then

                        If (i <> j) Then
                            ' only need to check if the the drops are from the same valve
                            If (Val(Sol_CB(j).Text) = Val(Sol_CB(i).Text)) Then

                                stopTimeJ = Val(StartTime(j).Text) + Val(Size(j).Text)
                                stopTimeI = Val(StartTime(i).Text) + Val(Size(i).Text)

                                If (Val(StartTime(j).Text) >= Val(StartTime(i).Text) And (Val(StartTime(j).Text) <= stopTimeI)) Then
                                    dropError = True
                                    StartTime(j).ForeColor = Color.Red
                                    StartTime(i).ForeColor = Color.Red
                                End If

                                If (stopTimeJ >= Val(StartTime(i).Text) And (stopTimeJ <= stopTimeI)) Then
                                    dropError = True
                                    StartTime(j).ForeColor = Color.Red
                                    StartTime(i).ForeColor = Color.Red
                                End If
                            End If
                        End If
                    End If
                Next i
            Next j
        End If

        Return Not dropError
    End Function

#End Region








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

#Region "SIDE PANEL"



    ' _   _                    _                            __        _                         
    '| \ | |                  | |                          / _|      | |                        
    '|  \| | _   _  _ __ ___  | |__    ___  _ __     ___  | |_     __| | _ __  ___   _ __   ___ 
    '| . ` || | | || '_ ` _ \ | '_ \  / _ \| '__|   / _ \ |  _|   / _` || '__|/ _ \ | '_ \ / __|
    '| |\  || |_| || | | | | || |_) ||  __/| |     | (_) || |    | (_| || |  | (_) || |_) |\__ \
    '\_| \_/ \__,_||_| |_| |_||_.__/  \___||_|      \___/ |_|     \__,_||_|   \___/ | .__/ |___/
    '                                                                               | |         
    '                                                                               |_|         
    ' This is not used in this version
    ' All drops are shown with on/off button
    ' Number of drops is set to 9 and the control is hidden


    Private Sub NumDrops_CB_SelectedIndexChanged(sender As Object, e As EventArgs) Handles NumDrops_CB.SelectedIndexChanged
        debug("Num Drops changed to " & NumDrops_CB.Text)
        UpdateRows()
    End Sub

    Private Sub CT_BUTTON_Click(sender As Object, e As EventArgs) Handles CT_BUTTON.Click
        If (CT_BUTTON.Text = "OFF") Then
            CT_BUTTON.Text = "ON"
        ElseIf (CT_BUTTON.Text = "ON") Then
            CT_BUTTON.Text = "SYNC"
        ElseIf (CT_BUTTON.Text = "SYNC") Then
            CT_BUTTON.Text = "BULB"
        ElseIf (CT_BUTTON.Text = "BULB") Then
            CT_BUTTON.Text = "OFF"
        End If
        updateSidePanel()
    End Sub


    Private Sub CT_IncDec_BTN_Click(sender As Object, e As EventArgs) Handles CT_IncDec_BTN.Click
        updateIncDec_BTN(sender)
        updateSidePanel()
    End Sub



    Private Sub FT1_BUTTON_Click(sender As Object, e As EventArgs) Handles FT1_OnOff_BUTTON.Click
        If (FT1_OnOff_BUTTON.Text = "OFF") Then
            FT1_OnOff_BUTTON.Text = "ON"
        Else
            FT1_OnOff_BUTTON.Text = "OFF"
        End If
        updateSidePanel()
    End Sub

    Private Sub FT1_IncDec_BTN_Click(sender As Object, e As EventArgs) Handles FT1_IncDec_BTN.Click
        updateIncDec_BTN(sender)
        updateSidePanel()
    End Sub


    Private Sub FT2_BUTTON_Click(sender As Object, e As EventArgs) Handles FT2_OnOff_BUTTON.Click
        If (FT2_OnOff_BUTTON.Text = "OFF") Then
            FT2_OnOff_BUTTON.Text = "ON"
        Else
            FT2_OnOff_BUTTON.Text = "OFF"
        End If
        updateSidePanel()
    End Sub

    Private Sub FT2_IncDec_BTN_Click(sender As Object, e As EventArgs) Handles FT2_IncDec_BTN.Click
        updateIncDec_BTN(sender)
        updateSidePanel()
    End Sub



    Private Sub FT3_BUTTON_Click(sender As Object, e As EventArgs) Handles FT3_OnOff_BUTTON.Click
        If (FT3_OnOff_BUTTON.Text = "OFF") Then
            FT3_OnOff_BUTTON.Text = "ON"
        Else
            FT3_OnOff_BUTTON.Text = "OFF"
        End If
        updateSidePanel()
    End Sub


    Private Sub FT3_IncDec_BTN_Click(sender As Object, e As EventArgs) Handles FT3_IncDec_BTN.Click
        updateIncDec_BTN(sender)
        updateSidePanel()
    End Sub




    Private Sub updateSidePanel()
        debug("Enter updateSidePanel()")

        ' ALL OFF
        CT_StartTime_TB.Visible = False
        CT_IncDec_BTN.Visible = False
        CT_IncDecTime_TB.Visible = False
        BulbStart_LBL.Visible = False
        BulbStartOffset_Time_TB.Visible = False
        BulbStop_LBL.Visible = False
        BulbStopOffset_Time_TB.Visible = False

        If (CT_BUTTON.Text = "ON") Then
            CT_StartTime_TB.Visible = True
            CT_IncDec_BTN.Visible = True
            CT_IncDecTime_TB.Visible = True

            If (CT_IncDec_BTN.Text) = "OFF" Then
                CT_IncDecTime_TB.Enabled = False
            Else
                CT_IncDecTime_TB.Enabled = True
            End If



        ElseIf (CT_BUTTON.Text = "SYNC") Then

            BulbStart_LBL.Location = New Point(602, 102)
            BulbStartOffset_Time_TB.Location = New Point(728, 96)
            'BulbStop_LBL.Location = New Point(602, 128)
            'BulbStopOffset_Time_TB.Location = New Point(728, 122)

            BulbStart_LBL.Visible = True
            BulbStartOffset_Time_TB.Visible = True
            'BulbStop_LBL.Visible = True
            'BulbStopOffset_Time_TB.Visible = True

        ElseIf (CT_BUTTON.Text = "BULB") Then

            'BulbStart_LBL.Location = New Point(602, 96)
            'BulbStartOffset_Time_TB.Location = New Point(728, 90)
            BulbStop_LBL.Location = New Point(602, 102)
            BulbStopOffset_Time_TB.Location = New Point(728, 96)

            'BulbStart_LBL.Visible = True
            'BulbStartOffset_Time_TB.Visible = True
            BulbStop_LBL.Visible = True
            BulbStopOffset_Time_TB.Visible = True

        End If


        If (FT3_OnOff_BUTTON.Text = "ON") Then
            FT3_Time_TB.Enabled = True
            FT3_IncDec_BTN.Enabled = True
            FT3_IncDecTime_TB.Enabled = True
            FT3_IncDec_BTN.BackColor = Color.LightSkyBlue
            If (FT3_IncDec_BTN.Text) = "OFF" Then
                FT3_IncDecTime_TB.Enabled = False
            Else
                FT3_IncDecTime_TB.Enabled = True
            End If

        Else
            FT3_Time_TB.Enabled = False
            FT3_IncDec_BTN.Enabled = False
            FT3_IncDecTime_TB.Enabled = False
            FT3_IncDec_BTN.BackColor = greyedOut
        End If


        If (FT2_OnOff_BUTTON.Text = "ON") Then
            FT2_Time_TB.Enabled = True
            FT2_IncDec_BTN.Enabled = True
            FT2_IncDecTime_TB.Enabled = True
            FT2_IncDec_BTN.BackColor = Color.LightSkyBlue

            If (FT2_IncDec_BTN.Text) = "OFF" Then
                FT2_IncDecTime_TB.Enabled = False
            Else
                FT2_IncDecTime_TB.Enabled = True
            End If
        Else
            FT2_Time_TB.Enabled = False
            FT2_IncDec_BTN.Enabled = False
            FT2_IncDecTime_TB.Enabled = False
            FT2_IncDec_BTN.BackColor = greyedOut
        End If

        If (FT1_OnOff_BUTTON.Text = "ON") Then
            FT1_Time_TB.Enabled = True
            FT1_IncDec_BTN.Enabled = True
            FT1_IncDecTime_TB.Enabled = True
            FT1_IncDec_BTN.BackColor = Color.LightSkyBlue

            If (FT1_IncDec_BTN.Text) = "OFF" Then
                FT1_IncDecTime_TB.Enabled = False
            Else
                FT1_IncDecTime_TB.Enabled = True
            End If
        Else
            FT1_Time_TB.Enabled = False
            FT1_IncDec_BTN.Enabled = False
            FT1_IncDecTime_TB.Enabled = False
            FT1_IncDec_BTN.BackColor = greyedOut
        End If

    End Sub





#End Region 'Region "SIDE PANEL"











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


#Region "SETTINGS TAB"


    Dim oldTab As Integer = 0
    Dim currentTab As Integer = 0


    Private Sub TabControl1_Selecting(sender As Object, e As TabControlCancelEventArgs) Handles GraphTabControl.Selecting


        Dim errMsg As String = ""


        If (e.TabPageIndex <> 1) Then

            ' NOT=1 means leaving the SETTINGS TAB
            If (oldTab = 1) Then
                If (Val(LP_waitTimeVal_TB.Text) < 1) Then
                    errMsg = "Loop delay time cannot be less than 1 second" & vbCrLf
                End If

                If (Val(FT1_Pulse_TB.Text) < 10) Then
                    errMsg = errMsg + "Flash trigger 1 pulse time cannot less than 10ms" & vbCrLf
                End If

                If (Val(FT2_Pulse_TB.Text) < 10) Then
                    errMsg = errMsg + "Flash trigger 2 pulse time cannot less than 10ms" & vbCrLf
                End If

                If (Val(FT3_Pulse_TB.Text) < 10) Then
                    errMsg = errMsg + "Flash trigger 3 pulse time cannot less than 10ms" & vbCrLf
                End If

                If (Val(CT_Pulse_TB.Text) < 10) Then
                    errMsg = errMsg + "Camera trigger pulse time cannot less than 10ms" & vbCrLf
                End If


            End If

        Else
            oldTab = e.TabPageIndex
        End If


        If (errMsg <> "") Then
            e.Cancel = True
            MsgBox(errMsg & vbCrLf)

        End If



    End Sub


    Private Sub SETTINGS_Enter(sender As Object, e As EventArgs) Handles TAB_SETTINGS.Enter
        debug(vbCrLf & "Enter Settings TAB")
        updateSettingsElements()
    End Sub


    Private Sub SETTINGS_Leave(sender As Object, e As EventArgs) Handles TAB_SETTINGS.Leave
        'check data
        formatSettings()
        saveSettings()
        closeValves()
        debug("  Exit Settings")
    End Sub


    Private Sub updateSettingsElements()
        formatSettings()
        updateML_Elements()
        'updateValveDrainButtons()
    End Sub




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

    Private Sub saveSettings()

        debug(vbCrLf & "Enter saveSettings()")
        formatSettings()


        Dim filename As String = "settings.txt"
        If (System.IO.File.Exists(filename) = False) Then
            System.IO.File.Create(filename).Dispose()
        End If
        Dim objWriter As New System.IO.StreamWriter(filename, False)

        Dim objCurrentDate As Date = DateTime.Today
        Dim currentDate As String = Format(objCurrentDate, "dd/MM/yyyy")
        Dim objCurrentTime As Date = TimeOfDay
        Format(DateTime.Today, "dd/MM/yyyy")

        objWriter.WriteLine("dropController: Settings File")
        objWriter.WriteLine("Saved: " & currentDate & " " & objCurrentTime)

        objWriter.WriteLine("Version=" + Version_ComboBox.Text)

        objWriter.WriteLine("Loop=" + LoopMode_BTN.Text)
        objWriter.WriteLine("ButOrTimer=" & lp_TimerOrButton_BTN.Text)
        objWriter.WriteLine("WaitTime=" & LP_waitTimeVal_TB.Text)

        objWriter.WriteLine("MirrLockup=" + mirrorLockupOnOff_BTN.Text)
        objWriter.WriteLine("MirrLockTime=" + mirrorLockupTime_TB.Text)
        objWriter.WriteLine("CT_Pulse=" + CT_Pulse_TB.Text)
        objWriter.WriteLine("FT1_Pulse=" + FT1_Pulse_TB.Text)
        objWriter.WriteLine("FT2_Pulse=" + FT2_Pulse_TB.Text)
        objWriter.WriteLine("FT3_Pulse=" + FT3_Pulse_TB.Text)

        '      objWriter.WriteLine("BulbMode=" + SET_bulbMode_Btn.Text)
        objWriter.WriteLine("BulbPre=" + BulbStartOffset_Time_TB.Text)
        objWriter.WriteLine("BulbPost=" + BulbStopOffset_Time_TB.Text)


        objWriter.WriteLine("Sound=" + SET_SOUND_BTN.Text)
        objWriter.WriteLine("Leo=" + SET_LEO_BUT.Text)
        'objWriter.WriteLine("Debug=" + SET_DEBUG_BTN.Text)

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

        debug("  settings saved")
    End Sub





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

        debug("Enter loadSettings()")


        Dim filename As String = "settings.txt"

        If Not System.IO.File.Exists(filename) Then
            ' file does not exist create new file
            resetSettings()
            saveSettings()
            debug("  settings file does not exist - new file created")
        End If


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

        Dim found As Boolean = False


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

        ' file header
        tmp = fileReader.ReadLine()

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

            'if tmp contains "=" then parse
            foundPos = InStr(1, tmp, "=", CompareMethod.Text)
            If (foundPos > 0) Then

                Dim tmpSplit() As String = Split(tmp, "=", -1, CompareMethod.Text)

                debug("    CMD=" & tmpSplit(0) & "  VAL=" & tmpSplit(1))



                If (tmpSplit(0) = "Version") Then
                    If (Val(tmpSplit(1)) = 2 Or Val(tmpSplit(1)) = 3) Then
                        Version_ComboBox.Text = tmpSplit(1)
                    Else
                        Version_ComboBox.Text = "2"
                    End If
                    found = True
                End If


                If (tmpSplit(0) = "Loop") Then
                    If (tmpSplit(1) = "ON" Or tmpSplit(1) = "OFF") Then
                        LoopMode_BTN.Text = tmpSplit(1)
                    Else
                        LoopMode_BTN.Text = "OFF"
                    End If
                    found = True
                End If
                If (tmpSplit(0) = "ButOrTimer") Then
                    lp_TimerOrButton_BTN.Text = tmpSplit(1)
                    found = True
                End If

                If (tmpSplit(0) = "WaitTime") Then
                    If (Val(tmpSplit(1)) < 0 Or Val(tmpSplit(1)) > 99) Then
                        tmpSplit(1) = "10"
                    End If
                    LP_waitTimeVal_TB.Text = tmpSplit(1)
                    found = True
                End If


                If (tmpSplit(0) = "MirrLockup") Then
                    If (tmpSplit(1) = "ON" Or tmpSplit(1) = "OFF") Then
                        mirrorLockupOnOff_BTN.Text = tmpSplit(1)
                    Else
                        mirrorLockupOnOff_BTN.Text = "OFF"
                    End If
                    found = True
                End If

                If (tmpSplit(0) = "MirrLockTime") Then
                    If (Val(tmpSplit(1)) < 0 Or Val(tmpSplit(1)) > 9999) Then
                        tmpSplit(1) = "1000"
                    End If
                    mirrorLockupTime_TB.Text = tmpSplit(1)
                    found = True
                End If
                If (tmpSplit(0) = "FT1_Pulse") Then
                    If (Val(tmpSplit(1)) < 0 Or Val(tmpSplit(1)) > 999) Then
                        tmpSplit(1) = "050"
                    End If
                    FT1_Pulse_TB.Text = tmpSplit(1)
                    found = True
                End If
                If (tmpSplit(0) = "FT2_Pulse") Then
                    If (Val(tmpSplit(1)) < 0 Or Val(tmpSplit(1)) > 999) Then
                        tmpSplit(1) = "050"
                    End If
                    FT2_Pulse_TB.Text = tmpSplit(1)
                    found = True
                End If

                If (tmpSplit(0) = "FT3_Pulse") Then
                    If (Val(tmpSplit(1)) < 0 Or Val(tmpSplit(1)) > 999) Then
                        tmpSplit(1) = "050"
                    End If
                    FT3_Pulse_TB.Text = tmpSplit(1)
                    found = True
                End If



                If (tmpSplit(0) = "CT_Pulse") Then
                    If (Val(tmpSplit(1)) < 0 Or Val(tmpSplit(1)) > 999) Then
                        tmpSplit(1) = "050"
                    End If
                    CT_Pulse_TB.Text = tmpSplit(1)
                    found = True
                End If




                If (tmpSplit(0) = "BulbPre") Then
                    If (Val(tmpSplit(1)) < 0 Or Val(tmpSplit(1)) > 9999) Then
                        BulbStartOffset_Time_TB.Text = "0100"
                    Else
                        BulbStartOffset_Time_TB.Text = tmpSplit(1)
                    End If
                    found = True
                End If

                If (tmpSplit(0) = "BulbPost") Then
                    If (Val(tmpSplit(1)) < 0 Or Val(tmpSplit(1)) > 9999) Then
                        BulbStopOffset_Time_TB.Text = "0100"
                    Else
                        BulbStopOffset_Time_TB.Text = tmpSplit(1)
                    End If
                    found = True
                End If



                If (tmpSplit(0) = "Sound") Then
                    If (tmpSplit(1) = "ON" Or tmpSplit(1) = "OFF") Then
                        SET_SOUND_BTN.Text = tmpSplit(1)
                    Else
                        SET_SOUND_BTN.Text = "OFF"
                    End If
                    found = True
                End If



                If (tmpSplit(0) = "Leo") Then
                    If (tmpSplit(1) = "YES" Or tmpSplit(1) = "NO") Then
                        SET_LEO_BUT.Text = tmpSplit(1)
                    Else
                        SET_LEO_BUT.Text = "NO"
                    End If
                    found = True
                End If


                If (tmpSplit(0) = "Debug" Or tmpSplit(0) = "DEBUG") Then
                    If (tmpSplit(1) = "ON" Or tmpSplit(1) = "OFF") Then
                        SET_DEBUG_BTN.Text = tmpSplit(1)
                    Else
                        SET_DEBUG_BTN.Text = "OFF"
                    End If
                    found = True

                    If (tmpSplit(1) = "ON") Then
                        turnDebugOn()
                        DEBUG_MASTER = True
                    End If
                End If




                If (Not found) Then
                    debug(tmp & " is not found")
                End If

            End If

        End While
        fileReader.Close()

        debug("  settings loaded")
        formatSettings()




    End Sub


    Private Sub formatSettings()
        debug("Enter formatSettings()")

        LP_waitTimeVal_TB.Text = Format(Val(LP_waitTimeVal_TB.Text), "00")

        mirrorLockupTime_TB.Text = Format(Val(mirrorLockupTime_TB.Text), "0000")
        FT1_Pulse_TB.Text = Format(Val(FT1_Pulse_TB.Text), "000")
        FT2_Pulse_TB.Text = Format(Val(FT2_Pulse_TB.Text), "000")
        FT3_Pulse_TB.Text = Format(Val(FT3_Pulse_TB.Text), "000")
        CT_Pulse_TB.Text = Format(Val(CT_Pulse_TB.Text), "000")

        '      BulbStartOffset_Time_TB.Text = Format(Val(BulbStartOffset_Time_TB.Text), "0000")
        '      BulbStopOffset_Time_TB.Text = Format(Val(BulbStopOffset_Time_TB.Text), "0000")

        If (Version_ComboBox.Text = "2") Then

            ' drop data panel - hide FT
            Label16.Visible = False
            FT2_OnOff_BUTTON.Visible = False
            FT2_Time_TB.Visible = False
            FT2_IncDec_BTN.Visible = False
            FT2_IncDecTime_TB.Visible = False

            Label31.Visible = False
            FT3_OnOff_BUTTON.Visible = False
            FT3_Time_TB.Visible = False
            FT3_IncDec_BTN.Visible = False
            FT3_IncDecTime_TB.Visible = False


            ' loop page = hide FT
            LP_FT2_LBL.Visible = False
            Loop_FT2_LBL.Visible = False
            LP_FT3_LBL.Visible = False
            Loop_FT3_LBL.Visible = False


            ' settings panel - hide FT
            FT2_Pulse_lbl.Visible = False
            FT2_Pulse_TB.Visible = False
            FT3_Pulse_lbl.Visible = False
            FT3_Pulse_TB.Visible = False


            ' graph panel handled in the graph tab function



        ElseIf (Version_ComboBox.Text = "3") Then

            ' drop data panel - show FT
            Label16.Visible = True
            FT2_OnOff_BUTTON.Visible = True
            FT2_Time_TB.Visible = True
            FT2_IncDec_BTN.Visible = True
            FT2_IncDecTime_TB.Visible = True

            Label31.Visible = True
            FT3_OnOff_BUTTON.Visible = True
            FT3_Time_TB.Visible = True
            FT3_IncDec_BTN.Visible = True
            FT3_IncDecTime_TB.Visible = True


            ' loop page = show FT2
            LP_FT2_LBL.Visible = True
            Loop_FT2_LBL.Visible = True
            LP_FT3_LBL.Visible = True
            Loop_FT3_LBL.Visible = True


            ' settings panel - show FT
            FT2_Pulse_lbl.Visible = True
            FT2_Pulse_TB.Visible = True
            FT3_Pulse_lbl.Visible = True
            FT3_Pulse_TB.Visible = True





            ' graph panel handled in the graph tab function


        End If

        updateSidePanel()
        updateLoopPage()


    End Sub





    Private Sub DeviceVersion_ComboBox_SelectedIndexChanged(sender As Object, e As EventArgs) Handles Version_ComboBox.SelectedIndexChanged

        If (Version_ComboBox.Text = "2") Then
            FT2_OnOff_BUTTON.Text = "OFF"
            FT3_OnOff_BUTTON.Text = "OFF"
        End If

        formatSettings()
    End Sub









    '                        _   
    '                       | |  
    '  _ __  ___  ___   ___ | |_ 
    ' | '__|/ _ \/ __| / _ \| __|
    ' | |  |  __/\__ \|  __/| |_ 
    ' |_|   \___||___/ \___| \__|
    '


    Private Sub ResetAll_BTN_Click(sender As Object, e As EventArgs) Handles ResetAll_BTN.Click

        Dim reply = MsgBox("Are you sure you want to reset all values?", 4, "Reset All Values")

        If (reply = vbYes) Then
            debug(vbCrLf & "Enter ResetAll()")
            resetSettings()
            resetDropData()

            loadSettings()
            loadDropData()

            updateLoopElements()
            UpdateRows()

            MsgBox("Reset complete", , "Reset All Values")

        End If

    End Sub



    Private Sub resetSettings()
        Dim filename As String = "settings.txt"
        If (System.IO.File.Exists(filename) = False) Then
            System.IO.File.Create(filename).Dispose()
        End If
        Dim objWriter As New System.IO.StreamWriter(filename, False)

        Dim objCurrentDate As Date = DateTime.Today
        Dim currentDate As String = Format(objCurrentDate, "dd/MM/yyyy")
        Dim objCurrentTime As Date = TimeOfDay
        Format(DateTime.Today, "dd/MM/yyyy")

        objWriter.WriteLine("dropController: Settings File")
        objWriter.WriteLine("Saved: " & currentDate & " " & objCurrentTime)

        objWriter.WriteLine("Version=" + Version_ComboBox.Text)

        objWriter.WriteLine("Loop=OFF")
        objWriter.WriteLine("ButOrTimer=BUTTON")
        objWriter.WriteLine("WaitTime=10")

        objWriter.WriteLine("MirrLockup=OFF")
        objWriter.WriteLine("MirrLockTime=1000")
        objWriter.WriteLine("CT_Pulse=50")
        objWriter.WriteLine("FT1_Pulse=50")
        objWriter.WriteLine("FT2_Pulse=50")

        objWriter.WriteLine("BulbPre=0100")
        objWriter.WriteLine("BulbPost=0100")

        objWriter.WriteLine("Sound=ON")
        objWriter.WriteLine("Debug=OFF")
        objWriter.WriteLine("Leo=NO")
        objWriter.WriteLine("END")
        objWriter.Close()

    End Sub

    Private Sub resetDropData()

        Dim objCurrentDate As Date = DateTime.Today
        Dim currentDate As String = Format(objCurrentDate, "dd/MM/yyyy")
        Dim objCurrentTime As Date = TimeOfDay
        Format(DateTime.Today, "dd/MM/yyyy")

        Dim filename As String = "dropData.txt"
        If (System.IO.File.Exists(filename) = False) Then
            System.IO.File.Create(filename).Dispose()
        End If

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

        objWriter.WriteLine("dropController: Drop data file")
        objWriter.WriteLine("Saved: " & currentDate & " " & objCurrentTime)
        objWriter.WriteLine("numDrops|1")

        objWriter.WriteLine("CT|OFF|0000|OFF|000")
        objWriter.WriteLine("FT1|1000|OFF|000|OFF")
        objWriter.WriteLine("FT2|1000|OFF|000|OFF")
        objWriter.WriteLine("FT3|1000|OFF|000|OFF")

        objWriter.WriteLine("Drop -ON-s-start-ID-val-size- ID-val ")
        objWriter.WriteLine("Drop1|ON|1|0100|OFF|000|0050|OFF|000")
        objWriter.WriteLine("Drop2|OFF|2|0200|OFF|000|0050|OFF|000")
        objWriter.WriteLine("Drop3|OFF|3|0300|OFF|000|0050|OFF|000")
        objWriter.WriteLine("Drop4|OFF|4|0400|OFF|000|0050|OFF|000")
        objWriter.WriteLine("Drop5|OFF|5|0500|OFF|000|0050|OFF|000")
        objWriter.WriteLine("Drop6|OFF|6|0600|OFF|000|0050|OFF|000")
        objWriter.WriteLine("Drop7|OFF|1|0700|OFF|000|0050|OFF|000")
        objWriter.WriteLine("Drop8|OFF|2|0800|OFF|000|0050|OFF|000")
        objWriter.WriteLine("Drop9|OFF|3|0900|OFF|000|0050|OFF|000")
        objWriter.WriteLine("END")

        objWriter.Close()

    End Sub



#End Region '  "SETTINGS TAB"




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

#Region "SETTING BUTTON EVENTS"



    Private Sub LoopMode_BTN_Click(sender As Object, e As EventArgs) Handles LoopMode_BTN.Click
        If (LoopMode_BTN.Text = "ON") Then
            LoopMode_BTN.Text = "OFF"
        Else
            LoopMode_BTN.Text = "ON"
        End If
        updateLoopElements()
    End Sub

    Private Sub lp_TimerOrButton_BTN_Click(sender As Object, e As EventArgs) Handles lp_TimerOrButton_BTN.Click
        If (lp_TimerOrButton_BTN.Text = "BUTTON") Then
            lp_TimerOrButton_BTN.Text = "TIMER"
        Else
            lp_TimerOrButton_BTN.Text = "BUTTON"
        End If
        updateLoopElements()
    End Sub

    Private Sub updateLoopElements()
        If (LoopMode_BTN.Text = "OFF") Then
            timerButton_LBL.ForeColor = Color.Gray
            lp_TimerOrButton_BTN.Enabled = False
            lp_TimerOrButton_BTN.BackColor = greyedOut

        Else
            timerButton_LBL.ForeColor = Color.Black
            lp_TimerOrButton_BTN.Enabled = True
            lp_TimerOrButton_BTN.BackColor = Color.PaleGreen
        End If


        If (lp_TimerOrButton_BTN.Enabled = False Or lp_TimerOrButton_BTN.Text = "BUTTON") Then
            waitTime_LBL.ForeColor = Color.Gray
            LP_waitTimeVal_TB.Enabled = False
        Else
            waitTime_LBL.ForeColor = Color.Black
            LP_waitTimeVal_TB.Enabled = True
        End If
    End Sub

    ' Private Sub LoopTimerVal_TB_Leave(sender As Object, e As EventArgs)
    ' If (Val(LP_waitTimeVal_TB.Text) < 1) Then
    '        MsgBox("Wait time cannot be less than 1 second")
    '       LP_waitTimeVal_TB.Focus()
    'End If
    'End Sub

    Private Sub SET_LEO_BUT_Click(sender As Object, e As EventArgs) Handles SET_LEO_BUT.Click
        If (SET_LEO_BUT.Text = "NO") Then
            SET_LEO_BUT.Text = "YES"
        Else
            SET_LEO_BUT.Text = "NO"
        End If


    End Sub


    Private Sub activateValveDrainButtons()
        debug("Enter activateValveDrainButtons()")
        Dim VD_BUT As Button() = New Button() {valve1Drain_BTN, valve1Drain_BTN, valve2Drain_BTN, valve3Drain_BTN, valve4Drain_BTN, valve5Drain_BTN, valve6Drain_BTN}
        For i As Integer = 1 To numValves
            VD_BUT(i).Enabled = True
        Next i
    End Sub

    Private Sub disableValveDrainButtons()
        debug("Enter disableValveDrainButtons()")
        Dim VD_BUT As Button() = New Button() {valve1Drain_BTN, valve1Drain_BTN, valve2Drain_BTN, valve3Drain_BTN, valve4Drain_BTN, valve5Drain_BTN, valve6Drain_BTN}
        For i As Integer = 1 To numValves
            VD_BUT(i).Enabled = False
        Next i
    End Sub




    Private Sub mirrorLockupYesNo_BTN_Click(sender As Object, e As EventArgs) Handles mirrorLockupOnOff_BTN.Click
        If (mirrorLockupOnOff_BTN.Text = "ON") Then
            mirrorLockupOnOff_BTN.Text = "OFF"
        Else
            mirrorLockupOnOff_BTN.Text = "ON"

            If (Val(mirrorLockupTime_TB.Text) < 1) Then
                mirrorLockupTime_TB.ForeColor = Color.Red
            End If
        End If
        updateML_Elements()
    End Sub


    Private Sub updateML_Elements()
        If (mirrorLockupOnOff_BTN.Text = "OFF") Then
            ML_Time_LBL.ForeColor = Color.Gray
            mirrorLockupTime_TB.Enabled = False
        Else
            ML_Time_LBL.ForeColor = Color.Black
            mirrorLockupTime_TB.Enabled = True
        End If
    End Sub


    Private Sub soundsOnOff_BTN_Click(sender As Object, e As EventArgs) Handles SET_SOUND_BTN.Click
        If (SET_SOUND_BTN.Text = "ON") Then
            SET_SOUND_BTN.Text = "OFF"
        Else
            SET_SOUND_BTN.Text = "ON"
        End If
    End Sub

    Private Sub SET_DEBUG_BTN_Click(sender As Object, e As EventArgs) Handles SET_DEBUG_BTN.Click
        If (SET_DEBUG_BTN.Text = "ON") Then
            SET_DEBUG_BTN.Text = "OFF"
            turnDebugOff()
        Else
            SET_DEBUG_BTN.Text = "ON"
            turnDebugOn()
        End If
    End Sub






    Private Sub valve1Drain_BTN_Click(sender As Object, e As EventArgs) Handles valve1Drain_BTN.Click
        sendValveCommand(sender, 1)
    End Sub

    Private Sub valve2Drain_BTN_Click(sender As Object, e As EventArgs) Handles valve2Drain_BTN.Click
        sendValveCommand(sender, 2)
    End Sub

    Private Sub valve3Drain_BTN_Click(sender As Object, e As EventArgs) Handles valve3Drain_BTN.Click
        sendValveCommand(sender, 3)
    End Sub

    Private Sub valve4Drain_BTN_Click(sender As Object, e As EventArgs) Handles valve4Drain_BTN.Click
        sendValveCommand(sender, 4)
    End Sub

    Private Sub valve5Drain_BTN_Click(sender As Object, e As EventArgs) Handles valve5Drain_BTN.Click
        sendValveCommand(sender, 5)
    End Sub

    Private Sub valve6Drain_BTN_Click(sender As Object, e As EventArgs) Handles valve6Drain_BTN.Click
        sendValveCommand(sender, 6)
    End Sub


    Private Sub sendValveCommand(ByVal theClickedButton As Button, val As Integer)
        Dim command As String = ""

        If (theClickedButton.Text = "OPEN") Then
            theClickedButton.Text = "CLOSED"
            theClickedButton.BackColor = Color.FromArgb(255, 128, 128)

            command = "[O" & val & "0]"
        ElseIf (theClickedButton.Text = "CLOSED") Then
            theClickedButton.Text = "OPEN"
            theClickedButton.BackColor = Color.FromArgb(128, 255, 128)
            command = "[O" & val & "1]"
        End If

        sendCommandToDropController(command)
    End Sub



#End Region     ' "SETTING BUTTON EVENTS"










    '    _____  _____             _____   _    _       _______         ____  
    '   / ____||  __ \     /\    |  __ \ | |  | |     |__   __| /\    |  _ \ 
    '  | |  __ | |__) |   /  \   | |__) || |__| |        | |   /  \   | |_) |
    '  | | |_ ||  _  /   / /\ \  |  ___/ |  __  |        | |  / /\ \  |  _ < 
    '  | |__| || | \ \  / ____ \ | |     | |  | |        | | / ____ \ | |_) |
    '   \_____||_|  \_\/_/    \_\|_|     |_|  |_|        |_|/_/    \_\|____/ 


    ' GGG

#Region "Graph"


    Private Sub TAB_GRAPH_Enter(sender As Object, e As EventArgs) Handles TAB_GRAPH.Enter
        debug(vbCrLf & "Enter Graph TAB")
        ' all the work is done in the PictureBox1_Paint event
    End Sub



    Private Sub TAB_GRAPH_Paint(sender As Object, e As PaintEventArgs) Handles TAB_GRAPH.Paint
        debug("Enter graph tab - paint event")

        Dim sequence As Integer = 1
        Dim numDrops As Integer = 9

        Dim graphSols() As Integer = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
        Dim graphStartTimes() As Integer = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
        Dim graphSizeTimes() As Integer = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
        Dim graphStopTimes() As Integer = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}

        For i As Integer = 1 To numDrops
            graphSols(i) = Val(SolCBs(i).Text)
            graphStartTimes(i) = Val(StartTimes(i).Text)
            graphSizeTimes(i) = Val(Sizes(i).Text)
            graphStopTimes(i) = graphStartTimes(i) + graphSizeTimes(i)
        Next i


        Dim Start_X As Integer = 70
        Dim Start_Y As Integer = 95

        Dim graphWidth As Integer = 700
        Dim GraphHeight As Integer = 340


        Dim yStep As Integer = 25
        Dim dropLineHeight As Integer = yStep - 4



        ' get longest time, round up to nearest 100 and scale the graph to longest
        Dim max_X As Integer = getLongestTime(sequence)
        max_X = roundUpNearest100(max_X)
        If max_X < 1000 Then max_X = 1000

        Dim scale As Double = 1
        scale = max_X / graphWidth
        debug("  Scale = " & scale)

        Dim blackPen As Pen = New Pen(Brushes.Black, 1)
        Dim LightGreyPen = New Pen(Brushes.LightGray, 1)
        Dim LightGreyDashPen1 = New Pen(Brushes.LightGray, 1) : LightGreyDashPen1.DashStyle = 2

        e.Graphics.FillRectangle(Brushes.White, Start_X, Start_Y, graphWidth, GraphHeight)



        '  draw the horizontal lines
        For i As Integer = 0 To 11
            e.Graphics.DrawLine(LightGreyPen, Start_X, Start_Y + (i * yStep), Start_X + graphWidth, Start_Y + (i * yStep))
        Next i

        ' draw the vertical lines
        For i As Integer = 1 To max_X Step 100
            Dim x As Integer = i / scale
            e.Graphics.DrawLine(LightGreyPen, Start_X + x, Start_Y, Start_X + x, Start_Y + (11 * yStep))

            ' draw dashed lines (sub divisions)
            If (max_X <= 2000) Then
                x = (i + 50) / scale
                e.Graphics.DrawLine(LightGreyDashPen1, Start_X + x, Start_Y, Start_X + x, Start_Y + (11 * yStep))
            End If
        Next i

        ' draw the black border around the graph . Do this after the lines to overwrite the lines at the edges.
        e.Graphics.DrawRectangle(blackPen, Start_X, Start_Y, graphWidth, (11 * yStep))




        '  draw the Y labels (SOL1, SOL2, etc)

        Dim y_lbl_Font As New System.Drawing.Font("Verdana", 10)
        Dim x_lbl_Font As New System.Drawing.Font("Verdana", 7)
        Dim drawFormat As New System.Drawing.StringFormat

        Dim tmpLbl As String = ""
        Dim y As Integer = 0

        For i As Integer = 1 To 6
            y = i * yStep + Start_Y - 20
            tmpLbl = "SOL" + CStr(i)
            e.Graphics.DrawString(tmpLbl, y_lbl_Font, Brushes.Black, 25, y, drawFormat)
        Next i

        ' CAM
        y = 8 * yStep + Start_Y - 20
        e.Graphics.DrawString("CAM", y_lbl_Font, Brushes.Black, 25, y, drawFormat)

        ' FT1
        y = 9 * yStep + Start_Y - 20
        e.Graphics.DrawString("FT1", y_lbl_Font, Brushes.Black, 25, y, drawFormat)

        If (Version_ComboBox.Text = "3") Then
            ' FT2
            y = 10 * yStep + Start_Y - 20
            e.Graphics.DrawString("FT2", y_lbl_Font, Brushes.Black, 25, y, drawFormat)

            ' FT3
            y = 11 * yStep + Start_Y - 20
            e.Graphics.DrawString("FT3", y_lbl_Font, Brushes.Black, 25, y, drawFormat)
        End If


        '    ' draw the X labels 
        '    ' if max_X is <  2,200          then use horizontal labels at every step
        '    ' if max_X is    2,201 - 5,000  then use vertical labels at every step
        '    ' if max_X is    5,501 - 10,000 then use vertical labels at every step
        '    ' if max_X is   10,000 - 15,000 then use vertical labels every 2 steps
        '    ' if max_X is > 15,000          then use vertical labels every 3 steps


        Dim labelStep As Integer = 0
        If (max_X <= 5500) Then
            labelStep = 1
        ElseIf (max_X <= 10000) Then
            labelStep = 2
        Else
            labelStep = 3
        End If
        debug("  labelStep = " & labelStep)



        Dim count As Integer = 0
        Dim lw As Integer = 0
        For i As Integer = 0 To max_X Step 100 * labelStep

            Dim x As Integer = i / scale
            Dim X_lbl_String As String = count * 100
            If (count = 0) Then
                X_lbl_String = "000"
            End If


            e.Graphics.DrawLine(blackPen, Start_X + x, Start_Y + (11 * yStep), Start_X + x, Start_Y + (11 * yStep) + 6)

            If (max_X <= 2500) Then

                ' horizontal labels 
                ' this is half the width of the label

                If (i < 1000) Then
                    lw = 13
                Else
                    lw = 15
                End If

                e.Graphics.DrawString(X_lbl_String, x_lbl_Font, Brushes.Black, Start_X + x - lw, Start_Y + (11 * yStep) + 6, drawFormat)


            Else
                ' vertical labels 
                lw = 5
                For k = 0 To X_lbl_String.Length - 1
                    ' Ypos = 440 + (10 * k)
                    'e.Graphics.DrawString(X_lbl_String(k), x_lbl_Font, Brushes.Black, x + Start_X - lw, 435 + (10 * k), drawFormat)
                    e.Graphics.DrawString(X_lbl_String(k), x_lbl_Font, Brushes.Black, x + Start_X - lw, Start_Y + ((11 * yStep) + 6) + (10 * k), drawFormat)
                Next k
            End If
            count = count + labelStep
        Next i

        ' Draw the drop time lines

        Dim c1 As Color = Color.FromArgb(104, 196, 254)
        Dim c2 As Color = Color.FromArgb(104, 196, 104)
        Dim c3 As Color = Color.FromArgb(196, 104, 254)
        Dim c4 As Color = Color.FromArgb(245, 186, 98)
        Dim c5 As Color = Color.FromArgb(245, 98, 186)
        Dim c6 As Color = Color.FromArgb(186, 245, 98)
        Dim c7 As Color = Color.FromArgb(186, 98, 245)
        Dim c8 As Color = Color.FromArgb(98, 245, 186)
        Dim c9 As Color = Color.FromArgb(98, 186, 245)

        Dim dropPen1 = New Pen(c1, dropLineHeight)
        Dim dropPen2 = New Pen(c2, dropLineHeight)
        Dim dropPen3 = New Pen(c3, dropLineHeight)
        Dim dropPen4 = New Pen(c4, dropLineHeight)
        Dim dropPen5 = New Pen(c5, dropLineHeight)
        Dim dropPen6 = New Pen(c6, dropLineHeight)
        Dim dropPen7 = New Pen(c7, dropLineHeight)
        Dim dropPen8 = New Pen(c8, dropLineHeight)
        Dim dropPen9 = New Pen(c9, dropLineHeight)
        Dim dropPens As Pen() = New Pen() {dropPen1, dropPen1, dropPen2, dropPen3, dropPen4, dropPen5, dropPen6, dropPen7, dropPen8, dropPen9}

        Dim triggerPen1 = New Pen(Brushes.Blue, dropLineHeight)
        Dim triggerPen2 = New Pen(Brushes.Red, dropLineHeight)

        Dim tmpStart As Integer = 0
        Dim tmpSize As Integer = 0
        Dim tmpSol As Integer = 0
        Dim tmpStop As Integer = 0

        '    ' draw drop data
        For i As Integer = 1 To numDrops

            If (drop_onOff_BTNS(i).Text = "ON") Then

                tmpStart = graphStartTimes(i) / scale
                tmpSize = graphSizeTimes(i) / scale
                tmpSol = graphSols(i)

                tmpStart = tmpStart + Start_X

                'y = (i - 1) * yStep + (yStep / 2) + Start_Y + 1
                y = (tmpSol - 1) * yStep + (yStep / 2) + Start_Y + 1
                e.Graphics.DrawLine(dropPens(tmpSol), tmpStart, y, tmpStart + tmpSize, y)

                If (tmpSize > 19) Then
                    'e.Graphics.DrawString("S" + CStr(tmpSol), y_lbl_Font, Brushes.Gray, tmpStart + 1, y - (yStep / 2) + 3, drawFormat)
                    e.Graphics.DrawString("D" + CStr(i), y_lbl_Font, Brushes.Black, tmpStart + 1, y - (yStep / 2) + 3, drawFormat)

                Else
                    'e.Graphics.DrawString("S" + CStr(tmpSol), y_lbl_Font, Brushes.Gray, tmpStart + tmpSize + 5, y - (yStep / 2) + 3, drawFormat)
                    e.Graphics.DrawString("D" + CStr(i), y_lbl_Font, Brushes.Gray, tmpStart + tmpSize + 2, y - (yStep / 2) + 3, drawFormat)

                End If

            End If


        Next



        ' camera trigger
        If (CT_BUTTON.Text = "ON") Then
            tmpStart = Val(CT_StartTime_TB.Text) / scale
            tmpStart = tmpStart + Start_X
            tmpSize = Val(CT_Pulse_TB.Text) / scale
            tmpStop = tmpStart + tmpSize
            y = 7 * yStep + (yStep / 2) + Start_Y
            e.Graphics.DrawLine(triggerPen2, tmpStart, y, tmpStop, y)

        ElseIf (CT_BUTTON.Text = "SYNC") Then


        ElseIf (CT_BUTTON.Text = "BULB") Then
            ' need to add offset BulbStopOffset_Time_TB
            tmpStart = Start_X
            tmpStop = getLongestTime(sequence) / scale
            tmpStop = tmpStop + Start_X

            y = 7 * yStep + (yStep / 2) + Start_Y
            e.Graphics.DrawLine(triggerPen2, tmpStart, y, tmpStop, y)
        End If


        '  If (CT_BUTTON.Text = "SYNC") And (FT1_BUTTON.Text = "ON") Then
        If (CT_BUTTON.Text = "SYNC") Then

            tmpStart = (Val(FT1_Time_TB.Text) - Val(BulbStartOffset_Time_TB.Text))
            If (tmpStart < 0) Then tmpStart = 0

            'debug("SYNC tmpStart" & tmpStart)
            tmpStart = tmpStart / scale
                tmpStart = tmpStart + Start_X

                tmpSize = Val(CT_Pulse_TB.Text) / scale
                tmpStop = tmpStart + tmpSize

                y = 7 * yStep + (yStep / 2) + Start_Y
                e.Graphics.DrawLine(triggerPen2, tmpStart, y, tmpStop, y)
            End If


            If (FT1_OnOff_BUTTON.Text = "ON") Then
            tmpStart = Val(FT1_Time_TB.Text) / scale
            tmpStart = tmpStart + Start_X
            tmpSize = Val(FT1_Pulse_TB.Text) / scale
            y = 8 * yStep + (yStep / 2) + Start_Y
            e.Graphics.DrawLine(triggerPen1, tmpStart, y, tmpStart + tmpSize, y)
        End If



        ' Flash trigger 2
        ' do not show if using version 2

        If (Version_ComboBox.Text > "2") Then

            If (FT2_OnOff_BUTTON.Text = "ON") Then
                tmpStart = Val(FT2_Time_TB.Text) / scale
                tmpStart = tmpStart + Start_X
                tmpSize = Val(FT2_Pulse_TB.Text) / scale
                y = 9 * yStep + (yStep / 2) + Start_Y
                e.Graphics.DrawLine(triggerPen1, tmpStart, y, tmpStart + tmpSize, y)
            End If


            ' Flash trigger 3
            ' do not show if using version 2

            If (FT3_OnOff_BUTTON.Text = "ON") Then
                tmpStart = Val(FT3_Time_TB.Text) / scale
                tmpStart = tmpStart + Start_X
                tmpSize = Val(FT3_Pulse_TB.Text) / scale
                y = 10 * yStep + (yStep / 2) + Start_Y
                e.Graphics.DrawLine(triggerPen1, tmpStart, y, tmpStart + tmpSize, y)
            End If



        End If

        ' KEY
        Dim key_lbl_Font As New System.Drawing.Font("Verdana", 12)
        Dim xPos2 As Integer = 0
        Dim kl As String = ""
        For i = 1 To 6
            y = 13 * yStep + (yStep / 2) + Start_Y + 1
            xPos2 = (i - 1) * 120 + Start_X + 20
            kl = "SOL" & i
            e.Graphics.DrawString(kl, key_lbl_Font, Brushes.Black, xPos2, y, drawFormat)

            y = y + 30
            e.Graphics.DrawLine(dropPens(i), xPos2, y, xPos2 + 50, y)
        Next

    End Sub





    Private Function roundUpNearest100(tmpNum As Integer) As Integer

        Dim tmpFraction As Integer = tmpNum / 100
        tmpFraction = tmpFraction * 100

        If (tmpNum > tmpFraction) Then
            tmpFraction = tmpFraction + 100
        End If

        '  roundUpNearest100 = tmpFraction
        Return tmpFraction
    End Function



#End Region       ' Graph









    '              ____    ____   _    _  _______      _______         ____  
    '       /\    |  _ \  / __ \ | |  | ||__   __|    |__   __| /\    |  _ \ 
    '      /  \   | |_) || |  | || |  | |   | |          | |   /  \   | |_) |
    '     / /\ \  |  _ < | |  | || |  | |   | |          | |  / /\ \  |  _ < 
    '    / ____ \ | |_) || |__| || |__| |   | |          | | / ____ \ | |_) |
    '   /_/    \_\|____/  \____/  \____/    |_|          |_|/_/    \_\|____/ 
    '  


#Region "ABOUT TAB"




    Dim imageCount As Integer = 0
    Dim firwareUpdated As Boolean = False

    Private Sub TAB_ABOUT_Enter(sender As Object, e As EventArgs) Handles TAB_ABOUT.Enter
        debug(vbCrLf & "ENTER ABOUT TAB")

        Dim tx As String = ""
        tx = tx & "New for 2021.1.1.1.3" & vbCrLf
        tx = tx & "Changed the max drop size to 9999 (not sure why or when I set it to 999)" & vbCrLf
        tx = tx & "Bug fix: fixed the valves not turning off when leaving the Settings page or closing the app" & vbCrLf & vbCrLf

        tx = tx & "New for 2021.1.1.1.2" & vbCrLf
        tx = tx & "Shutter SYNC mode. Sync the shutter trigger to FT1. Set & Forget!" & vbCrLf
        tx = tx & "Delta buttons: Added an OFF status. INC => DEC => OFF" & vbCrLf
        tx = tx & "Loop Page Copy. Copy the current sequence drop settings to the main drop data" & vbCrLf
        tx = tx & "Bug fix: drops not showing correctly in the Loop Page" & vbCrLf
        tx = tx & "Bug fix: COM port drop down not clearing after a failed connection attempt." & vbCrLf
        About_Updates_TB.Text = tx





        Timer_LoadImages.Interval = 4000
        Timer_LoadImages.Enabled = True
        imageCount = 1

        If (Not firwareUpdated) Then
            sendCommandToDropController("[VERSION]")

        End If


    End Sub


    Private Sub TAB_ABOUT_Leave(sender As Object, e As EventArgs) Handles TAB_ABOUT.Leave
        Timer_LoadImages.Enabled = False
        debug("  image timer OFF")
    End Sub

    Private Sub Timer_LoadImages_Tick(sender As Object, e As EventArgs) Handles Timer_LoadImages.Tick
        imageCount = imageCount + 1
        If (imageCount > 3) Then
            imageCount = 1
        End If

        'debug("  imageCount = " & imageCount)
        If (imageCount = 1) Then
            AboutTab_Picture1.BringToFront()
        ElseIf (imageCount = 2) Then
            AboutTab_Picture2.BringToFront()
        ElseIf (imageCount = 3) Then
            AboutTab_Picture3.BringToFront()
        End If

    End Sub


    Private Sub ABOUT_LINK_LBL_Click(sender As Object, e As EventArgs) Handles ABOUT_LINK_LBL.Click
        Try
            Process.Start("http://www.dropcontroller.com")
        Catch ex As Exception
            MsgBox("Can't load Web page" & vbCrLf & ex.Message)
        End Try

    End Sub

    Private Sub ABOUT_LINK_LBL_MouseHover(sender As Object, e As EventArgs) Handles ABOUT_LINK_LBL.MouseHover
        Me.Cursor = Cursors.Hand
    End Sub

    Private Sub ABOUT_LINK_LBL_MouseLeave(sender As Object, e As EventArgs) Handles ABOUT_LINK_LBL.MouseLeave
        Me.Cursor = Cursors.Arrow
    End Sub



#End Region   ' ABOUT TAB






    Private Sub closeValves()
        debug(vbCrLf & "Enter closeValves()")

        If (SerialPort1.IsOpen) Then
            debug("  serial port is open")

            sendCommandToDropController("[O10]")
            sendCommandToDropController("[O20]")
            sendCommandToDropController("[O30]")
            sendCommandToDropController("[O40]")
            sendCommandToDropController("[O50]")
            sendCommandToDropController("[O60]")

            debug(vbCrLf & "disableValveDrainButtons()")
            Dim VD_BUT As Button() = New Button() {valve1Drain_BTN, valve1Drain_BTN, valve2Drain_BTN, valve3Drain_BTN, valve4Drain_BTN, valve5Drain_BTN, valve6Drain_BTN}
            For i As Integer = 1 To numValves
                VD_BUT(i).Text = "CLOSED"
                VD_BUT(i).BackColor = Color.FromArgb(255, 128, 128)
            Next i

        Else
            debug("  serial port is closed - Valve close cmd not sent")
        End If
    End Sub









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


#Region "TIMERS"




    Private Sub Timer_ConnectionTimeoutON()
        Timer_ConnectionTimeout.Enabled = True
        timerConnectFlag.Text = "ON"
    End Sub

    Private Sub Timer_ConnectionTimeoutOFF()
        Timer_ConnectionTimeout.Enabled = False
        timerConnectFlag.Text = "OFF"
    End Sub




    Private Sub Timer_dropAckTimeoutON()
        ' will need to add sequence value
        Timer_dropAckTimeout.Interval = getLongestTime(1) + 3000
        debug("Timer_dropAckTimeout.Interval = " & getLongestTime(1) + 3000)

        Timer_dropAckTimeout.Enabled = True
        TimerACK_LBL.Text = "ON"
    End Sub

    Private Sub Timer_dropAckTimeoutOFF()
        Timer_dropAckTimeout.Enabled = False
        TimerACK_LBL.Text = "OFF"
    End Sub


    Private Sub TimerLoopDelayOn()
        Timer_LoopDelay.Enabled = True
        Timer_LoopDelay_LBL.Text = "ON"
    End Sub

    Private Sub TimerLoopDelayOff()
        Timer_LoopDelay.Enabled = False
        Timer_LoopDelay_LBL.Text = "OFF"
    End Sub


    Private Sub Timer_recieveSerialDataOn()
        Timer_recieveSerialData.Enabled = True
        Timer_SD_IN_LBL.Text = "ON"

    End Sub

    Private Sub Timer_recieveSerialDataOff()
        Timer_recieveSerialData.Enabled = False
        Timer_SD_IN_LBL.Text = "OFF"
    End Sub


    Private Sub Timer_TestConnection_TimeoutON()
        Timer_TestConnection_Timeout.Enabled = True
    End Sub

    Private Sub Timer_TestConnection_TimeoutOFF()
        Timer_TestConnection_Timeout.Enabled = False
    End Sub


#End Region








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


    ' the main start button has been clicked
    ' the drop data has been checked and is OK

    Private Sub makeDrop()

        SerialPort1.DiscardInBuffer()

        If (LoopMode_BTN.Text = "OFF") Then
            singleDrop()
        Else
            multiDrop()
        End If


    End Sub




    Private Sub singleDrop()

        debug(vbCrLf & "Enter singleDrop()")
        ' no need to open the loop page tab
        ' just make the drop(s)

        ' drop data already checked
        ' init - copy to temp variables ready for send

        ' disable MainStart_BTN
        ' enable ACTIVE button
        ' send data
        ' wait for ACK + timeout: If time out show error message
        ' activate START button

        LP_Sequence_LBL.Text = 1

        MainStart_BTN.Enabled = False
        MainStart_BTN.Text = "A C T I V E"
        MainStart_BTN.BackColor = Color.FromArgb(255, 182, 128)
        sendDropData()

        ' start Timer_dropAckTimeout
        Timer_dropAckTimeoutON()

    End Sub





    '
    '  _       ____    ____   _____      _____          _____  ______ 
    ' | |     / __ \  / __ \ |  __ \    |  __ \  /\    / ____||  ____|
    ' | |    | |  | || |  | || |__) |   | |__) |/  \  | |  __ | |__   
    ' | |    | |  | || |  | ||  ___/    |  ___// /\ \ | | |_ ||  __|  
    ' | |____| |__| || |__| || |        | |   / ____ \| |__| || |____ 
    ' |______|\____/  \____/ |_|        |_|  /_/    \_\\_____||______|
    '

#Region "Loop Page"

    Private Sub multiDrop()

        debug(vbCrLf & "Enter multiDrop()")


        GroupBox1.Visible = True
        debug("  GroupBox1.Visible = True")


        'show or hide drop data
        Dim lp_d_onOff As Button() = New Button() {drop1_onOff_Btn, drop1_onOff_Btn, drop2_onOff_Btn, drop3_onOff_Btn, drop4_onOff_Btn, drop5_onOff_Btn, drop6_onOff_Btn, drop7_onOff_Btn, drop8_onOff_Btn, drop9_onOff_Btn}
        Dim lp_dropNum_LBLs As Label() = New Label() {LP_dropNum1_LBL, LP_dropNum1_LBL, LP_dropNum2_LBL, LP_dropNum3_LBL, LP_dropNum4_LBL, LP_dropNum5_LBL, LP_dropNum6_LBL, LP_dropNum7_LBL, LP_dropNum8_LBL, LP_dropNum9_LBL}
        Dim lp_dropData_LBLs As Label() = New Label() {drop1_LBL, drop1_LBL, drop2_LBL, drop3_LBL, drop4_LBL, drop5_LBL, drop6_LBL, drop7_LBL, drop8_LBL, drop9_LBL}


        ' drop1_onOff_Btn  For orange, it would be "lblGrade.ForeColor = Color.Orange"
        For i = 1 To numDrops
            If (lp_d_onOff(i).Text = "ON") Then
                'lp_dropNum_LBLs(i).Visible = True
                'lp_dropData_LBLs(i).Visible = True
                lp_dropNum_LBLs(i).Visible = True
                lp_dropData_LBLs(i).ForeColor = Color.Black
            Else
                'lp_dropNum_LBLs(i).Visible = False
                'lp_dropData_LBLs(i).Visible = False
                lp_dropNum_LBLs(i).Visible = True
                lp_dropData_LBLs(i).ForeColor = Color.LightGray

            End If

        Next i


        LP_Sequence_LBL.Text = 1
        updateLoopPage()


        'init all the controls and timers
        LP_START_BTN.Location = New Point(80, 450)
        'LP_STOP_BTN.Location = New Point(258, 450)
        LP_RESET_BTN.Location = New Point(404, 450)
        LP_EXIT_BTN.Location = New Point(574, 450)


        LP_START_BTN.Enabled = True
        LP_START_BTN.Visible = True
        LP_START_BTN.Text = "S T A R T"
        LP_START_BTN.BackColor = Color.FromArgb(128, 255, 128)

        LP_RESET_BTN.Enabled = False
        LP_RESET_BTN.Visible = True


        LP_STOP_BTN.Enabled = False
        LP_STOP_BTN.Visible = False

        Loop_seq_LBL.Text = "Next Sequence = "
        LP_copy_BTN.Enabled = True
        LP_copy_BTN.BackColor = Color.LightSkyBlue


        If (lp_TimerOrButton_BTN.Text = "BUTTON") Then
            debug("  init for button mode")

            progressBar_LBL.Visible = False
            LP_ProgressBar.Visible = False


        ElseIf (lp_TimerOrButton_BTN.Text = "TIMER") Then
            debug("  init for timer mode")

            progressBar_LBL.Visible = True
            LP_ProgressBar.Visible = True

            TimerLoopDelayOff()
            updateProgressBar(0)

        End If

        sequenceAborted = False
        debug("sequenceAborted = False")

    End Sub





    Private Sub updateLoopPage()
        debug(vbCrLf & "Enter updateLoopPage()")

        Dim sequence As Integer = Val(LP_Sequence_LBL.Text)
        Dim lp_dropData_LBLs As Label() = New Label() {drop1_LBL, drop1_LBL, drop2_LBL, drop3_LBL, drop4_LBL, drop5_LBL, drop6_LBL, drop7_LBL, drop8_LBL, drop9_LBL}
        Dim stopTime As Long = 0

        UpdateDropDataArrays(sequence)

        For i As Integer = 1 To numDrops
            Dim startDeltaSign As String = " "
            If (dropStartTimeDelta(i) = "INC") Then startDeltaSign = "+"
            If (dropStartTimeDelta(i) = "DEC") Then startDeltaSign = "-"

            Dim sizeDeltaSign As String = " "
            If (dropSizeDelta(i) = "INC") Then sizeDeltaSign = "+"
            If (dropSizeDelta(i) = "DEC") Then sizeDeltaSign = "-"

            stopTime = dropStartTime(i) + dropSize(i)

            lp_dropData_LBLs(i).Text = dropSol(i) & "   " & Format(dropStartTime(i), "0000") & " [" & startDeltaSign & Format(dropStartTimeDeltaVal(i), "000") & "]  " _
                & Format(stopTime, "00000") & "   " _
                & Format(dropSize(i), "0000") & " [" & sizeDeltaSign & Format(dropSizeDeltaVal(i), "000") & "]"

        Next i



        Dim t As Integer = 4
        Dim LBLtext As String = ""
        Dim tmpSign As String = ""


        If (FT1_OnOff_BUTTON.Text = "ON") Then
            Dim incDecString As String = ""

            If (FT1_IncDec_BTN.Text = "INC") Then
                tmpSign = "+"
                incDecString = Format(Val(FT1_IncDecTime_TB.Text), "000")
            End If
            If (FT1_IncDec_BTN.Text = "DEC") Then
                tmpSign = "-"
                incDecString = Format(Val(FT1_IncDecTime_TB.Text), "000")
            End If
            If (FT1_IncDec_BTN.Text = "OFF") Then
                tmpSign = " "
                incDecString = "---"
            End If

            LBLtext = Format(FT1_StartTime, "0000") + " [" + tmpSign + incDecString + "]"
        Else
            LBLtext = "OFF"
        End If
        Loop_FT1_LBL.Text = LBLtext



        If (FT2_OnOff_BUTTON.Text = "ON") Then
            Dim incDecString As String = ""

            If (FT2_IncDec_BTN.Text = "INC") Then
                tmpSign = "+"
                incDecString = Format(Val(FT2_IncDecTime_TB.Text), "000")
            End If
            If (FT2_IncDec_BTN.Text = "DEC") Then
                tmpSign = "-"
                incDecString = Format(Val(FT2_IncDecTime_TB.Text), "000")
            End If
            If (FT2_IncDec_BTN.Text = "OFF") Then
                tmpSign = " "
                incDecString = "---"
            End If

            LBLtext = Format(FT2_StartTime, "0000") + " [" + tmpSign + incDecString + "]"
        Else
            LBLtext = "OFF"
        End If
        Loop_FT2_LBL.Text = LBLtext


        If (FT3_OnOff_BUTTON.Text = "ON") Then
            Dim incDecString As String = ""

            If (FT3_IncDec_BTN.Text = "INC") Then
                tmpSign = "+"
                incDecString = Format(Val(FT3_IncDecTime_TB.Text), "000")
            End If
            If (FT3_IncDec_BTN.Text = "DEC") Then
                tmpSign = "-"
                incDecString = Format(Val(FT3_IncDecTime_TB.Text), "000")
            End If
            If (FT3_IncDec_BTN.Text = "OFF") Then
                tmpSign = " "
                incDecString = "---"
            End If

            LBLtext = Format(FT3_StartTime, "0000") + " [" + tmpSign + incDecString + "]"
        Else
            LBLtext = "OFF"
        End If
        Loop_FT3_LBL.Text = LBLtext



        ' CT_BUTTON


        If (CT_BUTTON.Text = "OFF") Then
            Loop_CT_LBL.Text = "OFF"

        ElseIf (CT_BUTTON.Text = "ON") Then
            Loop_CT_LBL.Text = Format(CT_StartTime, "0000") & " " & "[" & tmpSign & Format(Val(CT_IncDecTime_TB.Text), "000") & "]"

        ElseIf (CT_BUTTON.Text = "SYNC") Then
            Loop_CT_LBL.Text = "SYNC [FT1-" & Format(Val(BulbStartOffset_Time_TB.Text), "0000") & "]"

        ElseIf (CT_BUTTON.Text = "BULB") Then
            Loop_CT_LBL.Text = "BULB MODE"

        End If



        If (mirrorLockupOnOff_BTN.Text = "ON") Then
            LP_ML_LBL.Text = Format(Val(mirrorLockupTime_TB.Text), "0000")
        Else
            LP_ML_LBL.Text = "OFF"
        End If



    End Sub







    '  after start button - when ACK received - if timer start timer not wait for button click
    '  Timer_waitACK
    '  remember to change to active button when sequence is active
    '  



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


    Private Sub LP_START_BTN_Click(sender As Object, e As EventArgs) Handles LP_START_BTN.Click

        debug("LP_START_BTN clicked")


        If (lp_TimerOrButton_BTN.Text = "BUTTON") Then debug("  button mode")
        If (lp_TimerOrButton_BTN.Text = "TIMER") Then debug("  timer mode")

        If (LP_START_BTN.Text = "S T A R T") Then
            LP_START_BTN_ACTIVE()
            LP_RESET_BTN.Enabled = False
            sendDropData()

            Timer_dropAckTimeoutON()


        ElseIf (LP_START_BTN.Text = "S T O P") Then

            LP_START_BTN.Text = "S T A R T"
            LP_START_BTN.BackColor = Color.FromArgb(128, 255, 128)

            If (Timer_dropAckTimeout.Enabled) Then
                Timer_dropAckTimeoutOFF()
                sequenceAborted = True
                debug("sequenceAborted = True")
            End If

            TimerLoopDelayOff()
            updateProgressBar(0)
            PB_count = 0

            LP_copy_BTN.Enabled = True
            LP_copy_BTN.BackColor = Color.LightSkyBlue

        End If
    End Sub






    Private Sub LP_RESET_BTN_Click(sender As Object, e As EventArgs) Handles LP_RESET_BTN.Click


        If (Timer_dropAckTimeout.Enabled) Then
            Timer_dropAckTimeoutOFF()
            sequenceAborted = True
            debug("sequenceAborted = True")

        End If

        TimerLoopDelayOff()
        updateProgressBar(0)

        debug("LP RESET BTN clicked")
        ' the stop button stops the current loop and resets the sequence to 1

        LP_RESET_BTN.Enabled = False

        LP_START_BTN.Enabled = True
        LP_START_BTN.Text = "S T A R T"

        '  LP_STOP_BTN.Enabled = False
        '  LP_STOP_BTN.Visible = False
        '  LP_STOP_BTN.Text = "P A U S E"

        PB_count = 0
        LP_Sequence_LBL.Text = 1
        multiDrop()


    End Sub




    Private Sub LP_EXIT_BTN_Click(sender As Object, e As EventArgs) Handles LP_EXIT_BTN.Click
        debug("LP EXIT BTN clicked")

        ' stop all timers
        If (Timer_dropAckTimeout.Enabled) Then
            Timer_dropAckTimeoutOFF()
            sequenceAborted = True
            debug("sequenceAborted = True")

        End If

        TimerLoopDelayOff()
        updateProgressBar(0)

        LP_RESET_BTN.Enabled = False

        LP_START_BTN.Enabled = True
        LP_START_BTN.Visible = True

        ' LP_STOP_BTN.Enabled = False
        ' LP_STOP_BTN.Visible = False
        ' LP_STOP_BTN.Text = "P A U S E"

        PB_count = 0
        GroupBox1.Visible = False
    End Sub



    ' no longer used
    Private Sub LP_PAUSE_BTN_Click(sender As Object, e As EventArgs) Handles LP_STOP_BTN.Click

        debug("LP PAUSE BTN clicked")
        ' the pause button stop the current sequence only.
        ' on restart the current sequence is started again (including the timer)

        If (LP_STOP_BTN.Text = "P A U S E") Then
            LP_STOP_BTN.Text = "CONTINUE"
            ' stop timer
            TimerLoopDelayOff()
        Else
            LP_STOP_BTN.Text = "P A U S E"
            TimerLoopDelayOn()

        End If



    End Sub

    Private Sub LP_START_BTN_START()
        LP_START_BTN.Enabled = True
        LP_START_BTN.Text = "S T A R T"
        LP_START_BTN.BackColor = Color.FromArgb(128, 255, 128)
        Loop_seq_LBL.Text = "Next Sequence = "
        LP_copy_BTN.Enabled = True
        LP_copy_BTN.BackColor = Color.LightSkyBlue
    End Sub

    Private Sub LP_START_BTN_STOP()
        LP_START_BTN.Enabled = True
        LP_START_BTN.Text = "S T O P"
        LP_START_BTN.BackColor = Color.FromArgb(255, 128, 128)
        Loop_seq_LBL.Text = "Next Sequence = "
        LP_copy_BTN.Enabled = True
        LP_copy_BTN.BackColor = Color.LightSkyBlue

    End Sub

    Private Sub LP_START_BTN_ACTIVE()
        LP_START_BTN.Enabled = False
        LP_START_BTN.Text = "A C T I V E"
        LP_START_BTN.BackColor = Color.FromArgb(255, 182, 128)
        LP_RESET_BTN.Enabled = False

        Loop_seq_LBL.Text = "This Sequence = "

        LP_copy_BTN.Enabled = False
        LP_copy_BTN.BackColor = greyedOut


    End Sub






    Private Sub initForNextDrop()

        If (LoopMode_BTN.Text = "OFF") Then

            MainStart_BTN.Text = "S T A R T"
            MainStart_BTN.BackColor = Color.FromArgb(128, 255, 128)
            MainStart_BTN.Enabled = True

        ElseIf (LoopMode_BTN.Text = "ON") Then


            If (lp_TimerOrButton_BTN.Text = "BUTTON") Then

                LP_START_BTN_START()
                LP_RESET_BTN.Enabled = True

                LP_Sequence_LBL.Text = Val(LP_Sequence_LBL.Text) + 1
                updateLoopPage()

                ' wait for the START button


            ElseIf (lp_TimerOrButton_BTN.Text = "TIMER") Then

                LP_START_BTN_STOP()

                LP_RESET_BTN.Enabled = True

                LP_Sequence_LBL.Text = Val(LP_Sequence_LBL.Text) + 1
                updateLoopPage()

                ' start the drop delay timer
                TimerLoopDelayOn()

            End If

        End If



    End Sub








#End Region ' "Loop Page"







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


    Private Sub sendDropData()

        Dim sequence As Integer = Val(LP_Sequence_LBL.Text)
        debug(vbCrLf & "Enter sendDropData() - Seq=" & sequence)


        UpdateDropDataArrays(sequence)

        Dim activeDrops As Integer = 0
        Dim dropCommandString() As String = {"", "", "", "", "", "", "", "", "", ""}
        Dim CT_Command As String = ""
        Dim FT1_Command As String = ""
        Dim FT2_Command As String = ""
        Dim FT3_Command As String = ""
        Dim ML_Command As String = ""


        For i As Integer = 1 To numDrops
            If (drop_onOff_BTNS(i).Text = "ON") Then
                activeDrops = activeDrops + 1
                '[Dn, sol, start, size]
                '[D212341234]
                dropCommandString(activeDrops) = "[D" & activeDrops & dropSol(i) & Format(dropStartTime(i), "0000") & Format(dropSize(i), "0000") & "]"
            End If
        Next


        sendCommandToDropController("[S" & sequence & "]")
        sendCommandToDropController("[N" & activeDrops & "]")
        For i As Integer = 1 To activeDrops
            sendCommandToDropController(dropCommandString(i))
        Next i




        If (mirrorLockupOnOff_BTN.Text = "ON") Then
            ML_Command = "[MY" & Format(Val(mirrorLockupTime_TB.Text), "0000") & "]"
        Else
            ML_Command = "[MN]"
        End If


        ' FT3
        If (FT3_OnOff_BUTTON.Text = "ON") Then
            ' [F3 Y,1234,123]   
            FT3_Command = "[F3Y" & Format(FT3_StartTime, "0000") & Format(FT3_Size, "000") & "]"
        Else
            FT3_Command = "[F3N]"
        End If


        ' FT2
        If (FT2_OnOff_BUTTON.Text = "ON") Then
            ' [F2 Y,1234,123]   
            FT2_Command = "[F2Y" & Format(FT2_StartTime, "0000") & Format(FT2_Size, "000") & "]"
        Else
            FT2_Command = "[F2N]"
        End If

        ' FT1
        If (FT1_OnOff_BUTTON.Text = "ON") Then
            ' [F1 Y,1234,123]   
            FT1_Command = "[F1Y" & Format(FT1_StartTime, "0000") & Format(FT1_Size, "000") & "]"
        Else
            FT1_Command = "[F1N]"
        End If



        If (CT_BUTTON.Text = "ON") Then
            CT_Command = "[CY" & Format(CT_StartTime, "0000") & Format(CT_Size, "000") & "]"

        ElseIf (CT_BUTTON.Text = "BULB") Then
            CT_Command = "[CB0000" & Format(Val(BulbStopOffset_Time_TB.Text), "0000") & "]"

        ElseIf (CT_BUTTON.Text = "SYNC") Then
            CT_Command = "[CY" & Format(CT_StartTime, "0000") & Format(CT_Size, "000") & "]"
        Else
            '(CT_BUTTON.Text = "OFF") 
            CT_Command = "[CN]"
        End If



        '     For i As Integer = 1 To activeDrops
        '     debug("  CMD =" & dropCommandString(i))
        '     Next i
        '     debug("  CMD =" & CT_Command)
        '     debug("  CMD =" & FT1_Command)
        '     debug("  CMD =" & FT2_Command)
        '     debug("  CMD =" & FT3_Command)


        debug("waste some time")
        debug(" now = " & Now)

        'the delay is very minor but it is enough to allow the arduino to process the received data
        Dim wasteSomeTime As Long = 0
        For j As Integer = 1 To 10000000
            wasteSomeTime = wasteSomeTime + j * 2
        Next j
        debug(" now = " & Now)

        sendCommandToDropController(ML_Command)
        sendCommandToDropController(CT_Command)
        sendCommandToDropController(FT1_Command)
        sendCommandToDropController(FT2_Command)
        sendCommandToDropController(FT3_Command)
        sendCommandToDropController("[EOD]")
        sendCommandToDropController("     ")


    End Sub







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


    Public Function getLongestTime(seq As Integer) As Long
        debug("Enter getLongestTime(). seq = " & seq)

        UpdateDropDataArrays(seq)

        Dim longest As Long = 0
        Dim glStop As Long = 0

        For i As Integer = 1 To numDrops
            If (dropOnOff(i) = "ON") Then
                glStop = dropStartTime(i) + dropSize(i)

                If (glStop > longest) Then longest = glStop
            End If
        Next i


        If (FT3_OnOff_BUTTON.Text = "ON") Then
            glStop = FT3_StartTime + FT3_Size
            If (glStop > longest) Then longest = glStop
        End If

        If (FT2_OnOff_BUTTON.Text = "ON") Then
            glStop = FT2_StartTime + FT2_Size
            If (glStop > longest) Then longest = glStop
        End If

        If (FT1_OnOff_BUTTON.Text = "ON") Then
            glStop = FT1_StartTime + FT1_Size
            If (glStop > longest) Then longest = glStop
        End If

        If (CT_BUTTON.Text = "ON") Then
            glStop = CT_StartTime + CT_Size
            If (glStop > longest) Then longest = glStop
        End If


        ' this has to be the last statement
        If (CT_BUTTON.Text = "BULB") Then
            longest = longest + Val(BulbStopOffset_Time_TB.Text)
        End If

        debug("  longest = " & longest)
        Return longest

    End Function









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

#Region "Progress Bar"



    Dim PB_count
    Private Sub Timer_LoopDelay_Tick(sender As Object, e As EventArgs) Handles Timer_LoopDelay.Tick
        PB_count = PB_count + 1
        Dim PB_timePassed As Long = PB_count * 100
        Dim waitTime As Long = Val(LP_waitTimeVal_TB.Text) * 1000
        Dim percent As Integer = PB_timePassed / waitTime * 100

        updateProgressBar(percent)
    End Sub


    Private Sub updateProgressBar(tmpVal As Integer)
        If (tmpVal > 100) Then
            tmpVal = 100
        End If
        LP_ProgressBar.Value = 100 - tmpVal

        If (tmpVal = 100) Then
            TimerLoopDelayOff()
            PB_count = 0

            LP_START_BTN_ACTIVE()
            sendDropData()

            ' start Timer_dropAckTimeout
            Timer_dropAckTimeoutON()

        End If

    End Sub

#End Region    ' "Progress Bar"







    Private Sub Timer_waitACK_Tick(sender As Object, e As EventArgs) Handles Timer_dropAckTimeout.Tick

        Timer_dropAckTimeoutOFF()
        'Timer_recieveSerialDataOff()


        debug("Timer_dropAckTimeout.Tick")
        debug("drop Ack has timed out")

        MsgBox("No acknowledgement from the dropController. Do you want to continue?",, "ERROR")

        initForNextDrop()


    End Sub











    Private Sub sendCommandToDropController(command As String)

        If (SerialPort1.IsOpen) Then
            SerialPort1.Write(command)
            'SerialPort1.Write(vbCrLf)
            debug("sent com = " & command)
        End If



    End Sub




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

    ' CheckReceivedData()
#Region "recieveSerialData"

    Private Sub Timer_recieveSerialData_Tick(sender As Object, e As EventArgs) Handles Timer_recieveSerialData.Tick

        ' receivedData is the buffer used to store what ever data is received via the serial port
        Timer_recieveSerialDataOff()

        Dim Incoming As String = ""

        If (SerialPort1.IsOpen) Then
            Try
                Incoming = SerialPort1.ReadExisting()
                If Incoming Is Nothing Then
                    Incoming = ""
                End If
            Catch ex As TimeoutException
                Incoming = "Error: Serial Port read timed out."
            End Try

            If (Incoming = "Error: Serial Port read timed out.") Then
                MsgBox(Incoming, "COM PORT ERROR")
                Incoming = ""
            End If
        End If

        receivedData = receivedData + Incoming
        If (receivedData <> "") Then
            debug("RD=" & receivedData)
        End If

        CheckReceivedData()

        Timer_recieveSerialDataOn()
    End Sub




    Private Sub CheckReceivedData()
        ' uses the global variable receivedData

        Dim pos1 As Integer
        Dim pos2 As Integer
        Dim length As Integer
        Dim newCommand As String
        Dim done As Boolean = False

        While (Not done)

            pos1 = receivedData.IndexOf("[") + 1
            pos2 = receivedData.IndexOf("]") + 1


            '  debug("RD=" & receivedData) : debug("pos1=" & pos1) : debug("pos2=" & pos2)


            ' do we have a START MARKER and an END MARKER?
            If (pos1 = 0 Or pos2 = 0) Then
                ' we do not have both START and END MARKERS so we are done
                done = True
            End If



            If (Not done) Then

                ' We have a START MARKER and an END MARKER but are they in the correct order?
                ' Occasionally we may not get complete data and the end marker will be in front of the start marker
                ' for example "xx][xxxxx][xx"

                ' if pos2 <pos1 then remove the first part of the string from receivedData
                ' for example.  "xx][xxxxx][xx" to "[xxxxx][xx"

                If (pos1 <> 0 And pos2 <> 0) Then
                    If (pos2 < pos1) Then
                        receivedData = Microsoft.VisualBasic.Mid(receivedData, pos2 + 1)
                        pos1 = receivedData.IndexOf("[") + 1
                        pos2 = receivedData.IndexOf("]") + 1
                    End If
                End If

                ' We may have removed the only END MARKER so need to check again.
                ' This is not the best code but this way keeps the flow easy to see and makes it easier to edit.
                ' (The first check is not really required).


                pos1 = receivedData.IndexOf("[") + 1
                pos2 = receivedData.IndexOf("]") + 1

                If (pos1 = 0 Or pos2 = 0) Then
                    ' we do not have both start and end markers and we are done
                    done = True
                End If


            End If



            ' If we still have a START MARKER and an END MARKER we should have a command
            If (Not done) Then

                length = pos2 - pos1 + 1
                If (length > 0) Then

                    ' get the data from between the first START MARKER and the first END MARKER
                    newCommand = Mid(receivedData, pos1 + 1, length - 2)


                    'remove the command (including MARKERS)from receivedData
                    receivedData = Mid(receivedData, pos2 + 1)


                    debug("New cmd=" & newCommand)



                    If (newCommand = "HELLO") Then

                        ' HELLO received
                        Timer_ConnectionTimeoutOFF()


                        If (SET_SOUND_BTN.Text = "ON") Then
                            My.Computer.Audio.Play(My.Resources.complete, AudioPlayMode.Background)
                        End If

                        startBTNon()
                        refreshCOM_BTN.Enabled = False
                        connect_BTN.Text = "Dis-connect"
                        connect_BTN.Enabled = True
                        COMport_CB.Enabled = False

                        activateValveDrainButtons()
                        TestConnection_BTN.Enabled = True



                        ' firmwareVersion_LBL
                    ElseIf (newCommand(0) = "V") Then

                        ' version received
                        ' [V,0001,May  5 2018]
                        Dim tmpSplit() As String = Split(newCommand, ",", -1, CompareMethod.Text)
                        aboutFirmware_02_LBL.Text = "Build " & tmpSplit(1)
                        firwareUpdated = True


                        ' Finished The Sequence
                    ElseIf (newCommand = "FTS") Then

                        Timer_dropAckTimeoutOFF()

                        ' drop sequence completed
                        ' reset for the next drop
                        debug("FTS received")

                        If (sequenceAborted = False) Then
                            debug("if (sequenceAborted = False) ")

                            If (SET_SOUND_BTN.Text = "ON") Then
                                My.Computer.Audio.Play(My.Resources.ready, AudioPlayMode.Background)
                            End If

                            initForNextDrop()
                        Else
                            debug("if (sequenceAborted = True) ")
                            sequenceAborted = False
                            debug("SequenceAborted = False ")
                        End If



                        'Are You There => Yes I Am
                    ElseIf (newCommand = "YIA") Then
                        Timer_TestConnection_TimeoutOFF()
                        MsgBox("The dropController is connected.",, "Test Connection")
                        TestConnection_BTN.Text = "Test Connection"
                        TestConnection_BTN.Enabled = True



                    ElseIf (newCommand(0) = "M") Then
                        debug("MESSAGE: " & newCommand)


                    Else

                        '  debug(">>" & newCommand & "<<")

                    End If

                End If ' (length > 0) 

            End If

        End While

    End Sub



    Function GetSerialInData() As String

        Dim Incoming As String
        Try
            Incoming = SerialPort1.ReadExisting()
            If Incoming Is Nothing Then
                Return "nothing" & vbCrLf
            Else
                Return Incoming
            End If
        Catch ex As TimeoutException
            Return "Error: Serial Port read timed out."
        End Try

    End Function


#End Region ' "recieveSerialData"


















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

    ' display the rows for the active drops only.
    ' Disable the rows for the non active drops

    Private Sub UpdateRows()
        debug("Enter UpdateRows()")
        ' need to work out why cannot use global arrays here....

        Dim RowLabels As Label() = New Label() {D1Row_LBL, D1Row_LBL, D2Row_LBL, D3Row_LBL, D4Row_LBL, D5Row_LBL, D6Row_LBL, D7Row_LBL, D8Row_LBL, D9Row_LBL}
        Dim SolCBs As ComboBox() = New ComboBox() {D1Sol_CB, D1Sol_CB, D2Sol_CB, D3Sol_CB, D4Sol_CB, D5Sol_CB, D6Sol_CB, D7Sol_CB, D8Sol_CB, D9Sol_CB}
        Dim StartTimes As TextBox() = New TextBox() {D1StartTime_TB, D1StartTime_TB, D2StartTime_TB, D3StartTime_TB, D4StartTime_TB, D5StartTime_TB, D6StartTime_TB, D7StartTime_TB, D8StartTime_TB, D9StartTime_TB}
        Dim StartIncDecBtns As Button() = New Button() {D1StartIncDec_BTN, D1StartIncDec_BTN, D2StartIncDec_BTN, D3StartIncDec_BTN, D4StartIncDec_BTN, D5StartIncDec_BTN, D6StartIncDec_BTN, D7StartIncDec_BTN, D8StartIncDec_BTN, D9StartIncDec_BTN}
        Dim StartIncVals As TextBox() = New TextBox() {D1StartIncVal_TB, D1StartIncVal_TB, D2StartIncVal_TB, D3StartIncVal_TB, D4StartIncVal_TB, D5StartIncVal_TB, D6StartIncVal_TB, D7StartIncVal_TB, D8StartIncVal_TB, D9StartIncVal_TB}
        Dim Sizes As TextBox() = New TextBox() {D1Size_TB, D1Size_TB, D2Size_TB, D3Size_TB, D4Size_TB, D5Size_TB, D6Size_TB, D7Size_TB, D8Size_TB, D9Size_TB}
        Dim SizeIncDecBtns As Button() = New Button() {D1SizeIncDec_BTN, D1SizeIncDec_BTN, D2SizeIncDec_BTN, D3SizeIncDec_BTN, D4SizeIncDec_BTN, D5SizeIncDec_BTN, D6SizeIncDec_BTN, D7SizeIncDec_BTN, D8SizeIncDec_BTN, D9SizeIncDec_BTN}
        Dim SizeIncTimes As TextBox() = New TextBox() {D1SizeIncVal_TB, D1SizeIncVal_TB, D2SizeIncVal_TB, D3SizeIncVal_TB, D4SizeIncVal_TB, D5SizeIncVal_TB, D6SizeIncVal_TB, D7SizeIncVal_TB, D8SizeIncVal_TB, D9SizeIncVal_TB}

        formatValues()

        For i As Integer = 1 To numDrops
            If (drop_onOff_BTNS(i).Text = "ON") Then

                RowLabels(i).Enabled = True
                SolCBs(i).Enabled = True
                StartTimes(i).Enabled = True
                StartIncDecBtns(i).Enabled = True

                StartIncDecBtns(i).BackColor = Color.LightSkyBlue

                Sizes(i).Enabled = True
                SizeIncTimes(i).Enabled = True
                SizeIncDecBtns(i).Enabled = True
                SizeIncDecBtns(i).BackColor = Color.LightSkyBlue

                If (StartIncDecBtns(i).Text = "OFF") Then
                    StartIncVals(i).Enabled = False
                Else
                    StartIncVals(i).Enabled = True
                End If

                If (SizeIncDecBtns(i).Text = "OFF") Then
                    SizeIncTimes(i).Enabled = False
                Else
                    SizeIncTimes(i).Enabled = True
                End If


            Else
                RowLabels(i).Enabled = False
                SolCBs(i).Enabled = False
                StartTimes(i).Enabled = False
                StartIncDecBtns(i).Enabled = False
                StartIncDecBtns(i).BackColor = greyedOut

                StartIncVals(i).Enabled = False
                Sizes(i).Enabled = False
                SizeIncTimes(i).Enabled = False
                SizeIncDecBtns(i).Enabled = False
                SizeIncDecBtns(i).BackColor = greyedOut


            End If
        Next

    End Sub






    Private Sub LP_copy_BTN_Click(sender As Object, e As EventArgs) Handles LP_copy_BTN.Click
        debug("LP_Copy clicked")

        ' If Timer Then On - pause timer  Timer_LoopDelay.Enabled = True

        If (lp_TimerOrButton_BTN.Text = "TIMER") Then
            TimerLoopDelayOff()
            LP_START_BTN_START()
            LP_ProgressBar.Value = 100
        End If



        Dim reply = MsgBox("Copy current values to main drop data?", 4, "Copy drop data")
        If (reply = vbYes) Then
            debug("Copy Confirmed")

            UpdateDropDataArrays(Val(LP_Sequence_LBL.Text))

            For i = 1 To numDrops
                If (dropOnOff(i) = "ON") Then
                    StartTimes(i).Text = Format(dropStartTime(i), "0000")
                    Sizes(i).Text = Format(dropSize(i), "0000")
                End If
            Next

            If (CT_BUTTON.Text = "ON") Then
                CT_StartTime_TB.Text = Format(CT_StartTime, "0000")
            End If

            If (FT1_OnOff_BUTTON.Text = "ON") Then
                FT1_Time_TB.Text = Format(FT1_StartTime, "0000")
            End If
            If (FT2_OnOff_BUTTON.Text = "ON") Then
                FT2_Time_TB.Text = Format(FT2_StartTime, "0000")
            End If
            If (FT3_OnOff_BUTTON.Text = "ON") Then
                FT3_Time_TB.Text = Format(FT3_StartTime, "0000")
            End If

        End If



    End Sub





    Public Function CheckSize(val As Long, low As Long, high As Long) As Long

        If (val < low) Then
            val = low
        End If
        If (val > high) Then
            val = high
        End If

        Return val
    End Function




    ' this is fairly new and part of the plan to move to global arrays
    ' at present many of the procedures have their own arrays which I don't like any more.

    Private Sub UpdateDropDataArrays(seq As Integer)
        debug("updateDropDataArrays: seq = " & seq)

        For i = 1 To numDrops
            dropOnOff(i) = drop_onOff_BTNS(i).Text
            dropSol(i) = Val(SolCBs(i).Text)

            dropStartTime(i) = Val(StartTimes(i).Text)
            dropStartTimeDelta(i) = StartIncDecBtns(i).Text
            dropStartTimeDeltaVal(i) = Val(StartIncDecVals(i).Text)

            dropSize(i) = Val(Sizes(i).Text)
            dropSizeDelta(i) = SizeIncDecBtns(i).Text
            dropSizeDeltaVal(i) = Val(SizeIncDecVals(i).Text)

            If (seq > 1) Then

                If (dropStartTimeDeltaVal(i) > 0) Then
                    If (dropStartTimeDelta(i) = "INC") Then dropStartTime(i) = Val(StartTimes(i).Text) + ((seq - 1) * Val(StartIncDecVals(i).Text))
                    If (dropStartTimeDelta(i) = "DEC") Then dropStartTime(i) = Val(StartTimes(i).Text) - ((seq - 1) * Val(StartIncDecVals(i).Text))
                End If

                dropStartTime(i) = CheckSize(dropStartTime(i), 0, 9999)

                If (dropSizeDeltaVal(i) > 0) Then
                    If (dropSizeDelta(i) = "INC") Then dropSize(i) = Val(Sizes(i).Text) + ((seq - 1) * Val(SizeIncDecVals(i).Text))
                    If (dropSizeDelta(i) = "DEC") Then dropSize(i) = Val(Sizes(i).Text) - ((seq - 1) * Val(SizeIncDecVals(i).Text))
                End If

                dropSize(i) = CheckSize(dropSize(i), 0, 9999)
            End If
        Next i

        FT1_StartTime = Val(FT1_Time_TB.Text)
        FT2_StartTime = Val(FT2_Time_TB.Text)
        FT3_StartTime = Val(FT3_Time_TB.Text)
        FT1_Size = Val(FT1_Pulse_TB.Text)
        FT2_Size = Val(FT2_Pulse_TB.Text)
        FT3_Size = Val(FT3_Pulse_TB.Text)

        CT_StartTime = Val(CT_StartTime_TB.Text)
        CT_Size = Val(CT_Pulse_TB.Text)


        If (seq > 1) Then

            If (FT1_IncDec_BTN.Text = "INC") Then FT1_StartTime = FT1_StartTime + ((seq - 1) * Val(FT1_IncDecTime_TB.Text))
            If (FT1_IncDec_BTN.Text = "DEC") Then FT1_StartTime = FT1_StartTime - ((seq - 1) * Val(FT1_IncDecTime_TB.Text))

            If (FT2_IncDec_BTN.Text = "INC") Then FT2_StartTime = FT2_StartTime + ((seq - 1) * Val(FT2_IncDecTime_TB.Text))
            If (FT2_IncDec_BTN.Text = "DEC") Then FT2_StartTime = FT2_StartTime - ((seq - 1) * Val(FT2_IncDecTime_TB.Text))

            If (FT3_IncDec_BTN.Text = "INC") Then FT3_StartTime = FT3_StartTime + ((seq - 1) * Val(FT3_IncDecTime_TB.Text))
            If (FT3_IncDec_BTN.Text = "DEC") Then FT3_StartTime = FT3_StartTime - ((seq - 1) * Val(FT3_IncDecTime_TB.Text))

            If (CT_BUTTON.Text = "ON") Then
                If (CT_IncDec_BTN.Text = "INC") Then CT_StartTime = CT_StartTime + ((seq - 1) * Val(CT_IncDecTime_TB.Text))
                If (CT_IncDec_BTN.Text = "DEC") Then CT_StartTime = CT_StartTime - ((seq - 1) * Val(CT_IncDecTime_TB.Text))
            End If

        End If

        FT1_StartTime = CheckSize(FT1_StartTime, 0, 9999)
        FT2_StartTime = CheckSize(FT2_StartTime, 0, 9999)
        FT3_StartTime = CheckSize(FT3_StartTime, 0, 9999)

        If (CT_BUTTON.Text = "BULB") Then
            CT_StartTime = 0
        ElseIf (CT_BUTTON.Text = "SYNC") Then
            CT_StartTime = FT1_StartTime - Val(BulbStartOffset_Time_TB.Text)
        End If

        CT_StartTime = CheckSize(CT_StartTime, 0, 9999)


    End Sub








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

#Region "debug"



    Dim objWriter_debug As New System.IO.StreamWriter("debugLog.txt", False)
    Dim debugFileIsOpen As Boolean = False

    Private Sub turnDebugOn()
        Me.Width = widthDebug
        debugTextBox.Visible = True
        SET_DEBUG_BTN.Text = "ON"
        SET_DEBUG_LBL.Visible = True
        SET_DEBUG_BTN.Visible = True
        SET_DEBUG_BTN2.Visible = True

        checkConnected_Timer.Enabled = True
    End Sub

    Private Sub turnDebugOff()
        Me.Width = widthNormal
        debugTextBox.Visible = False
        SET_DEBUG_BTN.Text = "OFF"

        checkConnected_Timer.Enabled = False

        If (DEBUG_MASTER = False) Then
            SET_DEBUG_LBL.Visible = False
            SET_DEBUG_BTN.Visible = False
            SET_DEBUG_BTN2.Visible = False
        End If

    End Sub


    Private Sub openDebugLogFile()
        If (System.IO.File.Exists("debugLog.txt") = False) Then
            System.IO.File.Create("debugLog.txt").Dispose()
        End If

        Dim objCurrentDate As Date = DateTime.Today
        Dim currentDate As String = Format(objCurrentDate, "dd/MM/yyyy")
        Dim objCurrentTime As Date = TimeOfDay
        Format(DateTime.Today, "dd/MM/yyyy")

        objWriter_debug.WriteLine("dropController V3: debug log File")
        objWriter_debug.WriteLine("Saved: " & currentDate & " " & objCurrentTime)

        debugFileIsOpen = True
    End Sub

    Private Sub closeDebugLogFile()
        debugTextBox.AppendText(vbCrLf & "Close debug file)" & vbCrLf)
        objWriter_debug.WriteLine("END")
        objWriter_debug.Close()
        debugFileIsOpen = False
    End Sub


    Private Sub debug(text As String)
        Dim txt As String = ""

        If (useDebugLogFile) Then
            If (debugFileIsOpen) Then
                objWriter_debug.WriteLine(text)
            End If
        End If

        If (text = "<RESET>") Then
            txt = "<RESET>" & vbCrLf & vbCrLf
        Else
            txt = text & vbCrLf
        End If

        debugTextBox.AppendText(txt)

    End Sub


    Private Sub SET_DEBUG_BTN2_Click(sender As Object, e As EventArgs) Handles SET_DEBUG_BTN2.Click
        For i As Integer = 1 To 9
            drop_onOff_BTNS(i).Text = "ON"
            SolCBs(i).Text = i
            If (i = 7) Then SolCBs(i).Text = 1
            If (i = 8) Then SolCBs(i).Text = 2
            If (i = 9) Then SolCBs(i).Text = 3
            StartTimes(i).Text = (i - 1) * 500
            Sizes(i).Text = "500"

        Next
        CT_BUTTON.Text = "BULB"
        FT1_OnOff_BUTTON.Text = "ON"
        FT2_OnOff_BUTTON.Text = "ON"
        FT3_OnOff_BUTTON.Text = "ON"
        FT1_Time_TB.Text = "1000"
        FT2_Time_TB.Text = "2000"
        FT3_Time_TB.Text = "3000"
        UpdateRows()
        updateSidePanel()
    End Sub






    Private Sub Timer1_Tick(sender As Object, e As EventArgs) Handles checkConnected_Timer.Tick
        checkConnected_Timer.Enabled = False
        Dim tmp As Boolean
        tmp = SerialPort1.IsOpen
        If (tmp) Then
            Connected_Flag.Text = "TRUE"
        Else
            Connected_Flag.Text = "FALSE"
        End If
        checkConnected_Timer.Enabled = True
    End Sub


#End Region ' "debug"






End Class

