You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
250 lines
4.6 KiB
250 lines
4.6 KiB
#define _GNU_SOURCE
|
|
#include <libopencm3/stm32/usart.h>
|
|
#include <libopencm3/cm3/nvic.h>
|
|
#include <libopencm3/cm3/scb.h>
|
|
|
|
#include <ctype.h>
|
|
#include <stdarg.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <errno.h>
|
|
#include <stddef.h>
|
|
#include <limits.h>
|
|
#include <sys/types.h>
|
|
|
|
#include <console.h>
|
|
#include <macros.h>
|
|
|
|
#define CONFIG_USER_ECHO 1
|
|
#define RECV_BUF_LEN 128
|
|
|
|
struct usart_console {
|
|
struct console console;
|
|
char recv_buf[RECV_BUF_LEN];
|
|
volatile size_t cur;
|
|
volatile size_t next;
|
|
unsigned irq_no;
|
|
uint32_t dev;
|
|
};
|
|
|
|
static struct usart_console usart[2];
|
|
|
|
#ifdef STM32F0
|
|
#define USART_STOPBITS_1 USART_CR2_STOP_1_0BIT
|
|
#endif
|
|
|
|
#ifdef STM32F1
|
|
#define USART_ISR_RXNE USART_SR_RXNE
|
|
#endif
|
|
|
|
static void usart_isr(struct usart_console *console)
|
|
{
|
|
size_t i;
|
|
|
|
if (!console)
|
|
return;
|
|
|
|
while (usart_get_flag(console->dev, USART_ISR_RXNE)) {
|
|
console->recv_buf[console->next] = usart_recv(console->dev);
|
|
|
|
i = (console->next + 1) % RECV_BUF_LEN;
|
|
|
|
if (i != console->cur)
|
|
console->next = i;
|
|
}
|
|
}
|
|
|
|
void usart1_isr(void)
|
|
{
|
|
usart_isr(usart + 0);
|
|
}
|
|
|
|
void usart2_isr(void)
|
|
{
|
|
usart_isr(usart + 1);
|
|
}
|
|
|
|
int console_peek(char *c, struct console *console_, int block)
|
|
{
|
|
struct usart_console *console = container_of(console_,
|
|
struct usart_console, console);
|
|
|
|
while (block && console->cur == console->next);
|
|
|
|
if (console->cur != console->next) {
|
|
*c = console->recv_buf[console->cur];
|
|
return 0;
|
|
}
|
|
|
|
return -EAGAIN;
|
|
}
|
|
|
|
int console_getc(char *c, struct console *console_)
|
|
{
|
|
struct usart_console *console = container_of(console_,
|
|
struct usart_console, console);
|
|
|
|
if (console->cur == console->next)
|
|
return -1;
|
|
|
|
if (console->cur != console->next) {
|
|
*c = console->recv_buf[console->cur];
|
|
console->cur = (console->cur + 1) % RECV_BUF_LEN;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int console_getline(struct console *console_, char *buf, size_t n)
|
|
{
|
|
struct usart_console *console = container_of(console_,
|
|
struct usart_console, console);
|
|
char *p = buf + strlen(buf);
|
|
char c;
|
|
|
|
*p = '\0';
|
|
|
|
while (console_getc(&c, console_) == 0) {
|
|
switch (c) {
|
|
case '\r':
|
|
#if CONFIG_USER_ECHO
|
|
usart_send_blocking(console->dev, '\r');
|
|
usart_send_blocking(console->dev, '\n');
|
|
#endif
|
|
return 0;
|
|
case 10:
|
|
case 127:
|
|
if (buf < p) {
|
|
#if CONFIG_USER_ECHO
|
|
usart_send_blocking(console->dev, '\010');
|
|
usart_send_blocking(console->dev, ' ');
|
|
usart_send_blocking(console->dev, '\010');
|
|
#endif
|
|
|
|
--p;
|
|
}
|
|
|
|
break;
|
|
default:
|
|
*p = c;
|
|
#if CONFIG_USER_ECHO
|
|
usart_send_blocking(console->dev, c);
|
|
#endif
|
|
|
|
if (((size_t)p - (size_t)buf) < n) {
|
|
++p;
|
|
}
|
|
}
|
|
|
|
*p = '\0';
|
|
}
|
|
|
|
*p = '\0';
|
|
|
|
return -EAGAIN;
|
|
}
|
|
|
|
ssize_t console_read(struct console *console, char *buf, size_t n)
|
|
{
|
|
char *p = buf;
|
|
char c;
|
|
|
|
while (console_peek(&c, console, 1) == 0) {
|
|
switch (c) {
|
|
case '\004':
|
|
console_getc(&c, console);
|
|
return p - buf;
|
|
default:
|
|
if (((size_t)p - (size_t)buf) >= n)
|
|
return p - buf;
|
|
|
|
*p++ = c;
|
|
console_getc(&c, console);
|
|
break;
|
|
}
|
|
}
|
|
|
|
return p - buf;
|
|
}
|
|
|
|
static ssize_t usart_write(void *cookie, const char *buf, size_t n)
|
|
{
|
|
struct usart_console *console = cookie;
|
|
size_t i;
|
|
|
|
for (i = 0; i < n; ++i) {
|
|
if (buf[i] == '\r')
|
|
continue;
|
|
|
|
if (buf[i] == '\n') {
|
|
usart_send_blocking(console->dev, '\r');
|
|
}
|
|
|
|
usart_send_blocking(console->dev, buf[i]);
|
|
};
|
|
|
|
return i;
|
|
}
|
|
|
|
static int usart_get_irq_no(unsigned *irq_no, unsigned dev)
|
|
{
|
|
if (!irq_no)
|
|
return -1;
|
|
|
|
switch (dev) {
|
|
case USART1: *irq_no = NVIC_USART1_IRQ; break;
|
|
case USART2: *irq_no = NVIC_USART2_IRQ; break;
|
|
default: return -1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int usart_init(struct usart_console *console)
|
|
{
|
|
if (usart_get_irq_no(&console->irq_no, console->dev) < 0)
|
|
return -1;
|
|
|
|
usart_set_baudrate(console->dev, 115200);
|
|
usart_set_databits(console->dev, 8);
|
|
usart_set_parity(console->dev, USART_PARITY_NONE);
|
|
usart_set_stopbits(console->dev, USART_STOPBITS_1);
|
|
usart_set_mode(console->dev, USART_MODE_TX_RX);
|
|
usart_set_flow_control(console->dev, USART_FLOWCONTROL_NONE);
|
|
|
|
nvic_enable_irq(console->irq_no);
|
|
usart_enable(console->dev);
|
|
usart_enable_rx_interrupt(console->dev);
|
|
|
|
return 0;
|
|
}
|
|
|
|
struct console *console_init(unsigned dev_id)
|
|
{
|
|
cookie_io_functions_t fops = {
|
|
.read = NULL,
|
|
.write = usart_write,
|
|
.seek = NULL,
|
|
.close = NULL,
|
|
};
|
|
struct usart_console *console;
|
|
|
|
console = usart + dev_id;
|
|
|
|
switch (dev_id) {
|
|
case 0: console->dev = USART1; break;
|
|
case 1: console->dev = USART2; break;
|
|
default: return NULL;
|
|
}
|
|
|
|
console->cur = 0;
|
|
console->next = 0;
|
|
|
|
usart_init(console);
|
|
|
|
console->console.fp = fopencookie(console, "w", fops);
|
|
setvbuf(console->console.fp, NULL, _IONBF, 0);
|
|
|
|
return &console->console;
|
|
}
|
|
|