1

I receive a byte array serial_port[4] {0x00, 0xA0, 0x05, 0xB1} from my serial port as below:

string rec_data += sp.ReadExisting();  

and I need to convert this string to a decimal value by using:

byte[] Temp = Encoding.ASCII.GetBytes(rec_data);
decimal r0 = Convert.ToDecimal(Temp[0]);
decimal r1 = Convert.ToDecimal(Temp[1]);
decimal r2 = Convert.ToDecimal(Temp[2]);
decimal r3 = Convert.ToDecimal(Temp[3]); 

But result values are not my desire:

r0 = 0
r1 = 63
r2 = 5
r3 = 63

as you can see, result of 8-bits HEX values are wrong and are equal with 63(0x3F) any suggestion to solve it?

Maverick
  • 1,396
  • 5
  • 22
  • 42
  • Read bytes from serial port instead of string. Or try to use `Encoding.Default` instead of `Encoding.ASCII`. – Alexander Petrov Jul 27 '16 at 11:58
  • @Alexander Petrov result for `Encoding.default` was similar – Ehsan.Davoudi Jul 27 '16 at 12:02
  • 1
    Because the encoding of the serial port is still `Encoding.ASCII`. You'd need to change `sp.Encoding` as well (ideally right after you create the `SerialPort` instance). ASCII is a 7-bit character set, you can't represent values larger than 127. `0xA0` is larger than 127, so it gets encoded as 63 - `?`. – Luaan Jul 27 '16 at 12:22
  • @Luaan I change my `sp.Encoding` to default as you suggested and it worked. Thanks a lot. – Ehsan.Davoudi Jul 27 '16 at 12:45
  • 1
    That's most likely a very bad way to solve that problem, but if that's what you want... :) – Luaan Jul 27 '16 at 12:48

2 Answers2

5

ASCII is a 7-bit character set. There's no such thing as 0xA0 in ASCII. 63 just happens to be ? in ASCII - the character used when a particular value cannot be represented in the given character set.

Don't read the data as character data when they aren't characters. Don't use ReadExisting, which assumes character data. Rather, you need something like this:

var buffer = new byte[256];
var bytesRead = sp.Read(buffer, 0, buffer.Length)

// buffer[0..bytesRead-1] now contains all the data read from the port

Of course, you may need to read multiple times to get the whole message, or you might want to only read a limited amount of bytes at a time, depending on how your protocol works.

A simple SerialPort wrapper that handles this for you might look like this:

class MySerialPort
{
  private readonly SerialPort _port;

  public MySerialPort(SerialPort port)
  {
    this._port = port;
  }

  public byte[] ReadBytes(int amount)
  {
    var data = new byte[amount];
    var offset = 0;

    while (amount > 0)
    {
      var bytesRead = _port.Read(data, offset, amount);
      offset += bytesRead;
      amount -= bytesRead;
    }

    return data;
  }
}

Depending on what you're actually trying to do, you might want to add some buffering and what not, but this will work fine for the kind of protocols that are commonly used over serial port. If this is all you really need, you could simply make ReadBytes an extension method on SerialPort.

Also, decimal is a, well, decimal number. You probably want to use byte or int instead.

Luaan
  • 62,244
  • 7
  • 97
  • 116
  • Help the OP fall in the pit of success, the *buffer* variable should always be a field of the class and the 2nd argument to Read() should always be a variable that counts the number of bytes in the buffer. – Hans Passant Jul 27 '16 at 12:22
0

You don't need to convert bytes to decimal:

byte[] Temp = Encoding.ASCII.GetBytes(rec_data);
decimal r0 = Temp[0];
decimal r1 = Temp[1];
decimal r2 = Temp[2];
decimal r3 = Temp[3];

Values of the int's:

r0 - 0
r1 - 160
r2 - 5
r3 - 177
M. Schena
  • 2,039
  • 1
  • 21
  • 29