-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathconsole.c
More file actions
483 lines (417 loc) · 14.5 KB
/
console.c
File metadata and controls
483 lines (417 loc) · 14.5 KB
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
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
// Console is the generic interface to the command line.
// These functions should not need signficant modification, only
// to be called from the normal loop. Note that adding commands should
// be done in console commands.
#include <string.h> // for NULL
#include <stdlib.h> // for atoi and itoa (though this code implement a version of that)
#include <stdbool.h>
#include "console.h"
#include "consoleIo.h"
#include "consoleCommands.h"
#define MIN(X, Y) (((X) < (Y)) ? (X) : (Y))
#define NOT_FOUND -1
#define INT16_MAX_STR_LENGTH 8 // -65534: six characters plus a two NULLs
#define INT32_MAX_STR_LENGTH 16
#define NULL_CHAR '\0'
#define CR_CHAR '\r'
#define LF_CHAR '\n'
// global variables
char mReceiveBuffer[CONSOLE_COMMAND_MAX_LENGTH];
uint32_t mReceivedSoFar;
bool mConsoleReady;
ConsoleHookFncPtr mConsoleStartHook;
ConsoleHookFncPtr mConsoleExitHook;
// local functions
static int32_t ConsoleCommandEndline(const char receiveBuffer[], const uint32_t filledLength);
static uint32_t ConsoleCommandMatch(const char* name, const char *buffer);
static eCommandResult_T ConsoleParamFindN(const char * buffer, const uint8_t parameterNumber, uint32_t *startLocation);
static uint32_t ConsoleResetBuffer(char receiveBuffer[], const uint32_t filledLength, uint32_t usedSoFar);
static eCommandResult_T ConsoleUtilHexCharToInt(char charVal, uint8_t* pInt); // this might be replaceable with *pInt = atoi(str)
static eCommandResult_T ConsoleUtilsIntToHexChar(uint8_t intVal, char* pChar); // this could be replaced with itoa (intVal, str, 16);
// ConsoleCommandMatch
// Look to see if the data in the buffer matches the command name given that
// the strings are different lengths and we have parameter separators
static uint32_t ConsoleCommandMatch(const char* name, const char *buffer)
{
uint32_t i = 0u;
uint32_t result = 0u; // match
if ( buffer[i] == name [i] )
{
result = 1u;
i++;
}
while ( ( 1u == result ) &&
( i < CONSOLE_COMMAND_MAX_COMMAND_LENGTH ) &&
( buffer[i] != PARAMETER_SEPARATER ) &&
( buffer[i] != LF_CHAR ) &&( buffer[i] != CR_CHAR ) &&
( buffer[i] != (char) NULL_CHAR )
)
{
if ( buffer[i] != name[i] )
{
result = 0u;
}
i++;
}
return result;
}
// ConsoleResetBuffer
// In an ideal world, this would just zero out the buffer. However, thre are times when the
// buffer may have data beyond what was used in the last command.
// We don't want to lose that data so we move it to the start of the command buffer and then zero
// the rest.
static uint32_t ConsoleResetBuffer(char receiveBuffer[], const uint32_t filledLength, uint32_t usedSoFar)
{
uint32_t i = 0;
while (usedSoFar < filledLength)
{
receiveBuffer[i] = receiveBuffer[usedSoFar]; // move the end to the start
i++;
usedSoFar++;
}
for ( /* nothing */ ; i < CONSOLE_COMMAND_MAX_LENGTH ; i++)
{
receiveBuffer[i] = NULL_CHAR;
}
return (filledLength - usedSoFar);
}
// ConsoleCommandEndline
// Check to see where in the buffer stream the endline is; that is the end of the command and parameters
static int32_t ConsoleCommandEndline(const char receiveBuffer[], const uint32_t filledLength)
{
uint32_t i = 0;
int32_t result = NOT_FOUND; // if no endline is found, then return -1 (NOT_FOUND)
while ( ( CR_CHAR != receiveBuffer[i]) && (LF_CHAR != receiveBuffer[i])
&& ( i < filledLength ) )
{
i++;
}
if ( i < filledLength )
{
result = i;
}
return result;
}
// ConsoleInit
// Initialize the console interface and all it depends on
void ConsoleInit(bool echoEn, ConsoleHookFncPtr startHook, ConsoleHookFncPtr exitHook)
{
uint32_t i;
mConsoleReady = false;
mConsoleStartHook = startHook;
mConsoleExitHook = exitHook;
ConsoleIoInit();
ConsoleIoSetEcho(echoEn);
mReceivedSoFar = 0u;
for ( i = 0u ; i < CONSOLE_COMMAND_MAX_LENGTH ; i++)
{
mReceiveBuffer[i] = NULL_CHAR;
}
}
eCommandResult_T ConsoleExit(const char buffer[])
{
if ( &buffer == &buffer ) {}
ConsoleIoSendString("Bye.");
ConsoleIoSendString(STR_ENDLINE);
mConsoleReady = false;
if(NULL != mConsoleExitHook) mConsoleExitHook();
return CONSOLE_SUCCESS;
}
// ConsoleProcess
// Looks for new inputs, checks for endline, then runs the matching command.
// Call ConsoleProcess from a loop, it will handle commands as they become available
void ConsoleProcess(void)
{
const sConsoleCommandTable_T* commandTable;
uint32_t received;
uint32_t cmdIndex;
int32_t cmdEndline;
int32_t found;
eCommandResult_T result;
if(!mConsoleReady) {
if(CONSOLE_SUCCESS == ConsoleIoReady()) {
mConsoleReady = true;
if(NULL != mConsoleStartHook) mConsoleStartHook();
ConsoleIoSendString("Welcome to the Consolinator, your gateway to testing code and hardware.");
ConsoleIoSendString(STR_ENDLINE);
ConsoleIoSendString(CONSOLE_PROMPT);
}
}
if(mConsoleReady) {
ConsoleIoReceive((uint8_t*)&(mReceiveBuffer[mReceivedSoFar]), ( CONSOLE_COMMAND_MAX_LENGTH - mReceivedSoFar ), &received);
if ( received > 0u )
{
mReceivedSoFar += received;
cmdEndline = ConsoleCommandEndline(mReceiveBuffer, mReceivedSoFar);
if ( cmdEndline >= 0 ) // have complete string, find command
{
commandTable = ConsoleCommandsGetTable();
cmdIndex = 0u;
found = NOT_FOUND;
while ( ( NULL != commandTable[cmdIndex].name ) && ( NOT_FOUND == found ) )
{
if ( ConsoleCommandMatch(commandTable[cmdIndex].name, mReceiveBuffer) )
{
result = commandTable[cmdIndex].execute(mReceiveBuffer);
if ( COMMAND_SUCCESS != result )
{
ConsoleIoSendString("Error: ");
ConsoleIoSendString(mReceiveBuffer);
ConsoleIoSendString("Help: ");
ConsoleIoSendString(commandTable[cmdIndex].help);
ConsoleIoSendString(STR_ENDLINE);
}
found = cmdIndex;
}
else
{
cmdIndex++;
}
}
if ( ( cmdEndline != 0 ) && ( NOT_FOUND == found ) )
{
if (mReceivedSoFar > 2) /// shorter than that, it is probably nothing
{
ConsoleIoSendString("Command not found.");
ConsoleIoSendString(STR_ENDLINE);
}
}
mReceivedSoFar = ConsoleResetBuffer(mReceiveBuffer, mReceivedSoFar, cmdEndline);
// exit command may have been issued, so check if we are still ready
if(mConsoleReady) {
ConsoleIoSendString(CONSOLE_PROMPT);
}
}
}
}
}
// ConsoleParamFindN
// Find the start location of the nth parametr in the buffer where the command itself is parameter 0
static eCommandResult_T ConsoleParamFindN(const char * buffer, const uint8_t parameterNumber, uint32_t *startLocation)
{
uint32_t bufferIndex = 0;
uint32_t parameterIndex = 0;
eCommandResult_T result = COMMAND_SUCCESS;
while ( ( parameterNumber != parameterIndex ) && ( bufferIndex < CONSOLE_COMMAND_MAX_LENGTH ) )
{
if ( PARAMETER_SEPARATER == buffer[bufferIndex] )
{
parameterIndex++;
}
bufferIndex++;
}
if ( CONSOLE_COMMAND_MAX_LENGTH == bufferIndex )
{
result = COMMAND_PARAMETER_ERROR;
}
else
{
*startLocation = bufferIndex;
}
return result;
}
// ConsoleReceiveParamInt16
// Identify and obtain a parameter of type int16_t, sent in in decimal, possibly with a negative sign.
// Note that this uses atoi, a somewhat costly function. You may want to replace it, see ConsoleReceiveParamHexUint16
// for some ideas on how to do that.
eCommandResult_T ConsoleReceiveParamInt16(const char * buffer, const uint8_t parameterNumber, int16_t* parameterInt)
{
uint32_t startIndex = 0;
uint32_t i;
eCommandResult_T result;
char charVal;
char str[INT16_MAX_STR_LENGTH];
result = ConsoleParamFindN(buffer, parameterNumber, &startIndex);
i = 0;
charVal = buffer[startIndex + i];
while ( ( LF_CHAR != charVal ) && ( CR_CHAR != charVal )
&& ( PARAMETER_SEPARATER != charVal )
&& ( i < INT16_MAX_STR_LENGTH ) )
{
str[i] = charVal; // copy the relevant part
i++;
charVal = buffer[startIndex + i];
}
if ( i == INT16_MAX_STR_LENGTH)
{
result = COMMAND_PARAMETER_ERROR;
}
if ( COMMAND_SUCCESS == result )
{
str[i] = NULL_CHAR;
*parameterInt = atoi(str);
}
return result;
}
// ConsoleReceiveParamHexUint16
// Identify and obtain a parameter of type uint16, sent in as hex. This parses the number and does not use
// a library function to do it.
eCommandResult_T ConsoleReceiveParamHexUint16(const char * buffer, const uint8_t parameterNumber, uint16_t* parameterUint16)
{
uint32_t startIndex = 0;
uint16_t value = 0;
uint32_t i;
eCommandResult_T result;
uint8_t tmpUint8;
result = ConsoleParamFindN(buffer, parameterNumber, &startIndex);
if ( COMMAND_SUCCESS == result )
{
// bufferIndex points to start of integer
// next separator or newline or NULL indicates end of parameter
for ( i = 0u ; i < 4u ; i ++) // U16 must be less than 4 hex digits: 0xFFFF
{
if ( COMMAND_SUCCESS == result )
{
result = ConsoleUtilHexCharToInt(buffer[startIndex + i], &tmpUint8);
}
if ( COMMAND_SUCCESS == result )
{
value = (value << 4u);
value += tmpUint8;
}
}
if ( COMMAND_PARAMETER_END == result )
{
result = COMMAND_SUCCESS;
}
*parameterUint16 = value;
}
return result;
}
// ConsoleSendParamHexUint16
// Send a parameter of type uint16 as hex.
// This does not use a library function to do it (though you could
// do itoa (parameterUint16, out, 16); instead of building it up
eCommandResult_T ConsoleSendParamHexUint16(uint16_t parameterUint16)
{
uint32_t i;
char out[4u + 1u]; // U16 must be less than 4 hex digits: 0xFFFF, end buffer with a NULL
eCommandResult_T result = COMMAND_SUCCESS;
uint8_t tmpUint8;
for ( i = 0u ; i < 4u ; i ++) // U16 must be less than 4 hex digits: 0xFFFF
{
if ( COMMAND_SUCCESS == result )
{
tmpUint8 = ( parameterUint16 >> (12u - (i*4u)) & 0xF);
result = ConsoleUtilsIntToHexChar(tmpUint8, &(out[i]));
}
}
out[i] = NULL_CHAR;
ConsoleIoSendString(out);
return COMMAND_SUCCESS;
}
eCommandResult_T ConsoleSendParamHexUint8(uint8_t parameterUint8)
{
uint32_t i;
char out[2u + 1u]; // U8 must be less than 4 hex digits: 0xFFFF, end buffer with a NULL
eCommandResult_T result = COMMAND_SUCCESS;
i = 0u;
result = ConsoleUtilsIntToHexChar( (parameterUint8 >> 4u) & 0xF, &(out[i]));
i++;
if ( COMMAND_SUCCESS == result )
{
result = ConsoleUtilsIntToHexChar( parameterUint8 & 0xF, &(out[i]));
i++;
}
out[i] = NULL_CHAR;
ConsoleIoSendString(out);
return COMMAND_SUCCESS;
}
// The C library itoa is sometimes a complicated function and the library costs aren't worth it
// so this is implements the parts of the function needed for console.
static void __console_itoa(int in, char* outBuffer, int radix)
{
bool isNegative = false;
int tmpIn;
int stringLen = 1u; // it will be at least as long as the NULL character
if (in < 0) {
isNegative = true;
in = -in;
stringLen++;
}
tmpIn = in;
while ((int)tmpIn/radix != 0) {
tmpIn = (int)tmpIn/radix;
stringLen++;
}
// Now fill it in backwards, starting with the NULL at the end
*(outBuffer + stringLen) = NULL_CHAR;
stringLen--;
tmpIn = in;
do {
*(outBuffer+stringLen) = (tmpIn%radix)+'0';
tmpIn = (int) tmpIn / radix;
} while(stringLen--);
if (isNegative) {
*(outBuffer) = '-';
}
}
// ConsoleSendParamInt16
// Send a parameter of type int16 using the (unsafe) C library function
// __console_itoa to translate from integer to string.
eCommandResult_T ConsoleSendParamInt16(int16_t parameterInt)
{
char out[INT16_MAX_STR_LENGTH];
// memset(out, 0, INT16_MAX_STR_LENGTH);
__console_itoa (parameterInt, out, 10);
ConsoleIoSendString(out);
return COMMAND_SUCCESS;
}
// ConsoleSendParamInt32
// Send a parameter of type int16 using the (unsafe) C library function
// __console_itoa to translate from integer to string.
eCommandResult_T ConsoleSendParamInt32(int32_t parameterInt)
{
char out[INT32_MAX_STR_LENGTH];
memset(out, 0, sizeof(out));
__console_itoa (parameterInt, out, 10);
ConsoleIoSendString(out);
return COMMAND_SUCCESS;
}
// ConsoleUtilHexCharToInt
// Converts a single hex character (0-9,A-F) to an integer (0-15)
static eCommandResult_T ConsoleUtilHexCharToInt(char charVal, uint8_t* pInt)
{
eCommandResult_T result = COMMAND_SUCCESS;
if ( ( '0' <= charVal ) && ( charVal <= '9' ) )
{
*pInt = charVal - '0';
}
else if ( ( 'A' <= charVal ) && ( charVal <= 'F' ) )
{
*pInt = 10u + charVal - 'A';
}
else if( ( 'a' <= charVal ) && ( charVal <= 'f' ) )
{
*pInt = 10u + charVal - 'a';
}
else if ( ( LF_CHAR != charVal ) || ( CR_CHAR != charVal )
|| ( PARAMETER_SEPARATER == charVal ) )
{
result = COMMAND_PARAMETER_END;
}
else
{
result = COMMAND_PARAMETER_ERROR;
}
return result;
}
// ConsoleUtilsIntToHexChar
// Converts an integer nibble (0-15) to a hex character (0-9,A-F)
static eCommandResult_T ConsoleUtilsIntToHexChar(uint8_t intVal, char* pChar)
{
eCommandResult_T result = COMMAND_SUCCESS;
if ( intVal <= 9u )
{
*pChar = intVal + '0';
}
else if ( ( 10u <= intVal ) && ( intVal <= 15u ) )
{
*pChar = intVal - 10u + 'A';
}
else
{
result = COMMAND_PARAMETER_ERROR;
}
return result;
}