Pages: [1]   Go Down
Author Topic: UART command shell server  (Read 2493 times)
0 Members and 1 Guest are viewing this topic.
0
Offline Offline
Newbie
*
Karma: 0
Posts: 5
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

I'm not sure if anyone has done this before, but I think the command shell is pretty useful so I wrote the command shell server, basic IO handling and servo control commands built in, and customized command can be easily integrated.
Oops, seems cannot post an attachment here?
Logged

Bristol, UK
Offline Offline
Edison Member
*
Karma: 1
Posts: 1197
Exhibitor at UK Maker Faire
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

You'll be able to post your code on your second posting (or after that).  It's an anti-spam feature.
Logged

0
Offline Offline
Newbie
*
Karma: 0
Posts: 5
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Well, it seems cannot hold the 600 line code in one post, the first part is the shell command server without the servo handling.
Code:
/*
 * Arduino uart shell command server
 *     -- a simple uart shell command server on Arduino
 *
 * Jiashu Lin, jiashu.lin@gmail.com
 *
 */

/* Macro define */

/* include the servo control commands */
#undef UART_CMD_SERVO

/* include the basic io commands */
#define UART_CMD_BASIC_IO

/* UART command buffer size */
#define UART_BUF_SIZE   32

/* UART command max length */
#define UART_CMD_LENGH_MAX (UART_BUF_SIZE - 1)

/* UART command max parameter count */
#define UART_PARA_CNT_MAX 2

/* UART command shell prompt */
#define UART_PROMPT ">>"

/* type defines */
/* UART command function prototype */
typedef int (*uart_cmd_func)(char * args[], char num_args);

/* UART command structure */
typedef struct uart_cmd_struct
{
  char *name;
  char *help;
  uart_cmd_func do_cmd;
} uart_cmd_struct_t;

/* local variables */
/* UART command buffer */
static unsigned char uart_buf[UART_BUF_SIZE];
/* UART command buffer write pointer */
static unsigned char uart_wptr = 0;
/* UART command parameter pointer */
static char * uart_para_ptr[UART_PARA_CNT_MAX];

/* UART command set array, customized commands may add here */
const uart_cmd_struct_t uart_cmd_set[] =
{
    {"help", "\thelp", uart_cmd_svr_help},
#ifdef UART_CMD_BASIC_IO
    {"pinMode", "\tpinMode [pin_num] [output|input]",uart_cmd_pinMode},
    {"digiWrite", "digiWrite [pin_num] [high|low]",uart_cmd_digiWrite},
    {"digiRead", "digiRead [pin_num]",uart_cmd_digiRead},
    {"analWrite", "analWrite [pin_num] [val]",uart_cmd_analWrite},
    {"analRead", "analRead [pin_num]",uart_cmd_analRead},
#endif //UART_CMD_BASIC_IO
#ifdef UART_CMD_SERVO
    {"servoEnable", "servoEnable [servo_index] [0|1]", uart_cmd_servoEnable},
    {"servoAttach", "servoAttach [servo_index] [pin_num]", uart_cmd_servoAttach},
    {"servoPos", "servoPos [servo_index] [pos]", uart_cmd_servoPos},
    {"servoStat", "servoStat [servo_index]", uart_cmd_servoStat},
#endif //UART_CMD_SERVO
    {0,0,0}
};

/* local function define */
/* flush the UART command buffer */
void uart_cmd_svr_flush_buf(void)
{
    uart_wptr = 0;
    memset(uart_buf,0,sizeof(uart_buf));
    memset(uart_para_ptr,0,sizeof(uart_para_ptr));
}

/* init the UART command server, should call in setup() */
void uart_cmd_svr_init(void)
{
    Serial.begin(9600);
    Serial.flush();
    uart_cmd_svr_flush_buf();
    Serial.println("\n\n   ---ARDUINO UART COMMAND SHELL---");
    Serial.println("[Jiashu Lin - jiashu.lin@gmail.com]\n\n");
    uart_cmd_prompt();
}

