/************************************************* Name: aid_cmd.c Purpose: Process commands over serial port to access various capabilities of the PIC. $Id: aid_cmd.c,v 1.4mpw 2004/05/26 19:28:55 aid Exp $ Copyright: This program is copyright 2003, 2004 Stefan Wiechula, Ben Bogart, Yehoshua Bendah, Tim Moody, Ian Garmaise. License: This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA The full text of the GPL is also online: http://www.gnu.org/copyleft/gpl **************************************************/ #include "aid_lib.c" #include /* Introducing the end-of-line (EOL) marker... * * '\n'==0x0A is a "line feed" (LF) character * '\r'==0x0D is a "carriage return" (CR) character * * DOS uses CR followed by LF to mark EOL. * UNIX uses LF alone. * MAC uses CR alone. * * To handle all all cases we accept a '\n' or a '\r'. */ #define isEOLchar(c) ( (c)=='\n' || (c)=='\r' ) /* We will often need to test for whitespace (meaning tab or space characters). * Note that the "isspace" function from is returns true for space, * tab, or newline characters. We treat these differently: space and tab as * token separators and newline as an end of line marker. */ #define isWSchar(c) ((c)==' '||(c)=='\t') /* Below are some input limits. While parsing commands we can check for these * limits and ignore commands that exceed them. */ #define MAX_PWM_FREQ 2500 #define MAX_AID_BUS_ADDRESS 15 #define MAX_AID_BUS_DATA 255 /* Help text describing the available commands... */ const char help_text1[] = "Read (AID bus) --> [rR] [
][*]"; const char help_text2[] = "Write (AID bus) --> [wW]
"; const char help_text3[] = "PWM (duty cycle) --> [pP]
"; const char help_text4[] = "PWM (frequency) --> [pP][fF] [][!]"; const char help_text5[] = "A/D --> [aA]
"; const char help_text6[] = "EOL(end of line) --> [eE][oO][lL] [][]"; const char help_text7[] = "Help --> [hH]"; /* and below are the states the machine may pass through in parsing * those commands. */ enum {INIT, ERROR, R, R_, R_A, R_all, W, W_, W_A, W_A_, W_A_D, P, P_, P_A, P_A_, P_A_DC, PF, PF_, PF_F, PF_default, A, A_, A_A, A_all, E, EO, EOL, EOL_, EOL_R, EOL_N, EOL_RN, H /*, M, MS, MA, MA_, MA_A, MA_A_, MA_A_A, MR, MR_, MR_A, MR_A_, MR_A_A*/ }; /* Acknowledgement, Error, and End Of Line strings. */ char ack[] = "OK"; char err[] = "ERR"; char eol[] = "\r\n"; /* The state machine is driven by characters recieved one at a time over the * serial link. */ int cmd_state; /* This table maps direct routes between cards used by the "map add", "map * remove" and "map show" commands. */ //unsigned char map_table [16][16]; /* Most commands take an address and one or two pieces of auxilary data. */ unsigned char addr; //addr2; int data; //int data2; int data3; const char aid_cmd_c_rev[] = "$Revision: 1.4mpw $ aid_cmd.c"; const char greeting[] = "Hello"; const char prompt[] = "Ready"; /**************************************************************** * puts * * Put a null-terminated string of characters onto the serial link. ****************************************************************/ int puts (const char *s) { while (*s != 0) putch (*s++); return 0; } /* puts */ /**************************************************************** * put3digits * * Type "unsigned char" has a range of [0,255] so any value can be * displayed by 3 decimal digits or less. * ****************************************************************/ void put3digits (unsigned char num) { div_t h = div (num, 100); div_t t = div (h.rem, 10); if (h.quot) { putch ('0' + h.quot); putch ('0' + t.quot); } else if (t.quot) putch ('0' + t.quot); putch ('0' + t.rem); } /* put3digits */ /**************************************************************** * put_some_digits ****************************************************************/ void put_some_digits (unsigned int num) { /*True once we're past the first non-zero digit. ("past leading zeros")*/ unsigned char plz = 0; /* Order of magnitude of the current digit. */ static const unsigned int mag [4] = {10000,1000,100,10}; div_t D; int i; if (!num) { putch('0'); return; } D.rem = num; for (i=0; i < 4; ++i) { D = div (D.rem, mag[i]); if (D.quot || plz) { putch ('0' + D.quot); plz = 1; } } putch ('0' + D.rem); } /* put_some_digits */ /* Emit a greeting, then restart the command processor by * setting state to INIT. */ void aid_cmd_restart(void) { puts(prompt); puts(eol); cmd_state = INIT; return; } /* Emit an acknowledgement message then go back to state INIT. */ void ack_then_INIT(void) { puts(eol); puts(ack); puts(eol); cmd_state = INIT; return; } /* Emit an error message then go back to state INIT. */ void err_then_INIT(void) { puts(eol); puts(err); puts(eol); cmd_state = INIT; return; } void cmd_next_char(unsigned char inchar) { if (isalpha(inchar)) { inchar = tolower(inchar); } switch (cmd_state) { case INIT: if (inchar=='r') { cmd_state = R; } else if (inchar=='w') { cmd_state = W; } else if (inchar=='p') { cmd_state = P; } else if (inchar=='a') { cmd_state = A; } else if (inchar=='e') { cmd_state = E; } else if (inchar=='h') { cmd_state = H; } /* else if (inchar=='m') { cmd_state = M; } */ else if (isEOLchar(inchar)) { /* Blank line? We didn't get a command so print the * error message and stay in state INIT. */ puts(eol); puts(err); puts(eol); } break; case ERROR: if (isEOLchar(inchar)) { err_then_INIT(); } /* Else stay here and keep eating characters. */ break; case R: if (isWSchar(inchar)) { cmd_state = R_; } else if (isEOLchar(inchar)) { err_then_INIT(); } else { cmd_state = ERROR; } break; case R_: if (isdigit(inchar)) { addr = inchar - '0'; cmd_state = R_A; } else if (inchar=='*') { cmd_state = R_all; } else if (isWSchar(inchar)) { /* Any amount of whitespace is ok. */ } else if (isEOLchar(inchar)) { err_then_INIT(); } else { cmd_state = ERROR; } break; case R_all: if (isEOLchar(inchar)) { puts(eol); for (addr=0; addr<=15; addr++) { data = aid_bus_read(addr); put_some_digits(data); putch(' '); } ack_then_INIT(); } else { cmd_state = ERROR; } break; case R_A: if (isEOLchar(inchar)) { data = aid_bus_read(addr); puts(eol); put_some_digits(data); ack_then_INIT(); } else if (isdigit(inchar)) { addr *= 10; addr += (inchar - '0'); if (addr > MAX_AID_BUS_ADDRESS) { cmd_state = ERROR; } } else { cmd_state = ERROR; } break; case W: if (isWSchar(inchar)) { cmd_state = W_; } else if (isEOLchar(inchar)) { err_then_INIT(); } else { cmd_state = ERROR; } break; case W_: if (isdigit(inchar)) { addr = inchar - '0'; cmd_state = W_A; } else if (isWSchar(inchar)) { /* Any amount of whitespace is ok. */ } else if (isEOLchar(inchar)) { err_then_INIT(); } else { cmd_state = ERROR; } break; case W_A: if (isWSchar(inchar)) { cmd_state = W_A_; } else if (isdigit(inchar)) { addr *= 10; addr += (inchar - '0'); if (addr > MAX_AID_BUS_ADDRESS) { cmd_state = ERROR; } } else if (isEOLchar(inchar)) { err_then_INIT(); } else { cmd_state = ERROR; } break; case W_A_: if (isdigit(inchar)) { data = inchar - '0'; cmd_state = W_A_D; } else if (isWSchar(inchar)) { /* Any amount of whitespace is ok. */ } else if (isEOLchar(inchar)) { err_then_INIT(); } else { cmd_state = ERROR; } break; case W_A_D: if (isdigit(inchar)) { data *= 10; data += inchar - '0'; if (data > MAX_AID_BUS_DATA) { cmd_state = ERROR; } } else if (isEOLchar(inchar)) { aid_bus_write(addr,data); ack_then_INIT(); } else { cmd_state = ERROR; } break; case P: if (isWSchar(inchar)) { cmd_state = P_; } else if (inchar=='f') { cmd_state = PF; } else if (isEOLchar(inchar)) { err_then_INIT(); } else { cmd_state = ERROR; } break; case P_: /* AVR models have four PWM chanels */ /* 040901 MPW */ if (inchar >='0' && inchar <= '3') /* 040901 MPW */ { addr = inchar - '0'; cmd_state = P_A; } else if (isWSchar(inchar)) { /* Any amount of whitespace is ok. */ } else if (isEOLchar(inchar)) { err_then_INIT(); } else { cmd_state = ERROR; } break; case P_A: if (isWSchar(inchar)) { cmd_state = P_A_; } else if (isEOLchar(inchar)) { err_then_INIT(); } else { cmd_state = ERROR; } break; case P_A_: if (isdigit(inchar)) { data = inchar - '0'; cmd_state = P_A_DC; } else if (isWSchar(inchar)) { /* Any amount of whitespace is ok. */ } else if (isEOLchar(inchar)) { err_then_INIT(); } else { cmd_state = ERROR; } break; case P_A_DC: if (isdigit(inchar)) { data *= 10; data += inchar - '0'; if (data > 100) { /* By definition, the duty cycle is not greater than 100% */ cmd_state = ERROR; } } else if (isEOLchar(inchar)) { set_pwm_duty_cycle(addr, data); ack_then_INIT(); } else { cmd_state = ERROR; } break; case PF: if (isWSchar(inchar)) { cmd_state = PF_; } else if (isEOLchar(inchar)) { err_then_INIT(); } else { cmd_state = ERROR; } break; case PF_: if (isdigit(inchar)) { data = inchar - '0'; cmd_state = PF_F; } else if (inchar=='!') { cmd_state = PF_default; } else if (isWSchar(inchar)) { /* Any amount of whitespace is ok. */ } else if (isEOLchar(inchar)) { err_then_INIT(); } else { cmd_state = ERROR; } break; case PF_F: if (isdigit(inchar)) { data *= 10; data += inchar - '0'; if (data > MAX_PWM_FREQ) { cmd_state = ERROR; } } else if (isEOLchar(inchar)) { set_pwm_frequency(data); ack_then_INIT(); } else { cmd_state = ERROR; } break; case PF_default: if (isEOLchar(inchar)) { set_pwm_frequency(DEFAULT_PWM_FREQ); ack_then_INIT(); } else { cmd_state = ERROR; } break; case A: if (isWSchar(inchar)) { cmd_state = A_; } else if (isEOLchar(inchar)) { err_then_INIT(); } else { cmd_state = ERROR; } break; case A_: if (inchar>='0' && inchar<='7') { addr = inchar - '0'; cmd_state = A_A; } else if (inchar=='*') { cmd_state = A_all; } else if (isWSchar(inchar)) { /* Any amount of whitespace is ok. */ } else if (isEOLchar(inchar)) { err_then_INIT(); } else { cmd_state = ERROR; } break; case A_A: if (isEOLchar(inchar)) { data = get_ad(addr); puts(eol); put_some_digits(data); ack_then_INIT(); } else { cmd_state = ERROR; } break; case A_all: if (isEOLchar(inchar)) { puts(eol); for (addr=0; addr<=7; addr++) { data = get_ad(addr); put_some_digits(data); putch(' '); } ack_then_INIT(); } else { cmd_state = ERROR; } break; case E: if (inchar=='o') { cmd_state = EO; } else if (isEOLchar(inchar)) { err_then_INIT(); } else { cmd_state = ERROR; } break; case EO: if (inchar=='l') { cmd_state = EOL; } else if (isEOLchar(inchar)) { err_then_INIT(); } else { cmd_state = ERROR; } break; case EOL: if (isWSchar(inchar)) { cmd_state = EOL_; } else if (isEOLchar(inchar)) { err_then_INIT(); } else { cmd_state = ERROR; } break; case EOL_: if (inchar=='r') { cmd_state = EOL_R; } else if (inchar=='n') { cmd_state = EOL_N; } else if (isEOLchar(inchar)) { err_then_INIT(); } else { cmd_state = ERROR; } break; case EOL_R: if (inchar=='n') { cmd_state = EOL_RN; } else if (isEOLchar(inchar)) { eol[0] = '\r'; eol[1] = '\0'; ack_then_INIT(); } else { cmd_state = ERROR; } break; case EOL_N: if (isEOLchar(inchar)) { eol[0] = '\n'; eol[1] = '\0'; ack_then_INIT(); } else { cmd_state = ERROR; } break; case EOL_RN: if (isEOLchar(inchar)) { eol[0] = '\r'; eol[1] = '\n'; eol[2] = '\0'; ack_then_INIT(); } else { cmd_state = ERROR; } break; case H: if (isEOLchar(inchar)) { puts(eol); puts(help_text1); puts(eol); puts(help_text2); puts(eol); puts(help_text3); puts(eol); puts(help_text4); puts(eol); puts(help_text5); puts(eol); puts(help_text6); puts(eol); puts(help_text7); puts(eol); ack_then_INIT(); } else { cmd_state = ERROR; } break; /* case M: if (inchar=='s') { cmd_state = MS; } else if (inchar=='a') { cmd_state = MA; } else if (inchar=='r') { cmd_state = MR; } else { cmd_state = ERROR; } break; case MS: if (isEOLchar(inchar)) { for (addr=0; addr<16; addr++) { for (addr2=0; addr2<16; addr2++) { put_some_digits(map_table[addr][addr2]); putch(' '); } puts(eol); } puts(ack); puts(eol); } else { cmd_state = ERROR; } break; case MA: cmd_state = INIT; break; case MR: cmd_state = INIT; break; */ } /*switch*/ } /*next_char*/