Receiving hex data from terminal
First, you have to understand what “hex” means. Basically, you are
representing binary data as text, where each byte is represented as
two characters. For example, the number 42 is represented as either “2A”
or “2a”. In C and C++, you can write this number as 0x2a, but I assume
your serial stream sends the raw hex data, without the “0x” prefix.
Thus, on the serial stream you may receive the character “2” (character
code 0x32 = 50 in decimal) followed, some time later, by “a” (charcode
0x61 = 97).

What you need is a conversion routine that takes these characters and
reconstructs the binary data out of them. Here is one such routine I
use. You have to provide it with an input string in and an output
array out large enough to store the resulting binary data. The
function will return the number of bytes filled in *size:



/*
 * Convert an hex string to binary. Spaces are allowed between bytes.
 * The output array is supposed to be large enough.
 * On return, *size is the size of the byte array.
 */
static void hex2bin(uint8_t *out, const char *in, size_t *size)
{
    size_t sz = 0;
    while (*in) {
        while (*in == ' ') in++;  // skip spaces
        if (!*in) break;
        uint8_t c = *in&gt;='a' ? *in-'a'+10 : *in&gt;='A' ? *in-'A'+10 : *in-'0';
        in++;
        c &lt;&lt;= 4;
        if (!*in) break;
        c |= *in&gt;='a' ? *in-'a'+10 : *in&gt;='A' ? *in-'A'+10 : *in-'0';
        in++;
        *out++ = c;
        sz++;
    }
    *size = sz;
}


As a mere convenience, the function above accepts spaces within the
string, but only between bytes. Notice however that it does not attempt
to do any error checking. You may want to improve it in this respect.

Next, you have to devise a way to frame your messages on the serial
line. Serial does not provide any framing per se: it only transmits byte
one by one. When dealing with text, a common scheme is to send a
carriage return (\r) to indicate the end of a message. With this
convention, you sketch has to buffer the bytes it receives until it
sees a carriage return. Then it can process the whole message as a
whole. This approach is nicely explained in the blog post Reading
Serial on the
Arduino,
by Majenko, a regular contributor to this site.

Here is an example that reads an hex string, converts it to binary, and
then sends it back as hex again:

void setup()
{
    Serial.begin(9600);
}

void loop()
{
    static char buffer[1024];
    static size_t length = 0;

    if (Serial.available()) {
        char c = Serial.read();

        // On carriage return, process the received data.
        if (c == '\r') {
            Serial.println();  // echo

            // Properly terminate the string.
            buffer[length] = '\0';

            // Convert the hex data to a byte array.
            size_t byte_count = length/2;
            uint8_t data[byte_count];
            hex2bin(data, buffer, &amp;byte_count);

            // Echo back the byte array in hex.
            for (size_t i = 0; i &lt; byte_count; i++) {
                Serial.print(data[i], HEX);
                Serial.print(" ");
            }
            Serial.println();

            // Reset the buffer for next line.
            length = 0;
        }

        // Otherwise buffer the incoming byte.
        else if (length &lt; sizeof buffer - 1) {
            Serial.write(c);  // echo
            buffer[length++] = c;
        }
    }
}


Notice the lines with the comment “echo”: they are meant to help you see
in the terminal what you are typing. You can remove them if you do not
what the Arduino to echo your typing. I tested it by sending



AA bb06 000000 0101 03 03


and it replied

AA BB 6 0 0 0 1 1 3 3