Search code examples
cserial-communicationrs485

Converting uint8_t to int issues


I am trying to communicate with a usb dongle via serial communication. My communication works, however I cant get the device to correctly parse the communication. My devices reads the message and compares it with a hardcoded c-string. It parses and recognizes that it's the correct string, but when I try to parse the value after the : character, it returns 0x00000000 and I have no idea why. I've tried using char cast and use atoi, I tried using a simple ascii translation, and even doing a bitwise addition operation as shown here: convert subset of vector<uint8_t> to int

For example:
I send "Heart Rate:55" It parses and recognizes that "Heart Rate:" but when I tell it to go find the 55 and bring it back to do stuff with it, it gives me a 0x00000000
Heres a snippet:

const uint8_t hrmSet[] = "Heart Rate:";

/** Find the : character in the string and break it apart to find if it matches, 
and determine the value of the value of the desired heart rate. **/
int parse(uint8_t *input, uint8_t size)
{
    for (uint8_t i = 0; i < size; i++)
    {
        if (input[i] == ':')
        {
            if (compare_string(input, hrmSet, i) == 0)
            {
                int val = 0;
                for (int j = i+1; j < size; j++)
                {
                    if (!isdigit(input[j]))
                    {
                        for (int k = i; k < j; k++)
                        {
                            val <<= 8;
                            val |= input[k];
                        }
                    }   
                }
                return val;
            }
            return -1;
        }
    }
    return -1;
}

Compare string function

/** Compare the input with the const values byte by byte to determine if they are equal.**/
int compare_string(uint8_t *first, const uint8_t *second, int total)
{
    for (int i = 0; i < total; i++)
    {
        if (*first != *second)
        {
            break;
        }

        if (*first == '\0' || *second == '\0')
        {
            break;
        }

        first++;
        second++;
    }

    if (*first == ':' && *second == ':')
    {
        return 0;
    }
    else
    {
       return -1;
    }
}

Solution

  • The problem here is that you are using nested loops to perform tasks that should be done with sequential loops.

    For example, the i loop searches for the colon, and then the loop in compare_string searches for the colon again. You could run the i loop first, and then call compare_string after the i loop finishes. But a better design is to have compare_string search for the colon while comparing, and then return the index of the character after the colon (or -1 if the colon is not found).

    The same is true of the j and k nested loops. The j loop is searching for the end of the number. The k loop only runs once after the j loop is finished, and so the k loop should be after the j loop, not nested. But a better design is a single loop that converts the number while searching for the end of the number.

    The code below demonstrates one possible implementation using the techniques I've described.

    const uint8_t hrmSet[] = "Heart Rate:";
    
    int compare_string( uint8_t *input, const uint8_t *expected, int size )
    {
        for ( int i = 0; i < size; i++ )
        {
            if ( *input != *expected || *expected == '\0' )
                return( -1 );
    
            if ( *input == ':' && *expected == ':' )
                return( i + 1 );
    
            input++;
            expected++;
        }
    
        return( -1 );
    }
    
    int parse( uint8_t *input, uint8_t size )
    {
        int i, val;
    
        if ( (i = compare_string( input, hrmSet, size )) < 0 )
            return( -1 );
    
        val = 0;
        for ( ; i < size && isdigit( input[i] ); i++ )
            val = val * 10 + input[i] - '0';
    
        return( val );
    }
    
    int main( void )
    {
        uint8_t input[] = "Heart Rate:75";
        int rate = parse( input, sizeof(input) - 1 );
        printf( "%d\n", rate );
    }