VB.NET Convert USB as RS232 - vb.net

I have a hardware with USB for communicate between computer to hardware. The vendor not giving any APIs to connect to the device. They give me a protocol. But the protocol is serve for RS232 mode. I ask the vendor whether this protocol can be apply to the USB, they said 'YES'.. So, I'm thirst of idea how to use this protocol. Does anyone know? My old friend said yes I can use the USB and treat is as COM which I need to create an object. Create instance of the object which declare as a serialport as below. But it still can't get the status.
Public Sub New(ByVal intComNumber As Integer, ByVal lngBaudRate As Long, ByVal intDataLng As Integer, ByVal intStopBit As Integer, ByVal intParity As Integer)
Try
objUPSPort = New SerialPort
With objUPSPort
.PortName = ("COM" & intComNumber)
.BaudRate = lngBaudRate
.DataBits = intDataLng
.StopBits = intStopBit
.Parity = intParity
.Handshake = Handshake.None
End With
Catch ex As Exception
MsgBox("Error In Init UPSComm")
End Try
End Sub
Can someone help me identified this? This hardware is UPS. A simple command write to the port. But I get the error when get status. Below is the code to write to the UPS.
Public Function GetStatus() As String
Dim strRet As String
Dim strRecv As String
Dim byteRead() As Byte
Try
If Not IsNothing(objUPSPort) Then
objUPSPort.Open()
objUPSPort.WriteLine("Command will be here" & vbCrLf)
For i = 0 To 100000
If objUPSPort.BytesToRead >= 45 Then
Exit For
End If
Next
ReDim byteRead(objUPSPort.BytesToRead)
objUPSPort.Read(byteRead, 0, objUPSPort.BytesToRead)
strRecv = String.Empty
For i = 0 To byteRead.Length - 1
strRecv = strRecv & Chr(byteRead(i))
Next
If byteRead(38) = 48 Then
MsgBox("Power OK")
ElseIf byteRead(38) = 49 Then
MsgBox("Power Off")
Else
MsgBox("Unknown")
End If
strRet = strRecv
Return strRecv
Else
MsgBox("Error In ComPort Object")
Return String.Empty
End If
Catch ex As Exception
MsgBox("Exception In ComPort Object - " & ex.Message)
Return String.Empty
Finally
objUPSPort.Close()
End Try
End Function

I had few experiences in RS232 comm with USB, as nowadays laptops/pc they dont come with serial port no more. Serial ports usually emulated by USB, using [TTL-to-RS232 transistor, MAX like] some common supplier would use prolific as driver to emulate USB-to-RS232. First you need to know the data type, a simple string or binary.
SerialPorts is event driven, data coming thru the ports can trigger events. I assume to get UPS to send you status, first, you need to send command, as such [some pseudo];
objUPSPort.WriteLine("Command will be here" & vbCrLf)
There two ways to get the data:
Using data receive event driven :
Private Sub objUPSPort_DataReceived(sender As Object, e As IO.Ports.SerialDataReceivedEventArgs) Handles objUPSPort.DataReceived
'call ReceiveData()
End Sub
Create a pooling thread to read data periodically
Private Sub threadUPSReceive()
Do
data = objUPSPort.ReadLine() 'for string
'process the data here or call ReceiveData()
Loop
End Sub
If data stream to be read is binary (similar like yours):
Private Function ReceiveData()
Dim bRead As Integer
Dim returnStr As String = vbEmpty
bRead = objUPSPort.BytesToRead 'Number of Bytes to read
Dim cData(bRead - 1) As Byte
For Each b As Byte In cData
returnStr += Chr(b) 'put data stream in readable ascii
Next
Return returnStr
End Sub
One more thing, make sure the baudrate/stopbit/databit is set correctly.
Hope this help.

Related

vb.net - receiving hex data over serial interface

