Main Page | Modules | Data Structures | Directories | File List | Data Fields | Globals | Related Pages

cmdline.c

Go to the documentation of this file.
00001 /*! \file cmdline.c \brief Command-Line Interface Library. */
00002 //*****************************************************************************
00003 //
00004 // File Name    : 'cmdline.c'
00005 // Title        : Command-Line Interface Library
00006 // Author       : Pascal Stang - Copyright (C) 2003
00007 // Created      : 2003.07.16
00008 // Revised      : 2003.07.23
00009 // Version      : 0.1
00010 // Target MCU   : Atmel AVR Series
00011 // Editor Tabs  : 4
00012 //
00013 // NOTE: This code is currently below version 1.0, and therefore is considered
00014 // to be lacking in some functionality or documentation, or may not be fully
00015 // tested.  Nonetheless, you can expect most functions to work.
00016 //
00017 // This code is distributed under the GNU Public License
00018 //      which can be found at http://www.gnu.org/licenses/gpl.txt
00019 //
00020 //*****************************************************************************
00021 
00022 //----- Include Files ---------------------------------------------------------
00023 #include <avr/io.h>         // include I/O definitions (port names, pin names, etc)
00024 #include <avr/interrupt.h>  // include interrupt support
00025 #include <avr/pgmspace.h>   // include AVR program memory support
00026 #include <string.h>         // include standard C string functions
00027 #include <stdlib.h>         // include stdlib for string conversion functions
00028 
00029 #include "global.h"     // include our global settings
00030 #include "cmdline.h"
00031 
00032 // include project-specific configuration
00033 #include "cmdlineconf.h"
00034 
00035 // defines
00036 #define ASCII_BEL               0x07
00037 #define ASCII_BS                0x08
00038 #define ASCII_CR                0x0D
00039 #define ASCII_LF                0x0A
00040 #define ASCII_ESC               0x1B
00041 #define ASCII_DEL               0x7F
00042 
00043 #define VT100_ARROWUP           'A'
00044 #define VT100_ARROWDOWN         'B'
00045 #define VT100_ARROWRIGHT        'C'
00046 #define VT100_ARROWLEFT         'D'
00047 
00048 #define CMDLINE_HISTORY_SAVE    0
00049 #define CMDLINE_HISTORY_PREV    1
00050 #define CMDLINE_HISTORY_NEXT    2
00051 
00052 
00053 // Global variables
00054 
00055 // strings
00056 u08 PROGMEM CmdlinePrompt[] = "cmd>";
00057 u08 PROGMEM CmdlineNotice[] = "cmdline: ";
00058 u08 PROGMEM CmdlineCmdNotFound[] = "command not found";
00059 
00060 // command list
00061 // -commands are null-terminated strings
00062 static char CmdlineCommandList[CMDLINE_MAX_COMMANDS][CMDLINE_MAX_CMD_LENGTH];
00063 // command function pointer list
00064 static CmdlineFuncPtrType CmdlineFunctionList[CMDLINE_MAX_COMMANDS];
00065 // number of commands currently registered
00066 u08 CmdlineNumCommands;
00067 
00068 u08 CmdlineBuffer[CMDLINE_BUFFERSIZE];
00069 u08 CmdlineBufferLength;
00070 u08 CmdlineBufferEditPos;
00071 u08 CmdlineInputVT100State;
00072 u08 CmdlineHistory[CMDLINE_HISTORYSIZE][CMDLINE_BUFFERSIZE];
00073 CmdlineFuncPtrType CmdlineExecFunction;
00074 
00075 // Functions
00076 
00077 // function pointer to single character output routine
00078 static void (*cmdlineOutputFunc)(unsigned char c);
00079 
00080 void cmdlineInit(void)
00081 {
00082     // reset vt100 processing state
00083     CmdlineInputVT100State = 0;
00084     // initialize input buffer
00085     CmdlineBufferLength = 0;
00086     CmdlineBufferEditPos = 0;
00087     // initialize executing function
00088     CmdlineExecFunction = 0;
00089     // initialize command list
00090     CmdlineNumCommands = 0;
00091 }
00092 
00093 void cmdlineAddCommand(u08* newCmdString, CmdlineFuncPtrType newCmdFuncPtr)
00094 {
00095     // add command string to end of command list
00096     strcpy(CmdlineCommandList[CmdlineNumCommands], newCmdString);
00097     // add command function ptr to end of function list
00098     CmdlineFunctionList[CmdlineNumCommands] = newCmdFuncPtr;
00099     // increment number of registered commands
00100     CmdlineNumCommands++;
00101 }
00102 
00103 void cmdlineSetOutputFunc(void (*output_func)(unsigned char c))
00104 {
00105     // set new output function
00106     cmdlineOutputFunc = output_func;
00107     
00108     // should we really do this?
00109     // print a prompt 
00110     //cmdlinePrintPrompt();
00111 }
00112 
00113 void cmdlineInputFunc(unsigned char c)
00114 {
00115     u08 i;
00116     // process the received character
00117 
00118     // VT100 handling
00119     // are we processing a VT100 command?
00120     if(CmdlineInputVT100State == 2)
00121     {
00122         // we have already received ESC and [
00123         // now process the vt100 code
00124         switch(c)
00125         {
00126         case VT100_ARROWUP:
00127             cmdlineDoHistory(CMDLINE_HISTORY_PREV);
00128             break;
00129         case VT100_ARROWDOWN:
00130             cmdlineDoHistory(CMDLINE_HISTORY_NEXT);
00131             break;
00132         case VT100_ARROWRIGHT:
00133             // if the edit position less than current string length
00134             if(CmdlineBufferEditPos < CmdlineBufferLength)
00135             {
00136                 // increment the edit position
00137                 CmdlineBufferEditPos++;
00138                 // move cursor forward one space (no erase)
00139                 cmdlineOutputFunc(ASCII_ESC);
00140                 cmdlineOutputFunc('[');
00141                 cmdlineOutputFunc(VT100_ARROWRIGHT);
00142             }
00143             else
00144             {
00145                 // else, ring the bell
00146                 cmdlineOutputFunc(ASCII_BEL);
00147             }
00148             break;
00149         case VT100_ARROWLEFT:
00150             // if the edit position is non-zero
00151             if(CmdlineBufferEditPos)
00152             {
00153                 // decrement the edit position
00154                 CmdlineBufferEditPos--;
00155                 // move cursor back one space (no erase)
00156                 cmdlineOutputFunc(ASCII_BS);
00157             }
00158             else
00159             {
00160                 // else, ring the bell
00161                 cmdlineOutputFunc(ASCII_BEL);
00162             }
00163             break;
00164         default:
00165             break;
00166         }
00167         // done, reset state
00168         CmdlineInputVT100State = 0;
00169         return;
00170     }
00171     else if(CmdlineInputVT100State == 1)
00172     {
00173         // we last received [ESC]
00174         if(c == '[')
00175         {
00176             CmdlineInputVT100State = 2;
00177             return;
00178         }
00179         else
00180             CmdlineInputVT100State = 0;
00181     }
00182     else
00183     {
00184         // anything else, reset state
00185         CmdlineInputVT100State = 0;
00186     }
00187 
00188     // Regular handling
00189     if( (c >= 0x20) && (c < 0x7F) )
00190     {
00191         // character is printable
00192         // is this a simple append
00193         if(CmdlineBufferEditPos == CmdlineBufferLength)
00194         {
00195             // echo character to the output
00196             cmdlineOutputFunc(c);
00197             // add it to the command line buffer
00198             CmdlineBuffer[CmdlineBufferEditPos++] = c;
00199             // update buffer length
00200             CmdlineBufferLength++;
00201         }
00202         else
00203         {
00204             // edit/cursor position != end of buffer
00205             // we're inserting characters at a mid-line edit position
00206             // make room at the insert point
00207             CmdlineBufferLength++;
00208             for(i=CmdlineBufferLength; i>CmdlineBufferEditPos; i--)
00209                 CmdlineBuffer[i] = CmdlineBuffer[i-1];
00210             // insert character
00211             CmdlineBuffer[CmdlineBufferEditPos++] = c;
00212             // repaint
00213             cmdlineRepaint();
00214             // reposition cursor
00215             for(i=CmdlineBufferEditPos; i<CmdlineBufferLength; i++)
00216                 cmdlineOutputFunc(ASCII_BS);
00217         }
00218     }
00219     // handle special characters
00220     else if(c == ASCII_CR)
00221     {
00222         // user pressed [ENTER]
00223         // echo CR and LF to terminal
00224         cmdlineOutputFunc(ASCII_CR);
00225         cmdlineOutputFunc(ASCII_LF);
00226         // add null termination to command
00227         CmdlineBuffer[CmdlineBufferLength++] = 0;
00228         CmdlineBufferEditPos++;
00229         // command is complete, process it
00230         cmdlineProcessInputString();
00231         // reset buffer
00232         CmdlineBufferLength = 0;
00233         CmdlineBufferEditPos = 0;
00234     }
00235     else if(c == ASCII_BS)
00236     {
00237         if(CmdlineBufferEditPos)
00238         {
00239             // is this a simple delete (off the end of the line)
00240             if(CmdlineBufferEditPos == CmdlineBufferLength)
00241             {
00242                 // destructive backspace
00243                 // echo backspace-space-backspace
00244                 cmdlineOutputFunc(ASCII_BS);
00245                 cmdlineOutputFunc(' ');
00246                 cmdlineOutputFunc(ASCII_BS);
00247                 // decrement our buffer length and edit position
00248                 CmdlineBufferLength--;
00249                 CmdlineBufferEditPos--;
00250             }
00251             else
00252             {
00253                 // edit/cursor position != end of buffer
00254                 // we're deleting characters at a mid-line edit position
00255                 // shift characters down, effectively deleting
00256                 CmdlineBufferLength--;
00257                 CmdlineBufferEditPos--;
00258                 for(i=CmdlineBufferEditPos; i<CmdlineBufferLength; i++)
00259                     CmdlineBuffer[i] = CmdlineBuffer[i+1];
00260                 // repaint
00261                 cmdlineRepaint();
00262                 // add space to clear leftover characters
00263                 cmdlineOutputFunc(' ');
00264                 // reposition cursor
00265                 for(i=CmdlineBufferEditPos; i<(CmdlineBufferLength+1); i++)
00266                     cmdlineOutputFunc(ASCII_BS);
00267             }
00268         }
00269         else
00270         {
00271             // else, ring the bell
00272             cmdlineOutputFunc(ASCII_BEL);
00273         }
00274     }
00275     else if(c == ASCII_DEL)
00276     {
00277         // not yet handled
00278     }
00279     else if(c == ASCII_ESC)
00280     {
00281         CmdlineInputVT100State = 1;
00282     }
00283 }
00284 
00285 void cmdlineRepaint(void)
00286 {
00287     u08* ptr;
00288     u08 i;
00289 
00290     // carriage return
00291     cmdlineOutputFunc(ASCII_CR);
00292     // print fresh prompt
00293     cmdlinePrintPrompt();
00294     // print the new command line buffer
00295     i = CmdlineBufferLength;
00296     ptr = CmdlineBuffer;
00297     while(i--) cmdlineOutputFunc(*ptr++);
00298 }
00299 
00300 void cmdlineDoHistory(u08 action)
00301 {
00302     switch(action)
00303     {
00304     case CMDLINE_HISTORY_SAVE:
00305         // copy CmdlineBuffer to history if not null string
00306         if( strlen(CmdlineBuffer) )
00307             strcpy(CmdlineHistory[0], CmdlineBuffer);
00308         break;
00309     case CMDLINE_HISTORY_PREV:
00310         // copy history to current buffer
00311         strcpy(CmdlineBuffer, CmdlineHistory[0]);
00312         // set the buffer position to the end of the line
00313         CmdlineBufferLength = strlen(CmdlineBuffer);
00314         CmdlineBufferEditPos = CmdlineBufferLength;
00315         // "re-paint" line
00316         cmdlineRepaint();
00317         break;
00318     case CMDLINE_HISTORY_NEXT:
00319         break;
00320     }
00321 }
00322 
00323 void cmdlineProcessInputString(void)
00324 {
00325     u08 cmdIndex;
00326     u08 i=0;
00327 
00328     // save command in history
00329     cmdlineDoHistory(CMDLINE_HISTORY_SAVE);
00330 
00331     // find the end of the command (excluding arguments)
00332     // find first whitespace character in CmdlineBuffer
00333     while( !((CmdlineBuffer[i] == ' ') || (CmdlineBuffer[i] == 0)) ) i++;
00334 
00335     if(!i)
00336     {
00337         // command was null or empty
00338         // output a new prompt
00339         cmdlinePrintPrompt();
00340         // we're done
00341         return;
00342     }
00343 
00344     // search command list for match with entered command
00345     for(cmdIndex=0; cmdIndex<CmdlineNumCommands; cmdIndex++)
00346     {
00347         if( !strncmp(CmdlineCommandList[cmdIndex], CmdlineBuffer, i) )
00348         {
00349             // user-entered command matched a command in the list (database)
00350             // run the corresponding function
00351             CmdlineExecFunction = CmdlineFunctionList[cmdIndex];
00352             // new prompt will be output after user function runs
00353             // and we're done
00354             return;
00355         }
00356     }
00357 
00358     // if we did not get a match
00359     // output an error message
00360     cmdlinePrintError();
00361     // output a new prompt
00362     cmdlinePrintPrompt();
00363 }
00364 
00365 void cmdlineMainLoop(void)
00366 {
00367     // do we have a command/function to be executed
00368     if(CmdlineExecFunction)
00369     {
00370         // run it
00371         CmdlineExecFunction();
00372         // reset
00373         CmdlineExecFunction = 0;
00374         // output new prompt
00375         cmdlinePrintPrompt();
00376     }
00377 }
00378 
00379 void cmdlinePrintPrompt(void)
00380 {
00381     // print a new command prompt
00382     u08* ptr = CmdlinePrompt;
00383     while(pgm_read_byte(ptr)) cmdlineOutputFunc( pgm_read_byte(ptr++) );
00384 }
00385 
00386 void cmdlinePrintError(void)
00387 {
00388     u08 * ptr;
00389 
00390     // print a notice header
00391     // (u08*) cast used to avoid compiler warning
00392     ptr = (u08*)CmdlineNotice;
00393     while(pgm_read_byte(ptr)) cmdlineOutputFunc( pgm_read_byte(ptr++) );
00394     
00395     // print the offending command
00396     ptr = CmdlineBuffer;
00397     while((*ptr) && (*ptr != ' ')) cmdlineOutputFunc(*ptr++);
00398 
00399     cmdlineOutputFunc(':');
00400     cmdlineOutputFunc(' ');
00401 
00402     // print the not-found message
00403     // (u08*) cast used to avoid compiler warning
00404     ptr = (u08*)CmdlineCmdNotFound;
00405     while(pgm_read_byte(ptr)) cmdlineOutputFunc( pgm_read_byte(ptr++) );
00406 
00407     cmdlineOutputFunc('\r');
00408     cmdlineOutputFunc('\n');
00409 }
00410 
00411 // argument retrieval commands
00412 
00413 // return string pointer to argument [argnum]
00414 u08* cmdlineGetArgStr(u08 argnum)
00415 {
00416     // find the offset of argument number [argnum]
00417     u08 idx=0;
00418     u08 arg;
00419     
00420     // find the first non-whitespace character
00421     while( (CmdlineBuffer[idx] != 0) && (CmdlineBuffer[idx] == ' ')) idx++;
00422     
00423     // we are at the first argument
00424     for(arg=0; arg<argnum; arg++)
00425     {
00426         // find the next whitespace character
00427         while( (CmdlineBuffer[idx] != 0) && (CmdlineBuffer[idx] != ' ')) idx++;
00428         // find the first non-whitespace character
00429         while( (CmdlineBuffer[idx] != 0) && (CmdlineBuffer[idx] == ' ')) idx++;
00430     }
00431     // we are at the requested argument or the end of the buffer
00432     return &CmdlineBuffer[idx];
00433 }
00434 
00435 // return argument [argnum] interpreted as a decimal integer
00436 long cmdlineGetArgInt(u08 argnum)
00437 {
00438     char* endptr;
00439     return strtol(cmdlineGetArgStr(argnum), &endptr, 10);
00440 }
00441 
00442 // return argument [argnum] interpreted as a hex integer
00443 long cmdlineGetArgHex(u08 argnum)
00444 {
00445     char* endptr;
00446     return strtol(cmdlineGetArgStr(argnum), &endptr, 16);
00447 }

Generated on Sun Oct 29 03:41:06 2006 for Procyon AVRlib by  doxygen 1.4.2