Imports System
Imports System.Collections.Generic
Imports System.ComponentModel
Imports System.Data
Imports System.Drawing
Imports System.Text
Imports System.IO.Ports
Imports System.Windows.Forms

Namespace SiWiComMSI
	#Region "Public Enumerations"
	Public Enum LogMsgType
		Incoming
		Outgoing
		Normal
		Warning
		[Error]
	End Enum
	Public Enum PacketType
		[Error]
		Normal
	End Enum
	#End Region

	Public Partial Class SiWiComDevTool_Main
		Inherits Form
		#Region "Local Variables"

		' Various colors for logging info
		Private LogMsgTypeColor As Color() = {Color.Gray, Color.LightGray, Color.Goldenrod, Color.Orange, Color.Red}

		Const WM_NCLBUTTONDOWN As Integer = 161
		Const WM_NCHITTEST As Integer = 132
		Const HT_CAPTION As Integer = 2

		Private pcProtocolInputBuffer As Byte() = New Byte(7) {}
		Private pcProtocolByteCount As Integer = 0
		Private terminalCounter As Integer = 0

		#End Region

		#Region "Constructor"
		Public Sub New()
			InitializeComponent()
			CheckForIllegalCrossThreadCalls = False
		End Sub
		#End Region

		#Region "Local Methods"

		Protected Overloads Overrides Sub WndProc(ByRef m As Message)
			MyBase.WndProc(m)
			If m.Msg = WM_NCHITTEST Then
				m.Result = DirectCast(HT_CAPTION, IntPtr)
			End If
		End Sub

		''' <summary> Save the user's settings. </summary>
		Private Sub SaveSettings()


			Try
				' If the port is open, close it.
				If comport.IsOpen Then
					comport.Close()
				End If

			Catch generatedExceptionName As Exception
			End Try
		End Sub

		''' <summary> Populate the form's controls with default settings. </summary>
		Private Sub InitializeControlValues()


			lstComPort.Items.Clear()
			lstComPort.Height = 0
			For Each s As String In SerialPort.GetPortNames()
				lstComPort.Items.Add(s)
				lstComPort.Height += 14
			Next

			If lstComPort.Items.Count = 0 Then
				MessageBox.Show(Me, "No COM ports detected. " & Chr(10) & "You need at least one free COM port for this to work!!!", "No COM ports detected!", MessageBoxButtons.OK, MessageBoxIcon.[Error])
				Me.Close()
			End If
		End Sub

		''' <summary> Open serial port fom communication (9600bps). </summary>
		''' <param name="port"> COM port to open. </param>
		Private Sub openComport(ByVal port As String)
			Try
				' If the port is open, close it.
				If comport.IsOpen Then
					comport.Close()
				End If
				' Set the port's settings
				comport.BaudRate = 9600
				comport.DataBits = 8
				comport.StopBits = DirectCast([Enum].Parse(GetType(StopBits), "1"), StopBits)
				comport.Parity = DirectCast([Enum].Parse(GetType(Parity), "None"), Parity)
				comport.PortName = port

				' Open the port
				comport.Open()

				btnConnect.ImageIndex = 1
			Catch generatedExceptionName As Exception
				btnConnect.ImageIndex = 0
				MessageBox.Show(Me, "Error connecting to port! " & Chr(10) & "Please check that no other program are connected to the selected COM port.", "Error connecting to port!", MessageBoxButtons.OK, MessageBoxIcon.[Error])
			End Try
		End Sub

		''' <summary> Adds one byte to the input buffer and validate packet when buffer is full. </summary>
		Private Function pcProtocolGetData() As Byte()
			pcProtocolByteCount = 0
			Return pcProtocolInputBuffer
		End Function

		''' <summary> Adds one byte to the input buffer and validate packet when buffer is full. </summary>
		''' <param name="data"> data byte to be added </param>
		''' <param name="mode"> mode = MASTER or SLAVE </param>
		''' <param name="address"> specific address for the slave device </param>
		Private Function pcProtocolAddByteToBuffer(ByVal data As Byte) As Boolean
			Dim gotPacket As Boolean = False

			If pcProtocolByteCount = 0 Then
				If data = 10 Then
					pcProtocolInputBuffer(pcProtocolByteCount) = data
					pcProtocolByteCount += 1
				End If
ElseIf pcProtocolByteCount < pcProtocolInputBuffer.Length - 1 Then
				pcProtocolInputBuffer(pcProtocolByteCount) = data
				pcProtocolByteCount += 1
ElseIf pcProtocolByteCount = pcProtocolInputBuffer.Length - 1 Then
				pcProtocolInputBuffer(pcProtocolByteCount) = data

				If calculateChecksum(pcProtocolInputBuffer) = data Then
					gotPacket = True
				Else
					pcProtocolByteCount = 0
				End If
			End If

			If gotPacket Then
				Return True
			Else
				Return False
			End If
		End Function

		''' <summary> Calculate checksum for roboMSP packet. </summary>
		''' <param name="stringToConvert"> The packet to calculate on. </param>
		''' <returns> Returns the checksum. </returns>
		Private Function calculateChecksum(ByVal data As Byte()) As Byte
			Dim checksum As Integer = 0
			For i As Integer = 0 To (data.Length - 1) - 1

				checksum += data(i)
			Next

			checksum = checksum And 255

			Return CByte(checksum)
		End Function
		''' <summary> Extract command discription from roboMSP packet. </summary>
		''' <param name="stringToConvert"> The packet to extract from. </param>
		''' <returns> Returns the command discription. </returns>
		Private Function getCommand(ByVal stringToConvert As String) As String
			Select Case stringToConvert.Substring(3, 2)
				Case "11"
					Return "GET_DATA"
				Case "22"
					Return "DATA"
				Case "33"
					Return "DATA"
				Case "44"
					Return "UPDATE"
				Case "55"
					Return "UPDATE"
				Case "FE"
					Return "ACK"
			End Select

			Return "Error"
		End Function

		''' <summary> Extract id from roboMSP packet. </summary>
		''' <param name="stringToConvert"> The packet to extract from. </param>
		''' <returns> Returns id. </returns>
		Private Function getId(ByVal stringToConvert As String) As String
			Return stringToConvert.Substring(4, 2)
		End Function

		''' <summary> Send the user's data currently entered in the 'send' box.</summary>
		Private Sub SendCommand(ByVal commandToSend As Byte, ByVal inputData As Byte())

			Dim data As Byte() = {10, commandToSend, inputData(0), inputData(1), inputData(2), inputData(3), _
				inputData(4), 85}

			data(data.Length - 1) = calculateChecksum(data)

			Try
				' Send the binary data out the port
				comport.Write(data, 0, data.Length)
				' Show the hex digits on in the terminal window
				Log(LogMsgType.Outgoing, ByteArrayToHexString(data), PacketType.Normal)
					' Show the hex digits on in the terminal window
					'Log(LogMsgType.Outgoing, ByteArrayToHexString(data), PacketType.Error);
			Catch generatedExceptionName As Exception
			End Try
		End Sub
		''' <summary> Send ACK command to robot. </summary>
		''' <param name="id"> Id to robot. </param>
		Private Sub SendACK()
			Dim data As Byte() = {10, 254, 85, 85, 85, 85, _
				85, 85}

			data(data.Length - 1) = calculateChecksum(data)

			Try
				comport.Write(data, 0, data.Length)
				' Show the hex digits on in the terminal window
				Log(LogMsgType.Outgoing, ByteArrayToHexString(data), PacketType.Normal)
					' Show the hex digits on in the terminal window
					'Log(LogMsgType.Outgoing, ByteArrayToHexString(data), PacketType.Error);
			Catch generatedExceptionName As FormatException
			End Try
		End Sub

		''' <summary> Log data to the terminal window. </summary>
		''' <param name="msgtype"> The type of message to be written. </param>
		''' <param name="msg"> The string containing the message to be shown. </param>
		Private Sub Log(ByVal msgtype As LogMsgType, ByVal msg As String, ByVal packetType As PacketType)
			If packetType = PacketType.[Error] Then
				rtfTerminal.SelectedText = String.Empty
				rtfTerminal.SelectionFont = New Font(rtfTerminal.SelectionFont, FontStyle.Regular)
				rtfTerminal.SelectionColor = LogMsgTypeColor(4)
				rtfTerminal.AppendText("Error" & Chr(10) & "")
				terminalCounter += 1
				rtfTerminal.ScrollToCaret()
