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.
Terminal.cpp@13:0dddfc8bce8d, 2012-10-09 (annotated)
- 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?
User | Revision | Line number | New 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 | } |