-
Notifications
You must be signed in to change notification settings - Fork 5
Expand file tree
/
Copy pathembedded_cli.h
More file actions
474 lines (413 loc) · 13.5 KB
/
Copy pathembedded_cli.h
File metadata and controls
474 lines (413 loc) · 13.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
#ifndef __EMBEDDED_CLI_H__
#define __EMBEDDED_CLI_H__
#ifdef __cplusplus
extern "C" {
#else
#include <stdbool.h>
#endif
// cstdint is available only since C++11, so use C header
#include <stddef.h>
#include <stdint.h>
#include "modules.h"
// used for proper alignment of cli buffer
#if UINTPTR_MAX == 0xFFFF
#define CLI_UINT uint16_t
#elif UINTPTR_MAX == 0xFFFFFFFF
#define CLI_UINT uint32_t
#elif UINTPTR_MAX == 0xFFFFFFFFFFFFFFFFu
#define CLI_UINT uint64_t
#else
#error unsupported pointer size
#endif
#define CLI_UINT_SIZE (sizeof(CLI_UINT))
// convert size in bytes to size in terms of CLI_UINTs (rounded up
// if bytes is not divisible by size of single CLI_UINT)
#define BYTES_TO_CLI_UINTS(bytes) \
(((bytes) + CLI_UINT_SIZE - 1) / CLI_UINT_SIZE)
typedef struct CliCommand CliCommand;
typedef struct CliCommandBinding CliCommandBinding;
typedef struct EmbeddedCli EmbeddedCli;
typedef struct EmbeddedCliConfig EmbeddedCliConfig;
struct CliCommand {
/**
* Name of the command.
* In command "set led 1 1" "set" is name
*/
const char* name;
/**
* String of arguments of the command.
* In command "set led 1 1" "led 1 1" is string of arguments
* Is ended with double 0x00 char
* Use tokenize functions to easily get individual tokens
*/
char* args;
};
/**
* Struct to describe binding of command to function and
*/
struct CliCommandBinding {
/**
* Binding function for when command is received.
* If null, default callback (onCommand) will be called.
* @param cli - pointer to cli that is calling this binding
* @param args - string of args (if tokenizeArgs is false) or tokens otherwise
* @param context
*/
void (*func)(EmbeddedCli* cli, char* args, void* context);
/**
* Name of command to bind. Should not be NULL.
*/
const char* name;
/**
* Help string for usage like "<cmd> <arg1> <arg2> [<arg3>]".
* Can be NULL if no help is provided.
*/
const char* usage;
/**
* Help string that will be displayed when "help <cmd>" is executed.
* Can have multiple lines separated with "\r\n"
* Can be NULL if no help is provided.
*/
const char* help;
/**
* Flag to perform tokenization before calling binding function.
*/
bool autoTokenizeArgs;
/**
* Pointer to any specific app context that is required for this binding.
* It will be provided in binding callback.
*/
void* context;
};
struct EmbeddedCli {
/**
* Should write char to connection (fallback if writeString is not set)
* @param cli - pointer to cli that executed this function
* @param c - actual character to write
*/
void (*writeChar)(EmbeddedCli* cli, char c);
/**
* Called when command is received and command not found in list of
* command bindings (or binding function is null).
* @param cli - pointer to cli that executed this function
* @param command - pointer to received command
*/
void (*onCommand)(EmbeddedCli* cli, CliCommand* command);
/**
* Pointer to actual implementation, do not use.
*/
void* _impl;
};
/**
* Configuration to create CLI
*/
struct EmbeddedCliConfig {
/**
* Invitation string. Is printed at the beginning of each line with user
* input
*/
const char* invitation;
/**
* Size of buffer that is used to store characters until they're processed
*/
uint16_t rxBufferSize;
/**
* Size of buffer that is used to store current input that is not yet
* sended as command (return not pressed yet)
*/
uint16_t cmdBufferSize;
/**
* Size of buffer that is used to store previously entered commands
* Only unique commands are stored in buffer. If buffer is smaller than
* entered command (including arguments), command is discarded from history
*/
uint16_t historyBufferSize;
/**
* Maximum amount of bindings that can be added via addBinding function.
* Cli increases takes extra bindings for internal commands:
* - help
*/
uint16_t maxBindingCount;
/**
* Buffer to use for cli and all internal structures. If NULL, memory will
* be allocated dynamically. Otherwise this buffer is used and no
* allocations are made
*/
CLI_UINT* cliBuffer;
/**
* Size of buffer for cli and internal structures (in bytes).
*/
uint16_t cliBufferSize;
/**
* Whether autocompletion should be enabled.
* If false, autocompletion is disabled but you still can use 'tab' to
* complete current command manually.
*/
bool enableAutoComplete;
/**
* Whether color output should be enabled.
* If false, color output is disabled and all color codes are ignored.
*/
bool enableColorOutput;
};
/**
* Returns pointer to default configuration for cli creation. It is safe to
* modify it and then send to embeddedCliNew().
* Returned structure is always the same so do not free and try to use it
* immediately.
* Default values:
* <ul>
* <li>rxBufferSize = 64</li>
* <li>cmdBufferSize = 64</li>
* <li>historyBufferSize = 128</li>
* <li>cliBuffer = NULL (use dynamic allocation)</li>
* <li>cliBufferSize = 0</li>
* <li>maxBindingCount = 8</li>
* <li>enableAutoComplete = true</li>
* </ul>
* @return configuration for cli creation
*/
EmbeddedCliConfig* embeddedCliDefaultConfig(void);
/**
* Returns how many space in config buffer is required for cli creation
* If you provide buffer with less space, embeddedCliNew will return NULL
* This amount will always be divisible by CLI_UINT_SIZE so allocated buffer
* and internal structures can be properly aligned
* @param config
* @return
*/
uint16_t embeddedCliRequiredSize(EmbeddedCliConfig* config);
/**
* Create new CLI.
* Memory is allocated dynamically if cliBuffer in config is NULL.
* After CLI is created, override function pointers to start using it
* @param config - config for cli creation
* @return pointer to created CLI
*/
EmbeddedCli* embeddedCliNew(EmbeddedCliConfig* config);
/**
* Same as calling embeddedCliNew with default config.
* @return
*/
EmbeddedCli* embeddedCliNewDefault(void);
/**
* Receive character and put it to internal buffer
* Actual processing is done inside embeddedCliProcess
* You can call this function from something like interrupt service routine,
* just make sure that you call it only from single place. Otherwise input
* might get corrupted
* @param cli
* @param c - received char
*/
void embeddedCliReceiveChar(EmbeddedCli* cli, char c);
/**
* Receive buffer and put it to internal buffer
* Actual processing is done inside embeddedCliProcess
* You can call this function from something like interrupt service routine,
* just make sure that you call it only from single place. Otherwise input
* might get corrupted
* @param cli
* @param buffer
* @param len
*/
void embeddedCliReceiveBuffer(EmbeddedCli* cli, const char* buffer, size_t len);
/**
* Process rx/tx buffers. Command callbacks are called from here
* @param cli
*/
void embeddedCliProcess(EmbeddedCli* cli);
/**
* Add specified binding to list of bindings. If list is already full, binding
* is not added and false is returned
* @param cli
* @param binding
* @return true if binding was added, false otherwise
*/
bool embeddedCliAddBinding(EmbeddedCli* cli, CliCommandBinding binding);
/**
* Delete binding with specified name from list of bindings
* @param cli
* @param name
* @return true if binding was deleted, false otherwise
*/
bool embeddedCliDelBinding(EmbeddedCli* cli, const char* name);
/**
* Print specified string and account for currently entered but not
* submitted command. Current command is deleted, provided string is printed
* (with new line) after that current command is printed again, so user can
* continue typing it.
* @param cli
* @param string
*/
void embeddedCliPrint(EmbeddedCli* cli, const char* string);
/**
* Free allocated for cli memory
* @param cli
*/
void embeddedCliFree(EmbeddedCli* cli);
/**
* @brief Get command entry from cli and switch to it (Professional only)
* @param cli
* @return command entry
*/
void (*embeddedCliSwitchToCommandEntry(EmbeddedCli* cli, const char* name))(
EmbeddedCli* cli, char* args, void* context);
/**
* Perform tokenization of arguments string. Original string is modified and
* should not be used directly (only inside other token functions).
* Individual tokens are separated by single 0x00 char, double 0x00 is put at
* the end of token list. After calling this function, you can use other
* token functions to get individual tokens and token count.
*
* Important: Call this function only once. Otherwise information will be lost
* if more than one token existed
* @param args - string to tokenize (must have extra writable char after 0x00)
* @return
*/
void embeddedCliTokenizeArgs(char* args);
/**
* Return specific token from tokenized string
* @param tokenizedStr
* @param pos (counted from 1)
* @return token
*/
const char* embeddedCliGetToken(const char* tokenizedStr, int16_t pos);
/**
* @brief Pop first token from tokenized string
* @param tokenizedStr pointer to tokenized string
* @return token or NULL if no token left
*/
const char* embeddedCliPopToken(char** tokenizedStr);
/**
* Same as embeddedCliGetToken but works on non-const buffer
* @param tokenizedStr
* @param pos (counted from 1)
* @return token
*/
char* embeddedCliGetTokenVariable(char* tokenizedStr, int16_t pos);
/**
* Find token in provided tokens string and return its position (counted from 1)
* If no such token is found - 0 is returned.
* @param tokenizedStr
* @param token - token to find
* @return position (from 1) or 0 if no such token found
*/
uint16_t embeddedCliFindToken(const char* tokenizedStr, const char* token);
/**
* @brief Find token starting with specified string in provided tokens string
* @param tokenizedStr
* @param token
* @retval position (from 1) or 0 if no such token found
*/
uint16_t embeddedCliFindTokenStartswith(const char* tokenizedStr,
const char* token);
/**
* @brief Find token ending with specified string in provided tokens string
* @param tokenizedStr
* @param token
* @retval position (from 1) or 0 if no such token found
*/
uint16_t embeddedCliFindTokenEndswith(const char* tokenizedStr,
const char* token);
/**
* Check if tokenized string contains specified token at specified position
* @param tokenizedStr
* @param token
* @param pos (counted from 1)
* @return true if token is at specified position, false otherwise
*/
bool embeddedCliCheckToken(const char* tokenizedStr, const char* token,
int16_t pos);
/**
* @brief Check if tokenized string starts with specified token at specified
* position
* @param tokenizedStr
* @param token
* @param pos (counted from 1)
* @retval true if token at specified position starts with specified token
*/
bool embeddedCliCheckTokenStartswith(const char* tokenizedStr,
const char* token, int16_t pos);
/**
* Check if tokenized string ends with specified token at specified position
* @param tokenizedStr
* @param token
* @param pos (counted from 1)
* @retval true if token at specified position ends with specified token
*/
bool embeddedCliCheckTokenEndswith(const char* tokenizedStr, const char* token,
int16_t pos);
/**
* Return number of tokens in tokenized string
* @param tokenizedStr
* @return number of tokens
*/
uint16_t embeddedCliGetTokenCount(const char* tokenizedStr);
/**
* Print help for current running command
* @param cli
*/
void embeddedCliPrintCurrentHelp(EmbeddedCli* cli);
/**
* @brief Enter Sub-Interpreter mode
* @param cli
* @param onCommand
* @param onExit called when Ctrl+D or manual exit is called
* @param invitation
*/
void embeddedCliEnterSubInterpreter(
EmbeddedCli* cli, void (*onCommand)(EmbeddedCli* cli, CliCommand* command),
void (*onExit)(EmbeddedCli* cli), const char* invitation);
/**
* @brief Exit Sub-Interpreter mode
*/
void embeddedCliExitSubInterpreter(EmbeddedCli* cli);
/**
* @brief Set invitation for cli
* @param cli
* @param invitation
*/
void embeddedCliSetInvitation(EmbeddedCli* cli, const char* invitation);
/**
* @brief Set Raw-Hanlder for cli
* @param cli
* @param rawHandler called when any raw data is received, return data to echo
*/
void embeddedCliSetRawHandler(EmbeddedCli* cli,
char (*rawHandler)(EmbeddedCli* cli, char data));
/**
* @brief Reset Raw-Handler for cli
*/
void embeddedCliResetRawHandler(EmbeddedCli* cli);
/**
* @brief Set Raw-Buffer-Handler for cli
* @param cli
* @param rawBufferHandler called when any raw data is received
*/
void embeddedCliSetRawBufferHandler(EmbeddedCli* cli,
void (*rawBufferHandler)(EmbeddedCli* cli,
const char* buffer,
size_t len));
/**
* @brief Reset Raw-Buffer-Handler for cli
* @param cli
*/
void embeddedCliResetRawBufferHandler(EmbeddedCli* cli);
/**
* @brief Set onCommandExecution callback
* @param cli
* @param onCommandExecution called before and after command execution
*/
void embeddedCliSetOnCommandExecution(
EmbeddedCli* cli,
void (*onCommandExecution)(EmbeddedCli* cli, CliCommand* command,
bool is_finished));
/**
* @brief Reset onCommandExecution callback
* @param cli
*/
void embeddedCliResetOnCommandExecution(EmbeddedCli* cli);
#ifdef __cplusplus
}
#endif
#endif /* __EMBEDDED_CLI_H__ */