Option Strict Off
Imports System.Collections
Imports Microsoft.Win32
Imports System.Text.RegularExpressions
Imports System.IO
Imports System.IO.MemoryMappedFiles
Imports System.Runtime.InteropServices
Imports System.Threading
Imports System.Security
Imports System.ComponentModel
Imports Microsoft.Win32.SafeHandles
Imports System.Runtime.ConstrainedExecution
Imports System.Security.Permissions

Public Class Class1
    Implements GOverlayPlugin.Interfaces.IPlugin
    Public testvar As Integer = 1

    Private objHost As GOverlayPlugin.Interfaces.IHost
    Public PluginName As String = "Euro Truck Simulator 2"

    Public Cache As String

    Public Const MapPrefix As String = "Local\"
    Public Const MapName As String = "GOverlay_ETS2"
    Public Const FullMapName As String = MapPrefix & MapName

    Public PosSlot As Integer
    Public LastCache As New System.Collections.Hashtable

    Dim hMapFile As SafeFileMappingHandle = Nothing
    Public pView As IntPtr = IntPtr.Zero
    Public rdata As ETSStructure

    ' File offset where the view is to begin.
    Public Const ViewOffset As UInt32 = 0

    ' The number of bytes of a file mapping to map to the view. All bytes of the
    ' view must be within the maximum size of the file mapping object (MAP_SIZE). 
    ' If VIEW_SIZE is 0, the mapping extends from the offset (VIEW_OFFSET) to 
    ' the end of the file mapping.
    'Friend Const ViewSize As UInt32 = &H400
    Public Const ViewSize As UInt32 = 259
    Public Sub Initialize(ByVal Host As GOverlayPlugin.Interfaces.IHost) Implements GOverlayPlugin.Interfaces.IPlugin.Initialize
        objHost = Host
    End Sub

    Public ReadOnly Property Description() As String Implements GOverlayPlugin.Interfaces.IPlugin.Description
        'Return your plugin name
        Get
            Return "This plugin allows to read the Truck Information from the game Euro Truck Simulator 2." & vbNewLine & vbNewLine & _
                "Make sure the required GOverlay ETS2 plugin is in the plugins folder of your game (you can find the plugin in plugins\Examples\ETS2\GamePlugin" & vbNewLine & _
                "Read the readme.txt file on how to install this plugin " & vbNewLine & _
                "Remember to UPLOAD the LCDSysInfo files with GOverlay (files with name xxx.x.plugin_ets_*.jpg)" & vbNewLine & vbNewLine & _
                "Developed by TheLaGmAn"
        End Get
    End Property

    Public ReadOnly Property Name() As String Implements GOverlayPlugin.Interfaces.IPlugin.Name
        'Return your plugin name
        Get
            Return PluginName
        End Get        
    End Property

    Public ReadOnly Property Display() As String Implements GOverlayPlugin.Interfaces.IPlugin.Display
        'Return the display this plugin belongs to
        Get
            Return "lcdsys"
        End Get
    End Property

    Function CallBack(method As String) As Hashtable Implements GOverlayPlugin.Interfaces.IPlugin.CallBacks
        'Send the request to upload all the files
        'objHost.DebugMessage("ETS2 Plugin - Callback Requested")
        'objHost.DebugMessage("ETS2 Plugin - " & method)

        Dim returnHT As Hashtable = New Hashtable

        Dim value = 0

        If method = "reqimagesbutton" Then
            objHost.DebugMessage("ETS2 Plugin - Callback is reqimages button")
            objHost.AccessHost("plugin_upload_files", PluginName, "reqimages", "")
            objHost.DebugMessage("ETS2 Plugin - Callback is done")
        ElseIf method = "willrequestvalues" Then
            'Comes here once per run (only if sensors are used thru here)
            GrabData(0)
        ElseIf method = "ETS2.Truck_Speed" Then
            value = rdata.speed
        ElseIf method = "ETS2.Engine_RPM" Then
            value = rdata.rpm
        ElseIf method = "ETS2.Engine_Gear" Then
            value = rdata.gear
        ElseIf method = "ETS2.RPM_At_Limit" Then
            value = rdata.rpm_at_limit
        ElseIf method = "ETS2.Parking_Brake" Then
            value = rdata.parking_brake
        ElseIf method = "ETS2.Adblue_Amount" Then
            value = rdata.adblue_amount
        ElseIf method = "ETS2.Adblue_Avg_Consumption" Then
            value = rdata.adblue_average_consumption
        ElseIf method = "ETS2.Adblue_Warning" Then
            value = rdata.adblue_warning
        ElseIf method = "ETS2.Battery_Voltage" Then
            value = rdata.battery_voltage
        ElseIf method = "ETS2.Battery_Voltage_Warning" Then
            value = rdata.battery_voltage_warning
        ElseIf method = "ETS2.Brake_Air_Pressure" Then
            value = rdata.brake_air_pressure
        ElseIf method = "ETS2.Brake_Air_Pressure_Emergency" Then
            value = rdata.brake_air_pressure_emergency
        ElseIf method = "ETS2.Brake_Air_Pressure_Warning" Then
            value = rdata.brake_air_pressure_warning
        ElseIf method = "ETS2.Brake_Temperature" Then
            value = rdata.brake_temperature
        ElseIf method = "ETS2.Dashboard_Backlight" Then
            value = rdata.dashboard_backlight
        ElseIf method = "ETS2.Electric_Enabled" Then
            value = rdata.electric_enabled
        ElseIf method = "ETS2.Fuel_Amount" Then
            value = rdata.fuel_amount
        ElseIf method = "ETS2.Fuel_Avg_Consumption" Then
            value = rdata.fuel_average_consumption
        ElseIf method = "ETS2.Fuel_Warning" Then
            value = rdata.fuel_warning
        ElseIf method = "ETS2.Left_Blinker" Then
            value = rdata.left_blinker
        ElseIf method = "ETS2.Left_Blinker_Light" Then
            value = rdata.left_blinker_light
        ElseIf method = "ETS2.Right_Blinker" Then
            value = rdata.right_blinker
        ElseIf method = "ETS2.Right_Blinker_Light" Then
            value = rdata.right_blinker_light
        ElseIf method = "ETS2.Light_Aux_Front" Then
            value = rdata.light_aux_front
        ElseIf method = "ETS2.Light_Aux_Roof" Then
            value = rdata.light_aux_roof
        ElseIf method = "ETS2.Light_Beacon" Then
            value = rdata.light_beacon
        ElseIf method = "ETS2.Light_Brake" Then
            value = rdata.light_brake
        ElseIf method = "ETS2.Light_High_Beam" Then
            value = rdata.light_high_beam
        ElseIf method = "ETS2.Light_Low_Beam" Then
            value = rdata.light_low_beam
        ElseIf method = "ETS2.Light_Parking" Then
            value = rdata.light_parking
        ElseIf method = "ETS2.Light_Reverse" Then
            value = rdata.light_reverse
        ElseIf method = "ETS2.Motor_Brake" Then
            value = rdata.motor_brake
        ElseIf method = "ETS2.Odometer" Then
            value = rdata.odometer
        ElseIf method = "ETS2.Oil_Pressure" Then
            value = rdata.oil_pressure
        ElseIf method = "ETS2.Oil_Pressure_Warning" Then
            value = rdata.oil_pressure_warning
        ElseIf method = "ETS2.Oil_Temperature" Then
            value = rdata.oil_temperature
        ElseIf method = "ETS2.Water_Temperature" Then
            value = rdata.water_temperature
        ElseIf method = "ETS2.Water_Temperature_Warning" Then
            value = rdata.water_temperature_warning
        ElseIf method = "ETS2.Wear_Cabin" Then
            value = rdata.wear_cabin
        ElseIf method = "ETS2.Wear_Chasis" Then
            value = rdata.wear_chassis
        ElseIf method = "ETS2.Wear_Engine" Then
            value = rdata.wear_engine
        ElseIf method = "ETS2.Wear_Transmission" Then
            value = rdata.wear_transmission
        ElseIf method = "ETS2.Wear_Wheels" Then
            value = rdata.wear_wheels
        ElseIf method = "ETS2.Wipers" Then
            value = rdata.wipers
        ElseIf method = "ETS2.Adblue_Capacity" Then
            value = rdata.adblue_capacity
        ElseIf method = "ETS2.Air_Pressure_Emergency_Minimum" Then
            value = rdata.air_pressure_emergency_minimum
        ElseIf method = "ETS2.Air_Pressure_Warning_Minimum" Then
            value = rdata.air_pressure_warning_minimum
        ElseIf method = "ETS2.Battery_Voltage_Warning_Minimum" Then
            value = rdata.battery_voltage_warning_minimum
        ElseIf method = "ETS2.Fuel_Capacity" Then
            value = rdata.fuel_capacity
        ElseIf method = "ETS2.Fuel_Warning_Minimum" Then
            value = rdata.fuel_warning_minimum
        ElseIf method = "ETS2.Oil_Pressure_Warning_Minimum" Then
            value = rdata.oil_pressure_warning_minimum
        ElseIf method = "ETS2.Oil_Pressure_Warning_Minimum" Then
            value = rdata.oil_pressure_warning_minimum
        ElseIf method = "ETS2.RPM_Limit" Then
            value = rdata.rpm_limit
        ElseIf method = "ETS2.Water_Temperature_Warning_Minimum" Then
            value = rdata.water_temperature_warning_minimum
        End If

        returnHT("value") = value

        Return returnHT

    End Function

    Function SensorHasCustomDraw(sensorId As String) As Boolean Implements GOverlayPlugin.Interfaces.IPlugin.SensorHasCustomDraw
        If sensorId = "ETS2.Gauge" Then
            Return True
        ElseIf sensorId = "ETS2.Gauge1" Then
            Return True
        Else
            Return False
        End If
    End Function


    Function AvailableSensors(pluginOptions As Hashtable) As System.Collections.Generic.Dictionary(Of String, String) Implements GOverlayPlugin.Interfaces.IPlugin.AvailableSensors
        'Create the list of the sensors/elements this plugin has
        'You can access your pluginOptions here as pluginOptions(your_option)        
        Dim sensors As New System.Collections.Generic.Dictionary(Of String, String)
        Try
            sensors.Add("ETS2.Gauge", "Full Gauge")

            sensors.Add("ETS2.Truck_Speed", "Truck Speed")
            sensors.Add("ETS2.Engine_RPM", "Engine RPM")
            sensors.Add("ETS2.RPM_At_Limit", "Engine RPM At limit (0/1)")
            sensors.Add("ETS2.Engine_Gear", "Current Gear")
            sensors.Add("ETS2.Parking_Brake", "Parking Brake (0/1)")
            sensors.Add("ETS2.Adblue_Amount", "Adblue Amount")
            sensors.Add("ETS2.Adblue_Avg_Consumption", "Adblue Average Consumption")
            sensors.Add("ETS2.Adblue_Warning", "Adblue Warning (0/1)")
            sensors.Add("ETS2.Battery_Voltage", "Battery Voltage")
            sensors.Add("ETS2.Battery_Voltage_Warning", "Battery Voltage Warning (0/1)")
            sensors.Add("ETS2.Brake_Air_Pressure", "Brake Air Pressure")
            sensors.Add("ETS2.Brake_Air_Pressure_Emergency", "Brake Air Pressure Emergency (0/1)")
            sensors.Add("ETS2.Brake_Air_Pressure_Warning", "Brake Air Pressure Warning (0/1)")
            sensors.Add("ETS2.Brake_Temperature", "Brake Temperature")
            sensors.Add("ETS2.Dashboard_Backlight", "Dasgboard Backlight")
            sensors.Add("ETS2.Electric_Enabled", "Electric Enabled (0/1)")
            sensors.Add("ETS2.Fuel_Amount", "Fuel Amount")
            sensors.Add("ETS2.Fuel_Avg_Consumption", "Fuel Average Consumption")
            sensors.Add("ETS2.Fuel_Warning", "Fuel Warning (0/1)")
            sensors.Add("ETS2.Left_Blinker", "Left Blinker Activated (0/1)")
            sensors.Add("ETS2.Left_Blinker_Light", "Left Blinker Light On (0/1)")
            sensors.Add("ETS2.Right_Blinker", "Right Blinker Activated (0/1)")
            sensors.Add("ETS2.Right_Blinker_Light", "Right Blinker Light On (0/1)")
            sensors.Add("ETS2.Light_Aux_Front", "Light Auxiliary Front (0/1)")
            sensors.Add("ETS2.Light_Aux_Roof", "Light Auxiliary Roof (0/1)")
            sensors.Add("ETS2.Light_Beacon", "Light Beacon (0/1)")
            sensors.Add("ETS2.Light_Brake", "Light Brake (0/1)")
            sensors.Add("ETS2.Light_High_Beam", "Light High Beam (0/1)")
            sensors.Add("ETS2.Light_Low_Beam", "Light Low Beam (0/1)")
            sensors.Add("ETS2.Light_Parking", "Light Parking (0/1)")
            sensors.Add("ETS2.Light_Reverse", "Light Reverse (0/1)")
            sensors.Add("ETS2.Motor_Brake", "Motor Brake (0/1)")
            sensors.Add("ETS2.Odometer", "Odometer")
            sensors.Add("ETS2.Oil_Pressure", "Oil Pressure")
            sensors.Add("ETS2.Oil_Pressure_Warning", "Oil Pressure Warning (0/1)")
            sensors.Add("ETS2.Oil_Temperature", "Oil Temperature")
            sensors.Add("ETS2.Water_Temperature", "Water Temperature")
            sensors.Add("ETS2.Water_Temperature_Warning", "Water Temperature Warning (0/1)")
            sensors.Add("ETS2.Wear_Cabin", "Wear Cabin")
            sensors.Add("ETS2.Wear_Chasis", "Wear Chasis")
            sensors.Add("ETS2.Wear_Engine", "Wear Engine")
            sensors.Add("ETS2.Wear_Transmission", "Wear Transmission")
            sensors.Add("ETS2.Wear_Wheels", "Wear Wheels")
            sensors.Add("ETS2.Wipers", "Wipers (0/1)")
            sensors.Add("ETS2.Adblue_Capacity", "Adblue Capacity (Max)")
            sensors.Add("ETS2.Air_Pressure_Emergency_Minimum", "Air Pressure Emergency Minimum")
            sensors.Add("ETS2.Air_Pressure_Warning_Minimum", "Air Pressure Warning Minimum")
            sensors.Add("ETS2.Battery_Voltage_Warning_Minimum", "Battery Voltage Warning Minimum")
            sensors.Add("ETS2.Fuel_Capacity", "Fuel Capacity (Max)")
            sensors.Add("ETS2.Fuel_Warning_Minimum", "Fuel Warning Minimum")
            sensors.Add("ETS2.Oil_Pressure_Warning_Minimum", "Oil Pressure Warning Minimum")
            sensors.Add("ETS2.RPM_Limit", "RPM Limit (Max)")
            sensors.Add("ETS2.Water_Temperature_Warning_Minimum", "Water Temperature Warning Minimum")

            Return sensors
        Catch ex As Exception
            objHost.DebugMessage("Error loading sensors:" & ex.Message & ": " & ex.StackTrace)
            Return sensors
        End Try
    End Function

    Function LCDSys2_AvailableSensors(pluginOptions As Hashtable) As System.Collections.Generic.Dictionary(Of String, String) Implements GOverlayPlugin.Interfaces.IPlugin.LCDSys2_AvailableSensors
        'Same sensors as lcd1
        Dim sensors As New System.Collections.Generic.Dictionary(Of String, String)
        sensors = AvailableSensors(pluginOptions)
        sensors.Add("ETS2.Gauge1", "Speed Gauge")
        Return sensors
    End Function

    Function ComboBoxes() As Hashtable Implements GOverlayPlugin.Interfaces.IPlugin.ComboBoxes
        'Create custom ComboBox for your configuration to use
        Dim boxes As New Hashtable
        Dim myboxOptions As New Hashtable
        'Set each one of the Combobox options as value, Display Name
        myboxOptions.Add(0, "Kmh")
        myboxOptions.Add(1, "Mph")

        boxes.Add("ETS2.ComboMetric", myboxOptions)
        Return boxes
    End Function

    Public Function SetDefaultOptions(sensorId As String, elementData As Hashtable) As Hashtable Implements GOverlayPlugin.Interfaces.IPlugin.SetDefaultOptions
        'Set the default values you want to have on your sensor when its created, if the user doesnt change any option, he will have this settings

        If sensorId = "ETS2.Gauge" Then
            elementData("width") = 320
            elementData("height") = 240
            elementData("maxfuel") = 600
            elementData("maxspeed") = 150
            elementData("maxtemp") = 120
            elementData("speedmetric") = 0
            elementData("maxrpm") = 0
        ElseIf sensorId = "ETS2.Gauge1" Then
            elementData("width") = 218
            elementData("height") = 187
            elementData("maxspeed") = 150
            elementData("speedmetric") = 0
        End If

        Return elementData
    End Function

    Public Function CreateOptions(sensorId As String, elementData As Hashtable) As Hashtable Implements GOverlayPlugin.Interfaces.IPlugin.CreateOptions
        'Set the options the user will have when clicking on the element
        'The available option_types are:
        'Text: Input text
        'Combo3: Combo with options (Enabled=0, Disabled=1)
        'Sensors: Combo with available sensors
        'ColorBasic: Combo with basic colors for the regular text font
        'ColorRGB: Combo with common RGB colors = 16bitinteger
        'ComboOnOff: Combo with options (Disabled=0, Enabled=1)
        'ComboYesNo: Combo with options (Yes=Yes, No=No)
        'TextSize: Combo with options (Extra Small=4, Very Small=5, Small=10, Normal=15, Big=20, Very Big=30, Extreme=40)
        'FontStyle2: Combo with options (Regular Font=0, Square Font=1, Numbers Font 1=2
        'Orientation: Combo with options (Horizontal=0, Vertical=1)
        'Here you can also load your custom comboboxes

        If sensorId = "ETS2.Gauge" Then
            Dim options As New Hashtable
            Dim x As Integer = 0
            options.Add(x, New ArrayList({"Text", "Max Speed", "maxspeed", "Write the max speed to calculate the gauge colors"})) : x = x + 1
            options.Add(x, New ArrayList({"ETS2.ComboMetric", "Speed Metric", "speedmetric", "Select the metric for the speed"})) : x = x + 1
            'options.Add(x, New ArrayList({"Text", "Fuel Tank", "maxfuel", "Write the fuel tank size to calculate the fuel gauge"})) : x = x + 1
            options.Add(x, New ArrayList({"Text", "Max Water Temperature", "maxtemp", "Write the maximum temperature to calculate the gauge"})) : x = x + 1
            options.Add(x, New ArrayList({"Text", "Manual Max RPM", "maxrpm", "Overwrite the game MAX RPM, zero to disable overwrite"})) : x = x + 1
            Return options
        ElseIf sensorId = "ETS2.Gauge1" Then
            Dim options As New Hashtable
            Dim x As Integer = 0
            options.Add(x, New ArrayList({"Text", "Max Speed", "maxspeed", "Write the max speed to calculate the gauge colors"})) : x = x + 1
            options.Add(x, New ArrayList({"ETS2.ComboMetric", "Speed Metric", "speedmetric", "Select the metric for the speed"})) : x = x + 1            
            Return options
        End If

        Return New Hashtable

    End Function

    Public Function LCDSys2_CreateOptions(sensorId As String, elementData As Hashtable) As Hashtable Implements GOverlayPlugin.Interfaces.IPlugin.LCDSys2_CreateOptions
        'Same options as lcd1
        Return CreateOptions(sensorId, elementData)
    End Function


    Public Function PluginOptionsDefault() As Hashtable Implements GOverlayPlugin.Interfaces.IPlugin.PluginOptionsDefault
        'Set the default values you want to have on plugin, if the user doesnt change any option, he will have this settings
        Dim options As New Hashtable
        options("reqimages") = "*.*.plugin_ets_*"
        Return options
    End Function
    Public Function PluginOptions(pluginCurrentOptions As Hashtable) As Hashtable Implements GOverlayPlugin.Interfaces.IPlugin.PluginOptions
        'Set the options the user will have when going to the plugins tab and clicking on your plugin
        'The availalbe option_type are teh same as CreateOptions function
        Dim options As New Hashtable
        'Option: option_index as integer, option_data as ArrayList
        'Option_Data: option_type as string, option_label as string, option_name as string (no spaces, no _)
        options.Add(0, New ArrayList({"TextMulti", "Images Match finder", "reqimages"}))
        options.Add(1, New ArrayList({"Button", "Upload Images", "reqimagesbutton"}))
        Return options
    End Function

    Structure ETSStructure

        Dim speed As Integer
        Dim rpm As Integer
        Dim rpm_at_limit As Integer
        Dim gear As Integer
        Dim parking_brake As Integer

        Dim adblue_amount As Double
        Dim adblue_average_consumption As Double
        Dim adblue_warning As Integer
        Dim battery_voltage As Double
        Dim battery_voltage_warning As Integer
        Dim brake_air_pressure As Double
        Dim brake_air_pressure_emergency As Integer
        Dim brake_air_pressure_warning As Integer
        Dim brake_temperature As Double
        Dim dashboard_backlight As Double
        Dim electric_enabled As Integer
        Dim engine_enabled As Integer
        Dim fuel_amount As Double
        Dim fuel_average_consumption As Double
        Dim fuel_warning As Integer
        Dim left_blinker As Integer
        Dim left_blinker_light As Integer
        Dim light_aux_front As Integer
        Dim light_aux_roof As Integer
        Dim light_beacon As Integer
        Dim light_brake As Integer
        Dim light_high_beam As Integer
        Dim light_low_beam As Integer
        Dim light_parking As Integer
        Dim light_reverse As Integer
        Dim motor_brake As Integer
        Dim odometer As Double
        Dim oil_pressure As Double
        Dim oil_pressure_warning As Integer
        Dim oil_temperature As Double
        Dim right_blinker As Integer
        Dim right_blinker_light As Integer
        Dim water_temperature As Integer
        Dim water_temperature_warning As Integer
        Dim wear_cabin As Double
        Dim wear_chassis As Double
        Dim wear_engine As Double
        Dim wear_transmission As Double
        Dim wear_wheels As Double
        Dim wipers As Integer

        Dim adblue_capacity As Double
        Dim air_pressure_emergency_minimum As Double
        Dim air_pressure_warning_minimum As Double
        Dim battery_voltage_warning_minimum As Double
        Dim fuel_capacity As Double
        Dim fuel_warning_minimum As Double
        Dim oil_pressure_warning_minimum As Double
        Dim rpm_limit As Integer
        Dim water_temperature_warning_minimum As Double

    End Structure

    Public Function GrabData(speedmetric As Integer) As Boolean
        Try
            ' Try to open the named file mapping.
            If hMapFile Is Nothing OrElse hMapFile.IsInvalid Then
                hMapFile = NativeMethod.OpenFileMapping(FileMapAccess.FILE_MAP_READ, False, FullMapName)
                objHost.DebugMessage("ETS2 - Connected to MapFile")
            End If

            If pView = IntPtr.Zero Then
                pView = NativeMethod.MapViewOfFile(hMapFile, FileMapAccess.FILE_MAP_READ, 0, ViewOffset, ViewSize)
                objHost.DebugMessage("ETS2 - pView Inited")
            End If

            If hMapFile Is Nothing Then Return False

            If (hMapFile.IsInvalid) Then Return False

            If (pView = IntPtr.Zero) Then Throw New Win32Exception


            Dim value As Integer = 0
            Dim arrSize As Integer = 259
            Dim data(arrSize - 1) As Byte
            Dim i As Integer
            For i = 0 To arrSize - 1
                data(i) = Marshal.ReadByte(New IntPtr(pView.ToInt32() + i))
            Next
            Dim s As Integer = 0
            Dim ss As Integer = 4
            If speedmetric = 0 Then
                'objHost.DebugMessage(BitConverter.ToSingle({data(s), data(s + 1), data(s + 2), data(s + 3)}, 0) & " -> " & (BitConverter.ToSingle({data(s), data(s + 1), data(s + 2), data(s + 3)}, 0) * 3600 / 1000))
                rdata.speed = BitConverter.ToSingle({data(s), data(s + 1), data(s + 2), data(s + 3)}, 0) * 3600 / 1000 'M/S to KM/H
            Else
                rdata.speed = (BitConverter.ToSingle({data(s), data(s + 1), data(s + 2), data(s + 3)}, 0) * 3600 / 1000) * 0.621371192237334 'M/S to MP/H
            End If

            s = s + ss : rdata.rpm = BitConverter.ToSingle({data(s), data(s + 1), data(s + 2), data(s + 3)}, 0)
            s = s + ss : rdata.gear = BitConverter.ToSingle({data(s), data(s + 1), data(s + 2), data(s + 3)}, 0)
            s = s + ss : rdata.parking_brake = BitConverter.ToSingle({data(s), data(s + 1), data(s + 2), data(s + 3)}, 0)
            s = s + ss : rdata.adblue_amount = BitConverter.ToSingle({data(s), data(s + 1), data(s + 2), data(s + 3)}, 0)
            s = s + ss : rdata.adblue_average_consumption = BitConverter.ToSingle({data(s), data(s + 1), data(s + 2), data(s + 3)}, 0)
            s = s + ss : rdata.adblue_warning = BitConverter.ToSingle({data(s), data(s + 1), data(s + 2), data(s + 3)}, 0)
            s = s + ss : rdata.battery_voltage = BitConverter.ToSingle({data(s), data(s + 1), data(s + 2), data(s + 3)}, 0)
            s = s + ss : rdata.battery_voltage_warning = BitConverter.ToSingle({data(s), data(s + 1), data(s + 2), data(s + 3)}, 0)
            s = s + ss : rdata.brake_air_pressure = BitConverter.ToSingle({data(s), data(s + 1), data(s + 2), data(s + 3)}, 0)
            s = s + ss : rdata.brake_air_pressure_emergency = BitConverter.ToSingle({data(s), data(s + 1), data(s + 2), data(s + 3)}, 0)
            s = s + ss : rdata.brake_air_pressure_warning = BitConverter.ToSingle({data(s), data(s + 1), data(s + 2), data(s + 3)}, 0)
            s = s + ss : rdata.brake_temperature = BitConverter.ToSingle({data(s), data(s + 1), data(s + 2), data(s + 3)}, 0)
            s = s + ss : rdata.dashboard_backlight = BitConverter.ToSingle({data(s), data(s + 1), data(s + 2), data(s + 3)}, 0)
            s = s + ss : rdata.electric_enabled = BitConverter.ToSingle({data(s), data(s + 1), data(s + 2), data(s + 3)}, 0)
            s = s + ss : rdata.engine_enabled = BitConverter.ToSingle({data(s), data(s + 1), data(s + 2), data(s + 3)}, 0)
            s = s + ss : rdata.fuel_amount = Math.Round(BitConverter.ToSingle({data(s), data(s + 1), data(s + 2), data(s + 3)}, 0), 2)
            s = s + ss : rdata.fuel_average_consumption = BitConverter.ToSingle({data(s), data(s + 1), data(s + 2), data(s + 3)}, 0)
            s = s + ss : rdata.fuel_warning = BitConverter.ToSingle({data(s), data(s + 1), data(s + 2), data(s + 3)}, 0)
            s = s + ss : rdata.left_blinker = BitConverter.ToSingle({data(s), data(s + 1), data(s + 2), data(s + 3)}, 0)
            s = s + ss : rdata.left_blinker_light = BitConverter.ToSingle({data(s), data(s + 1), data(s + 2), data(s + 3)}, 0)
            s = s + ss : rdata.light_aux_front = BitConverter.ToSingle({data(s), data(s + 1), data(s + 2), data(s + 3)}, 0)
            s = s + ss : rdata.light_aux_roof = BitConverter.ToSingle({data(s), data(s + 1), data(s + 2), data(s + 3)}, 0)
            s = s + ss : rdata.light_beacon = BitConverter.ToSingle({data(s), data(s + 1), data(s + 2), data(s + 3)}, 0)
            s = s + ss : rdata.light_brake = BitConverter.ToSingle({data(s), data(s + 1), data(s + 2), data(s + 3)}, 0)
            s = s + ss : rdata.light_high_beam = BitConverter.ToSingle({data(s), data(s + 1), data(s + 2), data(s + 3)}, 0)
            s = s + ss : rdata.light_low_beam = BitConverter.ToSingle({data(s), data(s + 1), data(s + 2), data(s + 3)}, 0)
            s = s + ss : rdata.light_parking = BitConverter.ToSingle({data(s), data(s + 1), data(s + 2), data(s + 3)}, 0)
            s = s + ss : rdata.light_reverse = BitConverter.ToSingle({data(s), data(s + 1), data(s + 2), data(s + 3)}, 0)
            s = s + ss : rdata.motor_brake = BitConverter.ToSingle({data(s), data(s + 1), data(s + 2), data(s + 3)}, 0)
            s = s + ss : rdata.odometer = BitConverter.ToSingle({data(s), data(s + 1), data(s + 2), data(s + 3)}, 0)
            s = s + ss : rdata.oil_pressure = BitConverter.ToSingle({data(s), data(s + 1), data(s + 2), data(s + 3)}, 0)
            s = s + ss : rdata.oil_pressure_warning = BitConverter.ToSingle({data(s), data(s + 1), data(s + 2), data(s + 3)}, 0)
            s = s + ss : rdata.oil_temperature = BitConverter.ToSingle({data(s), data(s + 1), data(s + 2), data(s + 3)}, 0)
            s = s + ss : rdata.right_blinker = BitConverter.ToSingle({data(s), data(s + 1), data(s + 2), data(s + 3)}, 0)
            s = s + ss : rdata.right_blinker_light = BitConverter.ToSingle({data(s), data(s + 1), data(s + 2), data(s + 3)}, 0)
            s = s + ss : rdata.water_temperature = BitConverter.ToSingle({data(s), data(s + 1), data(s + 2), data(s + 3)}, 0)
            s = s + ss : rdata.water_temperature_warning = BitConverter.ToSingle({data(s), data(s + 1), data(s + 2), data(s + 3)}, 0)
            s = s + ss : rdata.wear_cabin = Math.Round(BitConverter.ToSingle({data(s), data(s + 1), data(s + 2), data(s + 3)}, 0) * 100, 1)
            s = s + ss : rdata.wear_chassis = Math.Round(BitConverter.ToSingle({data(s), data(s + 1), data(s + 2), data(s + 3)}, 0) * 100, 1)
            s = s + ss : rdata.wear_engine = Math.Round(BitConverter.ToSingle({data(s), data(s + 1), data(s + 2), data(s + 3)}, 0) * 100, 1)
            s = s + ss : rdata.wear_transmission = Math.Round(BitConverter.ToSingle({data(s), data(s + 1), data(s + 2), data(s + 3)}, 0) * 100, 1)
            s = s + ss : rdata.wear_wheels = Math.Round(BitConverter.ToSingle({data(s), data(s + 1), data(s + 2), data(s + 3)}, 0) * 100, 1)
            s = s + ss : rdata.wipers = BitConverter.ToSingle({data(s), data(s + 1), data(s + 2), data(s + 3)}, 0)
            s = s + ss : rdata.adblue_capacity = BitConverter.ToSingle({data(s), data(s + 1), data(s + 2), data(s + 3)}, 0)
            s = s + ss : rdata.air_pressure_emergency_minimum = BitConverter.ToSingle({data(s), data(s + 1), data(s + 2), data(s + 3)}, 0)
            s = s + ss : rdata.air_pressure_warning_minimum = BitConverter.ToSingle({data(s), data(s + 1), data(s + 2), data(s + 3)}, 0)
            s = s + ss : rdata.battery_voltage_warning_minimum = BitConverter.ToSingle({data(s), data(s + 1), data(s + 2), data(s + 3)}, 0)
            s = s + ss : rdata.fuel_capacity = BitConverter.ToSingle({data(s), data(s + 1), data(s + 2), data(s + 3)}, 0)
            s = s + ss : rdata.fuel_warning_minimum = BitConverter.ToSingle({data(s), data(s + 1), data(s + 2), data(s + 3)}, 0)
            s = s + ss : rdata.oil_pressure_warning_minimum = BitConverter.ToSingle({data(s), data(s + 1), data(s + 2), data(s + 3)}, 0)
            s = s + ss : rdata.rpm_limit = BitConverter.ToSingle({data(s), data(s + 1), data(s + 2), data(s + 3)}, 0)
            s = s + ss : rdata.water_temperature_warning_minimum = BitConverter.ToSingle({data(s), data(s + 1), data(s + 2), data(s + 3)}, 0)

            If rdata.rpm >= rdata.rpm_limit - 200 Then
                rdata.rpm_at_limit = 1
            Else
                rdata.rpm_at_limit = 0
            End If

            Return True
        Catch ex As Exception
            Return False
        End Try
    End Function
    Public Function DisplayOnLCD(sensorId As String, elementData As Hashtable, pluginOptions As Hashtable, cacheRuns As Integer) As ArrayList Implements GOverlayPlugin.Interfaces.IPlugin.DisplayOnLCD

        Dim x As Integer = CInt(elementData("x"))    'grab X position of the element
        Dim y As Integer = CInt(elementData("y"))    'grab Y position of the element

        Dim commandList2 As New ArrayList()

        Try
            Dim value As Integer = 0

            'If it fails, dont output anything
            If GrabData(elementData("speedmetric")) = False Then
                'Return commandList2
            End If

            Try

                If sensorId = "ETS2.Gauge" Then
                    Dim inited = objHost.AccessHost("retrieve", "GLOBAL_GeneralVars", "lcdsys_windows_inited", "")
                    If inited <> 1 Then
                        objHost.DebugMessage("ETS2 - init Full Gauge")
                        commandList2.Add(New ArrayList({"image", x, y, 310}))
                        commandList2.Add(New ArrayList({"wait", 1150}))
                        commandList2.Add(New ArrayList({"image", x + 17, y + 201, 370}))
                        commandList2.Add(New ArrayList({"wait", 100}))
                        'Reset our internal cache
                        LastCache = New System.Collections.Hashtable
                    End If

                    If (Not LastCache.ContainsKey("right_blinker_light")) Then LastCache("right_blinker_light") = 9999
                    If (Not LastCache.ContainsKey("left_blinker_light")) Then LastCache("left_blinker_light") = 9999
                    If (Not LastCache.ContainsKey("light_low_beam")) Then LastCache("light_low_beam") = 9999
                    If (Not LastCache.ContainsKey("light_high_beam")) Then LastCache("light_high_beam") = 9999
                    If (Not LastCache.ContainsKey("parking_brake")) Then LastCache("parking_brake") = 9999
                    If (Not LastCache.ContainsKey("wipers")) Then LastCache("wipers") = 9999


                    Dim images As Integer = 19
                    Dim maxspeed As Integer = elementData("maxspeed")
                    Dim steps As Integer = maxspeed / images
                    Dim color_grey As Integer = 354
                    Dim color_green As Integer = 355
                    Dim color_red As Integer = 356
                    Dim color_yellow As Integer = 357
                    Dim use_color As Integer = color_grey

                    Dim offsetX1 As Integer = -9
                    Dim offsetX2 As Integer = -28

                    If rdata.speed < 0 Then rdata.speed = rdata.speed * -1

                    If steps * 1 < rdata.speed Then use_color = color_green Else use_color = color_grey
                    If Not LastCache.ContainsKey("s1") OrElse LastCache("s1") <> use_color Then commandList2.Add(New ArrayList({"image", x + 54, y + 142, use_color}))
                    LastCache("s1") = use_color
                    If steps * 2 < rdata.speed Then use_color = color_green Else use_color = color_grey
                    If Not LastCache.ContainsKey("s2") OrElse LastCache("s2") <> use_color Then commandList2.Add(New ArrayList({"image", x + 43, y + 128, use_color}))
                    LastCache("s2") = use_color
                    If steps * 3 < rdata.speed Then use_color = color_green Else use_color = color_grey
                    If Not LastCache.ContainsKey("s3") OrElse LastCache("s3") <> use_color Then commandList2.Add(New ArrayList({"image", x + 37, y + 111, use_color}))
                    LastCache("s3") = use_color
                    If steps * 4 < rdata.speed Then use_color = color_green Else use_color = color_grey
                    If Not LastCache.ContainsKey("s4") OrElse LastCache("s4") <> use_color Then commandList2.Add(New ArrayList({"image", x + 33, y + 93, use_color}))
                    LastCache("s4") = use_color
                    If steps * 5 < rdata.speed Then use_color = color_green Else use_color = color_grey
                    If Not LastCache.ContainsKey("s5") OrElse LastCache("s5") <> use_color Then commandList2.Add(New ArrayList({"image", x + 37, y + 74, use_color}))
                    LastCache("s5") = use_color
                    If steps * 6 < rdata.speed Then use_color = color_green Else use_color = color_grey
                    If Not LastCache.ContainsKey("s6") OrElse LastCache("s6") <> use_color Then commandList2.Add(New ArrayList({"image", x + 47, y + 59, use_color}))
                    LastCache("s6") = use_color
                    If steps * 7 < rdata.speed Then use_color = color_green Else use_color = color_grey
                    If Not LastCache.ContainsKey("s7") OrElse LastCache("s7") <> use_color Then commandList2.Add(New ArrayList({"image", x + 58, y + 45, use_color}))
                    LastCache("s7") = use_color
                    If steps * 8 < rdata.speed Then use_color = color_green Else use_color = color_grey
                    If Not LastCache.ContainsKey("s8") OrElse LastCache("s8") <> use_color Then commandList2.Add(New ArrayList({"image", x + 73, y + 35, use_color}))
                    LastCache("s8") = use_color
                    If steps * 9 < rdata.speed Then use_color = color_green Else use_color = color_grey
                    If Not LastCache.ContainsKey("s9") OrElse LastCache("s9") <> use_color Then commandList2.Add(New ArrayList({"image", x + 90, y + 28, use_color}))
                    LastCache("s9") = use_color
                    If steps * 10 < rdata.speed Then use_color = color_green Else use_color = color_grey
                    If Not LastCache.ContainsKey("s10") OrElse LastCache("s10") <> use_color Then commandList2.Add(New ArrayList({"image", x + 107, y + 28, use_color}))
                    LastCache("s10") = use_color

                    If steps * 11 < rdata.speed Then use_color = color_yellow Else use_color = color_grey
                    If Not LastCache.ContainsKey("s11") OrElse LastCache("s11") <> use_color Then commandList2.Add(New ArrayList({"image", x + 126, y + 35, use_color}))
                    LastCache("s11") = use_color
                    If steps * 12 < rdata.speed Then use_color = color_yellow Else use_color = color_grey
                    If Not LastCache.ContainsKey("s12") OrElse LastCache("s12") <> use_color Then commandList2.Add(New ArrayList({"image", x + 142, y + 45, use_color}))
                    LastCache("s12") = use_color
                    If steps * 13 < rdata.speed Then use_color = color_yellow Else use_color = color_grey
                    If Not LastCache.ContainsKey("s13") OrElse LastCache("s13") <> use_color Then commandList2.Add(New ArrayList({"image", x + 154, y + 59, use_color}))
                    LastCache("s13") = use_color
                    If steps * 14 < rdata.speed Then use_color = color_yellow Else use_color = color_grey
                    If Not LastCache.ContainsKey("s14") OrElse LastCache("s14") <> use_color Then commandList2.Add(New ArrayList({"image", x + 163, y + 74, use_color}))
                    LastCache("s14") = use_color
                    If steps * 15 < rdata.speed Then use_color = color_yellow Else use_color = color_grey
                    If Not LastCache.ContainsKey("s15") OrElse LastCache("s15") <> use_color Then commandList2.Add(New ArrayList({"image", x + 168, y + 93, use_color}))
                    LastCache("s15") = use_color
                    If steps * 16 < rdata.speed Then use_color = color_red Else use_color = color_grey
                    If Not LastCache.ContainsKey("s16") OrElse LastCache("s16") <> use_color Then commandList2.Add(New ArrayList({"image", x + 164, y + 111, use_color}))
                    LastCache("s16") = use_color
                    If steps * 17 < rdata.speed Then use_color = color_red Else use_color = color_grey
                    If Not LastCache.ContainsKey("s17") OrElse LastCache("s17") <> use_color Then commandList2.Add(New ArrayList({"image", x + 158, y + 128, use_color}))
                    LastCache("s17") = use_color
                    If steps * 18 < rdata.speed Then use_color = color_red Else use_color = color_grey
                    If Not LastCache.ContainsKey("s18") OrElse LastCache("s18") <> use_color Then commandList2.Add(New ArrayList({"image", x + 148, y + 142, use_color}))
                    LastCache("s18") = use_color
                    'If steps * 19 < rdata.speed Then use_color = color_red Else use_color = color_grey
                    'If Not LastCache.ContainsKey("s19") OrElse LastCache("s19") <> use_color Then commandList2.Add(New ArrayList({"image", x + 116 + offsetX1, y + 112 + offsetX2, use_color}))
                    'LastCache("s19") = use_color


                    commandList2 = createNeedle(commandList2, 53, 2.5, rdata.speed, maxspeed, x + 106, y + 103, "speed", 145, 0.25)


                    offsetX1 = 38
                    offsetX2 = 50
                    Dim rpm_max As Integer = rdata.rpm_limit
                    If elementData("maxrpm") > 0 Then
                        rpm_max = CInt(elementData("maxrpm"))
                    End If
                    'objHost.DebugMessage("rpm limit: " & rdata.rpm_limit)

                    commandList2 = createNeedle(commandList2, 30, 1.5, rdata.rpm, rpm_max, x + 128 + 93 + offsetX1, y + 88 + offsetX2, "rpm", 145, 0.25)


                    Dim val, needleLen As Integer, needleRadius As Integer
                    needleLen = 30
                    needleRadius = 1.5
                    val = ((rdata.speed * 145 / maxspeed) * 0.01) - 0.25
                   
                    offsetX1 = 40
                    offsetX2 = 49
                    steps = rpm_max / images
                    Dim offsetx As Integer = 128
                    color_grey = 350
                    color_green = 351
                    color_red = 352
                    color_yellow = 353
                    use_color = color_grey

                    If steps * 1 < rdata.rpm Then use_color = color_green Else use_color = color_grey
                    If Not LastCache.ContainsKey("r1") OrElse LastCache("r1") <> use_color Then commandList2.Add(New ArrayList({"image", offsetx + x + 63 + offsetX1, y + 112 + offsetX2, use_color}))
                    LastCache("r1") = use_color
                    If steps * 2 < rdata.rpm Then use_color = color_green Else use_color = color_grey
                    If Not LastCache.ContainsKey("r2") OrElse LastCache("r2") <> use_color Then commandList2.Add(New ArrayList({"image", offsetx + x + 57 + offsetX1, y + 104 + offsetX2, use_color}))
                    LastCache("r2") = use_color
                    If steps * 3 < rdata.rpm Then use_color = color_green Else use_color = color_grey
                    If Not LastCache.ContainsKey("r3") OrElse LastCache("r3") <> use_color Then commandList2.Add(New ArrayList({"image", offsetx + x + 52 + offsetX1, y + 94 + offsetX2, use_color}))
                    LastCache("r3") = use_color
                    If steps * 4 < rdata.rpm Then use_color = color_green Else use_color = color_grey
                    If Not LastCache.ContainsKey("r4") OrElse LastCache("r4") <> use_color Then commandList2.Add(New ArrayList({"image", offsetx + x + 50 + offsetX1, y + 84 + offsetX2, use_color}))
                    LastCache("r4") = use_color
                    If steps * 5 < rdata.rpm Then use_color = color_green Else use_color = color_grey
                    If Not LastCache.ContainsKey("r5") OrElse LastCache("r5") <> use_color Then commandList2.Add(New ArrayList({"image", offsetx + x + 53 + offsetX1, y + 73 + offsetX2, use_color}))
                    LastCache("r5") = use_color
                    If steps * 6 < rdata.rpm Then use_color = color_green Else use_color = color_grey
                    If Not LastCache.ContainsKey("r6") OrElse LastCache("r6") <> use_color Then commandList2.Add(New ArrayList({"image", offsetx + x + 58 + offsetX1, y + 64 + offsetX2, use_color}))
                    LastCache("r6") = use_color
                    If steps * 7 < rdata.rpm Then use_color = color_green Else use_color = color_grey
                    If Not LastCache.ContainsKey("r7") OrElse LastCache("r7") <> use_color Then commandList2.Add(New ArrayList({"image", offsetx + x + 64 + offsetX1, y + 56 + offsetX2, use_color}))
                    LastCache("r7") = use_color
                    If steps * 8 < rdata.rpm Then use_color = color_green Else use_color = color_grey
                    If Not LastCache.ContainsKey("r8") OrElse LastCache("r8") <> use_color Then commandList2.Add(New ArrayList({"image", offsetx + x + 73 + offsetX1, y + 50 + offsetX2, use_color}))
                    LastCache("r8") = use_color
                    If steps * 9 < rdata.rpm Then use_color = color_green Else use_color = color_grey
                    If Not LastCache.ContainsKey("r9") OrElse LastCache("r9") <> use_color Then commandList2.Add(New ArrayList({"image", offsetx + x + 83 + offsetX1, y + 46 + offsetX2, use_color}))
                    LastCache("r9") = use_color
                    If steps * 10 < rdata.rpm Then use_color = color_green Else use_color = color_grey
                    If Not LastCache.ContainsKey("r10") OrElse LastCache("r10") <> use_color Then commandList2.Add(New ArrayList({"image", offsetx + x + 93 + offsetX1, y + 46 + offsetX2, use_color}))
                    LastCache("r10") = use_color

                    If steps * 11 < rdata.rpm Then use_color = color_yellow Else use_color = color_grey
                    If Not LastCache.ContainsKey("r11") OrElse LastCache("r11") <> use_color Then commandList2.Add(New ArrayList({"image", offsetx + x + 104 + offsetX1, y + 50 + offsetX2, use_color}))
                    LastCache("r1") = use_color
                    If steps * 12 < rdata.rpm Then use_color = color_yellow Else use_color = color_grey
                    If Not LastCache.ContainsKey("r12") OrElse LastCache("r12") <> use_color Then commandList2.Add(New ArrayList({"image", offsetx + x + 113 + offsetX1, y + 56 + offsetX2, use_color}))
                    LastCache("r12") = use_color
                    If steps * 13 < rdata.rpm Then use_color = color_yellow Else use_color = color_grey
                    If Not LastCache.ContainsKey("r13") OrElse LastCache("r13") <> use_color Then commandList2.Add(New ArrayList({"image", offsetx + x + 113 + offsetX1, y + 56 + offsetX2, use_color}))
                    LastCache("r13") = use_color
                    If steps * 14 < rdata.rpm Then use_color = color_yellow Else use_color = color_grey
                    If Not LastCache.ContainsKey("r14") OrElse LastCache("r14") <> use_color Then commandList2.Add(New ArrayList({"image", offsetx + x + 120 + offsetX1, y + 64 + offsetX2, use_color}))
                    LastCache("r14") = use_color
                    If steps * 15 < rdata.rpm Then use_color = color_yellow Else use_color = color_grey
                    If Not LastCache.ContainsKey("r15") OrElse LastCache("r15") <> use_color Then commandList2.Add(New ArrayList({"image", offsetx + x + 125 + offsetX1, y + 73 + offsetX2, use_color}))
                    LastCache("r15") = use_color
                    If steps * 16 < rdata.rpm Then use_color = color_red Else use_color = color_grey
                    If Not LastCache.ContainsKey("r16") OrElse LastCache("r16") <> use_color Then commandList2.Add(New ArrayList({"image", offsetx + x + 128 + offsetX1, y + 84 + offsetX2, use_color}))
                    LastCache("r16") = use_color
                    If steps * 17 < rdata.rpm Then use_color = color_red Else use_color = color_grey
                    If Not LastCache.ContainsKey("r17") OrElse LastCache("r17") <> use_color Then commandList2.Add(New ArrayList({"image", offsetx + x + 126 + offsetX1, y + 94 + offsetX2, use_color}))
                    LastCache("r17") = use_color
                    If steps * 18 < rdata.rpm Then use_color = color_red Else use_color = color_grey
                    If Not LastCache.ContainsKey("r18") OrElse LastCache("r18") <> use_color Then commandList2.Add(New ArrayList({"image", offsetx + x + 122 + offsetX1, y + 104 + offsetX2, use_color}))
                    LastCache("r18") = use_color
                    If steps * 19 < rdata.rpm Then use_color = color_red Else use_color = color_grey
                    If Not LastCache.ContainsKey("r19") OrElse LastCache("r19") <> use_color Then commandList2.Add(New ArrayList({"image", offsetx + x + 116 + offsetX1, y + 112 + offsetX2, use_color}))
                    LastCache("r19") = use_color


                    'GEAR 

                    Dim rect_x As Integer = 243
                    Dim rect_y As Integer = 150
                    Dim rect_y2 As Integer = rect_y + 37
                    Dim rect_x2 As Integer = rect_x + 35
                    Dim text_y As Integer = rect_y - 1
                    Dim text_x As Integer = rect_x + 9

                    'objHost.DebugMessage(rdata.gear)

                    If rdata.gear = 0 OrElse rdata.gear = "0" Then
                        commandList2.Add(New ArrayList({"draw_rectangle", rect_x, rect_y, rect_x2, rect_y2, 1, convertcolorto16bit(0, 0, 0)}))
                        commandList2.Add(New ArrayList({"text", text_x, text_y, "N", 0, False, False, 0, 0}))
                    Else
                        If rdata.gear.ToString.Length = 1 Then
                            If LastCache.ContainsKey("last_gear") AndAlso LastCache("last_gear") > 9 Then
                                'clear gear red box if exists
                                commandList2.Add(New ArrayList({"fill_rectangle", rect_x - 4, rect_y, rect_x2 + 4, rect_y2, convertcolorto16bit(0, 0, 0)}))
                            End If


                            If steps * 16 < rdata.rpm Then
                                commandList2.Add(New ArrayList({"draw_rectangle", rect_x, rect_y, rect_x2, rect_y2, 1, convertcolorto16bit(253, 23, 36)}))
                                commandList2.Add(New ArrayList({"text", text_x, text_y, rdata.gear.ToString, 0, False, False, 0, 3}))
                            Else
                                commandList2.Add(New ArrayList({"draw_rectangle", rect_x, rect_y, rect_x2, rect_y2, 1, convertcolorto16bit(0, 0, 0)}))
                                commandList2.Add(New ArrayList({"text", text_x, text_y, rdata.gear.ToString, 0, False, False, 0, 0}))
                            End If


                        ElseIf rdata.gear.ToString.Length = 2 Then
                            If LastCache.ContainsKey("last_gear") AndAlso LastCache("last_gear") < 9 AndAlso LastCache("last_gear") >= 0 Then
                                'clear gear red box if exists
                                commandList2.Add(New ArrayList({"fill_rectangle", rect_x, rect_y, rect_x2, rect_y2, convertcolorto16bit(0, 0, 0)}))
                            End If

                            If rdata.gear < 0 Then
                                commandList2.Add(New ArrayList({"draw_rectangle", rect_x, rect_y, rect_x2, rect_y2, 1, convertcolorto16bit(0, 0, 0)}))
                                commandList2.Add(New ArrayList({"text", text_x, text_y, "R", 0, False, False, 0, 0}))
                            Else
                                If steps * 16 < rdata.rpm Then
                                    commandList2.Add(New ArrayList({"draw_rectangle", rect_x - 4, rect_y, rect_x2 + 4, rect_y2, 1, convertcolorto16bit(253, 23, 36)}))
                                    commandList2.Add(New ArrayList({"text", text_x - 8, text_y, rdata.gear.ToString, 0, False, False, 0, 3}))
                                Else
                                    commandList2.Add(New ArrayList({"draw_rectangle", rect_x - 4, rect_y, rect_x2 + 4, rect_y2, 1, convertcolorto16bit(0, 0, 0)}))
                                    commandList2.Add(New ArrayList({"text", text_x - 8, text_y, rdata.gear.ToString, 0, False, False, 0, 0}))
                                End If
                            End If
                        Else

                            commandList2.Add(New ArrayList({"draw_rectangle", rect_x, rect_y, rect_x2, rect_y2, 1, convertcolorto16bit(0, 0, 0)}))
                            commandList2.Add(New ArrayList({"text", text_x, text_y, "R", 0, False, False, 0, 0}))
                            End If

                            LastCache("last_gear") = rdata.gear
                    End If

                    Dim max_temp As Integer = elementData("maxtemp")




                    'Dim fuel_color_in = convertcolorto16bit(78, 141, 163)
                    'Dim fuel_color_out = convertcolorto16bit(254, 254, 254)
                    Dim fuel_color_out As Integer = convertcolorto16bit(254, 254, 254)
                    Dim fuel_color_in As Integer = convertcolorto16bit(253, 23, 36)
                    Dim rect_xstep As Integer = 7
                    Dim rect_ystep As Integer = 8
                    steps = max_temp / 8
                    rect_x = 286
                    rect_y = 138
                    rect_x2 = rect_x + rect_xstep
                    rect_y2 = rect_y + rect_ystep

                    ' objHost.DebugMessage("Fuel: " & rdata.ActualFuelLiters)
                    ' objHost.DebugMessage("temp: " & rdata.ActualEngineOilTemp)

                    'FUEL
                    Dim max_fuel As Integer = rdata.fuel_capacity
                    commandList2 = createNeedle(commandList2, 15, 0, rdata.fuel_amount, max_fuel, x + 215, y + 25, "fuel", 135, 0)
                    'commandList2 = createNeedle(commandList2, 15, 0, 0, max_fuel, x + 137, y + 24, "fuel", 135, 0)
                    'commandList2 = createNeedle(commandList2, 15, 0, max_fuel, max_fuel, x + 137, y + 24, "fuel2", 135, 0)

                    Dim ftext = rdata.fuel_amount
                    If rdata.fuel_amount >= 100 Then ftext = Math.Round(rdata.fuel_amount, 0) Else ftext = rdata.fuel_amount

                    If (Not LastCache.ContainsKey("fuel_val")) OrElse LastCache("fuel_val") <> ftext Then
                        Dim xpos = 234
                        Dim ypos = 7
                        If LastCache.ContainsKey("fuel_val") Then
                            commandList2.Add(New ArrayList({"text_square", LastCache("fuel_val").ToString & "L", xpos, ypos, 3, 3 * 2, 3, 0}))
                        End If
                        commandList2.Add(New ArrayList({"text_square", ftext.ToString & "L", xpos, ypos, 3, 3 * 2, 3, 65535}))
                        LastCache("fuel_val") = ftext
                    End If


                    'TEMP
                    commandList2 = createNeedle(commandList2, 15, 0, rdata.water_temperature, elementData("maxtemp"), x + 273, y + 61, "water_temp", 125, 0.28)

                    If (Not LastCache.ContainsKey("temp_val")) OrElse LastCache("temp_val") <> rdata.water_temperature Then
                        Dim xpos = 296
                        Dim ypos = 46
                        If LastCache.ContainsKey("temp_val") Then
                            commandList2.Add(New ArrayList({"text_square", LastCache("temp_val").ToString & "C", xpos, ypos, 3, 3 * 2, 3, 0}))
                        End If
                        commandList2.Add(New ArrayList({"text_square", rdata.water_temperature.ToString & "C", xpos, ypos, 3, 3 * 2, 3, 65535}))
                        LastCache("temp_val") = rdata.water_temperature
                    End If

                    'BAT

                    ftext = Math.Round(rdata.battery_voltage, 0)
                    'battery is always going from 23 to 24, so lets stick with 24
                    If ftext = 23 Then ftext = 24

                    If (Not LastCache.ContainsKey("bat_val")) OrElse LastCache("bat_val") <> ftext Then
                        Dim xpos As Integer = 284
                        Dim ypos As Integer = 26
                        If LastCache.ContainsKey("bat_val") Then
                            commandList2.Add(New ArrayList({"text_square", LastCache("bat_val").ToString & "V", xpos, ypos, 3, 3 * 2, 3, 0}))
                        End If
                        commandList2.Add(New ArrayList({"text_square", ftext.ToString & "V", xpos, ypos, 3, 3 * 2, 3, 65504}))
                        LastCache("bat_val") = ftext
                    End If

                    'commandList2 = createNeedle(commandList2, 15, 0, 0, 90, x + 186, y + 24, "water_temp", 125, 0.28)
                    'commandList2 = createNeedle(commandList2, 15, 0, 90, 90, x + 186, y + 24, "water_temp2", 125, 0.28)


                    If rdata.right_blinker_light + rdata.left_blinker_light = 0 Or rdata.right_blinker_light + rdata.left_blinker_light = 2 Then
                        If rdata.right_blinker_light + rdata.left_blinker_light = 0 Then
                            'commandList2.Add(New ArrayList({"image", x + 150, y + 91, 350}))
                        Else
                            'commandList2.Add(New ArrayList({"image", x + 150, y + 91, 349}))
                        End If
                    End If

                    If LastCache("right_blinker_light") <> rdata.right_blinker_light Then
                        If rdata.right_blinker_light = 1 Then
                            commandList2.Add(New ArrayList({"image", x + 280, y + 188, 361}))
                        Else
                            commandList2.Add(New ArrayList({"image", x + 280, y + 188, 360}))
                        End If
                    End If

                    If LastCache("left_blinker_light") <> rdata.left_blinker_light Then
                        If rdata.left_blinker_light = 1 Then
                            commandList2.Add(New ArrayList({"image", x + 212, y + 188, 363}))
                        Else
                            commandList2.Add(New ArrayList({"image", x + 212, y + 188, 362}))
                        End If
                    End If


                    If LastCache("light_low_beam") <> rdata.light_low_beam Or LastCache("light_high_beam") <> rdata.light_high_beam Then
                        If rdata.light_low_beam = 1 Or rdata.light_high_beam = 1 Then
                            commandList2.Add(New ArrayList({"image", x + 195, y + 212, 365}))
                        Else
                            commandList2.Add(New ArrayList({"image", x + 195, y + 212, 364}))
                        End If
                    End If

                    If LastCache("parking_brake") <> rdata.parking_brake Then
                        If rdata.parking_brake = 1 Then
                            commandList2.Add(New ArrayList({"image", x + 237, y + 212, 367}))
                        Else
                            commandList2.Add(New ArrayList({"image", x + 237, y + 212, 366}))
                        End If
                    End If

                    If LastCache("wipers") <> rdata.wipers Then
                        If rdata.wipers = 1 Then
                            commandList2.Add(New ArrayList({"image", x + 280, y + 212, 369}))
                        Else
                            commandList2.Add(New ArrayList({"image", x + 280, y + 212, 368}))
                        End If
                    End If

                    LastCache("wipers") = rdata.wipers
                    LastCache("parking_brake") = rdata.parking_brake
                    LastCache("light_low_beam") = rdata.light_low_beam
                    LastCache("light_high_beam") = rdata.light_high_beam
                    LastCache("left_blinker_light") = rdata.left_blinker_light
                    LastCache("right_blinker_light") = rdata.right_blinker_light

                    'WEAR
                    Dim xpos2 As Integer = 13
                    Dim ypos2 As Integer = 200

                    Dim colorbgtrailer As Integer = 65535
                    Dim valueW As Integer = 0

                    valueW = Math.Round((100 - rdata.wear_engine), 1)
                    If (Not LastCache.ContainsKey("wear_engine") OrElse LastCache("wear_engine") <> valueW) Then
                        If (LastCache.ContainsKey("wear_engine")) Then
                            commandList2.Add(New ArrayList({"text_square", "" & LastCache("wear_engine") & "%", xpos2 + 55, ypos2 + 6, 3, 3 * 2, 3, colorbgtrailer}))
                        End If
                        commandList2.Add(New ArrayList({"text_square", "" & valueW & "%", xpos2 + 55, ypos2 + 6, 3, 3 * 2, 3, 0}))
                        LastCache("wear_engine") = valueW
                    End If

                    valueW = Math.Round((100 - rdata.wear_wheels), 1)
                    If (Not LastCache.ContainsKey("wear_wheels") OrElse LastCache("wear_wheels") <> valueW) Then
                        If (LastCache.ContainsKey("wear_wheels")) Then
                            commandList2.Add(New ArrayList({"text_square", "" & LastCache("wear_wheels") & "%", xpos2 + 55, ypos2 + 14, 3, 3 * 2, 3, colorbgtrailer}))
                        End If
                        commandList2.Add(New ArrayList({"text_square", "" & valueW & "%", xpos2 + 55, ypos2 + 14, 3, 3 * 2, 3, 0}))
                        LastCache("wear_wheels") = valueW
                    End If

                    valueW = Math.Round((100 - rdata.wear_cabin), 1)
                    If (Not LastCache.ContainsKey("wear_cabin") OrElse LastCache("wear_cabin") <> valueW) Then
                        If (LastCache.ContainsKey("wear_cabin")) Then
                            commandList2.Add(New ArrayList({"text_square", "" & LastCache("wear_cabin") & "%", xpos2 + 102, ypos2 + 6, 3, 3 * 2, 3, colorbgtrailer}))
                        End If
                        commandList2.Add(New ArrayList({"text_square", "" & valueW & "%", xpos2 + 102, ypos2 + 6, 3, 3 * 2, 3, 0}))
                        LastCache("wear_cabin") = valueW
                    End If

                    valueW = Math.Round((100 - rdata.wear_chassis), 1)
                    If (Not LastCache.ContainsKey("wear_chassis") OrElse LastCache("wear_chassis") <> valueW) Then
                        If (LastCache.ContainsKey("wear_chassis")) Then
                            commandList2.Add(New ArrayList({"text_square", "" & LastCache("wear_chassis") & "%", xpos2 + 102, ypos2 + 14, 3, 3 * 2, 3, colorbgtrailer}))
                        End If
                        commandList2.Add(New ArrayList({"text_square", "" & valueW & "%", xpos2 + 102, ypos2 + 14, 3, 3 * 2, 3, 0}))
                        LastCache("wear_chassis") = valueW
                    End If




                    'commandList2.Add(New ArrayList({"text_square", "TRANSMISSION: " & (100 - rdata.wear_transmission) & "%", xpos2, ypos2, 3, 3 * 2, 3, 0}))





                    Dim rpm As String = rdata.rpm.ToString
                    If rpm.Length <= 0 Then
                        rpm = "0000"
                    ElseIf rpm.Length <= 1 Then
                        rpm = "000" & rpm
                    ElseIf rpm.Length <= 2 Then
                        rpm = "00" & rpm
                    ElseIf rpm.Length <= 3 Then
                        rpm = "0" & rpm
                    ElseIf rpm.Length > 4 Then
                        rpm = "9999"
                    End If

                    Dim speed2 As String = rdata.speed
                    If speed2.Length <= 0 Then
                        speed2 = "000"
                    ElseIf speed2.Length <= 1 Then
                        speed2 = "00" & speed2
                    ElseIf speed2.Length <= 2 Then
                        speed2 = "0" & speed2
                    ElseIf speed2.Length <= 3 Then
                        speed2 = speed2
                    ElseIf speed2.Length >= 4 Then
                        speed2 = "999"
                    End If

                    commandList2.Add(New ArrayList({"text_image", x + 74, y + 142, speed2, 4}))
                    'commandList2.Add(New ArrayList({"text_image", x + 195, y + 77, rpm, 5}))

                    Return commandList2
                Else

                End If

            Catch ex As Exception
                objHost.DebugMessage(ex.Message & ": " & ex.StackTrace)
            End Try

        Catch ex As Exception
            objHost.DebugMessage("The process throws the error:" & ex.Message & " : " & ex.StackTrace)
            'Console.ReadLine()
        Finally
            If (Not hMapFile Is Nothing) Then
                If (pView <> IntPtr.Zero) Then
                    ' Unmap the file view.
                    'NativeMethod.UnmapViewOfFile(pView)
                    'pView = IntPtr.Zero
                End If
                ' Close the file mapping object.
                'hMapFile.Close()
                'hMapFile = Nothing
            End If
        End Try


        Return commandList2
    End Function


    Public Function LCDSys2_DisplayOnLCD(sensorId As String, elementData As Hashtable, pluginOptions As Hashtable, cacheRuns As Integer) As ArrayList Implements GOverlayPlugin.Interfaces.IPlugin.LCDSys2_DisplayOnLCD

        Dim x As Integer = CInt(elementData("x"))    'grab X position of the element
        Dim y As Integer = CInt(elementData("y"))    'grab Y position of the element

        Dim color_16b_white = 65535
        Dim color_16b_black = 0
        Dim color_16b_red = 59553


        Dim image_bg As String = "ets2_bg.bmp"
        Dim image_bg2 As String = "ets2_bg2.bmp"
        Try
            Dim value As Integer = 0

            'If it fails, dont output anything
            If GrabData(elementData("speedmetric")) = False Then
                'Return commandList2
            End If

            Try

                If sensorId = "ETS2.Gauge1" Then
                    Dim inited = objHost.AccessHost("retrieve", "GLOBAL_GeneralVars", "lcdsys2_windows_inited", "")
                    If inited <> 1 Then
                        objHost.DebugMessage("ETS2 - init Speed Gauge")
                        objHost.LCDSys2_Draw_Icon(x, y, "ets2_gauge1.bmp")
                        Thread.Sleep(100)
                        'Reset our internal cache
                        LastCache = New System.Collections.Hashtable
                    End If

                    Dim images As Integer = 19
                    Dim maxspeed As Integer = elementData("maxspeed")
                    Dim steps As Integer = maxspeed / images
                    Dim color_grey As String = "ets2_grey.bmp"
                    Dim color_green As String = "ets2_green.bmp"
                    Dim color_red As String = "ets2_red.bmp"
                    Dim color_yellow As String = "ets2_yellow.bmp"
                    Dim use_color As String = color_grey

                    Dim offsetX1 As Integer = -9
                    Dim offsetX2 As Integer = -28

                    If rdata.speed < 0 Then rdata.speed = rdata.speed * -1

                    If steps * 1 < rdata.speed Then use_color = color_green Else use_color = color_grey
                    If Not LastCache.ContainsKey("s1") OrElse LastCache("s1") <> use_color Then objHost.LCDSys2_Draw_Icon(x + 54, y + 142, use_color)
                    LastCache("s1") = use_color
                    If steps * 2 < rdata.speed Then use_color = color_green Else use_color = color_grey
                    If Not LastCache.ContainsKey("s2") OrElse LastCache("s2") <> use_color Then objHost.LCDSys2_Draw_Icon(x + 43, y + 128, use_color)
                    LastCache("s2") = use_color
                    If steps * 3 < rdata.speed Then use_color = color_green Else use_color = color_grey
                    If Not LastCache.ContainsKey("s3") OrElse LastCache("s3") <> use_color Then objHost.LCDSys2_Draw_Icon(x + 37, y + 111, use_color)
                    LastCache("s3") = use_color
                    If steps * 4 < rdata.speed Then use_color = color_green Else use_color = color_grey
                    If Not LastCache.ContainsKey("s4") OrElse LastCache("s4") <> use_color Then objHost.LCDSys2_Draw_Icon(x + 33, y + 93, use_color)
                    LastCache("s4") = use_color
                    If steps * 5 < rdata.speed Then use_color = color_green Else use_color = color_grey
                    If Not LastCache.ContainsKey("s5") OrElse LastCache("s5") <> use_color Then objHost.LCDSys2_Draw_Icon(x + 37, y + 74, use_color)
                    LastCache("s5") = use_color
                    If steps * 6 < rdata.speed Then use_color = color_green Else use_color = color_grey
                    If Not LastCache.ContainsKey("s6") OrElse LastCache("s6") <> use_color Then objHost.LCDSys2_Draw_Icon(x + 47, y + 59, use_color)
                    LastCache("s6") = use_color
                    If steps * 7 < rdata.speed Then use_color = color_green Else use_color = color_grey
                    If Not LastCache.ContainsKey("s7") OrElse LastCache("s7") <> use_color Then objHost.LCDSys2_Draw_Icon(x + 58, y + 45, use_color)
                    LastCache("s7") = use_color
                    If steps * 8 < rdata.speed Then use_color = color_green Else use_color = color_grey
                    If Not LastCache.ContainsKey("s8") OrElse LastCache("s8") <> use_color Then objHost.LCDSys2_Draw_Icon(x + 73, y + 35, use_color)
                    LastCache("s8") = use_color
                    If steps * 9 < rdata.speed Then use_color = color_green Else use_color = color_grey
                    If Not LastCache.ContainsKey("s9") OrElse LastCache("s9") <> use_color Then objHost.LCDSys2_Draw_Icon(x + 90, y + 28, use_color)
                    LastCache("s9") = use_color
                    If steps * 10 < rdata.speed Then use_color = color_green Else use_color = color_grey
                    If Not LastCache.ContainsKey("s10") OrElse LastCache("s10") <> use_color Then objHost.LCDSys2_Draw_Icon(x + 107, y + 28, use_color)
                    LastCache("s10") = use_color

                    If steps * 11 < rdata.speed Then use_color = color_yellow Else use_color = color_grey
                    If Not LastCache.ContainsKey("s11") OrElse LastCache("s11") <> use_color Then objHost.LCDSys2_Draw_Icon(x + 126, y + 35, use_color)
                    LastCache("s11") = use_color
                    If steps * 12 < rdata.speed Then use_color = color_yellow Else use_color = color_grey
                    If Not LastCache.ContainsKey("s12") OrElse LastCache("s12") <> use_color Then objHost.LCDSys2_Draw_Icon(x + 142, y + 45, use_color)
                    LastCache("s12") = use_color
                    If steps * 13 < rdata.speed Then use_color = color_yellow Else use_color = color_grey
                    If Not LastCache.ContainsKey("s13") OrElse LastCache("s13") <> use_color Then objHost.LCDSys2_Draw_Icon(x + 154, y + 59, use_color)
                    LastCache("s13") = use_color
                    If steps * 14 < rdata.speed Then use_color = color_yellow Else use_color = color_grey
                    If Not LastCache.ContainsKey("s14") OrElse LastCache("s14") <> use_color Then objHost.LCDSys2_Draw_Icon(x + 163, y + 74, use_color)
                    LastCache("s14") = use_color
                    If steps * 15 < rdata.speed Then use_color = color_yellow Else use_color = color_grey
                    If Not LastCache.ContainsKey("s15") OrElse LastCache("s15") <> use_color Then objHost.LCDSys2_Draw_Icon(x + 168, y + 93, use_color)
                    LastCache("s15") = use_color
                    If steps * 16 < rdata.speed Then use_color = color_red Else use_color = color_grey
                    If Not LastCache.ContainsKey("s16") OrElse LastCache("s16") <> use_color Then objHost.LCDSys2_Draw_Icon(x + 164, y + 111, use_color)
                    LastCache("s16") = use_color
                    If steps * 17 < rdata.speed Then use_color = color_red Else use_color = color_grey
                    If Not LastCache.ContainsKey("s17") OrElse LastCache("s17") <> use_color Then objHost.LCDSys2_Draw_Icon(x + 158, y + 128, use_color)
                    LastCache("s17") = use_color
                    If steps * 18 < rdata.speed Then use_color = color_red Else use_color = color_grey
                    If Not LastCache.ContainsKey("s18") OrElse LastCache("s18") <> use_color Then objHost.LCDSys2_Draw_Icon(x + 148, y + 142, use_color)
                    LastCache("s18") = use_color
                    'If steps * 19 < rdata.speed Then use_color = color_red Else use_color = color_grey
                    'If Not LastCache.ContainsKey("s19") OrElse LastCache("s19") <> use_color Then commandList2.Add(New ArrayList({"image", x + 116 + offsetX1, y + 112 + offsetX2, use_color}))
                    'LastCache("s19") = use_color

                ElseIf sensorId = "ETS2.Gauge" Then
                    Dim inited = objHost.AccessHost("retrieve", "GLOBAL_GeneralVars", "lcdsys2_windows_inited", "")
                    If inited <> 1 Then
                        objHost.DebugMessage("ETS2 - init Full Gauge")
                        objHost.LCDSys2_Draw_Icon(x, y, image_bg)
                        Thread.Sleep(1150)
                        objHost.LCDSys2_Draw_Icon(x + 17, y + 201, image_bg2)
                        Thread.Sleep(100)
                        'Reset our internal cache
                        LastCache = New System.Collections.Hashtable
                    End If

                    LastCache = New System.Collections.Hashtable

                    If (Not LastCache.ContainsKey("right_blinker_light")) Then LastCache("right_blinker_light") = 9999
                    If (Not LastCache.ContainsKey("left_blinker_light")) Then LastCache("left_blinker_light") = 9999
                    If (Not LastCache.ContainsKey("light_low_beam")) Then LastCache("light_low_beam") = 9999
                    If (Not LastCache.ContainsKey("light_high_beam")) Then LastCache("light_high_beam") = 9999
                    If (Not LastCache.ContainsKey("parking_brake")) Then LastCache("parking_brake") = 9999
                    If (Not LastCache.ContainsKey("wipers")) Then LastCache("wipers") = 9999


                    Dim images As Integer = 19
                    Dim maxspeed As Integer = elementData("maxspeed")
                    Dim steps As Integer = maxspeed / images
                    Dim color_grey As String = "ets2_grey.bmp"
                    Dim color_green As String = "ets2_green.bmp"
                    Dim color_red As String = "ets2_red.bmp"
                    Dim color_yellow As String = "ets2_yellow.bmp"
                    Dim use_color As String = color_grey

                    Dim offsetX1 As Integer = -9
                    Dim offsetX2 As Integer = -28

                    If rdata.speed < 0 Then rdata.speed = rdata.speed * -1

                    If steps * 1 < rdata.speed Then use_color = color_green Else use_color = color_grey
                    If Not LastCache.ContainsKey("s1") OrElse LastCache("s1") <> use_color Then objHost.LCDSys2_Draw_Icon(x + 54, y + 142, use_color)
                    LastCache("s1") = use_color
                    If steps * 2 < rdata.speed Then use_color = color_green Else use_color = color_grey
                    If Not LastCache.ContainsKey("s2") OrElse LastCache("s2") <> use_color Then objHost.LCDSys2_Draw_Icon(x + 43, y + 128, use_color)
                    LastCache("s2") = use_color
                    If steps * 3 < rdata.speed Then use_color = color_green Else use_color = color_grey
                    If Not LastCache.ContainsKey("s3") OrElse LastCache("s3") <> use_color Then objHost.LCDSys2_Draw_Icon(x + 37, y + 111, use_color)
                    LastCache("s3") = use_color
                    If steps * 4 < rdata.speed Then use_color = color_green Else use_color = color_grey
                    If Not LastCache.ContainsKey("s4") OrElse LastCache("s4") <> use_color Then objHost.LCDSys2_Draw_Icon(x + 33, y + 93, use_color)
                    LastCache("s4") = use_color
                    If steps * 5 < rdata.speed Then use_color = color_green Else use_color = color_grey
                    If Not LastCache.ContainsKey("s5") OrElse LastCache("s5") <> use_color Then objHost.LCDSys2_Draw_Icon(x + 37, y + 74, use_color)
                    LastCache("s5") = use_color
                    If steps * 6 < rdata.speed Then use_color = color_green Else use_color = color_grey
                    If Not LastCache.ContainsKey("s6") OrElse LastCache("s6") <> use_color Then objHost.LCDSys2_Draw_Icon(x + 47, y + 59, use_color)
                    LastCache("s6") = use_color
                    If steps * 7 < rdata.speed Then use_color = color_green Else use_color = color_grey
                    If Not LastCache.ContainsKey("s7") OrElse LastCache("s7") <> use_color Then objHost.LCDSys2_Draw_Icon(x + 58, y + 45, use_color)
                    LastCache("s7") = use_color
                    If steps * 8 < rdata.speed Then use_color = color_green Else use_color = color_grey
                    If Not LastCache.ContainsKey("s8") OrElse LastCache("s8") <> use_color Then objHost.LCDSys2_Draw_Icon(x + 73, y + 35, use_color)
                    LastCache("s8") = use_color
                    If steps * 9 < rdata.speed Then use_color = color_green Else use_color = color_grey
                    If Not LastCache.ContainsKey("s9") OrElse LastCache("s9") <> use_color Then objHost.LCDSys2_Draw_Icon(x + 90, y + 28, use_color)
                    LastCache("s9") = use_color
                    If steps * 10 < rdata.speed Then use_color = color_green Else use_color = color_grey
                    If Not LastCache.ContainsKey("s10") OrElse LastCache("s10") <> use_color Then objHost.LCDSys2_Draw_Icon(x + 107, y + 28, use_color)
                    LastCache("s10") = use_color

                    If steps * 11 < rdata.speed Then use_color = color_yellow Else use_color = color_grey
                    If Not LastCache.ContainsKey("s11") OrElse LastCache("s11") <> use_color Then objHost.LCDSys2_Draw_Icon(x + 126, y + 35, use_color)
                    LastCache("s11") = use_color
                    If steps * 12 < rdata.speed Then use_color = color_yellow Else use_color = color_grey
                    If Not LastCache.ContainsKey("s12") OrElse LastCache("s12") <> use_color Then objHost.LCDSys2_Draw_Icon(x + 142, y + 45, use_color)
                    LastCache("s12") = use_color
                    If steps * 13 < rdata.speed Then use_color = color_yellow Else use_color = color_grey
                    If Not LastCache.ContainsKey("s13") OrElse LastCache("s13") <> use_color Then objHost.LCDSys2_Draw_Icon(x + 154, y + 59, use_color)
                    LastCache("s13") = use_color
                    If steps * 14 < rdata.speed Then use_color = color_yellow Else use_color = color_grey
                    If Not LastCache.ContainsKey("s14") OrElse LastCache("s14") <> use_color Then objHost.LCDSys2_Draw_Icon(x + 163, y + 74, use_color)
                    LastCache("s14") = use_color
                    If steps * 15 < rdata.speed Then use_color = color_yellow Else use_color = color_grey
                    If Not LastCache.ContainsKey("s15") OrElse LastCache("s15") <> use_color Then objHost.LCDSys2_Draw_Icon(x + 168, y + 93, use_color)
                    LastCache("s15") = use_color
                    If steps * 16 < rdata.speed Then use_color = color_red Else use_color = color_grey
                    If Not LastCache.ContainsKey("s16") OrElse LastCache("s16") <> use_color Then objHost.LCDSys2_Draw_Icon(x + 164, y + 111, use_color)
                    LastCache("s16") = use_color
                    If steps * 17 < rdata.speed Then use_color = color_red Else use_color = color_grey
                    If Not LastCache.ContainsKey("s17") OrElse LastCache("s17") <> use_color Then objHost.LCDSys2_Draw_Icon(x + 158, y + 128, use_color)
                    LastCache("s17") = use_color
                    If steps * 18 < rdata.speed Then use_color = color_red Else use_color = color_grey
                    If Not LastCache.ContainsKey("s18") OrElse LastCache("s18") <> use_color Then objHost.LCDSys2_Draw_Icon(x + 148, y + 142, use_color)
                    LastCache("s18") = use_color
                    'If steps * 19 < rdata.speed Then use_color = color_red Else use_color = color_grey
                    'If Not LastCache.ContainsKey("s19") OrElse LastCache("s19") <> use_color Then commandList2.Add(New ArrayList({"image", x + 116 + offsetX1, y + 112 + offsetX2, use_color}))
                    'LastCache("s19") = use_color

                    createNeedle2(53, 2.5, rdata.speed, maxspeed, x + 106, y + 103, "speed", 145, 0.25)

                    offsetX1 = 38
                    offsetX2 = 50
                    Dim rpm_max As Integer = rdata.rpm_limit
                    If elementData("maxrpm") > 0 Then
                        rpm_max = CInt(elementData("maxrpm"))
                    End If
                    'objHost.DebugMessage("rpm limit: " & rdata.rpm_limit)

                    createNeedle2(30, 1.5, rdata.rpm, rpm_max, x + 128 + 93 + offsetX1, y + 88 + offsetX2, "rpm", 145, 0.25)


                    Dim val, needleLen As Integer, needleRadius As Integer
                    needleLen = 30
                    needleRadius = 1.5
                    val = ((rdata.speed * 145 / maxspeed) * 0.01) - 0.25

                    offsetX1 = 40
                    offsetX2 = 49
                    steps = rpm_max / images
                    Dim offsetx As Integer = 128
                    color_grey = "ets2_grey_small.bmp"
                    color_green = "ets2_green_small.bmp"
                    color_red = "ets2_red_small.bmp"
                    color_yellow = "ets2_yellow_small.bmp"
                    use_color = color_grey

                    If steps * 1 < rdata.rpm Then use_color = color_green Else use_color = color_grey
                    If Not LastCache.ContainsKey("r1") OrElse LastCache("r1") <> use_color Then objHost.LCDSys2_Draw_Icon(offsetx + x + 63 + offsetX1, y + 112 + offsetX2, use_color)
                    LastCache("r1") = use_color
                    If steps * 2 < rdata.rpm Then use_color = color_green Else use_color = color_grey
                    If Not LastCache.ContainsKey("r2") OrElse LastCache("r2") <> use_color Then objHost.LCDSys2_Draw_Icon(offsetx + x + 57 + offsetX1, y + 104 + offsetX2, use_color)
                    LastCache("r2") = use_color
                    If steps * 3 < rdata.rpm Then use_color = color_green Else use_color = color_grey
                    If Not LastCache.ContainsKey("r3") OrElse LastCache("r3") <> use_color Then objHost.LCDSys2_Draw_Icon(offsetx + x + 52 + offsetX1, y + 94 + offsetX2, use_color)
                    LastCache("r3") = use_color
                    If steps * 4 < rdata.rpm Then use_color = color_green Else use_color = color_grey
                    If Not LastCache.ContainsKey("r4") OrElse LastCache("r4") <> use_color Then objHost.LCDSys2_Draw_Icon(offsetx + x + 50 + offsetX1, y + 84 + offsetX2, use_color)
                    LastCache("r4") = use_color
                    If steps * 5 < rdata.rpm Then use_color = color_green Else use_color = color_grey
                    If Not LastCache.ContainsKey("r5") OrElse LastCache("r5") <> use_color Then objHost.LCDSys2_Draw_Icon(offsetx + x + 53 + offsetX1, y + 73 + offsetX2, use_color)
                    LastCache("r5") = use_color
                    If steps * 6 < rdata.rpm Then use_color = color_green Else use_color = color_grey
                    If Not LastCache.ContainsKey("r6") OrElse LastCache("r6") <> use_color Then objHost.LCDSys2_Draw_Icon(offsetx + x + 58 + offsetX1, y + 64 + offsetX2, use_color)
                    LastCache("r6") = use_color
                    If steps * 7 < rdata.rpm Then use_color = color_green Else use_color = color_grey
                    If Not LastCache.ContainsKey("r7") OrElse LastCache("r7") <> use_color Then objHost.LCDSys2_Draw_Icon(offsetx + x + 64 + offsetX1, y + 56 + offsetX2, use_color)
                    LastCache("r7") = use_color
                    If steps * 8 < rdata.rpm Then use_color = color_green Else use_color = color_grey
                    If Not LastCache.ContainsKey("r8") OrElse LastCache("r8") <> use_color Then objHost.LCDSys2_Draw_Icon(offsetx + x + 73 + offsetX1, y + 50 + offsetX2, use_color)
                    LastCache("r8") = use_color
                    If steps * 9 < rdata.rpm Then use_color = color_green Else use_color = color_grey
                    If Not LastCache.ContainsKey("r9") OrElse LastCache("r9") <> use_color Then objHost.LCDSys2_Draw_Icon(offsetx + x + 83 + offsetX1, y + 46 + offsetX2, use_color)
                    LastCache("r9") = use_color
                    If steps * 10 < rdata.rpm Then use_color = color_green Else use_color = color_grey
                    If Not LastCache.ContainsKey("r10") OrElse LastCache("r10") <> use_color Then objHost.LCDSys2_Draw_Icon(offsetx + x + 93 + offsetX1, y + 46 + offsetX2, use_color)
                    LastCache("r10") = use_color

                    If steps * 11 < rdata.rpm Then use_color = color_yellow Else use_color = color_grey
                    If Not LastCache.ContainsKey("r11") OrElse LastCache("r11") <> use_color Then objHost.LCDSys2_Draw_Icon(offsetx + x + 104 + offsetX1, y + 50 + offsetX2, use_color)
                    LastCache("r1") = use_color
                    If steps * 12 < rdata.rpm Then use_color = color_yellow Else use_color = color_grey
                    If Not LastCache.ContainsKey("r12") OrElse LastCache("r12") <> use_color Then objHost.LCDSys2_Draw_Icon(offsetx + x + 113 + offsetX1, y + 56 + offsetX2, use_color)
                    LastCache("r12") = use_color
                    If steps * 13 < rdata.rpm Then use_color = color_yellow Else use_color = color_grey
                    If Not LastCache.ContainsKey("r13") OrElse LastCache("r13") <> use_color Then objHost.LCDSys2_Draw_Icon(offsetx + x + 113 + offsetX1, y + 56 + offsetX2, use_color)
                    LastCache("r13") = use_color
                    If steps * 14 < rdata.rpm Then use_color = color_yellow Else use_color = color_grey
                    If Not LastCache.ContainsKey("r14") OrElse LastCache("r14") <> use_color Then objHost.LCDSys2_Draw_Icon(offsetx + x + 120 + offsetX1, y + 64 + offsetX2, use_color)
                    LastCache("r14") = use_color
                    If steps * 15 < rdata.rpm Then use_color = color_yellow Else use_color = color_grey
                    If Not LastCache.ContainsKey("r15") OrElse LastCache("r15") <> use_color Then objHost.LCDSys2_Draw_Icon(offsetx + x + 125 + offsetX1, y + 73 + offsetX2, use_color)
                    LastCache("r15") = use_color
                    If steps * 16 < rdata.rpm Then use_color = color_red Else use_color = color_grey
                    If Not LastCache.ContainsKey("r16") OrElse LastCache("r16") <> use_color Then objHost.LCDSys2_Draw_Icon(offsetx + x + 128 + offsetX1, y + 84 + offsetX2, use_color)
                    LastCache("r16") = use_color
                    If steps * 17 < rdata.rpm Then use_color = color_red Else use_color = color_grey
                    If Not LastCache.ContainsKey("r17") OrElse LastCache("r17") <> use_color Then objHost.LCDSys2_Draw_Icon(offsetx + x + 126 + offsetX1, y + 94 + offsetX2, use_color)
                    LastCache("r17") = use_color
                    If steps * 18 < rdata.rpm Then use_color = color_red Else use_color = color_grey
                    If Not LastCache.ContainsKey("r18") OrElse LastCache("r18") <> use_color Then objHost.LCDSys2_Draw_Icon(offsetx + x + 122 + offsetX1, y + 104 + offsetX2, use_color)
                    LastCache("r18") = use_color
                    If steps * 19 < rdata.rpm Then use_color = color_red Else use_color = color_grey
                    If Not LastCache.ContainsKey("r19") OrElse LastCache("r19") <> use_color Then objHost.LCDSys2_Draw_Icon(offsetx + x + 116 + offsetX1, y + 112 + offsetX2, use_color)
                    LastCache("r19") = use_color


                    'GEAR 

                    Dim rect_x As Integer = 243
                    Dim rect_y As Integer = 150
                    Dim rect_y2 As Integer = rect_y + 37
                    Dim rect_x2 As Integer = rect_x + 35
                    Dim text_y As Integer = rect_y - 1
                    Dim text_x As Integer = rect_x + 9

                    'objHost.DebugMessage("GEAR:" & rdata.gear)

                    'objHost.LCDSys2_Draw_Text_Font(text_x, text_y + 60, "N", 50, color_16b_white, color_16b_black, "Arial_20px.bin", 0, -1)

                    If rdata.gear = 0 OrElse rdata.gear = "0" Then
                        objHost.LCDSys2_Draw_Rectangle(rect_x, rect_y, rect_x2, rect_y2, color_16b_black, 1, 0)
                        objHost.LCDSys2_Draw_Text_Font(text_x, text_y, "N", 50, color_16b_white, color_16b_black, "Arial_20px.bin", 0, -1)
                    ElseIf rdata.gear = -1 OrElse rdata.gear = "-1" Then
                        objHost.LCDSys2_Draw_Rectangle(rect_x, rect_y, rect_x2, rect_y2, color_16b_black, 1, 0)
                        objHost.LCDSys2_Draw_Text_Font(text_x, text_y, "R", 50, color_16b_white, color_16b_black, "Arial_20px.bin", 0, -1)
                    Else
                        If steps * 16 < rdata.rpm Then
                            objHost.LCDSys2_Draw_Rectangle(rect_x, rect_y, rect_x2, rect_y2, color_16b_red, 1, 0)
                        Else
                            objHost.LCDSys2_Draw_Rectangle(rect_x, rect_y, rect_x2, rect_y2, color_16b_black, 1, 0)
                        End If

                        'objHost.DebugMessage("drawing gear at " & text_x & "," & text_y)
                        objHost.LCDSys2_Draw_Text_Font(text_x, text_y, rdata.gear.ToString, 50, color_16b_white, color_16b_black, "Arial_20px.bin", 0, 0)

                        LastCache("last_gear") = rdata.gear
                    End If

                    Dim max_temp As Integer = elementData("maxtemp")


                    'Dim fuel_color_in = convertcolorto16bit(78, 141, 163)
                    'Dim fuel_color_out = convertcolorto16bit(254, 254, 254)
                    Dim fuel_color_out As Integer = convertcolorto16bit(254, 254, 254)
                    Dim fuel_color_in As Integer = convertcolorto16bit(253, 23, 36)
                    Dim rect_xstep As Integer = 7
                    Dim rect_ystep As Integer = 8
                    steps = max_temp / 8
                    rect_x = 286
                    rect_y = 138
                    rect_x2 = rect_x + rect_xstep
                    rect_y2 = rect_y + rect_ystep


                    'FUEL
                    Dim max_fuel As Integer = rdata.fuel_capacity
                    createNeedle2(15, 0, rdata.fuel_amount, max_fuel, x + 215, y + 25, "fuel", 135, 0)

                    Dim ftext = rdata.fuel_amount
                    If rdata.fuel_amount >= 100 Then ftext = Math.Round(rdata.fuel_amount, 0) Else ftext = rdata.fuel_amount

                    If (Not LastCache.ContainsKey("fuel_val")) OrElse LastCache("fuel_val") <> ftext Then
                        Dim xpos = 234
                        Dim ypos = 7
                        objHost.LCDSys2_Draw_Text_Font(xpos, ypos, ftext.ToString & "L" & "L", 50, color_16b_white, color_16b_black, "Arial_17px.bin", 0, 0)
                        LastCache("fuel_val") = ftext
                    End If


                    'TEMP
                    createNeedle2(15, 0, rdata.water_temperature, elementData("maxtemp"), x + 273, y + 61, "water_temp", 125, 0.28)

                    If (Not LastCache.ContainsKey("temp_val")) OrElse LastCache("temp_val") <> rdata.water_temperature Then
                        Dim xpos = 296
                        Dim ypos = 46
                        objHost.LCDSys2_Draw_Text_Font(xpos, ypos, rdata.water_temperature.ToString & "C", 50, color_16b_white, color_16b_black, "Arial_17px.bin", 0, 0)
                        LastCache("temp_val") = rdata.water_temperature
                    End If

                    'BAT

                    ftext = Math.Round(rdata.battery_voltage, 0)
                    'battery is always going from 23 to 24, so lets stick with 24
                    If ftext = 23 Then ftext = 24

                    If (Not LastCache.ContainsKey("bat_val")) OrElse LastCache("bat_val") <> ftext Then
                        Dim xpos As Integer = 284
                        Dim ypos As Integer = 26
                        objHost.LCDSys2_Draw_Text_Font(xpos, ypos, ftext.ToString & "V", 50, color_16b_white, color_16b_black, "Arial_17px.bin", 0, 0)
                        LastCache("bat_val") = ftext
                    End If

                    If rdata.right_blinker_light + rdata.left_blinker_light = 0 Or rdata.right_blinker_light + rdata.left_blinker_light = 2 Then
                        If rdata.right_blinker_light + rdata.left_blinker_light = 0 Then
                            'commandList2.Add(New ArrayList({"image", x + 150, y + 91, 350}))
                        Else
                            'commandList2.Add(New ArrayList({"image", x + 150, y + 91, 349}))
                        End If
                    End If

                    If LastCache("right_blinker_light") <> rdata.right_blinker_light Then
                        If rdata.right_blinker_light = 1 Then
                            objHost.LCDSys2_Draw_Icon(x + 280, y + 188, "ets2_right_blinker_on.bmp")
                        Else
                            objHost.LCDSys2_Draw_Icon(x + 280, y + 188, "ets2_right_blinker_off.bmp")
                        End If
                    End If

                    If LastCache("left_blinker_light") <> rdata.left_blinker_light Then
                        If rdata.left_blinker_light = 1 Then
                            objHost.LCDSys2_Draw_Icon(x + 212, y + 188, "ets2_left_blinker_on.bmp")
                        Else
                            objHost.LCDSys2_Draw_Icon(x + 212, y + 188, "ets2_left_blinker_off.bmp")
                        End If
                    End If


                    If LastCache("light_low_beam") <> rdata.light_low_beam Or LastCache("light_high_beam") <> rdata.light_high_beam Then
                        If rdata.light_low_beam = 1 Or rdata.light_high_beam = 1 Then
                            objHost.LCDSys2_Draw_Icon(x + 195, y + 212, "ets2_light_high_beam_on.bmp")
                        Else
                            objHost.LCDSys2_Draw_Icon(x + 195, y + 212, "ets2_light_high_beam_off.bmp")
                        End If
                    End If

                    If LastCache("parking_brake") <> rdata.parking_brake Then
                        If rdata.parking_brake = 1 Then
                            objHost.LCDSys2_Draw_Icon(x + 237, y + 212, "ets2_brake_on.bmp")
                        Else
                            objHost.LCDSys2_Draw_Icon(x + 237, y + 212, "ets2_brake_off.bmp")
                        End If
                    End If

                    If LastCache("wipers") <> rdata.wipers Then
                        If rdata.wipers = 1 Then
                            objHost.LCDSys2_Draw_Icon(x + 280, y + 212, "ets2_wipers_on.bmp")
                        Else
                            objHost.LCDSys2_Draw_Icon(x + 280, y + 212, "ets2_wipers_off.bmp")
                        End If
                    End If

                    LastCache("wipers") = rdata.wipers
                    LastCache("parking_brake") = rdata.parking_brake
                    LastCache("light_low_beam") = rdata.light_low_beam
                    LastCache("light_high_beam") = rdata.light_high_beam
                    LastCache("left_blinker_light") = rdata.left_blinker_light
                    LastCache("right_blinker_light") = rdata.right_blinker_light

                    'WEAR
                    Dim xpos2 As Integer = 13
                    Dim ypos2 As Integer = 200

                    Dim colorbgtrailer As Integer = 65535
                    Dim valueW As Integer = 0

                    valueW = Math.Round((100 - rdata.wear_engine), 1)
                    If (Not LastCache.ContainsKey("wear_engine") OrElse LastCache("wear_engine") <> valueW) Then
                        objHost.LCDSys2_Draw_Text_Font(xpos2 + 55, ypos2 + 6, "" & valueW & "%", 50, color_16b_white, color_16b_black, "Arial_17px.bin", 0, 0)
                        LastCache("wear_engine") = valueW
                    End If

                    valueW = Math.Round((100 - rdata.wear_wheels), 1)
                    If (Not LastCache.ContainsKey("wear_wheels") OrElse LastCache("wear_wheels") <> valueW) Then
                        objHost.LCDSys2_Draw_Text_Font(xpos2 + 55, ypos2 + 14, "" & valueW & "%", 50, color_16b_white, color_16b_black, "Arial_17px.bin", 0, 0)
                        LastCache("wear_wheels") = valueW
                    End If

                    valueW = Math.Round((100 - rdata.wear_cabin), 1)
                    If (Not LastCache.ContainsKey("wear_cabin") OrElse LastCache("wear_cabin") <> valueW) Then
                        objHost.LCDSys2_Draw_Text_Font(xpos2 + 102, ypos2 + 6, "" & valueW & "%", 50, color_16b_white, color_16b_black, "Arial_17px.bin", 0, 0)
                        LastCache("wear_cabin") = valueW
                    End If

                    valueW = Math.Round((100 - rdata.wear_chassis), 1)
                    If (Not LastCache.ContainsKey("wear_chassis") OrElse LastCache("wear_chassis") <> valueW) Then
                        objHost.LCDSys2_Draw_Text_Font(xpos2 + 102, ypos2 + 14, "" & valueW & "%", 50, color_16b_white, color_16b_black, "Arial_17px.bin", 0, 0)
                        LastCache("wear_chassis") = valueW
                    End If


                    Dim rpm As String = rdata.rpm.ToString
                    If rpm.Length <= 0 Then
                        rpm = "0000"
                    ElseIf rpm.Length <= 1 Then
                        rpm = "000" & rpm
                    ElseIf rpm.Length <= 2 Then
                        rpm = "00" & rpm
                    ElseIf rpm.Length <= 3 Then
                        rpm = "0" & rpm
                    ElseIf rpm.Length > 4 Then
                        rpm = "9999"
                    End If

                    Dim speed2 As String = rdata.speed
                    If speed2.Length <= 0 Then
                        speed2 = "000"
                    ElseIf speed2.Length <= 1 Then
                        speed2 = "00" & speed2
                    ElseIf speed2.Length <= 2 Then
                        speed2 = "0" & speed2
                    ElseIf speed2.Length <= 3 Then
                        speed2 = speed2
                    ElseIf speed2.Length >= 4 Then
                        speed2 = "999"
                    End If

                    objHost.LCDSys2_Draw_Text_Font(x + 74, y + 142, speed2, 50, color_16b_white, color_16b_black, "Arial_30px.bin", 0, 0)

                Else

                End If

            Catch ex As Exception
                objHost.DebugMessage(ex.Message & ": " & ex.StackTrace)
            End Try

        Catch ex As Exception
            objHost.DebugMessage("The process throws the error:" & ex.Message & " : " & ex.StackTrace)
            'Console.ReadLine()
        Finally
            If (Not hMapFile Is Nothing) Then
                If (pView <> IntPtr.Zero) Then
                    ' Unmap the file view.
                    'NativeMethod.UnmapViewOfFile(pView)
                    'pView = IntPtr.Zero
                End If
                ' Close the file mapping object.
                'hMapFile.Close()
                'hMapFile = Nothing
            End If
        End Try

        Return New ArrayList
    End Function


    Public Function percToDeg(perc As Integer) As Integer
        Return perc * 360
    End Function

    Public Function percToRad(perc As Integer) As Integer
        Return degToRad(percToDeg(perc))
    End Function

    Public Function degToRad(deg As Integer) As Integer
        Return deg * Math.PI / 180
    End Function

    Public Function createNeedle(commandlist2, needleLength, needleRadius, currentvalue, maxvalue, centerX, centerY, cacheName, maximumPercent, needlebelowZero)
        Dim leftX, leftY, rightX, rightY, thetaRad, topX, topY, val, needleLen, percent
        needleLen = needleLength
        'needleRadius = 1.5
        'val = ((rdata.speed * 115 / 90) * 0.01) - 0.15
        If currentvalue > maxvalue Then currentvalue = maxvalue

        val = ((currentvalue * maximumPercent / maxvalue) * 0.01) - needlebelowZero
        percent = val

        thetaRad = percToRad(percent / 2)

        'centerX = x + 93 - 29
        'centerY = y + 88 - 28

        topX = centerX - needleLen * Math.Cos(thetaRad)
        topY = centerY - needleLen * Math.Sin(thetaRad)

        leftX = centerX - needleRadius * Math.Cos(thetaRad - Math.PI / 2)
        leftY = centerY - needleRadius * Math.Sin(thetaRad - Math.PI / 2)

        rightX = centerX - needleRadius * Math.Cos(thetaRad + Math.PI / 2)
        rightY = centerY - needleRadius * Math.Sin(thetaRad + Math.PI / 2)

        If (Not LastCache.ContainsKey("prev_" & cacheName & "_value")) OrElse (LastCache.ContainsKey("prev_" & cacheName & "_value") AndAlso LastCache("prev_" & cacheName & "_value") <> currentvalue) Then
            If LastCache.ContainsKey("prev_" & cacheName & "_lines") Then
                commandlist2.Add(New ArrayList({"draw_lines", LastCache("prev_" & cacheName & "_lines"), convertcolorto16bit(0, 0, 0)}))
            End If

            'Dim mid = x + 60
            Dim lines As New ArrayList
            lines.Add(New ArrayList({leftX, leftY}))
            lines.Add(New ArrayList({topX, topY}))
            lines.Add(New ArrayList({rightX, rightY}))
            lines.Add(New ArrayList({leftX, leftY}))
            'objHost.DebugMessage(val & " > " & centerX & ":" & centerY & " > " & topX & ":" & topY)
            commandlist2.Add(New ArrayList({"draw_lines", lines, convertcolorto16bit(27, 160, 232)}))
            LastCache("prev_" & cacheName & "_lines") = lines
        End If
        LastCache("prev_" & cacheName & "_value") = currentvalue

        Return commandlist2
    End Function

    Public Function createNeedle2(needleLength, needleRadius, currentvalue, maxvalue, centerX, centerY, cacheName, maximumPercent, needlebelowZero)
        Try
            Dim leftX, leftY, rightX, rightY, thetaRad, topX, topY, val, needleLen, percent
            needleLen = needleLength
            'needleRadius = 1.5
            'val = ((rdata.speed * 115 / 90) * 0.01) - 0.15
            If currentvalue > maxvalue Then currentvalue = maxvalue

            val = ((currentvalue * maximumPercent / maxvalue) * 0.01) - needlebelowZero
            percent = val

            thetaRad = percToRad(percent / 2)

            'centerX = x + 93 - 29
            'centerY = y + 88 - 28

            topX = centerX - needleLen * Math.Cos(thetaRad)
            topY = centerY - needleLen * Math.Sin(thetaRad)

            leftX = centerX - needleRadius * Math.Cos(thetaRad - Math.PI / 2)
            leftY = centerY - needleRadius * Math.Sin(thetaRad - Math.PI / 2)

            rightX = centerX - needleRadius * Math.Cos(thetaRad + Math.PI / 2)
            rightY = centerY - needleRadius * Math.Sin(thetaRad + Math.PI / 2)

            If (Not LastCache.ContainsKey("prev_" & cacheName & "_value")) OrElse (LastCache.ContainsKey("prev_" & cacheName & "_value") AndAlso LastCache("prev_" & cacheName & "_value") <> currentvalue) Then
                If LastCache.ContainsKey("prev_" & cacheName & "_lines2") Then
                    objHost.LCDSys2_Draw_Lines(LastCache("prev_" & cacheName & "_lines2"), True, convertcolorto16bit(0, 0, 0))
                End If

                'Dim mid = x + 60
                Dim lines As New ArrayList
                lines.Add(New ArrayList({leftX, leftY, 65535}))
                lines.Add(New ArrayList({topX, topY, 65535}))
                lines.Add(New ArrayList({rightX, rightY, 65535}))
                lines.Add(New ArrayList({leftX, leftY, 65535}))
                'objHost.DebugMessage(val & " > " & centerX & ":" & centerY & " > " & topX & ":" & topY)
                Return lines
                objHost.LCDSys2_Draw_Lines(lines, True, convertcolorto16bit(27, 160, 232))
                LastCache("prev_" & cacheName & "_lines2") = lines
            End If
            'LastCache("prev_" & cacheName & "_value") = currentvalue

        Catch ex As Exception
            objHost.DebugMessage("ETS Plugin Error creating gauge: " & ex.Message & ex.StackTrace)
        End Try
        Return True
    End Function
    Public Function convertcolorto16bit(cr As Integer, cg As Integer, cb As Integer) As Integer

        Dim R As Double
        Dim G As Double
        Dim B As Double

        R = cr / 256 * 32
        G = cg / 256 * 64
        B = cb / 256 * 32

        R = Math.Floor(R)
        G = Math.Floor(G)
        B = Math.Floor(B)

        Dim final As Int32 = (CInt(R) << 11)
        final = final + Int(G << 5)
        final = final + Int(B)

        Return final

    End Function



