2014-01-20 00:40:36 +00:00
/* Copyright (C) 2014 by Jacob Alexander
*
2011-09-30 05:22:19 +00:00
* Permission is hereby granted , free of charge , to any person obtaining a copy
* of this software and associated documentation files ( the " Software " ) , to deal
* in the Software without restriction , including without limitation the rights
* to use , copy , modify , merge , publish , distribute , sublicense , and / or sell
* copies of the Software , and to permit persons to whom the Software is
* furnished to do so , subject to the following conditions :
2014-01-20 00:40:36 +00:00
*
2011-09-30 05:22:19 +00:00
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software .
2014-01-20 00:40:36 +00:00
*
2011-09-30 05:22:19 +00:00
* THE SOFTWARE IS PROVIDED " AS IS " , WITHOUT WARRANTY OF ANY KIND , EXPRESS OR
* IMPLIED , INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY ,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT . IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM , DAMAGES OR OTHER
* LIABILITY , WHETHER IN AN ACTION OF CONTRACT , TORT OR OTHERWISE , ARISING FROM ,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE .
*/
// ----- Includes -----
// Compiler Includes
2014-01-20 00:40:36 +00:00
//#include <stdarg.h>
2011-09-30 05:22:19 +00:00
2014-01-20 00:40:36 +00:00
// Project Includes
2014-01-23 10:01:12 +00:00
# include <buildvars.h>
2014-01-20 00:40:36 +00:00
# include "cli.h"
2014-01-23 10:01:12 +00:00
# include <led.h>
2014-01-22 08:38:53 +00:00
# include <print.h>
// ----- Variables -----
// Basic command dictionary
2014-01-24 09:56:44 +00:00
char * basicCLIDictName = " General Commands " ;
2014-01-22 08:38:53 +00:00
CLIDictItem basicCLIDict [ ] = {
2014-01-23 10:01:12 +00:00
{ " cliDebug " , " Enables/Disables hex output of the most recent cli input. " , cliFunc_cliDebug } ,
{ " help " , " You're looking at it :P " , cliFunc_help } ,
{ " led " , " Enables/Disables indicator LED. Try a couple times just in case the LED is in an odd state. \r \n \t \t \033 [33mWarning \033 [0m: May adversely affect some modules... " , cliFunc_led } ,
{ " reload " , " Signals microcontroller to reflash/reload. " , cliFunc_reload } ,
2014-01-23 10:36:00 +00:00
{ " reset " , " Resets the terminal back to initial settings. " , cliFunc_reset } ,
{ " restart " , " Sends a software restart, should be similar to powering on the device. " , cliFunc_restart } ,
2014-01-23 10:01:12 +00:00
{ " version " , " Version information about this firmware. " , cliFunc_version } ,
2014-01-22 08:38:53 +00:00
{ 0 , 0 , 0 } // Null entry for dictionary end
} ;
2013-01-27 06:47:52 +00:00
2011-09-30 05:22:19 +00:00
// ----- Functions -----
2014-01-22 08:38:53 +00:00
inline void prompt ( )
{
2014-01-24 11:01:09 +00:00
print ( " \033 [2K \r " ) ; // Erases the current line and resets cursor to beginning of line
print ( " \033 [1;34m: \033 [0m " ) ; // Blue bold prompt
2014-01-22 08:38:53 +00:00
}
2014-01-23 10:36:00 +00:00
// Initialize the CLI
2014-04-06 18:49:27 +00:00
inline void CLI_init ( )
2014-01-22 08:38:53 +00:00
{
// Reset the Line Buffer
CLILineBufferCurrent = 0 ;
// Set prompt
prompt ( ) ;
// Register first dictionary
CLIDictionariesUsed = 0 ;
2014-04-06 18:49:27 +00:00
CLI_registerDictionary ( basicCLIDict , basicCLIDictName ) ;
2014-01-23 10:01:12 +00:00
// Initialize main LED
init_errorLED ( ) ;
CLILEDState = 0 ;
2014-01-23 10:36:00 +00:00
// Hex debug mode is off by default
CLIHexDebugMode = 0 ;
2014-01-22 08:38:53 +00:00
}
2014-01-23 10:36:00 +00:00
// Query the serial input buffer for any new characters
2014-04-06 18:49:27 +00:00
void CLI_process ( )
2014-01-22 08:38:53 +00:00
{
// Current buffer position
uint8_t prev_buf_pos = CLILineBufferCurrent ;
// Process each character while available
while ( 1 )
{
// No more characters to process
2014-04-06 18:49:27 +00:00
if ( Output_availablechar ( ) = = 0 )
2014-01-22 08:38:53 +00:00
break ;
2014-03-31 08:07:48 +00:00
// Retrieve from output module
2014-04-06 18:49:27 +00:00
char cur_char = ( char ) Output_getchar ( ) ;
2014-01-22 08:38:53 +00:00
// Make sure buffer isn't full
if ( CLILineBufferCurrent > = CLILineBufferMaxSize )
{
print ( NL ) ;
erro_print ( " Serial line buffer is full, dropping character and resetting... " ) ;
// Clear buffer
CLILineBufferCurrent = 0 ;
// Reset the prompt
prompt ( ) ;
return ;
}
// Place into line buffer
CLILineBuffer [ CLILineBufferCurrent + + ] = cur_char ;
}
2014-01-23 10:36:00 +00:00
// Display Hex Key Input if enabled
if ( CLIHexDebugMode & & CLILineBufferCurrent > prev_buf_pos )
{
print ( " \033 [s \r \n " ) ; // Save cursor position, and move to the next line
print ( " \033 [2K " ) ; // Erases the current line
uint8_t pos = prev_buf_pos ;
while ( CLILineBufferCurrent > pos )
{
printHex ( CLILineBuffer [ pos + + ] ) ;
print ( " " ) ;
}
print ( " \033 [u " ) ; // Restore cursor position
}
2014-01-22 08:38:53 +00:00
// If buffer has changed, output to screen while there are still characters in the buffer not displayed
while ( CLILineBufferCurrent > prev_buf_pos )
{
// Check for control characters
switch ( CLILineBuffer [ prev_buf_pos ] )
{
case 0x0D : // Enter
2014-02-04 08:27:33 +00:00
CLILineBuffer [ CLILineBufferCurrent - 1 ] = ' ' ; // Replace Enter with a space (resolves a bug in args)
// Remove the space if there is no command
if ( CLILineBufferCurrent = = 1 )
CLILineBufferCurrent - - ;
2014-01-22 08:38:53 +00:00
// Process the current line buffer
2014-04-06 18:49:27 +00:00
CLI_commandLookup ( ) ;
2014-01-22 08:38:53 +00:00
// Reset the buffer
CLILineBufferCurrent = 0 ;
// Reset the prompt after processing has finished
print ( NL ) ;
prompt ( ) ;
// XXX There is a potential bug here when resetting the buffer (losing valid keypresses)
// Doesn't look like it will happen *that* often, so not handling it for now -HaaTa
return ;
case 0x09 : // Tab
// Tab completion for the current command
2014-04-06 18:49:27 +00:00
CLI_tabCompletion ( ) ;
2014-01-24 11:01:09 +00:00
CLILineBufferCurrent - - ; // Remove the Tab
// XXX There is a potential bug here when resetting the buffer (losing valid keypresses)
// Doesn't look like it will happen *that* often, so not handling it for now -HaaTa
2014-01-22 08:38:53 +00:00
return ;
case 0x1B : // Esc
// Check for escape sequence
// TODO
return ;
case 0x08 :
case 0x7F : // Backspace
// TODO - Does not handle case for arrow editing (arrows disabled atm)
CLILineBufferCurrent - - ; // Remove the backspace
// If there are characters in the buffer
if ( CLILineBufferCurrent > 0 )
{
// Remove character from current position in the line buffer
CLILineBufferCurrent - - ;
// Remove character from tty
print ( " \b \b " ) ;
}
break ;
default :
// Place a null on the end (to use with string print)
CLILineBuffer [ CLILineBufferCurrent ] = ' \0 ' ;
// Output buffer to screen
dPrint ( & CLILineBuffer [ prev_buf_pos ] ) ;
// Buffer reset
prev_buf_pos + + ;
break ;
}
}
}
2014-01-22 09:58:34 +00:00
// Takes a string, returns two pointers
// One to the first non-space character
// The second to the next argument (first NULL if there isn't an argument). delimited by a space
// Places a NULL at the first space after the first argument
2014-04-06 20:12:31 +00:00
void CLI_argumentIsolation ( char * string , char * * first , char * * second )
2014-01-22 08:38:53 +00:00
{
// Mark out the first argument
// This is done by finding the first space after a list of non-spaces and setting it NULL
2014-01-22 09:58:34 +00:00
char * cmdPtr = string - 1 ;
2014-01-22 08:38:53 +00:00
while ( * + + cmdPtr = = ' ' ) ; // Skips leading spaces, and points to first character of cmd
2014-01-22 09:10:32 +00:00
// Locates first space delimiter
char * argPtr = cmdPtr + 1 ;
while ( * argPtr ! = ' ' & & * argPtr ! = ' \0 ' )
2014-01-22 08:38:53 +00:00
argPtr + + ;
2014-01-22 09:10:32 +00:00
// Point to the first character of args or a NULL (no args) and set the space delimiter as a NULL
( + + argPtr ) [ - 1 ] = ' \0 ' ;
2014-01-22 08:38:53 +00:00
2014-01-22 09:58:34 +00:00
// Set return variables
* first = cmdPtr ;
* second = argPtr ;
}
2014-01-23 10:36:00 +00:00
// Scans the CLILineBuffer for any valid commands
2014-04-06 18:49:27 +00:00
void CLI_commandLookup ( )
2014-01-22 09:58:34 +00:00
{
// Ignore command if buffer is 0 length
if ( CLILineBufferCurrent = = 0 )
return ;
// Set the last+1 character of the buffer to NULL for string processing
CLILineBuffer [ CLILineBufferCurrent ] = ' \0 ' ;
// Retrieve pointers to command and beginning of arguments
// Places a NULL at the first space after the command
char * cmdPtr ;
char * argPtr ;
2014-04-06 18:49:27 +00:00
CLI_argumentIsolation ( CLILineBuffer , & cmdPtr , & argPtr ) ;
2014-01-22 09:58:34 +00:00
2014-01-22 08:38:53 +00:00
// Scan array of dictionaries for a valid command match
for ( uint8_t dict = 0 ; dict < CLIDictionariesUsed ; dict + + )
{
// Parse each cmd until a null command entry is found, or an argument match
for ( uint8_t cmd = 0 ; CLIDict [ dict ] [ cmd ] . name ! = 0 ; cmd + + )
{
// Compare the first argument and each command entry
2014-01-24 11:01:09 +00:00
if ( eqStr ( cmdPtr , CLIDict [ dict ] [ cmd ] . name ) = = - 1 )
2014-01-22 08:38:53 +00:00
{
// Run the specified command function pointer
// argPtr is already pointing at the first character of the arguments
( * CLIDict [ dict ] [ cmd ] . function ) ( argPtr ) ;
return ;
}
}
}
// No match for the command...
print ( NL ) ;
2014-01-22 09:58:34 +00:00
erro_dPrint ( " \" " , CLILineBuffer , " \" is not a valid command...type \033 [35mhelp \033 [0m " ) ;
2014-01-22 08:38:53 +00:00
}
2014-01-23 10:36:00 +00:00
// Registers a command dictionary with the CLI
2014-04-06 20:12:31 +00:00
void CLI_registerDictionary ( CLIDictItem * cmdDict , char * dictName )
2014-01-22 08:38:53 +00:00
{
// Make sure this max limit of dictionaries hasn't been reached
if ( CLIDictionariesUsed > = CLIMaxDictionaries )
{
erro_print ( " Max number of dictionaries defined already... " ) ;
return ;
}
// Add dictionary
2014-01-24 09:56:44 +00:00
CLIDictNames [ CLIDictionariesUsed ] = dictName ;
2014-01-22 08:38:53 +00:00
CLIDict [ CLIDictionariesUsed + + ] = cmdDict ;
}
2014-04-06 18:49:27 +00:00
inline void CLI_tabCompletion ( )
2014-01-24 11:01:09 +00:00
{
// Ignore command if buffer is 0 length
if ( CLILineBufferCurrent = = 0 )
return ;
// Set the last+1 character of the buffer to NULL for string processing
CLILineBuffer [ CLILineBufferCurrent ] = ' \0 ' ;
// Retrieve pointers to command and beginning of arguments
// Places a NULL at the first space after the command
char * cmdPtr ;
char * argPtr ;
2014-04-06 18:49:27 +00:00
CLI_argumentIsolation ( CLILineBuffer , & cmdPtr , & argPtr ) ;
2014-01-24 11:01:09 +00:00
// Tab match pointer
char * tabMatch = 0 ;
uint8_t matches = 0 ;
// Scan array of dictionaries for a valid command match
for ( uint8_t dict = 0 ; dict < CLIDictionariesUsed ; dict + + )
{
// Parse each cmd until a null command entry is found, or an argument match
for ( uint8_t cmd = 0 ; CLIDict [ dict ] [ cmd ] . name ! = 0 ; cmd + + )
{
// Compare the first argument piece to each command entry to see if it is "like"
// NOTE: To save on processing, we only care about the commands and ignore the arguments
// If there are arguments, and a valid tab match is found, buffer is cleared (args lost)
// Also ignores full matches
if ( eqStr ( cmdPtr , CLIDict [ dict ] [ cmd ] . name ) = = 0 )
{
// TODO Make list of commands if multiple matches
matches + + ;
tabMatch = CLIDict [ dict ] [ cmd ] . name ;
}
}
}
// Only tab complete if there was 1 match
if ( matches = = 1 )
{
// Reset the buffer
CLILineBufferCurrent = 0 ;
// Reprint the prompt (automatically clears the line)
prompt ( ) ;
// Display the command
dPrint ( tabMatch ) ;
// There are no index counts, so just copy the whole string to the input buffer
while ( * tabMatch ! = ' \0 ' )
{
CLILineBuffer [ CLILineBufferCurrent + + ] = * tabMatch + + ;
}
}
}
2014-01-22 08:38:53 +00:00
// ----- CLI Command Functions -----
2014-01-23 10:01:12 +00:00
void cliFunc_cliDebug ( char * args )
{
2014-01-23 10:36:00 +00:00
// Toggle Hex Debug Mode
if ( CLIHexDebugMode )
{
print ( NL ) ;
info_print ( " Hex debug mode disabled... " ) ;
CLIHexDebugMode = 0 ;
}
else
{
print ( NL ) ;
info_print ( " Hex debug mode enabled... " ) ;
CLIHexDebugMode = 1 ;
}
2014-01-23 10:01:12 +00:00
}
2014-01-22 08:38:53 +00:00
void cliFunc_help ( char * args )
{
2014-01-22 09:58:34 +00:00
// Scan array of dictionaries and print every description
// (no alphabetical here, too much processing/memory to sort...)
for ( uint8_t dict = 0 ; dict < CLIDictionariesUsed ; dict + + )
{
2014-01-24 09:56:44 +00:00
// Print the name of each dictionary as a title
dPrintStrsNL ( NL , " \033 [1;32m " , CLIDictNames [ dict ] , " \033 [0m " ) ;
2014-01-22 09:58:34 +00:00
// Parse each cmd/description until a null command entry is found
for ( uint8_t cmd = 0 ; CLIDict [ dict ] [ cmd ] . name ! = 0 ; cmd + + )
{
2014-01-23 10:01:12 +00:00
dPrintStrs ( " \033 [35m " , CLIDict [ dict ] [ cmd ] . name , " \033 [0m " ) ;
// Determine number of spaces to tab by the length of the command and TabAlign
uint8_t padLength = CLIEntryTabAlign - lenStr ( CLIDict [ dict ] [ cmd ] . name ) ;
while ( padLength - - > 0 )
print ( " " ) ;
dPrintStrNL ( CLIDict [ dict ] [ cmd ] . description ) ;
2014-01-22 09:58:34 +00:00
}
}
2014-01-22 08:38:53 +00:00
}
2014-01-23 10:01:12 +00:00
void cliFunc_led ( char * args )
{
CLILEDState ^ = 1 < < 1 ; // Toggle between 0 and 1
errorLED ( CLILEDState ) ; // Enable/Disable error LED
}
void cliFunc_reload ( char * args )
{
// Request to output module to be set into firmware reload mode
2014-04-06 18:49:27 +00:00
Output_firmwareReload ( ) ;
2014-01-23 10:01:12 +00:00
}
void cliFunc_reset ( char * args )
2014-01-23 10:36:00 +00:00
{
print ( " \033 c " ) ; // Resets the terminal
}
void cliFunc_restart ( char * args )
2014-01-23 10:01:12 +00:00
{
// Trigger an overall software reset
2014-04-06 18:49:27 +00:00
Output_softReset ( ) ;
2014-01-23 10:01:12 +00:00
}
2014-01-22 08:38:53 +00:00
void cliFunc_version ( char * args )
2014-01-20 00:40:36 +00:00
{
2014-01-22 08:38:53 +00:00
print ( NL ) ;
2014-01-23 10:01:12 +00:00
print ( " \033 [1mRevision: \033 [0m " CLI_Revision NL ) ;
print ( " \033 [1mBranch: \033 [0m " CLI_Branch NL ) ;
print ( " \033 [1mTree Status: \033 [0m " CLI_ModifiedStatus NL ) ;
print ( " \033 [1mRepo Origin: \033 [0m " CLI_RepoOrigin NL ) ;
print ( " \033 [1mCommit Date: \033 [0m " CLI_CommitDate NL ) ;
print ( " \033 [1mCommit Author: \033 [0m " CLI_CommitAuthor NL ) ;
print ( " \033 [1mBuild Date: \033 [0m " CLI_BuildDate NL ) ;
print ( " \033 [1mBuild OS: \033 [0m " CLI_BuildOS NL ) ;
print ( " \033 [1mArchitecture: \033 [0m " CLI_Arch NL ) ;
print ( " \033 [1mChip: \033 [0m " CLI_Chip NL ) ;
print ( " \033 [1mCPU: \033 [0m " CLI_CPU NL ) ;
print ( " \033 [1mDevice: \033 [0m " CLI_Device NL ) ;
print ( " \033 [1mModules: \033 [0m " CLI_Modules NL ) ;
2014-01-20 00:40:36 +00:00
}
2011-09-30 05:22:19 +00:00