8000 esp8266/uart: rework uart io structure so it can work with dupterm() and be used to disable stdio by mhoffma · Pull Request #2891 · micropython/micropython · GitHub
[go: up one dir, main page]

Skip to content

esp8266/uart: rework uart io structure so it can work with dupterm() and be used to disable stdio #2891

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

Closed
wants to merge 12 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
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
31 changes: 30 additions & 1 deletion esp8266/esp_mphal.c
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,10 @@ int mp_hal_stdin_rx_chr(void) {
}

void mp_hal_stdout_tx_char(char c) {
uart_tx_one_char(UART0, c);
mp_obj_t term = MP_STATE_PORT(term_obj);
if (term == NULL || term == MP_OBJ_NULL) {
uart_tx_one_char(UART0, c);
}
mp_uos_dupterm_tx_strn(&c, 1);
}

Expand Down Expand Up @@ -146,6 +149,32 @@ void mp_hal_signal_input(void) {
#endif
}

void mp_hal_uart_rx_intr(int uart_no) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IMO this belongs in machine_uart.c, since it's specific to UART behaviour. Also, since UART1 can't receive it doesn't need to take an argument.

int ch;
mp_obj_t term = MP_STATE_PORT(term_obj);
bool uart_term = (term == NULL || term == MP_STATE_PORT(pyb_uart_objs)[uart_no]);

for (;;) {
if ((ch = uart_rx_one_char(uart_no)) == -1) {
break;
}
if (uart_term) {
if (ch == mp_interrupt_char) {
mp_keyboard_interrupt();
} else {
ringbuf_put(&input_buf, ch);
}
} else {
void mp_uart_stuff_rx(mp_obj_t self_in, byte ch);
mp_uart_stuff_rx(MP_STATE_PORT(pyb_uart_objs)[uart_no],ch);
}
}
if (uart_term) {
mp_hal_signal_input();
}
}


static int call_dupterm_read(void) {
if (MP_STATE_PORT(term_obj) == NULL) {
return -1;
Expand Down
2 changes: 2 additions & 0 deletions esp8266/esp_mphal.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@ extern const struct _mp_print_t mp_debug_print;
extern ringbuf_t input_buf;
// Call this after putting data to input_buf
void mp_hal_signal_input(void);
// Call this to put characters into connected uart buffer if repl connected
void mp_hal_uart_rx_intr(int uart_no);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The way this function is currently implemented, it handles chars even if REPL is not connected.

// Call this when data is available in dupterm object
void mp_hal_signal_dupterm_input(void);

Expand Down
67 changes: 59 additions & 8 deletions esp8266/machine_uart.c
< 8000 td class="blob-code blob-code-addition js-file-line"> #include "user_interface.h"
Original file line number Diff line number Diff line change
Expand Up @@ -29,11 +29,14 @@
#include <string.h>

#include "ets_sys.h"
#include "uart.h"
#include "esp_mphal.h"

#include "py/runtime.h"
#include "py/stream.h"
#include "py/mperrno.h"
#include "py/ringbuf.h"
#include "modmachine.h"

// UartDev is defined and initialized in rom code.
Expand All @@ -48,22 +51,33 @@ typedef struct _pyb_uart_obj_t {
uint32_t baudrate;
uint16_t timeout; // timeout waiting for first char (in ms)
uint16_t timeout_char; // timeout waiting between chars (in ms)
uint16_t rxbuflen;
ringbuf_t rxbuf;
byte *buf;
} pyb_uart_obj_t;

pyb_uart_obj_t pyb_uart_objs[2];

STATIC const char *_parity_name[] = {"None", "1", "0"};

/******************************************************************************/
// MicroPython bindings for UART

void uart_init0 (void) {
// save references of the UART objects, to prevent the read buffers from being trashed by the gc
MP_STATE_PORT(pyb_uart_objs)[0] = &pyb_uart_objs[0];
MP_STATE_PORT(pyb_uart_objs)[1] = &pyb_uart_objs[1];
}

STATIC void pyb_uart_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
pyb_uart_obj_t *self = MP_OBJ_TO_PTR(self_in);
mp_printf(print, "UART(%u, baudrate=%u, bits=%u, parity=%s, stop=%u, timeout=%u, timeout_char=%u)",
mp_printf(print, "UART(%u, baudrate=%u, bits=%u, parity=%s, stop=%u, timeout=%u, timeout_char=%u, rxbuflen=%u)",
self->uart_id, self->baudrate, self->bits, _parity_name[self->parity],
self->stop, self->timeout, self->timeout_char);
self->stop, self->timeout, self->timeout_char, self->rxbuflen);
}

STATIC void pyb_uart_init_helper(pyb_uart_obj_t *self, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
enum { ARG_baudrate, ARG_bits, ARG_parity, ARG_stop, ARG_timeout, ARG_timeout_char };
enum { ARG_baudrate, ARG_bits, ARG_parity, ARG_stop, ARG_timeout, ARG_timeout_char, ARG_rxbuflen };
static const mp_arg_t allowed_args[] = {
{ MP_QSTR_baudrate, MP_ARG_INT, {.u_int = 0} },
{ MP_QSTR_bits, MP_ARG_INT, {.u_int = 0} },
Expand All @@ -73,6 +87,7 @@ STATIC void pyb_uart_init_helper(pyb_uart_obj_t *self, size_t n_args, const mp_o
//{ MP_QSTR_rx, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
{ MP_QSTR_timeout, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} },
{ MP_QSTR_timeout_char, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} },
{ MP_QSTR_rxbuflen, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 16} },
};
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
Expand Down Expand Up @@ -155,6 +170,7 @@ STATIC void pyb_uart_init_helper(pyb_uart_obj_t *self, size_t n_args, const mp_o
self->timeout_char = min_timeout_char;
}

