Search code examples
c++arduinoarduino-ide

Store HEX char array in byte array with out changing to ASCII or any thing else


My char array is "00000f01" and I want it to be like byte out[4]={0x00,0x00,0x0f,0x01}; I tried the code sent by @ChrisA and thanks to him the Serial.println( b,HEX ); shows exactly what I need but 1st I can not access this output array because when I try to print "out" array it seems empty I also tried this code:

void setup() {
    Serial.begin(9600);
    char arr[] = "00000f01";
    byte out[4];
    byte arer[4];
    auto getNum = [](char c){ return c ; };
    byte *ptr = out;
    for(char *idx = arr ; *idx ; ++idx, ++ptr ){
        *ptr = (getNum( *idx++ ) << 4) + getNum( *idx );
    }
    int co=0;
    //Check converted byte values.
    for( byte b : out ){
        Serial.println( co );
        Serial.println( b,HEX ); 
        arer[co]=b;
        co++; 
    }
    //    Serial.print(getNum,HEX); 
    //    Serial.print(out[4],HEX); 
    //    Serial.print(arer[4],HEX); 
    /*
    none of this codes commented above worked*/
}

void loop() {
}   

but it is not working neither. please help me.


Solution

  • The title of your question leads me to believe there's something missing in either your understanding of char arrays or the way you've asked the question. Often people have difficulty understanding the difference between a hexadecimal character or digit, and the representation of a byte in memory. A quick explanation:

    Internally, all memory is just binary. You can choose to represent (ie. display it) it in bits, ASCII, decimal or hexadecimal, but it doesn't change what is stored in memory. On the other hand, since memory is just binary, characters always require a character encoding. That can be unicode or other more exotic encodings, but typically it's just ASCII. So if you want a string of characters, whether they spell out a hexadecimal number or a sentence or random letters, they must be encoded in ASCII.

    Now the body of the question can easily be addressed:

    AFAIK, there's no way to "capture" the output of Serial.println( b,HEX ) pragmatically, so you need to find another way to do your conversion from hex characters. The getNum() lambda provides the perfect opportunity. At the moment it does nothing, but if you adjust it so the character '0' turns into the number 0, and the character 'f' turns in to the number 15, and so on, you'll be well on your way.

    Here's a quick and dirty way to do that:

    void setup() {
        Serial.begin(9600);
        char arr[] = "00000f01";
        byte out[4];
        byte arer[4];
        auto getNum = [](char c){ return (c <= '9' ? c-'0' : c-'a'+10) ; };
        byte *ptr = out;
        for(char *idx = arr ; *idx ; ++idx, ++ptr ){
            *ptr = (getNum( *idx++ ) << 4) + getNum( *idx );
        }
        int co=0;
        //Check converted byte values.
        for( byte b : out ){
            Serial.println( co );
            if(b < 0x10)
              Serial.print('0');
            Serial.println( b,HEX ); 
            arer[co]=b;
            co++; 
        }
    }
    
    void loop() {
    }
    

    All I've done is to modify getNum so it returns 0 for '0' and 15 for 'f', and so on in between. It does so by subtracting the value of the character '0' from the characters '0' through '9', or subtracting the value of the character 'a' from the characters 'a' through 'f'. Fortunately, the value of the characters '0' through '9' go up by one at a time, as do the characters from 'a' to 'f'. Note this will fall over if you input 'F' or something, but it'll do for the example you show.

    When I run the above code on a Uno, I get this output:

    0
    00
    1
    00
    2
    0F
    3
    01
    

    which seems to be what you want.

    Epilogue

    To demonstrate how print functions in C++ can lead you astray as to the actual value of thing you're printing, consider the cout version:

    If I compile and run the following code in C++14:

    #include <iostream>
    #include <iomanip>
    #include <string>
    
    typedef unsigned char byte;
    
    int main()
    {
        char arr[] = "00000f01";
        byte out[4];
        byte arer[4];
        auto getNum = [](char c){ return c ; };
        byte *ptr = out;
        for(char *idx = arr ; *idx ; ++idx, ++ptr ){
            *ptr = (getNum( *idx++ ) << 4) + getNum( *idx );
        }
        int co=0;
        //Check converted byte values.
        for( byte b : out ){
            std::cout << std::setfill('0') << std::setw(2) << std::hex << b;
            arer[co]=b;
            co++;
        }
    }
    

    I get this output:

    00000f01 
    

    appearing to show that the conversion from hex characters has occurred. But this is only because cout ignores std::hex and treats b as a char to be printed in ASCII. Because the string "00000f01" has '0' as the first char in each pair, which happens to have a hex value (0x30) with zero lower nybble value, the (getNum( *idx++ ) << 4) happens to do nothing. So b will contain the original second char in each pair, which when printed in ASCII looks like a hex string.