Public Enum E_GnetErrorCodes
    E00_Success
    E01_Failed
    E02_Unknown
End Enum

Public Class GnetCommandFormat
#Region "Constants"
    Private Const GNet_SOH As Byte = 1
    Private Const GNet_STX As Byte = 2
    Private Const GNet_CR As Byte = &HD
    Private Const GNet_ACK As Byte = 6
    Private Const GNet_NAK As Byte = &H15
    Private Const GNet_EVN As Byte = &H12
    Private Const GNETPACKAGE_ADDR As Integer = 0
    Private Const GNETPACKAGE_FUNCTION As Integer = 1
    Private Const GNETPACKAGE_LENGTH As Integer = 2
    Private Const GNETPACKAGE_DATA As Integer = 3
    Private Const GNETPACKAGE_HEADER_SIZE As Integer = 5 ' Addr(1 Byte)+Function(1 Byte)+Length(1 Byte)+CRC(2 Byte) = 5
#End Region

    Private _replyCode As Byte
    Private _replyDataSize As Byte
    Private _replyDataByteArray() As Byte
    Private _errorCode As E_GnetErrorCodes


    Private Function GNetCRC16(ByRef bBuffer() As Byte, _
                               Optional ByVal iLength As Integer = -1, _
                               Optional ByVal iStart As Integer = 0) As Integer
        Const CRC_PRESET As Integer = &HFFFF
        Const CRC_POLYNOM As Integer = &HA001
        Dim iCRC As Integer = CRC_PRESET
        Dim I As Integer, J As Integer
        Dim iLen As Integer = bBuffer.Length - iStart
        If iLength = -1 Or iLength > iLen Then
            iLength = iLen
        End If
        For I = iStart To iStart + iLength - 1
            iCRC = iCRC Xor bBuffer(I)
            For J = 0 To 7
                If (iCRC And 1) <> 0 Then
                    iCRC = (iCRC >> 1) Xor CRC_POLYNOM
                Else
                    iCRC >>= 1
                End If
            Next J
        Next I
        Return iCRC
    End Function

    ReadOnly Property ReplyCode() As Byte
        Get
            Return _replyCode
        End Get
    End Property

    ReadOnly Property ReplyDataSize() As Byte
        Get
            Return _replyDataSize
        End Get
    End Property

    ReadOnly Property ReplyDataByteArray() As Byte()
        Get
            Return _replyDataByteArray
        End Get
    End Property

    ReadOnly Property ErrorCode() As E_GnetErrorCodes
        Get
            Select Case _replyCode
                Case GNet_ACK
                    _errorCode = E_GnetErrorCodes.E00_Success
                Case GNet_NAK
                    _errorCode = E_GnetErrorCodes.E01_Failed
                Case Else
                    _errorCode = E_GnetErrorCodes.E02_Unknown
            End Select
            Return _errorCode
        End Get
    End Property

    Public Sub ParseGnetCommand(ByVal replyParameterByteArray() As Byte)
        Try
            _replyCode = replyParameterByteArray(2)
            _replyDataSize = replyParameterByteArray(3)
            If _replyDataSize > 0 Then
                ReDim _replyDataByteArray(_replyDataSize)
                Array.Copy(replyParameterByteArray, _
                           4, _
                           _replyDataByteArray, _
                           0, _
                           _replyDataSize)
            End If

        Catch ex As Exception
            Throw New Exception("Invalid parameter")
        End Try



    End Sub


    Public Function GetPackageCommand(ByVal address As Byte, _
                                      ByVal commandCode As Byte, _
                                      ByVal parameterByteArray As Byte()) As Byte()
        Dim cmd As New List(Of Byte)
        Dim crc As Integer
        Dim crcByteArray(1) As Byte

        'SOH
        cmd.Add(GNet_SOH)
        'Address
        cmd.Add(address)
        'Command Code
        cmd.Add(commandCode)
        'Parameter Length
        If parameterByteArray Is Nothing Then
            cmd.Add(0)
            'No need to add parameter field
        Else
            cmd.Add(parameterByteArray.Length)
            'Parameter
            cmd.AddRange(parameterByteArray)
        End If

        crc = GNetCRC16(cmd.ToArray, cmd.ToArray.Length - 1, 1)
        crcByteArray(0) = CByte(crc >> 8)
        crcByteArray(1) = CByte(crc And &HFF)

        cmd.AddRange(crcByteArray)

        Return cmd.ToArray

    End Function



End Class
