Hexadecimal string to binary

Hi guys,

I need to convert a hexadecimal string to a binary in order to extract specific bits from it.

I receive a character line by a serial port, and i separate the hexadecimal code in a string. I have to "reverse" it in a specific way but i skip this part because it is not the problem here.

So for example i have this hexadecimal string:
8000F9C2DFDAE814
I need to get the binary conversion in order to get this :
1000 0000 0000 0000 1111 1001 1100 0010 1101 1111 1101 1010 1110 1000 0001 0100
Then I have to get two parts from this binary : bit 17 to 26 and bit 27 to 64, which i later need to read in decimal base for the end user
giving:
bit 17 to 26 = 1111 1001 11 = 999 in decimal
bit 27 to 64 = 00 0010 1101 1111 1101 1010 1110 1000 0001 0100 = 12345600020 in decimal

I am looking for a solution to convert the hex string but can't make it work. I tried to use strtoul() but I guess I'm missing something obvious...

Thank you for your help.

Post your code, post your results.
Remember code tags

char inHex[] = "8000F9C2DFDAE814";
byte outData[(sizeof(inHex) - 1) / 2];

void setup() {
  Serial.begin(250000);
  unHex(inHex, outData, strlen(inHex));
  printBuffer();
}
void loop() {}

void unHex(const char* inP, byte* outP, size_t len) {
  for (; len > 1; len -= 2) {
    byte val = asc2byte(*inP++) << 4;
    *outP++ = val | asc2byte(*inP++);
  }
}

byte asc2byte(char chr) {
  byte rVal = 0;
  if (isdigit(chr)) {
    rVal = chr - '0';
  } else if (chr >= 'A' && chr <= 'F') {
    rVal = chr + 10 - 'A';
  }
  return rVal;
}

