diff --git a/Debug/cli/cli.c b/Debug/cli/cli.c index da657cc..b69bdf0 100644 --- a/Debug/cli/cli.c +++ b/Debug/cli/cli.c @@ -26,12 +26,226 @@ // Project Includes #include "cli.h" +#include + + + +// ----- Variables ----- + +// Basic command dictionary +CLIDictItem basicCLIDict[] = { + { "help", "This command :P", cliFunc_help }, + { "version", "Version information about this firmware.", cliFunc_version }, + { 0, 0, 0 } // Null entry for dictionary end +}; // ----- Functions ----- -void init_cli() +inline void prompt() { + print(": "); +} + +inline void init_cli() +{ + // Reset the Line Buffer + CLILineBufferCurrent = 0; + + // Set prompt + prompt(); + + // Register first dictionary + CLIDictionariesUsed = 0; + registerDictionary_cli( basicCLIDict ); +} + +void process_cli() +{ + // Current buffer position + uint8_t prev_buf_pos = CLILineBufferCurrent; + + // Process each character while available + int result = 0; + while ( 1 ) + { + // No more characters to process + result = usb_serial_getchar(); // Retrieve from serial module // TODO Make USB agnostic + if ( result == -1 ) + break; + + char cur_char = (char)result; + + // 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; + } + + // 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 + CLILineBufferCurrent--; // Remove the Enter + + // Process the current line buffer + commandLookup_cli(); + + // 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 + // TODO + 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; + } + + /* TODO Enable via option + uint8_t pos = prev_buf_pos; + while ( CLILineBuffer[pos] != 0 ) + { + printHex( CLILineBuffer[pos++] ); + print(" "); + } + + print( NL ); + */ + } +} + +void commandLookup_cli() +{ + // 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'; + + // Mark out the first argument + // This is done by finding the first space after a list of non-spaces and setting it NULL + char* cmdPtr = CLILineBuffer - 1; + while ( *++cmdPtr == ' ' ); // Skips leading spaces, and points to first character of cmd + + // Locates first space delimiter, and points to first character of args or a NULL (no args) + char* argPtr = cmdPtr; + do { + argPtr++; + } while ( *argPtr != ' ' && *argPtr != '\0' ); + + // Set the space delimiter as a NULL + argPtr[-1] = '\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 and each command entry + if ( eqStr( cmdPtr, CLIDict[dict][cmd].name ) ) + { + // 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 ); + erro_dPrint("\"", CLILineBuffer, "\" is not a valid command...try help"); +} + +void registerDictionary_cli( CLIDictItem *cmdDict ) +{ + // 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 + CLIDict[CLIDictionariesUsed++] = cmdDict; +} + + + +// ----- CLI Command Functions ----- + +void cliFunc_help( char* args ) +{ + print( NL ); + print("Help!"); + dPrint( args ); +} + +void cliFunc_version( char* args ) +{ + print( NL ); + print("Version!"); + dPrint( args ); } diff --git a/Debug/cli/cli.h b/Debug/cli/cli.h index d5f4e5b..081f372 100644 --- a/Debug/cli/cli.h +++ b/Debug/cli/cli.h @@ -37,12 +37,44 @@ // ----- Defines ----- +#define CLILineBufferMaxSize 100 +#define CLIMaxDictionaries 5 + + +// ----- Structs ----- + +// Each item has a name, description, and function pointer with an argument for arguments +typedef struct CLIDictItem { + char* name; + char* description; + void (*function)(char*); +} CLIDictItem; + + + +// ----- Variables ----- + +char CLILineBuffer[CLILineBufferMaxSize+1]; // +1 for an additional NULL +uint8_t CLILineBufferCurrent; + +// Main command dictionary +CLIDictItem *CLIDict[CLIMaxDictionaries]; +uint8_t CLIDictionariesUsed; + + // ----- Functions and Corresponding Function Aliases ----- void init_cli(); +void process_cli(); +void registerDictionary_cli( CLIDictItem *cmdDict ); +void commandLookup_cli(); + +// CLI Command Functions +void cliFunc_help ( char* args ); +void cliFunc_version( char* args ); #endif diff --git a/Debug/print/print.c b/Debug/print/print.c index bb97d3f..27ecf4b 100644 --- a/Debug/print/print.c +++ b/Debug/print/print.c @@ -240,3 +240,13 @@ uint16_t lenStr( char* in ) return (pos - in); } + +uint8_t eqStr( char* str1, char* str2 ) +{ + // Scan each string for NULLs and whether they are the same + while( *str1 != '\0' && *str1++ == *str2++ ); + + // If the strings are still identical (i.e. both NULL), then return 1, otherwise 0 + return *--str1 == *--str2 ? 1 : 0; +} + diff --git a/Debug/print/print.h b/Debug/print/print.h index 18fad6d..924d101 100644 --- a/Debug/print/print.h +++ b/Debug/print/print.h @@ -109,6 +109,7 @@ void int16ToStr ( uint16_t in, char* out ); void hexToStr_op( uint16_t in, char* out, uint8_t op ); void revsStr ( char* in ); uint16_t lenStr ( char* in ); +uint8_t eqStr ( char* str1, char* str2 ); // Returns 1 if identical, 0 otherwise #endif diff --git a/main.c b/main.c index dd8b8e0..ab43370 100644 --- a/main.c +++ b/main.c @@ -1,15 +1,15 @@ -/* Copyright (C) 2011-2013 by Jacob Alexander - * +/* Copyright (C) 2011-2014 by Jacob Alexander + * * 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: - * + * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. - * + * * 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 @@ -29,6 +29,7 @@ #include #include +#include #include #include