I do have a device, which I communicate with over the serial Interface.
The communication is done in hex, so I send hex and I do receive hex.
Example: if I send "AA 00 03 89 18 0A 98 BB" the device reports back with "AA 00 02 00 80 82 BB".
My aim is to get a hand on the return value in an human readable way, respecively as a string.
The sending works fine, however the receiving is the part where I struggle hard and where I need help.
The sending part:
This is the part where I define the command to send:
Public Class ClassRfidWrapper
Public Function Command(ByVal theCommand As String) As Byte()
'Versuche.
Try
If theCommand = "SetBuzzer" Then
Dim bytes() As Byte = {&HAA, &H0, &H3, &H89, &H18, &HA, &H98, &HBB}
Return bytes
End If
Catch ex As Exception
Console.ForegroundColor = ConsoleColor.Red
Console.WriteLine("Class -> ClassRfidWrapper, Method -> SendCommand, Error -> " & ex.Message)
End Try
Return Nothing
End Function
End Class
This is the part where I send the hex message to the device:
Public Sub MySendSerialData(ByVal data As Byte())
'Versuche.
Try
If MyCheckIfSerialIsConnected() = True Then
'Mitteilung.
Main.MessageObject.MyMessage("message sent to device: ", Bytes_To_String2(data), 3)
'Log [LogWrapperToDevice]
Main.LogObject.MyLog(Bytes_To_String2(data), "LogWrapperToDevice")
SerialInterface.Write(data, 0, data.Length)
End If
Catch ex As Exception
Console.ForegroundColor = ConsoleColor.Red
Console.WriteLine("Class -> ClassSerialInterface, Method -> MySendSerialData, Error -> " & ex.Message)
End Try
End Sub
Do the sending:
SerialInterfaceObject.MySendSerialData(RfidWrapperObject.Command("SetBuzzer"))
Function to convert Hex to string:
Public Function Bytes_To_String2(ByVal bytes_Input As Byte()) As String
Dim strTemp As New StringBuilder(bytes_Input.Length * 2)
For Each b As Byte In bytes_Input
strTemp.Append(Conversion.Hex(b))
Next
Return strTemp.ToString()
End Function
The receiving part:
This is where I have the problems
Public Shared Sub DataReceivedHandler(sender As Object, e As SerialDataReceivedEventArgs)
Dim sp As SerialPort = CType(sender, SerialPort)
Dim data As String = sp.ReadExisting()
'Mitteilung.
Main.MessageObject.MyMessage("incoming serial data: ", CStr(data), 3)
'Log [LogDeviceToWrapper]
Main.LogObject.MyLog(CStr(data), "LogDeviceToWrapper")
End Sub
The problem is, I get garbage...
I understand, that .ReadExisting is the wrong way, as it interprets the received data as string, so I need an example code, of how to receive and convert the data to a byte array containing hex code, which I can subsequently convert to a string with my function Bytes_To_String2
Thanks for your help
Read the response buffer as a byte array.
Public Shared Sub DataReceivedHandler(sender As Object, e As SerialDataReceivedEventArgs)
Dim sp As SerialPort = CType(sender, SerialPort)
Dim respSize As Integer = sp.BytesToRead
Dim respBuffer As Byte() = New Byte(respSize - 1)
comport.Read(respBuffer, 0, respSize)
' Convert to string and additional processing ...
End Sub

TCP Client not receiving all the messages

