Auxiliaries I use for CreaBot
CMD_Interpreter.cpp@1:6f5b84940d04, 2019-06-21 (annotated)
- Committer:
- sepp_nepp
- Date:
- Fri Jun 21 15:26:49 2019 +0000
- Revision:
- 1:6f5b84940d04
The Command Interpreter is the only key function that is now included inside the Bot-Auxiliaries ...;
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
sepp_nepp | 1:6f5b84940d04 | 1 | // ***************************************************************** |
sepp_nepp | 1:6f5b84940d04 | 2 | // Handle all the LEDs with some general function wrappers functions |
sepp_nepp | 1:6f5b84940d04 | 3 | // ***************************************************************** |
sepp_nepp | 1:6f5b84940d04 | 4 | #include "CMD_Interpreter.h" |
sepp_nepp | 1:6f5b84940d04 | 5 | |
sepp_nepp | 1:6f5b84940d04 | 6 | //************************************ |
sepp_nepp | 1:6f5b84940d04 | 7 | // Interpreter Class Creation |
sepp_nepp | 1:6f5b84940d04 | 8 | //************************************ |
sepp_nepp | 1:6f5b84940d04 | 9 | // Strategy: the interpreter accumulates characters in its input buffer |
sepp_nepp | 1:6f5b84940d04 | 10 | // it flags the presence of complete lines |
sepp_nepp | 1:6f5b84940d04 | 11 | // it also flags Overflow of the buffer in which case all subsequent characters |
sepp_nepp | 1:6f5b84940d04 | 12 | // are lost until the queue is emptied, and a CR-LF is received |
sepp_nepp | 1:6f5b84940d04 | 13 | // Defined States of the interpreter: |
sepp_nepp | 1:6f5b84940d04 | 14 | // MyState = isStartNew, isLineFilling, isOverflow, isWaitNewLine}; |
sepp_nepp | 1:6f5b84940d04 | 15 | |
sepp_nepp | 1:6f5b84940d04 | 16 | // #define DEBUG(...) { snprintf(buff, sizeof(buff), __VA_ARGS__); DataLog( buff ); } |
sepp_nepp | 1:6f5b84940d04 | 17 | |
sepp_nepp | 1:6f5b84940d04 | 18 | Interpreter::Interpreter( void ) |
sepp_nepp | 1:6f5b84940d04 | 19 | { Reinit( ); |
sepp_nepp | 1:6f5b84940d04 | 20 | MyState = isStartNew; |
sepp_nepp | 1:6f5b84940d04 | 21 | AllCommands = NULL; |
sepp_nepp | 1:6f5b84940d04 | 22 | NumCommands = 0; |
sepp_nepp | 1:6f5b84940d04 | 23 | } |
sepp_nepp | 1:6f5b84940d04 | 24 | |
sepp_nepp | 1:6f5b84940d04 | 25 | void Interpreter::FillCommands( int aNumCommands, const EXE_CMD_TYPE *ACommands ) |
sepp_nepp | 1:6f5b84940d04 | 26 | { int cnt; |
sepp_nepp | 1:6f5b84940d04 | 27 | AllCommands = new EXE_CMD_TYPE[ aNumCommands ]; |
sepp_nepp | 1:6f5b84940d04 | 28 | for( cnt=0; cnt<aNumCommands; cnt++) |
sepp_nepp | 1:6f5b84940d04 | 29 | { AllCommands[cnt] = ACommands[cnt]; } ; |
sepp_nepp | 1:6f5b84940d04 | 30 | NumCommands = aNumCommands; |
sepp_nepp | 1:6f5b84940d04 | 31 | } |
sepp_nepp | 1:6f5b84940d04 | 32 | |
sepp_nepp | 1:6f5b84940d04 | 33 | void Interpreter::Reinit( void ) { |
sepp_nepp | 1:6f5b84940d04 | 34 | MyState = isWaitNewLine; // indicates no buffer overflow |
sepp_nepp | 1:6f5b84940d04 | 35 | WriteIndex = 0; // points to next index to write to |
sepp_nepp | 1:6f5b84940d04 | 36 | LinesComplete = 0; // indicates that no complete line is currently available |
sepp_nepp | 1:6f5b84940d04 | 37 | // Start Scanning at the start |
sepp_nepp | 1:6f5b84940d04 | 38 | ScanIndex = 0; |
sepp_nepp | 1:6f5b84940d04 | 39 | BufAvail = BuffLen;// the full buffer size is available |
sepp_nepp | 1:6f5b84940d04 | 40 | } |
sepp_nepp | 1:6f5b84940d04 | 41 | |
sepp_nepp | 1:6f5b84940d04 | 42 | // Barebone function, assumes that checks havee been performed by writeBuf! |
sepp_nepp | 1:6f5b84940d04 | 43 | void Interpreter::AddChar( char aChar ) { |
sepp_nepp | 1:6f5b84940d04 | 44 | if (aChar == 8) // is it a backspace code, then remove one character: |
sepp_nepp | 1:6f5b84940d04 | 45 | { if (BufAvail<BuffLen) { // there's actually a character to be removed |
sepp_nepp | 1:6f5b84940d04 | 46 | BufAvail++; // Buffer regrows |
sepp_nepp | 1:6f5b84940d04 | 47 | if (WriteIndex == 0) {WriteIndex=BuffLen-1;} |
sepp_nepp | 1:6f5b84940d04 | 48 | else {WriteIndex--;} // recoil the write index |
sepp_nepp | 1:6f5b84940d04 | 49 | } |
sepp_nepp | 1:6f5b84940d04 | 50 | } |
sepp_nepp | 1:6f5b84940d04 | 51 | else { |
sepp_nepp | 1:6f5b84940d04 | 52 | if (WriteIndex == BuffLen-1) {WriteIndex=0;} |
sepp_nepp | 1:6f5b84940d04 | 53 | else {WriteIndex++;} |
sepp_nepp | 1:6f5b84940d04 | 54 | RingBuf[WriteIndex]=aChar; // all right, buffer it! |
sepp_nepp | 1:6f5b84940d04 | 55 | BufAvail--; // Buffer is shrinking |
sepp_nepp | 1:6f5b84940d04 | 56 | if (BufAvail==0) { MyState = isOverflow; } |
sepp_nepp | 1:6f5b84940d04 | 57 | } |
sepp_nepp | 1:6f5b84940d04 | 58 | } |
sepp_nepp | 1:6f5b84940d04 | 59 | |
sepp_nepp | 1:6f5b84940d04 | 60 | // High level method to add a Char to the buffer, |
sepp_nepp | 1:6f5b84940d04 | 61 | // Separates at Chars 10, 13, 0; replaced by a single 0 char |
sepp_nepp | 1:6f5b84940d04 | 62 | // Blocking write when buffer has overflowed |
sepp_nepp | 1:6f5b84940d04 | 63 | void Interpreter::writeBuf(char aChar) { |
sepp_nepp | 1:6f5b84940d04 | 64 | bool LineEnds = aChar==10 || aChar==13 || aChar==0; |
sepp_nepp | 1:6f5b84940d04 | 65 | switch (MyState) { |
sepp_nepp | 1:6f5b84940d04 | 66 | case isOverflow: break; |
sepp_nepp | 1:6f5b84940d04 | 67 | case isStartNew: // ready for the next line to start |
sepp_nepp | 1:6f5b84940d04 | 68 | // avoid that consecutive CR LF are counted as multiple lines |
sepp_nepp | 1:6f5b84940d04 | 69 | if (!LineEnds) {AddChar(aChar ); MyState = isLineFilling; } |
sepp_nepp | 1:6f5b84940d04 | 70 | break; |
sepp_nepp | 1:6f5b84940d04 | 71 | case isLineFilling:// New line has started filling |
sepp_nepp | 1:6f5b84940d04 | 72 | if (!LineEnds) {AddChar(aChar);} |
sepp_nepp | 1:6f5b84940d04 | 73 | else |
sepp_nepp | 1:6f5b84940d04 | 74 | {MyState = isStartNew; // ready for the next line |
sepp_nepp | 1:6f5b84940d04 | 75 | // Between consecutive commands, the endstring=NULL character is inserted |
sepp_nepp | 1:6f5b84940d04 | 76 | // this is to indicate that line was already counted as completed |
sepp_nepp | 1:6f5b84940d04 | 77 | AddChar(0 ); // append a line end char, will detect bufferFull! |
sepp_nepp | 1:6f5b84940d04 | 78 | LinesComplete++; } // count completed lines |
sepp_nepp | 1:6f5b84940d04 | 79 | break; |
sepp_nepp | 1:6f5b84940d04 | 80 | case isWaitNewLine: // waiting for a new line end to arrive after an overflow |
sepp_nepp | 1:6f5b84940d04 | 81 | if (LineEnds) { MyState = isStartNew; } |
sepp_nepp | 1:6f5b84940d04 | 82 | break; |
sepp_nepp | 1:6f5b84940d04 | 83 | default: MyState = isOverflow; // goes into error state, should never happen though |
sepp_nepp | 1:6f5b84940d04 | 84 | } |
sepp_nepp | 1:6f5b84940d04 | 85 | } // writeBuf |
sepp_nepp | 1:6f5b84940d04 | 86 | |
sepp_nepp | 1:6f5b84940d04 | 87 | // Barebone function, that performs the checks to be performed! |
sepp_nepp | 1:6f5b84940d04 | 88 | // Passes back the actC, and reads already the nextChar into actC |
sepp_nepp | 1:6f5b84940d04 | 89 | char Interpreter::GetAChar( void ) { |
sepp_nepp | 1:6f5b84940d04 | 90 | char oldC = actC; |
sepp_nepp | 1:6f5b84940d04 | 91 | if (BufAvail==BuffLen) { actC = 0; LinesComplete=0; } // buffer is empty, no more lines!! |
sepp_nepp | 1:6f5b84940d04 | 92 | else // something is in the buffer |
sepp_nepp | 1:6f5b84940d04 | 93 | { if (ScanIndex == BuffLen) {ScanIndex=0;} |
sepp_nepp | 1:6f5b84940d04 | 94 | else {ScanIndex++;} |
sepp_nepp | 1:6f5b84940d04 | 95 | actC=RingBuf[ScanIndex]; // all right, get it |
sepp_nepp | 1:6f5b84940d04 | 96 | if (actC==0) {LinesComplete--; } // now there is one line less in the storage |
sepp_nepp | 1:6f5b84940d04 | 97 | BufAvail++; // Buffer is increasing |
sepp_nepp | 1:6f5b84940d04 | 98 | } // something is in the buffer |
sepp_nepp | 1:6f5b84940d04 | 99 | return oldC; |
sepp_nepp | 1:6f5b84940d04 | 100 | } |
sepp_nepp | 1:6f5b84940d04 | 101 | |
sepp_nepp | 1:6f5b84940d04 | 102 | // skip true blank, but also Tab characters |
sepp_nepp | 1:6f5b84940d04 | 103 | void Interpreter::SkipBlanks( void ) { |
sepp_nepp | 1:6f5b84940d04 | 104 | while(BufAvail<BuffLen && (actC==' ' || actC==9|| actC==0)) { GetAChar(); } |
sepp_nepp | 1:6f5b84940d04 | 105 | } // SkipBlanks |
sepp_nepp | 1:6f5b84940d04 | 106 | |
sepp_nepp | 1:6f5b84940d04 | 107 | int Interpreter::ReadAnInt( void ) { |
sepp_nepp | 1:6f5b84940d04 | 108 | bool Negative = false; |
sepp_nepp | 1:6f5b84940d04 | 109 | int Result = 0; |
sepp_nepp | 1:6f5b84940d04 | 110 | if (actC=='-') {Negative = true; GetAChar(); } |
sepp_nepp | 1:6f5b84940d04 | 111 | else if (actC=='+') {Negative = false; GetAChar(); } |
sepp_nepp | 1:6f5b84940d04 | 112 | while(BufAvail<BuffLen && actC>='0' && actC<='9') |
sepp_nepp | 1:6f5b84940d04 | 113 | { Result = Result * 10 + (GetAChar()-'0') ; } |
sepp_nepp | 1:6f5b84940d04 | 114 | return Negative? -Result : Result; |
sepp_nepp | 1:6f5b84940d04 | 115 | } // ReadAnInt |
sepp_nepp | 1:6f5b84940d04 | 116 | |
sepp_nepp | 1:6f5b84940d04 | 117 | |
sepp_nepp | 1:6f5b84940d04 | 118 | RD_CMD_TYPE Interpreter::ParseCommand( void ) { |
sepp_nepp | 1:6f5b84940d04 | 119 | RD_CMD_TYPE cmd; // locally built command |
sepp_nepp | 1:6f5b84940d04 | 120 | actC=RingBuf[ScanIndex]; // initialiye the actC variable, as the first char to use |
sepp_nepp | 1:6f5b84940d04 | 121 | SkipBlanks(); |
sepp_nepp | 1:6f5b84940d04 | 122 | // Next Character is the command |
sepp_nepp | 1:6f5b84940d04 | 123 | cmd.Command = GetAChar(); |
sepp_nepp | 1:6f5b84940d04 | 124 | // Next Blanks are to be omitted, but are not even mandatory |
sepp_nepp | 1:6f5b84940d04 | 125 | SkipBlanks(); |
sepp_nepp | 1:6f5b84940d04 | 126 | if ((actC>='0' && actC<='9') || actC=='-' || actC=='+' ) |
sepp_nepp | 1:6f5b84940d04 | 127 | { cmd.Parameter= ReadAnInt(); cmd.NumParam = 1; } |
sepp_nepp | 1:6f5b84940d04 | 128 | else { cmd.Parameter= 0; cmd.NumParam = 0; } |
sepp_nepp | 1:6f5b84940d04 | 129 | SkipBlanks( ); // There should be at least a trailing NUL character to be removed |
sepp_nepp | 1:6f5b84940d04 | 130 | return cmd; // return the built command |
sepp_nepp | 1:6f5b84940d04 | 131 | } |
sepp_nepp | 1:6f5b84940d04 | 132 | |
sepp_nepp | 1:6f5b84940d04 | 133 | bool Interpreter::executeCommand(RD_CMD_TYPE cmd) { |
sepp_nepp | 1:6f5b84940d04 | 134 | int CmdNr; |
sepp_nepp | 1:6f5b84940d04 | 135 | bool Found; |
sepp_nepp | 1:6f5b84940d04 | 136 | CmdNr = 0; |
sepp_nepp | 1:6f5b84940d04 | 137 | Found = false; |
sepp_nepp | 1:6f5b84940d04 | 138 | // DEBUG("Com '%c'=%d %d NPar=%d \n\r",cmd.Command, cmd.Command, cmd.Parameter, cmd.NumParam); |
sepp_nepp | 1:6f5b84940d04 | 139 | // While not found go through all the commands, linear; they are not sorted by alphabet. |
sepp_nepp | 1:6f5b84940d04 | 140 | while(CmdNr<NumCommands && !Found) |
sepp_nepp | 1:6f5b84940d04 | 141 | { // DEBUG("NR:%d \n\r", CmdNr); |
sepp_nepp | 1:6f5b84940d04 | 142 | if (AllCommands[CmdNr].cmd == cmd.Command) |
sepp_nepp | 1:6f5b84940d04 | 143 | { // the command character matches |
sepp_nepp | 1:6f5b84940d04 | 144 | if (cmd.NumParam == AllCommands[CmdNr].Npar) |
sepp_nepp | 1:6f5b84940d04 | 145 | { // DEBUG("Execute: %s \n\r", AllCommands[CmdNr].help); |
sepp_nepp | 1:6f5b84940d04 | 146 | AllCommands[CmdNr].Handler( cmd.Parameter ); // then call the handler |
sepp_nepp | 1:6f5b84940d04 | 147 | } |
sepp_nepp | 1:6f5b84940d04 | 148 | // else { DataLog("Param Mismatch!\n\r"); } // Inform about Parameter error |
sepp_nepp | 1:6f5b84940d04 | 149 | Found = true; // and mark as found |
sepp_nepp | 1:6f5b84940d04 | 150 | } |
sepp_nepp | 1:6f5b84940d04 | 151 | else { CmdNr++; } // go on serarching |
sepp_nepp | 1:6f5b84940d04 | 152 | } // while |
sepp_nepp | 1:6f5b84940d04 | 153 | // if ( !Found ) { CmdInval(cmd.Command) ; } // call invalid command function |
sepp_nepp | 1:6f5b84940d04 | 154 | return Found; |
sepp_nepp | 1:6f5b84940d04 | 155 | } |
sepp_nepp | 1:6f5b84940d04 | 156 | |
sepp_nepp | 1:6f5b84940d04 | 157 | bool Interpreter::ProcessPresentCommands( void ) |
sepp_nepp | 1:6f5b84940d04 | 158 | { RD_CMD_TYPE Readcmd; |
sepp_nepp | 1:6f5b84940d04 | 159 | if (MyState==isOverflow) { Reinit(); } |
sepp_nepp | 1:6f5b84940d04 | 160 | if(LinesComplete>0) |
sepp_nepp | 1:6f5b84940d04 | 161 | { // DEBUG("X: Scan=%d ", Interp.ScanIndex); |
sepp_nepp | 1:6f5b84940d04 | 162 | Readcmd = ParseCommand(); |
sepp_nepp | 1:6f5b84940d04 | 163 | executeCommand( Readcmd ); |
sepp_nepp | 1:6f5b84940d04 | 164 | //DEBUG("state=%d; wix=%d; rix=%d; buf=%s ", Interp.MyState, Interp.WriteIndex, Interp.ScanIndex, &Interp.RingBuf[Interp.ScanIndex]); |
sepp_nepp | 1:6f5b84940d04 | 165 | return true; |
sepp_nepp | 1:6f5b84940d04 | 166 | } |
sepp_nepp | 1:6f5b84940d04 | 167 | else { return false; } |
sepp_nepp | 1:6f5b84940d04 | 168 | } |
sepp_nepp | 1:6f5b84940d04 | 169 | |
sepp_nepp | 1:6f5b84940d04 | 170 | char *ParamHelp[] = {" ", "<param>", "<par><par>"}; |
sepp_nepp | 1:6f5b84940d04 | 171 | |
sepp_nepp | 1:6f5b84940d04 | 172 | void Interpreter::PrtCmdHelp (Serial *aSerial ) // Display list of Commands |
sepp_nepp | 1:6f5b84940d04 | 173 | { EXE_CMD_TYPE *com; |
sepp_nepp | 1:6f5b84940d04 | 174 | int CmdNr; |
sepp_nepp | 1:6f5b84940d04 | 175 | char *parStr; |
sepp_nepp | 1:6f5b84940d04 | 176 | // DataLog("List of commands: \n\r"); |
sepp_nepp | 1:6f5b84940d04 | 177 | // Go Through all commands in the table |
sepp_nepp | 1:6f5b84940d04 | 178 | for (CmdNr = 0; CmdNr<NumCommands; CmdNr++ ) |
sepp_nepp | 1:6f5b84940d04 | 179 | { com = &AllCommands[CmdNr]; // get a pointer to the command |
sepp_nepp | 1:6f5b84940d04 | 180 | parStr = ParamHelp[com->Npar]; // Get the string that represents the number of parameters |
sepp_nepp | 1:6f5b84940d04 | 181 | aSerial->printf( " %c %s => %s \n\r", com->cmd, parStr, com->help.c_str() ); // output the full command help |
sepp_nepp | 1:6f5b84940d04 | 182 | } |
sepp_nepp | 1:6f5b84940d04 | 183 | } |
sepp_nepp | 1:6f5b84940d04 | 184 | |
sepp_nepp | 1:6f5b84940d04 | 185 | /* |
sepp_nepp | 1:6f5b84940d04 | 186 | void Interpreter::CmdInval( int param ) // Feedback that the command is invalid |
sepp_nepp | 1:6f5b84940d04 | 187 | { DEBUG( " Invalid command %d = '%c'; use: 'h' for help. \n\r", param, char(param) ) ; |
sepp_nepp | 1:6f5b84940d04 | 188 | } |
sepp_nepp | 1:6f5b84940d04 | 189 | |
sepp_nepp | 1:6f5b84940d04 | 190 | string Interpreter::GetLastMessage( void ) |
sepp_nepp | 1:6f5b84940d04 | 191 | { string LastMsg = LastMessage; |
sepp_nepp | 1:6f5b84940d04 | 192 | LastMessage = ""; // Empty the old Message |
sepp_nepp | 1:6f5b84940d04 | 193 | return LastMsg; |
sepp_nepp | 1:6f5b84940d04 | 194 | } |
sepp_nepp | 1:6f5b84940d04 | 195 | |
sepp_nepp | 1:6f5b84940d04 | 196 | void Interpreter::DataLog( char *DebugMessage ) |
sepp_nepp | 1:6f5b84940d04 | 197 | { if (LastMessage=="" ) { LastMessage = DebugMessage; } |
sepp_nepp | 1:6f5b84940d04 | 198 | else { LastMessage = LastMessage + "\n\r" + DebugMessage; } |
sepp_nepp | 1:6f5b84940d04 | 199 | }; |
sepp_nepp | 1:6f5b84940d04 | 200 | */ |