what is a better way to decode user inputs from uart interface

Thread Starter

bug13

Joined Feb 13, 2012
2,002
Hi guys

I often need to implement a way to receive user input from uart and change settings. eg:
Code:
// here are what a user may type in a terminal program
set param1 state1
set param1 state2
....
set param1 state10

set param2 state1
set param2 state2
...
set param2 state10
etc...
I usually write a function to find a match:
Code:
uint8_t isCmd(uint8_t *cmd, const unsigned char *param, uint8_t offset){
 
    // get the size of the command
    uint8_t size;
    size = strlen(param);
 
    // check if they match
    uint8_t i = 0;
    for(i = 0; i < size; i++){
        if (cmd[i + offset] != param[i])
            // no match
            return 0;
    }
    // match found
    return 1;
}
So with above case, that's what I need to do:
Code:
// look for "set" keyword, form location 0
if (isCmd(cmd_string_array, "set", 0){

  // look for "param1" keyword, form location 4
  // "set" + space = 4
  if (isCmd(cmd_string_array, "param1", 4)){

    // look for "state1" keyword, from location 11
    // "set" + space + "param1" + space = 11
    if (isCmd(cmd_string_array, "state1", 11){
      // do stuff for state 1
    }
    else if (isCmd(cmd_string_array, "state2", 11){
      // do stuff for state2
    }
    else if (isCmd(cmd_string_array, "state3", 11){
      // do stuff for state3
    }
    else if (others){
    }
  }
  // look for "param2" etc...
  else if (isCmd(cmd_string_array, "param2", 4)){
    // look for other state within this param2 etc...
  }
}
 
Last edited:

Thread Starter

bug13

Joined Feb 13, 2012
2,002
I find this is very un-readable, and properly not very efficient. What's is a better way to do the this?

thanks guys!!
 

xox

Joined Sep 8, 2017
838
You could use a simple parsing strategy, like:

Code:
#include <stdio.h>
#include <ctype.h>

char* parse(char* buf, char* pat)
{
    if(buf == 0)
        return 0;
    while(isspace(*buf))
        ++buf;
    for(;;)
    {
        char p = *pat++;
        if(p == 0)
            return buf;
        char b = tolower(*buf++);
        if(b == 0 || b != p)
            break;
    }
    return 0;
}

int main(void)
{
/*
    Example #1
*/   
    char* cmd = "set param1 1024";
    puts(parse(parse(cmd, "set"), "param1"));
/*
    Example #2
*/   
    char* val = 0;
    char* set = parse(cmd, "set");
    if(set)
    {
        if(val = parse(set, "param1"))
        {
            puts("set param1:");
            puts(val);
        }
        else if(val = parse(set, "param2"))
        {
            puts("set param2:");
            puts(val);           
        }
    }
}
 

Thread Starter

bug13

Joined Feb 13, 2012
2,002
You could use a simple parsing strategy, like...
Just make sure I understand you code properly, is this correct??

Code:
// return a pointer that is pointing to a location
// that is the end of pattern + 1
char* parse(char* buf, char* pat)
{
    // make sure point is not null
    if(buf == 0)
        return 0;
    // skip all space
    while(isspace(*buf))
        ++buf;
    for(;;)
    {
        // get a char, then point to next char
        char p = *pat++;
        // if its end of char array, return new pointer
        // pointer move to next char of the pattern
        if(p == 0)
            return buf;
        // convert to lower case for comparasion
        char b = tolower(*buf++);
        // exit if end of buffer or
        // one char from buffer != one char from the pattern
        if(b == 0 || b != p)
            break;
    }
    // return null
    return 0;
}
 
Top