self->rxbuflen = args[ARG_rxbuflen].u_int;
// setup
uart_setup(self->uart_id);
}
Expand All @@ -169,7 +185,7 @@ STATIC mp_obj_t pyb_uart_make_new(const mp_obj_type_t *type, size_t n_args, size
}

// create instance
pyb_uart_obj_t *self = m_new_obj(pyb_uart_obj_t);
pyb_uart_obj_t *self = &pyb_uart_objs[uart_id];
self->base.type = &pyb_uart_type;
self->uart_id = uart_id;
self->baudrate = 115200;
Expand All @@ -182,8 +198,20 @@ STATIC mp_obj_t pyb_uart_make_new(const mp_obj_type_t *type, size_t n_args, size
// init the peripheral
mp_map_t kw_args;
mp_map_init_fixed_table(&kw_args, n_kw, args + n_args);

pyb_uart_init_helper(self, n_args - 1, args + 1, &kw_args);

if (self->rxbuflen) {
if (self->buf) {
m_free(self->buf);
}
self->buf = m_malloc(self->rxbuflen);
}

self->rxbuf.buf = self->buf;
self->rxbuf.size = self->rxbuflen;
self->rxbuf.iget = self->rxbuf.iput=0;

return MP_OBJ_FROM_PTR(self);
}

