Skip to content

Commit e3cd154

Browse files
HenrikSolverdpgeorge
authored andcommitted
stmhal: Add support for sending and receiving CAN RTR messages.
1 parent 259eaab commit e3cd154

File tree

5 files changed

+158
-37
lines changed

5 files changed

+158
-37
lines changed

docs/library/pyb.CAN.rst

Lines changed: 31 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@ Methods
8282

8383
Turn off the CAN bus.
8484

85-
.. method:: can.setfilter(bank, mode, fifo, params)
85+
.. method:: can.setfilter(bank, mode, fifo, params, \*, rtr)
8686

8787
Configure a filter bank:
8888

@@ -107,6 +107,23 @@ Methods
107107
|CAN.MASK32 |As with CAN.MASK16 but with only one 32 bit id/mask pair.|
108108
+-----------+---------------------------------------------------------+
109109

110+
- ``rtr`` is an array of booleans that states if a filter should accept a
111+
remote transmission request message. If this argument is not given
112+
then it defaults to False for all entries. The length of the array
113+
depends on the ``mode`` argument.
114+
115+
+-----------+----------------------+
116+
|``mode`` |length of rtr array |
117+
+===========+======================+
118+
|CAN.LIST16 |4 |
119+
+-----------+----------------------+
120+
|CAN.LIST32 |2 |
121+
+-----------+----------------------+
122+
|CAN.MASK16 |2 |
123+
+-----------+----------------------+
124+
|CAN.MASK32 |1 |
125+
+-----------+----------------------+
126+
110127
.. method:: can.clearfilter(bank)
111128

112129
Clear and disables a filter bank:
@@ -124,15 +141,24 @@ Methods
124141
- ``fifo`` is an integer, which is the FIFO to receive on
125142
- ``timeout`` is the timeout in milliseconds to wait for the receive.
126143

127-
Return value: buffer of data bytes.
144+
Return value: A tuple containing four values.
145+
146+
- The id of the message.
147+
- A boolean that indicates if the message is an RTR message.
148+
- The FMI (Filter Match Index) value.
149+
- An array containing the data.
128150

129-
.. method:: can.send(send, addr, \*, timeout=0)
151+
.. method:: can.send(data, id, \*, timeout=0, rtr=False)
130152

131153
Send a message on the bus:
132154

133-
- ``send`` is the data to send (an integer to send, or a buffer object).
134-
- ``addr`` is the address to send to
155+
- ``data`` is the data to send (an integer to send, or a buffer object).
156+
- ``id`` is the id of the message to be sent.
135157
- ``timeout`` is the timeout in milliseconds to wait for the send.
158+
- ``rtr`` is a boolean that specifies if the message shall be sent as
159+
a remote transmission request. If ``rtr`` is True then only the length
160+
of ``data`` is used to fill in the DLC slot of the frame; the actual
161+
bytes in ``data`` are unused.
136162

137163
If timeout is 0 the message is placed in a buffer in one of three hardware
138164
buffers and the method returns immediately. If all three buffers are in use

stmhal/can.c

Lines changed: 64 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -436,9 +436,10 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_2(pyb_can_any_obj, pyb_can_any);
436436
/// Return value: `None`.
437437
STATIC mp_obj_t pyb_can_send(mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
438438
static const mp_arg_t allowed_args[] = {
439-
{ MP_QSTR_send, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
440-
{ MP_QSTR_addr, MP_ARG_REQUIRED | MP_ARG_INT, {.u_int = 0} },
439+
{ MP_QSTR_data, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
440+
{ MP_QSTR_id, MP_ARG_REQUIRED | MP_ARG_INT, {.u_int = 0} },
441441
{ MP_QSTR_timeout, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} },
442+
{ MP_QSTR_rtr, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = false} },
442443
};
443444

444445
// 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_
464465
tx_msg.StdId = args[1].u_int & 0x7FF;
465466
tx_msg.IDE = CAN_ID_STD;
466467
}
467-
tx_msg.RTR = CAN_RTR_DATA;
468+
if (args[3].u_bool == false) {
469+
tx_msg.RTR = CAN_RTR_DATA;
470+
} else {
471+
tx_msg.RTR = CAN_RTR_REMOTE;
472+
}
468473
tx_msg.DLC = bufinfo.len;
469474
for (mp_uint_t i = 0; i < bufinfo.len; i++) {
470475
tx_msg.Data[i] = ((byte*)bufinfo.buf)[i]; // Data is uint32_t but holds only 1 byte
471476
}
477+
472478
self->can.pTxMsg = &tx_msg;
473479
HAL_StatusTypeDef status = CAN_Transmit(&self->can, args[2].u_int);
474480

