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

Generated on Tue Sep 20 03:11:42 2005 for Procyon AVRlib by  doxygen 1.4.2