Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

shell: rtt: Add detection of host presence #68941

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
18 changes: 18 additions & 0 deletions subsys/shell/backends/Kconfig.backends
Expand Up @@ -185,6 +185,7 @@ config SHELL_BACKEND_RTT
bool "RTT backend"
select CONSOLE
select RTT_CONSOLE
select SEGGER_RTT_CUSTOM_LOCKING
depends on USE_SEGGER_RTT
help
Enable RTT backend.
Expand All @@ -206,6 +207,23 @@ config SHELL_BACKEND_RTT_BUFFER
Select index of up-buffer used for shell output, by default it uses
terminal up-buffer and its settings.

config SHELL_BACKEND_RTT_RETRY_CNT
int "Number of retries"
default 4
help
Number of TX retries before dropping the data and assuming that
RTT session is inactive.

config SHELL_BACKEND_RTT_RETRY_DELAY_MS
int "Delay between TX retries in milliseconds"
default 5
help
Sleep period between TX retry attempts. During RTT session, host pulls
data periodically. Period starts from 1-2 milliseconds and can be
increased if traffic on RTT increases (also from host to device). In
case of heavy traffic data can be lost and it may be necessary to
increase delay or number of retries.

config SHELL_RTT_RX_POLL_PERIOD
int "RX polling period (in milliseconds)"
default 10
Expand Down
79 changes: 69 additions & 10 deletions subsys/shell/backends/shell_rtt.c
Expand Up @@ -9,6 +9,12 @@
#include <SEGGER_RTT.h>
#include <zephyr/logging/log.h>

#define RTT_LOCK() \
COND_CODE_0(CONFIG_SHELL_BACKEND_RTT_BUFFER, (SEGGER_RTT_LOCK()), ())

#define RTT_UNLOCK() \
COND_CODE_0(CONFIG_SHELL_BACKEND_RTT_BUFFER, (SEGGER_RTT_UNLOCK()), ())

#if IS_ENABLED(CONFIG_LOG_BACKEND_RTT)
BUILD_ASSERT(!(CONFIG_SHELL_BACKEND_RTT_BUFFER == CONFIG_LOG_BACKEND_RTT_BUFFER),
"Conflicting log RTT backend enabled on the same channel");
Expand All @@ -25,7 +31,8 @@ SHELL_DEFINE(shell_rtt, CONFIG_SHELL_PROMPT_RTT, &shell_transport_rtt,

LOG_MODULE_REGISTER(shell_rtt, CONFIG_SHELL_RTT_LOG_LEVEL);

static bool rtt_blocking;
static bool panic_mode;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This variable is never set?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link

@aescov aescov Apr 17, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@nordic-krch @fabiobaltieri : It seems that api for settting panic mode is missing i shell_transport_api. In NCS setup this causes an attempt to lock mutex ISR context, when entering from log_panic.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@aescov could you open either a PR with the fix or an issue so we can assign this?

static bool host_present;

static void timer_handler(struct k_timer *timer)
{
Expand Down Expand Up @@ -78,29 +85,81 @@ static int enable(const struct shell_transport *transport, bool blocking)
struct shell_rtt *sh_rtt = (struct shell_rtt *)transport->ctx;

if (blocking) {
rtt_blocking = true;
k_timer_stop(&sh_rtt->timer);
}

return 0;
}

static inline bool is_panic_mode(void)
{
return panic_mode;
}

static inline bool is_sync_mode(void)
{
return (IS_ENABLED(CONFIG_LOG_MODE_IMMEDIATE) && IS_ENABLED(CONFIG_SHELL_LOG_BACKEND)) ||
is_panic_mode();
}

static void on_failed_write(int retry_cnt)
{
if (retry_cnt == 0) {
host_present = false;
} else if (is_sync_mode()) {
k_busy_wait(USEC_PER_MSEC *
CONFIG_SHELL_BACKEND_RTT_RETRY_DELAY_MS);
} else {
k_msleep(CONFIG_SHELL_BACKEND_RTT_RETRY_DELAY_MS);
}
}

static void on_write(int retry_cnt)
{
host_present = true;
if (is_panic_mode()) {
/* In panic mode block on each write until host reads it. This
* way it is ensured that if system resets all messages are read
* by the host. While pending on data being read by the host we
* must also detect situation where host is disconnected.
*/
while (SEGGER_RTT_HasDataUp(CONFIG_SHELL_BACKEND_RTT_BUFFER) &&
host_present) {
on_failed_write(retry_cnt--);
}
}

}

static int write(const struct shell_transport *transport,
const void *data, size_t length, size_t *cnt)
{
struct shell_rtt *sh_rtt = (struct shell_rtt *)transport->ctx;
const uint8_t *data8 = (const uint8_t *)data;
int ret = 0;
int retry_cnt = CONFIG_SHELL_BACKEND_RTT_RETRY_CNT;

do {
if (!is_sync_mode()) {
RTT_LOCK();
ret = SEGGER_RTT_WriteSkipNoLock(CONFIG_SHELL_BACKEND_RTT_BUFFER,
data, length);
RTT_UNLOCK();
} else {
ret = SEGGER_RTT_WriteSkipNoLock(CONFIG_SHELL_BACKEND_RTT_BUFFER,
data, length);
}

if (rtt_blocking) {
*cnt = SEGGER_RTT_WriteNoLock(CONFIG_SHELL_BACKEND_RTT_BUFFER, data8, length);
while (SEGGER_RTT_HasDataUp(CONFIG_SHELL_BACKEND_RTT_BUFFER)) {
/* empty */
if (ret) {
on_write(retry_cnt);
} else if (host_present) {
retry_cnt--;
on_failed_write(retry_cnt);
} else {
}
} else {
*cnt = SEGGER_RTT_Write(CONFIG_SHELL_BACKEND_RTT_BUFFER, data8, length);
}
} while ((ret == 0) && host_present);

sh_rtt->handler(SHELL_TRANSPORT_EVT_TX_RDY, sh_rtt->context);
*cnt = length;

return 0;
}
Expand Down