]> git.donarmstrong.com Git - kiibohd-controller.git/commitdiff
Adding basic CLI functionality.
authorJacob Alexander <haata@kiibohd.com>
Wed, 22 Jan 2014 08:38:53 +0000 (00:38 -0800)
committerJacob Alexander <haata@kiibohd.com>
Sat, 22 Mar 2014 21:10:51 +0000 (14:10 -0700)
- Supports multiple custom command dictionaries
- Basic handling of control characters
- Initial dictionary for integrated commands

Debug/cli/cli.c
Debug/cli/cli.h
Debug/print/print.c
Debug/print/print.h
main.c

index da657ccc60940ab4b1fc0c601aed377bf3111eeb..b69bdf0dd42a8e2c3cff04deae5fb1881eccd396 100644 (file)
 
 // Project Includes
 #include "cli.h"
+#include <print.h>
+
+
+
+// ----- 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 );
 }
 
index d5f4e5bb7ccded0afe5411ff305e4ee8c1f30842..081f372688bd2f253d815ab961294726dcc13eb8 100644 (file)
 
 // ----- 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
index bb97d3f60164179689fae0c953001052bf461b5d..27ecf4becb6170edb5e2662f18480b61b850b624 100644 (file)
@@ -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;
+}
+
index 18fad6d91cde660910b8e5a1b938df15dcf9e1d0..924d101030f7e2c53a5569fe49cfa84d0a2f017f 100644 (file)
@@ -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 dd8b8e0983ffdc8f705fc4c729082f7dd017fbaf..ab433700966203541a1f333020783d8267388981 100644 (file)
--- 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 <scan_loop.h>
 #include <output_com.h>
 
+#include <cli.h>
 #include <led.h>
 #include <print.h>