/* Execute the command in the command buffer */
void uart_cmd_execute(void)
{
    unsigned char i = 0, para_cnt = 0, err = 0;

    while((para_cnt < UART_PARA_CNT_MAX) && \
          (uart_para_ptr[para_cnt]) && \
          (*uart_para_ptr[para_cnt]))
    {
        para_cnt++;
    }
    
    while(0 != (uart_cmd_set[i].name))
    {
        if(!strcmp((char*)uart_buf,uart_cmd_set[i].name))
        {
          Serial.println();
          err = uart_cmd_set[i].do_cmd(uart_para_ptr, para_cnt);
          Serial.println('\n');
          Serial.println(err,HEX);
          uart_cmd_svr_flush_buf();
          uart_cmd_prompt();
          return;
        }
        i++;
    }

    Serial.println("\nUnknown Command");
    uart_cmd_svr_flush_buf();
    uart_cmd_prompt();
}

/* print the command shell prompt */
void uart_cmd_prompt()
{
  Serial.print('\n');
  Serial.print(UART_PROMPT);
}

/* uart command server service routine, should call in loop() */
void uart_cmd_service()
{
    char c = 0;
    char i = 0;
    while(Serial.available())
    {
      // read one byte from serial port
      c = Serial.read();

      // if the first byte is ' ' or '\n', ignore it
      if((0 == uart_wptr)&&(' ' == c || '\r' == c))
      {
        uart_cmd_prompt();
        continue;
      }

      // if '\n' is read, execute the command
      if('\r' == c)
      {
        uart_cmd_execute();
      }
      // if ' ' is read, record the parameter ptr
      else if(' ' == c)
      {
        // damping the space
        if(uart_buf[uart_wptr-1])
        {
            // replace it with NULL
            uart_buf[uart_wptr] = 0;

            uart_wptr++;

            // record the parameter address
            for(i = 0; i < UART_PARA_CNT_MAX; i++)
            {
                if(!uart_para_ptr[i])
                {
                  uart_para_ptr[i] = (char*)(&uart_buf[uart_wptr]);
                  break;
                }
            }
              
            if(UART_PARA_CNT_MAX == i)
            {
                uart_cmd_execute();
                break;
            }
        }
      }
      // other characters, just record it
      else
      {
          uart_buf[uart_wptr] = c;
          uart_wptr++;
          if(uart_wptr == UART_CMD_LENGH_MAX)
          {
            uart_cmd_execute();
          }
      }
    }
}

/* help command implementation */
int uart_cmd_svr_help(char * args[], char num_args)
{
    char i = 0;

  Serial.println("\nARDUINO COMMAND SHELL HELP\n\n\rCommand list");

    while (uart_cmd_set[i].name)
    {
       Serial.print(uart_cmd_set[i].name);
       Serial.print("\t");
       Serial.println(uart_cmd_set[i].help);
       i++;
    }
    Serial.println("\nCommand parameter uses hex format without '0x' prefix");
    
    return 0;
}

/* convert a hex number string into int */
int str2int(char * str,int * val_p)
{
  int i, len;
  char c;
  
  *val_p = 0;
  len = strlen(str);
  for(i = 0; i < len; i++)
  {
    if(str[i]>='0'&&str[i]<='9')
    {
      (*val_p)+=((str[i]-'0')<<(4*(len-i-1)));
    }
    else if(str[i]>='a'&&str[i]<='f')
    {
      (*val_p)+=((str[i]-'a'+0xa)<<(4*(len-i-1)));
    }
    else
    {
      return 1;
    }
  }
  return 0;
}

#ifdef UART_CMD_BASIC_IO
/* pinMode uart command implementation */
int uart_cmd_pinMode(char * args[],char num_args)
{
  int pin = 0;
  
  if(2 != num_args)
  {
    return 1;
  }

  if(0 != str2int(args[0],&pin))
  {
    return 2;
  }
  
  if(0 == strcmp(args[1],"input"))
  {
    pinMode(pin,INPUT);
  }
  else if(0 == strcmp(args[1],"output"))
  {
    pinMode(pin,OUTPUT);
  }
  else
  {
    return 3;
  }
  
  return 0;
}

