Browse Source

zephyr: Re-implement the Zephyr console in non-blocking mode.

The standard Zephyr console implementation doesn't make use of
`tty_set_rx_timeout()` and therefore all the functions to receive
characters block indefinitely until data is received (including
`console_read()`).

This commit also releases the GIL where it applies, e.g. the REPL and the
time sleep functions.

Signed-off-by: danicampora <danicampora@gmail.com>
pull/15467/head
danicampora 4 months ago
committed by Damien George
parent
commit
d68d8fcf90
  1. 5
      ports/zephyr/mphalport.c
  2. 1
      ports/zephyr/mpthreadport.c
  3. 18
      ports/zephyr/src/zephyr_getchar.c
  4. 2
      ports/zephyr/src/zephyr_getchar.h
  5. 4
      ports/zephyr/src/zephyr_start.c
  6. 96
      ports/zephyr/uart_core.c

5
ports/zephyr/mphalport.c

@ -51,12 +51,15 @@ void mp_hal_wait_sem(struct k_sem *sem, uint32_t timeout_ms) {
k_poll_event_init(&wait_events[1], K_POLL_TYPE_SEM_AVAILABLE, K_POLL_MODE_NOTIFY_ONLY, sem);
}
for (;;) {
mp_handle_pending(true);
MP_THREAD_GIL_EXIT();
k_timeout_t wait;
if (timeout_ms == (uint32_t)-1) {
wait = K_FOREVER;
} else {
uint32_t dt = mp_hal_ticks_ms() - t0;
if (dt >= timeout_ms) {
MP_THREAD_GIL_ENTER();
return;
}
wait = K_MSEC(timeout_ms - dt);
@ -65,9 +68,9 @@ void mp_hal_wait_sem(struct k_sem *sem, uint32_t timeout_ms) {
if (wait_events[0].state == K_POLL_STATE_SIGNALED) {
wait_events[0].signal->signaled = 0;
wait_events[0].state = K_POLL_STATE_NOT_READY;
mp_handle_pending(true);
} else if (sem && wait_events[1].state == K_POLL_STATE_SEM_AVAILABLE) {
wait_events[1].state = K_POLL_STATE_NOT_READY;
MP_THREAD_GIL_ENTER();
return;
}
}

1
ports/zephyr/mpthreadport.c

@ -269,6 +269,7 @@ int mp_thread_mutex_lock(mp_thread_mutex_t *mutex, int wait) {
void mp_thread_mutex_unlock(mp_thread_mutex_t *mutex) {
k_sem_give(&mutex->handle);
k_yield();
}
void mp_thread_deinit(void) {

18
ports/zephyr/src/zephyr_getchar.c

@ -50,14 +50,16 @@ static int console_irq_input_hook(uint8_t ch) {
return 1;
}
uint8_t zephyr_getchar(void) {
mp_hal_wait_sem(&uart_sem, -1);
k_sem_take(&uart_sem, K_FOREVER);
unsigned int key = irq_lock();
uint8_t c = uart_ringbuf[i_get++];
i_get &= UART_BUFSIZE - 1;
irq_unlock(key);
return c;
int zephyr_getchar(void) {
mp_hal_wait_sem(&uart_sem, 0);
if (k_sem_take(&uart_sem, K_MSEC(0)) == 0) {
unsigned int key = irq_lock();
int c = (int)uart_ringbuf[i_get++];
i_get &= UART_BUFSIZE - 1;
irq_unlock(key);
return c;
}
return -1;
}
void zephyr_getchar_init(void) {

2
ports/zephyr/src/zephyr_getchar.h

@ -17,4 +17,4 @@
#include <stdint.h>
void zephyr_getchar_init(void);
uint8_t zephyr_getchar(void);
int zephyr_getchar(void);

4
ports/zephyr/src/zephyr_start.c

@ -24,14 +24,14 @@
* THE SOFTWARE.
*/
#include <zephyr/zephyr.h>
#include <zephyr/console/console.h>
#include "zephyr_getchar.h"
int real_main(void);
int mp_console_init(void);
void main(void) {
#ifdef CONFIG_CONSOLE_SUBSYS
console_init();
mp_console_init();
#else
zephyr_getchar_init();
#endif

96
ports/zephyr/uart_core.c

@ -25,10 +25,28 @@
*/
#include <unistd.h>
#include "py/mpconfig.h"
#include "py/runtime.h"
#include "src/zephyr_getchar.h"
// Zephyr headers
#include <zephyr/drivers/uart.h>
#include <zephyr/zephyr.h>
#include <zephyr/device.h>
#include <zephyr/console/console.h>
#include <zephyr/console/tty.h>
#include <zephyr/drivers/uart.h>
#ifdef CONFIG_CONSOLE_SUBSYS
static int mp_console_putchar(char c);
static int mp_console_getchar(void);
static struct tty_serial mp_console_serial;
static uint8_t mp_console_rxbuf[CONFIG_CONSOLE_GETCHAR_BUFSIZE];
static uint8_t mp_console_txbuf[CONFIG_CONSOLE_PUTCHAR_BUFSIZE];
#endif // CONFIG_CONSOLE_SUBSYS
/*
* Core UART functions to implement for a port
@ -36,11 +54,18 @@
// Receive single character
int mp_hal_stdin_rx_chr(void) {
#ifdef CONFIG_CONSOLE_SUBSYS
return console_getchar();
#else
return zephyr_getchar();
#endif
for (;;) {
int _chr;
#ifdef CONFIG_CONSOLE_SUBSYS
_chr = mp_console_getchar();
#else
_chr = zephyr_getchar();
#endif
if (_chr >= 0) {
return _chr;
}
MICROPY_EVENT_POLL_HOOK
}
}
// Send string of given length
@ -49,8 +74,8 @@ mp_uint_t mp_hal_stdout_tx_strn(const char *str, mp_uint_t len) {
#ifdef CONFIG_CONSOLE_SUBSYS
while (len--) {
char c = *str++;
while (console_putchar(c) == -1) {
k_msleep(1);
while (mp_console_putchar(c) == -1) {
MICROPY_EVENT_POLL_HOOK
}
}
#else
@ -63,3 +88,58 @@ mp_uint_t mp_hal_stdout_tx_strn(const char *str, mp_uint_t len) {
#endif
return ret;
}
#ifdef CONFIG_CONSOLE_SUBSYS
int mp_console_init(void) {
const struct device *uart_dev;
int ret;
uart_dev = DEVICE_DT_GET(DT_CHOSEN(zephyr_console));
if (!device_is_ready(uart_dev)) {
return -ENODEV;
}
ret = tty_init(&mp_console_serial, uart_dev);
if (ret) {
return ret;
}
/* Checks device driver supports for interrupt driven data transfers. */
if (CONFIG_CONSOLE_GETCHAR_BUFSIZE + CONFIG_CONSOLE_PUTCHAR_BUFSIZE) {
const struct uart_driver_api *api =
(const struct uart_driver_api *)uart_dev->api;
if (!api->irq_callback_set) {
return -ENOTSUP;
}
}
tty_set_tx_buf(&mp_console_serial, mp_console_txbuf, sizeof(mp_console_txbuf));
tty_set_rx_buf(&mp_console_serial, mp_console_rxbuf, sizeof(mp_console_rxbuf));
tty_set_rx_timeout(&mp_console_serial, 0);
tty_set_tx_timeout(&mp_console_serial, 1);
return 0;
}
static int mp_console_putchar(char c) {
return tty_write(&mp_console_serial, &c, 1);
}
static int mp_console_getchar(void) {
uint8_t c;
int res;
res = tty_read(&mp_console_serial, &c, 1);
if (res < 0) {
return res;
}
return c;
}
#endif // CONFIG_CONSOLE_SUBSYS

Loading…
Cancel
Save