I am trying to write a small client which will listen to a server on a certain port. When I run my code it seems to hang, then it will only give me the first message and not receive anymore after? Im wrecking my brains here. Any help appreciated.
Option Strict On
Imports System.Net
Imports System.Net.Sockets
Imports System.Text
Public Class Form1
'Form Controls.
Private lblPort As New Label
Private txtPort As New TextBox
Private lblIp As New Label
Private txtIp As New TextBox
Private lblSend As New Label
Private txtSend As New TextBox
Private WithEvents btnConnectSendReceive As New Button
Private lblReceived As New Label
Private lvwReceived As New ListView
Private txtBoxrecieved As New RichTextBox
'Global Objects.
Private gSocket As Socket = Nothing
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
'Setup form controls.
With Me
.Text = "SplitPackManagerTest"
.Controls.Add(lblPort)
.Controls.Add(txtPort)
.Controls.Add(lblIp)
.Controls.Add(txtIp)
.Controls.Add(lblSend)
.Controls.Add(txtSend)
.Controls.Add(btnConnectSendReceive)
.Controls.Add(lblReceived)
.Controls.Add(lvwReceived)
.Controls.Add(txtBoxrecieved)
.Height = 600
End With
With lblPort
.Text = "Port:"
.Location = New Point(12, 12)
.AutoSize = True
End With
With txtPort
.Text = "3001" 'Same port that server is listening on.
.Location = New Point(100, 12)
End With
With lblIp
.Text = "IP:"
.Location = New Point(12, 42)
.AutoSize = True
End With
With txtIp
.Text = "127.0.0.1" 'Loop-back IP address (localhost).
.Location = New Point(100, 42)
End With
With lblSend
.Text = "Send:"
.Location = New Point(12, 72)
.AutoSize = True
End With
With txtSend
.Text = Chr(2) & "(login (term-id 2))" & Chr(3)
.Location = New Point(100, 72)
End With
With btnConnectSendReceive
.Text = "Connect"
.Location = New Point(12, 122)
.Width = 260
End With
With lblReceived
.Text = "Received Bytes:"
.Location = New Point(12, 182)
.AutoSize = True
End With
With lvwReceived
.Height = 100
.Dock = DockStyle.Bottom
.View = View.Details
.GridLines = True
.FullRowSelect = True
.MultiSelect = False
.Scrollable = True
.Columns.Add("Dec")
.Columns.Add("Hex")
.Columns.Add("Chr")
For Each vCol As ColumnHeader In .Columns
vCol.Width = CInt(Math.Floor(.Width / .Columns.Count)) - CInt(Math.Floor(30 / .Columns.Count))
Next
End With
With txtBoxrecieved
.Height = 200
.Dock = DockStyle.Bottom
.ScrollBars = RichTextBoxScrollBars.Both
End With
End Sub
Private Function ConnectSendReceive(ByVal pSendData As Byte(), ByVal pIp As String, ByVal pPort As Integer) As Byte()
'Try creating IP endpoint.
If String.IsNullOrEmpty(pIp) Then Return Nothing
If Not IPAddress.TryParse(pIp, Nothing) Then Return Nothing
Dim vIp As IPAddress = IPAddress.Parse(txtIp.Text)
Dim vEndPoint As New IPEndPoint(vIp, CInt(txtPort.Text))
'Timeout will be 0.5 seconds.
Dim vTimeout As Integer = 500000
'For our little example, we expect all messages to be 1024 bytes or below (arbitrary amount).
Dim vMessageLength As Integer = 1002400000
'Remember, when dimensioning arrays, the integer specified is the upper bounds, not the length.
Dim vServerResponse As Byte() = Nothing
'Initiate socket.
Dim gSocket As New Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp)
'Connect.
Try
gSocket.Connect(vEndPoint)
Catch ex As Exception
Return Nothing
End Try
If Not gSocket.Connected Then Return Nothing
'Send.
'Socket.SendTimeout = vTimeout
gSocket.Send(pSendData)
txtBoxrecieved.AppendText("Sending.. " & txtSend.Text)
'Receive response.
'Socket.ReceiveTimeout = vTimeout
Dim vBuffer(vMessageLength - 1) As Byte
Dim vNumOfBytesReceived As Integer = 0
Try
vNumOfBytesReceived = gSocket.Receive(vBuffer, 0, vMessageLength, SocketFlags.None)
Catch ex As Exception
Return Nothing
End Try
'Return received bytes.
ReDim vServerResponse(vNumOfBytesReceived - 1)
Array.Copy(vBuffer, vServerResponse, vNumOfBytesReceived)
'Disconnect (since we're using a "Using" statement, the socket will be disconnected here without us explicitly doing it).
Return vServerResponse
End Function
Private Sub btnConnectSendReceive_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnConnectSendReceive.Click
'Send message and get response from server.
Dim vServerResponse As Byte() = ConnectSendReceive(Encoding.ASCII.GetBytes(txtSend.Text), txtIp.Text, CInt(txtPort.Text))
'Did we receive a response?
If vServerResponse Is Nothing Then MessageBox.Show("Server not reachable / Received no response from server.") : Exit Sub
'Do something with response.
For Each vByte As Byte In vServerResponse
Dim vLvi As New ListViewItem
With vLvi
'Decimal column.
.Text = vByte.ToString
'Hexidecimal column.
.SubItems.Add(vByte.ToString("X2"))
'Character column.
.SubItems.Add(ChrW(vByte))
End With
With lvwReceived
.Items.Add(vLvi)
.EnsureVisible(.Items.Count - 1)
End With
Next
txtBoxrecieved.AppendText(UnicodeBytesToString(vServerResponse))
End Sub
Private Function UnicodeBytesToString(
ByVal bytes() As Byte) As String
Return System.Text.Encoding.ASCII.GetString(bytes)
End Function
End Class
THanks
David
You need to know what's happening on both sides of this conversation. To do that, you need to listen in with a tool like Wireshark. Download Wireshark and learn to use it.
The reason I tend to agree with the_lotus is that the very large buffer you have allocated (ignoring the likely sizing bug) implies that you are expecting a fairly large response. Packet payloads can be up to 64KB but that's uncommon and even if such a thing occurs the protocol allows for fragmentation en route.
So if the data is split over several packets you'll need to keep reading until you have a complete payload. This may entail looking for boundary markers in a stream, and if there's a possibility of receiving more payloads over the same connection you'll need to preserve the start of the next payload in a way that allows you to accumulate the rest of it.
If you do that you will probably see a complete packet with a partial payload, as described by the_lotus in a comment posted while I was still writing.
I think he's probably right, but he could also be wrong, and a tool like Wireshark will allow you to find out, instead of guessing and hacking your code around in a blind attempt to validate your hypotheses.
The style of I/O that you are using is called polling. Sometimes it's necessary to do it that way, eg embedded systems often don't support anything more sophisticated, there isn't space for it. But on a system with a full .NET framework you really ought to use IOCP. It's not strictly necessary for a single user app, but if you pick up the right habits you won't create scalability problems.
OK, as to why the response is truncated, after examining your code (VB makes my eyes hurt) I'm almost sure the_lotus is right. You are reading exactly once from the socket and then you are closing it without any attempt to check whether you have the entire response or any attempt to read more data.
This looks like a first year university assignment, so presumably you have some sort of specification. To determine whether you have the entire response you need to know either one of the following
an expected payload length
the location and structure of data in the payload telling you how long the remainder is (or sometimes the size of the total packet)
an end of payload marker, this will be a particular sequence of bytes guaranteed not to otherwise occur in the payload.
Some pseudocode
open the connection
while not CheckForCompletePayload(buffer)
read some data and append it to your buffer
close the connection.