/* digiWrite uart command implementation */
int uart_cmd_digiWrite(char * args[],char num_args)
{
  int pin = 0;
  
  if(2 != num_args)
  {
    return 1;
  }

  if(0 != str2int(args[0],&pin))
  {
    return 2;
  }
  
  if(0 == strcmp(args[1],"high"))
  {
    digitalWrite(pin,HIGH);
  }
  else if(0 == strcmp(args[1],"low"))
  {
    digitalWrite(pin,LOW);
  }
  else
  {
    return 3;
  }
  
  return 0;
}

/* digiRead UART command implementation */
int uart_cmd_digiRead(char * args[],char num_args)
{
  int pin = 0;
  
  if(1 != num_args)
  {
    return 1;
  }

  if(0 != str2int(args[0],&pin))
  {
    return 2;
  }

  if(HIGH == digitalRead(pin))
  {
    Serial.println("HIGH");
  }
  else
  {
    Serial.println("LOW");
  }
  
  return 0;
}

/* analRead uart command implementation */
int uart_cmd_analRead(char * args[], char num_args)
{
  int pin = 0;
  int val = 0;

  if(1 != num_args)
  {
    return 1;
  }

  if(0 != str2int(args[0],&pin))
  {
    return 2;
  }
  
  val = analogRead(pin);
  Serial.println(val,HEX);
  
  return 0;
}

/* analWrite uart command implementation */
int uart_cmd_analWrite(char * args[], char num_args)
{
  int pin = 0;
  int val = 0;  

  if(2 != num_args)
  {
    return 1;
  }

  if(0 != str2int(args[0],&pin))
  {
    return 2;
  }

  if(0 != str2int(args[1],&val))
  {
    return 3;
  }

  analogWrite(pin, val);

  return 0;
}
#endif //UART_CMD_BASIC_IO

void setup()
{
  /* initiate the uart command server */
  uart_cmd_svr_init();
    
  /* initiate the servo object */
#ifdef UART_CMD_SERVO
    servo_init();
#endif //UART_CMD_SERVO
}

void loop()
{
  /* service the uart command */
  uart_cmd_service();
  
  /* service the servo*/
#ifdef UART_CMD_SERVO
  servo_service();
#endif //UART_CMD_SERVO
}
Logged

0
Offline Offline
Newbie
*
Karma: 0
Posts: 5
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

The second part: servo handling, just past the following code to the first part and add"#define UART_CMD_SERVO"
Code:
/* servo control uart command implementations */
#ifdef UART_CMD_SERVO
/* include the servo library */
#include <Servo.h>

/* control structure type define */
typedef struct
{
  char pin;
  char enable;
  char pos;
  Servo servo_obj;
}servo_ctrl_t;

/* macro define */
/* max servo count */
#define SERVO_COUNT 2
/* pulse delay time in ms*/
#define REFRESH_TIME 20
/* default servo position on start up */
#define DEFAULT_SERVO_POS 90

/* variable */
/* servo control object */
servo_ctrl_t servo_ctrl[SERVO_COUNT];

/* servoAttach uart command implementation */
int uart_cmd_servoAttach(char* args[], char num_args)
{
  int pin = 0;
  int servo_index = 0;

  if(2 != num_args)
  {
    return 1;
  }

  if(0 != str2int(args[0],&servo_index))
  {
    return 2;
  }

  if(0 != str2int(args[1],&pin))
  {
    return 3;
  }
  
  servo_attach(servo_index, pin);
  
  return 0;
}

/* servoPos uart command implementation */
int uart_cmd_servoPos(char* args[], char num_args)
{
  int pos = 0;
  int servo_index = 0;

  if(2 != num_args)
  {
    return 1;
  }

  if(0 != str2int(args[0],&servo_index))
  {
    return 2;
  }

  if(0 != str2int(args[1],&pos))
  {
    return 3;
  }
  
  servo_pos(servo_index, pos);
  
  return 0;
}

/* servoStat uart command implementation */
int uart_cmd_servoStat(char* args[], char num_args)
{
  int servo_index = 0;

  if((1 != num_args) && \
     (0 != num_args))
  {
    return 1;
  }

  if((1 == num_args) && \
      (0 != str2int(args[0],&servo_index)))
  {
      return 2;
  }
  
  if(0 == num_args)
  {
    for(servo_index = 0; servo_index < SERVO_COUNT; servo_index++)
    {
      servo_stat(servo_index);
    }
  }
  else
  {
    servo_stat(servo_index);
  }
  return 0;
}

