changeset 106:15961894eaeb

Adding basic CLI functionality. - Supports multiple custom command dictionaries - Basic handling of control characters - Initial dictionary for integrated commands
author Jacob Alexander <haata@kiibohd.com>
date Wed, 22 Jan 2014 00:38:53 -0800
parents 3764d78996a8
children 6e3201b2c68b
files Debug/cli/cli.c Debug/cli/cli.h Debug/print/print.c Debug/print/print.h main.c
diffstat 5 files changed, 263 insertions(+), 5 deletions(-) [+]
line wrap: on
line diff
--- a/Debug/cli/cli.c	Sun Jan 19 16:54:58 2014 -0800
+++ b/Debug/cli/cli.c	Wed Jan 22 00:38:53 2014 -0800
@@ -26,12 +26,226 @@
 
 // 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 );
+}
+
--- a/Debug/cli/cli.h	Sun Jan 19 16:54:58 2014 -0800
+++ b/Debug/cli/cli.h	Wed Jan 22 00:38:53 2014 -0800
@@ -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
--- a/Debug/print/print.c	Sun Jan 19 16:54:58 2014 -0800
+++ b/Debug/print/print.c	Wed Jan 22 00:38:53 2014 -0800
@@ -240,3 +240,13 @@
 	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;
+}
+
--- a/Debug/print/print.h	Sun Jan 19 16:54:58 2014 -0800
+++ b/Debug/print/print.h	Wed Jan 22 00:38:53 2014 -0800
@@ -109,6 +109,7 @@
 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
 
--- a/main.c	Sun Jan 19 16:54:58 2014 -0800
+++ b/main.c	Wed Jan 22 00:38:53 2014 -0800
@@ -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>