ElseIf msgtype = LogMsgType.Incoming Then



				rtfTerminal.Invoke(New EventHandler(AddressOf ConvertedAnonymousMethod1))
ElseIf msgtype = LogMsgType.Outgoing Then



				rtfTerminal.Invoke(New EventHandler(AddressOf ConvertedAnonymousMethod2))
			End If

			If terminalCounter = 300 Then
				rtfTerminal.Clear()
				terminalCounter = 0
			End If

		End Sub

		''' <summary> Convert a string of hex digits (ex: E4 CA B2) to a byte array. </summary>
		''' <param name="s"> The string containing the hex digits (with or without spaces). </param>
		''' <returns> Returns an array of bytes. </returns>
		Private Sub showDataOnPanel(ByVal data As Byte())
			If (data(1) = 34) OrElse (data(1) = 51) Then
				Dim batTemp As Decimal = Convert.ToDecimal(CSng(data(4)) * 0.0146)
				Dim tempTemp As Decimal = Convert.ToDecimal(CSng(data(3)) / 9.8)
				Dim rssiTemp As Decimal = Convert.ToDecimal(CSng(CSByte(data(6))) / 2)

				lblAddr.Text = data(2).ToString()
				lblBat.Text = [Decimal].Round(batTemp, 1) + " V"
				lblRSSI.Text = [Decimal].Round(rssiTemp, 1) + " dB"
				lblTemp.Text = [Decimal].Round(tempTemp, 1) + " C"
			End If
		End Sub

		''' <summary> Convert a string of hex digits (ex: E4 CA B2) to a byte array. </summary>
		''' <param name="s"> The string containing the hex digits (with or without spaces). </param>
		''' <returns> Returns an array of bytes. </returns>
		Private Function HexStringToByteArray(ByVal s As String) As Byte()
			s = s.Replace(" ", "")
			Dim buffer As Byte() = New Byte(s.Length / 2 - 1) {}
			For i As Integer = 0 To s.Length - 1 Step 2
				buffer(i / 2) = CByte(Convert.ToByte(s.Substring(i, 2), 16))
			Next
			Return buffer
		End Function

		''' <summary> Converts an array of bytes into a formatted string of hex digits (ex: E4 CA B2)</summary>
		''' <param name="data"> The array of bytes to be translated into a string of hex digits. </param>
		''' <returns> Returns a well formatted string of hex digits with spacing. </returns>
		Private Function ByteArrayToHexString(ByVal data As Byte()) As String
			Dim sb As New StringBuilder(data.Length * 3)
			For Each b As Byte In data
				sb.Append(Convert.ToString(b, 16).PadLeft(2, "0"C).PadRight(3, " "C))
			Next
			Return sb.ToString().ToUpper()
		End Function

		''' <summary> Converts an array of bytes into a formatted string of hex digits (ex: E4 CA B2)</summary>
		''' <param name="data"> The array of bytes to be translated into a string of hex digits. </param>
		''' <returns> Returns a well formatted string of hex digits with spacing. </returns>
		Private Function ByteArrayToCharString(ByVal data As Byte()) As String
			Dim sb As New StringBuilder(data.Length)
			For Each b As Byte In data
				sb.Append(Convert.ToChar(b))
			Next
			Return sb.ToString().ToUpper()
		End Function
		#End Region

		#Region "Event Handlers"
		Private Sub Form1_Load(ByVal sender As Object, ByVal e As EventArgs)
			InitializeControlValues()
		End Sub
		#End Region

		Private Sub comport_DataReceived(ByVal sender As Object, ByVal e As SerialDataReceivedEventArgs)
			' Obtain the number of bytes waiting in the port's buffer
			Dim bytes As Integer = comport.BytesToRead
			Dim buffer As Byte() = New Byte(bytes - 1) {}

			' Read the data from the port and store it in our buffer
			comport.Read(buffer, 0, bytes)
			For i As Integer = 0 To bytes - 1

				'comport.DiscardInBuffer();

				If pcProtocolAddByteToBuffer(buffer(i)) Then
					Dim completePacket As Byte() = pcProtocolGetData()

					showDataOnPanel(completePacket)
					' Show the hex digits on in the terminal window
					Log(LogMsgType.Incoming, ByteArrayToHexString(completePacket), PacketType.Normal)
				End If
			Next

		End Sub

		Private Sub lstComPort_SelectedIndexChanged(ByVal sender As Object, ByVal e As EventArgs)
			openComport(lstComPort.Text)
			lstComPort.Visible = False
			lblSelectPort.Visible = False
		End Sub

		Private Sub SiWiComMSI_Main_FormClosing(ByVal sender As Object, ByVal e As FormClosingEventArgs)
			SaveSettings()
		End Sub

		Private Sub btnClose_MouseEnter(ByVal sender As Object, ByVal e As EventArgs)
			btnClose.ImageIndex = 1
		End Sub

		Private Sub btnClose_MouseLeave(ByVal sender As Object, ByVal e As EventArgs)
			btnClose.ImageIndex = 0
		End Sub

		Private Sub btnClose_Click(ByVal sender As Object, ByVal e As EventArgs)
			Me.Close()
		End Sub

		Private Sub btnConnect_Click_1(ByVal sender As Object, ByVal e As EventArgs)
			lstComPort.Visible = True
			lblSelectPort.Visible = True
		End Sub

		Private Sub lblLocalDeviceAddr_Click(ByVal sender As Object, ByVal e As EventArgs)
			listLocalDeviceAddr.Visible = True
		End Sub

		Private Sub lblLocalMasterAddr_Click(ByVal sender As Object, ByVal e As EventArgs)
			listLocalMasterAddr.Visible = True
		End Sub

		Private Sub lblRemoteOldDeviceAddr_Click(ByVal sender As Object, ByVal e As EventArgs)
			listRemoteOldDeviceAddr.Visible = True
		End Sub

		Private Sub lblRemoteNewDeviceAddr_Click(ByVal sender As Object, ByVal e As EventArgs)
			listRemoteNewDeviceAddr.Visible = True
		End Sub

		Private Sub lblRemoteMasterAddr_Click(ByVal sender As Object, ByVal e As EventArgs)
			listRemoteMasterAddr.Visible = True
		End Sub

		Private Sub listLocalDeviceAddr_SelectedIndexChanged(ByVal sender As Object, ByVal e As EventArgs)
			listLocalDeviceAddr.Visible = False
			lblLocalDeviceAddr.Text = listLocalDeviceAddr.Text
		End Sub

		Private Sub listLocalMasterAddr_SelectedIndexChanged(ByVal sender As Object, ByVal e As EventArgs)
			listLocalMasterAddr.Visible = False
			lblLocalMasterAddr.Text = listLocalMasterAddr.Text
		End Sub

		Private Sub listRemoteMasterAddr_SelectedIndexChanged(ByVal sender As Object, ByVal e As EventArgs)
			listRemoteMasterAddr.Visible = False
			lblRemoteMasterAddr.Text = listRemoteMasterAddr.Text
		End Sub

		Private Sub listRemoteNewDeviceAddr_SelectedIndexChanged(ByVal sender As Object, ByVal e As EventArgs)
			listRemoteNewDeviceAddr.Visible = False
			lblRemoteNewDeviceAddr.Text = listRemoteNewDeviceAddr.Text
		End Sub

		Private Sub listRemoteOldDeviceAddr_SelectedIndexChanged(ByVal sender As Object, ByVal e As EventArgs)
			listRemoteOldDeviceAddr.Visible = False
			lblRemoteOldDeviceAddr.Text = listRemoteOldDeviceAddr.Text
		End Sub

		Private Sub btnSendLocal_Click(ByVal sender As Object, ByVal e As EventArgs)
			Dim tmpPacket As Byte() = {CByte(Convert.ToByte(lblLocalMasterAddr.Text)), CByte(Convert.ToByte(lblLocalDeviceAddr.Text)), CByte(Convert.ToByte(txtLocalWakeUpTime.Text)), 0, 85}
			SendCommand(68, tmpPacket)
			lblLocalMasterAddr.Text = "0"
			lblLocalDeviceAddr.Text = "0"
			txtLocalWakeUpTime.Text = "0"
		End Sub

		Private Sub btnSendRemote_Click(ByVal sender As Object, ByVal e As EventArgs)
			Dim tmpPacket As Byte() = {CByte(Convert.ToByte(lblRemoteOldDeviceAddr.Text)), CByte(Convert.ToByte(lblRemoteMasterAddr.Text)), CByte(Convert.ToByte(lblRemoteNewDeviceAddr.Text)), CByte(Convert.ToByte(txtRemoteWakeUpTime.Text)), 85}
			SendCommand(85, tmpPacket)
			lblRemoteOldDeviceAddr.Text = "0"
			lblRemoteMasterAddr.Text = "0"
			lblRemoteNewDeviceAddr.Text = "0"
			txtRemoteWakeUpTime.Text = "0"
		End Sub

		Private Sub btnIDLE_Click(ByVal sender As Object, ByVal e As EventArgs)
			Dim tmpPacket As Byte() = {0, 0, 0, 1, 85}
			SendCommand(68, tmpPacket)
		End Sub

		Private Sub btnMASTER_Click(ByVal sender As Object, ByVal e As EventArgs)
			Dim tmpPacket As Byte() = {0, 0, 0, 2, 85}
			SendCommand(68, tmpPacket)
		End Sub

		Private Sub btnSLAVE_Click(ByVal sender As Object, ByVal e As EventArgs)
			Dim tmpPacket As Byte() = {0, 0, 0, 3, 85}
			SendCommand(68, tmpPacket)
		End Sub

		Private Sub btnNOICEMAKER_Click(ByVal sender As Object, ByVal e As EventArgs)
			Dim tmpPacket As Byte() = {0, 0, 0, 4, 85}
			SendCommand(68, tmpPacket)
		End Sub

		Private Sub btnGetLocalData_Click(ByVal sender As Object, ByVal e As EventArgs)
			Dim tmpPacket As Byte() = {85, 85, 85, 85, 85}
			SendCommand(17, tmpPacket)
		End Sub
		Private Sub ConvertedAnonymousMethod1()
			rtfTerminal.SelectedText = String.Empty
			rtfTerminal.SelectionFont = New Font(rtfTerminal.SelectionFont, FontStyle.Regular)
			rtfTerminal.SelectionColor = LogMsgTypeColor(0)
			rtfTerminal.AppendText(System.DateTime.Now.ToString("[HH:mm:ss]") + " >> ")
			rtfTerminal.SelectionFont = New Font(rtfTerminal.SelectionFont, FontStyle.Bold)
			rtfTerminal.SelectionColor = LogMsgTypeColor(0)
			rtfTerminal.AppendText(DirectCast(+" ", msg))
			rtfTerminal.SelectedText = String.Empty
			rtfTerminal.SelectionFont = New Font(rtfTerminal.SelectionFont, FontStyle.Regular)
			rtfTerminal.SelectionColor = LogMsgTypeColor(0)
			rtfTerminal.AppendText(CChar(34) + getCommand(msg) + CChar(34) + "" & Chr(10) & "")
			terminalCounter += 1
			rtfTerminal.ScrollToCaret()
		End Sub
		Private Sub ConvertedAnonymousMethod2()
			rtfTerminal.SelectedText = String.Empty
			rtfTerminal.SelectionFont = New Font(rtfTerminal.SelectionFont, FontStyle.Regular)
			rtfTerminal.SelectionColor = LogMsgTypeColor(2)
			rtfTerminal.AppendText(System.DateTime.Now.ToString("[HH:mm:ss]") + " << ")
			rtfTerminal.SelectionFont = New Font(rtfTerminal.SelectionFont, FontStyle.Bold)
			rtfTerminal.SelectionColor = LogMsgTypeColor(2)
			rtfTerminal.AppendText(DirectCast(+" ", msg))
			rtfTerminal.SelectedText = String.Empty
			rtfTerminal.SelectionFont = New Font(rtfTerminal.SelectionFont, FontStyle.Regular)
			rtfTerminal.SelectionColor = LogMsgTypeColor(2)
			rtfTerminal.AppendText(CChar(34) + getCommand(msg) + CChar(34) + "" & Chr(10) & "")
			terminalCounter += 1
			rtfTerminal.ScrollToCaret()
		End Sub


	End Class
End Namespace
