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