nrf/modules/machine/uart: Add timeout keyword options and "any" method.
Changes in this commit: - Add the timeout and timeout_char keyword options. - Make uart.read() non-blocking. - Add uart.any(). - Add ioctl MP_STREAM_POLL handling. - Change uart.write() into non-busy waiting. uart.write() still waits until all data has been sent, but calls MICROPY_EVENT_POLL_HOOK while waiting. uart.write() uses DMA for transfer. One option would be to add a small local buffer, such that transfers up to the size of the buffer could be done without waiting. - As a side effect to the change of uart.write(), uart.txdone() and ioctl flush now report/wait correctly for the end of transmission. - Change machine_hard_uart_buf_t in machine_hard_uart_obj_t to an instance of that struct, rather than a pointer to one.
This commit is contained in:
parent
42511b5291
commit
7ea192af05
@ -98,15 +98,15 @@ typedef struct _machine_hard_uart_buf_t {
|
|||||||
typedef struct _machine_hard_uart_obj_t {
|
typedef struct _machine_hard_uart_obj_t {
|
||||||
mp_obj_base_t base;
|
mp_obj_base_t base;
|
||||||
const nrfx_uart_t * p_uart; // Driver instance
|
const nrfx_uart_t * p_uart; // Driver instance
|
||||||
machine_hard_uart_buf_t *buf;
|
machine_hard_uart_buf_t buf;
|
||||||
|
uint16_t timeout; // timeout waiting for first char (in ms)
|
||||||
|
uint16_t timeout_char; // timeout waiting between chars (in ms)
|
||||||
} machine_hard_uart_obj_t;
|
} machine_hard_uart_obj_t;
|
||||||
|
|
||||||
static const nrfx_uart_t instance0 = NRFX_UART_INSTANCE(0);
|
static const nrfx_uart_t instance0 = NRFX_UART_INSTANCE(0);
|
||||||
|
|
||||||
STATIC machine_hard_uart_buf_t machine_hard_uart_buf[1];
|
STATIC machine_hard_uart_obj_t machine_hard_uart_obj[] = {
|
||||||
|
{{&machine_uart_type}, .p_uart = &instance0}
|
||||||
STATIC const machine_hard_uart_obj_t machine_hard_uart_obj[] = {
|
|
||||||
{{&machine_uart_type}, .p_uart = &instance0, .buf = &machine_hard_uart_buf[0]},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
void uart_init0(void) {
|
void uart_init0(void) {
|
||||||
@ -124,45 +124,45 @@ STATIC int uart_find(mp_obj_t id) {
|
|||||||
STATIC void uart_event_handler(nrfx_uart_event_t const *p_event, void *p_context) {
|
STATIC void uart_event_handler(nrfx_uart_event_t const *p_event, void *p_context) {
|
||||||
machine_hard_uart_obj_t *self = p_context;
|
machine_hard_uart_obj_t *self = p_context;
|
||||||
if (p_event->type == NRFX_UART_EVT_RX_DONE) {
|
if (p_event->type == NRFX_UART_EVT_RX_DONE) {
|
||||||
int chr = self->buf->rx_buf[0];
|
nrfx_uart_rx(self->p_uart, &self->buf.rx_buf[0], 1);
|
||||||
nrfx_uart_rx(self->p_uart, &self->buf->rx_buf[0], 1);
|
int chr = self->buf.rx_buf[0];
|
||||||
#if !MICROPY_PY_BLE_NUS && MICROPY_KBD_EXCEPTION
|
#if !MICROPY_PY_BLE_NUS && MICROPY_KBD_EXCEPTION
|
||||||
if (chr == mp_interrupt_char) {
|
if (chr == mp_interrupt_char) {
|
||||||
self->buf->rx_ringbuf.iget = 0;
|
self->buf.rx_ringbuf.iget = 0;
|
||||||
self->buf->rx_ringbuf.iput = 0;
|
self->buf.rx_ringbuf.iput = 0;
|
||||||
mp_sched_keyboard_interrupt();
|
mp_sched_keyboard_interrupt();
|
||||||
} else
|
} else
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
ringbuf_put((ringbuf_t*)&self->buf->rx_ringbuf, chr);
|
ringbuf_put((ringbuf_t *)&self->buf.rx_ringbuf, chr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool uart_rx_any(const machine_hard_uart_obj_t *self) {
|
bool uart_rx_any(machine_hard_uart_obj_t *self) {
|
||||||
return self->buf->rx_ringbuf.iput != self->buf->rx_ringbuf.iget;
|
return self->buf.rx_ringbuf.iput != self->buf.rx_ringbuf.iget;
|
||||||
}
|
}
|
||||||
|
|
||||||
int uart_rx_char(const machine_hard_uart_obj_t * self) {
|
int uart_rx_char(machine_hard_uart_obj_t *self) {
|
||||||
return ringbuf_get((ringbuf_t*)&self->buf->rx_ringbuf);
|
return ringbuf_get((ringbuf_t *)&self->buf.rx_ringbuf);
|
||||||
}
|
}
|
||||||
|
|
||||||
STATIC nrfx_err_t uart_tx_char(const machine_hard_uart_obj_t * self, int c) {
|
STATIC nrfx_err_t uart_tx_char(machine_hard_uart_obj_t *self, int c) {
|
||||||
while (nrfx_uart_tx_in_progress(self->p_uart)) {
|
while (nrfx_uart_tx_in_progress(self->p_uart)) {
|
||||||
;
|
;
|
||||||
}
|
}
|
||||||
self->buf->tx_buf[0] = c;
|
self->buf.tx_buf[0] = c;
|
||||||
return nrfx_uart_tx(self->p_uart, &self->buf->tx_buf[0], 1);
|
return nrfx_uart_tx(self->p_uart, &self->buf.tx_buf[0], 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void uart_tx_strn(const machine_hard_uart_obj_t *uart_obj, const char *str, uint len) {
|
void uart_tx_strn(machine_hard_uart_obj_t *uart_obj, const char *str, uint len) {
|
||||||
for (const char *top = str + len; str < top; str++) {
|
for (const char *top = str + len; str < top; str++) {
|
||||||
uart_tx_char(uart_obj, *str);
|
uart_tx_char(uart_obj, *str);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void uart_tx_strn_cooked(const machine_hard_uart_obj_t *uart_obj, const char *str, uint len) {
|
void uart_tx_strn_cooked(machine_hard_uart_obj_t *uart_obj, const char *str, uint len) {
|
||||||
for (const char *top = str + len; str < top; str++) {
|
for (const char *top = str + len; str < top; str++) {
|
||||||
if (*str == '\n') {
|
if (*str == '\n') {
|
||||||
uart_tx_char(uart_obj, '\r');
|
uart_tx_char(uart_obj, '\r');
|
||||||
@ -184,10 +184,12 @@ STATIC void machine_hard_uart_print(const mp_print_t *print, mp_obj_t self_in, m
|
|||||||
/// - `id`is bus id.
|
/// - `id`is bus id.
|
||||||
/// - `baudrate` is the clock rate.
|
/// - `baudrate` is the clock rate.
|
||||||
STATIC mp_obj_t machine_hard_uart_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) {
|
STATIC mp_obj_t machine_hard_uart_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) {
|
||||||
enum { ARG_id, ARG_baudrate };
|
enum { ARG_id, ARG_baudrate, ARG_timeout, ARG_timeout_char };
|
||||||
static const mp_arg_t allowed_args[] = {
|
static const mp_arg_t allowed_args[] = {
|
||||||
{ MP_QSTR_id, MP_ARG_REQUIRED | MP_ARG_OBJ },
|
{ MP_QSTR_id, MP_ARG_REQUIRED | MP_ARG_OBJ },
|
||||||
{ MP_QSTR_baudrate, MP_ARG_REQUIRED | MP_ARG_INT, {.u_int = 9600} },
|
{ MP_QSTR_baudrate, MP_ARG_REQUIRED | MP_ARG_INT, {.u_int = 9600} },
|
||||||
|
{ MP_QSTR_timeout, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 1} },
|
||||||
|
{ MP_QSTR_timeout_char, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 1} },
|
||||||
};
|
};
|
||||||
|
|
||||||
// parse args
|
// parse args
|
||||||
@ -196,7 +198,7 @@ STATIC mp_obj_t machine_hard_uart_make_new(const mp_obj_type_t *type, size_t n_a
|
|||||||
|
|
||||||
// get static peripheral object
|
// get static peripheral object
|
||||||
int uart_id = uart_find(args[ARG_id].u_obj);
|
int uart_id = uart_find(args[ARG_id].u_obj);
|
||||||
const machine_hard_uart_obj_t * self = &machine_hard_uart_obj[uart_id];
|
machine_hard_uart_obj_t *self = &machine_hard_uart_obj[uart_id];
|
||||||
|
|
||||||
nrfx_uart_config_t config;
|
nrfx_uart_config_t config;
|
||||||
|
|
||||||
@ -238,19 +240,21 @@ STATIC mp_obj_t machine_hard_uart_make_new(const mp_obj_type_t *type, size_t n_a
|
|||||||
config.pselrts = MICROPY_HW_UART1_RTS;
|
config.pselrts = MICROPY_HW_UART1_RTS;
|
||||||
config.pselcts = MICROPY_HW_UART1_CTS;
|
config.pselcts = MICROPY_HW_UART1_CTS;
|
||||||
#endif
|
#endif
|
||||||
|
self->timeout = args[ARG_timeout].u_int;
|
||||||
|
self->timeout_char = args[ARG_timeout_char].u_int;
|
||||||
|
|
||||||
// Set context to this instance of UART
|
// Set context to this instance of UART
|
||||||
config.p_context = (void *)self;
|
config.p_context = (void *)self;
|
||||||
|
|
||||||
// Initialise ring buffer
|
// Initialise ring buffer
|
||||||
self->buf->rx_ringbuf.buf = self->buf->rx_ringbuf_array;
|
self->buf.rx_ringbuf.buf = self->buf.rx_ringbuf_array;
|
||||||
self->buf->rx_ringbuf.size = sizeof(self->buf->rx_ringbuf_array);
|
self->buf.rx_ringbuf.size = sizeof(self->buf.rx_ringbuf_array);
|
||||||
self->buf->rx_ringbuf.iget = 0;
|
self->buf.rx_ringbuf.iget = 0;
|
||||||
self->buf->rx_ringbuf.iput = 0;
|
self->buf.rx_ringbuf.iput = 0;
|
||||||
|
|
||||||
// Enable event callback and start asynchronous receive
|
// Enable event callback and start asynchronous receive
|
||||||
nrfx_uart_init(self->p_uart, &config, uart_event_handler);
|
nrfx_uart_init(self->p_uart, &config, uart_event_handler);
|
||||||
nrfx_uart_rx(self->p_uart, &self->buf->rx_buf[0], 1);
|
nrfx_uart_rx(self->p_uart, &self->buf.rx_buf[0], 1);
|
||||||
|
|
||||||
#if NRFX_UART_ENABLED
|
#if NRFX_UART_ENABLED
|
||||||
nrfx_uart_rx_enable(self->p_uart);
|
nrfx_uart_rx_enable(self->p_uart);
|
||||||
@ -286,20 +290,29 @@ STATIC mp_obj_t machine_hard_uart_readchar(mp_obj_t self_in) {
|
|||||||
}
|
}
|
||||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(machine_hard_uart_readchar_obj, machine_hard_uart_readchar);
|
STATIC MP_DEFINE_CONST_FUN_OBJ_1(machine_hard_uart_readchar_obj, machine_hard_uart_readchar);
|
||||||
|
|
||||||
|
// uart.any()
|
||||||
|
STATIC mp_obj_t machine_uart_any(mp_obj_t self_in) {
|
||||||
|
machine_hard_uart_obj_t *self = self_in;
|
||||||
|
return MP_OBJ_NEW_SMALL_INT(ringbuf_avail((ringbuf_t *)&self->buf.rx_ringbuf));
|
||||||
|
}
|
||||||
|
STATIC MP_DEFINE_CONST_FUN_OBJ_1(machine_uart_any_obj, machine_uart_any);
|
||||||
|
|
||||||
// uart.sendbreak()
|
// uart.sendbreak()
|
||||||
STATIC mp_obj_t machine_hard_uart_sendbreak(mp_obj_t self_in) {
|
STATIC mp_obj_t machine_hard_uart_sendbreak(mp_obj_t self_in) {
|
||||||
return mp_const_none;
|
return mp_const_none;
|
||||||
}
|
}
|
||||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(machine_hard_uart_sendbreak_obj, machine_hard_uart_sendbreak);
|
STATIC MP_DEFINE_CONST_FUN_OBJ_1(machine_hard_uart_sendbreak_obj, machine_hard_uart_sendbreak);
|
||||||
|
|
||||||
// Since uart.write() waits up to the last byte, uart.txdone() always returns True.
|
// uart.txdone()
|
||||||
STATIC mp_obj_t machine_uart_txdone(mp_obj_t self_in) {
|
STATIC mp_obj_t machine_uart_txdone(mp_obj_t self_in) {
|
||||||
return mp_const_true;
|
machine_hard_uart_obj_t *self = self_in;
|
||||||
|
return mp_obj_new_bool(!nrfx_uart_tx_in_progress(self->p_uart));
|
||||||
}
|
}
|
||||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(machine_uart_txdone_obj, machine_uart_txdone);
|
STATIC MP_DEFINE_CONST_FUN_OBJ_1(machine_uart_txdone_obj, machine_uart_txdone);
|
||||||
|
|
||||||
STATIC const mp_rom_map_elem_t machine_hard_uart_locals_dict_table[] = {
|
STATIC const mp_rom_map_elem_t machine_hard_uart_locals_dict_table[] = {
|
||||||
// instance methods
|
// instance methods
|
||||||
|
{ MP_ROM_QSTR(MP_QSTR_any), MP_ROM_PTR(&machine_uart_any_obj) },
|
||||||
{ MP_ROM_QSTR(MP_QSTR_read), MP_ROM_PTR(&mp_stream_read_obj) },
|
{ MP_ROM_QSTR(MP_QSTR_read), MP_ROM_PTR(&mp_stream_read_obj) },
|
||||||
{ MP_ROM_QSTR(MP_QSTR_readline), MP_ROM_PTR(&mp_stream_unbuffered_readline_obj) },
|
{ MP_ROM_QSTR(MP_QSTR_readline), MP_ROM_PTR(&mp_stream_unbuffered_readline_obj) },
|
||||||
{ MP_ROM_QSTR(MP_QSTR_readinto), MP_ROM_PTR(&mp_stream_readinto_obj) },
|
{ MP_ROM_QSTR(MP_QSTR_readinto), MP_ROM_PTR(&mp_stream_readinto_obj) },
|
||||||
@ -321,14 +334,25 @@ STATIC const mp_rom_map_elem_t machine_hard_uart_locals_dict_table[] = {
|
|||||||
STATIC MP_DEFINE_CONST_DICT(machine_hard_uart_locals_dict, machine_hard_uart_locals_dict_table);
|
STATIC MP_DEFINE_CONST_DICT(machine_hard_uart_locals_dict, machine_hard_uart_locals_dict_table);
|
||||||
|
|
||||||
STATIC mp_uint_t machine_hard_uart_read(mp_obj_t self_in, void *buf_in, mp_uint_t size, int *errcode) {
|
STATIC mp_uint_t machine_hard_uart_read(mp_obj_t self_in, void *buf_in, mp_uint_t size, int *errcode) {
|
||||||
const machine_hard_uart_obj_t *self = self_in;
|
machine_hard_uart_obj_t *self = self_in;
|
||||||
byte *buf = buf_in;
|
byte *buf = buf_in;
|
||||||
|
uint32_t t = self->timeout + mp_hal_ticks_ms();
|
||||||
|
|
||||||
// read the data
|
// read the data
|
||||||
for (size_t i = 0; i < size; i++) {
|
for (size_t i = 0; i < size; i++) {
|
||||||
while (!uart_rx_any(self)) {
|
while (!uart_rx_any(self)) {
|
||||||
|
if ((int32_t)(mp_hal_ticks_ms() - t) >= 0) { // timed out
|
||||||
|
if (i == 0) {
|
||||||
|
*errcode = MP_EAGAIN;
|
||||||
|
return MP_STREAM_ERROR;
|
||||||
|
} else {
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
MICROPY_EVENT_POLL_HOOK;
|
||||||
}
|
}
|
||||||
buf[i] = uart_rx_char(self);
|
buf[i] = uart_rx_char(self);
|
||||||
|
t = self->timeout_char + mp_hal_ticks_ms();
|
||||||
}
|
}
|
||||||
|
|
||||||
return size;
|
return size;
|
||||||
@ -336,14 +360,12 @@ STATIC mp_uint_t machine_hard_uart_read(mp_obj_t self_in, void *buf_in, mp_uint_
|
|||||||
|
|
||||||
STATIC mp_uint_t machine_hard_uart_write(mp_obj_t self_in, const void *buf_in, mp_uint_t size, int *errcode) {
|
STATIC mp_uint_t machine_hard_uart_write(mp_obj_t self_in, const void *buf_in, mp_uint_t size, int *errcode) {
|
||||||
machine_hard_uart_obj_t *self = self_in;
|
machine_hard_uart_obj_t *self = self_in;
|
||||||
const byte *buf = buf_in;
|
|
||||||
|
|
||||||
nrfx_err_t err = NRFX_SUCCESS;
|
|
||||||
for (int i = 0; i < size; i++) {
|
|
||||||
err = uart_tx_char(self, (int)((uint8_t *)buf)[i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
nrfx_err_t err = nrfx_uart_tx(self->p_uart, buf_in, size);
|
||||||
if (err == NRFX_SUCCESS) {
|
if (err == NRFX_SUCCESS) {
|
||||||
|
while (nrfx_uart_tx_in_progress(self->p_uart)) {
|
||||||
|
MICROPY_EVENT_POLL_HOOK;
|
||||||
|
}
|
||||||
// return number of bytes written
|
// return number of bytes written
|
||||||
return size;
|
return size;
|
||||||
} else {
|
} else {
|
||||||
@ -355,9 +377,20 @@ STATIC mp_uint_t machine_hard_uart_write(mp_obj_t self_in, const void *buf_in, m
|
|||||||
STATIC mp_uint_t machine_hard_uart_ioctl(mp_obj_t self_in, mp_uint_t request, uintptr_t arg, int *errcode) {
|
STATIC mp_uint_t machine_hard_uart_ioctl(mp_obj_t self_in, mp_uint_t request, uintptr_t arg, int *errcode) {
|
||||||
machine_hard_uart_obj_t *self = self_in;
|
machine_hard_uart_obj_t *self = self_in;
|
||||||
(void)self;
|
(void)self;
|
||||||
|
mp_uint_t ret = 0;
|
||||||
|
|
||||||
if (request == MP_STREAM_FLUSH) {
|
if (request == MP_STREAM_POLL) {
|
||||||
// Since uart.write() waits up to the last byte, uart.flush() always succeds.
|
uintptr_t flags = arg;
|
||||||
|
if ((flags & MP_STREAM_POLL_RD) && uart_rx_any(self) != 0) {
|
||||||
|
ret |= MP_STREAM_POLL_RD;
|
||||||
|
}
|
||||||
|
if ((flags & MP_STREAM_POLL_WR) && !nrfx_uart_tx_in_progress(self->p_uart)) {
|
||||||
|
ret |= MP_STREAM_POLL_WR;
|
||||||
|
}
|
||||||
|
} else if (request == MP_STREAM_FLUSH) {
|
||||||
|
while (nrfx_uart_tx_in_progress(self->p_uart)) {
|
||||||
|
MICROPY_EVENT_POLL_HOOK;
|
||||||
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
return MP_STREAM_ERROR;
|
return MP_STREAM_ERROR;
|
||||||
|
@ -38,9 +38,9 @@ void uart_init0(void);
|
|||||||
void uart_deinit(void);
|
void uart_deinit(void);
|
||||||
void uart_irq_handler(mp_uint_t uart_id);
|
void uart_irq_handler(mp_uint_t uart_id);
|
||||||
|
|
||||||
bool uart_rx_any(const machine_hard_uart_obj_t * uart_obj);
|
bool uart_rx_any(machine_hard_uart_obj_t *uart_obj);
|
||||||
int uart_rx_char(const machine_hard_uart_obj_t * uart_obj);
|
int uart_rx_char(machine_hard_uart_obj_t *uart_obj);
|
||||||
void uart_tx_strn(const machine_hard_uart_obj_t * uart_obj, const char *str, uint len);
|
void uart_tx_strn(machine_hard_uart_obj_t *uart_obj, const char *str, uint len);
|
||||||
void uart_tx_strn_cooked(const machine_hard_uart_obj_t *uart_obj, const char *str, uint len);
|
void uart_tx_strn_cooked(machine_hard_uart_obj_t *uart_obj, const char *str, uint len);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
Loading…
x
Reference in New Issue
Block a user