92 lines
2.2 KiB
C
92 lines
2.2 KiB
C
|
#include <stdio.h>
|
||
|
#include <sys/cdefs.h>
|
||
|
#include <libopencm3/cm3/assert.h>
|
||
|
#include <libopencm3/cm3/nvic.h>
|
||
|
#include <libopencm3/stm32/usart.h>
|
||
|
|
||
|
#include <libcommon/iob.h>
|
||
|
|
||
|
#include <librfn/ringbuf.h>
|
||
|
|
||
|
/* picolibc iob implementation for non-blocking I/O on USART via ring-buffer */
|
||
|
|
||
|
static uint32_t stdio_usart;
|
||
|
static uint8_t outbuf[1024];
|
||
|
static ringbuf_t outring = RINGBUF_VAR_INIT(outbuf, sizeof(outbuf));
|
||
|
|
||
|
static uint8_t inbuf[256];
|
||
|
static ringbuf_t inring = RINGBUF_VAR_INIT(inbuf, sizeof(inbuf));
|
||
|
|
||
|
void iob_init(uint32_t usart)
|
||
|
{
|
||
|
cm3_assert(usart == USART2);
|
||
|
stdio_usart = usart;
|
||
|
|
||
|
nvic_enable_irq(NVIC_USART2_IRQ);
|
||
|
/* Enable RX non-empty interrupt */
|
||
|
USART_CR1(stdio_usart) |= USART_CR1_RXNEIE;
|
||
|
}
|
||
|
|
||
|
/* FIXME: this obviously doesn't work with iob_init() getting passed a dynamic UART */
|
||
|
void usart2_isr(void)
|
||
|
{
|
||
|
if ((USART_CR1(stdio_usart) & USART_CR1_RXNEIE) &&
|
||
|
(USART_SR(stdio_usart) & USART_SR_RXNE)) {
|
||
|
uint16_t c = usart_recv(stdio_usart);
|
||
|
ringbuf_put(&inring, c);
|
||
|
}
|
||
|
|
||
|
if ((USART_CR1(stdio_usart) & USART_CR1_TXEIE) &&
|
||
|
(USART_SR(stdio_usart) & USART_SR_TXE)) {
|
||
|
int data = ringbuf_get(&outring);
|
||
|
if (data == -1) {
|
||
|
USART_CR1(stdio_usart) &= ~USART_CR1_TXEIE;
|
||
|
} else {
|
||
|
usart_send(stdio_usart, data);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/* buffered output to stdout */
|
||
|
static int my_stdout_putc(char c, FILE *file)
|
||
|
{
|
||
|
(void) file;
|
||
|
cm3_assert(stdio_usart);
|
||
|
ringbuf_put(&outring, c);
|
||
|
USART_CR1(stdio_usart) |= USART_CR1_TXEIE;
|
||
|
return c;
|
||
|
}
|
||
|
|
||
|
/* unbuffered, blocking output to stderr (e.g. for assert, fault handlers, ...) */
|
||
|
static int my_stderr_putc(char c, FILE *file)
|
||
|
{
|
||
|
(void) file;
|
||
|
cm3_assert(stdio_usart);
|
||
|
usart_send_blocking(stdio_usart, c);
|
||
|
return c;
|
||
|
}
|
||
|
|
||
|
static int my_stdin_getc(FILE *file)
|
||
|
{
|
||
|
(void) file;
|
||
|
int data = ringbuf_get(&inring);
|
||
|
|
||
|
if (data == -1)
|
||
|
return EOF;
|
||
|
else
|
||
|
return data;
|
||
|
}
|
||
|
|
||
|
static int my_stdout_flush(FILE *file)
|
||
|
{
|
||
|
(void) file;
|
||
|
do { } while (!ringbuf_empty(&outring));
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
static FILE __stdin = FDEV_SETUP_STREAM(NULL, my_stdin_getc, NULL, _FDEV_SETUP_READ);
|
||
|
static FILE __stdout = FDEV_SETUP_STREAM(my_stdout_putc, NULL, my_stdout_flush, _FDEV_SETUP_WRITE);
|
||
|
static FILE __stderr = FDEV_SETUP_STREAM(my_stderr_putc, NULL, NULL, _FDEV_SETUP_WRITE);
|
||
|
|
||
|
FILE *const __iob[3] = { &__stdin, &__stdout, &__stderr };
|