so I am trying to send some bytes with hex values to setup my microcontroller on the other side of Serial Port. The thing is I am not quite sure how to properly do it and in what format to send them. For example I need to send two bytes and their hex values are 57 and B0. When I try to send it as a char array and I read it back I always get the ASCII Hex values of those characters like 53 and then 55 for the value 57. So I wanted to format the hex value as a byte and send both of them at the same time from byte array but I am not getting anything when reading the response. After formatting it to byte, the MessageBox is showing it's decimal value and I don't know if it supposed to be like that. I am providing my code below.
Info_Byte_Dec += Protocol_Set + Protocol_Unit + Protocol_Write + Protocol_Settings; //stores decimal value
Data_Byte_Dec = Mode * Protocol_Mode_Offset + ODR * Protocol_ODR_Offset + Scale; //stores decimal value
Info_Byte_Hex = Info_Byte_Dec.ToString("X"); //convert to hex value
Data_Byte_Hex = Data_Byte_Dec.ToString("X"); //convert to hex value
string Merged = $"{Info_Byte_Hex} {Data_Byte_Hex}";
MessageBox.Show("Merged1: " + Merged);
byte[] Mergedbytes = Merged.Split(' ').Select(s => Convert.ToByte(s, 16)).ToArray();
MessageBox.Show("Merged2: " + Mergedbytes[0] + Mergedbytes[1]);
port.Write(Mergedbytes, 0, 2);
I am not sure whether I should just send the decimal value 87, or I should format it to 57 hex value, or even to 0x57.
usually in the microcontroller world when you use hex, you mean actual bytes, the hex is just a convenient notation to write binary byte values in, it usually never means send the ascii hex values. Having said that, there are no rules, and sometimes people do actual ascii hex.
In your case, if you are using 0x57 on the stm32, it likely means you are using a byte literal, and not a ascii representation. You would have to do extra work to turn a 0x57 into a string.
So that means in C# just send bytes, not the ascii hex like you are at the moment
Related
I am receiving data from a cnc machine every 5 seconds. Length of the data is 66 bytes. And every two byte has a special meaning according to the guide that I have. The device sends the data over socket to a specific ip and port. I have been told that I should read the data as hex instead of ascii.
This line of code returns
string data = Encoding.ASCII.GetString(data.buffer,0,66);
this;
"\0\u0004\0\u0001\0\0\0\0\0\0\0\0\0\0\0\0\0\r\0\r\0\0\0\0\0\0:a\u0002#\0?\0`\u001b?\u0015U\0\0\0\0\u0001\u0010\0\u0018\0\0\u000f\a\0\0\0\0\0\0\0\0\0\0\0\0\0\0u/"
and of course it is not useful to me.
I did tried to convert byte array to the hex string with that code;
StringBuilder sb = new StringBuilder();
foreach (byte b in buffer)
sb.Append(b.ToString("X2"));
string hexString = sb.ToString();
And got result as
00040001000000000000000000020000000000000000000000003A9D023F00A000601B841555000000000110001800000F070000000000000000000000000000752F
And when I try to convert this result as string, no success, nothing meaningfull.
GOAL
What I am trying to achieve is, read the incoming socket data as hex and use every two byte as a word to match a value. For example first 2 byte should match either 0 or 1. With i have it returns ? (question mark)
Thank you.
I have been told that I should read the data as hex instead of ascii
My gut feeling is this statement has been misquoted or misunderstood. There is no value in processing binary data as string hex representation just as there is no value in converting it to ascii... The only sane way to process binary data, is in binary unless you have a meaningful way to convert it.
You mention you need word (2byte) groupings, you could just convert this to an array of short, or ushort depending on your needs
var bytes = new byte[66];
var shortArray = new short[bytes.Length / 2];
Buffer.BlockCopy(bytes, 0, shortArray, 0, bytes.Length);
or
for (int i = 0; i < shortArray.Length; i++)
shortArray[i] = BitConverter.ToInt16(bytes[(i*2)..(i*2+2)]);
Disclaimer : This is just an example, be very careful of the endianess of your data, there are other ways to do this
I'm working on a program in VS2010 C#. It has a GUI that is used to interact with an Arduino over the serial port.
The issue that I'm having is sending a byte value larger than 128(???) from the arduino to the program. I get an integer value on the arduino, break it into highBite and lowByte, and send each one, the reassemble on the other side.
If I send 600, it will send highByte of 2 and lowByte of 88, and it reassembles to 600 properly via bitshiting <<8 of highByte.
If I try to send 700 which should be 188 and 2, then I am seeing the 188 show in in C# as 63. Why???
A byte should be unsigned on both arduino and C#, so I'm not sure what is going wrong.
Arduino code (relevant parts): (0x43 signals to C# which data packet it is receiving)
byte bytesToSend[3] = {0x43, byte(88), byte(2)}; // 600 broken down to high and low bytes
Serial.write(bytesToSend, 3); // send three bytes
Serial.println(); //send line break to terminate transmission
byte bytesToSend[3] = {0x43, byte(188), byte(2)}; // 700 broken down to high and low bytes
Serial.write(bytesToSend, 3); // send three bytes
Serial.println(); //send line break to terminate transmission
C# code: (relevant parts - May have missed a syntax or two since I cut/trimmed and pasted...)
string inString = "";
inString = port.ReadLine(); // read a line of data from the serial port
inString = inString.Trim(); //remove newline
byte[] buf = new byte[15]; // reserve space for incoming data
buf = System.Text.Encoding.ASCII.GetBytes(inString); //convert string to byte array I've tried a block copy here, but it didn't work either...
Console.Write("Data received: H: {0}, L: {1}. =", buf[2], buf[1]); //display high and low bytes
Console.WriteLine(Convert.ToUInt32((buf[2] << 8) + buf[1])); //display combined value
And this is what I get in the serial monitor where it writes out the values:
Data received: H: 2, L: 88. = 600
Data received: H: 2, L: 63. = 575
The low byte value gets changed or mis-interpreted from 188 to 63 somewhere in the process. What is causing this and how can I fix it? It seems to work fine when the byte value is below 128, but not when it is above.
I think this could be problem at your c# side code. You should debug this by printing the string which you are reading just after port.ReadLine(), to see what you are receiving.
Also I would suggest to use C# Read(Byte[], Int32, Int32), so that your data is read into Byte Array which is array of unsigned char. ReadLine() is reading data into string (array of char).
Your encoding is wrong. Change the line from:
buf = System.Text.Encoding.ASCII.GetBytes(inString);
to
buf = System.Text.Encoding.GetEncoding("Windows-1252").GetBytes(inString);
Better yet, when you instantiate your Port object just set the encoder property to this type.
...
SerialPort port = new SerialPort();
System.Text.Encoding encoder = System.Text.Encoding.GetEncoding("Windows-1252");
port.Encoding = encoder;
...
Remember that ASCII is 7-bit so you will truncate values that are greater than decimal 127. The 1252 encoding is 8 bit and is great for binary data. The table shown at MSDN shows the full symbol support for the encoding.
Why, in C#, reading full string - which will force you to deal with encodings, ... - and do post-process instead of parsing in time?
System.IO.BinaryReader bin_port=new System.IO.BinaryReader(port); //Use binary reader
int b;
int data16;
b=bin_port.ReadByte();
switch (b) {
case 0x43: //Read integer
data16=bin_port.ReadUInt16();
while (bin_port.ReadByte()!=0x0a); //Discard all bytes until LF
break;
}
In a part of a software, card is read by a card reader and is allocated to an user. And in other part of this software, in a terminal by same card reader, the user card is read and fetch data from database by card serial number and etc.
In a new part of this software, there are a new terminal with a new card reader. card is read from this card reader and fetch data from database and etc.
So, now the problem is that a same card that is read by this two card readers are different in type. The first device return card id as a hexadecimal string, like this:
2E 6F 27 3F
This hexadecimal string is converted to decimal and is stored in the database. For example, the above hexadecimal string is converted to this integer:
779036479
Now, when second card reader read this same card, the card id is an array of bytes, like this for that card:
byte0: 49
byte1: 48
byte2: 53
byte3: 57
byte4: 53
byte5: 52
byte6: 56
byte7: 57
byte8: 55
byte9: 52
How can I coordinate this two serial number of same card with each other? In other words, I want to convert this array of bytes to corresponding hex code, so that this hex code is the serial number of that card that first device is return?
The card is Mifare.
The answer is that the second reader is returning ASCII encoded decimals. Your number is 1059548974. This number, encoded into hexadecimals is 3F276F2E if you use Big Endian encoding. If you use Little Endian encoding then you will get 2E6F273F which should be familiar to you.
So:
decode the returned byte array to ASCII, retrieving the string "1059548974"
convert that string to an integer using Convert.ToUInt32(str);
reverse the bytes in the integer
Probably the best way to reverse the bytes is this piece of code:
public static UInt32 ReverseBytes(UInt32 value)
{
return (value & 0x000000FFU) << 24 | (value & 0x0000FF00U) << 8 |
(value & 0x00FF0000U) >> 8 | (value & 0xFF000000U) >> 24;
}
Its rather hard to understand just exactly what your wanting, but in the bottom you state: 'in other words, i want to convert this array of bytes to corresponding hex code'.
You can perform that operation like so:
public static string ByteArrayToString(byte[] ba)
{
StringBuilder sb = new StringBuilder(ba.Length * 2);
foreach (byte b in ba)
{
sb.AppendFormat("{0:x2}", b);
}
return sb.ToString();
}
Just pass in your Byte array and the result will be your hex conversion in string format.
Edit: This will probably yield the same results, but try this:
byte[ ] bytes = {0, 1, 2, 4, 8, 16, 32, 64, 128, 255 }
Console.WriteLine( BitConverter.ToString( bytes ) );
I am reading a line from MCU via serial port. The line consists in 14 characters terminated by "OK". The characters are converted to int then processed. The problem is when the value becomes larger than 128. For values larger than 128 the value (int converted) remains at 63. Here is the code:
serialPort1.DiscardInBuffer();
serialPort1.DiscardOutBuffer();
serialPort1.Write("d");//request line from mcu
Thread.Sleep(100);
string line = serialPort1.ReadLine();
int p1_low = line[0];
int p1_high = line[1]*256;
int p1 = p1_low + (p1_high);
label1.Text = "Input Sensor: " + p1_low;
p1_low varies much often than p1_high and sticks to 63 value when is larger than 128. Where can be the problem?
Change the encoding to
SerialPort1.Encoding = System.Text.Encoding.GetEncoding(28591)
The default encoding, as you have discovered, replaces byte values > 127 with a '?'. Encoding 28591 preserves byte values greater than 127.
You do not need the thread sleep as .ReadLine blocks.
It sounds like you are set to use 7 data bits. Change the data bits config value to 8, so you can get all 256 values.
Reference: http://msdn.microsoft.com/en-us/library/system.io.ports.serialport.databits.aspx
Use the method
Write(Byte[], int32, int32) because a byte is a numerical value --> (0-255) or (0x00-0xFF) or (b00000000-11111111). A char or a string can be encoded but not a byte.
Make sure to
NOT use Write(Char[], int32, int32)
Is there something similar to sprintf() in C#?
I would for instance like to convert an integer to a 2-byte byte-array.
Something like:
int number = 17;
byte[] s = sprintf("%2c", number);
string s = string.Format("{0:00}", number)
The first 0 means "the first argument" (i.e. number); the 00 after the colon is the format specifier (2 numeric digits).
However, note that .NET strings are UTF-16, so a 2-character string is 4 bytes, not 2
(edit: question changed from string to byte[])
To get the bytes, use Encoding:
byte[] raw = Encoding.UTF8.GetBytes(s);
(obviously different encodings may give different results; UTF8 will give 2 bytes for this data)
Actually, a shorter version of the first bit is:
string s = number.ToString("00");
But the string.Format version is more flexible.
EDIT: I'm assuming that you want to convert the value of an integer to a byte array and not the value converted to a string first and then to a byte array (check marc's answer for the latter.)
To convert an int to a byte array you can use:
byte[] array = BitConverter.GetBytes(17);
but that will give you an array of 4 bytes and not 2 (since an int is 32 bits.)
To get an array of 2 bytes you should use:
byte[] array = BitConverter.GetBytes((short)17);
If you just want to convert the value 17 to two characters then use:
string result = string.Format("{0:00}", 17);
But as marc pointed out the result will consume 4 bytes since each character in .NET is 2 bytes (UTF-16) (including the two bytes that hold the string length it will be 6 bytes).
It turned out, that what I really wanted was this:
short number = 17;
System.IO.BinaryWriter writer = new System.IO.BinaryWriter(stream);
writer.Write(number);
writer.Flush();
The key here is the Write-function of the BinaryWriter class. It has 18 overloads, converting different formats to a byte array which it writes to the stream. In my case I have to make sure the number I want to write is kept in a short datatype, this will make the Write function write 2 bytes.