12#if (OS_CFG_USE_SHELL != 0u)
14#define AKOS_SHELL_SIG_RX_READY 1
15#define AKOS_SHELL_TOP_REFRESH_TICKS 1000u
16#define AKOS_SHELL_TOP_MAX_THREADS UINT8_MAX
21static volatile uint8_t shell_rx_head;
22static volatile uint8_t shell_rx_tail;
24static volatile bool shell_rx_notified;
27static uint8_t shell_line_length;
28static bool shell_top_active;
29static bool shell_top_has_snapshot;
30static uint32_t shell_top_prev_idle_ticks;
31static uint32_t shell_top_prev_total_ticks;
32static uint32_t shell_top_prev_thread_ticks[AKOS_SHELL_TOP_MAX_THREADS];
33static uint8_t shell_top_thread_prio[AKOS_SHELL_TOP_MAX_THREADS];
34static uint32_t shell_top_thread_load[AKOS_SHELL_TOP_MAX_THREADS];
35static const char *shell_top_thread_name[AKOS_SHELL_TOP_MAX_THREADS];
37static void shell_prompt(
void);
38static void shell_process_rx(
void);
39static void shell_process_byte(uint8_t
byte);
40static void shell_execute_line(
void);
41static int shell_tokenize(
char *line,
char **argv,
int argv_max);
42static void shell_show_help(
void);
43static void shell_show_top(
void);
44static void shell_top_enter(
void);
45static void shell_top_exit(
void);
46static bool shell_match_path(
const char *path,
int argc,
char **argv,
int *consumed_argc);
48void akos_shell_feature_init(
void)
52 shell_line_length = 0u;
53 shell_rx_notified =
false;
54 shell_top_active =
false;
55 shell_top_has_snapshot =
false;
56 shell_top_prev_idle_ticks = 0u;
57 shell_top_prev_total_ticks = 0u;
58 memset(shell_top_prev_thread_ticks, 0x00,
sizeof(shell_top_prev_thread_ticks));
59 memset(shell_top_thread_prio, 0x00,
sizeof(shell_top_thread_prio));
60 memset(shell_top_thread_load, 0x00,
sizeof(shell_top_thread_load));
61 memset(shell_top_thread_name, 0x00,
sizeof(shell_top_thread_name));
64void akos_shell_thread(
void *p_arg)
68 SYS_PRINT(
"\r\n[akos-shell] ready\r\n");
92void akos_shell_rx_isr(uint8_t
byte)
97 if (next != shell_rx_tail)
99 shell_rx_buffer[shell_rx_head] = byte;
100 shell_rx_head = next;
103 if ((shell_thread_id == UINT8_MAX) || shell_rx_notified)
108 shell_rx_notified =
true;
112static void shell_process_rx(
void)
118 if (shell_rx_tail == shell_rx_head)
120 shell_rx_notified =
false;
121 if (shell_rx_tail == shell_rx_head)
125 shell_rx_notified =
true;
128 byte = shell_rx_buffer[shell_rx_tail];
130 shell_process_byte(
byte);
134static void shell_process_byte(uint8_t
byte)
136 if (shell_top_active)
138 if ((
byte ==
'q') || (
byte ==
'Q') || (
byte == 0x03u))
145 if ((
byte ==
'\r') || (
byte ==
'\n'))
148 shell_line_buffer[shell_line_length] =
'\0';
149 shell_execute_line();
150 shell_line_length = 0u;
151 if (!shell_top_active)
158 if (((
byte ==
'\b') || (
byte == 0x7Fu)) && (shell_line_length > 0u))
161 shell_line_buffer[shell_line_length] =
'\0';
166 if ((
byte < 0x20u) || (
byte > 0x7Eu))
173 shell_line_buffer[shell_line_length++] = (char)
byte;
174 shell_line_buffer[shell_line_length] =
'\0';
175 SYS_PRINT(
"%c",
byte);
179static void shell_execute_line(
void)
186 if (shell_line_length == 0u)
197 if (strcmp(argv[0],
"help") == 0)
203 if (strcmp(argv[0],
"clear") == 0)
205 SYS_PRINT(
"\033[2J\033[H");
209 if (strcmp(argv[0],
"top") == 0)
215 for (; cmd < __stop_shell_cmd_desc; ++cmd)
217 if ((cmd->handler != NULL) && shell_match_path(cmd->path, argc, argv, &consumed_argc))
219 (void)cmd->handler(argc - consumed_argc, &argv[consumed_argc]);
224 SYS_PRINT(
"Unknown command: %s\r\n", argv[0]);
227static int shell_tokenize(
char *line,
char **argv,
int argv_max)
230 bool in_token =
false;
232 while ((*line !=
'\0') && (argc < argv_max))
234 if ((*line ==
' ') || (*line ==
'\t'))
251static void shell_show_help(
void)
255 SYS_PRINT(
" %-16s %s\r\n",
"help",
"Show available commands");
256 SYS_PRINT(
" %-16s %s\r\n",
"clear",
"Clear terminal screen");
257 SYS_PRINT(
" %-16s %s\r\n",
"top",
"Live MCU load screen, press q to exit");
259 for (; cmd < __stop_shell_cmd_desc; ++cmd)
261 SYS_PRINT(
" %-16s %s\r\n", cmd->path, cmd->help);
265static void shell_show_top(
void)
267 uint32_t idle_ticks_now;
268 uint32_t total_ticks_now;
270 uint32_t total_delta;
272 uint8_t runtime_count;
273 uint8_t runtime_limit;
276 uint8_t idle_thread_id;
277 uint8_t shell_thread_id;
278 uint8_t timer_thread_id;
282 SYS_PRINT(
"\033[2J\033[H");
283 SYS_PRINT(
"AKOS top - press q to exit\r\n\r\n");
285 if (!shell_top_has_snapshot)
287 shell_top_prev_idle_ticks = idle_ticks_now;
288 shell_top_prev_total_ticks = total_ticks_now;
290 runtime_limit = runtime_count;
291 for (index = 0u; index < runtime_limit; ++index)
295 shell_top_prev_thread_ticks[index] = snapshot.run_ticks;
297 shell_top_has_snapshot =
true;
298 SYS_PRINT(
"cpu load : sampling...\r\n");
302 idle_delta = idle_ticks_now - shell_top_prev_idle_ticks;
303 total_delta = total_ticks_now - shell_top_prev_total_ticks;
305 shell_top_prev_idle_ticks = idle_ticks_now;
306 shell_top_prev_total_ticks = total_ticks_now;
308 if (total_delta == 0u)
314 uint32_t busy_delta = (idle_delta >= total_delta) ? 0u : (total_delta - idle_delta);
315 uint32_t load = (busy_delta * 100u) / total_delta;
316 cpu_load = (load > 100u) ? 100u : (uint8_t)load;
319 SYS_PRINT(
"total cpu load : %u%%\r\n\r\n", (
unsigned)cpu_load);
320 SYS_PRINT(
"%-5s %-20s %s\r\n",
"prio",
"name",
"load");
323 runtime_limit = runtime_count;
327 for (index = 0u; index < runtime_limit; ++index)
332 if (snapshot.id == UINT8_MAX)
337 uint32_t thread_delta = snapshot.run_ticks - shell_top_prev_thread_ticks[index];
338 shell_top_prev_thread_ticks[index] = snapshot.run_ticks;
339 shell_top_thread_prio[index] = snapshot.prio;
340 shell_top_thread_name[index] = snapshot.name;
341 shell_top_thread_load[index] = (total_delta == 0u) ? 0u : ((thread_delta * 100u) / total_delta);
346 for (index = 0u; index < runtime_limit; ++index)
351 if ((snapshot.id == UINT8_MAX) ||
352 (snapshot.id == idle_thread_id) ||
353 (snapshot.id == shell_thread_id) ||
354 (snapshot.id == timer_thread_id) ||
355 (snapshot.prio != prio))
360 SYS_PRINT(
"%-5u %-20s %lu%%\r\n",
361 (
unsigned)shell_top_thread_prio[index],
362 (shell_top_thread_name[index] != NULL) ? shell_top_thread_name[index] :
"-",
363 (
unsigned long)shell_top_thread_load[index]);
367 SYS_PRINT(
"--------------------------------\r\n");
370 for (index = 0u; index < runtime_limit; ++index)
375 if ((snapshot.id == UINT8_MAX) ||
376 ((snapshot.id != shell_thread_id) &&
377 (snapshot.id != timer_thread_id) &&
378 (snapshot.id != idle_thread_id)) ||
379 (snapshot.prio != prio))
384 SYS_PRINT(
"%-5u %-20s %lu%%\r\n",
385 (
unsigned)shell_top_thread_prio[index],
386 (shell_top_thread_name[index] != NULL) ? shell_top_thread_name[index] :
"-",
387 (
unsigned long)shell_top_thread_load[index]);
392static void shell_top_enter(
void)
394 shell_top_active =
true;
395 shell_top_has_snapshot =
false;
396 memset(shell_top_prev_thread_ticks, 0x00,
sizeof(shell_top_prev_thread_ticks));
397 memset(shell_top_thread_prio, 0x00,
sizeof(shell_top_thread_prio));
398 memset(shell_top_thread_load, 0x00,
sizeof(shell_top_thread_load));
399 memset(shell_top_thread_name, 0x00,
sizeof(shell_top_thread_name));
403static void shell_top_exit(
void)
405 shell_top_active =
false;
406 shell_top_has_snapshot =
false;
407 SYS_PRINT(
"\033[2J\033[H");
411static void shell_prompt(
void)
416static bool shell_match_path(
const char *path,
int argc,
char **argv,
int *consumed_argc)
420 while (*path !=
'\0')
422 const char *token_start;
423 size_t token_len = 0u;
435 if (arg_index >= argc)
441 while ((path[token_len] !=
'\0') && (path[token_len] !=
' '))
446 if ((strlen(argv[arg_index]) != token_len) ||
447 (strncmp(argv[arg_index], token_start, token_len) != 0))
456 *consumed_argc = arg_index;
462void akos_shell_feature_init(
void)
466void akos_shell_thread(
void *p_arg)
474void akos_shell_rx_isr(uint8_t
byte)
#define OS_CFG_SHELL_RX_BUFFER_SIZE
#define OS_CFG_SHELL_PROMPT_NAME
#define OS_CFG_SHELL_MAX_ARGS
#define OS_CFG_SHELL_LINE_BUFFER_SIZE
Message object and message queue APIs.
void akos_message_free(msg_t *p_msg)
Return message to message pool.
int32_t akos_message_get_pure_data(msg_t *p_msg)
Get signal field from pure message.
Message object stored in queues.
Thread scheduling and thread messaging APIs.
msg_t * akos_thread_wait_for_msg(uint32_t time_out)
Wait for message from current thread queue.
uint8_t akos_thread_get_timer_thread_id(void)
Get the runtime thread ID assigned to the timer thread.
uint8_t akos_thread_get_runtime_count(void)
Get number of runtime thread slots, including internal threads.
void akos_thread_get_runtime_totals(uint32_t *p_idle_ticks, uint32_t *p_total_ticks)
Snapshot accumulated runtime counters.
uint8_t akos_thread_get_shell_thread_id(void)
Get the runtime thread ID assigned to the shell thread.
uint8_t akos_thread_get_idle_thread_id(void)
Get the runtime thread ID assigned to the idle thread.
void akos_thread_post_msg_pure(uint8_t des_thread_id, int32_t sig)
Post pure signal message to destination thread.
void akos_thread_get_runtime_snapshot(uint8_t index, thread_runtime_snapshot_t *p_snapshot)
Snapshot one runtime thread slot by index.