Expand Down Expand Up @@ -211,6 +239,27 @@ STATIC const mp_rom_map_elem_t pyb_uart_locals_dict_table[] = {

STATIC MP_DEFINE_CONST_DICT(pyb_uart_locals_dict, pyb_uart_locals_dict_table);

void mp_uart_stuff_rx(mp_obj_t self_in, byte ch) {
pyb_uart_obj_t *self = MP_OBJ_TO_PTR(self_in);
ringbuf_put(&self->rxbuf,ch);
}

// Waits at most timeout microseconds for at least 1 char to become ready for reading.
// Returns true if something available, false if not.
STATIC bool uart_rx_wait(pyb_uart_obj_t *self, uint32_t timeout_us) {
uint32_t start = system_get_time();

for (;;) {
if (*( volatile uint16_t *)(&self->rxbuf.iput) != self->rxbuf.iget) {
return true; // have at least 1 char ready for reading
}
if (timeout_us && system_get_time() - start >= timeout_us) {
return false; // timeout
}
ets_event_poll();
}
}

STATIC mp_uint_t pyb_uart_read(mp_obj_t self_in, void *buf_in, mp_uint_t size, int *errcode) {
pyb_uart_obj_t *self = MP_OBJ_TO_PTR(self_in);

Expand All @@ -224,16 +273,18 @@ STATIC mp_uint_t pyb_uart_read(mp_obj_t self_in, void *buf_in, mp_uint_t size, i
}

// wait for first char to become available
if (!uart_rx_wait(self->timeout * 1000)) {
if (!uart_rx_wait(self, self->timeout * 1000)) {
*errcode = MP_EAGAIN;
return MP_STREAM_ERROR;
}

// read the data
uint8_t *buf = buf_in;
for (;;) {
*buf++ = uart_rx_char();
if (--size == 0 || !uart_rx_wait(self->timeout_char * 1000)) {
char ch = ringbuf_get(&self->rxbuf);
int avail = uart_rx_wait(self, self->timeout_char * 1000);
*buf++ = ch;
if (--size == 0 || !avail) {
// return number of bytes read
return buf - (uint8_t*)buf_in;
}
Expand Down Expand Up @@ -267,7 +318,7 @@ STATIC mp_uint_t pyb_uart_ioctl(mp_obj_t self_in, mp_uint_t request, mp_uint_t a
if (request == MP_STREAM_POLL) {
mp_uint_t flags = arg;
ret = 0;
if ((flags & MP_STREAM_POLL_RD) && uart_rx_any(self->uart_id)) {
if ((flags & MP_STREAM_POLL_RD) && self->rxbuf.iget != self->rxbuf.iput) {
ret |= MP_STREAM_POLL_RD;
}
if ((flags & MP_STREAM_POLL_WR) && uart_tx_any_room(self->uart_id)) {
Expand Down
3 changes: 3 additions & 0 deletions esp8266/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@
#include "gccollect.h"
#include "user_interface.h"

void uart_init0 (void);

STATIC char heap[36 * 1024];

STATIC void mp_reset(void) {
Expand All @@ -60,6 +62,7 @@ STATIC void mp_reset(void) {
esp_native_code_init();
#endif
pin_init0();
uart_init0();
readline_init0();
dupterm_task_init();
#if MICROPY_MODULE_FROZEN
Expand Down
1 change: 1 addition & 0 deletions esp8266/mpconfigport.h
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,7 @@ extern const struct _mp_obj_module_t onewire_module;
#define MICROPY_PORT_ROOT_POINTERS \
const char *readline_hist[8]; \
mp_obj_t pin_irq_handler[16]; \
struct _pyb_uart_obj_t *pyb_uart_objs[2]; \

// We need to provide a declaration/definition of alloca()
#include <alloca.h>
Expand Down
39 changes: 5 additions & 34 deletions esp8266/uart.c
Original file line number Diff line number Diff line change
Expand Up @@ -167,58 +167,29 @@ static void uart0_rx_intr_handler(void *para) {
} else if (UART_RXFIFO_TOUT_INT_ST == (READ_PERI_REG(UART_INT_ST(uart_no)) & UART_RXFIFO_TOUT_INT_ST)) {
read_chars:
ETS_UART_INTR_DISABLE();

while (READ_PERI_REG(UART_STATUS(uart_no)) & (UART_RXFIFO_CNT << UART_RXFIFO_CNT_S)) {
uint8 RcvChar = READ_PERI_REG(UART_FIFO(uart_no)) & 0xff;
if (RcvChar == mp_interrupt_char) {
mp_keyboard_interrupt();
} else {
ringbuf_put(&input_buf, RcvChar);
}
}

mp_hal_signal_input();

mp_hal_uart_rx_intr(uart_no);
// Clear pending FIFO interrupts
WRITE_PERI_REG(UART_INT_CLR(UART_REPL), UART_RXFIFO_TOUT_INT_CLR | UART_RXFIFO_FULL_INT_ST);
ETS_UART_INTR_ENABLE();
}
}

// Waits at most timeout microseconds for at least 1 char to become ready for reading.
// Returns true if something available, false if not.
bool uart_rx_wait(uint32_t timeout_us) {
uint32_t start = system_get_time();
for (;;) {
if (input_buf.iget != input_buf.iput) {
return true; // have at least 1 char ready for reading
}
if (system_get_time() - start >= timeout_us) {
return false; // timeout
}
ets_event_poll();
}
}

int uart_rx_any(uint8 uart) {
if (input_buf.iget != input_buf.iput) {
int uart_rx_any(uint8 uart_no) {
if (READ_PERI_REG(UART_STATUS(uart_no)) & (UART_RXFIFO_CNT << UART_RXFIFO_CNT_S)) {
return true; // have at least 1 char ready for reading
}
return false;
}

int uart_tx_any_room(uint8 uart) {
uint32_t fifo_cnt = READ_PERI_REG(UART_STATUS(uart)) & (UART_TXFIFO_CNT << UART_TXFIFO_CNT_S);
int uart_tx_any_room(uint8 uart_no) {
uint32_t fifo_cnt = READ_PERI_REG(UART_STATUS(uart_no)) & (UART_TXFIFO_CNT << UART_TXFIFO_CNT_S);
if ((fifo_cnt >> UART_TXFIFO_CNT_S & UART_TXFIFO_CNT) >= 126) {
return false;
}
return true;
}

// Returns char from the input buffer, else -1 if buffer is empty.
int uart_rx_char(void) {
return ringbuf_get(&input_buf);
}

int uart_rx_one_char(uint8 uart_no) {
if (READ_PERI_REG(UART_STATUS(uart_no)) & (UART_RXFIFO_CNT << UART_RXFIFO_CNT_S)) {
Expand Down
3 changes: 1 addition & 2 deletions esp8266/uart.h
Original file line number Diff line number Diff line change
Expand Up @@ -93,8 +93,7 @@ typedef struct {

void uart_init(UartBautRate uart0_br, UartBautRate uart1_br);
int uart0_rx(void);
bool uart_rx_wait(uint32_t timeout_us);
int uart_rx_char(void);
int uart_rx_one_char(uint8 uart);
void uart_tx_one_char(uint8 uart, uint8 TxChar);
void uart_flush(uint8 uart);
void uart_os_config(int uart);
Expand Down
0