@@ -543,7 +549,7 @@ STATIC mp_obj_t pyb_can_recv(mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_
543549
} else {
544550
tuple->items[0] = MP_OBJ_NEW_SMALL_INT(rx_msg.ExtId);
545551
}
546-
tuple->items[1] = MP_OBJ_NEW_SMALL_INT(rx_msg.RTR);
552+
tuple->items[1] = rx_msg.RTR == CAN_RTR_REMOTE ? mp_const_true : mp_const_false;
547553
tuple->items[2] = MP_OBJ_NEW_SMALL_INT(rx_msg.FMI);
548554
vstr_t vstr;
549555
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
597603
{ MP_QSTR_mode, MP_ARG_REQUIRED | MP_ARG_INT, {.u_int = 0} },
598604
{ MP_QSTR_fifo, MP_ARG_REQUIRED | MP_ARG_INT, {.u_int = CAN_FILTER_FIFO0} },
599605
{ MP_QSTR_params, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
606+
{ MP_QSTR_rtr, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
600607
};
601608

602609
// 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
605612
mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
606613

607614
mp_uint_t len;
615+
mp_uint_t rtr_len;
616+
mp_uint_t rtr_masks[4] = {0, 0, 0, 0};
617+
mp_obj_t *rtr_flags;
608618
mp_obj_t *params;
609619
mp_obj_get_array(args[3].u_obj, &len, &params);
620+
if (args[4].u_obj != MP_OBJ_NULL){
621+
mp_obj_get_array(args[4].u_obj, &rtr_len, &rtr_flags);
622+
}
610623

611624
CAN_FilterConfTypeDef filter;
612625
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
615628
}
616629
filter.FilterScale = CAN_FILTERSCALE_16BIT;
617630
if (self->extframe) {
618-
filter.FilterIdLow = EXTENDED_ID_TO_16BIT_FILTER(mp_obj_get_int(params[0])); // id1
619-
filter.FilterMaskIdLow = EXTENDED_ID_TO_16BIT_FILTER(mp_obj_get_int(params[1])); // mask1
620-
filter.FilterIdHigh = EXTENDED_ID_TO_16BIT_FILTER(mp_obj_get_int(params[2])); // id2
621-
filter.FilterMaskIdHigh = EXTENDED_ID_TO_16BIT_FILTER(mp_obj_get_int(params[3])); // mask2
622-
} else {
623-
filter.FilterIdLow = mp_obj_get_int(params[0]) << 5; // id1
624-
filter.FilterMaskIdLow = mp_obj_get_int(params[1]) << 5; // mask1
625-
filter.FilterIdHigh = mp_obj_get_int(params[2]) << 5; // id2
626-
filter.FilterMaskIdHigh = mp_obj_get_int(params[3]) << 5; // mask2
631+
if (args[4].u_obj != MP_OBJ_NULL) {
632+
if (args[1].u_int == MASK16) {
633+
rtr_masks[0] = mp_obj_get_int(rtr_flags[0]) ? 0x02 : 0;
634+
rtr_masks[1] = 0x02;
635+
rtr_masks[2] = mp_obj_get_int(rtr_flags[1]) ? 0x02 : 0;
636+
rtr_masks[3] = 0x02;
637+
} else { // LIST16
638+
rtr_masks[0] = mp_obj_get_int(rtr_flags[0]) ? 0x02 : 0;
639+
rtr_masks[1] = mp_obj_get_int(rtr_flags[1]) ? 0x02 : 0;
640+
rtr_masks[2] = mp_obj_get_int(rtr_flags[2]) ? 0x02 : 0;
641+
rtr_masks[3] = mp_obj_get_int(rtr_flags[3]) ? 0x02 : 0;
642+
}
643+
}
644+
filter.FilterIdLow = EXTENDED_ID_TO_16BIT_FILTER(mp_obj_get_int(params[0])) | rtr_masks[0]; // id1
645+
filter.FilterMaskIdLow = EXTENDED_ID_TO_16BIT_FILTER(mp_obj_get_int(params[1])) | rtr_masks[1]; // mask1
646+
filter.FilterIdHigh = EXTENDED_ID_TO_16BIT_FILTER(mp_obj_get_int(params[2])) | rtr_masks[2]; // id2
647+
filter.FilterMaskIdHigh = EXTENDED_ID_TO_16BIT_FILTER(mp_obj_get_int(params[3])) | rtr_masks[3]; // mask2
648+
} else { // Basic frames
649+
if (args[4].u_obj != MP_OBJ_NULL) {
650+
if (args[1].u_int == MASK16) {
651+
rtr_masks[0] = mp_obj_get_int(rtr_flags[0]) ? 0x10 : 0;
652+
rtr_masks[1] = 0x10;
653+
rtr_masks[2] = mp_obj_get_int(rtr_flags[1]) ? 0x10 : 0;
654+
rtr_masks[3] = 0x10;
655+
} else { // LIST16
656+
rtr_masks[0] = mp_obj_get_int(rtr_flags[0]) ? 0x10 : 0;
657+
rtr_masks[1] = mp_obj_get_int(rtr_flags[1]) ? 0x10 : 0;
658+
rtr_masks[2] = mp_obj_get_int(rtr_flags[2]) ? 0x10 : 0;
659+
rtr_masks[3] = mp_obj_get_int(rtr_flags[3]) ? 0x10 : 0;
660+
}
661+
}
662+
filter.FilterIdLow = (mp_obj_get_int(params[0]) << 5) | rtr_masks[0]; // id1
663+
filter.FilterMaskIdLow = (mp_obj_get_int(params[1]) << 5) | rtr_masks[1]; // mask1
664+
filter.FilterIdHigh = (mp_obj_get_int(params[2]) << 5) | rtr_masks[2]; // id2
665+
filter.FilterMaskIdHigh = (mp_obj_get_int(params[3]) << 5) | rtr_masks[3]; // mask2
627666
}
628667
if (args[1].u_int == MASK16) {
629668
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
636675
if (len != 2) {
637676
goto error;
638677
}
639-
filter.FilterScale = CAN_FILTERSCALE_32BIT;
640-
678+
filter.FilterScale = CAN_FILTERSCALE_32BIT;
679+
if (args[4].u_obj != MP_OBJ_NULL) {
680+
if (args[1].u_int == MASK32) {
681+
rtr_masks[0] = mp_obj_get_int(rtr_flags[0]) ? 0x02 : 0;
682+
rtr_masks[1] = 0x02;
683+
} else { // LIST32
684+
rtr_masks[0] = mp_obj_get_int(rtr_flags[0]) ? 0x02 : 0;
685+
rtr_masks[1] = mp_obj_get_int(rtr_flags[1]) ? 0x02 : 0;
686+
}
687+
}
641688
filter.FilterIdHigh = (mp_obj_get_int(params[0]) & 0xFF00) >> 13;
642-
filter.FilterIdLow = ((mp_obj_get_int(params[0]) & 0x00FF) << 3) | 4;
689+
filter.FilterIdLow = (((mp_obj_get_int(params[0]) & 0x00FF) << 3) | 4) | rtr_masks[0];
643690
filter.FilterMaskIdHigh = (mp_obj_get_int(params[1]) & 0xFF00 ) >> 13;
644-
filter.FilterMaskIdLow = ((mp_obj_get_int(params[1]) & 0x00FF) << 3) | 4;
691+
filter.FilterMaskIdLow = (((mp_obj_get_int(params[1]) & 0x00FF) << 3) | 4) | rtr_masks[1];
645692
if (args[1].u_int == MASK32) {
646693
filter.FilterMode = CAN_FILTERMODE_IDMASK;
647694
}

stmhal/qstrdefsport.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -213,6 +213,7 @@ Q(initfilterbanks)
213213
Q(clearfilter)
214214
Q(setfilter)
215215
Q(rxcallback)
216+
Q(rtr)
216217
Q(NORMAL)
217218
Q(LOOPBACK)
218219
Q(SILENT)

tests/pyb/can.py

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -151,3 +151,40 @@ def cb1a(bus, reason):
151151
pyb.delay(500)
152152
while can.any(0):
153153
print(can.recv(0))
154+
155+
# Testing rtr messages
156+
bus1 = CAN(1, CAN.LOOPBACK)
157+
bus2 = CAN(2, CAN.LOOPBACK, extframe = True)
158+
while bus1.any(0):
159+
bus1.recv(0)
160+
while bus2.any(0):
161+
bus2.recv(0)
162+
bus1.setfilter(0, CAN.LIST16, 0, (1, 2, 3, 4))
163+
bus1.setfilter(1, CAN.LIST16, 0, (5, 6, 7, 8), rtr=(True, True, True, True))
164+
bus1.setfilter(2, CAN.MASK16, 0, (64, 64, 32, 32), rtr=(False, True))
165+
bus2.setfilter(0, CAN.LIST32, 0, (1, 2), rtr=(True, True))
166+
bus2.setfilter(1, CAN.LIST32, 0, (3, 4), rtr=(True, False))
167+
bus2.setfilter(2, CAN.MASK32, 0, (16, 16), rtr=(False,))
168+
bus2.setfilter(2, CAN.MASK32, 0, (32, 32), rtr=(True,))
169+
170+
bus1.send('',1,rtr=True)
171+
print(bus1.any(0))
172+
bus1.send('',5,rtr=True)
173+
print(bus1.recv(0))
174+
bus1.send('',6,rtr=True)
175+
print(bus1.recv(0))
176+
bus1.send('',7,rtr=True)
177+
print(bus1.recv(0))
178+
bus1.send('',16,rtr=True)
179+
print(bus1.any(0))
180+
bus1.send('',32,rtr=True)
181+
print(bus1.recv(0))
182+
183+
bus2.send('',1,rtr=True)
184+
print(bus2.recv(0))
185+
bus2.send('',2,rtr=True)
186+
print(bus2.recv(0))
187+
bus2.send('',3,rtr=True)
188+
print(bus2.recv(0))
189+
bus2.send('',4,rtr=True)
190+
print(bus2.any(0))

tests/pyb/can.py.exp

Lines changed: 25 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,9 @@ CAN(1)
22
CAN(1, CAN.LOOPBACK, extframe=False)
33
False
44
True
5-
(123, 0, 0, b'abcd')
6-
(2047, 0, 0, b'abcd')
7-
(0, 0, 0, b'abcd')
5+
(123, False, 0, b'abcd')
6+
(2047, False, 0, b'abcd')
7+
(0, False, 0, b'abcd')
88
passed
99
CAN(1, CAN.LOOPBACK, extframe=True)
1010
passed
@@ -20,21 +20,31 @@ cb1
2020
full
2121
cb1a
2222
overflow
23-
(1, 0, 0, b'11111111')
24-
(2, 0, 1, b'22222222')
25-
(4, 0, 3, b'44444444')
26-
(5, 0, 0, b'55555555')
27-
(6, 0, 1, b'66666666')
28-
(8, 0, 3, b'88888888')
23+
(1, False, 0, b'11111111')
24+
(2, False, 1, b'22222222')
25+
(4, False, 3, b'44444444')
26+
(5, False, 0, b'55555555')
27+
(6, False, 1, b'66666666')
28+
(8, False, 3, b'88888888')
2929
cb0a
3030
pending
3131
cb1a
3232
pending
33-
(1, 0, 0, b'11111111')
34-
(5, 0, 0, b'55555555')
33+
(1, False, 0, b'11111111')
34+
(5, False, 0, b'55555555')
3535
False
36-
(1, 0, 0, b'abcde')
36+
(1, False, 0, b'abcde')
3737
passed
38-
(2, 0, 0, b'abcde')
39-
(3, 0, 0, b'abcde')
40-
(4, 0, 0, b'abcde')
38+
(2, False, 0, b'abcde')
39+
(3, False, 0, b'abcde')
40+
(4, False, 0, b'abcde')
41+
False
42+
(5, True, 4, b'')
43+
(6, True, 5, b'')
44+
(7, True, 6, b'')
45+
False
46+
(32, True, 9, b'')
47+
(1, True, 0, b'')
48+
(2, True, 1, b'')
49+
(3, True, 2, b'')
50+
False

0 commit comments

Comments
 (0)