Test serial console demonstrating various API functions of WiConnect library.

Dependencies:   WiConnect mbed

Committer:
dan_ackme
Date:
Thu Nov 27 10:26:58 2014 +0000
Revision:
25:c8ca04ebbb96
Parent:
12:3dd3a1be40c1
updated for latest wiconnect

Who changed what in which revision?

UserRevisionLine numberNew contents of line
dan_ackme 12:3dd3a1be40c1 1 /**
dan_ackme 12:3dd3a1be40c1 2 * ACKme WiConnect Host Library is licensed under the BSD licence:
dan_ackme 12:3dd3a1be40c1 3 *
dan_ackme 12:3dd3a1be40c1 4 * Copyright (c)2014 ACKme Networks.
dan_ackme 12:3dd3a1be40c1 5 * All rights reserved.
dan_ackme 12:3dd3a1be40c1 6 *
dan_ackme 12:3dd3a1be40c1 7 * Redistribution and use in source and binary forms, with or without modification,
dan_ackme 12:3dd3a1be40c1 8 * are permitted provided that the following conditions are met:
dan_ackme 12:3dd3a1be40c1 9 *
dan_ackme 12:3dd3a1be40c1 10 * 1. Redistributions of source code must retain the above copyright notice,
dan_ackme 12:3dd3a1be40c1 11 * this list of conditions and the following disclaimer.
dan_ackme 12:3dd3a1be40c1 12 * 2. Redistributions in binary form must reproduce the above copyright notice,
dan_ackme 12:3dd3a1be40c1 13 * this list of conditions and the following disclaimer in the documentation
dan_ackme 12:3dd3a1be40c1 14 * and/or other materials provided with the distribution.
dan_ackme 12:3dd3a1be40c1 15 * 3. The name of the author may not be used to endorse or promote products
dan_ackme 12:3dd3a1be40c1 16 * derived from this software without specific prior written permission.
dan_ackme 12:3dd3a1be40c1 17 *
dan_ackme 12:3dd3a1be40c1 18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS AND ANY EXPRESS OR IMPLIED
dan_ackme 12:3dd3a1be40c1 19 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
dan_ackme 12:3dd3a1be40c1 20 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
dan_ackme 12:3dd3a1be40c1 21 * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
dan_ackme 12:3dd3a1be40c1 22 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
dan_ackme 12:3dd3a1be40c1 23 * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
dan_ackme 12:3dd3a1be40c1 24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
dan_ackme 12:3dd3a1be40c1 25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
dan_ackme 12:3dd3a1be40c1 26 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
dan_ackme 12:3dd3a1be40c1 27 * OF SUCH DAMAGE.
dan_ackme 0:836c9a6383e0 28 */
dan_ackme 0:836c9a6383e0 29 #pragma once
dan_ackme 0:836c9a6383e0 30
dan_ackme 0:836c9a6383e0 31 #include <ctype.h>
dan_ackme 0:836c9a6383e0 32
dan_ackme 0:836c9a6383e0 33 #include "Wiconnect.h"
dan_ackme 0:836c9a6383e0 34 #include "Console.h"
dan_ackme 0:836c9a6383e0 35 #include "StringUtil.h"
dan_ackme 0:836c9a6383e0 36 #include "util/log/log.h"
dan_ackme 0:836c9a6383e0 37
dan_ackme 0:836c9a6383e0 38
dan_ackme 0:836c9a6383e0 39
dan_ackme 0:836c9a6383e0 40 #define ADD_HEADER(header) { header, NULL, NULL, NULL}
dan_ackme 0:836c9a6383e0 41 #define ADD_CMD(key, func, desc, ext) { key, func ## Command, desc, ext }
dan_ackme 0:836c9a6383e0 42 #define CMD_LIST_TERMINATOR { NULL, NULL, NULL, NULL }
dan_ackme 0:836c9a6383e0 43 #define CMD_HELP_ENTRY { "?", NULL, "Print list of commands. Add '-v' option to print verbosely", NULL }, \
dan_ackme 0:836c9a6383e0 44 { "help", NULL, "Print list of commands. Add '-v' option to print verbosely", NULL }
dan_ackme 0:836c9a6383e0 45
dan_ackme 0:836c9a6383e0 46 typedef WiconnectResult (*CommandProcessorFunc)(int, char**);
dan_ackme 0:836c9a6383e0 47
dan_ackme 0:836c9a6383e0 48 typedef struct
dan_ackme 0:836c9a6383e0 49 {
dan_ackme 0:836c9a6383e0 50 const char *key;
dan_ackme 0:836c9a6383e0 51 CommandProcessorFunc func;
dan_ackme 0:836c9a6383e0 52 const char *desc;
dan_ackme 0:836c9a6383e0 53 const char *extendedDesc;
dan_ackme 0:836c9a6383e0 54 } CommandListEntry;
dan_ackme 0:836c9a6383e0 55
dan_ackme 0:836c9a6383e0 56
dan_ackme 0:836c9a6383e0 57 /*************************************************************************************************/
dan_ackme 0:836c9a6383e0 58 class Command
dan_ackme 0:836c9a6383e0 59 {
dan_ackme 0:836c9a6383e0 60 public:
dan_ackme 0:836c9a6383e0 61 Command()
dan_ackme 0:836c9a6383e0 62 {
dan_ackme 0:836c9a6383e0 63 argc = -1;
dan_ackme 0:836c9a6383e0 64 func = NULL;
dan_ackme 0:836c9a6383e0 65 }
dan_ackme 0:836c9a6383e0 66
dan_ackme 0:836c9a6383e0 67 void init(int argc_, CommandProcessorFunc func_)
dan_ackme 0:836c9a6383e0 68 {
dan_ackme 0:836c9a6383e0 69 argc = argc_;
dan_ackme 0:836c9a6383e0 70 func = func_;
dan_ackme 0:836c9a6383e0 71 }
dan_ackme 0:836c9a6383e0 72
dan_ackme 0:836c9a6383e0 73 char** getArgvBuffer()
dan_ackme 0:836c9a6383e0 74 {
dan_ackme 0:836c9a6383e0 75 return argv;
dan_ackme 0:836c9a6383e0 76 }
dan_ackme 0:836c9a6383e0 77
dan_ackme 0:836c9a6383e0 78 WiconnectResult execute()
dan_ackme 0:836c9a6383e0 79 {
dan_ackme 0:836c9a6383e0 80 return func(argc, argv);
dan_ackme 0:836c9a6383e0 81 }
dan_ackme 0:836c9a6383e0 82
dan_ackme 0:836c9a6383e0 83 private:
dan_ackme 0:836c9a6383e0 84 int argc;
dan_ackme 0:836c9a6383e0 85 char *argv[DEFAULT_COMMAND_MAX_ARGV];
dan_ackme 0:836c9a6383e0 86 CommandProcessorFunc func;
dan_ackme 0:836c9a6383e0 87 };
dan_ackme 0:836c9a6383e0 88
dan_ackme 0:836c9a6383e0 89
dan_ackme 0:836c9a6383e0 90
dan_ackme 0:836c9a6383e0 91 /*************************************************************************************************/
dan_ackme 0:836c9a6383e0 92 class CommandProcessor
dan_ackme 0:836c9a6383e0 93 {
dan_ackme 0:836c9a6383e0 94 private:
dan_ackme 0:836c9a6383e0 95 const CommandListEntry *commandList;
dan_ackme 0:836c9a6383e0 96 Console console;
dan_ackme 0:836c9a6383e0 97 ConsoleSerial *serial;
dan_ackme 0:836c9a6383e0 98 int commandListSize;
dan_ackme 0:836c9a6383e0 99
dan_ackme 0:836c9a6383e0 100 public:
dan_ackme 0:836c9a6383e0 101 /*************************************************************************************************/
dan_ackme 0:836c9a6383e0 102 CommandProcessor(ConsoleSerial *serial_, const CommandListEntry *commandList_) :
dan_ackme 0:836c9a6383e0 103 commandList(commandList_), console(serial_), serial(serial_), commandListSize(0)
dan_ackme 0:836c9a6383e0 104 {
dan_ackme 0:836c9a6383e0 105 for(const CommandListEntry *cmd = commandList; cmd->key != NULL; ++cmd)
dan_ackme 0:836c9a6383e0 106 {
dan_ackme 0:836c9a6383e0 107 ++commandListSize;
dan_ackme 0:836c9a6383e0 108 }
dan_ackme 0:836c9a6383e0 109 }
dan_ackme 0:836c9a6383e0 110
dan_ackme 0:836c9a6383e0 111 /*************************************************************************************************/
dan_ackme 0:836c9a6383e0 112 ~CommandProcessor()
dan_ackme 0:836c9a6383e0 113 {
dan_ackme 0:836c9a6383e0 114 }
dan_ackme 0:836c9a6383e0 115
dan_ackme 0:836c9a6383e0 116 /*************************************************************************************************/
dan_ackme 0:836c9a6383e0 117 void waitForCommand(Command *cmdPtr)
dan_ackme 0:836c9a6383e0 118 {
dan_ackme 0:836c9a6383e0 119 for(;;)
dan_ackme 0:836c9a6383e0 120 {
dan_ackme 0:836c9a6383e0 121 char *line;
dan_ackme 0:836c9a6383e0 122 char **argv;
dan_ackme 0:836c9a6383e0 123 intmax_t index;
dan_ackme 0:836c9a6383e0 124 int lineLength;
dan_ackme 0:836c9a6383e0 125 const CommandListEntry *foundCmd = NULL;
dan_ackme 0:836c9a6383e0 126
dan_ackme 0:836c9a6383e0 127 console.readLine(&line, &lineLength);
dan_ackme 0:836c9a6383e0 128
dan_ackme 0:836c9a6383e0 129 if(lineLength == 0)
dan_ackme 0:836c9a6383e0 130 {
dan_ackme 0:836c9a6383e0 131 continue;
dan_ackme 0:836c9a6383e0 132 }
dan_ackme 0:836c9a6383e0 133
dan_ackme 0:836c9a6383e0 134 argv = cmdPtr->getArgvBuffer();
dan_ackme 0:836c9a6383e0 135 int argc = parseArgs(line, DEFAULT_COMMAND_MAX_ARGV, argv);
dan_ackme 0:836c9a6383e0 136 if(argc == -1)
dan_ackme 0:836c9a6383e0 137 {
dan_ackme 0:836c9a6383e0 138 LOG_ERROR("Failed to parse commandline");
dan_ackme 0:836c9a6383e0 139 continue;
dan_ackme 0:836c9a6383e0 140 }
dan_ackme 0:836c9a6383e0 141
dan_ackme 0:836c9a6383e0 142 if(argv[0][0] == '?' || strcmp(argv[0], "help") == 0)
dan_ackme 0:836c9a6383e0 143 {
dan_ackme 0:836c9a6383e0 144 bool verbose = (argc > 1 && argv[1][0] == '-' && argv[1][1] == 'v');
dan_ackme 0:836c9a6383e0 145 printHelp(verbose);
dan_ackme 0:836c9a6383e0 146 continue;
dan_ackme 0:836c9a6383e0 147 }
dan_ackme 0:836c9a6383e0 148
dan_ackme 0:836c9a6383e0 149 for(const CommandListEntry *cmd = commandList; cmd->key != NULL; ++cmd)
dan_ackme 0:836c9a6383e0 150 {
dan_ackme 0:836c9a6383e0 151 if(cmd->desc != NULL && strcmp(cmd->key, argv[0]) == 0)
dan_ackme 0:836c9a6383e0 152 {
dan_ackme 0:836c9a6383e0 153 foundCmd = cmd;
dan_ackme 0:836c9a6383e0 154 break;
dan_ackme 0:836c9a6383e0 155 }
dan_ackme 0:836c9a6383e0 156 }
dan_ackme 0:836c9a6383e0 157
dan_ackme 0:836c9a6383e0 158 if(foundCmd == NULL)
dan_ackme 0:836c9a6383e0 159 {
dan_ackme 0:836c9a6383e0 160 if(StringUtil::parseInt(argv[0], &index, 0, commandListSize))
dan_ackme 0:836c9a6383e0 161 {
dan_ackme 0:836c9a6383e0 162 foundCmd = &commandList[(int)index];
dan_ackme 0:836c9a6383e0 163 }
dan_ackme 0:836c9a6383e0 164 else
dan_ackme 0:836c9a6383e0 165 {
dan_ackme 0:836c9a6383e0 166 LOG_ERROR("Unknown command. Enter: 'help' to list available commands");
dan_ackme 0:836c9a6383e0 167 continue;
dan_ackme 0:836c9a6383e0 168 }
dan_ackme 0:836c9a6383e0 169 }
dan_ackme 0:836c9a6383e0 170
dan_ackme 0:836c9a6383e0 171 --argc;
dan_ackme 0:836c9a6383e0 172 memmove(argv, &argv[1], sizeof(char*)*argc);
dan_ackme 0:836c9a6383e0 173
dan_ackme 0:836c9a6383e0 174 if(argc == 1 && (argv[0][0] == '?' || (strstr(argv[0], "help") != NULL)))
dan_ackme 0:836c9a6383e0 175 {
dan_ackme 0:836c9a6383e0 176 printCommandHelp(foundCmd, true, -1);
dan_ackme 0:836c9a6383e0 177 continue;
dan_ackme 0:836c9a6383e0 178 }
dan_ackme 0:836c9a6383e0 179 else
dan_ackme 0:836c9a6383e0 180 {
dan_ackme 0:836c9a6383e0 181 cmdPtr->init(argc, foundCmd->func);
dan_ackme 0:836c9a6383e0 182 }
dan_ackme 0:836c9a6383e0 183 break;
dan_ackme 0:836c9a6383e0 184 }
dan_ackme 0:836c9a6383e0 185 }
dan_ackme 0:836c9a6383e0 186
dan_ackme 0:836c9a6383e0 187 protected:
dan_ackme 0:836c9a6383e0 188
dan_ackme 0:836c9a6383e0 189 /*************************************************************************************************/
dan_ackme 0:836c9a6383e0 190 void printHelp(bool verbose)
dan_ackme 0:836c9a6383e0 191 {
dan_ackme 0:836c9a6383e0 192 int i = 0;
dan_ackme 0:836c9a6383e0 193 for(const CommandListEntry *cmd = commandList; cmd->key != NULL; ++cmd, ++i)
dan_ackme 0:836c9a6383e0 194 {
dan_ackme 0:836c9a6383e0 195 if(cmd->desc == NULL)
dan_ackme 0:836c9a6383e0 196 {
dan_ackme 0:836c9a6383e0 197 --i;
dan_ackme 0:836c9a6383e0 198 serial->printf("\r\n--------------------------------\r\n"
dan_ackme 0:836c9a6383e0 199 "%s\r\n", cmd->key);
dan_ackme 0:836c9a6383e0 200 continue;
dan_ackme 0:836c9a6383e0 201 }
dan_ackme 0:836c9a6383e0 202 printCommandHelp(cmd, verbose, i);
dan_ackme 0:836c9a6383e0 203 }
dan_ackme 0:836c9a6383e0 204 }
dan_ackme 0:836c9a6383e0 205
dan_ackme 0:836c9a6383e0 206
dan_ackme 0:836c9a6383e0 207 /*************************************************************************************************/
dan_ackme 0:836c9a6383e0 208 void printCommandHelp(const CommandListEntry *cmd, bool verbose, int i)
dan_ackme 0:836c9a6383e0 209 {
dan_ackme 0:836c9a6383e0 210 if(i != -1)
dan_ackme 0:836c9a6383e0 211 serial->printf("%2d: %10s : %s\r\n", i, cmd->key, cmd->desc);
dan_ackme 0:836c9a6383e0 212 else
dan_ackme 0:836c9a6383e0 213 serial->printf(" %10s : %s\r\n", cmd->key, cmd->desc);
dan_ackme 0:836c9a6383e0 214
dan_ackme 0:836c9a6383e0 215 if(verbose)
dan_ackme 0:836c9a6383e0 216 {
dan_ackme 0:836c9a6383e0 217 if(cmd->extendedDesc != NULL)
dan_ackme 0:836c9a6383e0 218 {
dan_ackme 0:836c9a6383e0 219 const char *newline, *ptr = cmd->extendedDesc;
dan_ackme 0:836c9a6383e0 220
dan_ackme 0:836c9a6383e0 221 print_extended_help:
dan_ackme 0:836c9a6383e0 222 paddHelpSpaces();
dan_ackme 0:836c9a6383e0 223 newline = strchr(ptr, '\n');
dan_ackme 0:836c9a6383e0 224 if(newline == NULL)
dan_ackme 0:836c9a6383e0 225 {
dan_ackme 0:836c9a6383e0 226 puts(ptr);
dan_ackme 0:836c9a6383e0 227 return;
dan_ackme 0:836c9a6383e0 228 }
dan_ackme 0:836c9a6383e0 229 else
dan_ackme 0:836c9a6383e0 230 {
dan_ackme 0:836c9a6383e0 231 while(ptr < newline)
dan_ackme 0:836c9a6383e0 232 serial->write(*ptr++);
dan_ackme 0:836c9a6383e0 233 serial->write('\r');
dan_ackme 0:836c9a6383e0 234 serial->write('\n');
dan_ackme 0:836c9a6383e0 235 ++ptr;
dan_ackme 0:836c9a6383e0 236 goto print_extended_help;
dan_ackme 0:836c9a6383e0 237 }
dan_ackme 0:836c9a6383e0 238 }
dan_ackme 0:836c9a6383e0 239 }
dan_ackme 0:836c9a6383e0 240 }
dan_ackme 0:836c9a6383e0 241
dan_ackme 0:836c9a6383e0 242 /*************************************************************************************************/
dan_ackme 0:836c9a6383e0 243 void paddHelpSpaces()
dan_ackme 0:836c9a6383e0 244 {
dan_ackme 0:836c9a6383e0 245 int spaces = 17;
dan_ackme 0:836c9a6383e0 246 while(spaces--)
dan_ackme 0:836c9a6383e0 247 serial->write(' ');
dan_ackme 0:836c9a6383e0 248 }
dan_ackme 0:836c9a6383e0 249
dan_ackme 0:836c9a6383e0 250
dan_ackme 0:836c9a6383e0 251 /*************************************************************************************************/
dan_ackme 0:836c9a6383e0 252 int parseArgs(char *line, int max_argc, char **argv)
dan_ackme 0:836c9a6383e0 253 {
dan_ackme 0:836c9a6383e0 254 // TODO: \x00 style escaping
dan_ackme 0:836c9a6383e0 255 char *p;
dan_ackme 0:836c9a6383e0 256 unsigned char c;
dan_ackme 0:836c9a6383e0 257 int argc = 0;
dan_ackme 0:836c9a6383e0 258 char *tokenstart = NULL;
dan_ackme 0:836c9a6383e0 259 enum states
dan_ackme 0:836c9a6383e0 260 {
dan_ackme 0:836c9a6383e0 261 INITIAL,
dan_ackme 0:836c9a6383e0 262 WORD,
dan_ackme 0:836c9a6383e0 263 STRING
dan_ackme 0:836c9a6383e0 264 } state = INITIAL;
dan_ackme 0:836c9a6383e0 265
dan_ackme 0:836c9a6383e0 266 for (p = line; *p != '\0'; p++)
dan_ackme 0:836c9a6383e0 267 {
dan_ackme 0:836c9a6383e0 268 c = (unsigned char) * p;
dan_ackme 0:836c9a6383e0 269 /* One less because word at end-of-line case increments again */
dan_ackme 0:836c9a6383e0 270 if (argc >= max_argc - 1)
dan_ackme 0:836c9a6383e0 271 {
dan_ackme 0:836c9a6383e0 272 return argc;
dan_ackme 0:836c9a6383e0 273 }
dan_ackme 0:836c9a6383e0 274 switch (state)
dan_ackme 0:836c9a6383e0 275 {
dan_ackme 0:836c9a6383e0 276 case INITIAL:
dan_ackme 0:836c9a6383e0 277 if (isspace(c))
dan_ackme 0:836c9a6383e0 278 {
dan_ackme 0:836c9a6383e0 279 continue;
dan_ackme 0:836c9a6383e0 280 }
dan_ackme 0:836c9a6383e0 281 if (c == '"')
dan_ackme 0:836c9a6383e0 282 {
dan_ackme 0:836c9a6383e0 283 state = STRING;
dan_ackme 0:836c9a6383e0 284 tokenstart = p + 1;
dan_ackme 0:836c9a6383e0 285 continue;
dan_ackme 0:836c9a6383e0 286 }
dan_ackme 0:836c9a6383e0 287 tokenstart = p;
dan_ackme 0:836c9a6383e0 288 state = WORD;
dan_ackme 0:836c9a6383e0 289 continue;
dan_ackme 0:836c9a6383e0 290 case STRING:
dan_ackme 0:836c9a6383e0 291 if (c == '"')
dan_ackme 0:836c9a6383e0 292 {
dan_ackme 0:836c9a6383e0 293 state = INITIAL;
dan_ackme 0:836c9a6383e0 294 *p = 0;
dan_ackme 0:836c9a6383e0 295 argv[argc++] = tokenstart;
dan_ackme 0:836c9a6383e0 296 }
dan_ackme 0:836c9a6383e0 297 continue;
dan_ackme 0:836c9a6383e0 298 case WORD:
dan_ackme 0:836c9a6383e0 299 if (c == '"')
dan_ackme 0:836c9a6383e0 300 {
dan_ackme 0:836c9a6383e0 301 state = STRING;
dan_ackme 0:836c9a6383e0 302 *p = 0;
dan_ackme 0:836c9a6383e0 303 argv[argc++] = tokenstart;
dan_ackme 0:836c9a6383e0 304 tokenstart = p + 1;
dan_ackme 0:836c9a6383e0 305 }
dan_ackme 0:836c9a6383e0 306 else if (isspace(c))
dan_ackme 0:836c9a6383e0 307 {
dan_ackme 0:836c9a6383e0 308 state = INITIAL;
dan_ackme 0:836c9a6383e0 309 *p = 0;
dan_ackme 0:836c9a6383e0 310 argv[argc++] = tokenstart;
dan_ackme 0:836c9a6383e0 311 }
dan_ackme 0:836c9a6383e0 312 continue;
dan_ackme 0:836c9a6383e0 313 }
dan_ackme 0:836c9a6383e0 314 }
dan_ackme 0:836c9a6383e0 315 if (state == WORD)
dan_ackme 0:836c9a6383e0 316 {
dan_ackme 0:836c9a6383e0 317 *p = 0;
dan_ackme 0:836c9a6383e0 318 argv[argc++] = tokenstart;
dan_ackme 0:836c9a6383e0 319 argv[argc] = NULL;
dan_ackme 0:836c9a6383e0 320 }
dan_ackme 0:836c9a6383e0 321 else if (state == STRING)
dan_ackme 0:836c9a6383e0 322 {
dan_ackme 0:836c9a6383e0 323 argc = -1; /* Unterminated string */
dan_ackme 0:836c9a6383e0 324 }
dan_ackme 0:836c9a6383e0 325 else
dan_ackme 0:836c9a6383e0 326 {
dan_ackme 0:836c9a6383e0 327 argv[argc] = NULL;
dan_ackme 0:836c9a6383e0 328 }
dan_ackme 0:836c9a6383e0 329
dan_ackme 0:836c9a6383e0 330 return argc;
dan_ackme 0:836c9a6383e0 331 }
dan_ackme 0:836c9a6383e0 332
dan_ackme 0:836c9a6383e0 333 };