sys/rtt_stdio: Support SEGGER RTT for stdin/stdout
This commit is contained in:
parent
662076e150
commit
1d6b9c6f8d
@ -333,7 +333,9 @@ ifneq (,$(filter newlib,$(USEMODULE)))
|
|||||||
ifeq (,$(filter newlib_syscalls_%,$(USEMODULE)))
|
ifeq (,$(filter newlib_syscalls_%,$(USEMODULE)))
|
||||||
USEMODULE += newlib_syscalls_default
|
USEMODULE += newlib_syscalls_default
|
||||||
endif
|
endif
|
||||||
USEMODULE += uart_stdio
|
ifeq (,$(filter rtt_stdio,$(USEMODULE)))
|
||||||
|
USEMODULE += uart_stdio
|
||||||
|
endif
|
||||||
endif
|
endif
|
||||||
|
|
||||||
ifneq (,$(filter posix_sockets,$(USEMODULE)))
|
ifneq (,$(filter posix_sockets,$(USEMODULE)))
|
||||||
@ -341,6 +343,10 @@ ifneq (,$(filter posix_sockets,$(USEMODULE)))
|
|||||||
USEMODULE += random
|
USEMODULE += random
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
ifneq (,$(filter rtt_stdio,$(USEMODULE)))
|
||||||
|
USEMODULE += xtimer
|
||||||
|
endif
|
||||||
|
|
||||||
ifneq (,$(filter uart_stdio,$(USEMODULE)))
|
ifneq (,$(filter uart_stdio,$(USEMODULE)))
|
||||||
USEMODULE += tsrb
|
USEMODULE += tsrb
|
||||||
endif
|
endif
|
||||||
|
|||||||
73
sys/include/rtt_stdio.h
Normal file
73
sys/include/rtt_stdio.h
Normal file
@ -0,0 +1,73 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2016 Michael Andersen <m.andersen@berkeley.edu>
|
||||||
|
*
|
||||||
|
* This file is subject to the terms and conditions of the GNU Lesser
|
||||||
|
* General Public License v2.1. See the file LICENSE in the top level
|
||||||
|
* directory for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @defgroup sys_rtt_stdio SEGGER RTT stdio
|
||||||
|
* @ingroup sys
|
||||||
|
*
|
||||||
|
* @brief stdio init/read/write functions for SEGGER RTT. This is
|
||||||
|
* designed to shadow the functions in uart_stdio
|
||||||
|
*
|
||||||
|
* @{
|
||||||
|
* @file
|
||||||
|
*
|
||||||
|
* @author Michael Andersen <m.andersen@cs.berkeley.edu>
|
||||||
|
*/
|
||||||
|
#ifndef RTT_STDIO_H
|
||||||
|
#define RTT_STDIO_H
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief initialize the module. This is a noop.
|
||||||
|
*/
|
||||||
|
void uart_stdio_init(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief read @p len bytes from stdio uart into @p buffer
|
||||||
|
*
|
||||||
|
* @param[out] buffer buffer to read into
|
||||||
|
* @param[in] len nr of bytes to read
|
||||||
|
*
|
||||||
|
* @return nr of bytes read
|
||||||
|
* @return <0 on error
|
||||||
|
*/
|
||||||
|
int uart_stdio_read(char* buffer, int len);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief write @p len bytes from @p buffer into uart
|
||||||
|
*
|
||||||
|
* @param[in] buffer buffer to read from
|
||||||
|
* @param[in] len nr of bytes to write
|
||||||
|
*
|
||||||
|
* @return nr of bytes written
|
||||||
|
* @return <0 on error
|
||||||
|
*/
|
||||||
|
int uart_stdio_write(const char* buffer, int len);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief enable stdin polling, at a power consumption cost. This is enabled
|
||||||
|
* by default unless RTT_STDIO_DISABLE_STDIN is defined.
|
||||||
|
*/
|
||||||
|
void rtt_stdio_enable_stdin(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief enable stdout blocking and free space polling. This must be done
|
||||||
|
* with caution because if there is no RTT client attached, all
|
||||||
|
* writes to stdout will block indefinitely. This can be enabled
|
||||||
|
* automatically by defining RTT_STDIO_ENABLE_BLOCKING_STDOUT
|
||||||
|
*/
|
||||||
|
void rtt_stdio_enable_blocking_stdout(void);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
/** @} */
|
||||||
|
#endif /* RTT_STDIO_H */
|
||||||
1
sys/rtt_stdio/Makefile
Normal file
1
sys/rtt_stdio/Makefile
Normal file
@ -0,0 +1 @@
|
|||||||
|
include $(RIOTBASE)/Makefile.base
|
||||||
45
sys/rtt_stdio/README.md
Normal file
45
sys/rtt_stdio/README.md
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
# RTT STDIO
|
||||||
|
|
||||||
|
This module will allow communication using SEGGER's Real Time Terminal protocol.
|
||||||
|
Briefly, it replaces UART stdio with a set of ringbuffers that are manipulated
|
||||||
|
over JTAG. There are several advantages to this system. The biggest is that
|
||||||
|
writing to stdout is extremely fast (as you are just copying to memory). This
|
||||||
|
is useful if you are adding print statements in timing-sensitive code as part
|
||||||
|
of debugging. The other advantage is that it frees your UART for other use
|
||||||
|
and enables stdio on platforms that do not have a UART.
|
||||||
|
|
||||||
|
To use this module, add
|
||||||
|
|
||||||
|
```
|
||||||
|
USEMODULE += rtt_stdio
|
||||||
|
```
|
||||||
|
|
||||||
|
to your makefile. By default the module will drop bytes written to stdout if the
|
||||||
|
buffer is full. If you know for certain that the debugger is attached, you
|
||||||
|
can obtain lossless stdout by adding
|
||||||
|
|
||||||
|
```
|
||||||
|
CFLAGS += -DRTT_STDIO_ENABLE_BLOCKING_STDOUT
|
||||||
|
```
|
||||||
|
|
||||||
|
to your makefile. Note well that if you do NOT plug in the debugger and run
|
||||||
|
the SEGGER RTT software (or compatible software) this will then lock up the
|
||||||
|
system as it waits forever. Typically you would only define this during
|
||||||
|
development on the lab bench.
|
||||||
|
|
||||||
|
If you are printing significant data out (pages a second), you can increase
|
||||||
|
your stdout bandwidth by lowering the poll interval. The default is 50ms.
|
||||||
|
A choice of 5ms is good during printf-heavy debugging:
|
||||||
|
|
||||||
|
```
|
||||||
|
CFLAGS += -DSTDIO_POLL_INTERVAL=5000U
|
||||||
|
```
|
||||||
|
|
||||||
|
SEGGER RTT supports stdin as well, and this is enabled by default. It requires
|
||||||
|
polling the stdin ringbuffer, however, which on low duty cycle systems
|
||||||
|
can increase the number of unnecessary wakeups from sleep. To disable stdin,
|
||||||
|
add this to your makefile:
|
||||||
|
|
||||||
|
```
|
||||||
|
CFLAGS += -DRTT_STDIO_DISABLE_STDIN
|
||||||
|
```
|
||||||
335
sys/rtt_stdio/rtt_stdio.c
Normal file
335
sys/rtt_stdio/rtt_stdio.c
Normal file
@ -0,0 +1,335 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2016 Michael Andersen <m.andersen@cs.berkeley.edu>
|
||||||
|
*
|
||||||
|
* This file was based on SEGGER's reference implementation
|
||||||
|
* which can be found here: https://www.segger.com/jlink-rtt.html
|
||||||
|
* (c) 2014-2016 SEGGER Microcontroller GmbH & Co. KG
|
||||||
|
* This implementation bore the following license notes:
|
||||||
|
**********************************************************************
|
||||||
|
* SEGGER MICROCONTROLLER GmbH & Co. KG *
|
||||||
|
* Solutions for real time microcontroller applications *
|
||||||
|
**********************************************************************
|
||||||
|
* *
|
||||||
|
* (c) 2014 - 2016 SEGGER Microcontroller GmbH & Co. KG *
|
||||||
|
* *
|
||||||
|
* www.segger.com Support: support@segger.com *
|
||||||
|
* *
|
||||||
|
**********************************************************************
|
||||||
|
* *
|
||||||
|
* SEGGER RTT * Real Time Transfer for embedded targets *
|
||||||
|
* *
|
||||||
|
**********************************************************************
|
||||||
|
* *
|
||||||
|
* All rights reserved. *
|
||||||
|
* *
|
||||||
|
* SEGGER strongly recommends to not make any changes *
|
||||||
|
* to or modify the source code of this software in order to stay *
|
||||||
|
* compatible with the RTT protocol and J-Link. *
|
||||||
|
* *
|
||||||
|
* Redistribution and use in source and binary forms, with or *
|
||||||
|
* without modification, are permitted provided that the following *
|
||||||
|
* conditions are met: *
|
||||||
|
* *
|
||||||
|
* o Redistributions of source code must retain the above copyright *
|
||||||
|
* notice, this list of conditions and the following disclaimer. *
|
||||||
|
* *
|
||||||
|
* o Redistributions in binary form must reproduce the above *
|
||||||
|
* copyright notice, this list of conditions and the following *
|
||||||
|
* disclaimer in the documentation and/or other materials provided *
|
||||||
|
* with the distribution. *
|
||||||
|
* *
|
||||||
|
* o Neither the name of SEGGER Microcontroller GmbH & Co. KG *
|
||||||
|
* nor the names of its contributors may be used to endorse or *
|
||||||
|
* promote products derived from this software without specific *
|
||||||
|
* prior written permission. *
|
||||||
|
* *
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND *
|
||||||
|
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, *
|
||||||
|
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF *
|
||||||
|
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE *
|
||||||
|
* DISCLAIMED. IN NO EVENT SHALL SEGGER Microcontroller BE LIABLE FOR *
|
||||||
|
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR *
|
||||||
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT *
|
||||||
|
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; *
|
||||||
|
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF *
|
||||||
|
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT *
|
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE *
|
||||||
|
* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH *
|
||||||
|
* DAMAGE. *
|
||||||
|
* *
|
||||||
|
**********************************************************************/
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @ingroup sys
|
||||||
|
* @{
|
||||||
|
*
|
||||||
|
* @file
|
||||||
|
* @brief SEGGER RTT stdio implementation
|
||||||
|
*
|
||||||
|
* This file implements UART read/write functions, but it
|
||||||
|
* is actually a virtual UART backed by a ringbuffer that
|
||||||
|
* complies with SEGGER RTT. It is designed to shadow
|
||||||
|
* uart_stdio that is used by newlib.
|
||||||
|
*
|
||||||
|
* @author Michael Andersen <m.andersen@cs.berkeley.edu>
|
||||||
|
*
|
||||||
|
* @}
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <rtt_stdio.h>
|
||||||
|
|
||||||
|
#include "thread.h"
|
||||||
|
#include "mutex.h"
|
||||||
|
#include "xtimer.h"
|
||||||
|
|
||||||
|
/* This parameter affects the bandwidth of both input and output. Decreasing
|
||||||
|
it will significantly improve bandwidth at the cost of CPU time. */
|
||||||
|
#ifndef STDIO_POLL_INTERVAL
|
||||||
|
#define STDIO_POLL_INTERVAL 50000U
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define MIN(a, b) (((a) < (b)) ? (a) : (b))
|
||||||
|
#define MAX(a, b) (((a) > (b)) ? (a) : (b))
|
||||||
|
|
||||||
|
#ifndef STDIO_TX_BUFSIZE
|
||||||
|
#define STDIO_TX_BUFSIZE (512)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef STDIO_RX_BUFSIZE
|
||||||
|
#define STDIO_RX_BUFSIZE (32)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief use mutex for waiting on stdin being enabled
|
||||||
|
*/
|
||||||
|
static mutex_t _rx_mutex = MUTEX_INIT;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief buffer holding stdout
|
||||||
|
*/
|
||||||
|
static char up_buffer [STDIO_TX_BUFSIZE];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief buffer holding stdin
|
||||||
|
*/
|
||||||
|
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;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief SEGGER's ring buffer implementation
|
||||||
|
*/
|
||||||
|
typedef struct {
|
||||||
|
const char* channel_name; /* Optional name. Standard names so far are:
|
||||||
|
"Terminal", "VCom" */
|
||||||
|
char* buf_ptr; /* Pointer to start of buffer */
|
||||||
|
int32_t buf_size; /* Buffer size in bytes. Note that one byte is
|
||||||
|
lost, as this implementation does not fill up
|
||||||
|
the buffer in order to avoid the problem of
|
||||||
|
being unable to distinguish between full and
|
||||||
|
empty. */
|
||||||
|
volatile int32_t wr_off; /* Position of next item to be written by either
|
||||||
|
host (down-buffer) or target (up-buffer). Must
|
||||||
|
be volatile since it may be modified by host
|
||||||
|
(down-buffer) */
|
||||||
|
volatile int32_t rd_off; /* Position of next item to be read by target
|
||||||
|
(down-buffer) or host (up-buffer). Must be
|
||||||
|
volatile since it may be modified by host
|
||||||
|
(up-buffer) */
|
||||||
|
int32_t flags; /* Contains configuration flags */
|
||||||
|
} rtt_ringbuf_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief RTT control block which describes the number of buffers available
|
||||||
|
* as well as the configuration for each buffer. The struct definition
|
||||||
|
* is fixed, as it is expected by SEGGER's software
|
||||||
|
*/
|
||||||
|
typedef struct {
|
||||||
|
char sentinel[16]; /* Initialized to "SEGGER RTT" */
|
||||||
|
int32_t max_up_buffers; /* Initialized to 1 */
|
||||||
|
int32_t max_down_buffers; /* Initialized to 1 */
|
||||||
|
rtt_ringbuf_t up[1]; /* Up buffers, transferring information up
|
||||||
|
from target via debug probe to host */
|
||||||
|
rtt_ringbuf_t down[1]; /* Down buffers, transferring information
|
||||||
|
down from host via debug probe to target */
|
||||||
|
} segger_rtt_cb_t;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief The SEGGER Real-Time-Terminal control block (CB)
|
||||||
|
*/
|
||||||
|
static segger_rtt_cb_t rtt_cb = {
|
||||||
|
"SEGGER RTT",
|
||||||
|
1,
|
||||||
|
1,
|
||||||
|
{{ "Terminal", &up_buffer[0], sizeof(up_buffer), 0, 0, 0 }},
|
||||||
|
{{ "Terminal", &down_buffer[0], sizeof(down_buffer), 0, 0, 0 }},
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @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) {
|
||||||
|
int16_t num_bytes_rem;
|
||||||
|
uint16_t num_bytes_read;
|
||||||
|
int16_t rd_off;
|
||||||
|
int16_t wr_off;
|
||||||
|
|
||||||
|
rd_off = rtt_cb.down[0].rd_off;
|
||||||
|
wr_off = rtt_cb.down[0].wr_off;
|
||||||
|
num_bytes_read = 0;
|
||||||
|
|
||||||
|
/* Read from current read position to wrap-around of buffer, first */
|
||||||
|
if (rd_off > wr_off) {
|
||||||
|
num_bytes_rem = rtt_cb.down[0].buf_size - rd_off;
|
||||||
|
num_bytes_rem = MIN(num_bytes_rem, (int)buf_size);
|
||||||
|
memcpy(buf_ptr, rtt_cb.down[0].buf_ptr + rd_off, num_bytes_rem);
|
||||||
|
num_bytes_read += num_bytes_rem;
|
||||||
|
buf_ptr += num_bytes_rem;
|
||||||
|
buf_size -= num_bytes_rem;
|
||||||
|
rd_off += num_bytes_rem;
|
||||||
|
/* Handle wrap-around of buffer */
|
||||||
|
if (rd_off == rtt_cb.down[0].buf_size) {
|
||||||
|
rd_off = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Read remaining items of buffer */
|
||||||
|
num_bytes_rem = wr_off - rd_off;
|
||||||
|
num_bytes_rem = MIN(num_bytes_rem, (int)buf_size);
|
||||||
|
if (num_bytes_rem > 0) {
|
||||||
|
memcpy(buf_ptr, rtt_cb.down[0].buf_ptr + rd_off, num_bytes_rem);
|
||||||
|
num_bytes_read += num_bytes_rem;
|
||||||
|
rd_off += num_bytes_rem;
|
||||||
|
}
|
||||||
|
if (num_bytes_read) {
|
||||||
|
rtt_cb.down[0].rd_off = rd_off;
|
||||||
|
}
|
||||||
|
return num_bytes_read;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief write bytes to the up 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 does not need to be null
|
||||||
|
* terminated.
|
||||||
|
*
|
||||||
|
* @return the number of bytes read
|
||||||
|
*/
|
||||||
|
int rtt_write(const char* buf_ptr, unsigned num_bytes) {
|
||||||
|
int num_bytes_to_write;
|
||||||
|
unsigned num_bytes_written;
|
||||||
|
int rd_off;
|
||||||
|
|
||||||
|
rd_off = rtt_cb.up[0].rd_off;
|
||||||
|
num_bytes_to_write = rd_off - rtt_cb.up[0].wr_off - 1;
|
||||||
|
if (num_bytes_to_write < 0) {
|
||||||
|
num_bytes_to_write += rtt_cb.up[0].buf_size;
|
||||||
|
}
|
||||||
|
/* If the complete data does not fit in the buffer, trim the data */
|
||||||
|
if ((int)num_bytes > num_bytes_to_write) {
|
||||||
|
num_bytes = num_bytes_to_write;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Early out if there is nothing to do */
|
||||||
|
if (num_bytes == 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Write data to buffer and handle wrap-around if necessary */
|
||||||
|
num_bytes_written = 0;
|
||||||
|
do {
|
||||||
|
/* May be changed by host (debug probe) in the meantime */
|
||||||
|
rd_off = rtt_cb.up[0].rd_off;
|
||||||
|
num_bytes_to_write = rd_off - rtt_cb.up[0].wr_off - 1;
|
||||||
|
if (num_bytes_to_write < 0) {
|
||||||
|
num_bytes_to_write += rtt_cb.up[0].buf_size;
|
||||||
|
}
|
||||||
|
/* Number of bytes that can be written until buffer wrap-around */
|
||||||
|
num_bytes_to_write = MIN(num_bytes_to_write, (rtt_cb.up[0].buf_size -
|
||||||
|
rtt_cb.up[0].wr_off));
|
||||||
|
num_bytes_to_write = MIN(num_bytes_to_write, (int)num_bytes);
|
||||||
|
memcpy(rtt_cb.up[0].buf_ptr + rtt_cb.up[0].wr_off, buf_ptr, num_bytes_to_write);
|
||||||
|
num_bytes_written += num_bytes_to_write;
|
||||||
|
buf_ptr += num_bytes_to_write;
|
||||||
|
num_bytes -= num_bytes_to_write;
|
||||||
|
rtt_cb.up[0].wr_off += num_bytes_to_write;
|
||||||
|
if (rtt_cb.up[0].wr_off == rtt_cb.up[0].buf_size) {
|
||||||
|
rtt_cb.up[0].wr_off = 0;
|
||||||
|
}
|
||||||
|
} while (num_bytes);
|
||||||
|
return num_bytes_written;
|
||||||
|
}
|
||||||
|
|
||||||
|
void uart_stdio_init(void) {
|
||||||
|
#ifndef RTT_STDIO_DISABLE_STDIN
|
||||||
|
stdin_enabled = 1;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef RTT_STDIO_ENABLE_BLOCKING_STDOUT
|
||||||
|
blocking_stdout = 1;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* the mutex should start locked */
|
||||||
|
mutex_lock(&_rx_mutex);
|
||||||
|
}
|
||||||
|
|
||||||
|
void rtt_stdio_enable_stdin(void) {
|
||||||
|
stdin_enabled = 1;
|
||||||
|
mutex_unlock(&_rx_mutex);
|
||||||
|
}
|
||||||
|
|
||||||
|
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. */
|
||||||
|
int uart_stdio_read(char* buffer, int count) {
|
||||||
|
int res = rtt_read(buffer, 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 */
|
||||||
|
}
|
||||||
|
uint32_t last_wakeup = xtimer_now();
|
||||||
|
while(1) {
|
||||||
|
xtimer_periodic_wakeup(&last_wakeup, STDIO_POLL_INTERVAL);
|
||||||
|
res = rtt_read(buffer, count);
|
||||||
|
if (res > 0)
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
int uart_stdio_write(const char* buffer, int len) {
|
||||||
|
int written = rtt_write(buffer, len);
|
||||||
|
uint32_t last_wakeup = xtimer_now();
|
||||||
|
while (blocking_stdout && written < len) {
|
||||||
|
xtimer_periodic_wakeup(&last_wakeup, STDIO_POLL_INTERVAL);
|
||||||
|
written += rtt_write(&buffer[written], len-written);
|
||||||
|
}
|
||||||
|
return written;
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user