Projects

Find all our projects in development below.
All source code is GNU General Public License (GPL)

plx2lm1

Browsing frmMain.vb (14.88 KB)

Option Explicit On

Imports System.BitConverter
Imports System.Collections
Imports System.IO
Imports System.Xml

Public Class frmMain

    Private bAllowClose As Boolean = False

    Private _inPort As String = ""
    Private _outPort As String = ""
    Private _afrMultiplier As Short = 0
    Private _lambdaOffset As Short = 0

    Private _inCount As Double = 0
    Private _outCount As Double = 0

    Private _inBuff(15) As Byte
    Private _outBuff(15) As Byte

    Private comImg_off As Bitmap = Nothing
    Private comImg_on As Bitmap = Nothing
    Private comImg_err As Bitmap = Nothing

    Private comIco_off As Icon = Nothing
    Private comIco_on As Icon = Nothing
    Private comIco_err As Icon = Nothing

    Private Const XML_CONFIG_FILE As String = "config.xml"
    Private Const XML_CONFIG_PATH As String = "/plx2lm1/config"

    Private Enum StatusCodes
        StatusError
        StatusOff
        StatusOn
    End Enum

    Private Function LoadXmlConfig(ByVal xmlFile As String) As Boolean

        Try

            If Not File.Exists(xmlFile) Then _
                Return False

            Dim xmlDoc As New XmlDocument

            ' load the xml file
            xmlDoc.Load(xmlFile)

            ' load configuration
            Dim cfgNode As XmlNode = xmlDoc.SelectSingleNode(XML_CONFIG_PATH)

            Dim thisNode As XmlNode = cfgNode.Item("incoming_port")
            _inPort = thisNode.InnerText

            thisNode = cfgNode.Item("outgoing_port")
            _outPort = thisNode.InnerText

            thisNode = cfgNode.Item("afr_multiplier")
            _afrMultiplier = CShort(Val(thisNode.InnerText) * 10)

            thisNode = cfgNode.Item("lambda_offset")
            _lambdaOffset = Short.Parse(thisNode.InnerText)

            Return True

        Catch
            Return False
        End Try

    End Function

    Private Function GetResImg(ByVal imgName As String) As Bitmap

        Try
            Return My.Resources.ResourceManager.GetObject(imgName)
        Catch
            Return Nothing
        End Try

    End Function

    Private Function GetResIcon(ByVal iconName As String) As Icon

        Try
            Return My.Resources.ResourceManager.GetObject(iconName)
        Catch
            Return Nothing
        End Try

    End Function

    Private Sub SetStatus(ByVal status As StatusCodes)

        If status = StatusCodes.StatusError Then

            ' set status icons
            lblIco.Image = comImg_err
            appNotifyIcon.Icon = comIco_err

            lblInfo.Text = "Error"

            timerUpdate.Enabled = False

        ElseIf status = StatusCodes.StatusOff Then

            ' set status icons
            lblIco.Image = comImg_off
            appNotifyIcon.Icon = comIco_off

            lblInfo.Text = "No connection"

            timerUpdate.Enabled = False

        ElseIf status = StatusCodes.StatusOn Then

            ' set status icons
            lblIco.Image = comImg_on
            appNotifyIcon.Icon = comIco_on

            lblInfo.Text = "Connected"

            timerUpdate.Enabled = True

        End If

        appNotifyIcon.Text = Me.Text + " :: " + lblInfo.Text
        lblIco.ToolTipText = "Status: " + lblInfo.Text

    End Sub

    Private Sub ConnectPorts()

        _inCount = 0
        _outCount = 0

        Try

            ' close open ports
            If spIn.IsOpen Then spIn.Close()
            If spOut.IsOpen Then spOut.Close()

        Catch
        End Try

        SetStatus(StatusCodes.StatusOff)
        Application.DoEvents()

        Try

            spIn.PortName = _inPort
            spIn.Open()

            spOut.PortName = _outPort
            spOut.Open()

            SetStatus(StatusCodes.StatusOn)

        Catch ex As Exception

            SetStatus(StatusCodes.StatusError)

            MessageBox.Show(ex.Message, Application.ProductName, _
                MessageBoxButtons.OK, MessageBoxIcon.Error)

        End Try

    End Sub

    Private Sub spIn_DataReceived(ByVal sender As Object, ByVal e As System.IO.Ports.SerialDataReceivedEventArgs) Handles spIn.DataReceived

        ' determine if there is data to be read
        If e.EventType = IO.Ports.SerialData.Chars Then

            ' read incoming data (plx protocol)
            ' http://www.plxdevices.com/AppNotes/PLXApp016.pdf
            '
            ' Speed1Low � LSB 8Bit of Speed Input #1 (First Byte Transmitted)
            ' Speed1High � MSB 8Bit of Speed Input #1
            ' Speed2Low � LSB 8Bit of Speed Input #2
            ' Speed2High � MSB 8Bit of Speed Input #2
            ' Analog1 � 8Bit of Analog Input #1
            ' Analog2 � 8Bit of Analog Input #2
            ' Analog3 � 8Bit of Analog Input #3
            ' Analog4 � 8Bit of Analog Input #4
            ' EventPacket � Decimal value of 255 (Binary value 11111111) (9th Byte Transmitted)
            '
            ' (Sequence is repeated)

            spIn.Read(_inBuff, 0, _inBuff.Length)
            _inCount += 1

            ' discard any extra data (if necessary)
            If spIn.BytesToRead > 0 Then spIn.DiscardInBuffer()

            ' find the event packet
            Dim i As Integer = 0
            For i = 0 To _inBuff.Length - 1
                If _inBuff(i) = &HFF Then Exit For
            Next

            ' validate index
            If (i > 0 And i < _inBuff.Length) AndAlso _
                (_inBuff(i - 1) > 0 And _inBuff(i - 1) < 254) Then

                ' build the lm-1 protocol
                ' http://www.innovatemotorsports.com/resources/serial-protocol.php
                ' ---------------------------------------------

                ' WORD Bit
                ' 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
                '
                ' 0 1 R F3 F2 F1 F0 0 AF7 0 AF6 AF5 AF4 AF3 AF2 AF1 AF0
                ' 1 0 0 L12 L11 L10 L9 L8 L7 0 L6 L5 L4 L3 L2 L1 L0
                ' 2 0 0 mb2 mb1 mb0 bv9 bv8 bv7 0 bv6 bv5 bv4 bv4 bv2 bv1 bv0
                ' 3..7 0 0 0 0 0 Aux9 Aux8 Aux7 0 Aux6 Aux5 Aux4 Aux3 Aux2 Aux1 Aux0

                ' ---------------------------------------------

                ' 2.1 Function/Status Word (Word 0)
                '
                '
                ' Bit 15 of always set
                '
                ' Bit 14 (R) is set if currently recording to Flash in LM-1
                '
                ' Bit 13..10 (Func3..0) are function/status bits how interpret the next word (Lambda Word).
                '
                ' Func3..0
                '
                ' 0000 Lambda valid and Aux data valid, normal operation.
                ' 0001 Lambda value contains O2 level in 1/10%
                ' 0010 Free air Calib in progress, Lambda data not valid
                ' 0011 Need Free air Calibration Request, Lambda data not valid
                ' 0100 Warming up, Lambda value is temp in 1/10% of operating temp.
                ' 0101 Heater Calibration, Lambda value contains calibration countdown.
                ' 0110 Error code in Lambda value
                ' 0111 Lambda Value is Flash level in 1/10%
                ' 1xxx reserved
                '
                ' Bit 8 contains high bit (bit 7) of AFR multiplier (AF7)
                '
                ' Bit 7 always 0
                '
                ' Bit 6..0 contain remaining 7 bits of AFR multiplier (AF6..AF0).
                '
                ' AFR multiplier is stochiometric AFR value of current fuel setting in the LM-1 times 10. E.g. 147 for gasoline (14.7).
                ' Air/Fuel Ratio = ((L12..L0) + 500)* (AF7..0) / 10000

                ' build word 0
                Dim w0() As Boolean = {True, False, False, False, False, False, False, False, _
                    False, False, False, False, False, False, False, False}

                Dim word0 As New BitArray(w0)

                ' apply afr multiplier to word 0
                Dim afr_bits As New BitArray(GetBytes(_afrMultiplier))

                word0(7) = afr_bits(0)
                word0(9) = afr_bits(1)
                word0(10) = afr_bits(2)
                word0(11) = afr_bits(3)
                word0(12) = afr_bits(4)
                word0(13) = afr_bits(5)
                word0(14) = afr_bits(6)
                word0(15) = afr_bits(7)

                ' ---------------------------------------------

                ' 2.2 Lambda Word (Word 1)
                '
                ' Lambda in 0.001 Lambda increments when F3..F0 is 0000, offset by 0.5 Lambda.
                '
                ' L = 0 -> 0.5 Lambda
                ' L = 1022 -> 1.522 Lambda
                ' L = 1023 Lambda = 1.523
                ' L = 8191 Lambda = 8.691

                Dim multiplier As Double = _inBuff(i - 1) / 255
                Dim lambda As Short = ((1760 - 312) * multiplier) + 312 + _lambdaOffset

                ' get the bytes of the lambda
                Dim lambda_bytes() As Byte = GetBytes(lambda)

                ' drop last 2 bytes and reverse (for big endian)
                Dim b(1) As Byte
                b(0) = lambda_bytes(1)
                b(1) = lambda_bytes(0)

                Dim word1 As New BitArray(b)

                ' ---------------------------------------------

                ' 2.3 Battery Voltage (Word 2)
                '
                ' Battery voltage digitized to 10 bit (bv9..bv0) and battery divider (mb2..mb0).
                ' Calculate battery voltage in Volt as bv * 5 * mb / 1023.

                ' word2 reserved for battery voltage
                Dim word2 As New BitArray(16)

                ' ---------------------------------------------

                ' 2.4 Aux Input (Word 3..7)
                '
                ' Aux Inputs digitized to 10 bits. 0 = 0V, 1023 = 5V.
                '
                ' If RPM converter is used, Multiply WORD 3 value by 10 to get rpm. 

                ' word3 reserved for aux input
                'Dim word3 As New BitArray(16)

                ' create output packet
                word0.CopyTo(_outBuff, 0)
                word1.CopyTo(_outBuff, 2)
                word2.CopyTo(_outBuff, 4)
                'word3.CopyTo(_outBuff, 6)

                ' discard any unsent data (if necessary)
                If spOut.BytesToWrite > 0 Then spOut.DiscardOutBuffer()

                Try

                    ' write the packet to the output port
                    spOut.Write(_outBuff, 0, _outBuff.Length)
                    _outCount += 1

                Catch
                End Try

            End If

        End If

    End Sub

    Private Sub appNotifyIcon_MouseDoubleClick(ByVal sender As System.Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles appNotifyIcon.MouseDoubleClick

        If (e.Button = Windows.Forms.MouseButtons.Left And _
            Not SystemInformation.MouseButtonsSwapped) Or _
            (e.Button = Windows.Forms.MouseButtons.Right And _
            SystemInformation.MouseButtonsSwapped) Then

            ' display the main form
            Me.Show()
            Me.WindowState = FormWindowState.Normal

        End If

    End Sub

    Private Sub frmMain_FormClosing(ByVal sender As Object, ByVal e As System.Windows.Forms.FormClosingEventArgs) Handles Me.FormClosing

        If Not bAllowClose And _
            e.CloseReason = CloseReason.UserClosing Then

            ' stop the form from closing
            e.Cancel = True
            Me.Hide()
            Exit Sub

        End If

        Try

            ' close open ports
            If spIn.IsOpen Then spIn.Close()
            If spOut.IsOpen Then spOut.Close()

        Catch
        End Try

        ' destroy resources
        If Not (comImg_off Is Nothing) Then _
            comImg_off.Dispose()

        If Not (comImg_on Is Nothing) Then _
            comImg_on.Dispose()

        If Not (comImg_err Is Nothing) Then _
            comImg_err.Dispose()

        If Not (comIco_off Is Nothing) Then _
            comIco_off.Dispose()

        If Not (comIco_on Is Nothing) Then _
            comIco_on.Dispose()

        If Not (comIco_err Is Nothing) Then _
            comIco_err.Dispose()

    End Sub

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

        ' load config from xml
        If Not LoadXmlConfig(XML_CONFIG_FILE) Then

            timerLoad.Enabled = False

            MessageBox.Show("Unable to load config from xml.", _
                Application.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Error)

            bAllowClose = True
            Me.Close()
            Exit Sub

        End If

        ' validate config
        If _inPort.Trim = "" Or _outPort.Trim = "" Then

            timerLoad.Enabled = False

            MessageBox.Show("Please set the correct ports in the config xml.", _
                Application.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Error)

            bAllowClose = True
            Me.Close()
            Exit Sub

        End If

        ' load resources
        comImg_off = GetResImg("com_off")
        comImg_on = GetResImg("com_on")
        comImg_err = GetResImg("com_err")
        comIco_off = GetResIcon("transfer_blk")
        comIco_on = GetResIcon("transfer_grn")
        comIco_err = GetResIcon("transfer_red")

        ' set initial tray icon
        appNotifyIcon.Icon = comIco_off

        lblInPort.Text = "IN: " + _inPort
        lblOutPort.Text = "OUT: " + _outPort

    End Sub

    Private Sub frmMain_Resize(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Resize

        ' check for windowstate change
        If Me.WindowState = FormWindowState.Minimized Then _
            Me.Hide()

    End Sub

    Private Sub mnuOpen_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles mnuOpen.Click

        ' display the main form
        Me.Show()
        Me.WindowState = FormWindowState.Normal

    End Sub

    Private Sub mnuExit_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles mnuExit.Click

        bAllowClose = True
        Me.Close()

    End Sub

    Private Sub mnuReconnect_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles mnuReconnect.Click

        ConnectPorts()

    End Sub

    Private Sub timerLoad_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles timerLoad.Tick

        timerLoad.Enabled = False
        ConnectPorts()

    End Sub

    Private Sub timerUpdate_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles timerUpdate.Tick

        lblIn.Text = Format(_inCount, "###,###,###,##0")
        lblOut.Text = Format(_outCount, "###,###,###,##0")

    End Sub

End Class

Download frmMain.vb

Back to file list


Back to project page