A UNIX emulation shell to access the underlying SDCard FileSystem through a terminal interface
Information
Dependencies not included with library:
Information
SDShell does not change the com baudrate. Access is made using the baud as initialized by the Serial object when passed into the SDShell object
Example
#include "mbed.h" #include "SDFileSystem.h" #include "SDShell.h" Serial com(USBTX, USBRX); SDFileSystem sd(p11, p12, p13, p14, "sd"); SDShell emulate; int main() { emulate.init(); emulate.shell(com, sd, "/sd"); }
SDShell.cpp@1:514f321aa528, 2013-04-27 (annotated)
- Committer:
- sam_grove
- Date:
- Sat Apr 27 16:08:39 2013 +0000
- Revision:
- 1:514f321aa528
- Parent:
- 0:618e98bf18ce
- Child:
- 2:b3107e463974
partially working implementation - has a bug in parsing come back to later
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
sam_grove | 1:514f321aa528 | 1 | |
sam_grove | 1:514f321aa528 | 2 | //http://mbed.org/users/shimniok/code/SDCardShell/file/792bddcf799d/main.cpp |
sam_grove | 0:618e98bf18ce | 3 | |
sam_grove | 0:618e98bf18ce | 4 | #include "SDShell.h" |
sam_grove | 0:618e98bf18ce | 5 | |
sam_grove | 0:618e98bf18ce | 6 | SDShell::SDShell() |
sam_grove | 0:618e98bf18ce | 7 | { |
sam_grove | 1:514f321aa528 | 8 | _debug = 0; |
sam_grove | 1:514f321aa528 | 9 | |
sam_grove | 0:618e98bf18ce | 10 | return; |
sam_grove | 0:618e98bf18ce | 11 | } |
sam_grove | 0:618e98bf18ce | 12 | |
sam_grove | 0:618e98bf18ce | 13 | void SDShell::init(void) |
sam_grove | 0:618e98bf18ce | 14 | { |
sam_grove | 1:514f321aa528 | 15 | // add known commands to a linked list |
sam_grove | 0:618e98bf18ce | 16 | return; |
sam_grove | 0:618e98bf18ce | 17 | } |
sam_grove | 0:618e98bf18ce | 18 | |
sam_grove | 0:618e98bf18ce | 19 | void SDShell::shell(Serial &com, SDFileSystem &storage, char *cwd) |
sam_grove | 0:618e98bf18ce | 20 | { |
sam_grove | 1:514f321aa528 | 21 | uint32_t done = 0; |
sam_grove | 1:514f321aa528 | 22 | |
sam_grove | 1:514f321aa528 | 23 | // get local copies of the initialized objects |
sam_grove | 0:618e98bf18ce | 24 | _com = &com; |
sam_grove | 1:514f321aa528 | 25 | _storage = &storage; |
sam_grove | 1:514f321aa528 | 26 | |
sam_grove | 1:514f321aa528 | 27 | // put the current working directory to the root of the card - should be pulled in I think |
sam_grove | 1:514f321aa528 | 28 | strcpy(_cwd, "/sd"); |
sam_grove | 1:514f321aa528 | 29 | |
sam_grove | 1:514f321aa528 | 30 | while(0 == done) |
sam_grove | 0:618e98bf18ce | 31 | { |
sam_grove | 1:514f321aa528 | 32 | // gather input from the Serial object |
sam_grove | 1:514f321aa528 | 33 | shellInput(); |
sam_grove | 1:514f321aa528 | 34 | // break up the command line arguemnt |
sam_grove | 1:514f321aa528 | 35 | _arg = split(_cmd, _cmd_line, 64, ' '); |
sam_grove | 1:514f321aa528 | 36 | // look at the arg and get paths and files separated if present |
sam_grove | 1:514f321aa528 | 37 | resolveDirectory(_new_path, _arg); |
sam_grove | 1:514f321aa528 | 38 | if(_debug) |
sam_grove | 1:514f321aa528 | 39 | { |
sam_grove | 1:514f321aa528 | 40 | LOG("cmdline:<%s> cmd:<%s> arg:<%s> newpath:<%s>\n", _cmd_line, _cmd, _arg, _new_path); |
sam_grove | 1:514f321aa528 | 41 | } |
sam_grove | 1:514f321aa528 | 42 | |
sam_grove | 1:514f321aa528 | 43 | if (match(_cmd, "ls")) |
sam_grove | 1:514f321aa528 | 44 | { |
sam_grove | 1:514f321aa528 | 45 | ls(_new_path, _com); |
sam_grove | 1:514f321aa528 | 46 | } |
sam_grove | 1:514f321aa528 | 47 | else if (match(_cmd, "cd")) |
sam_grove | 0:618e98bf18ce | 48 | { |
sam_grove | 1:514f321aa528 | 49 | cd(_new_path); |
sam_grove | 1:514f321aa528 | 50 | } |
sam_grove | 1:514f321aa528 | 51 | else if (match(_cmd, "pwd")) |
sam_grove | 1:514f321aa528 | 52 | { |
sam_grove | 1:514f321aa528 | 53 | pwd(_com); |
sam_grove | 1:514f321aa528 | 54 | } |
sam_grove | 1:514f321aa528 | 55 | else if (match(_cmd, "head")) |
sam_grove | 1:514f321aa528 | 56 | { |
sam_grove | 1:514f321aa528 | 57 | head(_new_path, _com); |
sam_grove | 1:514f321aa528 | 58 | } |
sam_grove | 1:514f321aa528 | 59 | else if (match(_cmd, "cat")) |
sam_grove | 1:514f321aa528 | 60 | { |
sam_grove | 1:514f321aa528 | 61 | cat(_new_path, _com); |
sam_grove | 0:618e98bf18ce | 62 | } |
sam_grove | 1:514f321aa528 | 63 | else if (match(_cmd, "mkdir")) |
sam_grove | 1:514f321aa528 | 64 | { |
sam_grove | 1:514f321aa528 | 65 | mkdir(_new_path, 1023); |
sam_grove | 1:514f321aa528 | 66 | } |
sam_grove | 1:514f321aa528 | 67 | else if (match(_cmd, "debug")) |
sam_grove | 1:514f321aa528 | 68 | { |
sam_grove | 1:514f321aa528 | 69 | _debug = !_debug; |
sam_grove | 1:514f321aa528 | 70 | } |
sam_grove | 1:514f321aa528 | 71 | else if (match(_cmd, "touch")) |
sam_grove | 0:618e98bf18ce | 72 | { |
sam_grove | 1:514f321aa528 | 73 | touch(_new_path, _com); |
sam_grove | 1:514f321aa528 | 74 | } |
sam_grove | 1:514f321aa528 | 75 | else if (match(_cmd, "rm")) |
sam_grove | 1:514f321aa528 | 76 | { |
sam_grove | 1:514f321aa528 | 77 | remove(_new_path); |
sam_grove | 1:514f321aa528 | 78 | } |
sam_grove | 1:514f321aa528 | 79 | else if (match(_cmd, "exit")) |
sam_grove | 1:514f321aa528 | 80 | { |
sam_grove | 1:514f321aa528 | 81 | done = true; |
sam_grove | 0:618e98bf18ce | 82 | } |
sam_grove | 0:618e98bf18ce | 83 | else |
sam_grove | 0:618e98bf18ce | 84 | { |
sam_grove | 1:514f321aa528 | 85 | _com->printf("%s: command not found\n", _cmd); |
sam_grove | 0:618e98bf18ce | 86 | } |
sam_grove | 0:618e98bf18ce | 87 | } |
sam_grove | 1:514f321aa528 | 88 | } |
sam_grove | 0:618e98bf18ce | 89 | |
sam_grove | 1:514f321aa528 | 90 | void SDShell::shellInput(void) |
sam_grove | 0:618e98bf18ce | 91 | { |
sam_grove | 1:514f321aa528 | 92 | int i=0; |
sam_grove | 1:514f321aa528 | 93 | char c; |
sam_grove | 1:514f321aa528 | 94 | uint32_t done = 0; |
sam_grove | 1:514f321aa528 | 95 | // clear the last command |
sam_grove | 1:514f321aa528 | 96 | memset(_cmd, 0, 64); |
sam_grove | 1:514f321aa528 | 97 | _com->printf("# ", _cwd); |
sam_grove | 1:514f321aa528 | 98 | do |
sam_grove | 0:618e98bf18ce | 99 | { |
sam_grove | 1:514f321aa528 | 100 | _cmd[i] = 0; |
sam_grove | 1:514f321aa528 | 101 | c = _com->getc(); |
sam_grove | 1:514f321aa528 | 102 | if (c == '\r') |
sam_grove | 1:514f321aa528 | 103 | { |
sam_grove | 1:514f321aa528 | 104 | done = 1; |
sam_grove | 1:514f321aa528 | 105 | } |
sam_grove | 1:514f321aa528 | 106 | else if (i < SHELL_BUF_MASK) |
sam_grove | 0:618e98bf18ce | 107 | { |
sam_grove | 1:514f321aa528 | 108 | if (c == 0x7f) |
sam_grove | 1:514f321aa528 | 109 | { // backspace |
sam_grove | 1:514f321aa528 | 110 | if (i > 0) |
sam_grove | 1:514f321aa528 | 111 | { // if we're at the beginning, do nothing |
sam_grove | 1:514f321aa528 | 112 | i--; |
sam_grove | 1:514f321aa528 | 113 | _com->printf("\b \b"); |
sam_grove | 1:514f321aa528 | 114 | } |
sam_grove | 1:514f321aa528 | 115 | } |
sam_grove | 1:514f321aa528 | 116 | else |
sam_grove | 1:514f321aa528 | 117 | { |
sam_grove | 1:514f321aa528 | 118 | _com->putc(c); |
sam_grove | 1:514f321aa528 | 119 | _cmd[i++] = c; |
sam_grove | 1:514f321aa528 | 120 | } |
sam_grove | 0:618e98bf18ce | 121 | } |
sam_grove | 1:514f321aa528 | 122 | } while (0 == done); |
sam_grove | 1:514f321aa528 | 123 | |
sam_grove | 1:514f321aa528 | 124 | _com->printf("\n"); |
sam_grove | 0:618e98bf18ce | 125 | } |
sam_grove | 0:618e98bf18ce | 126 | |
sam_grove | 1:514f321aa528 | 127 | char *SDShell::split(char *dst, char *src, int max, char delim) |
sam_grove | 0:618e98bf18ce | 128 | { |
sam_grove | 1:514f321aa528 | 129 | int i = 0; |
sam_grove | 1:514f321aa528 | 130 | char *v; |
sam_grove | 1:514f321aa528 | 131 | |
sam_grove | 1:514f321aa528 | 132 | // make sure pointers are valid (could validate RAM but that should be the caller responsibility) |
sam_grove | 1:514f321aa528 | 133 | if ((src == 0) || (dst == 0)) |
sam_grove | 1:514f321aa528 | 134 | { |
sam_grove | 1:514f321aa528 | 135 | return 0; |
sam_grove | 1:514f321aa528 | 136 | } |
sam_grove | 1:514f321aa528 | 137 | // break up the string |
sam_grove | 1:514f321aa528 | 138 | while((*src != 0) && (*src != delim) && (i < max)) |
sam_grove | 0:618e98bf18ce | 139 | { |
sam_grove | 1:514f321aa528 | 140 | *(dst++) = *(src++); |
sam_grove | 1:514f321aa528 | 141 | i++; |
sam_grove | 1:514f321aa528 | 142 | } |
sam_grove | 1:514f321aa528 | 143 | |
sam_grove | 1:514f321aa528 | 144 | *src = 0; |
sam_grove | 1:514f321aa528 | 145 | v = (*dst == '\0') ? src : (dst+1); |
sam_grove | 1:514f321aa528 | 146 | |
sam_grove | 1:514f321aa528 | 147 | return v; |
sam_grove | 1:514f321aa528 | 148 | } |
sam_grove | 1:514f321aa528 | 149 | |
sam_grove | 1:514f321aa528 | 150 | void SDShell::resolveDirectory(char *newpath, char *path) |
sam_grove | 1:514f321aa528 | 151 | { |
sam_grove | 1:514f321aa528 | 152 | char basename[64], dirname[64]; |
sam_grove | 1:514f321aa528 | 153 | |
sam_grove | 1:514f321aa528 | 154 | // absolute path |
sam_grove | 1:514f321aa528 | 155 | if (path[0] == '/') |
sam_grove | 1:514f321aa528 | 156 | { |
sam_grove | 1:514f321aa528 | 157 | strcpy(newpath, path); |
sam_grove | 1:514f321aa528 | 158 | } |
sam_grove | 1:514f321aa528 | 159 | // relative path |
sam_grove | 1:514f321aa528 | 160 | else |
sam_grove | 1:514f321aa528 | 161 | { |
sam_grove | 1:514f321aa528 | 162 | strcpy(newpath, _cwd); |
sam_grove | 1:514f321aa528 | 163 | // make sure something was passed |
sam_grove | 1:514f321aa528 | 164 | if(path[0] != 0) |
sam_grove | 0:618e98bf18ce | 165 | { |
sam_grove | 1:514f321aa528 | 166 | // add the backslash if the user didnt |
sam_grove | 1:514f321aa528 | 167 | if(newpath[strlen(newpath)-1] != '/') |
sam_grove | 1:514f321aa528 | 168 | { |
sam_grove | 1:514f321aa528 | 169 | strcat(newpath, "/"); |
sam_grove | 1:514f321aa528 | 170 | } |
sam_grove | 1:514f321aa528 | 171 | strcat(newpath, path); |
sam_grove | 0:618e98bf18ce | 172 | } |
sam_grove | 1:514f321aa528 | 173 | // Resolve .. references |
sam_grove | 1:514f321aa528 | 174 | splitName(newpath, dirname, basename); |
sam_grove | 1:514f321aa528 | 175 | if (0 == strcmp(basename, "..")) |
sam_grove | 1:514f321aa528 | 176 | { |
sam_grove | 1:514f321aa528 | 177 | splitName(dirname, newpath, basename); |
sam_grove | 1:514f321aa528 | 178 | } |
sam_grove | 0:618e98bf18ce | 179 | } |
sam_grove | 0:618e98bf18ce | 180 | |
sam_grove | 1:514f321aa528 | 181 | return; |
sam_grove | 0:618e98bf18ce | 182 | } |
sam_grove | 0:618e98bf18ce | 183 | |
sam_grove | 1:514f321aa528 | 184 | void SDShell::splitName(char *path, char *dirname, char *basename) |
sam_grove | 1:514f321aa528 | 185 | { |
sam_grove | 1:514f321aa528 | 186 | int sep = 0; |
sam_grove | 1:514f321aa528 | 187 | |
sam_grove | 1:514f321aa528 | 188 | if (_debug) |
sam_grove | 1:514f321aa528 | 189 | { |
sam_grove | 1:514f321aa528 | 190 | LOG("%d\n", strlen(path)); |
sam_grove | 1:514f321aa528 | 191 | } |
sam_grove | 1:514f321aa528 | 192 | for (int i=strlen(path)-1; i >= 0; i--) |
sam_grove | 1:514f321aa528 | 193 | { |
sam_grove | 1:514f321aa528 | 194 | if (_debug) |
sam_grove | 1:514f321aa528 | 195 | { |
sam_grove | 1:514f321aa528 | 196 | LOG("- %c\n", path[i]); |
sam_grove | 1:514f321aa528 | 197 | } |
sam_grove | 1:514f321aa528 | 198 | sep = i; |
sam_grove | 1:514f321aa528 | 199 | if (path[i] == '/') |
sam_grove | 1:514f321aa528 | 200 | { |
sam_grove | 1:514f321aa528 | 201 | break; |
sam_grove | 1:514f321aa528 | 202 | } |
sam_grove | 1:514f321aa528 | 203 | } |
sam_grove | 1:514f321aa528 | 204 | for (int j=0; j < sep; j++) |
sam_grove | 1:514f321aa528 | 205 | { |
sam_grove | 1:514f321aa528 | 206 | if (_debug) |
sam_grove | 1:514f321aa528 | 207 | { |
sam_grove | 1:514f321aa528 | 208 | LOG("> %c\n", path[j]); |
sam_grove | 1:514f321aa528 | 209 | } |
sam_grove | 1:514f321aa528 | 210 | dirname[j] = path[j]; |
sam_grove | 1:514f321aa528 | 211 | dirname[j+1] = 0; |
sam_grove | 1:514f321aa528 | 212 | } |
sam_grove | 1:514f321aa528 | 213 | for (int k=sep+1; k < strlen(path); k++) |
sam_grove | 1:514f321aa528 | 214 | { |
sam_grove | 1:514f321aa528 | 215 | if (_debug) |
sam_grove | 1:514f321aa528 | 216 | { |
sam_grove | 1:514f321aa528 | 217 | LOG("* %c\n", path[k]); |
sam_grove | 1:514f321aa528 | 218 | } |
sam_grove | 1:514f321aa528 | 219 | basename[k-(sep+1)] = path[k]; |
sam_grove | 1:514f321aa528 | 220 | basename[k-sep] = 0; |
sam_grove | 1:514f321aa528 | 221 | } |
sam_grove | 1:514f321aa528 | 222 | if (_debug) |
sam_grove | 1:514f321aa528 | 223 | { |
sam_grove | 1:514f321aa528 | 224 | LOG("d:<%s> b:<%s>\n", dirname, basename); |
sam_grove | 1:514f321aa528 | 225 | } |
sam_grove | 1:514f321aa528 | 226 | } |
sam_grove | 0:618e98bf18ce | 227 | |
sam_grove | 1:514f321aa528 | 228 | uint32_t SDShell::match(char *arg1, char *arg2) |
sam_grove | 1:514f321aa528 | 229 | { |
sam_grove | 1:514f321aa528 | 230 | return (0 == strcmp(arg1, arg2)) ? 1 : 0; |
sam_grove | 1:514f321aa528 | 231 | } |
sam_grove | 1:514f321aa528 | 232 | |
sam_grove | 1:514f321aa528 | 233 | void SDShell::ls(char *path, Serial *pc) |
sam_grove | 1:514f321aa528 | 234 | { |
sam_grove | 1:514f321aa528 | 235 | if (_debug) pc->printf("%s\n", _cwd); |
sam_grove | 1:514f321aa528 | 236 | DIR *d; |
sam_grove | 1:514f321aa528 | 237 | struct dirent *p; |
sam_grove | 0:618e98bf18ce | 238 | |
sam_grove | 1:514f321aa528 | 239 | if ((d = opendir(path)) != NULL) { |
sam_grove | 1:514f321aa528 | 240 | while ((p = readdir(d)) != NULL) { |
sam_grove | 1:514f321aa528 | 241 | pc->printf(" %s\n", p->d_name); |
sam_grove | 1:514f321aa528 | 242 | } |
sam_grove | 1:514f321aa528 | 243 | closedir(d); |
sam_grove | 1:514f321aa528 | 244 | } else { |
sam_grove | 1:514f321aa528 | 245 | pc->printf("%s: No such directory\n", path); |
sam_grove | 1:514f321aa528 | 246 | } |
sam_grove | 1:514f321aa528 | 247 | } |
sam_grove | 1:514f321aa528 | 248 | |
sam_grove | 1:514f321aa528 | 249 | void SDShell::cd(char *path) |
sam_grove | 1:514f321aa528 | 250 | { |
sam_grove | 1:514f321aa528 | 251 | strcpy(_cwd, path); |
sam_grove | 1:514f321aa528 | 252 | } |
sam_grove | 1:514f321aa528 | 253 | |
sam_grove | 1:514f321aa528 | 254 | void SDShell::pwd(Serial *pc) |
sam_grove | 1:514f321aa528 | 255 | { |
sam_grove | 1:514f321aa528 | 256 | pc->printf("%s\n", _cwd); |
sam_grove | 1:514f321aa528 | 257 | } |
sam_grove | 1:514f321aa528 | 258 | |
sam_grove | 1:514f321aa528 | 259 | void SDShell::head(char *path, Serial *pc) |
sam_grove | 1:514f321aa528 | 260 | { |
sam_grove | 1:514f321aa528 | 261 | FILE *fp; |
sam_grove | 1:514f321aa528 | 262 | char line = 0; |
sam_grove | 0:618e98bf18ce | 263 | |
sam_grove | 1:514f321aa528 | 264 | if ((fp = fopen(path, "r")) != NULL) { |
sam_grove | 1:514f321aa528 | 265 | while (!feof(fp) && line++ < 10) { |
sam_grove | 1:514f321aa528 | 266 | fgets(_buf, 128, fp); |
sam_grove | 1:514f321aa528 | 267 | pc->printf("%s", _buf); |
sam_grove | 1:514f321aa528 | 268 | } |
sam_grove | 1:514f321aa528 | 269 | fclose(fp); |
sam_grove | 1:514f321aa528 | 270 | } else { |
sam_grove | 1:514f321aa528 | 271 | pc->printf("%s: No such file\n", path); |
sam_grove | 1:514f321aa528 | 272 | } |
sam_grove | 1:514f321aa528 | 273 | } |
sam_grove | 0:618e98bf18ce | 274 | |
sam_grove | 1:514f321aa528 | 275 | void SDShell::cat(char *path, Serial *pc) |
sam_grove | 1:514f321aa528 | 276 | { |
sam_grove | 1:514f321aa528 | 277 | FILE *fp; |
sam_grove | 0:618e98bf18ce | 278 | |
sam_grove | 1:514f321aa528 | 279 | if ((fp = fopen(path, "r")) != NULL) { |
sam_grove | 1:514f321aa528 | 280 | while (!feof(fp)) { |
sam_grove | 1:514f321aa528 | 281 | fgets(_buf, 128, fp); |
sam_grove | 1:514f321aa528 | 282 | pc->printf("%s", _buf); |
sam_grove | 1:514f321aa528 | 283 | } |
sam_grove | 1:514f321aa528 | 284 | fclose(fp); |
sam_grove | 1:514f321aa528 | 285 | } else { |
sam_grove | 1:514f321aa528 | 286 | pc->printf("%s: No such file\n", path); |
sam_grove | 1:514f321aa528 | 287 | } |
sam_grove | 1:514f321aa528 | 288 | } |
sam_grove | 1:514f321aa528 | 289 | |
sam_grove | 1:514f321aa528 | 290 | void SDShell::touch(char *path, Serial *pc) |
sam_grove | 1:514f321aa528 | 291 | { |
sam_grove | 1:514f321aa528 | 292 | FILE *fp; |
sam_grove | 1:514f321aa528 | 293 | if ((fp = fopen(path, "w")) != NULL) { |
sam_grove | 1:514f321aa528 | 294 | fclose(fp); |
sam_grove | 1:514f321aa528 | 295 | } else { |
sam_grove | 1:514f321aa528 | 296 | pc->printf("%s: No such file\n", path); |
sam_grove | 1:514f321aa528 | 297 | } |
sam_grove | 1:514f321aa528 | 298 | } |
sam_grove | 1:514f321aa528 | 299 |