/*! \file cmdline.c \brief Command-Line Interface Library. */ //***************************************************************************** // // File Name : 'cmdline.c' // Title : Command-Line Interface Library // Author : Pascal Stang - Copyright (C) 2003 // Created : 2003.07.16 // Revised : 2003.07.23 // Version : 0.1 // Target MCU : Atmel AVR Series // Editor Tabs : 4 // // NOTE: This code is currently below version 1.0, and therefore is considered // to be lacking in some functionality or documentation, or may not be fully // tested. Nonetheless, you can expect most functions to work. // // This code is distributed under the GNU Public License // which can be found at http://www.gnu.org/licenses/gpl.txt // //***************************************************************************** //----- Include Files --------------------------------------------------------- #include // include I/O definitions (port names, pin names, etc) #include // include "signal" names (interrupt names) #include // include interrupt support #include // include AVR program memory support #include // include standard C string functions #include // include stdlib for string conversion functions #include "global.h" // include our global settings #include "cmdline.h" // include project-specific configuration #include "cmdlineconf.h" // defines #define ASCII_BEL 0x07 #define ASCII_BS 0x08 #define ASCII_CR 0x0D #define ASCII_LF 0x0A #define ASCII_ESC 0x1B #define ASCII_DEL 0x7F #define VT100_ARROWUP 'A' #define VT100_ARROWDOWN 'B' #define VT100_ARROWRIGHT 'C' #define VT100_ARROWLEFT 'D' #define CMDLINE_HISTORY_SAVE 0 #define CMDLINE_HISTORY_PREV 1 #define CMDLINE_HISTORY_NEXT 2 // Global variables // strings u08 PROGMEM CmdlinePrompt[] = "cmd>"; u08 PROGMEM CmdlineNotice[] = "cmdline: "; u08 PROGMEM CmdlineCmdNotFound[] = "command not found"; // command list // -commands are null-terminated strings static char CmdlineCommandList[CMDLINE_MAX_COMMANDS][CMDLINE_MAX_CMD_LENGTH]; // command function pointer list static CmdlineFuncPtrType CmdlineFunctionList[CMDLINE_MAX_COMMANDS]; // number of commands currently registered u08 CmdlineNumCommands; u08 CmdlineBuffer[CMDLINE_BUFFERSIZE]; u08 CmdlineBufferLength; u08 CmdlineBufferEditPos; u08 CmdlineInputVT100State; u08 CmdlineHistory[CMDLINE_HISTORYSIZE][CMDLINE_BUFFERSIZE]; CmdlineFuncPtrType CmdlineExecFunction; // Functions // function pointer to single character output routine static void (*cmdlineOutputFunc)(unsigned char c); void cmdlineInit(void) { // reset vt100 processing state CmdlineInputVT100State = 0; // initialize input buffer CmdlineBufferLength = 0; CmdlineBufferEditPos = 0; // initialize executing function CmdlineExecFunction = 0; // initialize command list CmdlineNumCommands = 0; } void cmdlineAddCommand(u08* newCmdString, CmdlineFuncPtrType newCmdFuncPtr) { // add command string to end of command list strcpy(CmdlineCommandList[CmdlineNumCommands], newCmdString); // add command function ptr to end of function list CmdlineFunctionList[CmdlineNumCommands] = newCmdFuncPtr; // increment number of registered commands CmdlineNumCommands++; } void cmdlineSetOutputFunc(void (*output_func)(unsigned char c)) { // set new output function cmdlineOutputFunc = output_func; // should we really do this? // print a prompt //cmdlinePrintPrompt(); } void cmdlineInputFunc(unsigned char c) { u08 i; // process the received character // VT100 handling // are we processing a VT100 command? if(CmdlineInputVT100State == 2) { // we have already received ESC and [ // now process the vt100 code switch(c) { case VT100_ARROWUP: cmdlineDoHistory(CMDLINE_HISTORY_PREV); break; case VT100_ARROWDOWN: cmdlineDoHistory(CMDLINE_HISTORY_NEXT); break; case VT100_ARROWRIGHT: // if the edit position less than current string length if(CmdlineBufferEditPos < CmdlineBufferLength) { // increment the edit position CmdlineBufferEditPos++; // move cursor forward one space (no erase) cmdlineOutputFunc(ASCII_ESC); cmdlineOutputFunc('['); cmdlineOutputFunc(VT100_ARROWRIGHT); } else { // else, ring the bell cmdlineOutputFunc(ASCII_BEL); } break; case VT100_ARROWLEFT: // if the edit position is non-zero if(CmdlineBufferEditPos) { // decrement the edit position CmdlineBufferEditPos--; // move cursor back one space (no erase) cmdlineOutputFunc(ASCII_BS); } else { // else, ring the bell cmdlineOutputFunc(ASCII_BEL); } break; default: break; } // done, reset state CmdlineInputVT100State = 0; return; } else if(CmdlineInputVT100State == 1) { // we last received [ESC] if(c == '[') { CmdlineInputVT100State = 2; return; } else CmdlineInputVT100State = 0; } else { // anything else, reset state CmdlineInputVT100State = 0; } // Regular handling if( (c >= 0x20) && (c < 0x7F) ) { // character is printable // is this a simple append if(CmdlineBufferEditPos == CmdlineBufferLength) { // echo character to the output cmdlineOutputFunc(c); // add it to the command line buffer CmdlineBuffer[CmdlineBufferEditPos++] = c; // update buffer length CmdlineBufferLength++; } else { // edit/cursor position != end of buffer // we're inserting characters at a mid-line edit position // make room at the insert point CmdlineBufferLength++; for(i=CmdlineBufferLength; i>CmdlineBufferEditPos; i--) CmdlineBuffer[i] = CmdlineBuffer[i-1]; // insert character CmdlineBuffer[CmdlineBufferEditPos++] = c; // repaint cmdlineRepaint(); // reposition cursor for(i=CmdlineBufferEditPos; i