Tarek Lule / CMD_Interpreter
Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers CMD_Interpreter.cpp Source File

CMD_Interpreter.cpp

00001 // *****************************************************************
00002 // Handle all the LEDs with some general function wrappers functions
00003 // *****************************************************************
00004 #include "CMD_Interpreter.h"
00005 
00006 //************************************
00007 // Interpreter Class Creation 
00008 //************************************
00009 // Strategy: the interpreter accumulates characters in its input buffer
00010 // it flags the presence of complete lines
00011 // it also flags Overflow of the buffer in which case all subsequent characters 
00012 //       are lost until the queue is emptied, and a CR-LF is received
00013 // Defined States of the interpreter: 
00014 //     MyState = isStartNew, isLineFilling, isOverflow, isWaitNewLine};
00015 
00016 // #define DEBUG(...) { snprintf(buff, sizeof(buff), __VA_ARGS__);   DataLog( buff );  }
00017 
00018 Interpreter::Interpreter( void ) 
00019 { Reinit( );
00020   MyState = isStartNew;
00021   AllCommands = NULL;
00022   NumCommands = 0;
00023   InvalidCommand = false;
00024 }
00025 
00026 void Interpreter::FillCommands( int aNumCommands, const  EXE_CMD_TYPE *ACommands  )
00027 {   int cnt;
00028     AllCommands = new EXE_CMD_TYPE[ aNumCommands ];
00029     for( cnt=0; cnt<aNumCommands; cnt++)
00030       { AllCommands[cnt] = ACommands[cnt]; } ;
00031     NumCommands = aNumCommands;
00032 }
00033 
00034 void Interpreter::Reinit( void ) {
00035     MyState = isWaitNewLine; // indicates no buffer overflow
00036     WriteIndex = 0;  // points to next index to write to
00037     LinesComplete = 0; // indicates that no complete line is currently available 
00038     // Start Scanning at the start
00039     ScanIndex = 0;
00040     BufAvail = BuffLen;// the full buffer size is available 
00041  }
00042 
00043 // Barebone function, assumes that checks havee been performed by writeBuf!
00044 void Interpreter::AddChar( char aChar ) {
00045     if (aChar == 8) // is it a backspace code, then remove one character:
00046       { if (BufAvail<BuffLen) { // there's actually a character to be removed
00047             BufAvail++; // Buffer regrows
00048             if (WriteIndex == 0) {WriteIndex=BuffLen-1;}
00049                else {WriteIndex--;} // recoil the write index
00050           }
00051       }
00052     else {
00053         if (WriteIndex == BuffLen-1) {WriteIndex=0;}
00054            else {WriteIndex++;}
00055         RingBuf[WriteIndex]=aChar; // all right, buffer it!
00056         BufAvail--; // Buffer is shrinking
00057         if (BufAvail==0) { MyState = isOverflow; }
00058      }
00059 }                 
00060 
00061 // High level method to add a Char to the buffer,
00062 // Separates at Chars 10, 13, 0; replaced by a single 0 char
00063 // Blocking write when buffer has overflowed
00064 void Interpreter::writeBuf(char aChar) {
00065   bool LineEnds = aChar==10 || aChar==13 || aChar==0;
00066   switch (MyState) {
00067     case isOverflow: break;
00068     case isStartNew:  // ready for the next line to start
00069         // avoid that consecutive CR LF are counted as multiple lines 
00070         if (!LineEnds) {AddChar(aChar ); MyState = isLineFilling; } 
00071         break;
00072     case isLineFilling:// New line has started filling
00073         if (!LineEnds)  {AddChar(aChar);} 
00074           else 
00075             {MyState = isStartNew; // ready for the next line
00076              // Between consecutive commands, the endstring=NULL character is inserted
00077              // this is to indicate that line was already counted as completed
00078              AddChar(0 ); // append a line end char, will detect bufferFull!
00079              LinesComplete++; } // count completed lines        
00080         break;
00081     case isWaitNewLine: // waiting for a new line end to arrive after an overflow
00082         if (LineEnds) { MyState = isStartNew; }
00083         break;
00084     default: MyState = isOverflow; // goes into error state, should never happen though
00085     }   
00086 } // writeBuf
00087 
00088 // Barebone function, that performs the checks to be performed!
00089 // Passes back the actC, and reads already the nextChar into actC
00090 char Interpreter::GetAChar( void ) {
00091 char oldC = actC;
00092     if (BufAvail==BuffLen) { actC = 0; LinesComplete=0; } // buffer is empty, no more lines!!
00093     else // something is in the buffer 
00094       { if (ScanIndex == BuffLen) {ScanIndex=0;}
00095            else {ScanIndex++;}
00096         actC=RingBuf[ScanIndex]; // all right, get it
00097         if (actC==0) {LinesComplete--; } // now there is one line less in the storage
00098         BufAvail++; // Buffer is increasing
00099       } // something is in the buffer 
00100     return oldC;
00101 }                 
00102 
00103 // skip true blank, but also Tab characters
00104 void Interpreter::SkipBlanks( void ) {
00105     while(BufAvail<BuffLen && (actC==' ' || actC==9|| actC==0)) { GetAChar(); }
00106 } // SkipBlanks
00107 
00108 int Interpreter::ReadAnInt( void ) {
00109 bool Negative = false;
00110 int  Result = 0;
00111     if (actC=='-') {Negative = true; GetAChar(); }
00112     else if (actC=='+') {Negative = false; GetAChar(); }
00113     while(BufAvail<BuffLen  && actC>='0' && actC<='9') 
00114         { Result = Result * 10 + (GetAChar()-'0') ; }
00115     return Negative? -Result : Result;
00116 } // ReadAnInt
00117 
00118 
00119 RD_CMD_TYPE Interpreter::ParseCommand( void ) {
00120   RD_CMD_TYPE cmd; // locally built command
00121     actC=RingBuf[ScanIndex]; // initialiye the actC variable, as the first char to use
00122     SkipBlanks();
00123     // Next Character is the command
00124     cmd.Command = GetAChar();
00125     // Next Blanks are to be omitted, but are not even mandatory
00126     SkipBlanks();
00127     if ((actC>='0' && actC<='9') || actC=='-' || actC=='+' )
00128            { cmd.Parameter= ReadAnInt(); cmd.NumParam = 1; }
00129       else { cmd.Parameter= 0;           cmd.NumParam = 0; }
00130     SkipBlanks( ); // There should be at least a trailing NUL character to be removed
00131     return cmd; // return the built command
00132 }
00133 
00134 bool Interpreter::executeCommand(RD_CMD_TYPE cmd) {
00135     int CmdNr;
00136     bool Found;
00137     CmdNr = 0;
00138     Found = false; 
00139     // DEBUG("Com '%c'=%d %d NPar=%d \n\r",cmd.Command, cmd.Command, cmd.Parameter, cmd.NumParam);
00140     // While not found go through all the commands, linear; they are not sorted by alphabet.
00141     while(CmdNr<NumCommands && !Found) 
00142       { // DEBUG("NR:%d \n\r", CmdNr);
00143         if (AllCommands[CmdNr].cmd == cmd.Command) 
00144             { // the command character matches
00145               if (cmd.NumParam == AllCommands[CmdNr].Npar) 
00146                   { // DEBUG("Execute: %s \n\r", AllCommands[CmdNr].help);
00147                     AllCommands[CmdNr].Handler( cmd.Parameter ); // then call the handler 
00148                   }
00149                //  else { DataLog("Param Mismatch!\n\r");  } // Inform about Parameter error
00150             Found = true; // and mark as found 
00151             }
00152         else { CmdNr++; } // go on serarching
00153       } // while   
00154     if ( !Found )  { // CmdInval(cmd.Command) ;   // call invalid command function
00155         InvalidCommand = true; 
00156         }
00157     return Found;
00158 }
00159 
00160 bool Interpreter::ProcessPresentCommands( void )
00161 {   RD_CMD_TYPE Readcmd;
00162     if (MyState==isOverflow)   { Reinit(); } 
00163     if(LinesComplete>0) 
00164        { // DEBUG("X: Scan=%d ", Interp.ScanIndex); 
00165          Readcmd = ParseCommand();
00166          executeCommand( Readcmd ); 
00167          //DEBUG("state=%d; wix=%d; rix=%d; buf=%s ", Interp.MyState, Interp.WriteIndex, Interp.ScanIndex, &Interp.RingBuf[Interp.ScanIndex]); 
00168          return true;
00169         } 
00170       else { return false; }
00171 }
00172 
00173 char *ParamHelp[] = {"     ", "<param>", "<par><par>"};
00174 
00175 void Interpreter::PrtCmdHelp  (Serial *aSerial ) // Display list of Commands
00176 {   EXE_CMD_TYPE *com;
00177     int CmdNr;
00178     char *parStr;
00179     // DataLog("List of commands: \n\r"); 
00180     // Go Through all commands in the table
00181     for (CmdNr = 0; CmdNr<NumCommands; CmdNr++ )
00182       { com = &AllCommands[CmdNr]; // get a pointer to the command
00183         parStr = ParamHelp[com->Npar]; // Get the string that represents the number of parameters
00184         aSerial->printf( " %c %s => %s \n\r", com->cmd, parStr, com->help.c_str() );  // output the full command help
00185       }   
00186 }
00187 
00188 /*
00189 void Interpreter::CmdInval( int param ) // Feedback that the command is invalid
00190 { DEBUG( " Invalid command %d = '%c'; use: 'h' for help. \n\r",  param, char(param) ) ; 
00191 }
00192 
00193 string Interpreter::GetLastMessage( void )
00194 { string LastMsg = LastMessage;
00195   LastMessage = ""; // Empty the old Message
00196   return LastMsg;
00197 }
00198 
00199 void Interpreter::DataLog( char *DebugMessage )
00200 { if (LastMessage=="" ) { LastMessage = DebugMessage; }
00201     else { LastMessage = LastMessage + "\n\r" + DebugMessage; }
00202 };
00203 */