|
29 | 29 | #include <stdarg.h> |
30 | 30 |
|
31 | 31 | #include "py/objtuple.h" |
| 32 | +#include "py/objarray.h" |
32 | 33 | #include "py/runtime.h" |
33 | 34 | #include "py/gc.h" |
| 35 | +#include "py/binary.h" |
34 | 36 | #include "py/stream.h" |
35 | 37 | #include "py/mperrno.h" |
36 | 38 | #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 * |
645 | 647 | } |
646 | 648 | STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_can_send_obj, 1, pyb_can_send); |
647 | 649 |
|
648 | | -/// \method recv(fifo, *, timeout=5000) |
| 650 | +/// \method recv(fifo, list=None, *, timeout=5000) |
649 | 651 | /// |
650 | 652 | /// Receive data on the bus: |
651 | 653 | /// |
652 | 654 | /// - `fifo` is an integer, which is the FIFO to receive on |
| 655 | +/// - `list` if not None is a list with at least 4 elements |
653 | 656 | /// - `timeout` is the timeout in milliseconds to wait for the receive. |
654 | 657 | /// |
655 | 658 | /// Return value: buffer of data bytes. |
656 | 659 | STATIC mp_obj_t pyb_can_recv(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { |
657 | | - enum { ARG_fifo, ARG_timeout }; |
| 660 | + enum { ARG_fifo, ARG_list, ARG_timeout }; |
658 | 661 | static const mp_arg_t allowed_args[] = { |
659 | 662 | { MP_QSTR_fifo, MP_ARG_REQUIRED | MP_ARG_INT, {.u_int = 0} }, |
| 663 | + { MP_QSTR_list, MP_ARG_OBJ, {.u_obj = mp_const_none} }, |
660 | 664 | { MP_QSTR_timeout, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 5000} }, |
661 | 665 | }; |
662 | 666 |
|
@@ -700,23 +704,49 @@ STATIC mp_obj_t pyb_can_recv(size_t n_args, const mp_obj_t *pos_args, mp_map_t * |
700 | 704 | } |
701 | 705 | } |
702 | 706 |
|
703 | | - // return the received data |
704 | | - // TODO use a namedtuple (when namedtuple types can be stored in ROM) |
705 | | - mp_obj_tuple_t *tuple = mp_obj_new_tuple(4, NULL); |
706 | | - if (rx_msg.IDE == CAN_ID_STD) { |
707 | | - tuple->items[0] = MP_OBJ_NEW_SMALL_INT(rx_msg.StdId); |
| 707 | + // Create the tuple, or get the list, that will hold the return values |
| 708 | + // Also populate the fourth element, either a new bytes or reuse existing memoryview |
| 709 | + mp_obj_t ret_obj = args[ARG_list].u_obj; |
| 710 | + mp_obj_t *items; |
| 711 | + if (ret_obj == mp_const_none) { |
| 712 | + ret_obj = mp_obj_new_tuple(4, NULL); |
| 713 | + items = ((mp_obj_tuple_t*)MP_OBJ_TO_PTR(ret_obj))->items; |
| 714 | + items[3] = mp_obj_new_bytes(&rx_msg.Data[0], rx_msg.DLC); |
708 | 715 | } else { |
709 | | - tuple->items[0] = MP_OBJ_NEW_SMALL_INT(rx_msg.ExtId); |
| 716 | + // User should provide a list of length at least 4 to hold the values |
| 717 | + if (!MP_OBJ_IS_TYPE(ret_obj, &mp_type_list)) { |
| 718 | + mp_raise_TypeError(NULL); |
| 719 | + } |
| 720 | + mp_obj_list_t *list = MP_OBJ_TO_PTR(ret_obj); |
| 721 | + if (list->len < 4) { |
| 722 | + mp_raise_ValueError(NULL); |
| 723 | + } |
| 724 | + items = list->items; |
| 725 | + // Fourth element must be a memoryview which we assume points to a |
| 726 | + // byte-like array which is large enough, and then we resize it inplace |
| 727 | + if (!MP_OBJ_IS_TYPE(items[3], &mp_type_memoryview)) { |
| 728 | + mp_raise_TypeError(NULL); |
| 729 | + } |
| 730 | + mp_obj_array_t *mv = MP_OBJ_TO_PTR(items[3]); |
| 731 | + if (!(mv->typecode == (0x80 | BYTEARRAY_TYPECODE) |
| 732 | + || (mv->typecode | 0x20) == (0x80 | 'b'))) { |
| 733 | + mp_raise_ValueError(NULL); |
| 734 | + } |
| 735 | + mv->len = rx_msg.DLC; |
| 736 | + memcpy(mv->items, &rx_msg.Data[0], rx_msg.DLC); |
710 | 737 | } |
711 | | - tuple->items[1] = rx_msg.RTR == CAN_RTR_REMOTE ? mp_const_true : mp_const_false; |
712 | | - tuple->items[2] = MP_OBJ_NEW_SMALL_INT(rx_msg.FMI); |
713 | | - vstr_t vstr; |
714 | | - vstr_init_len(&vstr, rx_msg.DLC); |
715 | | - for (mp_uint_t i = 0; i < rx_msg.DLC; i++) { |
716 | | - vstr.buf[i] = rx_msg.Data[i]; // Data is uint32_t but holds only 1 byte |
| 738 | + |
| 739 | + // Populate the first 3 values of the tuple/list |
| 740 | + if (rx_msg.IDE == CAN_ID_STD) { |
| 741 | + items[0] = MP_OBJ_NEW_SMALL_INT(rx_msg.StdId); |
| 742 | + } else { |
| 743 | + items[0] = MP_OBJ_NEW_SMALL_INT(rx_msg.ExtId); |
717 | 744 | } |
718 | | - tuple->items[3] = mp_obj_new_str_from_vstr(&mp_type_bytes, &vstr); |
719 | | - return tuple; |
| 745 | + items[1] = rx_msg.RTR == CAN_RTR_REMOTE ? mp_const_true : mp_const_false; |
| 746 | + items[2] = MP_OBJ_NEW_SMALL_INT(rx_msg.FMI); |
| 747 | + |
| 748 | + // Return the result |
| 749 | + return ret_obj; |
720 | 750 | } |
721 | 751 | STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_can_recv_obj, 1, pyb_can_recv); |
722 | 752 |
|
|
0 commit comments