I have one device which gives data in non printable characters through serial port. I am converting the data to Hex by using Encoding(to get byte array of data) and then BitConverter.ToString()(to get the Hex String). But I am getting different hex value for the same data in Real Term(TCP Terminal). I need the value which is coming in Real Term. How do I do?
Ex: Data - "\t\0î\0\0\u0098$VeW",
My hex- 0900EE00003F24566557,
In Real Term - 0900EE00009824566557.
I have tried all types of Encoding.
Code:-
public void port_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
Thread.Sleep(10);
string recievedData = port.ReadExisting();
}
The problem is that you're trying to read binary data as if it's text. Don't use the ReadExisting() call - use Read(byte[], int, int):
public void HandleDataReceived(object sender, SerialDataReceivedEventArgs e)
{
byte[] data = new byte[port.BytesToRead];
int bytesRead = port.Read(data, 0, data.Length);
if (bytesRead != data.Length)
{
throw new IOException("Unable to read advertised number of bytes");
}
}
Related
I am designing a terminal program which shows the transferred data for some comm. protocols. Data comes through UDP (or TCP) to the PC form application and writing it to richTextBox. I get the UDP data in byte[] format and convert it to string to show on textbox. However conversion is too slow for streaming applications. Are there any other fast solution?
private void Receive(IAsyncResult ar)
{
IPEndPoint ip = new IPEndPoint(ipadress, port);
byte[] bytes = udp.EndReceive(ar, ref ip); // Get actual data
if (binary format) // Convert to bytes to binary for textbox
{
//This conversion is slow
string data = string.Join( " ",
bytes.Reverse().Select( x => Convert.ToString( x, 2 ).PadLeft( 8, '0' ) )
this.Invoke(new(MethodInvoker(delegate
{
textDisplay.Text += "\nReceived Data: " + data;
}));
);
else if (ascii format) // Convert to bytes to ascii
{
string data = Encoding.ASCII.GetString(bytes);
this.Invoke(new(MethodInvoker(delegate
{
textDisplay.Text += "\nReceived Data: " + data;
}));
}
UdpReceive(); // Calls itself again from one upper method
}
...further formats can be added...
bytes to binary string conversion sounds a bit odd to me, because i have actual binary data in byte format which is 8 bit however i cant get it without conversion..
I am trying to use ReadExisting method under the serial port. the method return for me a string. however I want to convert this data into bytes.
the sender sends me bytes witout encoding.
however when I am trying to use the ReadExisting method and convert it to bytes I am not getting the exact bytes. (closer but no all of them are translate it correctly.
I tried to use get bytes in Encoding (tried UTF8,ASCII and others) however didn't find the correct one. how can I know which encoding it does?
private void _serialPort_DataReceived(object sender,
SerialDataReceivedEventArgs e)
{
int BytesToRead = _serialPort.BytesToRead;
if (BytesToRead > 1)
{
string tmpExist = _serialPort.ReadExisting();
SerialInfo _SerialInfo = new SerialInfo();
byte[] tmpData = Encoding.ASCII.GetBytes(tmpExist); //
System.Text.Encoding.ASCII.GetBytes(tmpExist);
}
Thanks
I believe the serial port .Encoding property will get you what you are after. It has been a few years, but I think that was it.
My existing code:
private void ConvertAndSend_Click(object sender, EventArgs e)
{
if (serialPort.IsOpen)
{
byte[] TxBuffer = new byte[240];
string[] coords = textBox1.Text.Split('\n');
for (int i = 0; i <= coords.Length - 1; i++)
{
if (coords[i].Length > 0)
{
Data = GetValue(coords[i]);
}
}
TxBuffer[0] = 0x5A;
TxBuffer[1] = Instruction;
TxBuffer[2] = (byte)Data.Length;
Data.CopyTo(TxBuffer, 3);
TxBuffer[Data.Length + 3] = 0x2C;
serialPort.Write(TxBuffer, 0, 4 + Data.Length);
}
}
Now I am sending every "Data" in separate "Txbuffer". e.g. if I have more than one "Data", I am going to send more than one "Txbuffer". How can I combine all "Data" into one "Txbuffer" and send at one time?
It isn't exactly "wrong", although a magic number like 240 doesn't win any prizes. You can also use BinaryWriter, pass the SerialPort.BaseStream to its constructor.
Keep in mind that serial ports implement streams, not 'packets'. Just a raw train of bytes with no distinctive beginning and end. Just like TCP. There is no framing protocol unless you create your own. Which you did. It is up to the receiver to turn the stream of bytes back into a frame. That same requirement doesn't exist when you transmit it.
Here is my method for sending data:
// this method serializes an object and is returned as a string (Base64 encoded)
public void Send(Packet packetData)
{
try
{
StreamWriter w = new StreamWriter(cli.GetStream());
string s = SerializeObject(packetData);
w.WriteLine(s + "\n");
w.Flush();
}
catch (ObjectDisposedException) { ShutdownClient(-2); }
}
cli is TcpClient object
Packet is a serializable object
Here's my receive method:
private string GetMessage(StreamReader r)
{
try
{
string s = r.ReadLine();
s = s.Replace(" ", "");
// this string is returned and then deserialized
return s;
}
catch (Exception e) { System.Windows.Forms.MessageBox.Show(e.Message); return null; }
}
When I use this, 50% of the time it works. If it doesn't work, it's because of this:
"The input stream is not a valid binary format. The starting contents (in bytes) are: 6D-2E-44-72-61-77-69-6E-67-2E-43-6F-6C-6F-72-0F-00 ..."
I have tried using Encoding.Default.GetString/GetBytes in replacement of Base64, but then I get this:
"Binary stream '0' does not contain a valid BinaryHeader. Possible causes are invalid stream or object version change between serialization and deserialization."
If I print out the length of this (Default encoded) string, it is 183. But if I print out the actual string, nothing is printed.
How else can I send a byte[] as a string over StreamWriter?
How else can I send a byte[] as a string
Not the way you do it now, the byte[] content will get corrupted when the string is normalized. A string should only ever be used to store Unicode characters. Not every Unicode codepoint is valid.
If using a string is paramount then you should use Convert.ToBase64String() at the transmitter, Convert.FromBase64String() at the receiving end.
Do keep in mind that TCP is entirely capable of transferring binary data. You possibly fell into this hole because TCP implements a stream, it doesn't do anything to help you transmit messages. The simple way to transfer a binary 'message' is to first write the Length of the byte[]. The receiver first read that length, then knows what it should pass to the Read() call to recover the byte[] back from the TCP stream.
I'm talking serially to a Smart Motor and I'm trying to look for the specific string "# Positon" coming back from the motor. When I see that I want to set the Play button to be enabled (btnPlay.Enabled=true;).
I've tried every way but can't seem to fit it to the following code. What can I place in my code below where I can test the incoming data and then trigger the enable?
The following code works - I just don't know where and how to read for specific information.
private void port_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
// If the com port has been closed, do nothing
if (!comport.IsOpen) return;
// Determain which mode (string or binary) the user is in
if (CurrentDataMode == DataMode.Text)
{
// Read all the data waiting in the buffer
string data = comport.ReadExisting();
// Display the text to the user in the terminal
Log(LogMsgType.Incoming, data);
}
else
{
// Obtain the number of bytes waiting in the port's buffer
int bytes = comport.BytesToRead;
// Create a byte array buffer to hold the incoming data
byte[] buffer = new byte[bytes];
// Read the data from the port and store it in our buffer
comport.Read(buffer, 0, bytes);
// Show the user the incoming data in hex format
Log(LogMsgType.Incoming, ByteArrayToHexString(buffer));
}
}