?lang_form? ?lang_select? ?lang_submit? ?lang_endform?
{HEADER END}
{FILE START}

library

?curdirlinks? - Rev 6

?prevdifflink? - Blame - ?getfile?

/*! \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 <avr/io.h>                     // include I/O definitions (port names, pin names, etc)
#include <avr/interrupt.h>      // include interrupt support
#include <avr/pgmspace.h>       // include AVR program memory support
#include <string.h>                     // include standard C string functions
#include <stdlib.h>                     // 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<CmdlineBufferLength; i++)
                                cmdlineOutputFunc(ASCII_BS);
                }
        }
        // handle special characters
        else if(c == ASCII_CR)
        {
                // user pressed [ENTER]
                // echo CR and LF to terminal
                cmdlineOutputFunc(ASCII_CR);
                cmdlineOutputFunc(ASCII_LF);
                // add null termination to command
                CmdlineBuffer[CmdlineBufferLength++] = 0;
                CmdlineBufferEditPos++;
                // command is complete, process it
                cmdlineProcessInputString();
                // reset buffer
                CmdlineBufferLength = 0;
                CmdlineBufferEditPos = 0;
        }
        else if(c == ASCII_BS)
        {
                if(CmdlineBufferEditPos)
                {
                        // is this a simple delete (off the end of the line)
                        if(CmdlineBufferEditPos == CmdlineBufferLength)
                        {
                                // destructive backspace
                                // echo backspace-space-backspace
                                cmdlineOutputFunc(ASCII_BS);
                                cmdlineOutputFunc(' ');
                                cmdlineOutputFunc(ASCII_BS);
                                // decrement our buffer length and edit position
                                CmdlineBufferLength--;
                                CmdlineBufferEditPos--;
                        }
                        else
                        {
                                // edit/cursor position != end of buffer
                                // we're deleting characters at a mid-line edit position
                                // shift characters down, effectively deleting
                                CmdlineBufferLength--;
                                CmdlineBufferEditPos--;
                                for(i=CmdlineBufferEditPos; i<CmdlineBufferLength; i++)
                                        CmdlineBuffer[i] = CmdlineBuffer[i+1];
                                // repaint
                                cmdlineRepaint();
                                // add space to clear leftover characters
                                cmdlineOutputFunc(' ');
                                // reposition cursor
                                for(i=CmdlineBufferEditPos; i<(CmdlineBufferLength+1); i++)
                                        cmdlineOutputFunc(ASCII_BS);
                        }
                }
                else
                {
                        // else, ring the bell
                        cmdlineOutputFunc(ASCII_BEL);
                }
        }
        else if(c == ASCII_DEL)
        {
                // not yet handled
        }
        else if(c == ASCII_ESC)
        {
                CmdlineInputVT100State = 1;
        }
}

void cmdlineRepaint(void)
{
        u08* ptr;
        u08 i;

        // carriage return
        cmdlineOutputFunc(ASCII_CR);
        // print fresh prompt
        cmdlinePrintPrompt();
        // print the new command line buffer
        i = CmdlineBufferLength;
        ptr = CmdlineBuffer;
        while(i--) cmdlineOutputFunc(*ptr++);
}

void cmdlineDoHistory(u08 action)
{
        switch(action)
        {
        case CMDLINE_HISTORY_SAVE:
                // copy CmdlineBuffer to history if not null string
                if( strlen(CmdlineBuffer) )
                        strcpy(CmdlineHistory[0], CmdlineBuffer);
                break;
        case CMDLINE_HISTORY_PREV:
                // copy history to current buffer
                strcpy(CmdlineBuffer, CmdlineHistory[0]);
                // set the buffer position to the end of the line
                CmdlineBufferLength = strlen(CmdlineBuffer);
                CmdlineBufferEditPos = CmdlineBufferLength;
                // "re-paint" line
                cmdlineRepaint();
                break;
        case CMDLINE_HISTORY_NEXT:
                break;
        }
}

void cmdlineProcessInputString(void)
{
        u08 cmdIndex;
        u08 i=0;

        // save command in history
        cmdlineDoHistory(CMDLINE_HISTORY_SAVE);

        // find the end of the command (excluding arguments)
        // find first whitespace character in CmdlineBuffer
        while( !((CmdlineBuffer[i] == ' ') || (CmdlineBuffer[i] == 0)) ) i++;

        if(!i)
        {
                // command was null or empty
                // output a new prompt
                cmdlinePrintPrompt();
                // we're done
                return;
        }

        // search command list for match with entered command
        for(cmdIndex=0; cmdIndex<CmdlineNumCommands; cmdIndex++)
        {
                if( !strncmp(CmdlineCommandList[cmdIndex], CmdlineBuffer, i) )
                {
                        // user-entered command matched a command in the list (database)
                        // run the corresponding function
                        CmdlineExecFunction = CmdlineFunctionList[cmdIndex];
                        // new prompt will be output after user function runs
                        // and we're done
                        return;
                }
        }

        // if we did not get a match
        // output an error message
        cmdlinePrintError();
        // output a new prompt
        cmdlinePrintPrompt();
}

void cmdlineMainLoop(void)
{
        // do we have a command/function to be executed
        if(CmdlineExecFunction)
        {
                // run it
                CmdlineExecFunction();
                // reset
                CmdlineExecFunction = 0;
                // output new prompt
                cmdlinePrintPrompt();
        }
}

void cmdlinePrintPrompt(void)
{
        // print a new command prompt
        u08* ptr = CmdlinePrompt;
        while(pgm_read_byte(ptr)) cmdlineOutputFunc( pgm_read_byte(ptr++) );
}

void cmdlinePrintError(void)
{
        u08 * ptr;

        // print a notice header
        // (u08*) cast used to avoid compiler warning
        ptr = (u08*)CmdlineNotice;
        while(pgm_read_byte(ptr)) cmdlineOutputFunc( pgm_read_byte(ptr++) );
        
        // print the offending command
        ptr = CmdlineBuffer;
        while((*ptr) && (*ptr != ' ')) cmdlineOutputFunc(*ptr++);

        cmdlineOutputFunc(':');
        cmdlineOutputFunc(' ');

        // print the not-found message
        // (u08*) cast used to avoid compiler warning
        ptr = (u08*)CmdlineCmdNotFound;
        while(pgm_read_byte(ptr)) cmdlineOutputFunc( pgm_read_byte(ptr++) );

        cmdlineOutputFunc('\r');
        cmdlineOutputFunc('\n');
}

// argument retrieval commands

// return string pointer to argument [argnum]
u08* cmdlineGetArgStr(u08 argnum)
{
        // find the offset of argument number [argnum]
        u08 idx=0;
        u08 arg;
        
        // find the first non-whitespace character
        while( (CmdlineBuffer[idx] != 0) && (CmdlineBuffer[idx] == ' ')) idx++;
        
        // we are at the first argument
        for(arg=0; arg<argnum; arg++)
        {
                // find the next whitespace character
                while( (CmdlineBuffer[idx] != 0) && (CmdlineBuffer[idx] != ' ')) idx++;
                // find the first non-whitespace character
                while( (CmdlineBuffer[idx] != 0) && (CmdlineBuffer[idx] == ' ')) idx++;
        }
        // we are at the requested argument or the end of the buffer
        return &CmdlineBuffer[idx];
}

// return argument [argnum] interpreted as a decimal integer
long cmdlineGetArgInt(u08 argnum)
{
        char* endptr;
        return strtol(cmdlineGetArgStr(argnum), &endptr, 10);
}

// return argument [argnum] interpreted as a hex integer
long cmdlineGetArgHex(u08 argnum)
{
        char* endptr;
        return strtol(cmdlineGetArgStr(argnum), &endptr, 16);
}
{FILE END}
{FOOTER START}

Powered by WebSVN v2.8.3