void printBuffer() {
  Serial.print(F("input '"));
  Serial.print(inHex);
  Serial.print(F("' output"));
  for (byte i = 0; i < sizeof(outData); i++) {
    Serial.write(' ');
    if (outData[i] < 16) {
      Serial.write('0');
    }
    Serial.print(outData[i], HEX);
  }
  Serial.println();
}
input '8000F9C2DFDAE814' output 80 00 F9 C2 DF DA E8 14
void loop() {
  char trame[30];
  String strTrame = "";
  String strEid = "";
  String temp = "";
  int intEid = 0;

  int i = 0,j = 0,k = 0;

//get the serial line
  if(Serial2.available()){
    while (i <= 30){
      trame[i] =  Serial2.read(); 
      Serial.write(trame[i]);
      strTrame += trame[i];
      i++;
    } 
    Serial.println();
  }

//cheking a good line
if(strTrame.substring(0,1).equals(":")){
    Serial.println("bonne trame");
    Serial.println(strTrame.substring(1,4));
//checking the EID type
  if(strTrame.substring(1,4).equals("HDX")){
    strEid =strTrame.substring(5,21);
  }else{
    strEid =strTrame.substring(6,22);
  }

  Serial.println(strEid);

//reversing the hex
  for(j = 0; j<7; j++){
    k=k+2;
    temp = strEid.substring(k,k+2);
    strEid.remove(k,2);
    Serial.println(strEid);
    Serial.println(temp);
    strEid = temp+strEid; 
    Serial.println(strEid);
    temp = "";
  }
  
  Serial.println(strEid);
//need help here to convert the hex str...
}else{
Serial.println("Attente bonne trame"); //"waiting for a good line"

}

I put you an example of what i get on the serial port:

:HDX=14E8DADFC2F900807E0000
bonne trame // = "good line"
HDX
E814DADFC2F90080
DAE814DFC2F90080
DFDAE814C2F90080
C2DFDAE814F90080
F9C2DFDAE8140080
00F9C2DFDAE81480
8000F9C2DFDAE814
8000F9C2DFDAE814

Okwolus:
I am looking for a solution to convert the hex string but can't make it work. I tried to use strtoul() but I guess I'm missing something obvious...

Yes you are. This is because there is NO difference between binary and hex to a computer (or MCU). The real difference is only in representation. 0x1 in hex is exactly the same as 00000001 in binary and is exactly the same as 1 in decimal. There is NO need for conversion.

In order to find the bits of a single bit in a variable, you need to execute a mask on said variable. For instance, if I want to know if the 4th bit of 00011001 in binary (or 0x19 in hex - same thing) is a 1 or 0, I would do this:

byte variable = 0x19;
byte mask = 1 << 3;
byte answer = (variable & mask) >> 3;

Okwolus:
Hi guys,

I need to convert a hexadecimal string to a binary in order to extract specific bits from it.

I receive a character line by a serial port, and i separate the hexadecimal code in a string. I have to "reverse" it in a specific way but i skip this part because it is not the problem here.

So for example i have this hexadecimal string:
8000F9C2DFDAE814
I need to get the binary conversion in order to get this :
1000 0000 0000 0000 1111 1001 1100 0010 1101 1111 1101 1010 1110 1000 0001 0100
Then I have to get two parts from this binary : bit 17 to 26 and bit 27 to 64, which i later need to read in decimal base for the end user
giving:
bit 17 to 26 = 1111 1001 11 = 999 in decimal
bit 27 to 64 = 00 0010 1101 1111 1101 1010 1110 1000 0001 0100 = 12345600020 in decimal

I am looking for a solution to convert the hex string but can't make it work. I tried to use strtoul() but I guess I'm missing something obvious...

Thank you for your help.

Now that I look at what you are trying to accomplish I'm wondering - why have such a convoluted way to do processing? What are you trying to do and what project is this for? There may be an easier way.

I know that there is different representation of numbers, HEX, DEC, OCTAL, etc, but the problem is i'm dealing with a string at first, and it only comes in HEX.

I'm not an expert at arduino coding so there must be a better way to process it, you're probably right ^^

This is a project where I use a RFID bluetooth reader. This is used to scan animal RFID chips (placed on theyre ear). The reader uses SPP by a MAX232 module giveing me an appropriate way to read incoming lines. The reader has a specific decoding protocol where I need to reverse the HEX i'm getting, and extracting the bits from it to get a national ID ( 999 here) and a personnal ID (12345600020 here). I will create a screen later to display all the information.

This is just a little part of the project, because I connect weighing scales and command pneumatic cylinder by relays, etc...

I posted a working solution to your problem, but I will not embed it into your awful String code.

[OT]
Why post here, when even the OT does not read answers that are not spoonfeeding?
[/OT]

Are you sure you're using the correct "endian"? The number may be stored in "big endian" format and you're reading it as "little endian", maybe the HEX number is 00 80 C2 F9 DA DF 14 E8 or F9C2 8000 E814 DFDA

edgemoron:
Are you sure you're using the correct "endian"? The number may be stored in "big endian" format and you're reading it as "little endian"...

The OT wants to convert ASCII Hex to bytes. Bytes have no endianness.

Whandall:
I posted a working solution to your problem, but I will not embed it into your awful String code.

[OT]
Why post here, when even the OT does not read answers that are not spoonfeeding?
[/OT]

I read your answer and will adapt your code, thanks for the help.

Okwolus:
I know that there is different representation of numbers, HEX, DEC, OCTAL, etc, but the problem is i'm dealing with a string at first, and it only comes in HEX.

I guess you didn't read this:

Power_Broker:
Yes you are. This is because there is NO difference between binary and hex to a computer (or MCU).

And you probably didn't read this either:

Power_Broker:
The real difference is only in representation. 0x1 in hex is exactly the same as 00000001 in binary and is exactly the same as 1 in decimal. There is NO need for conversion.

Power_Broker:
I guess you didn't read this:

I think I'm not mad and continue to think that a STRING HEX is different form a BYTE HEX representation.

Whandall gave me the good way to deal with it.

I inslcuded it in my code and it works well. Then I try to isolate some groups of bits from this BIN representation.

Tell me if I am wrong but I think I need to convert it back to string in order to manipulate bits as characters, because I don't see a way to separate bits when they exist as bits.

The problem is, when I print my byte on HEX base with Whandall's code, and print them on BIN base, the 0x14 become "10100", when I need to full 8 bits"00010100", because the 3 zeros are counting in the final bits I need to extract.
Is there an option to print the non-desired zeros ?

Still couldnt find a solution after lots of test. If anyone has a starting idea ?

Okwolus:
The problem is, when I print my byte on HEX base with Whandall's code, and print them on BIN base, the 0x14 become "10100", when I need to full 8 bits"00010100", because the 3 zeros are counting in the final bits I need to extract.
Is there an option to print the non-desired zeros ?

The number 1234 is not usually written "00001234" so the binary and hex output from the standard Arduino print() function doesn't include leading zeroes either.

if(x<0b10000000) Serial.print("0");
if(x<0b1000000) Serial.print("0");
if(x<0b100000) Serial.print("0");
if(x<0b10000) Serial.print("0");
if(x<0b1000) Serial.print("0");
if(x<0b100) Serial.print("0");
if(x<0b10) Serial.print("0");
Serial.print(x, BIN);

Okwolus:
Tell me if I am wrong but I think I need to convert it back to string in order to manipulate bits as characters, because I don't see a way to separate bits when they exist as bits.

You are wrong.

Bits are isolated from the binary data via bit operations.

I number the bits LSB first, little-endian, so

bit #0 is the lowest bit of the first byte,
bit #8 is the lowest bit of the second byte
bit #16 is the lowest bit of the third byte
....

char inHex[] = "8000F9C2DFDAE814";
byte outData[(sizeof(inHex) - 1) / 2];

void setup() {
  Serial.begin(250000);
  unHex(inHex, outData, strlen(inHex));
  printBuffer();
  showTestBit(7);
  showTestBit(15);
  showTestBit(16);
}
void loop() {}

bool testABit(byte* area, byte bitNumber) {
  return area[bitNumber >> 3] & (1 << (bitNumber & 7));
}

void unHex(const char* inP, byte* outP, size_t len) {
  for (; len > 1; len -= 2) {
    byte val = asc2byte(*inP++) << 4;
    *outP++ = val | asc2byte(*inP++);
  }
}

void showTestBit(byte which) {
  Serial.print(F("Bit #"));
  Serial.print(which);
  Serial.print(F(" is "));
  Serial.println(testABit(outData, which) ? F("TRUE") : F("FALSE"));
}

byte asc2byte(char chr) {
  byte rVal = 0;
  if (isdigit(chr)) {
    rVal = chr - '0';
  } else if (chr >= 'A' && chr <= 'F') {
    rVal = chr + 10 - 'A';
  }
  return rVal;
}

void printBuffer() {
  Serial.print(F("input '"));
  Serial.print(inHex);
  Serial.print(F("' output"));
  for (byte i = 0; i < sizeof(outData); i++) {
    Serial.write(' ');
    if (outData[i] < 16) {
      Serial.write('0');
    }
    Serial.print(outData[i], HEX);
  }
  Serial.println();
}
input '8000F9C2DFDAE814' output 80 00 F9 C2 DF DA E8 14
Bit #7 is TRUE
Bit #15 is FALSE
Bit #16 is TRUE

Ok I get the method. Gonna try it in my code. Thanks a lot