diff --git a/docs/library/pyb.CAN.rst b/docs/library/pyb.CAN.rst index 46e6d08cf144eb2469f7791090bced69f098fcc2..e5d2b9acb1bb8c61a705cf1fc1501fc459d36a58 100644 --- a/docs/library/pyb.CAN.rst +++ b/docs/library/pyb.CAN.rst @@ -82,7 +82,7 @@ Methods Turn off the CAN bus. -.. method:: can.setfilter(bank, mode, fifo, params) +.. method:: can.setfilter(bank, mode, fifo, params, \*, rtr) Configure a filter bank: @@ -107,6 +107,23 @@ Methods |CAN.MASK32 |As with CAN.MASK16 but with only one 32 bit id/mask pair.| +-----------+---------------------------------------------------------+ + - ``rtr`` is an array of booleans that states if a filter should accept a + remote transmission request message. If this argument is not given + then it defaults to False for all entries. The length of the array + depends on the ``mode`` argument. + + +-----------+----------------------+ + |``mode`` |length of rtr array | + +===========+======================+ + |CAN.LIST16 |4 | + +-----------+----------------------+ + |CAN.LIST32 |2 | + +-----------+----------------------+ + |CAN.MASK16 |2 | + +-----------+----------------------+ + |CAN.MASK32 |1 | + +-----------+----------------------+ + .. method:: can.clearfilter(bank) Clear and disables a filter bank: @@ -124,15 +141,24 @@ Methods - ``fifo`` is an integer, which is the FIFO to receive on - ``timeout`` is the timeout in milliseconds to wait for the receive. - Return value: buffer of data bytes. + Return value: A tuple containing four values. + + - The id of the message. + - A boolean that indicates if the message is an RTR message. + - The FMI (Filter Match Index) value. + - An array containing the data. -.. method:: can.send(send, addr, \*, timeout=0) +.. method:: can.send(data, id, \*, timeout=0, rtr=False) Send a message on the bus: - - ``send`` is the data to send (an integer to send, or a buffer object). - - ``addr`` is the address to send to + - ``data`` is the data to send (an integer to send, or a buffer object). + - ``id`` is the id of the message to be sent. - ``timeout`` is the timeout in milliseconds to wait for the send. + - ``rtr`` is a boolean that specifies if the message shall be sent as + a remote transmission request. If ``rtr`` is True then only the length + of ``data`` is used to fill in the DLC slot of the frame; the actual + bytes in ``data`` are unused. If timeout is 0 the message is placed in a buffer in one of three hardware buffers and the method returns immediately. If all three buffers are in use diff --git a/stmhal/can.c b/stmhal/can.c index f60f79532da01fee0a20f055e3781df77bbe8eb7..f4758399cec6010343ea6e72e8cc23b4b653e87b 100644 --- a/stmhal/can.c +++ b/stmhal/can.c @@ -436,9 +436,10 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_2(pyb_can_any_obj, pyb_can_any); /// Return value: `None`. STATIC mp_obj_t pyb_can_send(mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { static const mp_arg_t allowed_args[] = { - { MP_QSTR_send, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, - { MP_QSTR_addr, MP_ARG_REQUIRED | MP_ARG_INT, {.u_int = 0} }, + { MP_QSTR_data, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, + { MP_QSTR_id, MP_ARG_REQUIRED | MP_ARG_INT, {.u_int = 0} }, { MP_QSTR_timeout, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} }, + { MP_QSTR_rtr, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = false} }, }; // parse args @@ -464,11 +465,16 @@ STATIC mp_obj_t pyb_can_send(mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_ tx_msg.StdId = args[1].u_int & 0x7FF; tx_msg.IDE = CAN_ID_STD; } - tx_msg.RTR = CAN_RTR_DATA; + if (args[3].u_bool == false) { + tx_msg.RTR = CAN_RTR_DATA; + } else { + tx_msg.RTR = CAN_RTR_REMOTE; + } tx_msg.DLC = bufinfo.len; for (mp_uint_t i = 0; i < bufinfo.len; i++) { tx_msg.Data[i] = ((byte*)bufinfo.buf)[i]; // Data is uint32_t but holds only 1 byte } + self->can.pTxMsg = &tx_msg; HAL_StatusTypeDef status = CAN_Transmit(&self->can, args[2].u_int); @@ -543,7 +549,7 @@ STATIC mp_obj_t pyb_can_recv(mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_ } else { tuple->items[0] = MP_OBJ_NEW_SMALL_INT(rx_msg.ExtId); } - tuple->items[1] = MP_OBJ_NEW_SMALL_INT(rx_msg.RTR); + 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); @@ -597,6 +603,7 @@ STATIC mp_obj_t pyb_can_setfilter(mp_uint_t n_args, const mp_obj_t *pos_args, mp { MP_QSTR_mode, MP_ARG_REQUIRED | MP_ARG_INT, {.u_int = 0} }, { MP_QSTR_fifo, MP_ARG_REQUIRED | MP_ARG_INT, {.u_int = CAN_FILTER_FIFO0} }, { MP_QSTR_params, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, + { MP_QSTR_rtr, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, }; // parse args @@ -605,8 +612,14 @@ STATIC mp_obj_t pyb_can_setfilter(mp_uint_t n_args, const mp_obj_t *pos_args, mp mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); mp_uint_t len; + mp_uint_t rtr_len; + mp_uint_t rtr_masks[4] = {0, 0, 0, 0}; + mp_obj_t *rtr_flags; mp_obj_t *params; mp_obj_get_array(args[3].u_obj, &len, ¶ms); + if (args[4].u_obj != MP_OBJ_NULL){ + mp_obj_get_array(args[4].u_obj, &rtr_len, &rtr_flags); + } CAN_FilterConfTypeDef filter; if (args[1].u_int == MASK16 || args[1].u_int == LIST16) { @@ -615,15 +628,41 @@ STATIC mp_obj_t pyb_can_setfilter(mp_uint_t n_args, const mp_obj_t *pos_args, mp } filter.FilterScale = CAN_FILTERSCALE_16BIT; if (self->extframe) { - filter.FilterIdLow = EXTENDED_ID_TO_16BIT_FILTER(mp_obj_get_int(params[0])); // id1 - filter.FilterMaskIdLow = EXTENDED_ID_TO_16BIT_FILTER(mp_obj_get_int(params[1])); // mask1 - filter.FilterIdHigh = EXTENDED_ID_TO_16BIT_FILTER(mp_obj_get_int(params[2])); // id2 - filter.FilterMaskIdHigh = EXTENDED_ID_TO_16BIT_FILTER(mp_obj_get_int(params[3])); // mask2 - } else { - filter.FilterIdLow = mp_obj_get_int(params[0]) << 5; // id1 - filter.FilterMaskIdLow = mp_obj_get_int(params[1]) << 5; // mask1 - filter.FilterIdHigh = mp_obj_get_int(params[2]) << 5; // id2 - filter.FilterMaskIdHigh = mp_obj_get_int(params[3]) << 5; // mask2 + if (args[4].u_obj != MP_OBJ_NULL) { + if (args[1].u_int == MASK16) { + rtr_masks[0] = mp_obj_get_int(rtr_flags[0]) ? 0x02 : 0; + rtr_masks[1] = 0x02; + rtr_masks[2] = mp_obj_get_int(rtr_flags[1]) ? 0x02 : 0; + rtr_masks[3] = 0x02; + } else { // LIST16 + rtr_masks[0] = mp_obj_get_int(rtr_flags[0]) ? 0x02 : 0; + rtr_masks[1] = mp_obj_get_int(rtr_flags[1]) ? 0x02 : 0; + rtr_masks[2] = mp_obj_get_int(rtr_flags[2]) ? 0x02 : 0; + rtr_masks[3] = mp_obj_get_int(rtr_flags[3]) ? 0x02 : 0; + } + } + filter.FilterIdLow = EXTENDED_ID_TO_16BIT_FILTER(mp_obj_get_int(params[0])) | rtr_masks[0]; // id1 + filter.FilterMaskIdLow = EXTENDED_ID_TO_16BIT_FILTER(mp_obj_get_int(params[1])) | rtr_masks[1]; // mask1 + filter.FilterIdHigh = EXTENDED_ID_TO_16BIT_FILTER(mp_obj_get_int(params[2])) | rtr_masks[2]; // id2 + filter.FilterMaskIdHigh = EXTENDED_ID_TO_16BIT_FILTER(mp_obj_get_int(params[3])) | rtr_masks[3]; // mask2 + } else { // Basic frames + if (args[4].u_obj != MP_OBJ_NULL) { + if (args[1].u_int == MASK16) { + rtr_masks[0] = mp_obj_get_int(rtr_flags[0]) ? 0x10 : 0; + rtr_masks[1] = 0x10; + rtr_masks[2] = mp_obj_get_int(rtr_flags[1]) ? 0x10 : 0; + rtr_masks[3] = 0x10; + } else { // LIST16 + rtr_masks[0] = mp_obj_get_int(rtr_flags[0]) ? 0x10 : 0; + rtr_masks[1] = mp_obj_get_int(rtr_flags[1]) ? 0x10 : 0; + rtr_masks[2] = mp_obj_get_int(rtr_flags[2]) ? 0x10 : 0; + rtr_masks[3] = mp_obj_get_int(rtr_flags[3]) ? 0x10 : 0; + } + } + filter.FilterIdLow = (mp_obj_get_int(params[0]) << 5) | rtr_masks[0]; // id1 + filter.FilterMaskIdLow = (mp_obj_get_int(params[1]) << 5) | rtr_masks[1]; // mask1 + filter.FilterIdHigh = (mp_obj_get_int(params[2]) << 5) | rtr_masks[2]; // id2 + filter.FilterMaskIdHigh = (mp_obj_get_int(params[3]) << 5) | rtr_masks[3]; // mask2 } if (args[1].u_int == MASK16) { filter.FilterMode = CAN_FILTERMODE_IDMASK; @@ -636,12 +675,20 @@ STATIC mp_obj_t pyb_can_setfilter(mp_uint_t n_args, const mp_obj_t *pos_args, mp if (len != 2) { goto error; } - filter.FilterScale = CAN_FILTERSCALE_32BIT; - + filter.FilterScale = CAN_FILTERSCALE_32BIT; + if (args[4].u_obj != MP_OBJ_NULL) { + if (args[1].u_int == MASK32) { + rtr_masks[0] = mp_obj_get_int(rtr_flags[0]) ? 0x02 : 0; + rtr_masks[1] = 0x02; + } else { // LIST32 + rtr_masks[0] = mp_obj_get_int(rtr_flags[0]) ? 0x02 : 0; + rtr_masks[1] = mp_obj_get_int(rtr_flags[1]) ? 0x02 : 0; + } + } filter.FilterIdHigh = (mp_obj_get_int(params[0]) & 0xFF00) >> 13; - filter.FilterIdLow = ((mp_obj_get_int(params[0]) & 0x00FF) << 3) | 4; + filter.FilterIdLow = (((mp_obj_get_int(params[0]) & 0x00FF) << 3) | 4) | rtr_masks[0]; filter.FilterMaskIdHigh = (mp_obj_get_int(params[1]) & 0xFF00 ) >> 13; - filter.FilterMaskIdLow = ((mp_obj_get_int(params[1]) & 0x00FF) << 3) | 4; + filter.FilterMaskIdLow = (((mp_obj_get_int(params[1]) & 0x00FF) << 3) | 4) | rtr_masks[1]; if (args[1].u_int == MASK32) { filter.FilterMode = CAN_FILTERMODE_IDMASK; } diff --git a/stmhal/qstrdefsport.h b/stmhal/qstrdefsport.h index e992f545ba62fcf453e8741dddc66940d0b5e786..3c265b616dab720d704e412321bb279a5405f6e0 100644 --- a/stmhal/qstrdefsport.h +++ b/stmhal/qstrdefsport.h @@ -213,6 +213,7 @@ Q(initfilterbanks) Q(clearfilter) Q(setfilter) Q(rxcallback) +Q(rtr) Q(NORMAL) Q(LOOPBACK) Q(SILENT) diff --git a/tests/pyb/can.py b/tests/pyb/can.py index 5fd4d39d05d328fceb6bd9ae473e1f139ee96e8e..63a3be4e925fd8b372b7a579ba1c0d155863bf37 100644 --- a/tests/pyb/can.py +++ b/tests/pyb/can.py @@ -151,3 +151,40 @@ except OSError as e: pyb.delay(500) while can.any(0): print(can.recv(0)) + +# Testing rtr messages +bus1 = CAN(1, CAN.LOOPBACK) +bus2 = CAN(2, CAN.LOOPBACK, extframe = True) +while bus1.any(0): + bus1.recv(0) +while bus2.any(0): + bus2.recv(0) +bus1.setfilter(0, CAN.LIST16, 0, (1, 2, 3, 4)) +bus1.setfilter(1, CAN.LIST16, 0, (5, 6, 7, 8), rtr=(True, True, True, True)) +bus1.setfilter(2, CAN.MASK16, 0, (64, 64, 32, 32), rtr=(False, True)) +bus2.setfilter(0, CAN.LIST32, 0, (1, 2), rtr=(True, True)) +bus2.setfilter(1, CAN.LIST32, 0, (3, 4), rtr=(True, False)) +bus2.setfilter(2, CAN.MASK32, 0, (16, 16), rtr=(False,)) +bus2.setfilter(2, CAN.MASK32, 0, (32, 32), rtr=(True,)) + +bus1.send('',1,rtr=True) +print(bus1.any(0)) +bus1.send('',5,rtr=True) +print(bus1.recv(0)) +bus1.send('',6,rtr=True) +print(bus1.recv(0)) +bus1.send('',7,rtr=True) +print(bus1.recv(0)) +bus1.send('',16,rtr=True) +print(bus1.any(0)) +bus1.send('',32,rtr=True) +print(bus1.recv(0)) + +bus2.send('',1,rtr=True) +print(bus2.recv(0)) +bus2.send('',2,rtr=True) +print(bus2.recv(0)) +bus2.send('',3,rtr=True) +print(bus2.recv(0)) +bus2.send('',4,rtr=True) +print(bus2.any(0)) diff --git a/tests/pyb/can.py.exp b/tests/pyb/can.py.exp index 845f6d5ba16e83794829d2942cb0fbde395ea2a3..ec6f97ea02b5525ebc359bfc509b51ea1c149aa7 100644 --- a/tests/pyb/can.py.exp +++ b/tests/pyb/can.py.exp @@ -2,9 +2,9 @@ CAN(1) CAN(1, CAN.LOOPBACK, extframe=False) False True -(123, 0, 0, b'abcd') -(2047, 0, 0, b'abcd') -(0, 0, 0, b'abcd') +(123, False, 0, b'abcd') +(2047, False, 0, b'abcd') +(0, False, 0, b'abcd') passed CAN(1, CAN.LOOPBACK, extframe=True) passed @@ -20,21 +20,31 @@ cb1 full cb1a overflow -(1, 0, 0, b'11111111') -(2, 0, 1, b'22222222') -(4, 0, 3, b'44444444') -(5, 0, 0, b'55555555') -(6, 0, 1, b'66666666') -(8, 0, 3, b'88888888') +(1, False, 0, b'11111111') +(2, False, 1, b'22222222') +(4, False, 3, b'44444444') +(5, False, 0, b'55555555') +(6, False, 1, b'66666666') +(8, False, 3, b'88888888') cb0a pending cb1a pending -(1, 0, 0, b'11111111') -(5, 0, 0, b'55555555') +(1, False, 0, b'11111111') +(5, False, 0, b'55555555') False -(1, 0, 0, b'abcde') +(1, False, 0, b'abcde') passed -(2, 0, 0, b'abcde') -(3, 0, 0, b'abcde') -(4, 0, 0, b'abcde') +(2, False, 0, b'abcde') +(3, False, 0, b'abcde') +(4, False, 0, b'abcde') +False +(5, True, 4, b'') +(6, True, 5, b'') +(7, True, 6, b'') +False +(32, True, 9, b'') +(1, True, 0, b'') +(2, True, 1, b'') +(3, True, 2, b'') +False