#Region "Native API Signatures and Types"

    ''' <summary>
    ''' Access rights for file mapping objects
    ''' http://msdn.microsoft.com/en-us/library/aa366559.aspx
    ''' </summary>
    ''' <remarks></remarks>
    Public Enum FileMapAccess
        FILE_MAP_COPY = 1
        FILE_MAP_WRITE = 2
        FILE_MAP_READ = 4
        FILE_MAP_ALL_ACCESS = &HF001F
    End Enum


    ''' <summary>
    ''' Represents a wrapper class for a file mapping handle. 
    ''' </summary>
    ''' <remarks></remarks>
    <SuppressUnmanagedCodeSecurity(), _
    HostProtection(SecurityAction.LinkDemand, MayLeakOnAbort:=True)> _
    Friend NotInheritable Class SafeFileMappingHandle
        Inherits SafeHandleZeroOrMinusOneIsInvalid

        <SecurityPermission(SecurityAction.LinkDemand, UnmanagedCode:=True)> _
        Private Sub New()
            MyBase.New(True)
        End Sub

        <SecurityPermission(SecurityAction.LinkDemand, UnmanagedCode:=True)> _
        Public Sub New(ByVal handle As IntPtr, ByVal ownsHandle As Boolean)
            MyBase.New(ownsHandle)
            MyBase.SetHandle(handle)
        End Sub

        <ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success), _
        DllImport("kernel32.dll", CharSet:=CharSet.Auto, SetLastError:=True)> _
        Private Shared Function CloseHandle(ByVal handle As IntPtr) _
        As <MarshalAs(UnmanagedType.Bool)> Boolean
        End Function

        Protected Overrides Function ReleaseHandle() As Boolean
            Return SafeFileMappingHandle.CloseHandle(MyBase.handle)
        End Function

    End Class


    Friend ReadOnly INVALID_HANDLE_VALUE As New IntPtr(-1)


    ''' <summary>
    ''' The class exposes Windows APIs used in this code sample.
    ''' </summary>
    ''' <remarks></remarks>
    <SuppressUnmanagedCodeSecurity()> _
    Friend Class NativeMethod

        ''' <summary>
        ''' Opens a named file mapping object.
        ''' </summary>
        ''' <param name="dwDesiredAccess">
        ''' The access to the file mapping object. This access is checked against 
        ''' any security descriptor on the target file mapping object.
        ''' </param>
        ''' <param name="bInheritHandle">
        ''' If this parameter is TRUE, a process created by the CreateProcess 
        ''' function can inherit the handle; otherwise, the handle cannot be 
        ''' inherited.
        ''' </param>
        ''' <param name="lpName">
        ''' The name of the file mapping object to be opened.
        ''' </param>
        ''' <returns>
        ''' If the function succeeds, the return value is an open handle to the 
        ''' specified file mapping object.
        ''' </returns>
        <DllImport("kernel32.dll", CharSet:=CharSet.Auto, SetLastError:=True)> _
        Public Shared Function OpenFileMapping( _
            ByVal dwDesiredAccess As FileMapAccess, _
            ByVal bInheritHandle As Boolean, _
            ByVal lpName As String) _
            As SafeFileMappingHandle
        End Function


        ''' <summary>
        ''' Maps a view of a file mapping into the address space of a calling 
        ''' process.
        ''' </summary>
        ''' <param name="hFileMappingObject">
        ''' A handle to a file mapping object. The CreateFileMapping and 
        ''' OpenFileMapping functions return this handle.
        ''' </param>
        ''' <param name="dwDesiredAccess">
        ''' The type of access to a file mapping object, which determines the 
        ''' protection of the pages.
        ''' </param>
        ''' <param name="dwFileOffsetHigh">
        ''' A high-order DWORD of the file offset where the view begins.
        ''' </param>
        ''' <param name="dwFileOffsetLow">
        ''' A low-order DWORD of the file offset where the view is to begin.
        ''' </param>
        ''' <param name="dwNumberOfBytesToMap">
        ''' The number of bytes of a file mapping to map to the view. All bytes 
        ''' must be within the maximum size specified by CreateFileMapping.
        ''' </param>
        ''' <returns>
        ''' If the function succeeds, the return value is the starting address of
        ''' the mapped view.
        ''' </returns>
        <DllImport("Kernel32.dll", CharSet:=CharSet.Auto, SetLastError:=True)> _
        Public Shared Function MapViewOfFile( _
            ByVal hFileMappingObject As SafeFileMappingHandle, _
            ByVal dwDesiredAccess As FileMapAccess, _
            ByVal dwFileOffsetHigh As UInt32, _
            ByVal dwFileOffsetLow As UInt32, _
            ByVal dwNumberOfBytesToMap As UInt32) _
            As IntPtr
        End Function


        ''' <summary>
        ''' Unmaps a mapped view of a file from the calling process's address 
        ''' space.
        ''' </summary>
        ''' <param name="lpBaseAddress">
        ''' A pointer to the base address of the mapped view of a file that is to 
        ''' be unmapped.
        ''' </param>
        ''' <returns></returns>
        <DllImport("Kernel32.dll", CharSet:=CharSet.Auto, SetLastError:=True)> _
        Public Shared Function UnmapViewOfFile( _
            ByVal lpBaseAddress As IntPtr) _
            As <MarshalAs(UnmanagedType.Bool)> Boolean
        End Function

    End Class

#End Region
End Class