Convert Char Array to byte Array

Hello,

Hopefully a simple question for one of you guys. I have a char array:
const byte tempChars = 45;
char temP[tempChars];

This array holds null terminated array of hex characters eg;

temP [A, B, C, D, E, F, \0]

Problem #1
What I would like to do is convert that array into a byte array with [0] and [1] as a byte [2] and [3] as a byte etc.:

bytearray [ AB, CD, EF]

Problem #2
If there is an odd number of hex characters, I would like to have a 0 added if needed to the last hex value:

temP[ A, B, C, \0]

bytearray[ AB, C0]

I would appreciate any help

If the elements of temP[] are char, each will need quotes, including the null.

So this post here

I adapted and it does work, but the bytes in the array are reversed. You can see how he uses k-- in order to display them as expected (unless I am missing something).

char array[] ="AABB"

Put through the code there and output into a byte array then iterated with a standard for loop;

for(int i = 0; i<3; i++) {
     Serial.print(bytes[i], HEX);
}

Will output:

BB
AA

Sure. Those arrays are fine though and are generated.

Some new info in my latest response, that almost gets me where I want to be.

Now that I think about it he is using i++ when generating the bytes. If I get the length, set i equal to that, and use i-- that might get me the correct order.

Interesting, very interesting

You just gave me an idea. I am really really close after hacking up that code to fit my needs. Let me try something a bit different. Well different from that code, but in line with what you are suggesting.

To answer your question, I am using an ESP32 to interface with a radio and the registers. I use serial input to trigger various commands to set radio registers. This piece is directly applicable to transmission.

I have 2 part commands; so for transmission Rfxmit(AABBCCDD). With the ascii in hex form between the () specifying what information to send. Already got the parsing of commands and parameters set up and working perfectly for all other commands/params in a very long sketch.

This almost works:

char temP[] = "AABB";
byte arr [4];    //the byte array will be oversized, maybe full maybe not which is why I 
                 //left it oversized here.

int i = (strlen(temP) / 2);  //The problem is I don't know how it will handle odd lengths. 
                             //But first get it working then address that part
while (x != 0) {
    arr[i] = x % 0x100;
    x = x / 0x100;
    i--;
}

The above code generates:
0
AA
BB

With

for (int i =0; i<3; i++) {
    Serial.println(arr[i], HEX)
}

So it gets it there, but always with a 0 in arr[0].

Trying to compile that gave me a "Invalid conversion from long unsigned int to const void" error with the memcopy.

Perhaps because the arr array is larger than this test case? (I am just guessing)

temP can be any length greater than 0 but less than 496.

declared temP[496]

arr can be any length up to 248 bytes.

declared arr[248]

No real pointers in temP that I can use it is all just straight hex values parsed from initial input.

I think I am done for the night. I'll have to give it more thought.

Seems like a standard hex decode, aside from how to handle a half-byte. You'd be better off adapting the post just above that other one, and it's even simpler if you don't have any non-hex characters like spaces.

char temP[496];
byte arr[(sizeof(temP) + 1) / 2];  // +1 in case odd

const char *test[] = {
  "AABBCCDDEE",
  "ABBCCDDEE",
  "210",
};

String space(" ");

void setup() {
  Serial.begin(115200);
  Serial.println(sizeof(temP));
  Serial.println(sizeof(arr));
  Serial.println(sizeof(test));
  Serial.println(sizeof(char *));
}

size_t hexDecode() {
  auto hex2num = [] (char c) {
    switch (c) {
      case '0' ... '9':
        return c - '0';
      case 'A' ... 'F':
        return c - 'A' + 10;
      case 'a' ... 'f':
        return c - 'a' + 10;
      default:
        return 0;
    }
  };
  int i = 0;
  for (i = 0; i < sizeof(arr); i++) {
    char left = temP[2 * i];
    if (!left) {  // NUL-terminator in source
      break;  
    }
    char right = temP[2 * i + 1];
    arr[i] = 16 * hex2num(left) + hex2num(right);
    if (!right) {  // Only half a byte
      i++;         // Skip x0 just-assigned
      break;
    }
  }
  return i;
}

void hexPrint(size_t len) {
  char buf[] = "12 ";
  for (int i = 0; i < len; i++) {
    sprintf(buf, "%02x ", arr[i]);
    Serial.print(buf);
  }
}

void loop() {
  static unsigned t = 0;
  if (t < sizeof(test) / sizeof(char *)) {
    Serial.println(test[t] + space + strlen(test[t]));
    strcpy(temP, test[t]);
    size_t len = hexDecode();
    hexPrint(len);
    Serial.println(len);
    delay(50);
  } else {
    delay(1000);
  }
  t++;
}

yields

AABBCCDDEE 10
aa bb cc dd ee 5
ABBCCDDEE 9
ab bc cd de e0 5
210 3
21 00 2

You mean the one that didn't compile? Up front I explained buffer sizes, format, etc.

That's fine though. My own research has me close.

Thanks. I'll check it out!

Nope, no spaces. The format is always an ASCII hex string. It's just the length that is variable.

Check if the following sketch helps:

char temP[] = {'A', 'B', 'C', 'D', 'E', 'F', '\0'};
byte myData[3];

void setup() 
{
  Serial.begin(9600);
  for(int i = 0; i<= 4; i= i+2)
  {
    myData[i] = temP[i] - 55 <<4 | temP[i+1]-55;
    Serial.println(myData[i], HEX);
  }
}

void loop() {}

Output:

AB
CD
EF

Are you sure that the zero should be add at the end? Usually the leading zero disappears, since 0x0A and 0xA the same, but 0xA and 0xA0 are not.
Most likely null should be added to the first element of the array:

temP[ A, B, C, \0]   =>   bytearray[ 0A, BC]

why are you only processing numbers above A ?

Hex chars are '0'-'F'

1 Like

I'm sorry. Yes you are absolutely correct. Although in that example it would be 0xAB, 0x0C if the input is "ABC"

temP is populated via serial input, the ASCII input will only be hex chars. No spaces, commas, periods, etc

Sorry for the confusion

I have given a solution to the char array of the OP! Do you want a solution for the charcaters: '0' to 'F'?

OP wrote:

As I understand, the array with only 'A'-'F' chars is just an example. The code have to process ANY hex characters rather than A-F only.

Yes that is correct.

Your last question regarding preceeding 0's got me thinking. The way it is currently working isn't very good.

The example of "ABC" could work out to any number of possibilities eg 0x0A, 0x0B, 0x0C, or 0x0A, 0xBC, or 0xAB, 0x0C.

Thank you for getting me thinking about that.

If I require the hex to be input in xx hex format eg 0ABC0D the char array will always have an even length, which should make things a bit easier to translate to the desired and correct output 0x0A 0xBC and 0x0D.

This post is definately going to come in handy Print hex with leading zeroes as my signal RX function does not produce proceeding 0's which is what started this post.

No thanks. I am not posting a thousand lines for a single function.

I didn't imagine I would have to explain that RF signals come in all different lengths, hence the temP[] array and byte array would be all different lengths up to the max size of each array.

That why I didn't post code at the start, because I cant use something that produces only 4 bytes when the input is much longer, and there is no "solution" that doesn't iterate. You just jumped on an example that happened to be only 4 char long and pretended it would always be 4 char long.

Feel free to "not waste your time".

@b707 thanks for your help, you definitely pointed out some issues I hadn't thought of and that once fixed should get me where I can finish it off.