/* servoEnable uart command implementation */
int uart_cmd_servoEnable(char* args[], char num_args)
{
  int enable = 0;
  int servo_index = 0;

  if(2 != num_args)
  {
    return 1;
  }

  if(0 != str2int(args[0],&servo_index))
  {
    return 2;
  }

  if(0 != str2int(args[1],&enable))
  {
    return 3;
  }

  servo_enable(servo_index,enable);
  return 0;
}

/* attach a servo to a digital pin,
 * should call before enable the servo
 */
void servo_attach(int servo_index, int pin)
{
  if(servo_index > SERVO_COUNT)
  {
    return;
  }

  if(pin > 13 || pin < 0)
  {
    return;
  }

  servo_ctrl[servo_index].servo_obj.attach(pin);
  servo_ctrl[servo_index].pin = pin;
}

/* set servo position */
void servo_pos(int servo_index, int pos)
{
  if(servo_index > SERVO_COUNT)
  {
    return;
  }

  if(pos > 179 || pos < 0)
  {
    return;
  }
  
  if(servo_ctrl[servo_index].enable)
  {
    servo_ctrl[servo_index].pos = pos;
  }
}

/* print the servo status */
void servo_stat(int servo_index)
{
  
  Serial.print("servo");
  Serial.print(servo_index,HEX);
  if(servo_index >= SERVO_COUNT)
  {
    Serial.print("\tinvalid");
    return;
  }
  
  if(servo_ctrl[servo_index].enable)
  {
    Serial.print("\tenabled");
  }
  else
  {
     Serial.print("\tdisabled");
  }

  Serial.print("\tpin ");
  Serial.print(servo_ctrl[servo_index].pin, HEX);
  Serial.print("\tpos ");
  Serial.println(servo_ctrl[servo_index].pos,HEX);
}

/* enable a servo object, should attach first */
void servo_enable(int servo_index, char enable)
{
  if(enable)
  {
    if(servo_ctrl[servo_index].pin!=-1)
    {
      servo_ctrl[servo_index].enable = 1;
    }
  }
  else
  {
    servo_ctrl[servo_index].enable = 0;
  }
}

/* init the servo objects, call in setup() */
void servo_init(void)
{
  int i;
  for(i = 0; i < SERVO_COUNT; i++)
  {
    servo_ctrl[i].enable = 0;
    servo_ctrl[i].pos = DEFAULT_SERVO_POS;
    servo_ctrl[i].pin = -1;
  }
}

/* servie the servo, call in loop() */
void servo_service(void)
{
  static long last_update = 0;
  int i;
  
  if (millis() - last_update >= REFRESH_TIME)
  {
    for(i = 0; i < SERVO_COUNT; i++)
    {
      if(servo_ctrl[i].enable)
     {
        servo_ctrl[i].servo_obj.write(servo_ctrl[i].pos);
     }
    }
    last_update = millis();
  }
}
#endif //UART_CMD_SERVO
Logged

0
Offline Offline
Newbie
*
Karma: 0
Posts: 6
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

This is great!
Logged

0
Offline Offline
Newbie
*
Karma: 0
Posts: 5
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hey Jiashu,
I found a adoption in http://thomascannon.net/projects/hacking-challenge/
(featured on Hack A Day http://hackaday.com/2010/11/15/playing-hacker-with-a-toy-vault/ (Just for your information smiley-wink)

Thanks for your work!


rf_

edit:

Hint: Remember the hex-notation of numbers. eg to set pin 13 high use:
Code:
>>digiWrite d high
smiley-wink

For a more general purpose Arduino shell see http://bitlash.net/wiki/

For a AVR shell see: http://www.instructables.com/id/AVRSH-A-Command-Interpreter-Shell-for-ArduinoAVR/
[/list]
« Last Edit: November 16, 2010, 11:27:15 am by rf_ » Logged

Pages: [1]   Go Up
Jump to: