Simple embedded shell with runtime pluggable commands.

Dependents:   DataBus2018

Implements a simple unix-like shell for embedded systems with a pluggable command architecture.

Committer:
shimniok
Date:
Thu Dec 13 09:00:28 2018 +0000
Revision:
11:23f61057d877
Parent:
10:c3faa7ffd23b
Parent:
8:41b7274a9753
Child:
12:ecf3fc049bca
merged

Who changed what in which revision?

UserRevisionLine numberNew contents of line
shimniok 0:49820d5a38c9 1 #include "SimpleShell.h"
shimniok 5:8f486f4d29d3 2 #include <ctype.h>
shimniok 0:49820d5a38c9 3
shimniok 10:c3faa7ffd23b 4 #define ESC 0x1b
shimniok 10:c3faa7ffd23b 5
shimniok 0:49820d5a38c9 6 SimpleShell::SimpleShell()
shimniok 0:49820d5a38c9 7 {
shimniok 2:4f0affdb7db9 8 lookupEnd = 0;
shimniok 8:41b7274a9753 9 // Built-in shell commands
shimniok 8:41b7274a9753 10 attach(callback(this, &SimpleShell::help), "help");
shimniok 8:41b7274a9753 11 // TODO: cd
shimniok 0:49820d5a38c9 12 }
shimniok 0:49820d5a38c9 13
shimniok 8:41b7274a9753 14
shimniok 8:41b7274a9753 15 void SimpleShell::help()
shimniok 8:41b7274a9753 16 {
shimniok 8:41b7274a9753 17 printf("Available commands: ");
shimniok 8:41b7274a9753 18 for (int i=0; i < lookupEnd; i++) {
shimniok 8:41b7274a9753 19 printf("%s ", lookup[i].command);
shimniok 8:41b7274a9753 20 }
shimniok 8:41b7274a9753 21 printf("\n\n");
shimniok 8:41b7274a9753 22 }
shimniok 8:41b7274a9753 23
shimniok 8:41b7274a9753 24
shimniok 0:49820d5a38c9 25 void SimpleShell::run()
shimniok 0:49820d5a38c9 26 {
shimniok 0:49820d5a38c9 27 bool done=false;
shimniok 4:8b8fa59d0015 28 Callback<void()> cb;
shimniok 5:8f486f4d29d3 29 int status; // TODO implement command status return
shimniok 4:8b8fa59d0015 30
shimniok 0:49820d5a38c9 31 strcpy(_cwd, "/log");
shimniok 0:49820d5a38c9 32
shimniok 0:49820d5a38c9 33 printf("Type help for assistance.\n");
shimniok 8:41b7274a9753 34 help();
shimniok 0:49820d5a38c9 35 while (!done) {
shimniok 0:49820d5a38c9 36 printPrompt();
shimniok 0:49820d5a38c9 37 readCommand();
shimniok 5:8f486f4d29d3 38 if (cmd[0]) { // skip blank command
shimniok 5:8f486f4d29d3 39 if (cb = findCommand()) {
shimniok 5:8f486f4d29d3 40 cb.call();
shimniok 5:8f486f4d29d3 41 } else {
shimniok 5:8f486f4d29d3 42 printf("command <%s> not found\n", cmd);
shimniok 5:8f486f4d29d3 43 }
shimniok 4:8b8fa59d0015 44 }
shimniok 0:49820d5a38c9 45 }
shimniok 0:49820d5a38c9 46 puts("exiting shell\n");
shimniok 0:49820d5a38c9 47
shimniok 0:49820d5a38c9 48 return;
shimniok 0:49820d5a38c9 49 }
shimniok 0:49820d5a38c9 50
shimniok 0:49820d5a38c9 51
shimniok 2:4f0affdb7db9 52 void SimpleShell::attach(Callback<void()> cb, char *command)
shimniok 2:4f0affdb7db9 53 {
shimniok 2:4f0affdb7db9 54 if (lookupEnd < MAXLOOKUP) {
shimniok 2:4f0affdb7db9 55 lookup[lookupEnd].cb = cb;
shimniok 2:4f0affdb7db9 56 lookup[lookupEnd].command = command;
shimniok 2:4f0affdb7db9 57 lookupEnd++;
shimniok 2:4f0affdb7db9 58 }
shimniok 2:4f0affdb7db9 59
shimniok 2:4f0affdb7db9 60 return;
shimniok 1:998a7ed04f10 61 }
shimniok 1:998a7ed04f10 62
shimniok 1:998a7ed04f10 63
shimniok 3:ebb4893f033d 64 Callback<void()> SimpleShell::findCommand()
shimniok 3:ebb4893f033d 65 {
shimniok 3:ebb4893f033d 66 Callback<void()> cb=NULL;
shimniok 3:ebb4893f033d 67
shimniok 4:8b8fa59d0015 68 for (int i=0; i < lookupEnd; i++) {
shimniok 4:8b8fa59d0015 69 if (strncmp(cmd, lookup[i].command, MAXBUF) == 0) {
shimniok 4:8b8fa59d0015 70 cb = lookup[i].cb;
shimniok 4:8b8fa59d0015 71 break;
shimniok 4:8b8fa59d0015 72 }
shimniok 4:8b8fa59d0015 73 }
shimniok 4:8b8fa59d0015 74
shimniok 3:ebb4893f033d 75 return cb;
shimniok 3:ebb4893f033d 76 }
shimniok 3:ebb4893f033d 77
shimniok 3:ebb4893f033d 78
shimniok 0:49820d5a38c9 79 void SimpleShell::printPrompt()
shimniok 0:49820d5a38c9 80 {
shimniok 0:49820d5a38c9 81 fputc('(', stdout);
shimniok 0:49820d5a38c9 82 fputs(_cwd, stdout);
shimniok 0:49820d5a38c9 83 fputs(")# ", stdout);
shimniok 2:4f0affdb7db9 84
shimniok 2:4f0affdb7db9 85 return;
shimniok 0:49820d5a38c9 86 }
shimniok 0:49820d5a38c9 87
shimniok 0:49820d5a38c9 88
shimniok 0:49820d5a38c9 89 void SimpleShell::readCommand()
shimniok 0:49820d5a38c9 90 {
shimniok 0:49820d5a38c9 91 int i=0;
shimniok 0:49820d5a38c9 92 char c;
shimniok 0:49820d5a38c9 93 bool done = false;
shimniok 0:49820d5a38c9 94
shimniok 0:49820d5a38c9 95 memset(cmd, 0, MAXBUF);
shimniok 0:49820d5a38c9 96 do {
shimniok 0:49820d5a38c9 97 cmd[i] = 0;
shimniok 0:49820d5a38c9 98 c = fgetc(stdin);
shimniok 0:49820d5a38c9 99 if (c == '\r') { // if return is hit, we're done, don't add \r to cmd
shimniok 0:49820d5a38c9 100 done = true;
shimniok 10:c3faa7ffd23b 101 } else if (c == ESC) { // keyboard escape codes (arrow keys, etc)
shimniok 10:c3faa7ffd23b 102 char c2 = getchar();
shimniok 10:c3faa7ffd23b 103 char c3 = getchar();
shimniok 10:c3faa7ffd23b 104
shimniok 10:c3faa7ffd23b 105 if (c2 == 0x4f && c3 == 0x46) {
shimniok 10:c3faa7ffd23b 106 printf("<END>");
shimniok 10:c3faa7ffd23b 107 } else if (c2 == 0x5b) {
shimniok 10:c3faa7ffd23b 108 switch (c3) {
shimniok 10:c3faa7ffd23b 109 case 0x41 : // up
shimniok 10:c3faa7ffd23b 110 printf("<UP>");
shimniok 10:c3faa7ffd23b 111 break;
shimniok 10:c3faa7ffd23b 112 case 0x42 : // down
shimniok 10:c3faa7ffd23b 113 printf("<DOWN>");
shimniok 10:c3faa7ffd23b 114 break;
shimniok 10:c3faa7ffd23b 115 case 0x43 : // right
shimniok 10:c3faa7ffd23b 116 printf("<RIGHT>");
shimniok 10:c3faa7ffd23b 117 break;
shimniok 10:c3faa7ffd23b 118 case 0x44 : // left
shimniok 10:c3faa7ffd23b 119 printf("<LEFT>");
shimniok 10:c3faa7ffd23b 120 break;
shimniok 10:c3faa7ffd23b 121 case 0x31 : // home
shimniok 10:c3faa7ffd23b 122 case 0x32 : // ins
shimniok 10:c3faa7ffd23b 123 case 0x33: // del
shimniok 10:c3faa7ffd23b 124 case 0x35: // pgup
shimniok 10:c3faa7ffd23b 125 case 0x36: // pgdn
shimniok 10:c3faa7ffd23b 126 char c4 = getchar();
shimniok 10:c3faa7ffd23b 127 if (c4 == 0x7e) {
shimniok 10:c3faa7ffd23b 128 switch (c3) {
shimniok 10:c3faa7ffd23b 129 case 0x31 :
shimniok 10:c3faa7ffd23b 130 printf("<HOME>");
shimniok 10:c3faa7ffd23b 131 break;
shimniok 10:c3faa7ffd23b 132 case 0x32 : // ins
shimniok 10:c3faa7ffd23b 133 printf("<INS>");
shimniok 10:c3faa7ffd23b 134 break;
shimniok 10:c3faa7ffd23b 135 case 0x33: // del
shimniok 10:c3faa7ffd23b 136 printf("<DEL>");
shimniok 10:c3faa7ffd23b 137 break;
shimniok 10:c3faa7ffd23b 138 case 0x35: // pgup
shimniok 10:c3faa7ffd23b 139 printf("<PGUP>");
shimniok 10:c3faa7ffd23b 140 break;
shimniok 10:c3faa7ffd23b 141 case 0x36: // pgdn
shimniok 10:c3faa7ffd23b 142 printf("<PGDN>");
shimniok 10:c3faa7ffd23b 143 break;
shimniok 10:c3faa7ffd23b 144 default:
shimniok 10:c3faa7ffd23b 145 break;
shimniok 10:c3faa7ffd23b 146 }//switch
shimniok 10:c3faa7ffd23b 147 }//if
shimniok 10:c3faa7ffd23b 148 default:
shimniok 10:c3faa7ffd23b 149 //printf("<0x%02x>", c3);
shimniok 10:c3faa7ffd23b 150 break;
shimniok 10:c3faa7ffd23b 151 }//switch
shimniok 10:c3faa7ffd23b 152 }//if
shimniok 10:c3faa7ffd23b 153 //printf("\n");
shimniok 0:49820d5a38c9 154 } else if (i < MAXBUF-1) {
shimniok 0:49820d5a38c9 155 if (c == 0x7f || c == '\b') { // backspace or delete
shimniok 0:49820d5a38c9 156 if (i > 0) { // if we're at the beginning, do nothing
shimniok 0:49820d5a38c9 157 i--;
shimniok 0:49820d5a38c9 158 fputs("\b \b", stdout);
shimniok 0:49820d5a38c9 159 }
shimniok 0:49820d5a38c9 160 } else {
shimniok 10:c3faa7ffd23b 161 if (isprint(c))
shimniok 10:c3faa7ffd23b 162 fputc(c, stdout);
shimniok 0:49820d5a38c9 163 cmd[i++] = c;
shimniok 0:49820d5a38c9 164 }
shimniok 0:49820d5a38c9 165 }
shimniok 10:c3faa7ffd23b 166
shimniok 0:49820d5a38c9 167 } while (!done);
shimniok 0:49820d5a38c9 168 fputc('\n', stdout);
shimniok 0:49820d5a38c9 169
shimniok 5:8f486f4d29d3 170 // chomp
shimniok 5:8f486f4d29d3 171 for (int j=i; j >= 0; j--) {
shimniok 5:8f486f4d29d3 172 if (isspace(cmd[j])) {
shimniok 5:8f486f4d29d3 173 cmd[j] = '\0';
shimniok 5:8f486f4d29d3 174 }
shimniok 5:8f486f4d29d3 175 }
shimniok 5:8f486f4d29d3 176
shimniok 2:4f0affdb7db9 177 return;
shimniok 0:49820d5a38c9 178 }