rusEFI
The most advanced open source ECU
Loading...
Searching...
No Matches
cli_registry.cpp
Go to the documentation of this file.
1/**
2 * @file cli_registry.cpp
3 * @brief Command-line interface commands registry
4 *
5 * Here we have a data structure which holds all the dynamically-registered
6 * command line interface action names & callback. This logic is invoked in
7 * user context by the console thread - see consoleThreadEntryPoint
8 *
9 * TODO: there is too much copy-paste here, this class needs some refactoring :)
10 *
11 * see testConsoleLogic()
12 *
13 * @date Nov 15, 2012
14 * @author Andrey Belomutskiy, (c) 2012-2020
15 */
16
17#include <cstring>
18#include <cstdint>
19
20// looks like some technical debt here?! that's about error: ‘isnan’ is not a member of ‘std’
21#include <cmath>
22#include <rusefi/rusefi_math.h>
23
24#include "efiprintf.h"
25#include "rusefi/efistringutil.h"
26#include "cli_registry.h"
27
28/* for isspace() */
29#include <cctype>
30
31#ifndef CONSOLE_MAX_ACTIONS
32#define CONSOLE_MAX_ACTIONS 256
33#endif
34
35#ifndef MAX_CMD_LINE_LENGTH
36#define MAX_CMD_LINE_LENGTH 100
37#endif
38
39// todo: support \t as well
40#define SPACE_CHAR ' '
41
42using namespace rusefi::stringutil;
43
44static int consoleActionCount = 0;
45static TokenCallback consoleActions[CONSOLE_MAX_ACTIONS];
46
49}
50
51static void doAddAction(const char *token, action_type_e type, Void callback, void *param) {
52#if !defined(EFI_DISABLE_CONSOLE_ACTIONS)
53 for (uint32_t i = 0; i < std::strlen(token); i++) {
54 char ch = token[i];
55 if (isupper(ch)) {
56 onCliCaseError(token);
57 return;
58 }
59 }
60 for (int i = 0; i < consoleActionCount; i++) {
61 if (strcmp(token, consoleActions[i].token) == 0 /* zero result means strings are equal */) {
63 return;
64 }
65 }
66
67 if (consoleActionCount >= CONSOLE_MAX_ACTIONS) {
69 return;
70 }
71
73 current->token = token;
74 current->parameterType = type;
75 current->callback = callback;
76 current->param = param;
77#endif /* EFI_DISABLE_CONSOLE_ACTIONS */
78}
79
80void addConsoleActionP(const char *token, VoidPtr callback, void *param) {
81 doAddAction(token, NO_PARAMETER_P, (Void) callback, param);
82}
83
84void addConsoleActionSSP(const char *token, VoidCharPtrCharPtrVoidPtr callback, void *param) {
85 doAddAction(token, STRING2_PARAMETER_P, (Void) callback, param);
86}
87
88/**
89 * @brief Register console action without parameters
90 */
91void addConsoleAction(const char *token, Void callback) {
92 doAddAction(token, NO_PARAMETER, callback, NULL);
93}
94
95/**
96 * @brief Register a console command with one Integer parameter
97 */
98void addConsoleActionI(const char *token, VoidInt callback) {
99 doAddAction(token, ONE_PARAMETER, (Void) callback, NULL);
100}
101
102void addConsoleActionIP(const char *token, VoidIntVoidPtr callback, void *param) {
103 doAddAction(token, ONE_PARAMETER_P, (Void) callback, param);
104}
105
106/**
107 * @brief Register a console command with two Integer parameters
108 */
109void addConsoleActionII(const char *token, VoidIntInt callback) {
110 doAddAction(token, TWO_INTS_PARAMETER, (Void) callback, NULL);
111}
112
113void addConsoleActionIIP(const char *token, VoidIntIntVoidPtr callback, void *param) {
114 doAddAction(token, TWO_INTS_PARAMETER_P, (Void) callback, param);
115}
116
117void addConsoleActionIF(const char *token, VoidIntFloat callback) {
118 doAddAction(token, INT_FLOAT_PARAMETER, (Void) callback, NULL);
119}
120
121void addConsoleActionS(const char *token, VoidCharPtr callback) {
122 doAddAction(token, STRING_PARAMETER, (Void) callback, NULL);
123}
124
125void addConsoleActionSP(const char *token, VoidCharPtrVoidPtr callback, void *param) {
126 doAddAction(token, STRING_PARAMETER_P, (Void) callback, param);
127}
128
129void addConsoleActionSS(const char *token, VoidCharPtrCharPtr callback) {
130 doAddAction(token, STRING2_PARAMETER, (Void) callback, NULL);
131}
132
133void addConsoleActionSSS(const char *token, VoidCharPtrCharPtrCharPtr callback) {
134 doAddAction(token, STRING3_PARAMETER, (Void) callback, NULL);
135}
136
138 doAddAction(token, STRING5_PARAMETER, (Void) callback, NULL);
139}
140
141void addConsoleActionNANF(const char *token, VoidFloat callback) {
142 doAddAction(token, FLOAT_PARAMETER_NAN_ALLOWED, (Void) callback, NULL);
143}
144
145void addConsoleActionF(const char *token, VoidFloat callback) {
146 doAddAction(token, FLOAT_PARAMETER, (Void) callback, NULL);
147}
148
149void addConsoleActionFF(const char *token, VoidFloatFloat callback) {
150 doAddAction(token, FLOAT_FLOAT_PARAMETER, (Void) callback, NULL);
151}
152
153void addConsoleActionFFF(const char *token, VoidFloatFloatFloat callback) {
154 doAddAction(token, FLOAT_FLOAT_FLOAT_PARAMETER, (Void) callback, NULL);
155}
156
157void addConsoleActionFFFF(const char *token, VoidFloatFloatFloatFloat callback) {
158 doAddAction(token, FLOAT_FLOAT_FLOAT_FLOAT_PARAMETER, (Void) callback, NULL);
159}
160
161void addConsoleActionFFP(const char *token, VoidFloatFloatVoidPtr callback, void *param) {
162 doAddAction(token, FLOAT_FLOAT_PARAMETER_P, (Void) callback, param);
163}
164
165static int getParameterCount(action_type_e parameterType) {
166 switch (parameterType) {
167 case NO_PARAMETER:
168 case NO_PARAMETER_P:
169 return 0;
170 case ONE_PARAMETER:
171 case ONE_PARAMETER_P:
172 case FLOAT_PARAMETER:
173 case STRING_PARAMETER:
174 return 1;
182 return 2;
185 return 3;
187 return 4;
189 return 5;
190 default:
191 return -1;
192 }
193}
194
195/**
196 * @brief This function prints out a list of all available commands
197 */
198void helpCommand(void) {
199 efiPrintf("%d actions available", consoleActionCount);
200 for (int i = 0; i < consoleActionCount; i++) {
201 TokenCallback *current = &consoleActions[i];
202 efiPrintf(" %s: %d parameters", current->token, getParameterCount(current->parameterType));
203 }
204 efiPrintf("For more visit https://github.com/rusefi/rusefi/wiki/Dev-Console-Commands");
205}
206
207int findEndOfToken(const char *line) {
208 if (line[0] == '"') {
209 /**
210 * Looks like this is a quoted token
211 */
212 int v = indexOf(line + 1, '"');
213 if (v == -1) {
214 /**
215 * Matching closing quote not found
216 */
217 return -1;
218 }
219 /**
220 * Skipping first quote and the symbol after closing quote
221 */
222 return v + 2;
223 }
224 return indexOf(line, SPACE_CHAR);
225}
226
227/**
228 * @return Number of space-separated tokens in the string
229 */
230int tokenLength(const char *msgp) {
231 int result = 0;
232 while (*msgp) {
233 char ch = *msgp++;
234 if (ch == SPACE_CHAR) {
235 break;
236 }
237 result++;
238 }
239 return result;
240}
241
242char *unquote(char *line) {
243 if (line[0] == '"') {
244 int len = std::strlen(line);
245 if (line[len - 1] == '"') {
246 line[len - 1] = 0;
247 return line + 1;
248 }
249 }
250 return line;
251}
252
253static int setargs(char *args, char **argv, int max_args)
254{
255 int count = 0;
256
257 while (isspace(*args)) {
258 *args = '\0';
259 args++;
260 }
261 while ((*args) && (count < max_args)) {
262 if (argv) {
263 argv[count] = args;
264 }
265 while ((*args) && (!isspace(*args))) {
266 if (*args == '"') {
267 args++;
268 /* find closing quote */
269 while ((*args) && (*args != '"')) {
270 args++;
271 }
272 /* failed? */
273 if (*args == '\0') {
274 return -1;
275 }
276 }
277 args++;
278 }
279 if (*args) {
280 *args = '\0';
281 args++;
282 }
283 while (isspace(*args)) {
284 *args = '\0';
285 args++;
286 }
287 count++;
288 }
289 return count;
290}
291
292int handleActionWithParameter(TokenCallback *current, char *argv[], int argc) {
293 (void)argc;
294
295 switch (current->parameterType) {
296 case NO_PARAMETER:
297 {
298 (*current->callback)();
299 return 0;
300 }
301 case NO_PARAMETER_P:
302 {
303 VoidPtr callbackS = (VoidPtr) current->callback;
304 (*callbackS)(current->param);
305 return 0;
306 }
307 case STRING_PARAMETER:
308 {
309 VoidCharPtr callbackS = (VoidCharPtr) current->callback;
310 (*callbackS)(argv[0]);
311 return 0;
312 }
314 {
315 VoidCharPtrVoidPtr callbackS = (VoidCharPtrVoidPtr) current->callback;
316 (*callbackS)(argv[0], current->param);
317 return 0;
318 }
320 {
321 VoidCharPtrCharPtr callbackS = (VoidCharPtrCharPtr) current->callback;
322 (*callbackS)(argv[0], argv[1]);
323 return 0;
324 }
326 {
328 (*callbackS)(argv[0], argv[1], current->param);
329 return 0;
330 }
332 {
334 (*callbackS)(argv[0], argv[1], argv[2]);
335 return 0;
336 }
338 {
340 (*callbackS)(argv[0], argv[1], argv[2], argv[3], argv[4]);
341 return 0;
342 }
344 {
345 int value[2];
346 for (int i = 0; i < 2; i++) {
347 value[i] = atoi(argv[i]);
348 if (absI(value[i]) == ATOI_ERROR_CODE) {
349 #if EFI_PROD_CODE || EFI_SIMULATOR
350 efiPrintf("not an integer [%s]", argv[0]);
351 #endif
352 return -1;
353 }
354 }
355 VoidIntInt callbackS = (VoidIntInt) current->callback;
356 (*callbackS)(value[0], value[1]);
357 return 0;
358 }
360 {
361 float value = atoff(argv[0]);
362 VoidFloat callbackF = (VoidFloat) current->callback;
363 (*callbackF)(value);
364 return 0;
365 }
366
367 case FLOAT_PARAMETER:
368 {
369 float value = atoff(argv[0]);
370 if (std::isnan(value)) {
371 efiPrintf("invalid float [%s]", argv[0]);
372 return -1;
373 }
374 VoidFloat callbackF = (VoidFloat) current->callback;
375 (*callbackF)(value);
376 return 0;
377 }
378
381 {
382 float value[2];
383 for (int i = 0; i < 2; i++) {
384 value[i] = atoff(argv[i]);
385 if (std::isnan(value[i])) {
386 efiPrintf("invalid float [%s]", argv[i]);
387 return -1;
388 }
389 }
390 if (current->parameterType == FLOAT_FLOAT_PARAMETER) {
391 VoidFloatFloat callbackS = (VoidFloatFloat) current->callback;
392 (*callbackS)(value[0], value[1]);
393 } else {
395 (*callbackS)(value[0], value[1], current->param);
396 }
397 return 0;
398 }
400 {
401 float value[3];
402 for (int i = 0; i < 3; i++) {
403 value[i] = atoff(argv[i]);
404 if (std::isnan(value[i])) {
405 efiPrintf("invalid float [%s]", argv[i]);
406 return -1;
407 }
408 }
409 VoidFloatFloatFloat callbackS = (VoidFloatFloatFloat) current->callback;
410 (*callbackS)(value[0], value[1], value[2]);
411 return 0;
412 }
414 {
415 float value[4];
416 for (int i = 0; i < 4; i++) {
417 value[i] = atoff(argv[i]);
418 if (std::isnan(value[i])) {
419 efiPrintf("invalid float [%s]", argv[i]);
420 return -1;
421 }
422 }
424 (*callbackS)(value[0], value[1], value[2], value[3]);
425 return 0;
426 }
428 {
429 int value1 = atoi(argv[0]);
430 if (absI(value1) == ATOI_ERROR_CODE) {
431 #if EFI_PROD_CODE || EFI_SIMULATOR
432 efiPrintf("not an integer [%s]", argv[0]);
433 #endif
434 return -1;
435 }
436 float value2 = atoff(argv[1]);
437 if (std::isnan(value2)) {
438 efiPrintf("invalid float [%s]", argv[1]);
439 return -1;
440 }
441 VoidIntFloat callback = (VoidIntFloat) current->callback;
442 callback(value1, value2);
443 return 0;
444 }
445 case ONE_PARAMETER_P:
446 case ONE_PARAMETER:
447 {
448 int value = atoi(argv[0]);
449 if (absI(value) == ATOI_ERROR_CODE) {
450 #if EFI_PROD_CODE || EFI_SIMULATOR
451 efiPrintf("not an integer [%s]", argv[0]);
452 #endif
453 return -1;
454 }
455 if (current->parameterType == ONE_PARAMETER_P) {
456 VoidIntVoidPtr callback1 = (VoidIntVoidPtr) current->callback;
457 (*callback1)(value, current->param);
458
459 } else {
460 VoidInt callback1 = (VoidInt) current->callback;
461 (*callback1)(value);
462 }
463 return 0;
464 }
465 default:
466 efiPrintf("Unsupported parameterType %d", current->parameterType);
467 break;
468 }
469 return -1;
470}
471
475
476static char handleBuffer[MAX_CMD_LINE_LENGTH + 1];
477
478static int handleConsoleLineInternal(const char *commandLine) {
479 strncpy(handleBuffer, commandLine, sizeof(handleBuffer) - 1);
480
481 char *argv[10];
482 int argc = setargs(handleBuffer, argv, 10);
483
484 if (argc <= 0) {
485 efiPrintf("invalid input");
486 return -1;
487 }
488
489 for (int i = 0; i < consoleActionCount; i++) {
490 TokenCallback *current = &consoleActions[i];
491 if (strEqual(argv[0], current->token)) {
492 if ((argc - 1) != getParameterCount(current->parameterType)) {
493 efiPrintf("Incorrect argument count %d, expected %d",
494 (argc - 1), getParameterCount(current->parameterType));
495 return -1;
496 }
497
498 /* skip commant name */
499 return handleActionWithParameter(current, argv + 1, argc - 1);
500 }
501 }
502
503 efiPrintf("unknown command [%s]", commandLine);
504 return -1;
505}
506
507/**
508 * @brief This function takes care of one command line once we have it
509 */
510void handleConsoleLine(char *line) {
511 if (line == NULL)
512 return; // error detected
513
514 int lineLength = std::strlen(line);
515 if (lineLength > MAX_CMD_LINE_LENGTH) {
516 // todo: better reaction to excessive line
517 efiPrintf("Long line?");
518 return;
519 }
520
521 int ret = handleConsoleLineInternal(line);
522
523 if (ret < 0) {
524 efiPrintf("failed to handle command [%s]", line);
525 return;
526 }
527
528 efiPrintf("confirmation_%s:%d", line, lineLength);
529}
pwm_settings ch[2]
void addConsoleActionSSSSS(const char *token, VoidCharPtrCharPtrCharPtrCharPtrCharPtr callback)
void addConsoleActionP(const char *token, VoidPtr callback, void *param)
void addConsoleActionFF(const char *token, VoidFloatFloat callback)
static TokenCallback consoleActions[CONSOLE_MAX_ACTIONS]
void addConsoleActionSP(const char *token, VoidCharPtrVoidPtr callback, void *param)
static void doAddAction(const char *token, action_type_e type, Void callback, void *param)
void handleConsoleLine(char *line)
This function takes care of one command line once we have it.
void addConsoleActionIP(const char *token, VoidIntVoidPtr callback, void *param)
static int consoleActionCount
void addConsoleActionF(const char *token, VoidFloat callback)
static int setargs(char *args, char **argv, int max_args)
static int getParameterCount(action_type_e parameterType)
void resetConsoleActions(void)
void addConsoleActionS(const char *token, VoidCharPtr callback)
void helpCommand(void)
This function prints out a list of all available commands.
void addConsoleActionNANF(const char *token, VoidFloat callback)
int findEndOfToken(const char *line)
void addConsoleAction(const char *token, Void callback)
Register console action without parameters.
void addConsoleActionII(const char *token, VoidIntInt callback)
Register a console command with two Integer parameters.
int tokenLength(const char *msgp)
void initConsoleLogic()
void addConsoleActionIIP(const char *token, VoidIntIntVoidPtr callback, void *param)
char * unquote(char *line)
void addConsoleActionSS(const char *token, VoidCharPtrCharPtr callback)
void addConsoleActionSSS(const char *token, VoidCharPtrCharPtrCharPtr callback)
static char handleBuffer[MAX_CMD_LINE_LENGTH+1]
void addConsoleActionI(const char *token, VoidInt callback)
Register a console command with one Integer parameter.
void addConsoleActionSSP(const char *token, VoidCharPtrCharPtrVoidPtr callback, void *param)
void addConsoleActionFFFF(const char *token, VoidFloatFloatFloatFloat callback)
static int handleConsoleLineInternal(const char *commandLine)
void addConsoleActionIF(const char *token, VoidIntFloat callback)
void addConsoleActionFFF(const char *token, VoidFloatFloatFloat callback)
void addConsoleActionFFP(const char *token, VoidFloatFloatVoidPtr callback, void *param)
int handleActionWithParameter(TokenCallback *current, char *argv[], int argc)
Command-line interface commands registry.
void(* VoidCharPtrCharPtr)(const char *, const char *)
void(* VoidFloat)(float)
void(* VoidCharPtrCharPtrVoidPtr)(const char *, const char *, void *)
void(* VoidIntInt)(int, int)
void(* Void)(void)
void(* VoidFloatFloatFloatFloat)(float, float, float, float)
void(* VoidIntIntVoidPtr)(int, int, void *)
void(* VoidCharPtrVoidPtr)(const char *, void *)
void(* VoidPtr)(void *)
void(* VoidIntVoidPtr)(int, void *)
void(* VoidCharPtr)(const char *)
void(* VoidInt)(int)
void(* VoidFloatFloatFloat)(float, float, float)
void(* VoidFloatFloat)(float, float)
void(* VoidCharPtrCharPtrCharPtrCharPtrCharPtr)(const char *, const char *, const char *, const char *, const char *)
void(* VoidIntFloat)(int, float)
void(* VoidCharPtrCharPtrCharPtr)(const char *, const char *, const char *)
void(* VoidFloatFloatVoidPtr)(float, float, void *)
action_type_e
@ STRING5_PARAMETER
@ NO_PARAMETER_P
@ FLOAT_FLOAT_FLOAT_PARAMETER
@ FLOAT_FLOAT_PARAMETER_P
@ ONE_PARAMETER_P
@ NO_PARAMETER
@ FLOAT_PARAMETER
@ FLOAT_PARAMETER_NAN_ALLOWED
@ TWO_INTS_PARAMETER_P
@ STRING_PARAMETER_P
@ TWO_INTS_PARAMETER
@ STRING2_PARAMETER
@ INT_FLOAT_PARAMETER
@ STRING2_PARAMETER_P
@ FLOAT_FLOAT_PARAMETER
@ FLOAT_FLOAT_FLOAT_FLOAT_PARAMETER
@ STRING_PARAMETER
@ STRING3_PARAMETER
@ ONE_PARAMETER
void onCliOverflowError()
void onCliDuplicateError(const char *token)
void onCliCaseError(const char *token)
value1("SENT ch0 value1", SensorCategory.SENSOR_INPUTS, FieldType.INT16, 1974, 1.0, 0.0, 4095.0, "RAW")
action_type_e parameterType
void(* callback)(void)
const char * token
uint16_t count
Definition tunerstudio.h:1
static tstrWifiInitParam param