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

stdio_dispatch: allow to select multiple stdio methods at the same time #19738

Merged
merged 19 commits into from
Feb 9, 2024
Merged
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
stdio_rtt: port to new interface
  • Loading branch information
benpicco committed Feb 9, 2024
commit 76997fdd760b8f5d97ba99de9bda628d9adc0924
123 changes: 69 additions & 54 deletions sys/stdio_rtt/stdio_rtt.c
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@
#include "mutex.h"
#include "stdio_rtt.h"
#include "thread.h"
#include "ztimer.h"
#include "ztimer/periodic.h"

/* This parameter affects the bandwidth of both input and output. Decreasing
it will significantly improve bandwidth at the cost of CPU time. */
Expand All @@ -96,10 +96,9 @@
#define STDIO_RX_BUFSIZE (32)
#endif

/**
* @brief use mutex for waiting on stdin being enabled
*/
static mutex_t _rx_mutex = MUTEX_INIT;
#if !defined(MODULE_STDIN) && !defined(STDIO_RTT_DISABLE_STDIN)
#define STDIO_RTT_DISABLE_STDIN 1
#endif

/**
* @brief buffer holding stdout
Expand All @@ -111,15 +110,12 @@ static char up_buffer [STDIO_TX_BUFSIZE];
*/
static char down_buffer [STDIO_RX_BUFSIZE];

/**
* @brief flag that enables stdin polling
*/
static char stdin_enabled = 0;

/**
* @brief flag that enables stdout blocking/polling
*/
static char blocking_stdout = 0;
static char blocking_stdout = IS_USED(STDIO_RTT_ENABLE_BLOCKING_STDOUT);

static ztimer_periodic_t stdin_timer;

/**
* @brief SEGGER's ring buffer implementation
Expand Down Expand Up @@ -170,14 +166,30 @@ static segger_rtt_cb_t rtt_cb = {
{{ "Terminal", &down_buffer[0], sizeof(down_buffer), 0, 0, 0 }},
};

static int rtt_read_bytes_avail(void)
{
int16_t rd_off;
int16_t wr_off;

rd_off = rtt_cb.down[0].rd_off;
wr_off = rtt_cb.down[0].wr_off;

/* Read from current read position to wrap-around of buffer, first */
if (rd_off > wr_off) {
return rtt_cb.down[0].buf_size - rd_off;
} else {
return wr_off - rd_off;
}
}

/**
* @brief read bytes from the down buffer. This function does not block.
* The logic here is unmodified from SEGGER's reference, it is just
* refactored to match code style. The string is not null terminated.
*
* @return the number of bytes read
*/
static int rtt_read(char* buf_ptr, uint16_t buf_size) {
static int rtt_read(uint8_t* buf_ptr, uint16_t buf_size) {
int16_t num_bytes_rem;
uint16_t num_bytes_read;
int16_t rd_off;
Expand Down Expand Up @@ -269,61 +281,64 @@ int rtt_write(const char* buf_ptr, unsigned num_bytes) {
return num_bytes_written;
}

void stdio_init(void) {
#ifndef STDIO_RTT_DISABLE_STDIN
stdin_enabled = 1;
#endif
static bool _rtt_read_cb(void *arg)
{
int bytes = rtt_read_bytes_avail();
uint8_t buffer[STDIO_RX_BUFSIZE];

#ifdef STDIO_RTT_ENABLE_BLOCKING_STDOUT
blocking_stdout = 1;
#endif
if (bytes) {
bytes = rtt_read(buffer, sizeof(buffer));
isrpipe_write(arg, buffer, bytes);
}

return true;
}

static bool _init_done;
static void _init(void) {
if (IS_USED(STDIO_RTT_DISABLE_STDIN)) {
return;
}
if (!thread_getpid()) {
/* we can't use ztimer in early init */
return;
}

/* the mutex should start locked */
mutex_lock(&_rx_mutex);
ztimer_periodic_init(ZTIMER_MSEC, &stdin_timer, _rtt_read_cb, &stdin_isrpipe,
STDIO_POLL_INTERVAL_MS);
ztimer_periodic_start(&stdin_timer);
_init_done = true;
}

void rtt_stdio_enable_stdin(void) {
stdin_enabled = 1;
mutex_unlock(&_rx_mutex);
static void _detach(void)
{
if (!IS_USED(STDIO_RTT_DISABLE_STDIN)) {
ztimer_periodic_stop(&stdin_timer);
}
}

void rtt_stdio_enable_blocking_stdout(void) {
blocking_stdout = 1;
}

/* The reason we have this strange logic is as follows:
If we have an RTT console, we are powered, and so don't care
that polling uses a lot of power. If however, we do not
actually have an RTT console (because we are deployed on
a battery somewhere) then we REALLY don't want to poll
especially since we are not expecting to EVER get input. */
ssize_t stdio_read(void* buffer, size_t count) {
int res = rtt_read((void *)buffer, (uint16_t)count);
if (res == 0) {
if (!stdin_enabled) {
mutex_lock(&_rx_mutex);
/* We only unlock when rtt_stdio_enable_stdin is called
Note that we assume only one caller invoked this function */
}
static ssize_t _write(const void* in, size_t len) {
const char *buffer = in;
int written = rtt_write(buffer, len);

/* we have to postpone ztimer init */
if (!_init_done) {
_init();
}

if (blocking_stdout) {
uint32_t last_wakeup = ztimer_now(ZTIMER_MSEC);
while(1) {
ztimer_periodic_wakeup(ZTIMER_MSEC, &last_wakeup,
STDIO_POLL_INTERVAL_MS);
res = rtt_read(buffer, count);
if (res > 0)
return res;
while ((size_t)written < len) {
ztimer_periodic_wakeup(ZTIMER_MSEC, &last_wakeup, STDIO_POLL_INTERVAL_MS);
written += rtt_write(&buffer[written], len-written);
}
}
return (ssize_t)res;
}

ssize_t stdio_write(const void* in, size_t len) {
const char *buffer = (const char *)in;
int written = rtt_write(buffer, (unsigned)len);
uint32_t last_wakeup = ztimer_now(ZTIMER_MSEC);
while (blocking_stdout && ((size_t)written < len)) {
ztimer_periodic_wakeup(ZTIMER_MSEC, &last_wakeup, STDIO_POLL_INTERVAL_MS);
written += rtt_write(&buffer[written], len-written);
}
return (ssize_t)written;
}

STDIO_PROVIDER(STDIO_RTT, _init, _detach, _write)