Auxiliaries I use for CreaBot

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?

UserRevisionLine numberNew 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 */