// // wandio.c - wand functions // // Copyright (C) 2006 Nathan (Acorn) Pooley // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // version 2 as published by the Free Software Foundation. // // 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 (gpl.txt) 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. // // You can contact the author, Nathan (Acorn) Pooley, by writing // to Nathan (Acorn) Pooley, 949 Buckeye Drive, Sunnyvale, CA 94086, USA // or through the form at http://www.rawbw.com/~acorn/wand/feedback.html // // //#@DOC@ functions for communicating with the wand (over serial port) //########################################################################### //############################### INCLUDES ################################## //########################################################################### #include "wandio.h" #include "ac_serialio.h" #include "ac_fdio.h" #include "ac_time.h" #include "ac_log.h" #include <stdio.h> #include <stdarg.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <ctype.h> //########################################################################### //############################### DEFINES ################################### //########################################################################### #define CTRL(c) ((c) & 0x1f) //########################################################################### //############################### TYPEDEFS ################################## //########################################################################### typedef enum WandStateEnum { WS_UNKNOWN, WS_RECOVER, WS_PROMPT, WS_CMD, WS_PROMPT_PLUS, WS_ECHO, WS_REPLY, WS_DISCONNECT, WS_END } WandState; typedef enum WandCKSStateEnum { WCKS_DISABLED, WCKS_NEWLINE, WCKS_LINE, WCKS_AT, WCKS_C1, WCKS_C2, WCKS_ERR, WCKS_GARBAGE, WCKS_END } WandCKSState; struct WandInfoRec { AcSerial *sio; int fd; AcFdGroup *grpNull; AcFdGroup *grpHandler; AcFdGroup *grpSleep; char *outBuf; int outBufLen; WandState state; int line_cnt; int cksum_start_cnt; int cksum; WandCKSState cksum_state; char recoverStr[4]; char *recoverPtr; AcTime recoverTime; int debugLevel; int wasdisconnect; int quiet; WandOutFunction wandOutFunc; void *wandOutFuncData; char lastprompt[1000]; char line[1000]; }; //########################################################################### //############################### PROTOTYPES ################################ //########################################################################### static void WandFlush(WandInfo *wi); //########################################################################### //############################### GLOBALS ################################### //########################################################################### //########################################################################### //############################### CODE ###################################### //########################################################################### //=========================================================================== // WandSleep() //=========================================================================== // // return values: // -2 = timeout // 2 = keyboard input available // static int WandSleep(WandInfo *wi, unsigned long usec) { if (usec == 0) return -2; return AcFdGroupWaitTimeout(wi->grpSleep,usec); } //=========================================================================== // makePrintable() //=========================================================================== static char *makePrintable(char *s,int cnt) { static char buf[2000]; char *d = buf; while(cnt>0) { if (d-buf > sizeof(buf)-10) { *(d++) = '\\'; *(d++) = '.'; *(d++) = '.'; *(d++) = '.'; break; } if (*s < ' ' || *s > '}' || *s == '\\') { d += sprintf(d,"\\%02x",*(unsigned char*)s); } else { *(d++) = *s; } s++; cnt--; } *d = 0; return buf; } //=========================================================================== // WandPromptWait() - wait for prompt //=========================================================================== // // Return // 0 success // 2 keypressed // -2 timeout // int WandPromptWait(WandInfo *wi, AcTime *timeout) { int rv = 0; unsigned long usec = 200000; AcTime t0; AcTimeGet(&t0); if (wi->debugLevel >= 9) { AcLogPrintf(0,4,"9:<enter WandPromptWait>\n"); fflush(stdout); } if (timeout && timeout->sec == 0 && timeout->usec < usec) { usec = timeout->usec; } while(wi->state != WS_PROMPT || wi->recoverPtr) { int wrv = AcFdGroupWaitTimeout(wi->grpHandler,usec); if (wrv) { if (wrv < 0) { WandRecover(wi); } rv = wrv; break; } // // check timeout // if (timeout) { if (wi->state != WS_PROMPT || wi->recoverPtr) { AcTime t1, d; AcTimeGet(&t1); AcTimeDiff(&d,&t1,&t0); if (d.sec > timeout->sec || (d.sec == timeout->sec && d.usec > timeout->usec)) { // // timed out // if (wi->debugLevel >= 9) { AcLogPrintf(0,4,"9:<exit WandPromptWait (timeout)>\n"); fflush(stdout); } return -2; } } } } if (wi->debugLevel >= 9) { AcLogPrintf(0,4,"9:<exit WandPromptWait>\n"); fflush(stdout); } return rv; } //=========================================================================== // WandPromptWaitUsec() - wait for prompt with usec timeout //=========================================================================== // // Return // 0 success // 2 keypressed // -2 timeout // int WandPromptWaitUsec(WandInfo *wi, unsigned long usec) { AcTime timeout; timeout.sec = 0; while(usec > 1000000) { timeout.sec++; usec -= 1000000; } timeout.usec = usec; return WandPromptWait(wi,&timeout); } //=========================================================================== // WandGetPrompt() //=========================================================================== char *WandGetPrompt(WandInfo *wi) { return strdup(wi->lastprompt); } //=========================================================================== // WandPrompt() //=========================================================================== void WandPrompt(WandInfo *wi) { if (wi->state != WS_DISCONNECT && wi->state != WS_PROMPT) { AcTime timeout; timeout.sec = 1; timeout.usec = 0; WandPromptWait(wi,&timeout); } if (wi->state == WS_PROMPT) { wi->wasdisconnect = 0; AcLogPrompt(0,wi->lastprompt,0); } else if (wi->state == WS_DISCONNECT) { wi->wasdisconnect = 1; AcLogPrompt(0,"(disconnect)> ",0); } } #if 1 //=========================================================================== // WandWrite() - write chars to wand (raw) //=========================================================================== int WandWrite(WandInfo *wi, const char *buf, int cnt) { int sum = 0; if (wi->debugLevel >= 9) { int i; AcLogPrintf(0,4,"9:--WandWrite: "); for (i=0; i<cnt; i++) { if (buf[i]>=0x20 && buf[i]<0x7f) { AcLogPrintf(0,4,"9:%c",buf[i]); } else { AcLogPrintf(0,4,"9:\\%02x",buf[i]); } } AcLogPrintf(0,4,"9:\n"); } while (cnt>0) { int n = write(wi->fd, buf, 1); AcLogWrite(0,1,buf,1); if (!n) break; sum += n; buf += n; cnt -= n; if (cnt == 0) break; #if 0 // // Do this to slow things down if serial does not work right // if ((sum & 0xf) == 0) { if (WandSleep(wi,20000) == 2) return sum; //if (WandSleep(wi,1000) == 2) return sum; } #endif } AcLogFlush(0); return sum; } #else //=========================================================================== // WandWrite() - write chars to wand (raw) SLOW BUT WORKS!! //=========================================================================== int WandWrite(WandInfo *wi, const char *buf, int cnt) { int sum = 0; if (wi->debugLevel >= 9) { int i; AcLogPrintf(0,4,"9:--WandWrite: "); for (i=0; i<cnt; i++) { if (buf[i]>=0x20 && buf[i]<0x7f) { AcLogPrintf(0,4,"9:%c",buf[i]); } else { AcLogPrintf(0,4,"9:\\%02x",buf[i]); } } AcLogPrintf(0,4,"9:\n"); } while (cnt>0) { int n = write(wi->fd, buf, 1); AcLogWrite(0,1,buf,1); if (!n) break; sum += n; buf += n; cnt -= n; if (cnt == 0) break; //if (WandSleep(wi,20000) == 2) return sum; if (WandSleep(wi,1000) == 2) return sum; } AcLogFlush(0); return sum; } #endif //=========================================================================== // WandWriteChar() - write 1 char to wand //=========================================================================== int WandWriteChar(WandInfo *wi, int ch) { char buf[1]; buf[0] = ch; return WandWrite(wi, buf, 1); } //=========================================================================== // WandWriteTimed() - write chars to wand slowly //=========================================================================== int WandWriteTimed(WandInfo *wi, const char *buf, int cnt, unsigned long usec) { int sum = 0; while(cnt>0) { if (WandSleep(wi,usec) == 2) return sum; if (!WandWrite(wi, buf, 1)) { return sum; } buf++; cnt--; sum++; } return sum; } //=========================================================================== // WandIsRunning() - true if wand is running (as of last prompt) //=========================================================================== // // Return // 0 halted or disconnected // 1 running (RUN or DEBUG mode) // int WandIsRunning(WandInfo *wi) { printf(">>>>>>>>> state=%d lastpompt=%s\n",wi->state,wi->lastprompt); switch(wi->state) { case WS_RECOVER: case WS_PROMPT: case WS_CMD: case WS_PROMPT_PLUS: case WS_ECHO: case WS_REPLY: break; case WS_DISCONNECT: case WS_UNKNOWN: default: return 0; } if (!strncmp(wi->lastprompt,"Debug",4) || !strncmp(wi->lastprompt,"Run",3)) { return 1; } return 0; } #if 1 //=========================================================================== // WandHalt() - halt the wand //=========================================================================== // // Return // 0 success // 2 keypressed // -2 timeout // int WandHalt(WandInfo *wi) { int rv; int i; unsigned long usec1 = 100000; unsigned long usec2 = 1000000; static char hcmd1[] = "H\n"; static char hcmd2[] = "Hbeefb055\n"; hcmd1[1] = 0x0a; hcmd2[9] = 0x0a; for (i=0; ; i++) { char *hcmd = hcmd1; int len = 2; if (i<3 && !strncmp(wi->lastprompt,"Run>",4)) { i = 3; } if (i>2 && (i&1)) { hcmd = hcmd2; len = 10; } WandWriteTimed(wi, hcmd, len, usec1); wi->state = WS_CMD; WandPromptWaitUsec(wi, usec2); if (wi->state == WS_PROMPT) { if (!strncmp(wi->lastprompt,"Halt",4)) { if (wi->debugLevel >= 9) { AcLogPrintf(0,4,"9:--Halt succeeded\n"); } return 0; } } rv = WandRecoverWait(wi); // // return if keypressed // if (rv == 2) return 2; if (i>3) { usec1 *= 2; usec2 *= 2; } if (usec1 > 1000000) { usec1 = 1000000; } if (usec2 > 5000000) { usec2 = 5000000; } if (i>1) { AcLogPrintf(0,4, "2:Attempting to halt wand... (usec1=%ld usec2=%ld)\n", usec1,usec2); } } } #else //=========================================================================== // WandHalt() - halt the wand //=========================================================================== // // return 0 on success // return -1 on failure // int WandHalt(WandInfo *wi) { static AcTime timeout1; static AcTime timeout2; static char hcmd1[] = "_H_"; static char hcmd2[] = "_Hbeefb055_"; unsigned long usec = 250000; AcTime *timeout = &timeout1; if (hcmd1[0] == '_') { hcmd1[0] = CTRL('X'); hcmd2[0] = CTRL('X'); hcmd1[sizeof(hcmd1)-2] = 0x0a; hcmd2[sizeof(hcmd2)-2] = 0x0a; timeout1.sec = 0; timeout1.usec = 100000; timeout2.sec = 1; timeout2.usec = 0; } while(1) { // // try simple halt command // if (wi->debugLevel >= 9) { AcLogPrintf(0,4,"9:--Attempting to Halt wand with H command\n"); } WandWriteTimed(wi, hcmd1, sizeof(hcmd1)-1, usec); if (WandSleep(wi,usec) == 2) { AcLogPrintf(0,4,"3:Halt aborted by keyboard!\n"); return -1; } WandPromptWait(wi, timeout); // // halted yet? // if (wi->state == WS_PROMPT) { if (!strncmp(wi->lastprompt,"Halt",4)) { if (wi->debugLevel >= 9) { AcLogPrintf(0,4,"9:--Halt succeeded\n"); } return 0; } } // // taking a while - tell the user // AcLogPrintf(0,4,"2:Attempting to halt wand... (usec=%ld)\n",usec); // // try complex halt command // if (wi->debugLevel >= 9) { AcLogPrintf(0,4,"9:--simple H command failed\n"); AcLogPrintf(0,4, "9:--Attempting to Halt wand with password H command\n"); } WandWriteTimed(wi, hcmd2, sizeof(hcmd2)-1, usec); if (WandSleep(wi,usec) == 2) { AcLogPrintf(0,4,"3:Halt aborted by keyboard!\n"); return -1; } WandPromptWait(wi, timeout); // // halted yet? // if (wi->state == WS_PROMPT) { if (!strncmp(wi->lastprompt,"Halt",4)) { if (wi->debugLevel >= 9) { AcLogPrintf(0,4,"9:--Halt succeeded\n"); } return 0; } } // // increase the time between chars // if (usec < 2000000) { usec *= 2; } else { AcLogPrintf(0,4,"1:Failed to halt wand!\n"); return -1; } timeout = &timeout2; if (wi->debugLevel >= 9) { AcLogPrintf(0,4,"9:--Increasing halt char timeout to %f seconds\n", (double)usec/1000000.0); } } } #endif //=========================================================================== // WandOutCallback() - set callback for wand output text //=========================================================================== void WandOutCallback(WandInfo *wi, WandOutFunction func, void *data) { wi->wandOutFunc = func; wi->wandOutFuncData = data; } //=========================================================================== // WandCmdf() //=========================================================================== int WandCmdf(WandInfo *wi, const char *fmt, ...) { int ccnt; va_list va; char cbuf[1000]; char rbuf[1000]; char *s; char *r; char *se; char *re; va_start(va, fmt); ccnt = vsnprintf(cbuf,sizeof(cbuf)-5,fmt,va); va_end(va); if (wi->debugLevel >= 9) { AcLogPrintf(0,4,"9:--Got CMD: '%s'\n",cbuf); } if (wi->state != WS_PROMPT) { WandRecoverWait(wi); } wi->state = WS_CMD; #if 0 // // handle halt command specially // if (!strcmp(cbuf,"H")) { return WandHalt(wi); } #endif if (ccnt) { s = cbuf; se = cbuf + ccnt; while(s != se) { s += WandWrite(wi, s, ccnt); } s = cbuf; while(s != se) { int rcnt = 0; int rv = AcFdGroupWaitTimeout(wi->grpNull,250000); if (rv) { AcLogPrintf(0,4,"1:Wand command failed: '%s'\n",cbuf); WandRecoverWait(wi); return -1; // timeout } rcnt = read(wi->fd, rbuf, sizeof(rbuf)); AcLogWrite(0,2,rbuf,rcnt); AcLogFlush(0); rbuf[rcnt] = 0; r = rbuf; re = r + rcnt; while(r != re && s != se) { if (*r != *s) { AcLogPrintf(0,4,"5:Error in command: '%s'\n",cbuf); AcLogPrintf(0,4,"5:Error: Wand sent: '%s' (bad echo)\n", makePrintable(rbuf,rcnt)); return -1; } wi->cksum += *s; s++; r++; } } if (r != re) { AcLogPrintf(0,4,"5:Error in command: '%s'\n",cbuf); AcLogPrintf(0,4,"5:Error: Wand sent: '%s' (too many)\n", makePrintable(rbuf,re-rbuf)); return -1; } } if (wi->debugLevel >= 9) { AcLogPrintf(0,4,"9:--Sending LF\n"); } cbuf[0] = 0xa; #if 1 // this improves reliability significantly WandSleep(wi,20000); #endif WandWrite(wi, cbuf, 1); return 0; } //=========================================================================== // WandCmdfStr() - send wand command & get result in string (free str when done) //=========================================================================== char *WandCmdfStr(WandInfo *wi, const char *fmt, ...) { va_list va; char cbuf[1000]; static char buf[20000]; char *s; int cnt; int rv; AcTime t0; if (wi->outBuf) { AcLogPrintf(0,4,"0:Error: called WandCmdfStr() but outBuf != 0\n"); return 0; } va_start(va, fmt); cnt = vsnprintf(cbuf,sizeof(buf)-5,fmt,va); va_end(va); cbuf[cnt] = 0; rv = WandCmdf(wi, "%s", cbuf); if (rv) return 0; wi->outBuf = buf; wi->outBufLen = sizeof(buf)-1; s = buf; AcTimeGet(&t0); while(wi->state != WS_PROMPT) { int wrv = AcFdGroupWait(wi->grpHandler); if (wrv) { WandRecoverWait(wi); return 0; } if (wi->outBuf == s) { AcTime t1, d; AcTimeGet(&t1); AcTimeDiff(&d,&t1,&t0); //if (d.sec > 1 || d.usec > 250000) { if (d.sec >= 2) { if (wi->outBuf == buf) { AcLogPrintf(0,4, "5:Error: no response from cmd '%s'\n",cbuf); } else { *(wi->outBuf) = 0; AcLogPrintf(0,4, "5:Error: incomplete response from cmd '%s'\n",cbuf); AcLogPrintf(0,4,"5:============== start response\n"); AcLogPrintf(0,4,"5:%s\n",buf); AcLogPrintf(0,4,"5:============== end response\n"); } WandRecoverWait(wi); return 0; } } else { AcTimeGet(&t0); } s = wi->outBuf; } cnt = wi->outBuf - buf; s = malloc(cnt+1); if (s) { memcpy(s,buf,cnt); s[cnt] = 0; if (cnt > 0 && s[cnt-1] == '\n') s[cnt-1] = 0; } wi->outBuf = 0; wi->outBufLen = 0; return s; } //=========================================================================== // wandChar() //=========================================================================== static void wandChar(WandInfo *wi, int c) { char *outStr = 0; char *msg = ""; if (wi->recoverPtr) { if (c == wi->recoverPtr[0]) { wi->recoverPtr++; if (wi->debugLevel >= 9) { AcLogPrintf(0,4,"9:--recoverPtr='%s'\n",wi->recoverPtr); } if (!wi->recoverPtr[0]) { wi->recoverPtr = 0; } } else { wi->recoverPtr = wi->recoverStr; } } if ((c==0x0a || c==0x0d) && wi->cksum_state != WCKS_DISABLED) { if (wi->cksum_state == WCKS_GARBAGE) { msg = "<garbage>"; } else if (wi->cksum_state != WCKS_C2) { msg = "<BAD CHECKSUM>"; } wi->cksum_state = WCKS_NEWLINE; wi->cksum = 0; } else switch(wi->cksum_state) { case WCKS_NEWLINE: if (c=='\n' || c=='\r') { wi->cksum = 0; break; } wi->cksum_state = WCKS_LINE; case WCKS_LINE: if (c=='@') { wi->cksum_state = WCKS_AT; wi->cksum_start_cnt = wi->line_cnt; } else { wi->cksum += c; } break; case WCKS_AT: if (isxdigit(c)) { int val = isdigit(c) ? c-'0' : toupper(c)-'A'+10; if (val == ((wi->cksum>>4)&0xf)) { wi->cksum_state = WCKS_C1; break; } } wi->cksum_state = WCKS_LINE; wi->cksum += '@'; wi->cksum += c; break; case WCKS_C1: if (isxdigit(c)) { int val = isdigit(c) ? c-'0' : toupper(c)-'A'+10; if (val == ((wi->cksum)&0xf)) { wi->cksum_state = WCKS_C2; break; } } wi->cksum_state = WCKS_LINE; wi->cksum += '@'; wi->cksum += wi->line[wi->line_cnt-1]; wi->cksum += c; break; case WCKS_C2: wi->cksum_state = WCKS_LINE; break; case WCKS_GARBAGE: case WCKS_DISABLED: default: break; } wi->line[wi->line_cnt++] = c; // // check for prompt // if (c == ' ' && wi->line_cnt>2 && wi->line[wi->line_cnt-2] == '>') { int i; for (i=0; ; i++) { if (i==wi->line_cnt-2) { // // got a prompt // if (memcmp(wi->lastprompt, wi->line, wi->line_cnt)) { memcpy(wi->lastprompt, wi->line, wi->line_cnt); wi->lastprompt[wi->line_cnt] = 0; if (!wi->outBuf) { AcLogPrintf(0,4,"1:Wand: '%s'\n",wi->lastprompt); } } wi->line_cnt = 0; if (wi->debugLevel >= 9) { AcLogPrintf(0,4,"9:--Got prompt: '%s'\n",wi->lastprompt); } wi->state = WS_PROMPT; if (wi->debugLevel >= 9) { AcLogPrintf(0,4,"9:--state=WS_PROMPT=%d\n",wi->state); } return; } if (!isalpha(wi->line[i])) { if (i< 2 && isxdigit(wi->line[i])) continue; if (i==2 && isspace(wi->line[i])) continue; break; } } } // // check for end of line // if (c!=0xa && c!=0xd && wi->line_cnt<sizeof(wi->line)-20) { if (wi->state == WS_PROMPT) { wi->state = WS_PROMPT_PLUS; if (wi->debugLevel >= 9) { AcLogPrintf(0,4,"9:--state=WS_PROMPT_PLUS=%d\n",wi->state); } } return; } if (msg[0]==0 && wi->cksum_start_cnt >= 0 && wi->cksum_start_cnt < wi->line_cnt) { wi->line_cnt = wi->cksum_start_cnt+1; } wi->line[--wi->line_cnt] = 0; // // ignore blank lines // if (wi->line_cnt == 0) { return; } // // check for recover timeout // if (wi->recoverPtr) { AcTime t, d; AcTimeGet(&t); AcTimeDiff(&d,&t,&wi->recoverTime); if (d.sec >= 2) { AcLogPrintf(0,4,"6:<<<recoverPtr '%s' timed out>>>\n", wi->recoverStr); wi->recoverPtr = 0; } } if (wi->outBuf) { if (msg[0]) { AcLogPrintf(0,4,"4:Error: %s\n",msg); AcLogPrintf(0,4,"4:Error: wand reply buffer overflow\n"); AcLogPrintf(0,4,"4:Wand: '%s'%s\n",wi->line,msg); #if 0 if (wi->wandOutFunc) { wi->wandOutFunc(wi->wandOutFuncData, wi->line); } #endif } else if (wi->line_cnt < wi->outBufLen) { memcpy(wi->outBuf, wi->line, wi->line_cnt); wi->outBufLen -= wi->line_cnt; wi->outBuf += wi->line_cnt; if (wi->outBufLen) { wi->outBuf[0] = '\n'; wi->outBuf++; wi->outBufLen--; } } else { AcLogPrintf(0,4,"4:Error: wand reply buffer overflow\n"); wi->outBufLen = 0; AcLogPrintf(0,4,"4:Wand: '%s'%s\n",wi->line,msg); #if 0 if (wi->wandOutFunc) { wi->wandOutFunc(wi->wandOutFuncData, wi->line); } #endif } } else if (wi->recoverPtr || wi->quiet) { AcLogPrintf(0,4,"5:Wand: '%s'%s\n",wi->line,msg); } else { AcLogPrintf(0,4,"3:Wand: '%s'%s\n",wi->line,msg); #if 0 if (wi->wandOutFunc) { wi->wandOutFunc(wi->wandOutFuncData, wi->line); } #endif if (wi->line[0] && wi->wandOutFunc) { outStr = strdup(wi->line); } } wi->line_cnt = 0; if (outStr) { if (wi->wandOutFunc) { wi->wandOutFunc(wi->wandOutFuncData, outStr); } free(outStr); } return; } //=========================================================================== // WandRecoverString() - set a recover string - send string to look for //=========================================================================== // // set a string to look for. // void WandRecoverString(WandInfo *wi) { static int c = 'A'; char buf[6]; if (c=='Z') { c = 'a'; } else if (c=='z') { c = 'A'; } else { c++; } wi->recoverStr[0] = c; wi->recoverStr[1] = c; wi->recoverStr[2] = c; wi->recoverStr[3] = 0; wi->recoverPtr = wi->recoverStr; if (wi->debugLevel >= 9) { AcLogPrintf(0,4,"9:--recoverStr='%s'\n", wi->recoverPtr); } buf[0] = c; buf[1] = c; buf[2] = c; buf[3] = c; buf[4] = CTRL('X'); buf[5] = 0; WandWrite(wi, buf, 5); } //=========================================================================== // WandRecover() - recover to known state //=========================================================================== void WandRecover(WandInfo *wi) { AcLogPrintf(0,4,"6:<<<WandRecover() called>>>\n"); if (wi->debugLevel >= 9) { AcLogPrintf(0,4,"9:--WandRecover called state=%d\n",wi->state); } wi->outBuf = 0; wi->outBufLen = 0; wi->state = WS_DISCONNECT; WandSleep(wi,10000); WandRecoverString(wi); WandSleep(wi,10000); wi->cksum_state = WCKS_GARBAGE; wi->cksum = 0; } //=========================================================================== // WandRecoverWait() - recover to known state //=========================================================================== // // Return // 0 success // 2 keypressed // -2 timeout // int WandRecoverWait(WandInfo *wi) { WandRecover(wi); return WandPromptWaitUsec(wi,1000000); } //=========================================================================== // WandHandleReturn0() - return 0 //=========================================================================== int WandHandleReturn0(int fd, void *data) { return 0; } //=========================================================================== // WandHandleReturn2() - return 2 //=========================================================================== int WandHandleReturn2(int fd, void *data) { return 2; } //=========================================================================== // WandFlush() - get rid of all pending chars //=========================================================================== static void WandFlush(WandInfo *wi) { char buf[1000]; int cnt; while(1) { int rv = AcFdGroupWaitTimeout(wi->grpNull,100000); if (rv) { return; // timeout -- nothing to read } cnt = read(wi->fd, buf, sizeof(buf)-100); AcLogWrite(0,2,buf,cnt); AcLogFlush(0); } } //=========================================================================== // WandHandleSerial() //=========================================================================== int WandHandleSerial(int fd, void *data) { WandInfo *wi = data; char buf[1000]; int cnt; // // make sure we really do have something to read // { int rv = AcFdGroupWaitTimeout(wi->grpNull,0); if (rv) { AcLogPrintf(0,4, "0:<<<WandHandleSerial called with nothing to read>>>\n"); return 0; // timeout -- nothing to read } } cnt = read(fd, buf, sizeof(buf)-100); AcLogWrite(0,2,buf,cnt); AcLogFlush(0); if (cnt) { int i; buf[cnt] = 0; if (wi->debugLevel >= 9) { AcLogPrintf(0,4,"9:--From wand: '%s'\n",makePrintable(buf,cnt)); } for (i=0; i<cnt; i++) { wandChar(wi,buf[i]); } } if (wi->wasdisconnect && wi->state == WS_PROMPT) { WandPrompt(wi); } return 0; } //=========================================================================== // WandGetFd() - get file descriptor group for wand //=========================================================================== int WandGetFd(WandInfo *wi) { return wi->fd; } //=========================================================================== // WandDebugLevel() - set debug level //=========================================================================== int WandDebugLevel(WandInfo *wi, int level) { int old = wi->debugLevel; wi->debugLevel = level; return old; } //=========================================================================== // WandQuiet() - turn quiet on - surpress some errors a normal verbose level //=========================================================================== void WandQuiet(WandInfo *wi) { wi->quiet++; } //=========================================================================== // WandUnQuiet() - turn quiet off //=========================================================================== void WandUnQuiet(WandInfo *wi) { wi->quiet--; if (wi->quiet<0) wi->quiet = 0; } //=========================================================================== // WandInit() //=========================================================================== WandInfo *WandInit(void) { WandInfo *wi = calloc(1,sizeof(WandInfo)); if (!wi) return 0; wi->debugLevel = 8; wi->state = WS_UNKNOWN; strcpy(wi->lastprompt,"?>"); wi->sio = acSerialCreate("/dev/ttyS0", 9600); //wi->sio = acSerialCreate("/dev/ttyUSB0", 9600); if (!wi->sio) { AcLogPrintf(0,4,"0:Error in acSerialCreate\n"); free(wi); return 0; } acSerialSetNonCanonical(wi->sio, 1, 200); acSerialOpen(wi->sio); wi->fd = acSerialGetFD(wi->sio); if (wi->fd < 0) { AcLogPrintf(0,4,"0:Error in acSerialOpen\n"); free(wi); return 0; } // // grpNull does not call any real handler functions. // Returns // 0 if wand has sent characters // 2 if keyboard has sent characters // -2 if timeout // wi->grpNull = AcFdGroupCreate(); if (!wi->grpNull) { WandShutdown(wi); return 0; } AcFdGroupAdd(wi->grpNull, wi->fd, WandHandleReturn0, wi); AcFdGroupAdd(wi->grpNull, 0, WandHandleReturn2, wi); AcFdGroupSetTimeout(wi->grpNull,0,250000); // 1/4 sec timeout // // grpHandler calls WandHandleSerial when wand has chars // Returns // 0 if wand has sent characters (handler gets called too) // 2 if keyboard has sent characters // -2 if timeout // wi->grpHandler = AcFdGroupCreate(); if (!wi->grpHandler) { WandShutdown(wi); return 0; } AcFdGroupAdd(wi->grpHandler, wi->fd, WandHandleSerial, wi); AcFdGroupAdd(wi->grpHandler, 0, WandHandleReturn2, wi); AcFdGroupSetTimeout(wi->grpHandler,0,250000); // 1/4 sec timeout // // grpSleep waits for some number of usec // Characters from wand are ignored (but not lost) // Returns // 2 if keyboard has sent characters // -2 if timeout // wi->grpSleep = AcFdGroupCreate(); if (!wi->grpSleep) { WandShutdown(wi); return 0; } AcFdGroupAdd(wi->grpSleep, 0, WandHandleReturn2, wi); AcFdGroupSetTimeout(wi->grpSleep,0,250000); // 1/4 sec timeout wi->cksum_state = WCKS_NEWLINE; wi->cksum = 0; WandRecover(wi); WandFlush(wi); WandRecover(wi); return wi; } //=========================================================================== // WandShutdown() //=========================================================================== void WandShutdown(WandInfo *wi) { WandRecover(wi); if (wi->grpSleep) { AcFdGroupDestroy(wi->grpSleep); } if (wi->grpHandler) { AcFdGroupDestroy(wi->grpHandler); } if (wi->grpNull) { AcFdGroupDestroy(wi->grpNull); } acSerialDestroy(wi->sio); } |
This file Copyright (C) 2006 by Nathan (Acorn) Pooley
Go to TOP Wand page
Go to Acorn's personal webpage
Go to Hogwarts website: www.gotohogwarts.com
Snout: www.snout.org/game
Gadgets of Justice Unlimited
Snout GC (Wiki)
Snout Wiki
File created by do_doc at Wed May 30 03:29:06 PDT 2007