2018-08-09 09:56:10 +02:00
|
|
|
/*
|
|
|
|
* Copyright (c) 2018 Nordic Semiconductor ASA
|
|
|
|
*
|
|
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
|
|
*/
|
|
|
|
|
2019-01-11 15:08:55 +01:00
|
|
|
#include <ctype.h>
|
2018-08-09 09:56:10 +02:00
|
|
|
#include "shell_ops.h"
|
|
|
|
|
2020-12-07 13:22:35 +01:00
|
|
|
void z_shell_op_cursor_vert_move(const struct shell *shell, int32_t delta)
|
2018-08-09 09:56:10 +02:00
|
|
|
{
|
|
|
|
if (delta != 0) {
|
2020-12-07 13:22:35 +01:00
|
|
|
z_shell_raw_fprintf(shell->fprintf_ctx, "\033[%d%c",
|
|
|
|
delta > 0 ? delta : -delta,
|
|
|
|
delta > 0 ? 'A' : 'B');
|
2018-08-09 09:56:10 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-12-07 13:22:35 +01:00
|
|
|
void z_shell_op_cursor_horiz_move(const struct shell *shell, int32_t delta)
|
2018-08-09 09:56:10 +02:00
|
|
|
{
|
|
|
|
if (delta != 0) {
|
2020-12-07 13:22:35 +01:00
|
|
|
z_shell_raw_fprintf(shell->fprintf_ctx, "\033[%d%c",
|
|
|
|
delta > 0 ? delta : -delta,
|
|
|
|
delta > 0 ? 'C' : 'D');
|
2018-08-09 09:56:10 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Function returns true if command length is equal to multiplicity of terminal
|
|
|
|
* width.
|
|
|
|
*/
|
|
|
|
static inline bool full_line_cmd(const struct shell *shell)
|
|
|
|
{
|
2020-12-07 16:10:11 +01:00
|
|
|
return ((shell->ctx->cmd_buff_len + z_shell_strlen(shell->ctx->prompt))
|
2019-03-26 19:57:45 -06:00
|
|
|
% shell->ctx->vt100_ctx.cons.terminal_wid == 0U);
|
2018-08-09 09:56:10 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Function returns true if cursor is at beginning of an empty line. */
|
2020-12-07 13:22:35 +01:00
|
|
|
bool z_shell_cursor_in_empty_line(const struct shell *shell)
|
2018-08-09 09:56:10 +02:00
|
|
|
{
|
2020-12-07 16:10:11 +01:00
|
|
|
return ((shell->ctx->cmd_buff_pos + z_shell_strlen(shell->ctx->prompt))
|
2019-03-26 19:57:45 -06:00
|
|
|
% shell->ctx->vt100_ctx.cons.terminal_wid == 0U);
|
2018-08-09 09:56:10 +02:00
|
|
|
}
|
|
|
|
|
2020-12-07 13:22:35 +01:00
|
|
|
void z_shell_op_cond_next_line(const struct shell *shell)
|
2018-08-09 09:56:10 +02:00
|
|
|
{
|
2020-12-07 13:22:35 +01:00
|
|
|
if (z_shell_cursor_in_empty_line(shell) || full_line_cmd(shell)) {
|
|
|
|
z_cursor_next_line_move(shell);
|
2018-08-09 09:56:10 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-12-07 13:22:35 +01:00
|
|
|
void z_shell_op_cursor_position_synchronize(const struct shell *shell)
|
2018-08-09 09:56:10 +02:00
|
|
|
{
|
|
|
|
struct shell_multiline_cons *cons = &shell->ctx->vt100_ctx.cons;
|
|
|
|
bool last_line;
|
|
|
|
|
2020-12-07 16:10:11 +01:00
|
|
|
z_shell_multiline_data_calc(cons, shell->ctx->cmd_buff_pos,
|
|
|
|
shell->ctx->cmd_buff_len);
|
2018-08-09 09:56:10 +02:00
|
|
|
last_line = (cons->cur_y == cons->cur_y_end);
|
|
|
|
|
|
|
|
/* In case cursor reaches the bottom line of a terminal, it will
|
|
|
|
* be moved to the next line.
|
|
|
|
*/
|
|
|
|
if (full_line_cmd(shell)) {
|
2020-12-07 13:22:35 +01:00
|
|
|
z_cursor_next_line_move(shell);
|
2018-08-09 09:56:10 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if (last_line) {
|
2020-12-07 13:22:35 +01:00
|
|
|
z_shell_op_cursor_horiz_move(shell, cons->cur_x -
|
2018-08-09 09:56:10 +02:00
|
|
|
cons->cur_x_end);
|
|
|
|
} else {
|
2020-12-07 13:22:35 +01:00
|
|
|
z_shell_op_cursor_vert_move(shell, cons->cur_y_end - cons->cur_y);
|
|
|
|
z_shell_op_cursor_horiz_move(shell, cons->cur_x -
|
2018-08-09 09:56:10 +02:00
|
|
|
cons->cur_x_end);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-12-07 13:22:35 +01:00
|
|
|
void z_shell_op_cursor_move(const struct shell *shell, int16_t val)
|
2018-08-09 09:56:10 +02:00
|
|
|
{
|
|
|
|
struct shell_multiline_cons *cons = &shell->ctx->vt100_ctx.cons;
|
2020-05-27 11:26:57 -05:00
|
|
|
uint16_t new_pos = shell->ctx->cmd_buff_pos + val;
|
|
|
|
int32_t row_span;
|
|
|
|
int32_t col_span;
|
2018-08-09 09:56:10 +02:00
|
|
|
|
2020-12-07 16:10:11 +01:00
|
|
|
z_shell_multiline_data_calc(cons, shell->ctx->cmd_buff_pos,
|
|
|
|
shell->ctx->cmd_buff_len);
|
2018-08-09 09:56:10 +02:00
|
|
|
|
|
|
|
/* Calculate the new cursor. */
|
2020-12-07 16:10:11 +01:00
|
|
|
row_span = z_row_span_with_buffer_offsets_get(
|
|
|
|
&shell->ctx->vt100_ctx.cons,
|
|
|
|
shell->ctx->cmd_buff_pos,
|
|
|
|
new_pos);
|
|
|
|
col_span = z_column_span_with_buffer_offsets_get(
|
|
|
|
&shell->ctx->vt100_ctx.cons,
|
|
|
|
shell->ctx->cmd_buff_pos,
|
|
|
|
new_pos);
|
2018-08-09 09:56:10 +02:00
|
|
|
|
2020-12-07 13:22:35 +01:00
|
|
|
z_shell_op_cursor_vert_move(shell, -row_span);
|
|
|
|
z_shell_op_cursor_horiz_move(shell, col_span);
|
2018-08-09 09:56:10 +02:00
|
|
|
shell->ctx->cmd_buff_pos = new_pos;
|
|
|
|
}
|
|
|
|
|
2020-05-27 11:26:57 -05:00
|
|
|
static uint16_t shift_calc(const char *str, uint16_t pos, uint16_t len, int16_t sign)
|
2019-01-11 15:08:55 +01:00
|
|
|
{
|
|
|
|
bool found = false;
|
2020-05-27 11:26:57 -05:00
|
|
|
uint16_t ret = 0U;
|
|
|
|
uint16_t idx;
|
2019-01-11 15:08:55 +01:00
|
|
|
|
|
|
|
while (1) {
|
|
|
|
idx = pos + ret * sign;
|
2019-03-26 19:57:45 -06:00
|
|
|
if (((idx == 0U) && (sign < 0)) ||
|
2019-01-11 15:08:55 +01:00
|
|
|
((idx == len) && (sign > 0))) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (isalnum((int)str[idx]) != 0) {
|
|
|
|
found = true;
|
|
|
|
} else {
|
|
|
|
if (found) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
ret++;
|
|
|
|
}
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2020-12-07 13:22:35 +01:00
|
|
|
void z_shell_op_cursor_word_move(const struct shell *shell, int16_t val)
|
2019-01-11 15:08:55 +01:00
|
|
|
{
|
2020-05-27 11:26:57 -05:00
|
|
|
int16_t shift;
|
|
|
|
int16_t sign;
|
2019-01-11 15:08:55 +01:00
|
|
|
|
|
|
|
if (val < 0) {
|
|
|
|
val = -val;
|
|
|
|
sign = -1;
|
|
|
|
} else {
|
|
|
|
sign = 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
while (val--) {
|
|
|
|
shift = shift_calc(shell->ctx->cmd_buff,
|
|
|
|
shell->ctx->cmd_buff_pos,
|
|
|
|
shell->ctx->cmd_buff_len, sign);
|
2020-12-07 13:22:35 +01:00
|
|
|
z_shell_op_cursor_move(shell, sign * shift);
|
2019-01-11 15:08:55 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-12-07 13:22:35 +01:00
|
|
|
void z_shell_op_word_remove(const struct shell *shell)
|
2018-08-09 09:56:10 +02:00
|
|
|
{
|
|
|
|
char *str = &shell->ctx->cmd_buff[shell->ctx->cmd_buff_pos - 1];
|
|
|
|
char *str_start = &shell->ctx->cmd_buff[0];
|
2020-05-27 11:26:57 -05:00
|
|
|
uint16_t chars_to_delete;
|
2018-08-09 09:56:10 +02:00
|
|
|
|
|
|
|
/* Line must not be empty and cursor must not be at 0 to continue. */
|
|
|
|
if ((shell->ctx->cmd_buff_len == 0) ||
|
|
|
|
(shell->ctx->cmd_buff_pos == 0)) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Start at the current position. */
|
2018-11-29 11:23:03 -08:00
|
|
|
chars_to_delete = 0U;
|
2018-08-09 09:56:10 +02:00
|
|
|
|
|
|
|
/* Look back for all spaces then for non-spaces. */
|
|
|
|
while ((str >= str_start) && (*str == ' ')) {
|
|
|
|
++chars_to_delete;
|
|
|
|
--str;
|
|
|
|
}
|
|
|
|
|
|
|
|
while ((str >= str_start) && (*str != ' ')) {
|
|
|
|
++chars_to_delete;
|
|
|
|
--str;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Manage the buffer. */
|
|
|
|
memmove(str + 1, str + 1 + chars_to_delete,
|
|
|
|
shell->ctx->cmd_buff_len - chars_to_delete);
|
|
|
|
shell->ctx->cmd_buff_len -= chars_to_delete;
|
|
|
|
shell->ctx->cmd_buff[shell->ctx->cmd_buff_len] = '\0';
|
|
|
|
|
|
|
|
/* Update display. */
|
2020-12-07 13:22:35 +01:00
|
|
|
z_shell_op_cursor_move(shell, -chars_to_delete);
|
|
|
|
z_cursor_save(shell);
|
2020-12-06 11:22:27 +01:00
|
|
|
z_shell_fprintf(shell, SHELL_NORMAL, "%s", str + 1);
|
2020-12-07 13:22:35 +01:00
|
|
|
z_clear_eos(shell);
|
|
|
|
z_cursor_restore(shell);
|
2018-08-09 09:56:10 +02:00
|
|
|
}
|
|
|
|
|
2020-12-07 13:22:35 +01:00
|
|
|
void z_shell_op_cursor_home_move(const struct shell *shell)
|
2018-08-09 09:56:10 +02:00
|
|
|
{
|
2020-12-07 13:22:35 +01:00
|
|
|
z_shell_op_cursor_move(shell, -shell->ctx->cmd_buff_pos);
|
2018-08-09 09:56:10 +02:00
|
|
|
}
|
|
|
|
|
2020-12-07 13:22:35 +01:00
|
|
|
void z_shell_op_cursor_end_move(const struct shell *shell)
|
2018-08-09 09:56:10 +02:00
|
|
|
{
|
2020-12-07 13:22:35 +01:00
|
|
|
z_shell_op_cursor_move(shell, shell->ctx->cmd_buff_len -
|
2018-08-09 09:56:10 +02:00
|
|
|
shell->ctx->cmd_buff_pos);
|
|
|
|
}
|
|
|
|
|
2020-12-07 13:22:35 +01:00
|
|
|
void z_shell_op_left_arrow(const struct shell *shell)
|
2018-08-09 09:56:10 +02:00
|
|
|
{
|
|
|
|
if (shell->ctx->cmd_buff_pos > 0) {
|
2020-12-07 13:22:35 +01:00
|
|
|
z_shell_op_cursor_move(shell, -1);
|
2018-08-09 09:56:10 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-12-07 13:22:35 +01:00
|
|
|
void z_shell_op_right_arrow(const struct shell *shell)
|
2018-08-09 09:56:10 +02:00
|
|
|
{
|
|
|
|
if (shell->ctx->cmd_buff_pos < shell->ctx->cmd_buff_len) {
|
2020-12-07 13:22:35 +01:00
|
|
|
z_shell_op_cursor_move(shell, 1);
|
2018-08-09 09:56:10 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-05-27 11:26:57 -05:00
|
|
|
static void reprint_from_cursor(const struct shell *shell, uint16_t diff,
|
2018-08-09 09:56:10 +02:00
|
|
|
bool data_removed)
|
|
|
|
{
|
|
|
|
/* Clear eos is needed only when newly printed command is shorter than
|
|
|
|
* previously printed command. This can happen when delete or backspace
|
|
|
|
* was called.
|
|
|
|
*
|
|
|
|
* Such condition is useful for Bluetooth devices to save number of
|
|
|
|
* bytes transmitted between terminal and device.
|
|
|
|
*/
|
|
|
|
if (data_removed) {
|
2020-12-07 13:22:35 +01:00
|
|
|
z_clear_eos(shell);
|
2018-08-09 09:56:10 +02:00
|
|
|
}
|
|
|
|
|
2021-03-04 11:28:05 -08:00
|
|
|
if (z_flag_obscure_get(shell)) {
|
|
|
|
int len = strlen(&shell->ctx->cmd_buff[shell->ctx->cmd_buff_pos]);
|
|
|
|
|
|
|
|
while (len--) {
|
|
|
|
z_shell_raw_fprintf(shell->fprintf_ctx, "*");
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
z_shell_fprintf(shell, SHELL_NORMAL, "%s",
|
|
|
|
&shell->ctx->cmd_buff[shell->ctx->cmd_buff_pos]);
|
|
|
|
}
|
2018-08-09 09:56:10 +02:00
|
|
|
shell->ctx->cmd_buff_pos = shell->ctx->cmd_buff_len;
|
|
|
|
|
|
|
|
if (full_line_cmd(shell)) {
|
|
|
|
if (((data_removed) && (diff > 0)) || (!data_removed)) {
|
2020-12-07 13:22:35 +01:00
|
|
|
z_cursor_next_line_move(shell);
|
2018-08-09 09:56:10 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-12-07 13:22:35 +01:00
|
|
|
z_shell_op_cursor_move(shell, -diff);
|
2018-08-09 09:56:10 +02:00
|
|
|
}
|
|
|
|
|
2020-05-27 11:26:57 -05:00
|
|
|
static void data_insert(const struct shell *shell, const char *data, uint16_t len)
|
2018-08-09 09:56:10 +02:00
|
|
|
{
|
2020-05-27 11:26:57 -05:00
|
|
|
uint16_t after = shell->ctx->cmd_buff_len - shell->ctx->cmd_buff_pos;
|
2018-08-09 09:56:10 +02:00
|
|
|
char *curr_pos = &shell->ctx->cmd_buff[shell->ctx->cmd_buff_pos];
|
|
|
|
|
|
|
|
if ((shell->ctx->cmd_buff_len + len) >= CONFIG_SHELL_CMD_BUFF_SIZE) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
memmove(curr_pos + len, curr_pos, after);
|
|
|
|
memcpy(curr_pos, data, len);
|
|
|
|
shell->ctx->cmd_buff_len += len;
|
|
|
|
shell->ctx->cmd_buff[shell->ctx->cmd_buff_len] = '\0';
|
|
|
|
|
2020-12-07 13:22:35 +01:00
|
|
|
if (!z_flag_echo_get(shell)) {
|
2018-08-09 09:56:10 +02:00
|
|
|
shell->ctx->cmd_buff_pos += len;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
reprint_from_cursor(shell, after, false);
|
|
|
|
}
|
|
|
|
|
2019-01-28 19:06:58 +01:00
|
|
|
static void char_replace(const struct shell *shell, char data)
|
2018-08-09 09:56:10 +02:00
|
|
|
{
|
|
|
|
shell->ctx->cmd_buff[shell->ctx->cmd_buff_pos++] = data;
|
2019-01-27 13:09:39 +01:00
|
|
|
|
2020-12-07 13:22:35 +01:00
|
|
|
if (!z_flag_echo_get(shell)) {
|
2019-01-27 13:09:39 +01:00
|
|
|
return;
|
|
|
|
}
|
2021-03-04 11:28:05 -08:00
|
|
|
if (z_flag_obscure_get(shell)) {
|
|
|
|
data = '*';
|
|
|
|
}
|
2019-01-27 13:09:39 +01:00
|
|
|
|
2020-12-07 13:22:35 +01:00
|
|
|
z_shell_raw_fprintf(shell->fprintf_ctx, "%c", data);
|
|
|
|
if (z_shell_cursor_in_empty_line(shell)) {
|
|
|
|
z_cursor_next_line_move(shell);
|
2018-08-09 09:56:10 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-12-07 13:22:35 +01:00
|
|
|
void z_shell_op_char_insert(const struct shell *shell, char data)
|
2018-08-09 09:56:10 +02:00
|
|
|
{
|
|
|
|
if (shell->ctx->internal.flags.insert_mode &&
|
|
|
|
(shell->ctx->cmd_buff_len != shell->ctx->cmd_buff_pos)) {
|
|
|
|
char_replace(shell, data);
|
|
|
|
} else {
|
|
|
|
data_insert(shell, &data, 1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-12-07 13:22:35 +01:00
|
|
|
void z_shell_op_char_backspace(const struct shell *shell)
|
2018-08-09 09:56:10 +02:00
|
|
|
{
|
|
|
|
if ((shell->ctx->cmd_buff_len == 0) ||
|
|
|
|
(shell->ctx->cmd_buff_pos == 0)) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2020-12-07 13:22:35 +01:00
|
|
|
z_shell_op_cursor_move(shell, -1);
|
|
|
|
z_shell_op_char_delete(shell);
|
2018-08-09 09:56:10 +02:00
|
|
|
}
|
|
|
|
|
2020-12-07 13:22:35 +01:00
|
|
|
void z_shell_op_char_delete(const struct shell *shell)
|
2018-08-09 09:56:10 +02:00
|
|
|
{
|
2020-05-27 11:26:57 -05:00
|
|
|
uint16_t diff = shell->ctx->cmd_buff_len - shell->ctx->cmd_buff_pos;
|
2018-08-09 09:56:10 +02:00
|
|
|
char *str = &shell->ctx->cmd_buff[shell->ctx->cmd_buff_pos];
|
|
|
|
|
2019-03-26 19:57:45 -06:00
|
|
|
if (diff == 0U) {
|
2018-08-09 09:56:10 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
memmove(str, str + 1, diff);
|
|
|
|
--shell->ctx->cmd_buff_len;
|
|
|
|
reprint_from_cursor(shell, --diff, true);
|
|
|
|
}
|
|
|
|
|
2020-12-07 13:22:35 +01:00
|
|
|
void z_shell_op_delete_from_cursor(const struct shell *shell)
|
2019-01-11 15:08:55 +01:00
|
|
|
{
|
|
|
|
shell->ctx->cmd_buff_len = shell->ctx->cmd_buff_pos;
|
|
|
|
shell->ctx->cmd_buff[shell->ctx->cmd_buff_pos] = '\0';
|
|
|
|
|
2020-12-07 13:22:35 +01:00
|
|
|
z_clear_eos(shell);
|
2019-01-11 15:08:55 +01:00
|
|
|
}
|
|
|
|
|
2020-12-07 13:22:35 +01:00
|
|
|
void z_shell_op_completion_insert(const struct shell *shell,
|
|
|
|
const char *compl,
|
|
|
|
uint16_t compl_len)
|
2018-08-09 09:56:10 +02:00
|
|
|
{
|
|
|
|
data_insert(shell, compl, compl_len);
|
|
|
|
}
|
2018-11-26 17:09:56 +01:00
|
|
|
|
2020-12-07 13:22:35 +01:00
|
|
|
void z_shell_cmd_line_erase(const struct shell *shell)
|
2018-12-13 10:26:49 +01:00
|
|
|
{
|
2020-12-07 16:10:11 +01:00
|
|
|
z_shell_multiline_data_calc(&shell->ctx->vt100_ctx.cons,
|
|
|
|
shell->ctx->cmd_buff_pos,
|
|
|
|
shell->ctx->cmd_buff_len);
|
2020-12-07 13:22:35 +01:00
|
|
|
z_shell_op_cursor_horiz_move(shell,
|
2019-01-29 11:40:08 +01:00
|
|
|
-(shell->ctx->vt100_ctx.cons.cur_x - 1));
|
2020-12-07 13:22:35 +01:00
|
|
|
z_shell_op_cursor_vert_move(shell, shell->ctx->vt100_ctx.cons.cur_y - 1);
|
2018-12-13 10:26:49 +01:00
|
|
|
|
2020-12-07 13:22:35 +01:00
|
|
|
z_clear_eos(shell);
|
2018-12-13 10:26:49 +01:00
|
|
|
}
|
|
|
|
|
2019-02-01 14:15:44 +01:00
|
|
|
static void print_prompt(const struct shell *shell)
|
|
|
|
{
|
2020-12-06 11:22:27 +01:00
|
|
|
z_shell_fprintf(shell, SHELL_INFO, "%s", shell->ctx->prompt);
|
2019-02-01 14:15:44 +01:00
|
|
|
}
|
|
|
|
|
2020-12-07 13:22:35 +01:00
|
|
|
void z_shell_print_cmd(const struct shell *shell)
|
2019-02-01 14:15:44 +01:00
|
|
|
{
|
2020-12-07 13:22:35 +01:00
|
|
|
z_shell_raw_fprintf(shell->fprintf_ctx, "%s", shell->ctx->cmd_buff);
|
2019-02-01 14:15:44 +01:00
|
|
|
}
|
|
|
|
|
2020-12-07 13:22:35 +01:00
|
|
|
void z_shell_print_prompt_and_cmd(const struct shell *shell)
|
2019-02-01 14:15:44 +01:00
|
|
|
{
|
|
|
|
print_prompt(shell);
|
|
|
|
|
2020-12-07 13:22:35 +01:00
|
|
|
if (z_flag_echo_get(shell)) {
|
|
|
|
z_shell_print_cmd(shell);
|
|
|
|
z_shell_op_cursor_position_synchronize(shell);
|
2019-02-01 14:15:44 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-11-26 17:09:56 +01:00
|
|
|
static void shell_pend_on_txdone(const struct shell *shell)
|
|
|
|
{
|
2018-12-05 13:25:43 +01:00
|
|
|
if (IS_ENABLED(CONFIG_MULTITHREADING) &&
|
|
|
|
(shell->ctx->state < SHELL_STATE_PANIC_MODE_ACTIVE)) {
|
2018-11-26 17:09:56 +01:00
|
|
|
k_poll(&shell->ctx->events[SHELL_SIGNAL_TXDONE], 1, K_FOREVER);
|
|
|
|
k_poll_signal_reset(&shell->ctx->signals[SHELL_SIGNAL_TXDONE]);
|
|
|
|
} else {
|
|
|
|
/* Blocking wait in case of bare metal. */
|
2020-12-07 13:22:35 +01:00
|
|
|
while (!z_flag_tx_rdy_get(shell)) {
|
2018-11-26 17:09:56 +01:00
|
|
|
}
|
2020-12-07 13:22:35 +01:00
|
|
|
z_flag_tx_rdy_set(shell, false);
|
2018-11-26 17:09:56 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-12-07 13:22:35 +01:00
|
|
|
void z_shell_write(const struct shell *shell, const void *data,
|
2018-11-26 17:09:56 +01:00
|
|
|
size_t length)
|
|
|
|
{
|
|
|
|
__ASSERT_NO_MSG(shell && data);
|
|
|
|
|
|
|
|
size_t offset = 0;
|
|
|
|
size_t tmp_cnt;
|
|
|
|
|
|
|
|
while (length) {
|
|
|
|
int err = shell->iface->api->write(shell->iface,
|
2020-05-27 11:26:57 -05:00
|
|
|
&((const uint8_t *) data)[offset], length,
|
2018-11-26 17:09:56 +01:00
|
|
|
&tmp_cnt);
|
|
|
|
(void)err;
|
|
|
|
__ASSERT_NO_MSG(err == 0);
|
|
|
|
__ASSERT_NO_MSG(length >= tmp_cnt);
|
|
|
|
offset += tmp_cnt;
|
|
|
|
length -= tmp_cnt;
|
|
|
|
if (tmp_cnt == 0 &&
|
|
|
|
(shell->ctx->state != SHELL_STATE_PANIC_MODE_ACTIVE)) {
|
|
|
|
shell_pend_on_txdone(shell);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Function shall be only used by the fprintf module. */
|
2020-12-06 11:22:27 +01:00
|
|
|
void z_shell_print_stream(const void *user_ctx, const char *data, size_t len)
|
2018-11-26 17:09:56 +01:00
|
|
|
{
|
2020-12-07 13:22:35 +01:00
|
|
|
z_shell_write((const struct shell *) user_ctx, data, len);
|
2018-11-26 17:09:56 +01:00
|
|
|
}
|
2018-12-13 10:26:49 +01:00
|
|
|
|
|
|
|
static void vt100_bgcolor_set(const struct shell *shell,
|
|
|
|
enum shell_vt100_color bgcolor)
|
|
|
|
{
|
|
|
|
if ((bgcolor == SHELL_NORMAL) ||
|
|
|
|
(shell->ctx->vt100_ctx.col.bgcol == bgcolor)) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* -1 because default value is first in enum */
|
2020-05-27 11:26:57 -05:00
|
|
|
uint8_t cmd[] = SHELL_VT100_BGCOLOR(bgcolor - 1);
|
2018-12-13 10:26:49 +01:00
|
|
|
|
|
|
|
shell->ctx->vt100_ctx.col.bgcol = bgcolor;
|
2020-12-07 13:22:35 +01:00
|
|
|
z_shell_raw_fprintf(shell->fprintf_ctx, "%s", cmd);
|
2018-12-13 10:26:49 +01:00
|
|
|
|
|
|
|
}
|
|
|
|
|
2020-12-07 13:22:35 +01:00
|
|
|
void z_shell_vt100_color_set(const struct shell *shell,
|
|
|
|
enum shell_vt100_color color)
|
2018-12-13 10:26:49 +01:00
|
|
|
{
|
|
|
|
|
|
|
|
if (shell->ctx->vt100_ctx.col.col == color) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
shell->ctx->vt100_ctx.col.col = color;
|
|
|
|
|
|
|
|
if (color != SHELL_NORMAL) {
|
|
|
|
|
2020-05-27 11:26:57 -05:00
|
|
|
uint8_t cmd[] = SHELL_VT100_COLOR(color - 1);
|
2018-12-13 10:26:49 +01:00
|
|
|
|
2020-12-07 13:22:35 +01:00
|
|
|
z_shell_raw_fprintf(shell->fprintf_ctx, "%s", cmd);
|
2018-12-13 10:26:49 +01:00
|
|
|
} else {
|
2020-05-27 11:26:57 -05:00
|
|
|
static const uint8_t cmd[] = SHELL_VT100_MODESOFF;
|
2018-12-13 10:26:49 +01:00
|
|
|
|
2020-12-07 13:22:35 +01:00
|
|
|
z_shell_raw_fprintf(shell->fprintf_ctx, "%s", cmd);
|
2018-12-13 10:26:49 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-12-07 13:22:35 +01:00
|
|
|
void z_shell_vt100_colors_restore(const struct shell *shell,
|
2018-12-13 10:26:49 +01:00
|
|
|
const struct shell_vt100_colors *color)
|
|
|
|
{
|
2020-12-07 13:22:35 +01:00
|
|
|
z_shell_vt100_color_set(shell, color->col);
|
2018-12-13 10:26:49 +01:00
|
|
|
vt100_bgcolor_set(shell, color->bgcol);
|
|
|
|
}
|
shell: allow commands to suspend shell thread
It was possible to deadlock the shell when command
suspended shell's thread and next another thread wanted
to print something on the shell.
To avoid that shell releases mutex before entering command
handler. Due to this change some adapations to shell
internal print functions have been applied.
This change addresses following usecase:
1. A command handler needs to call a (system) function which
communicate results via a callback, and this callback is expected
to print these results. The callback is called by the system from
another thread.
2. To achieve that, the handler needs to pass `struct shell *`
to callbacks, but also some other data specific to callback.
Thus, handles allocates some structure will those fields on
the stack.
3. The handler schedules this callback to be called.
4. As a reference to stack structure is passed to the callback,
the handler can't return immediately (or stack data will go out
of scope and will be overwritten).
5. So, the handler blocks waiting for callback to finish.
Previously, this scenario led to deadlock when the callback
trying or print to shell. With these changes, it just works,
as long as main handler and callback serialize there access
to the shell structure (i.e. when callback prints, the main
handler is blocked waiting for its completion).
Signed-off-by: Jakub Rzeszutko <jakub.rzeszutko@nordicsemi.no>
2019-02-12 15:38:16 +01:00
|
|
|
|
2020-12-06 11:22:27 +01:00
|
|
|
void z_shell_vfprintf(const struct shell *shell, enum shell_vt100_color color,
|
|
|
|
const char *fmt, va_list args)
|
shell: allow commands to suspend shell thread
It was possible to deadlock the shell when command
suspended shell's thread and next another thread wanted
to print something on the shell.
To avoid that shell releases mutex before entering command
handler. Due to this change some adapations to shell
internal print functions have been applied.
This change addresses following usecase:
1. A command handler needs to call a (system) function which
communicate results via a callback, and this callback is expected
to print these results. The callback is called by the system from
another thread.
2. To achieve that, the handler needs to pass `struct shell *`
to callbacks, but also some other data specific to callback.
Thus, handles allocates some structure will those fields on
the stack.
3. The handler schedules this callback to be called.
4. As a reference to stack structure is passed to the callback,
the handler can't return immediately (or stack data will go out
of scope and will be overwritten).
5. So, the handler blocks waiting for callback to finish.
Previously, this scenario led to deadlock when the callback
trying or print to shell. With these changes, it just works,
as long as main handler and callback serialize there access
to the shell structure (i.e. when callback prints, the main
handler is blocked waiting for its completion).
Signed-off-by: Jakub Rzeszutko <jakub.rzeszutko@nordicsemi.no>
2019-02-12 15:38:16 +01:00
|
|
|
{
|
|
|
|
if (IS_ENABLED(CONFIG_SHELL_VT100_COLORS) &&
|
|
|
|
shell->ctx->internal.flags.use_colors &&
|
|
|
|
(color != shell->ctx->vt100_ctx.col.col)) {
|
|
|
|
struct shell_vt100_colors col;
|
|
|
|
|
2020-12-07 13:22:35 +01:00
|
|
|
z_shell_vt100_colors_store(shell, &col);
|
|
|
|
z_shell_vt100_color_set(shell, color);
|
shell: allow commands to suspend shell thread
It was possible to deadlock the shell when command
suspended shell's thread and next another thread wanted
to print something on the shell.
To avoid that shell releases mutex before entering command
handler. Due to this change some adapations to shell
internal print functions have been applied.
This change addresses following usecase:
1. A command handler needs to call a (system) function which
communicate results via a callback, and this callback is expected
to print these results. The callback is called by the system from
another thread.
2. To achieve that, the handler needs to pass `struct shell *`
to callbacks, but also some other data specific to callback.
Thus, handles allocates some structure will those fields on
the stack.
3. The handler schedules this callback to be called.
4. As a reference to stack structure is passed to the callback,
the handler can't return immediately (or stack data will go out
of scope and will be overwritten).
5. So, the handler blocks waiting for callback to finish.
Previously, this scenario led to deadlock when the callback
trying or print to shell. With these changes, it just works,
as long as main handler and callback serialize there access
to the shell structure (i.e. when callback prints, the main
handler is blocked waiting for its completion).
Signed-off-by: Jakub Rzeszutko <jakub.rzeszutko@nordicsemi.no>
2019-02-12 15:38:16 +01:00
|
|
|
|
2020-12-06 11:22:27 +01:00
|
|
|
z_shell_fprintf_fmt(shell->fprintf_ctx, fmt, args);
|
shell: allow commands to suspend shell thread
It was possible to deadlock the shell when command
suspended shell's thread and next another thread wanted
to print something on the shell.
To avoid that shell releases mutex before entering command
handler. Due to this change some adapations to shell
internal print functions have been applied.
This change addresses following usecase:
1. A command handler needs to call a (system) function which
communicate results via a callback, and this callback is expected
to print these results. The callback is called by the system from
another thread.
2. To achieve that, the handler needs to pass `struct shell *`
to callbacks, but also some other data specific to callback.
Thus, handles allocates some structure will those fields on
the stack.
3. The handler schedules this callback to be called.
4. As a reference to stack structure is passed to the callback,
the handler can't return immediately (or stack data will go out
of scope and will be overwritten).
5. So, the handler blocks waiting for callback to finish.
Previously, this scenario led to deadlock when the callback
trying or print to shell. With these changes, it just works,
as long as main handler and callback serialize there access
to the shell structure (i.e. when callback prints, the main
handler is blocked waiting for its completion).
Signed-off-by: Jakub Rzeszutko <jakub.rzeszutko@nordicsemi.no>
2019-02-12 15:38:16 +01:00
|
|
|
|
2020-12-07 13:22:35 +01:00
|
|
|
z_shell_vt100_colors_restore(shell, &col);
|
shell: allow commands to suspend shell thread
It was possible to deadlock the shell when command
suspended shell's thread and next another thread wanted
to print something on the shell.
To avoid that shell releases mutex before entering command
handler. Due to this change some adapations to shell
internal print functions have been applied.
This change addresses following usecase:
1. A command handler needs to call a (system) function which
communicate results via a callback, and this callback is expected
to print these results. The callback is called by the system from
another thread.
2. To achieve that, the handler needs to pass `struct shell *`
to callbacks, but also some other data specific to callback.
Thus, handles allocates some structure will those fields on
the stack.
3. The handler schedules this callback to be called.
4. As a reference to stack structure is passed to the callback,
the handler can't return immediately (or stack data will go out
of scope and will be overwritten).
5. So, the handler blocks waiting for callback to finish.
Previously, this scenario led to deadlock when the callback
trying or print to shell. With these changes, it just works,
as long as main handler and callback serialize there access
to the shell structure (i.e. when callback prints, the main
handler is blocked waiting for its completion).
Signed-off-by: Jakub Rzeszutko <jakub.rzeszutko@nordicsemi.no>
2019-02-12 15:38:16 +01:00
|
|
|
} else {
|
2020-12-06 11:22:27 +01:00
|
|
|
z_shell_fprintf_fmt(shell->fprintf_ctx, fmt, args);
|
shell: allow commands to suspend shell thread
It was possible to deadlock the shell when command
suspended shell's thread and next another thread wanted
to print something on the shell.
To avoid that shell releases mutex before entering command
handler. Due to this change some adapations to shell
internal print functions have been applied.
This change addresses following usecase:
1. A command handler needs to call a (system) function which
communicate results via a callback, and this callback is expected
to print these results. The callback is called by the system from
another thread.
2. To achieve that, the handler needs to pass `struct shell *`
to callbacks, but also some other data specific to callback.
Thus, handles allocates some structure will those fields on
the stack.
3. The handler schedules this callback to be called.
4. As a reference to stack structure is passed to the callback,
the handler can't return immediately (or stack data will go out
of scope and will be overwritten).
5. So, the handler blocks waiting for callback to finish.
Previously, this scenario led to deadlock when the callback
trying or print to shell. With these changes, it just works,
as long as main handler and callback serialize there access
to the shell structure (i.e. when callback prints, the main
handler is blocked waiting for its completion).
Signed-off-by: Jakub Rzeszutko <jakub.rzeszutko@nordicsemi.no>
2019-02-12 15:38:16 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-12-06 11:22:27 +01:00
|
|
|
void z_shell_fprintf(const struct shell *shell,
|
shell: allow commands to suspend shell thread
It was possible to deadlock the shell when command
suspended shell's thread and next another thread wanted
to print something on the shell.
To avoid that shell releases mutex before entering command
handler. Due to this change some adapations to shell
internal print functions have been applied.
This change addresses following usecase:
1. A command handler needs to call a (system) function which
communicate results via a callback, and this callback is expected
to print these results. The callback is called by the system from
another thread.
2. To achieve that, the handler needs to pass `struct shell *`
to callbacks, but also some other data specific to callback.
Thus, handles allocates some structure will those fields on
the stack.
3. The handler schedules this callback to be called.
4. As a reference to stack structure is passed to the callback,
the handler can't return immediately (or stack data will go out
of scope and will be overwritten).
5. So, the handler blocks waiting for callback to finish.
Previously, this scenario led to deadlock when the callback
trying or print to shell. With these changes, it just works,
as long as main handler and callback serialize there access
to the shell structure (i.e. when callback prints, the main
handler is blocked waiting for its completion).
Signed-off-by: Jakub Rzeszutko <jakub.rzeszutko@nordicsemi.no>
2019-02-12 15:38:16 +01:00
|
|
|
enum shell_vt100_color color,
|
|
|
|
const char *fmt, ...)
|
|
|
|
{
|
|
|
|
__ASSERT_NO_MSG(shell);
|
|
|
|
__ASSERT(!k_is_in_isr(), "Thread context required.");
|
|
|
|
__ASSERT_NO_MSG(shell->ctx);
|
|
|
|
__ASSERT_NO_MSG(shell->fprintf_ctx);
|
|
|
|
__ASSERT_NO_MSG(fmt);
|
|
|
|
|
2019-06-06 11:27:12 -07:00
|
|
|
va_list args;
|
shell: allow commands to suspend shell thread
It was possible to deadlock the shell when command
suspended shell's thread and next another thread wanted
to print something on the shell.
To avoid that shell releases mutex before entering command
handler. Due to this change some adapations to shell
internal print functions have been applied.
This change addresses following usecase:
1. A command handler needs to call a (system) function which
communicate results via a callback, and this callback is expected
to print these results. The callback is called by the system from
another thread.
2. To achieve that, the handler needs to pass `struct shell *`
to callbacks, but also some other data specific to callback.
Thus, handles allocates some structure will those fields on
the stack.
3. The handler schedules this callback to be called.
4. As a reference to stack structure is passed to the callback,
the handler can't return immediately (or stack data will go out
of scope and will be overwritten).
5. So, the handler blocks waiting for callback to finish.
Previously, this scenario led to deadlock when the callback
trying or print to shell. With these changes, it just works,
as long as main handler and callback serialize there access
to the shell structure (i.e. when callback prints, the main
handler is blocked waiting for its completion).
Signed-off-by: Jakub Rzeszutko <jakub.rzeszutko@nordicsemi.no>
2019-02-12 15:38:16 +01:00
|
|
|
|
|
|
|
va_start(args, fmt);
|
2020-12-06 11:22:27 +01:00
|
|
|
z_shell_vfprintf(shell, color, fmt, args);
|
shell: allow commands to suspend shell thread
It was possible to deadlock the shell when command
suspended shell's thread and next another thread wanted
to print something on the shell.
To avoid that shell releases mutex before entering command
handler. Due to this change some adapations to shell
internal print functions have been applied.
This change addresses following usecase:
1. A command handler needs to call a (system) function which
communicate results via a callback, and this callback is expected
to print these results. The callback is called by the system from
another thread.
2. To achieve that, the handler needs to pass `struct shell *`
to callbacks, but also some other data specific to callback.
Thus, handles allocates some structure will those fields on
the stack.
3. The handler schedules this callback to be called.
4. As a reference to stack structure is passed to the callback,
the handler can't return immediately (or stack data will go out
of scope and will be overwritten).
5. So, the handler blocks waiting for callback to finish.
Previously, this scenario led to deadlock when the callback
trying or print to shell. With these changes, it just works,
as long as main handler and callback serialize there access
to the shell structure (i.e. when callback prints, the main
handler is blocked waiting for its completion).
Signed-off-by: Jakub Rzeszutko <jakub.rzeszutko@nordicsemi.no>
2019-02-12 15:38:16 +01:00
|
|
|
va_end(args);
|
|
|
|
}
|