Imports System.IO.Ports
Imports System.Threading

Public Class displayConnector
    Private mDisplayModel As String
    Private mDisplayCommands As DataTable = New DataTable("DisplayCommands")
    Private mComPort As String

#Region "Documentation"
    '****************************************************************** 
    ' .Net Library for communicating with digital screens through RS232 
    ' Author: Jeremy Hughes
    ' Date  : 2-28-2014
    '****************************************************************** 

    '********************* todo ************************  
    '1. create interface
    '2. streamline process of adding new displays
    '3. have better cleanup for open serial ports (`Using` clause)

    '********************* .dll building steps ***********************
    '1. save the project
    '2. build as you would an application. 
    '3. Browse to the project's Bin/Debug directory to get DLL that was built
#End Region

#Region "Private Functions"
    Public Sub New(ByVal sModel As String, Optional ByVal sCom As String = "COM1")
        displayModel = sModel
        comPort = sCom
        buildCommandTable()
    End Sub

    Private Sub buildCommandTable()
        ' Declare variables for DataColumn and DataRow objects. 
        Dim column As DataColumn
        Dim row As DataRow

        column = New DataColumn()
        column.DataType = System.Type.GetType("System.String")
        column.ColumnName = "model"
        mDisplayCommands.Columns.Add(column)
        column = New DataColumn()
        column.DataType = System.Type.GetType("System.String")
        column.ColumnName = "command"
        mDisplayCommands.Columns.Add(column)
        column = New DataColumn()
        column.DataType = System.Type.GetType("System.Byte[]")
        column.ColumnName = "bytearray"
        mDisplayCommands.Columns.Add(column)

        row = mDisplayCommands.NewRow()
        row("model") = "NEC_42_E424"
        row("command") = "powon"
        row("bytearray") = New Byte() {&H1, &H30, &H41, &H30, &H41, &H30, &H43, _
                                 &H2, &H43, &H32, &H30, &H33, &H44, &H36, &H30, &H30, &H30, &H31, &H3, _
                                 &H73, _
                                 &HD}
        mDisplayCommands.Rows.Add(row)

        row = mDisplayCommands.NewRow()
        row("model") = "NEC_42_E424"
        row("command") = "powoff"
        row("bytearray") = New Byte() {&H1, &H30, &H41, &H30, &H41, &H30, &H43, _
                                         &H2, &H43, &H32, &H30, &H33, &H44, &H36, &H30, &H30, &H30, &H34, &H3, _
                                         &H76, _
                                         &HD}
        mDisplayCommands.Rows.Add(row)


        row = mDisplayCommands.NewRow()
        row("model") = "NEC_42_E424"
        row("command") = "powstate"
        row("bytearray") = New Byte() {&H1, &H30, &H41, &H30, &H41, &H30, &H36, _
                                &H2, &H30, &H31, &H44, &H36, &H3, _
                                &H74, _
                                  &HD}
        mDisplayCommands.Rows.Add(row)


        row = mDisplayCommands.NewRow()
        row("model") = "NEC_42_E424"
        row("command") = "input_HDMI1"
        row("bytearray") = New Byte() {&H1, &H30, &H41, &H30, &H45, &H30, &H41, _
                                &H2, &H30, &H30, &H36, &H30, &H30, &H30, &H31, &H31, &H3, _
                                &H72, _
                                &HD}
        mDisplayCommands.Rows.Add(row)

        row = mDisplayCommands.NewRow()        
        row("model") = "NEC_42_E424"
        row("command") = "input_HDMI2"
        row("bytearray") = New Byte() {&H1, &H30, &H41, &H30, &H45, &H30, &H41, _
                                &H2, &H30, &H30, &H36, &H30, &H30, &H30, &H31, &H31, &H32, &H3, _
                                &H71, _
                                &HD}
        mDisplayCommands.Rows.Add(row)

        row = mDisplayCommands.NewRow()
        row("model") = "NEC_42_E424"
        row("command") = "input_TV"
        row("bytearray") = New Byte() {&H1, &H30, &H41, &H30, &H45, &H30, &H41, _
                                &H2, &H30, &H30, &H36, &H30, &H30, &H30, &H30, &H41, &H3,
                                &H3, _
                                &HD}
        mDisplayCommands.Rows.Add(row)


        row = mDisplayCommands.NewRow()
        row("model") = "NEC_42_E424"
        row("command") = "keylock"
        row("bytearray") = New Byte() {&H1, &H30, &H41, &H30, &H45, &H30, &H41, _
                                &H2, &H30, &H30, &H46, &H42, &H30, &H30, &H30, &H31, &H3,
                                &H71, _
                                &HD}
        mDisplayCommands.Rows.Add(row)

        row = mDisplayCommands.NewRow()
        row("model") = "NEC_42_E424"
        row("command") = "keyunlock"
        row("bytearray") = New Byte() {&H1, &H30, &H41, &H30, &H45, &H30, &H41, _
                                &H2, &H30, &H30, &H46, &H42, &H30, &H30, &H30, &H30, &H3,
                                &H70, _
                                &HD}
        mDisplayCommands.Rows.Add(row)
    End Sub

    Private Function nec_e424_port() As SerialPort
        'returns a new serial port object for an NEC E424
        Dim _serialPort As New SerialPort

        ''****Documentation From NEC****
        ''http://www.nec-display-solutions.com/p/download/pr/File/cp/Products/PublicDisplays/Shared/CommandLists/PDF-ExternalControlManual-RS232LANX461SX551S-%28english%29.pdf?fn=ExternalControlManual-RS232LANX461SX551S_en.pdf

        'Create a new SerialPort object with default settings.
        _serialPort = New SerialPort()
        ' Allow the user to set the appropriate properties.
        _serialPort.PortName = comPort
        _serialPort.BaudRate = 9600
        _serialPort.Parity = Parity.None
        _serialPort.DataBits = 8
        _serialPort.StopBits = 1
        _serialPort.Handshake = Handshake.None

        ' Set the read/write timeouts
        _serialPort.ReadTimeout = 600
        _serialPort.WriteTimeout = 600
        Return _serialPort
    End Function

    Private Sub calcBCC()
        'this calculation is used to determine the bcc check code for an NEC tv command string
        '(Only used in program testing)
        'BCC result = Xor all bytes between SOH and ETX (&H01, &H03)
        Dim val As Long
        ''val = &H30 Xor &H41 Xor &H30 Xor &H45 Xor &H30 Xor &H41 Xor &H2 Xor &H30 Xor &H30 Xor &H31 Xor &H30 Xor &H30 Xor &H30 Xor &H36 Xor &H34 Xor &H3 '(= 77)
        ''val = &H30 Xor &H41 Xor &H30 Xor &H41 Xor &H30 Xor &H43 Xor &H2 Xor &H43 Xor &H32 Xor &H30 Xor &H33 Xor &H44 Xor &H36 Xor &H30 Xor &H30 Xor &H30 Xor &H34 '(= 75)
        ''val = &H30 Xor &H41 Xor &H30 Xor &H41 Xor &H30 Xor &H43 Xor &H2 Xor &H43 Xor &H32 Xor &H30 Xor &H33 Xor &H44 Xor &H36 Xor &H30 Xor &H30 Xor &H30 Xor &H34 Xor &H3 '(= 76)
        val = &H30 Xor &H41 Xor &H30 Xor &H41 Xor &H30 Xor &H43 Xor &H2 Xor &H43 Xor &H32 Xor &H30 Xor &H33 Xor &H44 Xor &H36 Xor &H30 Xor &H30 Xor &H30 Xor &H31 Xor &H3 '(= 73)
        MsgBox(Hex(val))
    End Sub

    Private Function getresponse(serialport As SerialPort) As Byte()
        'reads data from an open serial port connection
        Dim response As String = ""
        Dim sleepctr As Integer = 0

        Dim buf As Integer = serialport.BytesToRead

        Do Until buf <> 0 Or sleepctr > 10
            buf = serialport.BytesToRead
            System.Threading.Thread.Sleep(300)
            sleepctr += 1
        Loop

        Dim responseArr As Byte() = New Byte() {}

        If buf <> 0 Then
            responseArr = New Byte(buf) {}
            serialport.Read(responseArr, 0, buf)
        End If

        Return responseArr
    End Function

    Private Function byteArrayToString(bytearray As Byte()) As String
        Dim retval As String = ""
        If bytearray.Length > 0 Then
            For Each b As Byte In bytearray
                retval += "&h" & Hex(b) & " "
            Next
        End If

        Return retval
    End Function

