stm32/can: Add "list" param to CAN.recv() to receive data inplace.
This API matches (as close as possible) how other pyb classes allow inplace operations, such as pyb.SPI.recv(buf).pull/1/head
parent
5e1279d41a
commit
0abbafd424
|
@ -187,11 +187,12 @@ Methods
|
|||
|
||||
Return ``True`` if any message waiting on the FIFO, else ``False``.
|
||||
|
||||
.. method:: CAN.recv(fifo, \*, timeout=5000)
|
||||
.. method:: CAN.recv(fifo, list=None, \*, timeout=5000)
|
||||
|
||||
Receive data on the bus:
|
||||
|
||||
- *fifo* is an integer, which is the FIFO to receive on
|
||||
- *list* is an optional list object to be used as the return value
|
||||
- *timeout* is the timeout in milliseconds to wait for the receive.
|
||||
|
||||
Return value: A tuple containing four values.
|
||||
|
@ -201,6 +202,24 @@ Methods
|
|||
- The FMI (Filter Match Index) value.
|
||||
- An array containing the data.
|
||||
|
||||
If *list* is ``None`` then a new tuple will be allocated, as well as a new
|
||||
bytes object to contain the data (as the fourth element in the tuple).
|
||||
|
||||
If *list* is not ``None`` then it should be a list object with a least four
|
||||
elements. The fourth element should be a memoryview object which is created
|
||||
from either a bytearray or an array of type 'B' or 'b', and this array must
|
||||
have enough room for at least 8 bytes. The list object will then be
|
||||
populated with the first three return values above, and the memoryview object
|
||||
will be resized inplace to the size of the data and filled in with that data.
|
||||
The same list and memoryview objects can be reused in subsequent calls to
|
||||
this method, providing a way of receiving data without using the heap.
|
||||
For example::
|
||||
|
||||
buf = bytearray(8)
|
||||
lst = [0, 0, 0, memoryview(buf)]
|
||||
# No heap memory is allocated in the following call
|
||||
can.recv(0, lst)
|
||||
|
||||
.. method:: CAN.send(data, id, \*, timeout=0, rtr=False)
|
||||
|
||||
Send a message on the bus:
|
||||
|
|
|
@ -29,8 +29,10 @@
|
|||
#include <stdarg.h>
|
||||
|
||||
#include "py/objtuple.h"
|
||||
#include "py/objarray.h"
|
||||
#include "py/runtime.h"
|
||||
#include "py/gc.h"
|
||||
#include "py/binary.h"
|
||||
#include "py/stream.h"
|
||||
#include "py/mperrno.h"
|
||||
#include "py/mphal.h"
|
||||
|
@ -645,18 +647,20 @@ STATIC mp_obj_t pyb_can_send(size_t n_args, const mp_obj_t *pos_args, mp_map_t *
|
|||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_can_send_obj, 1, pyb_can_send);
|
||||
|
||||
/// \method recv(fifo, *, timeout=5000)
|
||||
/// \method recv(fifo, list=None, *, timeout=5000)
|
||||
///
|
||||
/// Receive data on the bus:
|
||||
///
|
||||
/// - `fifo` is an integer, which is the FIFO to receive on
|
||||
/// - `list` if not None is a list with at least 4 elements
|
||||
/// - `timeout` is the timeout in milliseconds to wait for the receive.
|
||||
///
|
||||
/// Return value: buffer of data bytes.
|
||||
STATIC mp_obj_t pyb_can_recv(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
|
||||
enum { ARG_fifo, ARG_timeout };
|
||||
enum { ARG_fifo, ARG_list, ARG_timeout };
|
||||
static const mp_arg_t allowed_args[] = {
|
||||
{ MP_QSTR_fifo, MP_ARG_REQUIRED | MP_ARG_INT, {.u_int = 0} },
|
||||
{ MP_QSTR_list, MP_ARG_OBJ, {.u_obj = mp_const_none} },
|
||||
{ MP_QSTR_timeout, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 5000} },
|
||||
};
|
||||
|
||||
|
@ -700,23 +704,49 @@ STATIC mp_obj_t pyb_can_recv(size_t n_args, const mp_obj_t *pos_args, mp_map_t *
|
|||
}
|
||||
}
|
||||
|
||||
// return the received data
|
||||
// TODO use a namedtuple (when namedtuple types can be stored in ROM)
|
||||
mp_obj_tuple_t *tuple = mp_obj_new_tuple(4, NULL);
|
||||
if (rx_msg.IDE == CAN_ID_STD) {
|
||||
tuple->items[0] = MP_OBJ_NEW_SMALL_INT(rx_msg.StdId);
|
||||
// Create the tuple, or get the list, that will hold the return values
|
||||
// Also populate the fourth element, either a new bytes or reuse existing memoryview
|
||||
mp_obj_t ret_obj = args[ARG_list].u_obj;
|
||||
mp_obj_t *items;
|
||||
if (ret_obj == mp_const_none) {
|
||||
ret_obj = mp_obj_new_tuple(4, NULL);
|
||||
items = ((mp_obj_tuple_t*)MP_OBJ_TO_PTR(ret_obj))->items;
|
||||
items[3] = mp_obj_new_bytes(&rx_msg.Data[0], rx_msg.DLC);
|
||||
} else {
|
||||
tuple->items[0] = MP_OBJ_NEW_SMALL_INT(rx_msg.ExtId);
|
||||
// User should provide a list of length at least 4 to hold the values
|
||||
if (!MP_OBJ_IS_TYPE(ret_obj, &mp_type_list)) {
|
||||
mp_raise_TypeError(NULL);
|
||||
}
|
||||
mp_obj_list_t *list = MP_OBJ_TO_PTR(ret_obj);
|
||||
if (list->len < 4) {
|
||||
mp_raise_ValueError(NULL);
|
||||
}
|
||||
items = list->items;
|
||||
// Fourth element must be a memoryview which we assume points to a
|
||||
// byte-like array which is large enough, and then we resize it inplace
|
||||
if (!MP_OBJ_IS_TYPE(items[3], &mp_type_memoryview)) {
|
||||
mp_raise_TypeError(NULL);
|
||||
}
|
||||
mp_obj_array_t *mv = MP_OBJ_TO_PTR(items[3]);
|
||||
if (!(mv->typecode == (0x80 | BYTEARRAY_TYPECODE)
|
||||
|| (mv->typecode | 0x20) == (0x80 | 'b'))) {
|
||||
mp_raise_ValueError(NULL);
|
||||
}
|
||||
mv->len = rx_msg.DLC;
|
||||
memcpy(mv->items, &rx_msg.Data[0], rx_msg.DLC);
|
||||
}
|
||||
tuple->items[1] = rx_msg.RTR == CAN_RTR_REMOTE ? mp_const_true : mp_const_false;
|
||||
tuple->items[2] = MP_OBJ_NEW_SMALL_INT(rx_msg.FMI);
|
||||
vstr_t vstr;
|
||||
vstr_init_len(&vstr, rx_msg.DLC);
|
||||
for (mp_uint_t i = 0; i < rx_msg.DLC; i++) {
|
||||
vstr.buf[i] = rx_msg.Data[i]; // Data is uint32_t but holds only 1 byte
|
||||
|
||||
// Populate the first 3 values of the tuple/list
|
||||
if (rx_msg.IDE == CAN_ID_STD) {
|
||||
items[0] = MP_OBJ_NEW_SMALL_INT(rx_msg.StdId);
|
||||
} else {
|
||||
items[0] = MP_OBJ_NEW_SMALL_INT(rx_msg.ExtId);
|
||||
}
|
||||
tuple->items[3] = mp_obj_new_str_from_vstr(&mp_type_bytes, &vstr);
|
||||
return tuple;
|
||||
items[1] = rx_msg.RTR == CAN_RTR_REMOTE ? mp_const_true : mp_const_false;
|
||||
items[2] = MP_OBJ_NEW_SMALL_INT(rx_msg.FMI);
|
||||
|
||||
// Return the result
|
||||
return ret_obj;
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_can_recv_obj, 1, pyb_can_recv);
|
||||
|
||||
|
|
Loading…
Reference in New Issue