Implements a framework for an interactive terminal over a serial link. Commands can be added by writing functions to handle them and passing pointers to the functions to the terminal object.

Committer:
UCSBRobotics
Date:
Tue Oct 09 17:01:19 2012 +0000
Revision:
13:0dddfc8bce8d
Parent:
10:ce5816cee1e4
Removed a comment

Who changed what in which revision?

UserRevisionLine numberNew contents of line
UCSBRobotics 6:4269b879a2af 1 #include "Terminal.h"
UCSBRobotics 6:4269b879a2af 2 #include "mbed.h"
UCSBRobotics 6:4269b879a2af 3 #include <cctype>
UCSBRobotics 6:4269b879a2af 4 #include <cstring>
UCSBRobotics 6:4269b879a2af 5
UCSBRobotics 6:4269b879a2af 6
UCSBRobotics 6:4269b879a2af 7
UCSBRobotics 6:4269b879a2af 8 Terminal::Terminal(PinName tx, PinName rx, int baudrate) : serial(tx, rx)
UCSBRobotics 6:4269b879a2af 9 {
UCSBRobotics 9:bb92a6ecb668 10 // These values need to be initialized
UCSBRobotics 6:4269b879a2af 11 numCommands = 0;
UCSBRobotics 6:4269b879a2af 12 runningCmd = NULL;
UCSBRobotics 10:ce5816cee1e4 13 inputBuffer[0] = '\0';
UCSBRobotics 6:4269b879a2af 14
UCSBRobotics 9:bb92a6ecb668 15 // Set up the serial connection
UCSBRobotics 6:4269b879a2af 16 serial.baud(baudrate);
UCSBRobotics 6:4269b879a2af 17 serial.attach(this, &Terminal::receive, Serial::RxIrq);
UCSBRobotics 10:ce5816cee1e4 18 serial.printf("\n> ");
UCSBRobotics 6:4269b879a2af 19 }
UCSBRobotics 6:4269b879a2af 20
UCSBRobotics 6:4269b879a2af 21
UCSBRobotics 6:4269b879a2af 22
UCSBRobotics 6:4269b879a2af 23 void Terminal::addCommand(const char* cmdString, CmdHandler* (*fpointer)(Terminal*, const char*) )
UCSBRobotics 6:4269b879a2af 24 {
UCSBRobotics 9:bb92a6ecb668 25 // Check if there's room in the command array before adding a command
UCSBRobotics 6:4269b879a2af 26 if (numCommands < NUM_COMMANDS_MAX)
UCSBRobotics 6:4269b879a2af 27 {
UCSBRobotics 6:4269b879a2af 28 strncpy(cmdList[numCommands].cmdString, cmdString, INPUT_BUFFER_MAX);
UCSBRobotics 6:4269b879a2af 29 cmdList[numCommands].cmdString[INPUT_BUFFER_MAX - 1] = '\0'; // Make sure that the command string is null terminated
UCSBRobotics 6:4269b879a2af 30 cmdList[numCommands].stringLength = strlen(cmdList[numCommands].cmdString);
UCSBRobotics 6:4269b879a2af 31 cmdList[numCommands].fpointer = fpointer;
UCSBRobotics 6:4269b879a2af 32 numCommands++;
UCSBRobotics 6:4269b879a2af 33 }
UCSBRobotics 6:4269b879a2af 34 else
UCSBRobotics 6:4269b879a2af 35 {
UCSBRobotics 9:bb92a6ecb668 36 serial.printf("error: too many commands\n");
UCSBRobotics 6:4269b879a2af 37 }
UCSBRobotics 6:4269b879a2af 38 }
UCSBRobotics 6:4269b879a2af 39
UCSBRobotics 6:4269b879a2af 40
UCSBRobotics 6:4269b879a2af 41
UCSBRobotics 6:4269b879a2af 42 void Terminal::terminateCmd()
UCSBRobotics 6:4269b879a2af 43 {
UCSBRobotics 9:bb92a6ecb668 44 // Delete the running command's CmdHandler, if it exists
UCSBRobotics 6:4269b879a2af 45 if (runningCmd != NULL)
UCSBRobotics 6:4269b879a2af 46 {
UCSBRobotics 6:4269b879a2af 47 delete runningCmd;
UCSBRobotics 6:4269b879a2af 48 runningCmd = NULL;
UCSBRobotics 6:4269b879a2af 49 }
UCSBRobotics 6:4269b879a2af 50
UCSBRobotics 6:4269b879a2af 51 serial.printf("\n> ");
UCSBRobotics 9:bb92a6ecb668 52 inputBuffer[0] = '\0'; // Clear the input buffer
UCSBRobotics 6:4269b879a2af 53 }
UCSBRobotics 6:4269b879a2af 54
UCSBRobotics 6:4269b879a2af 55
UCSBRobotics 6:4269b879a2af 56
UCSBRobotics 6:4269b879a2af 57 void Terminal::write(const char* string)
UCSBRobotics 6:4269b879a2af 58 {
UCSBRobotics 9:bb92a6ecb668 59 serial.printf("%s", string);
UCSBRobotics 6:4269b879a2af 60 }
UCSBRobotics 6:4269b879a2af 61
UCSBRobotics 6:4269b879a2af 62
UCSBRobotics 6:4269b879a2af 63
UCSBRobotics 6:4269b879a2af 64 void Terminal::receive()
UCSBRobotics 6:4269b879a2af 65 {
UCSBRobotics 6:4269b879a2af 66 char c = serial.getc();
UCSBRobotics 6:4269b879a2af 67
UCSBRobotics 6:4269b879a2af 68 // Check if a command is currently running
UCSBRobotics 6:4269b879a2af 69 if (runningCmd == NULL) // No command is currently running
UCSBRobotics 6:4269b879a2af 70 {
UCSBRobotics 6:4269b879a2af 71 int len = strlen(inputBuffer);
UCSBRobotics 6:4269b879a2af 72
UCSBRobotics 9:bb92a6ecb668 73 if (isprint(c)) // If c is a printable character
UCSBRobotics 6:4269b879a2af 74 {
UCSBRobotics 6:4269b879a2af 75 if (len < INPUT_BUFFER_MAX - 1)
UCSBRobotics 6:4269b879a2af 76 {
UCSBRobotics 9:bb92a6ecb668 77 // Add the new character to the input buffer and display it
UCSBRobotics 6:4269b879a2af 78 inputBuffer[len] = c;
UCSBRobotics 6:4269b879a2af 79 inputBuffer[len + 1] = '\0';
UCSBRobotics 6:4269b879a2af 80 serial.putc(c);
UCSBRobotics 6:4269b879a2af 81 }
UCSBRobotics 6:4269b879a2af 82 }
UCSBRobotics 9:bb92a6ecb668 83 else if (c == '\b' || c == 127) // Backspace or DEL
UCSBRobotics 6:4269b879a2af 84 {
UCSBRobotics 6:4269b879a2af 85 if (len > 0)
UCSBRobotics 6:4269b879a2af 86 {
UCSBRobotics 6:4269b879a2af 87 inputBuffer[len - 1] = '\0';
UCSBRobotics 6:4269b879a2af 88 serial.printf("\b \b");
UCSBRobotics 6:4269b879a2af 89 }
UCSBRobotics 6:4269b879a2af 90 }
UCSBRobotics 10:ce5816cee1e4 91 else if (c == '\n' || c == '\r') // Execute input command
UCSBRobotics 6:4269b879a2af 92 {
UCSBRobotics 6:4269b879a2af 93 serial.putc('\n');
UCSBRobotics 6:4269b879a2af 94
UCSBRobotics 9:bb92a6ecb668 95 bool matchFound = false; // Initialize flag
UCSBRobotics 6:4269b879a2af 96
UCSBRobotics 9:bb92a6ecb668 97 // Try to match the input string to a command
UCSBRobotics 6:4269b879a2af 98 for (int i = 0; i < NUM_COMMANDS_MAX; i++)
UCSBRobotics 6:4269b879a2af 99 {
UCSBRobotics 6:4269b879a2af 100 if (cmdList[i].stringLength && !strncmp(inputBuffer, cmdList[i].cmdString, cmdList[i].stringLength))
UCSBRobotics 6:4269b879a2af 101 {
UCSBRobotics 9:bb92a6ecb668 102 // Match found, call the associated command
UCSBRobotics 6:4269b879a2af 103 runningCmd = cmdList[i].fpointer(this, inputBuffer);
UCSBRobotics 6:4269b879a2af 104 matchFound = true;
UCSBRobotics 6:4269b879a2af 105 break;
UCSBRobotics 6:4269b879a2af 106 }
UCSBRobotics 6:4269b879a2af 107 }
UCSBRobotics 6:4269b879a2af 108
UCSBRobotics 6:4269b879a2af 109 if (matchFound)
UCSBRobotics 6:4269b879a2af 110 {
UCSBRobotics 6:4269b879a2af 111 // If the command finishes immediately, it should return null instead of a pointer to a CmdHandler
UCSBRobotics 6:4269b879a2af 112 if (runningCmd == NULL)
UCSBRobotics 9:bb92a6ecb668 113 {
UCSBRobotics 9:bb92a6ecb668 114 // Terminate the command here, because there is no CmdHandler to terminate it later
UCSBRobotics 6:4269b879a2af 115 terminateCmd();
UCSBRobotics 9:bb92a6ecb668 116 }
UCSBRobotics 6:4269b879a2af 117 }
UCSBRobotics 6:4269b879a2af 118 else
UCSBRobotics 6:4269b879a2af 119 {
UCSBRobotics 6:4269b879a2af 120 // No match was found
UCSBRobotics 6:4269b879a2af 121 serial.printf("unrecognized command");
UCSBRobotics 10:ce5816cee1e4 122 terminateCmd();
UCSBRobotics 6:4269b879a2af 123 }
UCSBRobotics 6:4269b879a2af 124 }
UCSBRobotics 9:bb92a6ecb668 125 // Control characters other than \n, \b, and 127 (DEL) are ignored
UCSBRobotics 6:4269b879a2af 126 }
UCSBRobotics 6:4269b879a2af 127 else // A command is running, so pass the character to the CmdHandler
UCSBRobotics 6:4269b879a2af 128 {
UCSBRobotics 6:4269b879a2af 129 runningCmd->sendChar(c);
UCSBRobotics 6:4269b879a2af 130 }
UCSBRobotics 0:6b2bae4e0481 131 }