#End Region

#Region "Public Methods"
    Public Function readPowerState() As String
        Dim serialPort As SerialPort = nec_e424_port()
        Dim response As String = ""
        Dim buf As New List(Of Byte)
        Dim responsebuf As New List(Of Byte)
        Dim cmdData As DataRow() = mDisplayCommands.Select("model = '" & mDisplayModel & "' AND command = 'powstate'")

        serialPort.Open()

        If cmdData.Length > 0 Then
            buf.AddRange(cmdData(0)("bytearray"))

            serialPort.Write(buf.ToArray, 0, buf.Count)

            response = byteArrayToString(getresponse(serialPort))

            'REMOVE THIS LINE BEFORE USING THIS CLASS IN OTHER PROJECTS *****
            Form1.lstResponse.Items.Add(Now & " - " & response)

            Select Case response
                Case "&h1 &h30 &h30 &h41 &h42 &h31 &h32 &h2 &h30 &h32 &h30 &h30 &h44 &h36 &h30 &h30 &h30 &h30 &h30 &h34 &h30 &h30 &h30 &h31 &h3 &h74 &hD &h0 "
                    response = "On"

                Case "&h1 &h30 &h30 &h41 &h42 &h31 &h32 &h2 &h30 &h32 &h30 &h30 &h44 &h36 &h30 &h30 &h30 &h30 &h30 &h34 &h30 &h30 &h30 &h32 &h3 &h74 &hD &h0 "
                    response = "Standby"

                Case Else
                    response = "Off"
            End Select
            serialPort.Close()
        End If

        Return response
    End Function

    Public Function readVolumeLevel() As Integer


        Return 0
    End Function

    Public Function setVolumeLevel(ByVal _vol As Integer) As Boolean


        Return True
    End Function

    Public Function turnPowerOn() As String

        Dim serialPort As SerialPort = nec_e424_port()
        Dim response As String = ""
        serialPort.Open()

        Dim buf As New List(Of Byte)
        Dim cmdData As DataRow() = mDisplayCommands.Select("model = '" & mDisplayModel & "' AND command = 'powon'")
        'Pow on

        If cmdData.Length > 0 Then
            buf.AddRange(cmdData(0)("bytearray"))
            serialPort.Write(buf.ToArray, 0, buf.Count)
            response = byteArrayToString(getresponse(serialPort))
            serialPort.Close()
        End If

        Return response

    End Function

    Public Function turnPowerOff() As String
        Dim serialPort As SerialPort = nec_e424_port()
        Dim response As String = ""
        serialPort.Open()

        Dim buf As New List(Of Byte)
        Dim cmdData As DataRow() = mDisplayCommands.Select("model = '" & mDisplayModel & "' AND command = 'powoff'")

        If cmdData.Length > 0 Then
            buf.AddRange(cmdData(0)("bytearray"))

            serialPort.Write(buf.ToArray, 0, buf.Count)
            response = byteArrayToString(getresponse(serialPort))
            serialPort.Close()
        End If

        Return response

    End Function

    Public Function changeInput(sInput As String) As String
        Dim serialPort As SerialPort = nec_e424_port()
        Dim response As String = ""
        serialPort.Open()

        Dim buf As New List(Of Byte)
        Dim cmdData As DataRow() = mDisplayCommands.Select("model = '" & mDisplayModel & "' AND command = 'input_" & sInput & "'")

        If cmdData.Length > 0 Then
            buf.AddRange(cmdData(0)("bytearray"))

            serialPort.Write(buf.ToArray, 0, buf.Count)
            response = byteArrayToString(getresponse(serialPort))
            serialPort.Close()
        End If

        Return response

    End Function

    Public Function lockoutKeys() As String
        Dim serialPort As SerialPort = nec_e424_port()
        Dim response As String = ""
        serialPort.Open()

        Dim buf As New List(Of Byte)
        Dim cmdData As DataRow() = mDisplayCommands.Select("model = '" & mDisplayModel & "' AND command = 'keylock'")

        If cmdData.Length > 0 Then
            buf.AddRange(cmdData(0)("bytearray"))

            serialPort.Write(buf.ToArray, 0, buf.Count)
            response = byteArrayToString(getresponse(serialPort))
            serialPort.Close()
        End If

        Return response

    End Function

    Public Function unlockKeys() As String
        Dim serialPort As SerialPort = nec_e424_port()
        Dim response As String = ""
        serialPort.Open()

        Dim buf As New List(Of Byte)
        Dim cmdData As DataRow() = mDisplayCommands.Select("model = '" & mDisplayModel & "' AND command = 'keyunlock'")

        If cmdData.Length > 0 Then
            buf.AddRange(cmdData(0)("bytearray"))

            serialPort.Write(buf.ToArray, 0, buf.Count)
            response = byteArrayToString(getresponse(serialPort))
            serialPort.Close()
        End If

        Return response

    End Function

#End Region

#Region "Public Properties"
    Public Property displayModel() As String
        Set(ByVal value As String)
            mDisplayModel = value
        End Set
        Get
            Return mDisplayModel
        End Get
    End Property

    Public Property comPort() As String
        Set(ByVal value As String)
            mComPort = value
        End Set
        Get
            Return mComPort
        End Get
    End Property
#End Region





End Class