1

I am not that great at Arduino and C++ yet, but I'll give this a shot:

I have a char array that looks like this:

char PROGMEM bitmap[] = {0xD7,0xED,0xEF,0xFF,0xF6,0xEF,0xFE};

However, I receive this char array from a string, which is basically:

String input = "0xD7,0xED,0xEF,0xFF,0xF6,0xEF,0xFE";

How do I turn my input variable with a comma separated char array into the actual array? I need it to be fast and not use a lot of memory. I haven't been able to find a use case like this, because it's very unique.

I feel like this should be super simple to do, but I can't wrap my head around it.

Things I've tried and didn't understand that much:

1:

char delimiter[] = ",";

char* ptr = strtok_r(text, delimiter);

while (ptr != NULL) {
  Serial.println(ptr);
  ptr = strtok_r(NULL, delimiter);
}

cannot convert 'String' to 'char*' for argument '1' to 'char* strtok(char*, const char*)'

2:

char buf[4800];
text.toCharArray(buf, 4800);
char *p = buf;
char *str;
int i = 0;
char bitmap[115];
while ((str = strtok_r(p, ",", &p)) != NULL) {
  bitmap[i] = str;
  i++;
}
Serial.println(bitmap);

(the total length of my characters are 4799 and the total length of hexadecimals are 114, so I'm just trying something here)

Error: Apparently you can't use =?

3:

char buf[4800];
text.toCharArray(buf, 4800);
char *p = buf;
char *str;
while ((str = strtok_r(p, ",", &p)) != NULL) {
  Serial.println(str);
}

This actually prints the strings to the console, but trying to add them to a char array is still a mystery I am trying to solve right as I write this.

4:

char buf[4800];
text.toCharArray(buf, 4800);
char *p = buf;
char *str;
char *ptr;
char bitmap[115];
int i = 0;
while ((str = strtok_r(p, ",", &p)) != NULL) {
  bitmap[i] = strtol(str, &ptr, 16);
  i++;
}

Serial.println(bitmap);

I'm getting a lot closer now. strtol(str, &ptr, 16) actually gives me the right integers I need, but it seems like my Arduino crashes when I run this code. It simply reboots it. Error:

assertion "heap != NULL && "free() target pointer is outside heap areas"" failed: file "/Users/ficeto/Desktop/ESP32/ESP32/esp-idf-public/components/heap/./heap_caps.c", line 171, function: heap_caps_free abort() was called at PC 0x4011c173 on core 1

10
  • 1
    While it may be frustrating to not get the answers you wanted, this isn't a code-writing service. Both here and on SO, good explanations have been given about the need to parse the string by the comma character, then parse each element therein from a set of characters into the actual byte you want. It's not impossible, but it's not necessarily a one-line-of-code answer, either. Sep 14, 2017 at 19:36
  • @josecanuc I completely agree that this isn't a code-writing service. However, when I've tried basically everything I've seen so far, that should be able to do it, I'm really desperate. I'm not asking for someone to give me the code. I am more than capable of looking at different functions and do my own research, but when everything I've tried has failed, what's there left to do? I come with my case and idea and hope that someone understands it and helps me solve the problem. Not give me the answer, although that would help more, but help me. Sep 14, 2017 at 19:47
  • Seperate using strtok into individual strings is done and easy. Adding them to an array of chars is not that easy. Sep 14, 2017 at 19:48
  • You got some useful comments on SO and an answer here, but now you deleted both questions and wasted everyone's time, who tried to help you. That isn't nice.
    – gre_gor
    Sep 14, 2017 at 19:49
  • Also show us what you tried and explain why it isn't working. Otherwise the question is too-broad.
    – gre_gor
    Sep 14, 2017 at 19:49

3 Answers 3

1

So after a lot of help and some tweaking, I finally got it to work!

String text = server.arg(0);

char buf[text.length()];
text.toCharArray(buf, text.length());
char *p = buf;
char *str;
char bitmap[960]; //960 is fixed for now, need to count amount of commas + 1
int i = 0;
while ((str = strtok_r(p, ",", &p)) != NULL) {
  bitmap[i] = strtol(str, NULL, 16);
  i++;
}

bitmap now contains all the XBM data from the GET request. I ran into some issues, causing the device to restart, because I accidentally forgot that the length of the bitmap array isn't 114 (that's the amount of horizontal pixels of the display). This caused it to overflow by a lot.

Huge thanks to jose can u c for helping me.

0

You note you can easily use strtok() to get individual strings of the text representation of the hex values. So now all you need is to convert the string "0xD7" or similar into the number 0xD7.

Have a look at strtol() function to perform that task.

10
  • Now that's something I like to see. Using strtok() I now have each value as a string. Using strtol() on that, I now get them all as longs. See my updated post (number 4). The Arduino crashes when I try this. Sep 14, 2017 at 20:05
  • strtol(str, NULL, 16) Sep 14, 2017 at 20:07
  • Same problem. Here's a small detail: If I remove the Serial.println(bitmap) it does not crash immediately. If I then add the display.drawXbm() to draw it on my OLED screen, it crashes the Arduino. Am I running out of memory perhaps? Sep 14, 2017 at 20:11
  • Serial.println(bitmap) is interpreting bitmap as a C-style string, but it's not null-terminated (nor does it likely contain printable ASCII values), so it runs amok and causes a crash. Once you have your array of bytes, it's no longer a string, but an array of bytes, and you can't use it where you would use a string. What are you trying to print? What output are you expecting from Serial.println(bitmap) ? Sep 14, 2017 at 20:14
  • I'm not sure. I was hoping I could see what it contained, but that's not how it works. Discard the Serial.println(bitmap). Sep 14, 2017 at 20:18
0

When dealing with string containing values separated by comma (or any other special character), you use the function strtok to parse the string. That means, separate each value.

The mechanics is:

  • In the first call you indicate the string to parse and the delimiters. That calls return a pointer to the first token found.
  • After that, you keep calling the same way, but passing NULL as the string to parse.
  • When the call returns a NULL, you are done.

Here is how you do it:

void setup()

{
Serial.begin(9600);

String input = "0xD7,0xED,0xEF,0xFF,0xF6,0xEF,0xFE,0x0,0x1,0xFF,0x10,0x2";
char *pch;

Serial.print("Splitting string '");
Serial.print(input);
Serial.println("' into tokens:\n");
// --- Start the strtok scan
pch = strtok((char *) input.c_str(),",");

// --- Cycle thru each comma separated hex value.
while(pch != NULL) {
    //  pch poinst to a string representation of an hex value.
    Serial.print(pch);
    Serial.print(" ->");
    //  convert string to value.
    char *p = pch + 2;        // Skip "0x"
    int val = hex2dec(*p++);  // Convert first hex digit.

    if(*p) {  // Convert an optional second hex digit.
        val = val * 16 + hex2dec(*p);
    }

    Serial.println(val, HEX); // Print the value to check.
    //  Next hex value
    pch = strtok(NULL, ",");
}
}

/*
 * Convert a hex digit to decimal.
 */
int hex2dec(char d)
{
    int val = 0;

    if(isDigit(d)) {
        val = (d - '0');
    } else {
        val = 10 + (toupper(d) - 'A');
    }

    return val;
}
1
  • Interesting. The first you say is something I've learned now. Great stuff, actually. Your example is basically half done right there. It still needs to be added to a char array (I can't use each individual value for anything). Can be done farely easy, though. Thanks for a further explanation and some more code to look at! Sep 14, 2017 at 21:30

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.