Browse Source

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

pull/1184/merge
Henrik 10 years ago
committed by Damien George
parent
commit
e3cd154317
  1. 36
      docs/library/pyb.CAN.rst
  2. 81
      stmhal/can.c
  3. 1
      stmhal/qstrdefsport.h
  4. 37
      tests/pyb/can.py
  5. 40
      tests/pyb/can.py.exp

36
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

81
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, &params);
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;
}

1
stmhal/qstrdefsport.h

@ -213,6 +213,7 @@ Q(initfilterbanks)
Q(clearfilter)
Q(setfilter)
Q(rxcallback)
Q(rtr)
Q(NORMAL)
Q(LOOPBACK)
Q(SILENT)

37
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))

40
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

Loading…
Cancel
Save