Skip to content

Commit

Permalink
Moved command parser to library, added motor test (which is working w…
Browse files Browse the repository at this point in the history
…ith a motor!)
  • Loading branch information
guyc committed Jan 9, 2012
1 parent efd49b1 commit ab143c2
Show file tree
Hide file tree
Showing 5 changed files with 338 additions and 0 deletions.
1 change: 1 addition & 0 deletions .gitignore
@@ -0,0 +1 @@
*~
105 changes: 105 additions & 0 deletions Command.cpp
@@ -0,0 +1,105 @@
/*
Copyright (c) 2011 Guy Carpenter
*/

#include <Arduino.h>
#include "Command.h"

#define CMDBUF_LEN 40


void Command::skipWhitespace(char **line, int *len)
{
while (*len > 0 && **line == ' ') {
(*len)--;
(*line)++;
}
}


boolean Command::parseCommand(char **line, int *len, char *cmd)
{
boolean result = false;
skipWhitespace(line, len);
if (*len > 0) {
*cmd = **line;
(*len)--;
(*line)++;
result = true;
}
return result;
}


boolean Command::parseInteger(char **line, int *len, value_t *value)
{
boolean result = false;
*value = 0;
while (*len>0 && **line>='0' && **line<='9') {
*value = *value * 10 + (**line - '0');
(*len)--;
(*line)++;
result = true;
}
return result;
}

boolean Command::parseTuple(char **line, int *len, value_t *tuple)
{
boolean result = false;
skipWhitespace(line, len);
for (int i=0; i<COMMAND_TUPLE_LEN; i++) {
if (parseInteger(line, len, tuple+i+1)) {
result = true;
tuple[0] = i+1;
if (*len>0 && **line == ',') {
// found comma, so more integers expected
(*len)--;
(*line)++;
result = false; // need another int to succeed
} else {
break;
}
} else {
break;
}
}
return result;
}

boolean Command::parseLine(char *line, int len)
{
boolean result = false;
if (parseCommand(&line, &len, &command) &&
parseTuple(&line, &len, address) &&
parseTuple(&line, &len, value)) {
result = true;
} else {
Serial.println("$Error Invalid command syntax");
}
return result;
}


boolean Command::parseInput()
{
boolean result = false;
static char line[CMDBUF_LEN]; // NOT zero terminated
static int len = 0;

if (Serial.available()) {
char c = Serial.read();
if (c==10 || c==13) {
result = parseLine(line, len);
len = 0;
} else if (len < CMDBUF_LEN) {
line[len++] = c;
}
return result;
}
}





27 changes: 27 additions & 0 deletions Command.h
@@ -0,0 +1,27 @@

#ifndef Command_h
#define Command_h

#include <Arduino.h>
#define COMMAND_TUPLE_LEN 3
typedef unsigned int value_t;

class Command
{
public:
char command;
value_t address[COMMAND_TUPLE_LEN+1];
value_t value[COMMAND_TUPLE_LEN+1];

private:
void skipWhitespace(char**, int*);
boolean parseCommand(char **line, int *len, char *cmd);
boolean parseInteger(char **line, int *len, value_t *value);
boolean parseTuple(char **line, int *len, value_t *tuple);
boolean parseLine(char *line, int len);
public:
boolean parseInput();
};

#endif

113 changes: 113 additions & 0 deletions motortest/motortest.ino
@@ -0,0 +1,113 @@
int motorPin1 = 8; // orange
int motorPin2 = 9; // brown
int motorPin3 = 10; // blue
int motorPin4 = 11; // green
int delayTime = 5;
int count = 157;

// 6 steps per motor rotation
// 180:1 gear
// 180 * 6 steps per rotation
// 2 degrees per 6-states
// stops liit to 315 degrees
// 315 = 157.5 steps
// maximum speed seems to be about 800 microseconds delay

void setup() {
pinMode(motorPin1, OUTPUT);
pinMode(motorPin2, OUTPUT);
pinMode(motorPin3, OUTPUT);
pinMode(motorPin4, OUTPUT);
center();
}

void pause()
{
delayMicroseconds(800);
}

void state1() {
digitalWrite(motorPin1, HIGH);
digitalWrite(motorPin2, LOW);
digitalWrite(motorPin3, LOW);
digitalWrite(motorPin4, HIGH);
pause();
}

void state2() {
digitalWrite(motorPin1, HIGH);
digitalWrite(motorPin2, LOW);
digitalWrite(motorPin3, LOW);
digitalWrite(motorPin4, LOW);
pause();
}

void state3() {
digitalWrite(motorPin1, HIGH);
digitalWrite(motorPin2, HIGH);
digitalWrite(motorPin3, HIGH);
digitalWrite(motorPin4, LOW);
pause();
}

void state4()
{
digitalWrite(motorPin1, LOW);
digitalWrite(motorPin2, HIGH);
digitalWrite(motorPin3, HIGH);
digitalWrite(motorPin4, LOW);
pause();
}

void state5() {
digitalWrite(motorPin1, LOW);
digitalWrite(motorPin2, HIGH);
digitalWrite(motorPin3, HIGH);
digitalWrite(motorPin4, HIGH);
pause();
}

void state6()
{
digitalWrite(motorPin1, LOW);
digitalWrite(motorPin2, LOW);
digitalWrite(motorPin3, LOW);
digitalWrite(motorPin4, HIGH);
pause();
}


void center()
{
for (int i=0;i<count;i++) {
state6();
state5();
state4();
state3();
state2();
state1();
}

for (int i=0;i<count;i++) {
state1();
state2();
state3();
state4();
state5();
state6();
}

for (int i=0;i<count/2;i++) {
state6();
state5();
state4();
state3();
state2();
state1();
}

}

void loop()
{
}
92 changes: 92 additions & 0 deletions notes.txt
@@ -0,0 +1,92 @@
PROTOCOL:

Actions:

DIAL <n> <value>
set gauge to value
I think 100 is not enough steps,
so maybe express as float or 1000ths or 0..255
or query the device to get the fsd range

LED <n> <value>
set led on or off. If we have multiple leds
per device we could address them as 1,1
RGB values? LED 1,1 100,255,128

So what about generalizing dial and led to a single command:

SET a v
where n is an address (which could be a comma separated list)
and v is a value (which could be a comma separated list)

SET 0 0
GET 0 echos back "a v" (or maybe "a v t", see below regarding time stamps)

Later if we support input we can get unsolicited input: "a v"
in the same format, so a push button event might be:

0,1 1
0,1 0

Maybe we want a time stamp to help determine duration of events?

0,1 1 1234
0,1 1 1238

======================================================================
command parser

What we want to get:
First letter of command
Address tuple
Value tuple

Each tuple should be
count,value0,value1...

parser should call
command_handler(command, address, value)
where command is a byte representing the command.
(the first character of the command?), address is a vector of bytes,
and value is a vector of bytes.

Hmmm - that limits me to 256 step resolution, which seems poor.
What about making the values 16-bit signed integers instead?
That seems better.

S 0,0 1000
S 0,0 0
G 0,0

Maximum tuple length is 3 (for rgb) so we need 2 x 4 int16 arrays or 16 bytes.
Seems fine.

So in loop we call the parser
loop:
if there is a character ready, parse_character
end

parse_command checks for serial input.
It could state-machine or parse on CRLF. The latter
would allow backspaces!

parse_character(c)
if input
if input is crlf terminate input string and parse it
else
if buffer is not full add to end of buffer

parse_line(buffer, length)
c = parse_command
a = parse_tuple
v = parse_tuple

command_handler(c,a,v)








0 comments on commit ab143c2

Please sign in to comment.