Using ThreadPool to connect to multiple TCP servers simultaneously

Imports System.IO
Imports System.Threading
Imports System.Net.Sockets
Imports System.Text
Module Module1
<MTAThread()>
Sub Main()
Dim maxthreads As Integer = 10
ThreadPool.SetMaxThreads(maxthreads, maxthreads)
Dim serverlist() As String = File.ReadAllLines("final.txt")
Dim servernum As New CountdownEvent(serverlist.GetUpperBound(0) + 1)
For Each a In serverlist
Dim args(1) As Object
args(0) = a
args(1) = servernum
ThreadPool.QueueUserWorkItem(New WaitCallback(AddressOf ping), args)
Next
servernum.Wait()
Console.ReadLine()
End Sub
Public Sub ping(ByVal server() As Object)
Dim serverinfo() As String = Split(server(0), ",")
Dim socketclient As New TcpClient
Console.WriteLine(serverinfo(0))
Try
socketclient.Connect(serverinfo(0), serverinfo(1))
Catch ex As Exception
If socketclient.Connected = False Then
Throw New Exception("Server Offline")
Else
Throw New Exception("Unknown Error Occured")
End If
End Try
Dim stream As NetworkStream = socketclient.GetStream
stream.ReadTimeout = 1000
stream.WriteTimeout = 1000
Dim sendBytes As [Byte]() = {&HFE}
stream.Write(sendBytes, 0, sendBytes.Length)
Dim bytes(421) As Byte
stream.Read(bytes, 0, CInt(421))
socketclient.Close()
Dim trimbytes(bytes.Length - 3) As Byte
Array.Copy(bytes, 3, trimbytes, 0, bytes.Length - 3)
Dim returndata As String = Encoding.BigEndianUnicode.GetString(trimbytes)
Dim sb As New System.Text.StringBuilder
For i As Integer = 1 To 241 Step 2
If trimbytes(i) <> 0 Then
sb.Append(ChrW(BitConverter.ToInt16(trimbytes, i)))
End If
Next i
Dim message() As String = sb.ToString.Split("ยง")
'Write processed server information to the console
Console.WriteLine("Received -->" & message(1) & " " & message(2) & " | " & serverinfo(0))
server(1).signal()
End Sub
End Module
Above is my code, what I basically want to do is to get two (or more) ips from the text file, connect to both of them via TCP on two different threads and get the responses from the servers.
Now, the problem here is that; for whatever reason one of the two servers get a response but the other doesn't. I've made sure both of the servers are online and accepting connections. I've also tried having the same server on both lines of the text file so that the same ip is being used on both threads but this doesn't work either. Even when the two ips are the same, one gets a response but not the other; which must mean I'm doing something horribly wrong.
When I use one server rather than 1+ everything works perfectly and I get the response I'm looking for, anything more than 1 and it looks like the first thread that runs produces the response but not anything that runs later. Any help will be appreciated.
I have also tried using Paarallel.For but ended up running into the same issue.
Parallel.ForEach(serverlist, _
Sub(currentElement)
ping(currentElement)
End Sub)

Test telnet communication on remote computer using VB.net?

I have a central server and I need to write a bit of vb.net which will see if I can telnet to a specified server on a specified port.
Is there anyway this can be done in VB.net? I thought about sending command prompts to the remote server to execute telnet, then output the logs of netsh and read those and send the information back to the central server for review.
Its a very messy way of doing it, so I was just wondering if there was an easier way
You should just create a TcpClient object with the IP address of the target server and port (typically 23 for telnet). Then call Connect!
See here for more info:
http://msdn.microsoft.com/en-us/library/system.net.sockets.tcpclient.aspx
Something like this (may not be exact):
Try
Dim telnetServerIp As String = "192.168.100.55"
Dim telnetPort As Integer = 23
Dim client As New TcpClient(telnetServerIp, telnetPort)
MessageBox.Show("Server is reachable")
Catch ex As Exception
MessageBox.Show("Could not reach server")
End Try
Be advised this is sample code. You'd want to clean up (close/dispose) the connection (TcpClient) object when you were done, etc. But it should get you started.
You should try something to implement this. there are lots help available for Telnet communication using .net.
Take idea from these specified links and implement in vb.net..
How can I open a telnet connection and run a few commands in C#
Telnet connection using .net
You can use a System.Net.Sockets.TcpClient object instead of a
socket object, which already has the socket parameters configured to
use ProtocolType.Tcp
1.Create a new TcpClient object, which takes a server name and a port (no IPEndPoint necessary, nice).
2.Pull a NetworkStream out of the TcpClient by calling GetStream()
3.Convert your message into bytes using Encoding.ASCII.GetBytes(string)
4.Now you can send and receive data using the stream.Write and stream.Read methods, respectively. The stream.Read method returns the number of bytes written to your receiving array, by the way.
5.Put the data back into human-readable format using Encoding.ASCII.GetString(byte array).
6.Clean up your mess before the network admins get mad by calling stream.Close() and client.Close().
Ref:C# 2.0* and Telnet - Not As Painful As It Sounds
// Create a TcpClient.
// Note, for this client to work you need to have a TcpServer
// connected to the same address as specified by the server, port
// combination.
Int32 port = 13000;
TcpClient client = new TcpClient(server, port);
// Translate the passed message into ASCII and store it as a Byte array.
Byte[] data = System.Text.Encoding.ASCII.GetBytes(message);
// Get a client stream for reading and writing.
// Stream stream = client.GetStream();
NetworkStream stream = client.GetStream();
// Send the message to the connected TcpServer.
stream.Write(data, 0, data.Length);
Console.WriteLine("Sent: {0}", message);
I made this for a project at work.
I think it's a complete general solution for most people's needs
However, This is my first real .net project so feel free to critique it.
Modeled on http://www.codeproject.com/Articles/63201/TelnetSocket
Imports System.Threading
Imports System.IO
Imports System.IO.Pipes
Public Class TelnetClient
Private Server As String
Private NetWorkProtocolClient As System.Net.Sockets.TcpClient
Private ServerStream As System.Net.Sockets.NetworkStream
Private DoReader As Boolean
Private ReaderThread As Thread
Private OutputPipe As AnonymousPipeServerStream
Private WaitForString As String
Private WaitForStringEvent As New AutoResetEvent(False)
ReadOnly Property IsConnected() As Boolean
Get
Return (Not (IsNothing(NetWorkProtocolClient)) AndAlso (NetWorkProtocolClient.Connected))
End Get
End Property
ReadOnly Property ConnectedTo() As String
Get
If (Not (IsNothing(NetWorkProtocolClient)) AndAlso (NetWorkProtocolClient.Connected)) Then
Return NetWorkProtocolClient.Client.RemoteEndPoint.ToString()
Else
Return "Nothing"
End If
End Get
End Property
'Set the Server string to connect to.
Public Sub SetServer(ByVal new_server As String)
'double check this later
Server = new_server
End Sub
'Connects if possilbe. If already conneced to some thing it Disconnects from old Telnet and connects to new Telnet.
Public Sub Connect()
Try
If (Not (IsNothing(NetWorkProtocolClient))) AndAlso NetWorkProtocolClient.Connected Then
Disconnect()
End If
If Not IsNothing(Server) Then
NetWorkProtocolClient = New System.Net.Sockets.TcpClient(Server, 23)
If NetWorkProtocolClient.Connected Then
'clear on a new client
WaitForString = Nothing
WaitForStringEvent.Reset()
NetWorkProtocolClient.NoDelay = True
ServerStream = NetWorkProtocolClient.GetStream()
ServerStream.ReadTimeout = 1000
DoReader = True
ReaderThread = New Thread(AddressOf ReaderTask)
ReaderThread.IsBackground = True
ReaderThread.Priority = ThreadPriority.AboveNormal
ReaderThread.Start()
End If
End If
Catch ex As System.Net.Sockets.SocketException
Console.WriteLine("SocketException Connect: {0}", ex)
End Try
End Sub
'Disconnects if connected, otherwise does nothing.
Public Sub Disconnect()
Try
If ReaderThread.IsAlive Then
DoReader = False
ReaderThread.Join(1000)
End If
If (Not (IsNothing(NetWorkProtocolClient))) Then
ServerStream.Close()
NetWorkProtocolClient.Close()
End If
Catch ex As System.Net.Sockets.SocketException
Console.WriteLine("SocketException Disconnect: {0}", ex)
End Try
End Sub
'Returns true if found before timeout milliseconds. Use -1 to have infinite wait time.
'Returns false if timeout occured.
Public Function WaitFor(ByVal command As String, ByVal timeout As Integer) As Boolean
WaitForString = New String(command)
WaitForStringEvent.Reset()
Dim was_signaled As Boolean = False
'Block until a the right value from reader or user defined timeout
was_signaled = WaitForStringEvent.WaitOne(timeout)
WaitForString = Nothing
Return was_signaled
End Function
Public Sub Write(ByVal command As String)
Try
If (Not (IsNothing(NetWorkProtocolClient))) Then
If NetWorkProtocolClient.Connected Then
'Write the value to the Stream
Dim bytes() As Byte = System.Text.Encoding.ASCII.GetBytes(command)
SyncLock ServerStream
ServerStream.Write(bytes, 0, bytes.Length)
End SyncLock
End If
End If
Catch ex As System.Net.Sockets.SocketException
Console.WriteLine("SocketException Write: {0}", ex)
End Try
End Sub
'appends CrLf for the caller
Public Sub WriteLine(ByVal command As String)
Try
If (Not (IsNothing(NetWorkProtocolClient))) Then
If NetWorkProtocolClient.Connected Then
'Write the value to the Stream
Dim bytes() As Byte = System.Text.Encoding.ASCII.GetBytes(command & vbCrLf)
SyncLock ServerStream
ServerStream.Write(bytes, 0, bytes.Length)
End SyncLock
End If
End If
Catch ex As System.Net.Sockets.SocketException
Console.WriteLine("SocketException Write: {0}", ex)
End Try
End Sub
'Get a pipe to read output. Note: anything written by WriteLine may be echoed back if the other Telnet offers to do it.
Public Function GetPipeHandle() As String
If Not IsNothing(ReaderThread) AndAlso ReaderThread.IsAlive AndAlso Not IsNothing(OutputPipe) Then
Return OutputPipe.GetClientHandleAsString
Else
Return Nothing
End If
End Function
'Task that watches the tcp stream, passes info to the negotiation function and signals the WaitFor task.
Private Sub ReaderTask()
Try
OutputPipe = New AnonymousPipeServerStream(PipeDirection.Out)
Dim prevData As New String("")
While (DoReader)
If (Not (IsNothing(NetWorkProtocolClient))) Then
If ServerStream.DataAvailable Then
'Grab Data
Dim data As [Byte]() = New [Byte](NetWorkProtocolClient.ReceiveBufferSize) {}
Dim bytes As Integer = ServerStream.Read(data, 0, data.Length)
'Negotiate anything that came in
bytes = Negotiate(data, bytes)
If (bytes > 0) Then
'append previous to the search sting incase messages were fragmented
Dim s As New String(prevData & System.Text.ASCIIEncoding.ASCII.GetChars(data))
'If Pipe is connected send it remaining real data
If OutputPipe.IsConnected Then
OutputPipe.Write(data, 0, bytes)
End If
'Check remaining against WaitForString
If Not IsNothing(WaitForString) Then
If s.Contains(WaitForString) Then
WaitForStringEvent.Set()
'clear prevData buffer because the WaitForString was found
prevData = New String("")
Else
'Nothing found make the current string part of the next string.
prevData = New String(s)
End If
Else
prevData = New String("")
End If
End If
Else
Thread.Sleep(100)
End If
End If
End While
OutputPipe.Close()
OutputPipe.Dispose()
Catch ex As System.IO.IOException
Console.WriteLine("IO Error: {0}", ex)
Catch ex As System.Net.Sockets.SocketException
Console.WriteLine("SocketException Reader: {0}", ex)
End Try
End Sub
'Shamelessly adapted from http://www.codeproject.com/Articles/63201/TelnetSocket
'The basic algorithm used here is:
' Iterate across the incoming bytes
' Assume that an IAC (byte 255) is the first of a two- or three-byte Telnet command and handle it:
' If two IACs are together, they represent one data byte 255
' Ignore the Go-Ahead command
' Respond WONT to all DOs and DONTs
' Respond DONT to all WONTs
' Respond DO to WILL ECHO and WILL SUPPRESS GO-AHEAD
' Respond DONT to all other WILLs
' Any other bytes are data; ignore nulls, and shift the rest as necessary
' Return the number of bytes that remain after removing the Telnet command and ignoring nulls
Private Function Negotiate(ByVal data As Byte(), ByVal length As Int32) As Int32
Dim index As Int32 = 0
Dim remaining As Int32 = 0
While (index < length)
If (data(index) = TelnetBytes.IAC) Then
Try
Select Case data(index + 1)
Case TelnetBytes.IAC
data(remaining) = data(index)
remaining += 1
index += 2
Case TelnetBytes.GA
index += 2
Case TelnetBytes.WDO
data(index + 1) = TelnetBytes.WONT
SyncLock ServerStream
ServerStream.Write(data, index, 3)
End SyncLock
index += 3
Case TelnetBytes.DONT
data(index + 1) = TelnetBytes.WONT
SyncLock ServerStream
ServerStream.Write(data, index, 3)
End SyncLock
index += 3
Case TelnetBytes.WONT
data(index + 1) = TelnetBytes.DONT
SyncLock ServerStream
ServerStream.Write(data, index, 3)
End SyncLock
index += 3
Case TelnetBytes.WILL
Dim action As Byte = TelnetBytes.DONT
Select Case data(index + 2)
Case TelnetBytes.ECHO
action = TelnetBytes.WDO
Case TelnetBytes.SUPP
action = TelnetBytes.WDO
End Select
data(index + 1) = action
SyncLock ServerStream
ServerStream.Write(data, index, 3)
End SyncLock
index += 3
End Select
Catch ex As System.IndexOutOfRangeException
index = length
End Try
Else
If (data(index) <> 0) Then
data(remaining) = data(index)
remaining += 1
End If
index += 1
End If
End While
Return remaining
End Function
Private Structure TelnetBytes
'Commands
Public Const GA As Byte = 249
Public Const WILL As Byte = 251
Public Const WONT As Byte = 252
Public Const WDO As Byte = 253 'Actually just DO but is protected word in vb.net
Public Const DONT As Byte = 254
Public Const IAC As Byte = 255
'Options
Public Const ECHO As Byte = 1
Public Const SUPP As Byte = 3
End Structure
End Class

Sending UDP data including hex using VB.NET

As a hobby I'm interesting in programming an Ethernet-connected LED sign to scroll messages across a screen. But I'm having trouble making a UDP sender in VB.NET (I am using 2008 currently).
Now the sign is nice enough to have a specifications sheet on programming for it.
But an example of a line to send to it (page 3):
<0x01>Z30<0x02>AA<0x06><0x1B>0b<0x1C>1<0x1A>1This message will show up on the screen<0x04>
With codes such as <0x01> representing the hex character.
Now, to send this to the sign I need to use UDP. However, the examples I have all encode the message as ASCII before sending, like this one (from UDP: Client sends packets to, and receives packets from, a server):
Imports System.Threading
Imports System.Net.Sockets
Imports System.IO
Imports System.Net
Public Class MainClass
Shared Dim client As UdpClient
Shared Dim receivePoint As IPEndPoint
Public Shared Sub Main()
receivePoint = New IPEndPoint(New IPAddress(0), 0)
client = New UdpClient(8888)
Dim thread As Thread = New Thread(New ThreadStart(AddressOf WaitForPackets))
thread.Start()
Dim packet As String = "client"
Console.WriteLine("Sending packet containing: ")
'
' Note the following line below, would appear to be my problem.
'
Dim data As Byte() = System.Text.Encoding.ASCII.GetBytes(packet)
client.Send(data, data.Length, "localhost", 5000)
Console.WriteLine("Packet sent")
End Sub
Shared Public Sub WaitForPackets()
While True
Dim data As Byte() = client.Receive(receivePoint)
Console.WriteLine("Packet received:" & _
vbCrLf & "Length: " & data.Length & vbCrLf & _
System.Text.Encoding.ASCII.GetString(data))
End While
End Sub ' WaitForPackets
End Class
To output a hexcode in VB.NET, I think the syntax may possibly be &H1A - to send what the specifications would define as <0x1A>.
Could I modify that code, to correctly send a correctly formated packet to this sign?
The answers from Grant (after sending a packet with hex in it), Hamish Smith (using a function to get hex values), and Hafthor (hardcoded chr() message into example) when attempted all did not work. So I'll research to see what else could go wrong. In theory, if this string is sent successfully, I should have a message containing "OK" back, which will help to know when it works.
I have tried and am now able to monitor the packets going through. A working packet example is this (in raw hex): http://www.brettjamesonline.com/misc/forums/other/working.raw vs my version: http://www.brettjamesonline.com/misc/forums/other/failed.raw. The difference is my hex codes are still not encoded correctly, seen in this side-by-side image: http://www.brettjamesonline.com/misc/forums/other/snapshotcoding.png.
I have used this code to generate the packet and send it:
container = &H1 & "Z" & &H30 & &H2 & "temp.nrg" & &H1C & "1Something" & &H4
' This did not appear to work neither
'container = Chr(&H1) & "Z" & Chr(&H30) & Chr(&H2) & Chr(&H1C) & "1Something" & Chr(&H4)
'<0x01>Z00<0x02>FILENAME<0x1C>1Test to display<0x04> <- the "official" spec to send
Dim sendBytes As [Byte]() = Encoding.ASCII.GetBytes(container)
(Full snippet: http://pastebin.com/f44417743.)
You could put together a quickie decoder like this one:
Function HexCodeToHexChar(ByVal m as System.Text.RegularExpressions.Match) As String
Return Chr(Integer.Parse(m.Value.Substring("<0x".Length, 2), _
Globalization.NumberStyles.HexNumber))
End Function
then use this to transform:
Dim r As New System.Text.RegularExpressions.Regex("<0x[0-9a-fA-F]{2}>")
Dim s As String = r.Replace("abc<0x44>efg", AddressOf HexCodeToHexChar)
' s should now be "abcDefg"
you could also make an encoder function that undoes this decoding (although a little more complicated)
Function HexCharToHexCode(ByVal m As Match) As String
If m.Value.StartsWith("<0x") And m.Value.EndsWith(">") And m.Value.Length = "<0x??>".Length Then
Return "<0<0x78>" + m.Value.Substring("<0x".Length)
ElseIf Asc(m.Value) >= 0 And Asc(m.Value) <= &HFF Then
Return "<0x" + Right("0" + Hex(Asc(m.Value)), 2) + ">"
Else
Throw New ArgumentException("Non-SBCS ANSI characters not supported")
End If
End Function
and use this to transform:
Dim r As New Regex("[^ -~]|<0x[0-9a-fA-F]{2}>")
Dim s As String = r.Replace("abc"+chr(4)+"efg", AddressOf HexCharToHexCode)
' s should now be "abc<0x04>efg"
or you could just build the string with the special characters in it to begin with like this:
Dim packet As String = Chr(&H01) + "Z30" + Chr(&H02) + "AA" + Chr(&H06) + _
Chr(&H1B) + "0b" + Chr(&H1C) + "1" + Chr(&H1A) + _
"1This message will show up on the screen" + Chr(&H04)
for sending a UDP packet, the following should suffice:
Dim i As New IPEndPoint(IPAddress.Parse("192.168.0.5"), 3001) ''//Target IP:port
Dim u As New UdpClient()
Dim b As Byte() = Encoding.UTF8.GetBytes(s) ''//Where s is the decoded string
u.Send(b, b.Length, i)
This might help. At my company we have to communicate with our hardware using sort of a combination of ascii and hex.
I use this function to hexify ip addresses before sending them to the hardware
Public Function HexFromIP(ByVal sIP As String)
Dim aIP As String()
Dim sHexCode As String = ""
aIP = sIP.Split(".")
For Each IPOct As String In aIP
sHexCode += Hex(Val(IPOct)).PadLeft(2, "0")
Next
Return sHexCode
End Function
And occationally I use hexSomething = Hex(Val(number)).PadLeft(2,"0") as well.
I can give you the source for the whole program too, though it's designed to talk to different hardware.
EDIT:
Are you trying to send packets in hex, or get packets in hex?
The UDP client sends an array of bytes.
You could use a memory stream and write bytes to an array.
Public Class MainClass
Shared client As UdpClient
Shared receivePoint As IPEndPoint
Public Shared Sub Main()
receivePoint = New IPEndPoint(New IPAddress(0), 0)
client = New UdpClient(8888)
Dim thread As Thread = New Thread(New ThreadStart(AddressOf WaitForPackets))
thread.Start()
Dim packet As Packet = New Packet("client")
Console.WriteLine("Sending packet containing: ")
Dim data As Byte() = packet.Data
client.Send(data, data.Length, "localhost", 5000)
Console.WriteLine("Packet sent")
End Sub
Public Shared Sub WaitForPackets()
While True
Dim data As Byte() = client.Receive(receivePoint)
Console.WriteLine("Packet received:" & _
vbCrLf & "Length: " & data.Length & vbCrLf & _
System.Text.Encoding.ASCII.GetString(data))
End While
End Sub ' WaitForPackets
End Class
Public Class Packet
Private _message As String
Public Sub New(ByVal message As String)
_message = message
End Sub
Public Function Data() As Byte()
Dim ret(13 + _message.Length) As Byte
Dim ms As New MemoryStream(ret, True)
ms.WriteByte(&H1)
'<0x01>Z30<0x02>AA<0x06><0x1B>0b<0x1C>1<0x1A>1This message will show up on the screen<0x04>
ms.Write(System.Text.Encoding.ASCII.GetBytes("Z30"), 0, 3)
ms.WriteByte(&H2)
ms.Write(System.Text.Encoding.ASCII.GetBytes("AA"), 0, 2)
ms.WriteByte(&H6)
ms.Write(System.Text.Encoding.ASCII.GetBytes("0b"), 0, 2)
ms.WriteByte(&H1C)
ms.Write(System.Text.Encoding.ASCII.GetBytes("1"), 0, 1)
ms.WriteByte(&H1A)
ms.Write(System.Text.Encoding.ASCII.GetBytes(_message), 0, _message.Length)
ms.WriteByte(&H4)
ms.Close()
Data = ret
End Function
End Class
They posted libraries for a bunch of languages including Visual Basic (in the separate file). I tested the demos out with one of their signs and they work!
http://support.favotech.com