Commit e3cd1543 authored by Henrik's avatar Henrik Committed by Damien George
Browse files

stmhal: Add support for sending and receiving CAN RTR messages.

parent 259eaab9
...@@ -82,7 +82,7 @@ Methods ...@@ -82,7 +82,7 @@ Methods
Turn off the CAN bus. Turn off the CAN bus.
.. method:: can.setfilter(bank, mode, fifo, params) .. method:: can.setfilter(bank, mode, fifo, params, \*, rtr)
Configure a filter bank: Configure a filter bank:
...@@ -107,6 +107,23 @@ Methods ...@@ -107,6 +107,23 @@ Methods
|CAN.MASK32 |As with CAN.MASK16 but with only one 32 bit id/mask pair.| |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) .. method:: can.clearfilter(bank)
Clear and disables a filter bank: Clear and disables a filter bank:
...@@ -124,15 +141,24 @@ Methods ...@@ -124,15 +141,24 @@ Methods
- ``fifo`` is an integer, which is the FIFO to receive on - ``fifo`` is an integer, which is the FIFO to receive on
- ``timeout`` is the timeout in milliseconds to wait for the receive. - ``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 a message on the bus:
- ``send`` is the data to send (an integer to send, or a buffer object). - ``data`` is the data to send (an integer to send, or a buffer object).
- ``addr`` is the address to send to - ``id`` is the id of the message to be sent.
- ``timeout`` is the timeout in milliseconds to wait for the send. - ``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 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 buffers and the method returns immediately. If all three buffers are in use
......
...@@ -436,9 +436,10 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_2(pyb_can_any_obj, pyb_can_any); ...@@ -436,9 +436,10 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_2(pyb_can_any_obj, pyb_can_any);
/// Return value: `None`. /// 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 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[] = { static const mp_arg_t allowed_args[] = {
{ MP_QSTR_send, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, { MP_QSTR_data, 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_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_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 // 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_ ...@@ -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.StdId = args[1].u_int & 0x7FF;
tx_msg.IDE = CAN_ID_STD; 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; tx_msg.DLC = bufinfo.len;
for (mp_uint_t i = 0; i < bufinfo.len; i++) { 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 tx_msg.Data[i] = ((byte*)bufinfo.buf)[i]; // Data is uint32_t but holds only 1 byte
} }
self->can.pTxMsg = &tx_msg; self->can.pTxMsg = &tx_msg;
HAL_StatusTypeDef status = CAN_Transmit(&self->can, args[2].u_int); 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_ ...@@ -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 { } else {
tuple->items[0] = MP_OBJ_NEW_SMALL_INT(rx_msg.ExtId); 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); tuple->items[2] = MP_OBJ_NEW_SMALL_INT(rx_msg.FMI);
vstr_t vstr; vstr_t vstr;
vstr_init_len(&vstr, rx_msg.DLC); 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 ...@@ -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_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_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_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 // 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 ...@@ -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_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 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_t *params;
mp_obj_get_array(args[3].u_obj, &len, &params); mp_obj_get_array(args[3].u_obj, &len, &params);
if (args[4].u_obj != MP_OBJ_NULL){
mp_obj_get_array(args[4].u_obj, &rtr_len, &rtr_flags);
}
CAN_FilterConfTypeDef filter; CAN_FilterConfTypeDef filter;
if (args[1].u_int == MASK16 || args[1].u_int == LIST16) { 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 ...@@ -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; filter.FilterScale = CAN_FILTERSCALE_16BIT;
if (self->extframe) { if (self->extframe) {
filter.FilterIdLow = EXTENDED_ID_TO_16BIT_FILTER(mp_obj_get_int(params[0])); // id1 if (args[4].u_obj != MP_OBJ_NULL) {
filter.FilterMaskIdLow = EXTENDED_ID_TO_16BIT_FILTER(mp_obj_get_int(params[1])); // mask1 if (args[1].u_int == MASK16) {
filter.FilterIdHigh = EXTENDED_ID_TO_16BIT_FILTER(mp_obj_get_int(params[2])); // id2 rtr_masks[0] = mp_obj_get_int(rtr_flags[0]) ? 0x02 : 0;
filter.FilterMaskIdHigh = EXTENDED_ID_TO_16BIT_FILTER(mp_obj_get_int(params[3])); // mask2 rtr_masks[1] = 0x02;
} else { rtr_masks[2] = mp_obj_get_int(rtr_flags[1]) ? 0x02 : 0;
filter.FilterIdLow = mp_obj_get_int(params[0]) << 5; // id1 rtr_masks[3] = 0x02;
filter.FilterMaskIdLow = mp_obj_get_int(params[1]) << 5; // mask1 } else { // LIST16
filter.FilterIdHigh = mp_obj_get_int(params[2]) << 5; // id2 rtr_masks[0] = mp_obj_get_int(rtr_flags[0]) ? 0x02 : 0;
filter.FilterMaskIdHigh = mp_obj_get_int(params[3]) << 5; // mask2 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) { if (args[1].u_int == MASK16) {
filter.FilterMode = CAN_FILTERMODE_IDMASK; 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 ...@@ -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) { if (len != 2) {
goto error; 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.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.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) { if (args[1].u_int == MASK32) {
filter.FilterMode = CAN_FILTERMODE_IDMASK; filter.FilterMode = CAN_FILTERMODE_IDMASK;
} }
......
...@@ -213,6 +213,7 @@ Q(initfilterbanks) ...@@ -213,6 +213,7 @@ Q(initfilterbanks)
Q(clearfilter) Q(clearfilter)
Q(setfilter) Q(setfilter)
Q(rxcallback) Q(rxcallback)
Q(rtr)
Q(NORMAL) Q(NORMAL)
Q(LOOPBACK) Q(LOOPBACK)
Q(SILENT) Q(SILENT)
......
...@@ -151,3 +151,40 @@ except OSError as e: ...@@ -151,3 +151,40 @@ except OSError as e:
pyb.delay(500) pyb.delay(500)
while can.any(0): while can.any(0):
print(can.recv(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))
...@@ -2,9 +2,9 @@ CAN(1) ...@@ -2,9 +2,9 @@ CAN(1)
CAN(1, CAN.LOOPBACK, extframe=False) CAN(1, CAN.LOOPBACK, extframe=False)
False False
True True
(123, 0, 0, b'abcd') (123, False, 0, b'abcd')
(2047, 0, 0, b'abcd') (2047, False, 0, b'abcd')
(0, 0, 0, b'abcd') (0, False, 0, b'abcd')
passed passed
CAN(1, CAN.LOOPBACK, extframe=True) CAN(1, CAN.LOOPBACK, extframe=True)
passed passed
...@@ -20,21 +20,31 @@ cb1 ...@@ -20,21 +20,31 @@ cb1
full full
cb1a cb1a
overflow overflow
(1, 0, 0, b'11111111') (1, False, 0, b'11111111')
(2, 0, 1, b'22222222') (2, False, 1, b'22222222')
(4, 0, 3, b'44444444') (4, False, 3, b'44444444')
(5, 0, 0, b'55555555') (5, False, 0, b'55555555')
(6, 0, 1, b'66666666') (6, False, 1, b'66666666')
(8, 0, 3, b'88888888') (8, False, 3, b'88888888')
cb0a cb0a
pending pending
cb1a cb1a
pending pending
(1, 0, 0, b'11111111') (1, False, 0, b'11111111')
(5, 0, 0, b'55555555') (5, False, 0, b'55555555')
False False
(1, 0, 0, b'abcde') (1, False, 0, b'abcde')
passed passed
(2, 0, 0, b'abcde') (2, False, 0, b'abcde')
(3, 0, 0, b'abcde') (3, False, 0, b'abcde')
(4, 0, 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
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment