-
Notifications
You must be signed in to change notification settings - Fork 0
/
commands.c
358 lines (336 loc) · 11.5 KB
/
commands.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
/**
* @file commands.c
* Implements CLI command handlers.
*/
#include <string.h>
/* TI-RTOS Header files */
#include <ti/drivers/GPIO.h>
#include <ti/drivers/UART.h>
#include "cli.h"
#include "sd_card.h"
#include "uart_logger_task.h"
/* Board-specific functions */
#include "Board.h"
typedef struct {
char *cmd_name;
int (*cmd_fxn)(CLIContext *, char **, int);
char *cmd_help;
} CmdEntry;
/*
* Maximum number of arguments that the parser will handle.
* Includes command name.
*/
#define MAX_ARGC 8
/*
* Delimiter used for parsing arguments.
* Add any other delimeters to this string.
*/
#define DELIMETER " "
static int help(CLIContext *ctx, char **argv, int argc);
static int mount(CLIContext *ctx, char **argv, int argc);
static int unmount(CLIContext *ctx, char **argv, int argc);
static int sdstatus(CLIContext *ctx, char **argv, int argc);
static int sdpwr(CLIContext *ctx, char **argv, int argc);
static int sdwrite(CLIContext *ctx, char **argv, int argc);
static int logfile_size(CLIContext *ctx, char **argv, int argc);
static int connect_log(CLIContext *ctx, char **argv, int argc);
static int disconnect_log(CLIContext *ctx, char **argv, int argc);
static int realtime_terminal(CLIContext *ctx, char **argv, int argc);
static int write_ts(CLIContext *ctx, char **argv, int argc);
/**
* Declaration of commands. Syntax is as follows:
* {"NAME_OF_COMMAND", command_function, "HELP_STRING"}
* The command function follows the signature of "main", but with a
* Context Parameter, ex:
* int command_function(CLIContext *ctx, char** argv, int argc)
* A return value of zero indicates success, anything else indicates failure.
*/
const CmdEntry COMMANDS[] = {
{"help", help,
"Prints help for this commandline.\r\n"
"supply the name of a command after \"help\" for help with that command"},
{"mount", mount,
"Mounts the SD card. Powering on the SD card slot before inserting the "
"card may be required."},
{"unmount", unmount, "Unmounts the SD card"},
{"sdstatus", sdstatus, "Gets the mount and power status of the SD card"},
{"sdpwr", sdpwr,
"Sets the power status of SD card: \"sdpwr on\" or \"sdpwr off\""},
{"write_sd", sdwrite, "Writes provided string to the SD card"},
{"filesize", logfile_size, "Gets the size of the log file in bytes"},
{"write_timestamp", write_ts, "Writes a timestamp to the SD card log"},
{"connect_log", connect_log, "Connects to the UART console being logged"},
{"disconnect_log", disconnect_log,
"Disconnects from the UART console being logged"},
{"rtt", realtime_terminal,
"Opens a 2 way connection to the UART console being logged"},
// Add more entries here.
{NULL, NULL, NULL}};
/**
* Handles a command, as given by the null terminated string "cmd"
* @param ctx: CLI context to print to.
* @param cmd: command string to handle.
* @return 0 on successful handling, or another value on failure.
*/
int handle_command(CLIContext *ctx, char *cmd) {
const CmdEntry *entry;
int argc;
char *arguments[MAX_ARGC], *saveptr, cmd_buf[CLI_MAX_LINE + 1];
strncpy(cmd_buf, cmd, CLI_MAX_LINE);
// The parser interprets a space as a delimeter between arguments.
// Init strtok_r.
arguments[0] = strtok_r(cmd_buf, DELIMETER, &saveptr);
// Parse the rest of the arguments.
for (argc = 1; argc < MAX_ARGC; argc++) {
arguments[argc] = strtok_r(NULL, DELIMETER, &saveptr);
if (arguments[argc] == NULL) {
// Out of args to parse, break.
break;
}
}
// Now, find the command to run.
entry = COMMANDS;
while (entry->cmd_name != NULL) {
if (strncmp(entry->cmd_name, arguments[0], CLI_MAX_LINE) == 0) {
return entry->cmd_fxn(ctx, arguments, argc);
}
entry++;
}
// If we exit the loop, we don't recognize this command.
cli_printf(ctx, "Warning: unknown command. Try \"help\". \r\n");
return 0;
}
/**
* Help function. Prints avaliable commandline targets.
* @param argv: list of all string arguments given (first will be "help")
* @param argc: length of the argv array.
*/
static int help(CLIContext *ctx, char **argv, int argc) {
const CmdEntry *entry = COMMANDS;
if (argc == 1) {
cli_printf(ctx, "Avaliable Commands:\r\n");
while (entry->cmd_name != NULL) {
// Write command name and newline
cli_printf(ctx, "%s\r\n", entry->cmd_name);
entry++;
}
return 0;
} else if (argc == 2) {
while (entry->cmd_name != NULL) {
if (strncmp(entry->cmd_name, argv[1], CLI_MAX_LINE) == 0) {
// Print help for this command.
cli_printf(ctx, "%s: %s\r\n", entry->cmd_name, entry->cmd_help);
return 0;
}
entry++;
}
// If we make it here, the command name was unknown.
cli_printf(ctx, "Unknown command: %s\r\n", argv[1]);
return 255;
}
// If neither of the above conditions are triggered, print error.
cli_printf(ctx, "Unsupported number of arguments\r\n");
return 255;
}
/**
* Attempts to mount the SD card.
* @param ctx: CLI context to print to
* @param argv list of arguments
* @param argc argument count
* @return 0 on success, or another value on failure
*/
static int mount(CLIContext *ctx, char **argv, int argc) {
if (argc != 1) {
cli_printf(ctx, "Unexpected arguments!\r\n");
return 255;
}
if (sd_card_mounted()) {
cli_printf(ctx, "SD card is already mounted\r\n");
return 0;
}
cli_printf(ctx, "Attempting to mount sdcard...");
if (attempt_sd_mount()) {
cli_printf(ctx, "Success\r\n");
return 0;
} else {
cli_printf(ctx, "Failed\r\n");
return 255;
}
}
/**
* Attempts to unmount the SD card.
* @param ctx: CLI context to print to
* @param argv list of arguments
* @param argc argument count
* @return 0 on success, or another value on failure
*/
static int unmount(CLIContext *ctx, char **argv, int argc) {
if (!sd_card_mounted()) {
cli_printf(ctx, "SD card is not mounted\r\n");
return 0;
}
unmount_sd_card();
cli_printf(ctx, "SD card unmounted\r\n");
return 0;
}
/**
* Reports the mount and power status of the SD card.
* @param ctx: CLI context to print to
* @param argv list of arguments
* @param argc argument count
* @return 0 on success, or another value on failure
*/
static int sdstatus(CLIContext *ctx, char **argv, int argc) {
cli_printf(ctx, "SD card is %s\r\n",
sd_card_mounted() ? "mounted" : "unmounted");
cli_printf(ctx, "SD card power: %s\r\n",
GPIO_read(Board_SDCARD_VCC) ? "on" : "off");
return 0;
}
/**
* Manually controls power to the SD card. Useful for debugging.
* @param ctx: CLI context to print to
* @param argv list of arguments
* @param argc argument count
* @return 0 on success, or another value on failure
*/
static int sdpwr(CLIContext *ctx, char **argv, int argc) {
if (argc != 2) {
cli_printf(ctx, "Unsupported number of arguments\r\n");
return 255;
}
if (strncmp("on", argv[1], 2) == 0) {
GPIO_write(Board_SDCARD_VCC, Board_LED_ON);
cli_printf(ctx, "SD card power on\r\n");
return 0;
} else if (strncmp("off", argv[1], 3) == 0) {
GPIO_write(Board_SDCARD_VCC, Board_LED_OFF);
cli_printf(ctx, "SD card power off\r\n");
return 0;
} else {
cli_printf(ctx, "Unknown argument %s\r\n", argv[1]);
return 255;
}
}
/**
* Writes provided string to the SD card.
* @param ctx: CLI context to print to
* @param argv list of arguments
* @param argc argument count
* @return 0 on success, or another value on failure
*/
static int sdwrite(CLIContext *ctx, char **argv, int argc) {
if (argc != 2) {
cli_printf(ctx, "Unsupported number of arguments\r\n");
return 255;
}
// Check SD card mount status
if (!sd_card_mounted()) {
cli_printf(ctx, "Cannot write to SD card, not mounted\r\n");
return 255;
}
// Write the string to the SD card.
if (write_sd(argv[1], strlen(argv[1])) != strlen(argv[1])) {
cli_printf(ctx, "Write error!\r\n");
return 255;
}
return 0;
}
/**
* Gets the size of the the logfile in bytes.
* @param ctx: CLI context to print to
* @param argv list of arguments
* @param argc argument count
* @return 0 on success, or another value on failure
*/
static int logfile_size(CLIContext *ctx, char **argv, int argc) {
cli_printf(ctx, "SD card file size is: %d\r\n", filesize());
return 0;
}
/**
* Connects directly to the UART device being logged from. Useful for
* situations where the logged device exposes a terminal, and you'd like to
* access it.
* @param ctx: CLI context to print to
* @param argv list of arguments
* @param argc argument count
* @return 0 on success, or another value on failure
*/
static int connect_log(CLIContext *ctx, char **argv, int argc) {
if (enable_log_forwarding(ctx) != 0) {
cli_printf(ctx, "Could not enable log forwarding\r\n");
return 255;
} else {
return 0;
}
}
/**
* Disconnects from the UART device being logged, so it's data no longer will
* print to the CLI.
* @param ctx: CLI context to print to
* @param argv list of arguments
* @param argc argument count
* @return 0 on success, or another value on failure
*/
static int disconnect_log(CLIContext *ctx, char **argv, int argc) {
if (disable_log_forwarding() != 0) {
cli_printf(ctx,
"Could not disable log forwarding from this terminal\r\n");
return 255;
} else {
return 0;
}
}
/**
* Opens a real time terminal to the UART console being logged. This function
* will write data to the UART device being logged from, and request that
* the logger task print all data it reads to the CLI, creating a two way
* connection. Will run this until user enters escape sequence.
* @param ctx: CLI context to print to
* @param argv list of arguments
* @param argc argument count
* @return 0 on success, or another value on failure
*/
static int realtime_terminal(CLIContext *ctx, char **argv, int argc) {
char input;
// First, enable log forwarding.
if (enable_log_forwarding(ctx) != 0) {
cli_printf(ctx, "Could not start terminal, another console is using "
"log forwarding\r\n");
return 255;
}
/*
* Now, enter a loop. Until the user enters the escape sequence CTRL+E,
* read all the data they type and write it to the UART device being logged.
*/
cli_printf(ctx, "Starting real time terminal, press CTRL+E to exit\r\n");
while (1) {
ctx->cli_read(&input, 1);
if (input == 5) { // Corresponds to CTRL+E
break;
}
write_to_logger(&input, 1);
}
// Now that escape sequence was read, disable forwarding and return.
if (disable_log_forwarding() != 0) {
cli_printf(ctx, "Error, could not disable log forwarding. This should "
"not occur\r\n");
return 255;
}
return 0;
}
/**
* Writes a timestamp into the SD card log file.
* @param ctx: CLI context to print to
* @param argv list of arguments
* @param argc argument count
* @return 0 on success, or another value on failure
*/
static int write_ts(CLIContext *ctx, char **argv, int argc) {
if (write_timestamp() != 0) {
cli_printf(ctx,
"SD card write write error: could not write timestamp\r\n");
return 255;
}
return 0;
}