Skip to content

Commit 7fd6cab

Browse files
committed
canio: Make both tx and rx (but not both) optional
.. loopback and silent come from the (optional) constructor parameters not guessing based on the pin specification .. docstring & comment improvements
1 parent 09f8a83 commit 7fd6cab

File tree

3 files changed

+74
-20
lines changed

3 files changed

+74
-20
lines changed

ports/atmel-samd/common-hal/_canio/CAN.c

Lines changed: 17 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -51,9 +51,10 @@ __attribute__((optimize("O0"), noinline))
5151
void common_hal_canio_can_construct(canio_can_obj_t *self, mcu_pin_obj_t *rx, mcu_pin_obj_t *tx, int baudrate, bool loopback, bool silent)
5252
{
5353
mcu_pin_function_t *tx_function = mcu_find_pin_function(can_tx, tx, -1, MP_QSTR_tx);
54-
int instance = tx_function->instance;
54+
int instance = tx_function ? tx_function->instance : -1;
5555

5656
mcu_pin_function_t *rx_function = mcu_find_pin_function(can_rx, rx, instance, MP_QSTR_rx);
57+
instance = rx_function->instance;
5758

5859
const uint32_t can_frequency = CONF_CAN0_FREQUENCY;
5960

@@ -68,22 +69,25 @@ void common_hal_canio_can_construct(canio_can_obj_t *self, mcu_pin_obj_t *rx, mc
6869
mp_raise_OSError(MP_EINVAL); // baudrate cannot be attained (16kHz or something is lower bound, should never happen)
6970
}
7071

71-
gpio_set_pin_direction(tx_function->pin, GPIO_DIRECTION_OUT);
72-
gpio_set_pin_function(tx_function->pin, tx_function->function);
73-
common_hal_never_reset_pin(tx_function->obj);
72+
if (tx_function) {
73+
gpio_set_pin_direction(tx_function->pin, GPIO_DIRECTION_OUT);
74+
gpio_set_pin_function(tx_function->pin, tx_function->function);
75+
common_hal_never_reset_pin(tx_function->obj);
76+
}
7477

7578
if (rx_function) {
7679
gpio_set_pin_direction(rx_function->pin, GPIO_DIRECTION_IN);
7780
gpio_set_pin_function(rx_function->pin, rx_function->function);
7881
common_hal_never_reset_pin(rx_function->obj);
7982
}
8083

81-
self->tx_pin_number = common_hal_mcu_pin_number(tx);
84+
self->tx_pin_number = tx ? common_hal_mcu_pin_number(tx) : COMMON_HAL_MCU_NO_PIN;
8285
self->rx_pin_number = rx ? common_hal_mcu_pin_number(rx) : COMMON_HAL_MCU_NO_PIN;
8386
self->hw = can_insts[instance];
8487
self->state = &can_state[instance];
8588

8689
self->loopback = loopback;
90+
self->silent = silent;
8791

8892
// Allow configuration change
8993
hri_can_set_CCCR_INIT_bit(self->hw);
@@ -129,11 +133,9 @@ void common_hal_canio_can_construct(canio_can_obj_t *self, mcu_pin_obj_t *rx, mc
129133
hri_can_write_NBTP_reg(self->hw, btp.reg);
130134
}
131135

132-
// we don't do the high bit rate yet, so do we need to set this register?
133-
// hri_can_write_DBTP_reg(self->hw, ???);
134-
// A "data bit" is a data bit :) with dul rate CAN FD, this is a higher
135-
// rate. However, CAN FD is not implemented in CircuitPython, and this is the same rate as
136-
// the "nominal rate".
136+
// A "data bit" is a data bit :) with dula rate CAN FD, this is a higher
137+
// rate. However, CAN FD is not implemented in CircuitPython, and this is
138+
// the same rate as the "nominal rate".
137139
{
138140
CAN_DBTP_Type btp = {
139141
.bit.DTSEG1 = DIV_ROUND(clocks_to_sample, divisor) - 1,
@@ -259,7 +261,7 @@ void common_hal_canio_can_construct(canio_can_obj_t *self, mcu_pin_obj_t *rx, mc
259261
can_objs[instance] = self;
260262
}
261263

262-
int common_hal_canio_can_loopback_get(canio_can_obj_t *self)
264+
bool common_hal_canio_can_loopback_get(canio_can_obj_t *self)
263265
{
264266
return self->loopback;
265267
}
@@ -368,6 +370,10 @@ void common_hal_canio_can_send(canio_can_obj_t *self, canio_message_obj_t *messa
368370
}
369371
}
370372

373+
bool common_hal_canio_can_silent_get(canio_can_obj_t *self) {
374+
return self->silent;
375+
}
376+
371377
bool common_hal_canio_can_deinited(canio_can_obj_t *self) {
372378
return !self->hw;
373379
}

ports/atmel-samd/common-hal/_canio/CAN.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,8 +60,10 @@ int common_hal_canio_can_baudrate_get(canio_can_obj_t *self);
6060
int common_hal_canio_can_bus_off_state_count_get(canio_can_obj_t *self);
6161
int common_hal_canio_can_error_passive_state_count_get(canio_can_obj_t *self);
6262
int common_hal_canio_can_error_warning_state_count_get(canio_can_obj_t *self);
63+
bool common_hal_canio_can_loopback_get(canio_can_obj_t *self);
6364
int common_hal_canio_can_receive_error_count_get(canio_can_obj_t *self);
6465
canio_bus_state_t common_hal_canio_can_state_get(canio_can_obj_t *self);
66+
bool common_hal_canio_can_silent_get(canio_can_obj_t *self);
6567
int common_hal_canio_can_transmit_error_count_get(canio_can_obj_t *self);
6668
void common_hal_canio_can_auto_restart_set(canio_can_obj_t *self, bool auto_restart);
6769
void common_hal_canio_can_check_for_deinit(canio_can_obj_t *self);

shared-bindings/_canio/CAN.c

Lines changed: 55 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -42,30 +42,35 @@
4242
//| """CAN bus protocol"""
4343
//|
4444
//| def __init__(self,
45-
//| rx: microcontroller.Pin,
45+
//| rx: Optional[microcontroller.Pin]=None,
4646
//| tx: Optional[microcontroller.Pin]=None,
4747
//| *,
4848
//| baudrate: int = 250000,
4949
//| loopback: bool = False,
5050
//| auto_restart: bool = False,
5151
//| ):
5252
//| """A common shared-bus protocol. The rx and tx pins are generally
53-
//| connected to a transceiver which controls the H and L pins on a shared
54-
//| bus.
53+
//| connected to a transceiver which controls the H and L pins on a
54+
//| shared bus.
5555
//|
56-
//| :param ~microcontroller.Pin rx: the pin to receive with.
57-
//| :param ~microcontroller.Pin tx: the pin to transmit with, or None if the peripheral should operate in "silent" mode.
56+
//| Normally, both ``tx`` and ``rx`` pins will be specified. However,
57+
//| in silent and loopback modes, the other pin may not be required and
58+
//| can be used for other purposes.
59+
//|
60+
//| :param ~microcontroller.Pin rx: the pin to receive with, or None.
61+
//| :param ~microcontroller.Pin tx: the pin to transmit with, or None.
5862
//| :param int baudrate: The bit rate of the bus in Hz. All devices on the bus must agree on this value.
59-
//| :param bool loopback: True if the peripheral will be operated in loopback mode.
63+
//| :param bool loopback: True if the peripheral will be operated in loopback mode. In loopback mode, the ``rx`` pin's value is ignored, and the device receives the packets it sends.
64+
//| :param bool silent: True if the peripheral will be operated in silent mode. In silent mode, the ``tx`` pin is always driven to the high logic level. This mode can be used to "sniff" a CAN bus without interfering.
6065
//| :param bool auto_restart: If True, will restart communications after entering bus-off state
6166
//| """
6267
//| ...
6368
//|
6469
STATIC mp_obj_t canio_can_make_new(const mp_obj_type_t *type, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
6570
enum { ARG_rx, ARG_tx, ARG_baudrate, ARG_loopback, ARG_silent, ARG_auto_restart, NUM_ARGS };
6671
static const mp_arg_t allowed_args[] = {
67-
{ MP_QSTR_rx, MP_ARG_OBJ | MP_ARG_REQUIRED, {.u_obj = 0} },
68-
{ MP_QSTR_tx, MP_ARG_OBJ, {.u_obj = 0} },
72+
{ MP_QSTR_rx, MP_ARG_OBJ, {.u_obj = mp_const_none} },
73+
{ MP_QSTR_tx, MP_ARG_OBJ, {.u_obj = mp_const_none} },
6974
{ MP_QSTR_baudrate, MP_ARG_INT, {.u_int = 250000} },
7075
{ MP_QSTR_loopback, MP_ARG_BOOL, {.u_bool = false} },
7176
{ MP_QSTR_silent, MP_ARG_BOOL, {.u_bool = false} },
@@ -76,8 +81,11 @@ STATIC mp_obj_t canio_can_make_new(const mp_obj_type_t *type, size_t n_args, con
7681

7782
mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
7883

79-
mcu_pin_obj_t *rx_pin = validate_obj_is_free_pin(args[ARG_rx].u_obj);
84+
mcu_pin_obj_t *rx_pin = validate_obj_is_free_pin_or_none(args[ARG_rx].u_obj);
8085
mcu_pin_obj_t *tx_pin = validate_obj_is_free_pin_or_none(args[ARG_tx].u_obj);
86+
if (!rx_pin && !tx_pin) {
87+
mp_raise_ValueError(translate("tx and rx cannot both be None"));
88+
}
8189

8290
canio_can_obj_t *self = m_new_obj(canio_can_obj_t);
8391
self->base.type = &canio_can_type;
@@ -301,6 +309,24 @@ STATIC mp_obj_t canio_can_listen(size_t n_args, const mp_obj_t *pos_args, mp_map
301309
}
302310
MP_DEFINE_CONST_FUN_OBJ_KW(canio_can_listen_obj, 1, canio_can_listen);
303311

312+
//| loopback: bool
313+
//| """True if the device was created in loopback mode, False otherwise"""
314+
//|
315+
STATIC mp_obj_t canio_can_loopback_get(mp_obj_t self_in) {
316+
canio_can_obj_t *self = MP_OBJ_TO_PTR(self_in);
317+
common_hal_canio_can_check_for_deinit(self);
318+
return mp_obj_new_bool(common_hal_canio_can_loopback_get(self));
319+
}
320+
MP_DEFINE_CONST_FUN_OBJ_1(canio_can_loopback_get_obj, canio_can_loopback_get);
321+
322+
STATIC const mp_obj_property_t canio_can_loopback_obj = {
323+
.base.type = &mp_type_property,
324+
.proxy = {(mp_obj_t)&canio_can_loopback_get_obj,
325+
(mp_obj_t)mp_const_none,
326+
(mp_obj_t)mp_const_none},
327+
};
328+
329+
304330
//| def send(message: Message) -> None:
305331
//| """Send a message on the bus with the given data and id.
306332
//| If the message could not be sent due to a full fifo or a bus error condition, RuntimeError is raised.
@@ -321,6 +347,24 @@ STATIC mp_obj_t canio_can_send(mp_obj_t self_in, mp_obj_t message_in) {
321347
}
322348
MP_DEFINE_CONST_FUN_OBJ_2(canio_can_send_obj, canio_can_send);
323349

350+
//| silent: bool
351+
//| """True if the device was created in silent mode, False otherwise"""
352+
//|
353+
STATIC mp_obj_t canio_can_silent_get(mp_obj_t self_in) {
354+
canio_can_obj_t *self = MP_OBJ_TO_PTR(self_in);
355+
common_hal_canio_can_check_for_deinit(self);
356+
return mp_obj_new_bool(common_hal_canio_can_silent_get(self));
357+
}
358+
MP_DEFINE_CONST_FUN_OBJ_1(canio_can_silent_get_obj, canio_can_silent_get);
359+
360+
STATIC const mp_obj_property_t canio_can_silent_obj = {
361+
.base.type = &mp_type_property,
362+
.proxy = {(mp_obj_t)&canio_can_silent_get_obj,
363+
(mp_obj_t)mp_const_none,
364+
(mp_obj_t)mp_const_none},
365+
};
366+
367+
324368
//| def deinit(self) -> None:
325369
//| """Deinitialize this object, freeing its hardware resources"""
326370
//| ...
@@ -363,9 +407,11 @@ STATIC const mp_rom_map_elem_t canio_can_locals_dict_table[] = {
363407
{ MP_ROM_QSTR(MP_QSTR_error_passive_state_count), MP_ROM_PTR(&canio_can_error_passive_state_count_obj) },
364408
{ MP_ROM_QSTR(MP_QSTR_error_warning_state_count), MP_ROM_PTR(&canio_can_error_warning_state_count_obj) },
365409
{ MP_ROM_QSTR(MP_QSTR_listen), MP_ROM_PTR(&canio_can_listen_obj) },
410+
{ MP_ROM_QSTR(MP_QSTR_loopback), MP_ROM_PTR(&canio_can_loopback_obj) },
366411
{ MP_ROM_QSTR(MP_QSTR_receive_error_count), MP_ROM_PTR(&canio_can_receive_error_count_obj) },
367412
{ MP_ROM_QSTR(MP_QSTR_restart), MP_ROM_PTR(&canio_can_restart_obj) },
368413
{ MP_ROM_QSTR(MP_QSTR_send), MP_ROM_PTR(&canio_can_send_obj) },
414+
{ MP_ROM_QSTR(MP_QSTR_silent), MP_ROM_PTR(&canio_can_silent_obj) },
369415
{ MP_ROM_QSTR(MP_QSTR_state), MP_ROM_PTR(&canio_can_state_obj) },
370416
{ MP_ROM_QSTR(MP_QSTR_transmit_error_count), MP_ROM_PTR(&canio_can_transmit_error_count_obj) },
371417
};

0 commit comments

Comments
 (0)