From f95ad7b27c040e54daeb4c71d6bb6c35844be66e Mon Sep 17 00:00:00 2001 From: Lucian Copeland Date: Thu, 10 Sep 2020 15:37:43 -0400 Subject: Fix reset pin null reference, construct error null reference --- shared-module/displayio/FourWire.c | 4 +++- shared-module/displayio/I2CDisplay.c | 5 ++++- 2 files changed, 7 insertions(+), 2 deletions(-) (limited to 'shared-module') diff --git a/shared-module/displayio/FourWire.c b/shared-module/displayio/FourWire.c index 17e8cfa1d..726116208 100644 --- a/shared-module/displayio/FourWire.c +++ b/shared-module/displayio/FourWire.c @@ -76,7 +76,9 @@ void common_hal_displayio_fourwire_deinit(displayio_fourwire_obj_t* self) { common_hal_reset_pin(self->command.pin); common_hal_reset_pin(self->chip_select.pin); - common_hal_reset_pin(self->reset.pin); + if (self->reset.pin) { + common_hal_reset_pin(self->reset.pin); + } } bool common_hal_displayio_fourwire_reset(mp_obj_t obj) { diff --git a/shared-module/displayio/I2CDisplay.c b/shared-module/displayio/I2CDisplay.c index 0c8f2e69a..9e9e17881 100644 --- a/shared-module/displayio/I2CDisplay.c +++ b/shared-module/displayio/I2CDisplay.c @@ -53,6 +53,7 @@ void common_hal_displayio_i2cdisplay_construct(displayio_i2cdisplay_obj_t* self, // Probe the bus to see if a device acknowledges the given address. if (!common_hal_busio_i2c_probe(i2c, device_address)) { + self->base.type = &mp_type_NoneType; mp_raise_ValueError_varg(translate("Unable to find I2C Display at %x"), device_address); } @@ -71,7 +72,9 @@ void common_hal_displayio_i2cdisplay_deinit(displayio_i2cdisplay_obj_t* self) { common_hal_busio_i2c_deinit(self->bus); } - common_hal_reset_pin(self->reset.pin); + if (self->reset.pin) { + common_hal_reset_pin(self->reset.pin); + } } bool common_hal_displayio_i2cdisplay_reset(mp_obj_t obj) { -- cgit v1.2.3 From e114b5ab54e3c7f4a36a03dae2913cb76804efa3 Mon Sep 17 00:00:00 2001 From: FoamyGuy Date: Fri, 11 Sep 2020 21:37:00 -0500 Subject: fixes showing OnDiskBitmap with adafruit_sdcard --- shared-module/displayio/Display.c | 5 ++--- shared-module/displayio/display_core.c | 12 +++++++++++- shared-module/displayio/display_core.h | 3 ++- 3 files changed, 15 insertions(+), 5 deletions(-) (limited to 'shared-module') diff --git a/shared-module/displayio/Display.c b/shared-module/displayio/Display.c index 021159c0d..70ed8f2c2 100644 --- a/shared-module/displayio/Display.c +++ b/shared-module/displayio/Display.c @@ -317,11 +317,10 @@ STATIC bool _refresh_area(displayio_display_obj_t* self, const displayio_area_t* } STATIC void _refresh_display(displayio_display_obj_t* self) { - if (!displayio_display_core_bus_free(&self->core)) { - // Can't acquire display bus; skip updating this display. Try next display. + if (!displayio_display_core_start_refresh(&self->core)) { + // A refresh on this bus is already in progress. Try next display. return; } - displayio_display_core_start_refresh(&self->core); const displayio_area_t* current_area = _get_refresh_areas(self); while (current_area != NULL) { _refresh_area(self, current_area); diff --git a/shared-module/displayio/display_core.c b/shared-module/displayio/display_core.c index 43f2d1937..68572c44f 100644 --- a/shared-module/displayio/display_core.c +++ b/shared-module/displayio/display_core.c @@ -295,8 +295,17 @@ void displayio_display_core_set_region_to_update(displayio_display_core_t* self, } } -void displayio_display_core_start_refresh(displayio_display_core_t* self) { +bool displayio_display_core_start_refresh(displayio_display_core_t* self) { + if (!displayio_display_core_bus_free(self)) { + // Can't acquire display bus; skip updating this display. Try next display. + return false; + } + if (self->refresh_in_progress) { + return false; + } + self->refresh_in_progress = true; self->last_refresh = supervisor_ticks_ms64(); + return true; } void displayio_display_core_finish_refresh(displayio_display_core_t* self) { @@ -305,6 +314,7 @@ void displayio_display_core_finish_refresh(displayio_display_core_t* self) { displayio_group_finish_refresh(self->current_group); } self->full_refresh = false; + self->refresh_in_progress = false; self->last_refresh = supervisor_ticks_ms64(); } diff --git a/shared-module/displayio/display_core.h b/shared-module/displayio/display_core.h index e4fd62d4a..c72111f7d 100644 --- a/shared-module/displayio/display_core.h +++ b/shared-module/displayio/display_core.h @@ -54,6 +54,7 @@ typedef struct { int16_t colstart; int16_t rowstart; bool full_refresh; // New group means we need to refresh the whole display. + bool refresh_in_progress; } displayio_display_core_t; void displayio_display_core_construct(displayio_display_core_t* self, @@ -78,7 +79,7 @@ void displayio_display_core_set_region_to_update(displayio_display_core_t* self, void release_display_core(displayio_display_core_t* self); -void displayio_display_core_start_refresh(displayio_display_core_t* self); +bool displayio_display_core_start_refresh(displayio_display_core_t* self); void displayio_display_core_finish_refresh(displayio_display_core_t* self); void displayio_display_core_collect_ptrs(displayio_display_core_t* self); -- cgit v1.2.3 From e504438fd223c9bb0b9d6950a699f1283ece137c Mon Sep 17 00:00:00 2001 From: Lucian Copeland Date: Mon, 14 Sep 2020 11:58:13 -0400 Subject: Remove unlicensed file, fix reset pin type check --- ports/esp32s2/boards/esp32s2-saola-1.cfg | 41 -------------------------------- shared-module/displayio/I2CDisplay.c | 4 ++-- 2 files changed, 2 insertions(+), 43 deletions(-) delete mode 100644 ports/esp32s2/boards/esp32s2-saola-1.cfg (limited to 'shared-module') diff --git a/ports/esp32s2/boards/esp32s2-saola-1.cfg b/ports/esp32s2/boards/esp32s2-saola-1.cfg deleted file mode 100644 index 677290757..000000000 --- a/ports/esp32s2/boards/esp32s2-saola-1.cfg +++ /dev/null @@ -1,41 +0,0 @@ -# The ESP32-S2 only supports JTAG. -transport select jtag -adapter_khz 1000 - -# Source the ESP common configuration file -source [find target/esp_common.cfg] - -if { [info exists CHIPNAME] } { - set _CHIPNAME $CHIPNAME -} else { - set _CHIPNAME esp32s2 -} - -if { [info exists CPUTAPID] } { - set _CPUTAPID $CPUTAPID -} else { - set _CPUTAPID 0x120034e5 -} - -set _TARGETNAME $_CHIPNAME -set _CPUNAME cpu -set _TAPNAME $_CHIPNAME.$_CPUNAME - -jtag newtap $_CHIPNAME $_CPUNAME -irlen 5 -expected-id $_CPUTAPID - -if { $_RTOS == "none" } { - target create $_TARGETNAME esp32s2 -endian little -chain-position $_TAPNAME -} else { - target create $_TARGETNAME esp32s2 -endian little -chain-position $_TAPNAME -rtos $_RTOS -} - -configure_esp_workarea $_TARGETNAME 0x40030000 0x3400 0x3FFE0000 0x6000 -configure_esp_flash_bank $_TARGETNAME $_TARGETNAME $_FLASH_SIZE - -xtensa maskisr on -if { $_SEMIHOST_BASEDIR != "" } { - esp semihost_basedir $_SEMIHOST_BASEDIR -} -if { $_FLASH_SIZE == 0 } { - gdb_breakpoint_override hard -} diff --git a/shared-module/displayio/I2CDisplay.c b/shared-module/displayio/I2CDisplay.c index 9e9e17881..5bd03dcd6 100644 --- a/shared-module/displayio/I2CDisplay.c +++ b/shared-module/displayio/I2CDisplay.c @@ -72,8 +72,8 @@ void common_hal_displayio_i2cdisplay_deinit(displayio_i2cdisplay_obj_t* self) { common_hal_busio_i2c_deinit(self->bus); } - if (self->reset.pin) { - common_hal_reset_pin(self->reset.pin); + if (self->reset.base.type == &digitalio_digitalinout_type) { + common_hal_digitalio_digitalinout_deinit(&self->reset); } } -- cgit v1.2.3 From a2e1867f69ec2d703a9651e5c36a02b0e14dfd9c Mon Sep 17 00:00:00 2001 From: Jeff Epler Date: Thu, 20 Aug 2020 11:08:00 -0500 Subject: _canio: Minimal implementation for SAM E5x MCUs Tested & working: * Send standard packets * Receive standard packets (1 FIFO, no filter) Interoperation between SAM E54 Xplained running this tree and MicroPython running on STM32F405 Feather with an external transceiver was also tested. Many other aspects of a full implementation are not yet present, such as error detection and recovery. --- main.c | 8 + ports/atmel-samd/Makefile | 4 + .../asf4_conf/same54/peripheral_clk_config.h | 82 +++++ ports/atmel-samd/boards/common.template.ld | 7 +- .../boards/same54_xplained/mpconfigboard.mk | 1 + ports/atmel-samd/boards/same54_xplained/pins.c | 5 +- ports/atmel-samd/common-hal/_canio/CAN.c | 384 +++++++++++++++++++++ ports/atmel-samd/common-hal/_canio/CAN.h | 62 ++++ ports/atmel-samd/common-hal/_canio/Listener.c | 117 +++++++ ports/atmel-samd/common-hal/_canio/Listener.h | 53 +++ ports/atmel-samd/common-hal/_canio/__init__.c | 25 ++ ports/atmel-samd/common-hal/_canio/__init__.h | 62 ++++ ports/atmel-samd/tools/mkcandata.py | 31 ++ py/circuitpy_defns.mk | 9 + py/circuitpy_mpconfig.h | 8 + py/circuitpy_mpconfig.mk | 3 + shared-bindings/_canio/CAN.c | 338 ++++++++++++++++++ shared-bindings/_canio/CAN.h | 31 ++ shared-bindings/_canio/Listener.c | 197 +++++++++++ shared-bindings/_canio/Listener.h | 31 ++ shared-bindings/_canio/Match.c | 140 ++++++++ shared-bindings/_canio/Match.h | 33 ++ shared-bindings/_canio/Message.c | 213 ++++++++++++ shared-bindings/_canio/Message.h | 31 ++ shared-bindings/_canio/__init__.c | 73 ++++ shared-bindings/_canio/__init__.h | 29 ++ shared-module/_canio/Match.c | 43 +++ shared-module/_canio/Match.h | 41 +++ shared-module/_canio/Message.c | 85 +++++ shared-module/_canio/Message.h | 47 +++ 30 files changed, 2190 insertions(+), 3 deletions(-) create mode 100644 ports/atmel-samd/common-hal/_canio/CAN.c create mode 100644 ports/atmel-samd/common-hal/_canio/CAN.h create mode 100644 ports/atmel-samd/common-hal/_canio/Listener.c create mode 100644 ports/atmel-samd/common-hal/_canio/Listener.h create mode 100644 ports/atmel-samd/common-hal/_canio/__init__.c create mode 100644 ports/atmel-samd/common-hal/_canio/__init__.h create mode 100755 ports/atmel-samd/tools/mkcandata.py create mode 100644 shared-bindings/_canio/CAN.c create mode 100644 shared-bindings/_canio/CAN.h create mode 100644 shared-bindings/_canio/Listener.c create mode 100644 shared-bindings/_canio/Listener.h create mode 100644 shared-bindings/_canio/Match.c create mode 100644 shared-bindings/_canio/Match.h create mode 100644 shared-bindings/_canio/Message.c create mode 100644 shared-bindings/_canio/Message.h create mode 100644 shared-bindings/_canio/__init__.c create mode 100644 shared-bindings/_canio/__init__.h create mode 100644 shared-module/_canio/Match.c create mode 100644 shared-module/_canio/Match.h create mode 100644 shared-module/_canio/Message.c create mode 100644 shared-module/_canio/Message.h (limited to 'shared-module') diff --git a/main.c b/main.c index 5b719dc4b..f259fea3f 100755 --- a/main.c +++ b/main.c @@ -81,6 +81,10 @@ #include "supervisor/shared/bluetooth.h" #endif +#if CIRCUITPY_CANIO +#include "common-hal/_canio/CAN.h" +#endif + void do_str(const char *src, mp_parse_input_kind_t input_kind) { mp_lexer_t *lex = mp_lexer_new_from_str_len(MP_QSTR__lt_stdin_gt_, src, strlen(src), 0); if (lex == NULL) { @@ -226,6 +230,10 @@ void cleanup_after_vm(supervisor_allocation* heap) { free_memory(heap); supervisor_move_memory(); + #ifdef CIRCUITPY_CANIO + common_hal_canio_reset(); + #endif + reset_port(); #if CIRCUITPY_BOARD reset_board_busses(); diff --git a/ports/atmel-samd/Makefile b/ports/atmel-samd/Makefile index aba630dbb..1ee21679d 100644 --- a/ports/atmel-samd/Makefile +++ b/ports/atmel-samd/Makefile @@ -393,6 +393,10 @@ SRC_QSTR += $(HEADER_BUILD)/sdiodata.h $(HEADER_BUILD)/sdiodata.h: tools/mksdiodata.py | $(HEADER_BUILD) $(Q)$(PYTHON3) $< > $@ +SRC_QSTR += $(HEADER_BUILD)/candata.h +$(HEADER_BUILD)/candata.h: tools/mkcandata.py | $(HEADER_BUILD) + $(Q)$(PYTHON3) $< > $@ + SRC_QSTR += $(SRC_C) $(SRC_SUPERVISOR) $(SRC_COMMON_HAL_EXPANDED) $(SRC_SHARED_MODULE_EXPANDED) # Sources that only hold QSTRs after pre-processing. SRC_QSTR_PREPROCESSOR += peripherals/samd/$(PERIPHERALS_CHIP_FAMILY)/clocks.c diff --git a/ports/atmel-samd/asf4_conf/same54/peripheral_clk_config.h b/ports/atmel-samd/asf4_conf/same54/peripheral_clk_config.h index 59fe8730e..51173f6d3 100644 --- a/ports/atmel-samd/asf4_conf/same54/peripheral_clk_config.h +++ b/ports/atmel-samd/asf4_conf/same54/peripheral_clk_config.h @@ -1165,6 +1165,88 @@ #define CONF_SDHC1_SLOW_FREQUENCY 12000000 #endif +// CAN Clock Settings +// CAN Clock source + +// Generic clock generator 0 + +// Generic clock generator 1 + +// Generic clock generator 2 + +// Generic clock generator 3 + +// Generic clock generator 4 + +// Generic clock generator 5 + +// Generic clock generator 6 + +// Generic clock generator 7 + +// Generic clock generator 8 + +// Generic clock generator 9 + +// Generic clock generator 10 + +// Generic clock generator 11 + +// Select the clock source for CAN. +// sdhc_gclk_selection +#ifndef CONF_GCLK_CAN0_SRC +#define CONF_GCLK_CAN0_SRC GCLK_PCHCTRL_GEN_GCLK0_Val +#endif + +/** + * \def CAN FREQUENCY + * \brief CAN's Clock frequency + */ +#ifndef CONF_CAN0_FREQUENCY +#define CONF_CAN0_FREQUENCY 120000000 +#endif + +// CAN Clock Settings +// CAN Clock source + +// Generic clock generator 0 + +// Generic clock generator 1 + +// Generic clock generator 2 + +// Generic clock generator 3 + +// Generic clock generator 4 + +// Generic clock generator 5 + +// Generic clock generator 6 + +// Generic clock generator 7 + +// Generic clock generator 8 + +// Generic clock generator 9 + +// Generic clock generator 10 + +// Generic clock generator 11 + +// Select the clock source for CAN. +// sdhc_gclk_selection +#ifndef CONF_GCLK_CAN1_SRC +#define CONF_GCLK_CAN1_SRC GCLK_PCHCTRL_GEN_GCLK0_Val +#endif + +/** + * \def CAN FREQUENCY + * \brief CAN's Clock frequency + */ +#ifndef CONF_CAN1_FREQUENCY +#define CONF_CAN1_FREQUENCY 120000000 +#endif + // <<< end of configuration section >>> #endif // PERIPHERAL_CLK_CONFIG_H diff --git a/ports/atmel-samd/boards/common.template.ld b/ports/atmel-samd/boards/common.template.ld index 1054605c8..19e4753f8 100644 --- a/ports/atmel-samd/boards/common.template.ld +++ b/ports/atmel-samd/boards/common.template.ld @@ -51,6 +51,7 @@ SECTIONS { . = ALIGN(4); _srelocate = .; /* create a global symbol at data start; used by startup code in order to initialize the .data section in RAM */ + . = ALIGN(4); *(.ramfunc) *(.ramfunc*) *(.data) /* .data sections */ @@ -61,11 +62,15 @@ SECTIONS } >RAM /* Uninitialized data section */ - .bss : + .bss (NOLOAD) : { . = ALIGN(4); _sbss = .; _szero = .; /* define a global symbol at bss start; used by startup code */ + /* Data accessed by the CAN peripheral must be in the first 64kB RAM */ + _scanram = .; + *(.canram) + _ecanram = .; *(.bss) *(.bss*) *(COMMON) diff --git a/ports/atmel-samd/boards/same54_xplained/mpconfigboard.mk b/ports/atmel-samd/boards/same54_xplained/mpconfigboard.mk index 7ac126514..e4472e05d 100644 --- a/ports/atmel-samd/boards/same54_xplained/mpconfigboard.mk +++ b/ports/atmel-samd/boards/same54_xplained/mpconfigboard.mk @@ -12,3 +12,4 @@ EXTERNAL_FLASH_DEVICES = "N25Q256A" LONGINT_IMPL = MPZ CIRCUITPY_SDIOIO = 1 +CIRCUITPY_CANIO = 1 diff --git a/ports/atmel-samd/boards/same54_xplained/pins.c b/ports/atmel-samd/boards/same54_xplained/pins.c index 8a864ab97..1ed431fba 100644 --- a/ports/atmel-samd/boards/same54_xplained/pins.c +++ b/ports/atmel-samd/boards/same54_xplained/pins.c @@ -48,8 +48,9 @@ STATIC const mp_rom_map_elem_t board_global_dict_table[] = { { MP_OBJ_NEW_QSTR(MP_QSTR_QT), MP_ROM_PTR(&pin_PA16) }, - { MP_OBJ_NEW_QSTR(MP_QSTR_CANRX), MP_ROM_PTR(&pin_PB12) }, - { MP_OBJ_NEW_QSTR(MP_QSTR_CANTX), MP_ROM_PTR(&pin_PB13) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_CAN_RX), MP_ROM_PTR(&pin_PB13) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_CAN_TX), MP_ROM_PTR(&pin_PB12) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_CAN_STANDBY), MP_ROM_PTR(&pin_PC13) }, // EXT1 header { MP_OBJ_NEW_QSTR(MP_QSTR_PB04), MP_ROM_PTR(&pin_PB04) }, diff --git a/ports/atmel-samd/common-hal/_canio/CAN.c b/ports/atmel-samd/common-hal/_canio/CAN.c new file mode 100644 index 000000000..dcd269495 --- /dev/null +++ b/ports/atmel-samd/common-hal/_canio/CAN.c @@ -0,0 +1,384 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2020 Jeff Epler for Adafruit Industries + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include + +#include "py/runtime.h" +#include "py/mperrno.h" + +#include "peripheral_clk_config.h" + +#include "common-hal/_canio/CAN.h" +#include "shared-bindings/microcontroller/Pin.h" +#include "shared-bindings/util.h" +#include "supervisor/port.h" + +#include "component/can.h" + +#include "genhdr/candata.h" + +STATIC Can * const can_insts[] = CAN_INSTS; + +STATIC canio_can_obj_t *can_objs[MP_ARRAY_SIZE(can_insts)]; + +// This must be placed in the first 64kB of RAM +STATIC COMPILER_SECTION(".canram") canio_can_state_t can_state[MP_ARRAY_SIZE(can_insts)]; + +__attribute__((optimize("O0"), noinline)) +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) +{ + mcu_pin_function_t *tx_function = mcu_find_pin_function(can_tx, tx, -1, MP_QSTR_tx); + int instance = tx_function->instance; + + mcu_pin_function_t *rx_function = mcu_find_pin_function(can_rx, rx, instance, MP_QSTR_rx); + + const uint32_t can_frequency = CONF_CAN0_FREQUENCY; + +#define DIV_ROUND(a, b) (((a) + (b)/2) / (b)) +#define DIV_ROUND_UP(a, b) (((a) + (b) - 1) / (b)) + + uint32_t clocks_per_bit = DIV_ROUND(can_frequency, baudrate); + uint32_t clocks_to_sample = DIV_ROUND(clocks_per_bit * 7, 8); + uint32_t clocks_after_sample = clocks_per_bit - clocks_to_sample; + uint32_t divisor = MAX(DIV_ROUND_UP(clocks_to_sample, 256), DIV_ROUND_UP(clocks_after_sample, 128)); + if (divisor > 32) { + mp_raise_OSError(MP_EINVAL); // baudrate cannot be attained (16kHz or something is lower bound, should never happen) + } + + gpio_set_pin_direction(tx_function->pin, GPIO_DIRECTION_OUT); + gpio_set_pin_function(tx_function->pin, tx_function->function); + common_hal_never_reset_pin(tx_function->obj); + + if (rx_function) { + gpio_set_pin_direction(rx_function->pin, GPIO_DIRECTION_IN); + gpio_set_pin_function(rx_function->pin, rx_function->function); + common_hal_never_reset_pin(rx_function->obj); + } + + self->tx_pin_number = common_hal_mcu_pin_number(tx); + self->rx_pin_number = rx ? common_hal_mcu_pin_number(rx) : COMMON_HAL_MCU_NO_PIN; + self->hw = can_insts[instance]; + self->state = &can_state[instance]; + + self->loopback = loopback; + + // Allow configuration change + hri_can_set_CCCR_INIT_bit(self->hw); + while (hri_can_get_CCCR_INIT_bit(self->hw) == 0) { + } + hri_can_set_CCCR_CCE_bit(self->hw); + + if(instance == 0) { + hri_mclk_set_AHBMASK_CAN0_bit(MCLK); + hri_gclk_write_PCHCTRL_reg(GCLK, CAN0_GCLK_ID, CONF_GCLK_CAN0_SRC | (1 << GCLK_PCHCTRL_CHEN_Pos)); + + NVIC_DisableIRQ(CAN0_IRQn); + NVIC_ClearPendingIRQ(CAN0_IRQn); + NVIC_EnableIRQ(CAN0_IRQn); + hri_can_write_ILE_reg(self->hw, CAN_ILE_EINT0); +#ifdef CAN1_GCLK_ID + } else if(instance == 1) { + hri_mclk_set_AHBMASK_CAN1_bit(MCLK); + hri_gclk_write_PCHCTRL_reg(GCLK, CAN1_GCLK_ID, CONF_GCLK_CAN1_SRC | (1 << GCLK_PCHCTRL_CHEN_Pos)); + + NVIC_DisableIRQ(CAN1_IRQn); + NVIC_ClearPendingIRQ(CAN1_IRQn); + NVIC_EnableIRQ(CAN1_IRQn); + hri_can_write_ILE_reg(self->hw, CAN_ILE_EINT0); +#endif + } + + self->hw->CCCR.bit.FDOE = 0; // neither FD nor Bit Rate Switch enabled + self->hw->CCCR.bit.BRSE = 0; + + hri_can_write_MRCFG_reg(self->hw, CAN_MRCFG_QOS(CAN_MRCFG_QOS_DISABLE_Val)); // QoS disabled (no sensitive operation) + + // A "nominal bit" is a header bit. With dual rate CAN FD, this is a slower rate + { + CAN_NBTP_Type btp = { + // 0 means "1 tq", but 2 is subtracted from NTSEG1 for the + // fixed 1 "SYNC" tq + .bit.NTSEG1 = DIV_ROUND(clocks_to_sample, divisor) - 2, + .bit.NTSEG2 = DIV_ROUND(clocks_after_sample, divisor) - 1, + .bit.NBRP = divisor - 1, + .bit.NSJW = DIV_ROUND(clocks_after_sample, divisor * 4), + }; + hri_can_write_NBTP_reg(self->hw, btp.reg); + } + + // we don't do the high bit rate yet, so do we need to set this register? + // hri_can_write_DBTP_reg(self->hw, ???); + // A "data bit" is a data bit :) with dul rate CAN FD, this is a higher + // rate. However, CAN FD is not implemented in CircuitPython, and this is the same rate as + // the "nominal rate". + { + CAN_DBTP_Type btp = { + .bit.DTSEG1 = DIV_ROUND(clocks_to_sample, divisor) - 1, + .bit.DTSEG2 = DIV_ROUND(clocks_after_sample, divisor) - 1, + .bit.DBRP = divisor - 1, + .bit.DSJW = DIV_ROUND(clocks_after_sample, divisor * 4), + }; + hri_can_write_DBTP_reg(self->hw, btp.reg); + } + + { + CAN_RXF0C_Type rxf = { + .bit.F0SA = (uint32_t)self->state->rx0_fifo, + .bit.F0S = COMMON_HAL_CANIO_RX_FIFO_SIZE, + }; + hri_can_write_RXF0C_reg(self->hw, rxf.reg); + } + + { + CAN_RXF1C_Type rxf = { + .bit.F1SA = (uint32_t)self->state->rx1_fifo, + .bit.F1S = COMMON_HAL_CANIO_RX_FIFO_SIZE, + }; + hri_can_write_RXF1C_reg(self->hw, rxf.reg); + } + + // All RX data has an 8 byte payload (max) + { + CAN_RXESC_Type esc = { + .bit.F0DS = CAN_RXESC_F0DS_DATA8_Val, + .bit.F1DS = CAN_RXESC_F1DS_DATA8_Val, + .bit.RBDS = CAN_RXESC_RBDS_DATA8_Val, + }; + hri_can_write_RXESC_reg(self->hw, esc.reg); + } + + // All TX data has an 8 byte payload (max) + { + CAN_TXESC_Type esc = { + .bit.TBDS = CAN_TXESC_TBDS_DATA8_Val, + }; + hri_can_write_TXESC_reg(self->hw, esc.reg); + } + + { + CAN_TXBC_Type bc = { + .bit.TBSA = (uint32_t)self->state->tx_fifo, + .bit.NDTB = COMMON_HAL_CANIO_TX_FIFO_SIZE, + .bit.TFQM = 0, // Messages are transmitted in the order submitted + }; + hri_can_write_TXBC_reg(self->hw, bc.reg); + } + + { + CAN_TXEFC_Type efc = { + .bit.EFS = 0, + }; + hri_can_write_TXEFC_reg(self->hw, efc.reg); + } + + { + CAN_GFC_Type gfc = { + .bit.RRFE = 1, + .bit.ANFS = CAN_GFC_ANFS_RXF0_Val, + .bit.ANFE = CAN_GFC_ANFE_REJECT_Val, + }; + hri_can_write_GFC_reg(self->hw, gfc.reg); + } + + { + CAN_SIDFC_Type dfc = { + .bit.LSS = COMMON_HAL_CANIO_RX_FILTER_SIZE, + .bit.FLSSA = (uint32_t)self->state->rx_filter + }; + hri_can_write_SIDFC_reg(self->hw, dfc.reg); + } + + { + CAN_XIDFC_Type dfc = { + .bit.LSE = 0, + }; + hri_can_write_XIDFC_reg(self->hw, dfc.reg); + } + + hri_can_write_XIDAM_reg(self->hw, CAN_XIDAM_RESETVALUE); + +// silent: The CAN is set in Bus Monitoring Mode by programming CCCR.MON to '1'. (tx pin unused) +// external loopback: The CAN can be set in External Loop Back Mode by programming TEST.LBCK and CCCR.MON to '1'. (rx pin unused) +// internal loopback (silent loopback): Internal Loop Back Mode is entered by programming bits TEST.LBCK and CCCR.MON to '1'. (tx, rx unused) + self->hw->CCCR.bit.MON = silent; + self->hw->CCCR.bit.TEST = loopback; + self->hw->TEST.bit.LBCK = loopback; + + if(instance == 0) { + NVIC_DisableIRQ(CAN0_IRQn); + NVIC_ClearPendingIRQ(CAN0_IRQn); + NVIC_EnableIRQ(CAN0_IRQn); +#ifdef CAN1_GCLK_ID + } else if(instance == 1) { + NVIC_DisableIRQ(CAN1_IRQn); + NVIC_ClearPendingIRQ(CAN1_IRQn); + NVIC_EnableIRQ(CAN1_IRQn); +#endif + } + + hri_can_write_ILE_reg(self->hw, CAN_ILE_EINT0); + // Prevent configuration change + hri_can_clear_CCCR_CCE_bit(self->hw); + hri_can_clear_CCCR_INIT_bit(self->hw); + while (hri_can_get_CCCR_INIT_bit(self->hw)) { + } + + can_objs[instance] = self; +} + +int common_hal_canio_can_loopback_get(canio_can_obj_t *self) +{ + return self->loopback; +} + +int common_hal_canio_can_baudrate_get(canio_can_obj_t *self) +{ + return self->baudrate; +} + +int common_hal_canio_can_transmit_error_count_get(canio_can_obj_t *self) +{ + return -1; +} + +int common_hal_canio_can_receive_error_count_get(canio_can_obj_t *self) +{ + return -1; +} + +int common_hal_canio_can_error_warning_state_count_get(canio_can_obj_t *self) +{ + return -1; +} + +int common_hal_canio_can_error_passive_state_count_get(canio_can_obj_t *self) +{ + return -1; +} + +int common_hal_canio_can_bus_off_state_count_get(canio_can_obj_t *self) +{ + return -1; +} + +int common_hal_canio_can_state_get(canio_can_obj_t *self) { + return -1; +} + +void common_hal_canio_can_send(canio_can_obj_t *self, canio_message_obj_t *message) +{ + // We have just one dedicated TX buffer, use it! + canio_can_fifo_t *ent = &self->state->tx_fifo[0]; + ent->txb0.bit.ESI = false; + ent->txb0.bit.XTD = false; + ent->txb0.bit.RTR = message->rtr; + ent->txb0.bit.ID = message->id << 18; // short addresses are left-justified + + ent->txb1.bit.MM = 0; // "message marker" + ent->txb1.bit.EFC = 0; // don't store fifo events to event queue + ent->txb1.bit.FDF = 0; // Classic CAN format + ent->txb1.bit.BRS = 0; // No bit rate switching + ent->txb1.bit.DLC = message->size; + + if (!message->rtr) { + memcpy(ent->data, message->data, message->size); + } + + // TX buffer add request + self->hw->TXBAR.reg = 1; + + // wait 8ms (hard coded for now) for TX to occur + uint64_t deadline = port_get_raw_ticks(NULL) + 8; + while (port_get_raw_ticks(NULL) < deadline && !(self->hw->TXBTO.reg & 1)) { + RUN_BACKGROUND_TASKS; + } +} + +bool common_hal_canio_can_deinited(canio_can_obj_t *self) { + return !self->hw; +} + +void common_hal_canio_can_check_for_deinit(canio_can_obj_t *self) { + if(common_hal_canio_can_deinited(self)) { + raise_deinited_error(); + } +} + +void common_hal_canio_can_deinit(canio_can_obj_t *self) +{ + if (self->hw) { + hri_can_set_CCCR_INIT_bit(self->hw); + self->hw = 0; + } + if (self->rx_pin_number != COMMON_HAL_MCU_NO_PIN) { + reset_pin_number(self->rx_pin_number); + self->rx_pin_number = COMMON_HAL_MCU_NO_PIN; + } + if (self->tx_pin_number != COMMON_HAL_MCU_NO_PIN) { + reset_pin_number(self->tx_pin_number); + self->tx_pin_number = COMMON_HAL_MCU_NO_PIN; + } +} + +void common_hal_canio_reset(void) { + memset(can_state, 0, sizeof(can_state)); + + for (size_t i=0; i +#include + +#include "py/obj.h" +#include "py/runtime.h" + +#include "common-hal/_canio/__init__.h" +#include "common-hal/_canio/Listener.h" +#include "shared-bindings/util.h" +#include "supervisor/shared/tick.h" + +void common_hal_canio_listener_construct(canio_listener_obj_t *self, canio_can_obj_t *can, size_t nmatch, canio_match_obj_t **matches, float timeout) { + if (nmatch) { + mp_raise_NotImplementedError(NULL); + } + + if (!can->fifo0_in_use) { + self->fifo_idx = 0; + self->fifo = can->state->rx0_fifo; + self->hw = (canio_rxfifo_reg_t*)&can->hw->RXF0C; + can->hw->IR.reg = CAN_IR_RF0N | CAN_IR_RF0W | CAN_IR_RF0F | CAN_IR_RF0L; + can->fifo0_in_use = true; + } else if (!can->fifo1_in_use) { + self->fifo_idx = 1; + self->fifo = can->state->rx1_fifo; + self->hw = (canio_rxfifo_reg_t*)&can->hw->RXF1C; + can->fifo1_in_use = true; + can->hw->IR.reg = CAN_IR_RF1N | CAN_IR_RF1W | CAN_IR_RF1F | CAN_IR_RF1L; + } else { + mp_raise_ValueError(translate("All RX FIFOs in use")); + } + + self->can = can; + common_hal_canio_listener_set_timeout(self, timeout); +} + +void common_hal_canio_listener_set_timeout(canio_listener_obj_t *self, float timeout) { + self->timeout_ms = (int)MICROPY_FLOAT_C_FUN(ceil)(timeout * 1000); +} + +float common_hal_canio_listener_get_timeout(canio_listener_obj_t *self) { + return self->timeout_ms / 1000.0f; +} + +void common_hal_canio_listener_check_for_deinit(canio_listener_obj_t *self) { + if(!self->can) { + raise_deinited_error(); + } + common_hal_canio_can_check_for_deinit(self->can); +} + +int common_hal_canio_listener_in_waiting(canio_listener_obj_t *self) { + return self->hw->RXFS.bit.F0FL; +} + +bool common_hal_canio_listener_readinto(canio_listener_obj_t *self, canio_message_obj_t *message) { + if (!common_hal_canio_listener_in_waiting(self)) { + uint64_t deadline = supervisor_ticks_ms64() + self->timeout_ms; + do { + if(supervisor_ticks_ms64() > deadline) { + return false; + } + } while (!common_hal_canio_listener_in_waiting(self)); + } + int index = self->hw->RXFS.bit.F0GI; + canio_can_fifo_t *hw_message = &self->fifo[index]; + message->id = hw_message->rxb0.bit.ID >> 18; // short addresses are left-justified + message->rtr = hw_message->rxb0.bit.RTR; + message->size = hw_message->rxb1.bit.DLC; + if(!message->rtr) { + memcpy(message->data, hw_message->data, message->size); + } + self->hw->RXFA.bit.F0AI = index; + return true; +} + +void common_hal_canio_listener_deinit(canio_listener_obj_t *self) { + // free our FIFO, clear our matches, SOMETHING + if(self->can) { + if(self->fifo_idx == 0) { + self->can->fifo0_in_use = false; + } + if(self->fifo_idx == 1) { + self->can->fifo1_in_use = false; + } + } + self->fifo_idx = -1; + self->fifo = NULL; + self->can = NULL; + self->hw = NULL; +} diff --git a/ports/atmel-samd/common-hal/_canio/Listener.h b/ports/atmel-samd/common-hal/_canio/Listener.h new file mode 100644 index 000000000..cc6770e6e --- /dev/null +++ b/ports/atmel-samd/common-hal/_canio/Listener.h @@ -0,0 +1,53 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2020 Jeff Epler for Adafruit Industries + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#pragma once + +#include "common-hal/_canio/CAN.h" +#include "shared-module/_canio/Match.h" + +typedef struct { + __IO CAN_RXF0C_Type RXFC; /**< \brief (R/W 32) Rx FIFO n Configuration */ + __I CAN_RXF0S_Type RXFS; /**< \brief (R/ 32) Rx FIFO n Status */ + __IO CAN_RXF0A_Type RXFA; /**< \brief (R/W 32) Rx FIFO n Acknowledge */ +} canio_rxfifo_reg_t; + +typedef struct { + mp_obj_base_t base; + canio_can_obj_t *can; + canio_can_fifo_t *fifo; + canio_rxfifo_reg_t *hw; + uint32_t timeout_ms; + uint8_t fifo_idx; +} canio_listener_obj_t; + +void common_hal_canio_listener_construct(canio_listener_obj_t *self, canio_can_obj_t *can, size_t nmatch, canio_match_obj_t **matches, float timeout); +void common_hal_canio_listener_check_for_deinit(canio_listener_obj_t *self); +void common_hal_canio_listener_deinit(canio_listener_obj_t *self); +bool common_hal_canio_listener_readinto(canio_listener_obj_t *self, canio_message_obj_t *message); +int common_hal_canio_listener_in_waiting(canio_listener_obj_t *self); +float common_hal_canio_listener_get_timeout(canio_listener_obj_t *self); +void common_hal_canio_listener_set_timeout(canio_listener_obj_t *self, float timeout); diff --git a/ports/atmel-samd/common-hal/_canio/__init__.c b/ports/atmel-samd/common-hal/_canio/__init__.c new file mode 100644 index 000000000..7932bfc2d --- /dev/null +++ b/ports/atmel-samd/common-hal/_canio/__init__.c @@ -0,0 +1,25 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2020 Jeff Epler for Adafruit Industries + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ diff --git a/ports/atmel-samd/common-hal/_canio/__init__.h b/ports/atmel-samd/common-hal/_canio/__init__.h new file mode 100644 index 000000000..429369e18 --- /dev/null +++ b/ports/atmel-samd/common-hal/_canio/__init__.h @@ -0,0 +1,62 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2020 Jeff Epler for Adafruit Industries + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#pragma once + +#include "hal/utils/include/utils.h" +#include "component/can.h" + +#define COMMON_HAL_CANIO_MAX_MESSAGE_LENGTH (8) +#define COMMON_HAL_CANIO_RX_FIFO_SIZE (3) +#define COMMON_HAL_CANIO_RX_FILTER_SIZE (4) +#define COMMON_HAL_CANIO_TX_FIFO_SIZE (1) + +typedef struct canio_listener canio_listener_t; +typedef struct canio_can canio_can_t; + +typedef struct { + union { + CAN_RXBE_0_Type rxb0; + CAN_TXBE_0_Type txb0; + CAN_RXF0E_0_Type rxf0; + }; + union { + CAN_RXBE_1_Type rxb1; + CAN_TXBE_1_Type txb1; + CAN_RXF0E_1_Type rxf1; + }; + COMPILER_ALIGNED(4) + uint8_t data[COMMON_HAL_CANIO_MAX_MESSAGE_LENGTH]; +} canio_can_fifo_t; + +typedef uint32_t canio_can_filter_t; + +typedef struct { + canio_can_fifo_t tx_fifo[COMMON_HAL_CANIO_TX_FIFO_SIZE]; + canio_can_fifo_t rx0_fifo[COMMON_HAL_CANIO_RX_FIFO_SIZE]; + canio_can_fifo_t rx1_fifo[COMMON_HAL_CANIO_RX_FIFO_SIZE]; + canio_can_filter_t rx_filter[COMMON_HAL_CANIO_RX_FILTER_SIZE]; +} canio_can_state_t; diff --git a/ports/atmel-samd/tools/mkcandata.py b/ports/atmel-samd/tools/mkcandata.py new file mode 100755 index 000000000..9668d2208 --- /dev/null +++ b/ports/atmel-samd/tools/mkcandata.py @@ -0,0 +1,31 @@ +#!/usr/bin/python3 + +def defines(name, suffix): + print(f'mcu_pin_function_t {name} [] = {{') + for instance in (0, 1): + for function in 'HI': + for port in 'ABCD': + for idx in range(32): + pin = f'P{port}{idx:02d}' + pinmux = f'PINMUX_{pin}{function}_CAN{instance}_{suffix}' + print(f'''\ +#if defined({pinmux}) && ! defined(IGNORE_PIN_{pin}) + {{&pin_{pin}, {instance}, PIN_{pin}, {pinmux} & 0xffff}}, +#endif''') + print(f'{{NULL, 0, 0}}') + print(f'}};') + print() + +print('''\ +#include +#include "py/obj.h" +#include "sam.h" +#include "samd/pins.h" +#include "mpconfigport.h" +#include "atmel_start_pins.h" +#include "hal/include/hal_gpio.h" +#include "common-hal/microcontroller/Pin.h" +''') + +defines('can_rx', 'RX') +defines('can_tx', 'TX') diff --git a/py/circuitpy_defns.mk b/py/circuitpy_defns.mk index 6e98af868..2614dc011 100644 --- a/py/circuitpy_defns.mk +++ b/py/circuitpy_defns.mk @@ -142,6 +142,9 @@ endif ifeq ($(CIRCUITPY_CAMERA),1) SRC_PATTERNS += camera/% endif +ifeq ($(CIRCUITPY_CANIO),1) +SRC_PATTERNS += _canio/% +endif ifeq ($(CIRCUITPY_COUNTIO),1) SRC_PATTERNS += countio/% endif @@ -315,6 +318,9 @@ SRC_COMMON_HAL_ALL = \ busio/__init__.c \ camera/__init__.c \ camera/Camera.c \ + _canio/CAN.c \ + _canio/Listener.c \ + _canio/__init__.c \ countio/Counter.c \ countio/__init__.c \ digitalio/DigitalInOut.c \ @@ -384,6 +390,7 @@ $(filter $(SRC_PATTERNS), \ _bleio/Address.c \ _bleio/Attribute.c \ _bleio/ScanEntry.c \ + _canio/Match.c \ _eve/__init__.c \ camera/ImageFormat.c \ digitalio/Direction.c \ @@ -402,6 +409,8 @@ SRC_SHARED_MODULE_ALL = \ _bleio/Attribute.c \ _bleio/ScanEntry.c \ _bleio/ScanResults.c \ + _canio/Match.c \ + _canio/Message.c \ _eve/__init__.c \ _pixelbuf/PixelBuf.c \ _pixelbuf/__init__.c \ diff --git a/py/circuitpy_mpconfig.h b/py/circuitpy_mpconfig.h index 4272de2ec..d1b12f354 100644 --- a/py/circuitpy_mpconfig.h +++ b/py/circuitpy_mpconfig.h @@ -336,6 +336,13 @@ extern const struct _mp_obj_module_t camera_module; #define CAMERA_MODULE #endif +#if CIRCUITPY_CANIO +extern const struct _mp_obj_module_t canio_module; +#define CANIO_MODULE { MP_OBJ_NEW_QSTR(MP_QSTR__canio), (mp_obj_t)&canio_module }, +#else +#define CANIO_MODULE +#endif + #if CIRCUITPY_COUNTIO extern const struct _mp_obj_module_t countio_module; #define COUNTIO_MODULE { MP_OBJ_NEW_QSTR(MP_QSTR_countio), (mp_obj_t)&countio_module }, @@ -766,6 +773,7 @@ extern const struct _mp_obj_module_t wifi_module; BOARD_MODULE \ BUSIO_MODULE \ CAMERA_MODULE \ + CANIO_MODULE \ COUNTIO_MODULE \ DIGITALIO_MODULE \ DISPLAYIO_MODULE \ diff --git a/py/circuitpy_mpconfig.mk b/py/circuitpy_mpconfig.mk index 54bdefc6d..9b9bd83b4 100644 --- a/py/circuitpy_mpconfig.mk +++ b/py/circuitpy_mpconfig.mk @@ -93,6 +93,9 @@ CFLAGS += -DCIRCUITPY_BUSIO=$(CIRCUITPY_BUSIO) CIRCUITPY_CAMERA ?= 0 CFLAGS += -DCIRCUITPY_CAMERA=$(CIRCUITPY_CAMERA) +CIRCUITPY_CANIO ?= 0 +CFLAGS += -DCIRCUITPY_CANIO=$(CIRCUITPY_CANIO) + CIRCUITPY_DIGITALIO ?= 1 CFLAGS += -DCIRCUITPY_DIGITALIO=$(CIRCUITPY_DIGITALIO) diff --git a/shared-bindings/_canio/CAN.c b/shared-bindings/_canio/CAN.c new file mode 100644 index 000000000..4c7ae3650 --- /dev/null +++ b/shared-bindings/_canio/CAN.c @@ -0,0 +1,338 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2020 Jeff Epler for Adafruit Industries + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "common-hal/_canio/CAN.h" +#include "common-hal/_canio/Listener.h" +#include "shared-bindings/_canio/CAN.h" +#include "shared-bindings/_canio/Listener.h" +#include "shared-bindings/_canio/Match.h" +#include "shared-bindings/_canio/Message.h" +#include "shared-bindings/microcontroller/Pin.h" + +#include "py/objproperty.h" +#include "py/runtime.h" + +//| +//| class CAN: +//| """CAN bus protocol""" +//| +//| def __init__(self, +//| rx: microcontroller.Pin, +//| tx: Optional[microcontroller.Pin]=None, +//| *, +//| baudrate: int = 250000, +//| loopback: bool = False, +//| ): +//| """A common shared-bus protocol. The rx and tx pins are generally +//| connected to a transceiver which controls the H and L pins on a shared +//| bus. +//| +//| :param ~microcontrller.Pin rx: the pin to receive with. +//| :param ~microcontrller.Pin tx: the pin to transmit with, or None if the peripheral should operate in "silent" mode. +//| :param int baudrate: The bit rate of the bus in Hz. All devices on the bus must agree on this value. +//| :param bool loopback: True if the peripheral will be operated in loopback mode. +//| """ +//| ... +//| +//## auto_restart: bool = False, # Whether to restart communications after entering bus-off state +//## sample_point: float = .875, # When to sample within bit time (0.0-1.0) +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) { + enum { ARG_rx, ARG_tx, ARG_baudrate, ARG_loopback, ARG_silent, NUM_ARGS }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_rx, MP_ARG_OBJ | MP_ARG_REQUIRED, {.u_obj = 0} }, + { MP_QSTR_tx, MP_ARG_OBJ, {.u_obj = 0} }, + { MP_QSTR_baudrate, MP_ARG_INT, {.u_int = 250000} }, + { MP_QSTR_loopback, MP_ARG_BOOL, {.u_bool = false} }, + { MP_QSTR_silent, MP_ARG_BOOL, {.u_bool = false} }, + }; + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + MP_STATIC_ASSERT( MP_ARRAY_SIZE(allowed_args) == NUM_ARGS ); + + mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + +mp_printf(&mp_plat_print, "ARG_rx=%d args[ARG_rx].u_obj=%p\n", ARG_rx, args[ARG_rx].u_obj); +mp_printf(&mp_plat_print, "ARG_tx=%d args[ARG_tx].u_obj=%p\n", ARG_tx, args[ARG_tx].u_obj); + + mcu_pin_obj_t *rx_pin = validate_obj_is_free_pin(args[ARG_rx].u_obj); +mp_printf(&mp_plat_print, "rx_pin=%p\n", rx_pin); + mcu_pin_obj_t *tx_pin = validate_obj_is_free_pin_or_none(args[ARG_tx].u_obj); +mp_printf(&mp_plat_print, "tx_pin=%p\n", tx_pin); + + canio_can_obj_t *self = m_new_obj(canio_can_obj_t); + self->base.type = &canio_can_type; + common_hal_canio_can_construct(self, rx_pin, tx_pin, args[ARG_baudrate].u_int, args[ARG_loopback].u_bool, args[ARG_silent].u_bool); + + return MP_OBJ_FROM_PTR(self); +} + + +//| baudrate: int +//| """The baud rate(read-only)""" +//| +STATIC mp_obj_t canio_can_baudrate_get(mp_obj_t self_in) { + canio_can_obj_t *self = MP_OBJ_TO_PTR(self_in); + common_hal_canio_can_check_for_deinit(self); + return MP_OBJ_NEW_SMALL_INT(common_hal_canio_can_baudrate_get(self)); +} +MP_DEFINE_CONST_FUN_OBJ_1(canio_can_baudrate_get_obj, canio_can_baudrate_get); + +STATIC const mp_obj_property_t canio_can_baudrate_obj = { + .base.type = &mp_type_property, + .proxy = {(mp_obj_t)&canio_can_baudrate_get_obj, + (mp_obj_t)mp_const_none, + (mp_obj_t)mp_const_none}, +}; + +//| state: State +//| """The status of the hardware (read-only)""" +//| +STATIC mp_obj_t canio_can_state_get(mp_obj_t self_in) { + canio_can_obj_t *self = MP_OBJ_TO_PTR(self_in); + common_hal_canio_can_check_for_deinit(self); + return MP_OBJ_NEW_SMALL_INT(common_hal_canio_can_state_get(self)); +} +MP_DEFINE_CONST_FUN_OBJ_1(canio_can_state_get_obj, canio_can_state_get); + +STATIC const mp_obj_property_t canio_can_state_obj = { + .base.type = &mp_type_property, + .proxy = {(mp_obj_t)&canio_can_state_get_obj, + (mp_obj_t)mp_const_none, + (mp_obj_t)mp_const_none}, +}; + +//| transmit_error_count: int +//| """The number of transmit errors (read-only). Increased for a detected transmission error, decreased for successful transmission. Limited to the range from 0 to 255 inclusive. Also called TEC.""" +//| +STATIC mp_obj_t canio_can_transmit_error_count_get(mp_obj_t self_in) { + canio_can_obj_t *self = MP_OBJ_TO_PTR(self_in); + common_hal_canio_can_check_for_deinit(self); + return MP_OBJ_NEW_SMALL_INT(common_hal_canio_can_transmit_error_count_get(self)); +} +MP_DEFINE_CONST_FUN_OBJ_1(canio_can_transmit_error_count_get_obj, canio_can_transmit_error_count_get); + +STATIC const mp_obj_property_t canio_can_transmit_error_count_obj = { + .base.type = &mp_type_property, + .proxy = {(mp_obj_t)&canio_can_transmit_error_count_get_obj, + (mp_obj_t)mp_const_none, + (mp_obj_t)mp_const_none}, +}; + +//| receive_error_count: int +//| """The number of receive errors (read-only). Increased for a detected reception error, decreased for successful reception. Limited to the range from 0 to 255 inclusive. Also called REC.""" +//| +STATIC mp_obj_t canio_can_receive_error_count_get(mp_obj_t self_in) { + canio_can_obj_t *self = MP_OBJ_TO_PTR(self_in); + common_hal_canio_can_check_for_deinit(self); + return MP_OBJ_NEW_SMALL_INT(common_hal_canio_can_receive_error_count_get(self)); +} +MP_DEFINE_CONST_FUN_OBJ_1(canio_can_receive_error_count_get_obj, canio_can_receive_error_count_get); + +STATIC const mp_obj_property_t canio_can_receive_error_count_obj = { + .base.type = &mp_type_property, + .proxy = {(mp_obj_t)&canio_can_receive_error_count_get_obj, + (mp_obj_t)mp_const_none, + (mp_obj_t)mp_const_none}, +}; + +//| error_warning_state_count: int +//| """The number of times the controller enterted the Error Warning state (read-only). This number wraps around to 0 after an implementation-defined number of errors.""" +//| +STATIC mp_obj_t canio_can_error_warning_state_count_get(mp_obj_t self_in) { + canio_can_obj_t *self = MP_OBJ_TO_PTR(self_in); + common_hal_canio_can_check_for_deinit(self); + return MP_OBJ_NEW_SMALL_INT(common_hal_canio_can_error_warning_state_count_get(self)); +} +MP_DEFINE_CONST_FUN_OBJ_1(canio_can_error_warning_state_count_get_obj, canio_can_error_warning_state_count_get); + +STATIC const mp_obj_property_t canio_can_error_warning_state_count_obj = { + .base.type = &mp_type_property, + .proxy = {(mp_obj_t)&canio_can_error_warning_state_count_get_obj, + (mp_obj_t)mp_const_none, + (mp_obj_t)mp_const_none}, +}; + +//| error_passive_state_count: int +//| """The number of times the controller enterted the Error Passive state (read-only). This number wraps around to 0 after an implementation-defined number of errors.""" +//| +STATIC mp_obj_t canio_can_error_passive_state_count_get(mp_obj_t self_in) { + canio_can_obj_t *self = MP_OBJ_TO_PTR(self_in); + common_hal_canio_can_check_for_deinit(self); + return MP_OBJ_NEW_SMALL_INT(common_hal_canio_can_error_passive_state_count_get(self)); +} +MP_DEFINE_CONST_FUN_OBJ_1(canio_can_error_passive_state_count_get_obj, canio_can_error_passive_state_count_get); + +STATIC const mp_obj_property_t canio_can_error_passive_state_count_obj = { + .base.type = &mp_type_property, + .proxy = {(mp_obj_t)&canio_can_error_passive_state_count_get_obj, + (mp_obj_t)mp_const_none, + (mp_obj_t)mp_const_none}, +}; + +//| bus_off_state_count: int +//| """The number of times the controller enterted the Bus Off state (read-only). This number wraps around to 0 after an implementation-defined number of errors.""" +//| +STATIC mp_obj_t canio_can_bus_off_state_count_get(mp_obj_t self_in) { + canio_can_obj_t *self = MP_OBJ_TO_PTR(self_in); + common_hal_canio_can_check_for_deinit(self); + return MP_OBJ_NEW_SMALL_INT(common_hal_canio_can_bus_off_state_count_get(self)); +} +MP_DEFINE_CONST_FUN_OBJ_1(canio_can_bus_off_state_count_get_obj, canio_can_bus_off_state_count_get); + +STATIC const mp_obj_property_t canio_can_bus_off_state_count_obj = { + .base.type = &mp_type_property, + .proxy = {(mp_obj_t)&canio_can_bus_off_state_count_get_obj, + (mp_obj_t)mp_const_none, + (mp_obj_t)mp_const_none}, +}; + +#if 0 +//| # pending_tx_count: int +//| # """The number of messages waiting to be transmitted. (read-only)""" +#endif + +//| def listen(filters: Optional[Sequence[Filter]]=None, *, timeout: float=10) -> Listener: +//| """Start receiving messages that match any one of the filters. +//| Creating a listener is an expensive operation and can interfere with reception of messages by other listeners. +//| There is an implementation-defined maximum number of listeners and limit to the complexity of the filters. +//| If the hardware cannot support all the requested filters, a ValueError is raised. Note that generally there are some number of hardware filters shared among all fifos. +//| A message can be received by at most one Listener. +//| An empty filter list causes all messages to be accepted. +//| Timeout dictates how long readinto, read and next() will block. +//| Readinto will return false(), read will return None, and next() will raise StopIteration.""" +//| ... +//| +STATIC mp_obj_t canio_can_listen(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + canio_can_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]); + common_hal_canio_can_check_for_deinit(self); + + enum { ARG_match, ARG_timeout, NUM_ARGS }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_match, MP_ARG_OBJ, {.u_obj = 0} }, + { MP_QSTR_timeout, MP_ARG_OBJ, {.u_obj = 0} }, + }; + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + MP_STATIC_ASSERT( MP_ARRAY_SIZE(allowed_args) == NUM_ARGS ); + + mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + size_t nmatch = 0; + mp_obj_t *match_objects = NULL; + + if (args[ARG_match].u_obj) { + mp_obj_get_array(args[ARG_match].u_obj, &nmatch, &match_objects); + } + + canio_match_obj_t *matches[nmatch]; + for (size_t i=0; iname); + } + matches[i] = MP_OBJ_TO_PTR(match_objects[i]); + } + + float timeout = args[ARG_timeout].u_obj ? mp_obj_get_float(args[ARG_timeout].u_obj) : 10.0f; + canio_listener_obj_t *listener = m_new_obj(canio_listener_obj_t); + listener->base.type = &canio_listener_type; + common_hal_canio_listener_construct(listener, self, nmatch, matches, timeout); + return listener; +} +MP_DEFINE_CONST_FUN_OBJ_KW(canio_can_listen_obj, 1, canio_can_listen); + +//| def send(message: Message) -> None: +//| """Send a message on the bus with the given data and id. +//| If the message could not be sent due to a full fifo or a bus error condition, RuntimeError is raised. +//| """ +//| ... +//| +STATIC mp_obj_t canio_can_send(mp_obj_t self_in, mp_obj_t message_in) { + canio_can_obj_t *self = MP_OBJ_TO_PTR(self_in); + common_hal_canio_can_check_for_deinit(self); + mp_obj_type_t *message_type = mp_obj_get_type(message_in); + if (message_type != &canio_message_type) { + mp_raise_TypeError_varg(translate("expected '%q' but got '%q'"), MP_QSTR_Message, message_type->name); + } + + canio_message_obj_t *message = message_in; + common_hal_canio_can_send(self, message); + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_2(canio_can_send_obj, canio_can_send); + +//| def deinit(self) -> None: +//| """Deinitialize this object, freeing its hardware resources""" +//| ... +//| +STATIC mp_obj_t canio_can_deinit(mp_obj_t self_in) { + canio_can_obj_t *self = MP_OBJ_TO_PTR(self_in); + common_hal_canio_can_deinit(self); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(canio_can_deinit_obj, canio_can_deinit); + +//| def __enter__(self) -> CAN: +//| """Returns self, to allow the object to be used in a `with` statement for resource control""" +//| ... +//| +STATIC mp_obj_t canio_can_enter(mp_obj_t self_in) { + canio_can_obj_t *self = MP_OBJ_TO_PTR(self_in); + common_hal_canio_can_check_for_deinit(self); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(canio_can_enter_obj, canio_can_enter); + +//| def __exit__(self, unused1, unused2, unused3) -> None: +//| """Calls deinit()""" +//| ... +STATIC mp_obj_t canio_can_exit(size_t num_args, const mp_obj_t args[]) { + canio_can_obj_t *self = MP_OBJ_TO_PTR(args[0]); + common_hal_canio_can_deinit(self); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(canio_can_exit_obj, 4, 4, canio_can_exit); + +STATIC const mp_rom_map_elem_t canio_can_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR___enter__), MP_ROM_PTR(&canio_can_enter_obj) }, + { MP_ROM_QSTR(MP_QSTR___exit__), MP_ROM_PTR(&canio_can_exit_obj) }, + { MP_ROM_QSTR(MP_QSTR_bus_off_state_count), MP_ROM_PTR(&canio_can_bus_off_state_count_obj) }, + { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&canio_can_deinit_obj) }, + { MP_ROM_QSTR(MP_QSTR_error_passive_state_count), MP_ROM_PTR(&canio_can_error_passive_state_count_obj) }, + { MP_ROM_QSTR(MP_QSTR_error_warning_state_count), MP_ROM_PTR(&canio_can_error_warning_state_count_obj) }, + { MP_ROM_QSTR(MP_QSTR_listen), MP_ROM_PTR(&canio_can_listen_obj) }, + { MP_ROM_QSTR(MP_QSTR_receive_error_count), MP_ROM_PTR(&canio_can_receive_error_count_obj) }, + { MP_ROM_QSTR(MP_QSTR_send), MP_ROM_PTR(&canio_can_send_obj) }, + { MP_ROM_QSTR(MP_QSTR_state), MP_ROM_PTR(&canio_can_state_obj) }, + { MP_ROM_QSTR(MP_QSTR_baudrate), MP_ROM_PTR(&canio_can_baudrate_obj) }, + { MP_ROM_QSTR(MP_QSTR_transmit_error_count), MP_ROM_PTR(&canio_can_transmit_error_count_obj) }, +}; +STATIC MP_DEFINE_CONST_DICT(canio_can_locals_dict, canio_can_locals_dict_table); + +const mp_obj_type_t canio_can_type = { + { &mp_type_type }, + .name = MP_QSTR_CAN, + .make_new = canio_can_make_new, + .locals_dict = (mp_obj_t)&canio_can_locals_dict, +}; diff --git a/shared-bindings/_canio/CAN.h b/shared-bindings/_canio/CAN.h new file mode 100644 index 000000000..81040cf23 --- /dev/null +++ b/shared-bindings/_canio/CAN.h @@ -0,0 +1,31 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2020 Jeff Epler for Adafruit Industries + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#pragma once + +#include "py/obj.h" + +extern const mp_obj_type_t canio_can_type; diff --git a/shared-bindings/_canio/Listener.c b/shared-bindings/_canio/Listener.c new file mode 100644 index 000000000..7f83c735f --- /dev/null +++ b/shared-bindings/_canio/Listener.c @@ -0,0 +1,197 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2020 Jeff Epler for Adafruit Industries + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "shared-bindings/_canio/Listener.h" +#include "shared-bindings/_canio/Message.h" +#include "common-hal/_canio/Listener.h" + +#include "py/runtime.h" +#include "py/objproperty.h" + +//| class Listener: +//| """Listens for CAN message +//| +//| _canio.Listener is not constructed directly, but instead by calling the +//| Listen method of a _canio.CAN object.""" +//| + +//| def read(self) -> Optional[Message]: +//| """Returns a message, after waiting up to self.timeout seconds +//| +//| If no message is received in time, None is returned. Otherwise, +//| a Message is returned.""" +//| ... +//| +STATIC mp_obj_t canio_listener_read(mp_obj_t self_in) { + canio_listener_obj_t *self = MP_OBJ_TO_PTR(self_in); + common_hal_canio_listener_check_for_deinit(self); + + canio_message_obj_t *message = m_new_obj(canio_message_obj_t); + self->base.type = &canio_message_type; + + if (common_hal_canio_listener_readinto(self, message)) { + return message; + } else { + m_free(message); // message did not escape into vm + } + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(canio_listener_read_obj, canio_listener_read); + +//| def readinto(self, message: Message) -> bool: +//| """Returns a message, after waiting up to self.timeout seconds +//| +//| Returns True (and modifies message) if a message was received, +//| False otherwise.""" +//| ... +//| +STATIC mp_obj_t canio_listener_readinto(mp_obj_t self_in, mp_obj_t message) { + canio_listener_obj_t *self = MP_OBJ_TO_PTR(self_in); + mp_obj_type_t *type = mp_obj_get_type(message); + if (type != &canio_message_type) { + mp_raise_TypeError_varg(translate("expected '%q' but got '%q'"), MP_QSTR_Message, type->name); + } + common_hal_canio_listener_check_for_deinit(self); + return mp_obj_new_bool(common_hal_canio_listener_readinto(self, message)); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(canio_listener_readinto_obj, canio_listener_readinto); + +//| def in_waiting(self) -> int: +//| """Returns the number of messages waiting""" +//| ... +//| +STATIC mp_obj_t canio_listener_in_waiting(mp_obj_t self_in) { + canio_listener_obj_t *self = MP_OBJ_TO_PTR(self_in); + common_hal_canio_listener_check_for_deinit(self); + return MP_OBJ_NEW_SMALL_INT(common_hal_canio_listener_in_waiting(self)); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(canio_listener_in_waiting_obj, canio_listener_in_waiting); + +//| def __iter__(self): +//| """Returns self, unless the object is deinitialized""" +//| ... +//| +STATIC mp_obj_t canio_listener_iter(mp_obj_t self_in) { + canio_listener_obj_t *self = MP_OBJ_TO_PTR(self_in); + common_hal_canio_listener_check_for_deinit(self); + return self; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(canio_listener_iter_obj, canio_listener_iter); + +//| def __next__(self): +//| """Returns the next waiting message, if one is available +//| +//| If the object is deinitialized, raises ValueError. +//| +//| If no message is waiting raises StopIteration""" +//| ... +//| +STATIC mp_obj_t canio_listener_next(mp_obj_t self_in) { + canio_listener_obj_t *self = MP_OBJ_TO_PTR(self_in); + common_hal_canio_listener_check_for_deinit(self); + if(common_hal_canio_listener_in_waiting(self)) { + return canio_listener_read(self_in); + } + return self; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(canio_listener_next_obj, canio_listener_next); + +//| def deinit(self) -> None: +//| """Deinitialize this object, freeing its hardware resources""" +//| ... +//| +STATIC mp_obj_t canio_listener_deinit(mp_obj_t self_in) { + canio_listener_obj_t *self = MP_OBJ_TO_PTR(self_in); + common_hal_canio_listener_deinit(self); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(canio_listener_deinit_obj, canio_listener_deinit); + +//| def __enter__(self) -> CAN: +//| """Returns self, to allow the object to be used in a `with` statement for resource control""" +//| ... +//| +STATIC mp_obj_t canio_listener_enter(mp_obj_t self_in) { + canio_listener_obj_t *self = MP_OBJ_TO_PTR(self_in); + common_hal_canio_listener_check_for_deinit(self); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(canio_listener_enter_obj, canio_listener_enter); + +//| def __exit__(self, unused1, unused2, unused3) -> None: +//| """Calls deinit()""" +//| ... +STATIC mp_obj_t canio_listener_exit(size_t num_args, const mp_obj_t args[]) { + canio_listener_obj_t *self = MP_OBJ_TO_PTR(args[0]); + common_hal_canio_listener_deinit(self); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(canio_listener_exit_obj, 4, 4, canio_listener_exit); + + +//| timeout : float +STATIC mp_obj_t canio_listener_timeout_get(mp_obj_t self_in) { + canio_listener_obj_t *self = MP_OBJ_TO_PTR(self_in); + common_hal_canio_listener_check_for_deinit(self); + return mp_obj_new_float(common_hal_canio_listener_get_timeout(self)); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(canio_listener_timeout_get_obj, canio_listener_timeout_get); + +STATIC mp_obj_t canio_listener_timeout_set(mp_obj_t self_in, mp_obj_t timeout_in) { + canio_listener_obj_t *self = MP_OBJ_TO_PTR(self_in); + common_hal_canio_listener_check_for_deinit(self); + common_hal_canio_listener_set_timeout(self, mp_obj_get_float(timeout_in)); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(canio_listener_timeout_set_obj, canio_listener_timeout_set); + +STATIC const mp_obj_property_t canio_listener_timeout_obj = { + .base.type = &mp_type_property, + .proxy = {(mp_obj_t)&canio_listener_timeout_get_obj, + (mp_obj_t)&canio_listener_timeout_set_obj, + (mp_obj_t)mp_const_none}, +}; + + + +STATIC const mp_rom_map_elem_t canio_listener_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR___enter__), MP_ROM_PTR(&canio_listener_enter_obj) }, + { MP_ROM_QSTR(MP_QSTR___exit__), MP_ROM_PTR(&canio_listener_exit_obj) }, + { MP_ROM_QSTR(MP_QSTR___iter__), MP_ROM_PTR(&canio_listener_iter_obj) }, + { MP_ROM_QSTR(MP_QSTR___next__), MP_ROM_PTR(&canio_listener_next_obj) }, + { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&canio_listener_deinit_obj) }, + { MP_ROM_QSTR(MP_QSTR_in_waiting), MP_ROM_PTR(&canio_listener_in_waiting_obj) }, + { MP_ROM_QSTR(MP_QSTR_read), MP_ROM_PTR(&canio_listener_read_obj) }, + { MP_ROM_QSTR(MP_QSTR_readinto), MP_ROM_PTR(&canio_listener_readinto_obj) }, + { MP_ROM_QSTR(MP_QSTR_timeout), MP_ROM_PTR(&canio_listener_timeout_obj) }, +}; +STATIC MP_DEFINE_CONST_DICT(canio_listener_locals_dict, canio_listener_locals_dict_table); + +const mp_obj_type_t canio_listener_type = { + { &mp_type_type }, + .name = MP_QSTR_Listener, + .locals_dict = (mp_obj_dict_t*)&canio_listener_locals_dict, +}; diff --git a/shared-bindings/_canio/Listener.h b/shared-bindings/_canio/Listener.h new file mode 100644 index 000000000..eaa3490df --- /dev/null +++ b/shared-bindings/_canio/Listener.h @@ -0,0 +1,31 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2020 Jeff Epler for Adafruit Industries + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#pragma once + +#include "py/obj.h" + +extern const mp_obj_type_t canio_listener_type; diff --git a/shared-bindings/_canio/Match.c b/shared-bindings/_canio/Match.c new file mode 100644 index 000000000..6c32aa539 --- /dev/null +++ b/shared-bindings/_canio/Match.c @@ -0,0 +1,140 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2020 Jeff Epler for Adafruit Industries + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "shared-bindings/_canio/Match.h" +#include "shared-module/_canio/Match.h" + +#include "py/objproperty.h" +#include "py/runtime.h" + +//| class Match: +//| """Describe CAN bus messages to match""" +//| +//| +//| def __init__(self, address: int, *, mask: int = 0, extended: bool = False): +//| """Construct a Match with the given properties. +//| +//| If mask is nonzero, then the filter is for any sender which matches all +//| the nonzero bits in mask. Otherwise, it matches exactly the given address. +//| If extended is true then only extended addresses are matched, otherwise +//| only standard addresses are matched.""" +//| + +STATIC mp_obj_t canio_match_make_new(const mp_obj_type_t *type, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + enum { ARG_address, ARG_mask, ARG_extended, NUM_ARGS }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_address, MP_ARG_INT | MP_ARG_REQUIRED, {.u_int = 0} }, + { MP_QSTR_mask, MP_ARG_INT, {.u_int = 0} }, + { MP_QSTR_extended, MP_ARG_BOOL, {.u_bool = false} }, + }; + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + MP_STATIC_ASSERT( MP_ARRAY_SIZE(allowed_args) == NUM_ARGS ); + + mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + int address_bits = args[ARG_extended].u_bool ? 0x1fffffff : 0x7ff; + int address = args[ARG_address].u_int; + int mask = args[ARG_mask].u_int; + + if(address & ~address_bits) { + mp_raise_ValueError_varg(translate("%q out of range"), MP_QSTR_address); + } + + if(mask & ~address_bits) { + mp_raise_ValueError_varg(translate("%q out of range"), MP_QSTR_mask); + } + + canio_match_obj_t *self = m_new_obj(canio_match_obj_t); + self->base.type = &canio_match_type; + common_hal_canio_match_construct(self, args[ARG_address].u_int, args[ARG_mask].u_int, args[ARG_extended].u_bool); + return self; +} + +//| address: int +//| """The address to match""" +//| + +STATIC mp_obj_t canio_match_address_get(mp_obj_t self_in) { + canio_match_obj_t *self = self_in; + return MP_OBJ_NEW_SMALL_INT(common_hal_canio_match_address_get(self)); +} +MP_DEFINE_CONST_FUN_OBJ_1(canio_match_address_get_obj, canio_match_address_get); + +const mp_obj_property_t canio_match_address_obj = { + .base.type = &mp_type_property, + .proxy = {(mp_obj_t)&canio_match_address_get_obj, + (mp_obj_t)&mp_const_none_obj, + (mp_obj_t)&mp_const_none_obj}, +}; + +//| +//| mask: int +//| """The optional mask of addresses to match""" +//| + +STATIC mp_obj_t canio_match_mask_get(mp_obj_t self_in) { + canio_match_obj_t *self = self_in; + return MP_OBJ_NEW_SMALL_INT(common_hal_canio_match_mask_get(self)); +} +MP_DEFINE_CONST_FUN_OBJ_1(canio_match_mask_get_obj, canio_match_mask_get); + +const mp_obj_property_t canio_match_mask_obj = { + .base.type = &mp_type_property, + .proxy = {(mp_obj_t)&canio_match_mask_get_obj, + (mp_obj_t)&mp_const_none_obj, + (mp_obj_t)&mp_const_none_obj}, +}; + +//| extended: bool +//| """True to match extended addresses, False to match standard addresses""" +//| + +STATIC mp_obj_t canio_match_extended_get(mp_obj_t self_in) { + canio_match_obj_t *self = self_in; + return mp_obj_new_bool(common_hal_canio_match_extended_get(self)); +} +MP_DEFINE_CONST_FUN_OBJ_1(canio_match_extended_get_obj, canio_match_extended_get); + +const mp_obj_property_t canio_match_extended_obj = { + .base.type = &mp_type_property, + .proxy = {(mp_obj_t)&canio_match_extended_get_obj, + (mp_obj_t)&mp_const_none_obj, + (mp_obj_t)&mp_const_none_obj}, +}; + +STATIC const mp_rom_map_elem_t canio_match_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_address), MP_ROM_PTR(&canio_match_address_obj) }, + { MP_ROM_QSTR(MP_QSTR_mask), MP_ROM_PTR(&canio_match_mask_obj) }, + { MP_ROM_QSTR(MP_QSTR_extended), MP_ROM_PTR(&canio_match_extended_obj) }, +}; +STATIC MP_DEFINE_CONST_DICT(canio_match_locals_dict, canio_match_locals_dict_table); + +const mp_obj_type_t canio_match_type = { + { &mp_type_type }, + .name = MP_QSTR_Match, + .make_new = canio_match_make_new, + .locals_dict = (mp_obj_dict_t*)&canio_match_locals_dict, +}; diff --git a/shared-bindings/_canio/Match.h b/shared-bindings/_canio/Match.h new file mode 100644 index 000000000..adf98eb86 --- /dev/null +++ b/shared-bindings/_canio/Match.h @@ -0,0 +1,33 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2020 Jeff Epler for Adafruit Industries + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#pragma once + +#include "py/obj.h" + +extern const mp_obj_type_t canio_match_type; + +// Nothing now. diff --git a/shared-bindings/_canio/Message.c b/shared-bindings/_canio/Message.c new file mode 100644 index 000000000..a8e588354 --- /dev/null +++ b/shared-bindings/_canio/Message.c @@ -0,0 +1,213 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2020 Jeff Epler for Adafruit Industries + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "shared-bindings/_canio/Message.h" +#include "shared-module/_canio/Message.h" + +#include "py/obj.h" +#include "py/objproperty.h" +#include "py/runtime.h" + +//| class Message: +//| def __init__(self, id: int=0, data: Optional[bytes] = None, *, size: Optional[int] = None, rtr: bool = False): +//| """Construct a Message to send on a CAN bus +//| +//| :param int id: The numeric ID of the message +//| :param bytes data: The content of the message +//| :param int size: The amount of data requested, for an rtr +//| :param bool rtr: True if the message represents an rtr (Remote Transmission Request) +//| +//| In CAN, messages can have a size from 0 to 8 bytes. +//| +//| For a non-rtr message, specify `data`. For an rtr-message, specify either `data` (a dummy buffer of the requested size) or `size`. +//| """ +//| ... +//| +STATIC mp_obj_t canio_message_make_new(const mp_obj_type_t *type, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + enum { ARG_id, ARG_data, ARG_size, ARG_rtr, NUM_ARGS }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_id, MP_ARG_INT, {.u_obj = 0} }, + { MP_QSTR_data, MP_ARG_OBJ, {.u_obj = 0} }, + { MP_QSTR_size, MP_ARG_INT, {.u_int = -1} }, + { MP_QSTR_rtr, MP_ARG_BOOL, {.u_bool = false} }, + }; + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + MP_STATIC_ASSERT( MP_ARRAY_SIZE(allowed_args) == NUM_ARGS ); + + mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + bool rtr = args[ARG_rtr].u_bool; + size_t size = (size_t)args[ARG_size].u_int; + bool specified_size = (size != (size_t)-1); + bool specified_data = (args[ARG_data].u_obj != NULL); + + if(specified_size && specified_data) { + mp_raise_TypeError(translate("specify size or data, but not both")); + } + + mp_buffer_info_t data; + if (specified_data) { + mp_get_buffer_raise(args[ARG_data].u_obj, &data, MP_BUFFER_READ); + } else if (specified_size) { + data.buf = 0; + data.len = size; + } else { + data.buf = 0; + data.len = 0; + } + + if(data.len > 8) { + mp_raise_ValueError(translate("Messages limited to 8 bytes")); + } + + canio_message_obj_t *self = m_new_obj(canio_message_obj_t); + self->base.type = &canio_message_type; + common_hal_canio_message_construct(self, args[ARG_id].u_int, data.buf, data.len, rtr); + return self; +} + +//| id: int +//| """The numeric ID of the message""" +//| +STATIC mp_obj_t canio_message_id_get(const mp_obj_t self_in) { + canio_message_obj_t *self = self_in; + return MP_OBJ_NEW_SMALL_INT(common_hal_canio_message_id_get(self)); +} +MP_DEFINE_CONST_FUN_OBJ_1(canio_message_id_get_obj, canio_message_id_get); + +STATIC mp_obj_t canio_message_id_set(const mp_obj_t self_in, const mp_obj_t id) { + canio_message_obj_t *self = self_in; + common_hal_canio_message_id_set(self, mp_obj_get_int(id)); + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_2(canio_message_id_set_obj, canio_message_id_set); + +STATIC const mp_obj_property_t canio_message_id_obj = { + .base.type = &mp_type_property, + .proxy = {(mp_obj_t)&canio_message_id_get_obj, + (mp_obj_t)&canio_message_id_set_obj, + (mp_obj_t)&mp_const_none_obj}, +}; + +//| data: bytes +//| """The content of the message, or dummy content in the case of an rtr. +//| +//| Assigning to data sets the bytes to zero""" +//| +STATIC mp_obj_t canio_message_data_get(const mp_obj_t self_in) { + canio_message_obj_t *self = self_in; + return mp_obj_new_bytes((const byte*)common_hal_canio_message_data_get(self), common_hal_canio_message_size_get(self)); +} +MP_DEFINE_CONST_FUN_OBJ_1(canio_message_data_get_obj, canio_message_data_get); + +STATIC mp_obj_t canio_message_data_set(const mp_obj_t self_in, const mp_obj_t data_in) { + canio_message_obj_t *self = self_in; + mp_buffer_info_t data; + mp_get_buffer_raise(data_in, &data, MP_BUFFER_READ); + if(data.len > 8) { + mp_raise_ValueError(translate("Messages limited to 8 bytes")); + } + common_hal_canio_message_data_set(self, data.buf, data.len); + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_2(canio_message_data_set_obj, canio_message_data_set); + + +STATIC const mp_obj_property_t canio_message_data_obj = { + .base.type = &mp_type_property, + .proxy = {(mp_obj_t)&canio_message_data_get_obj, + (mp_obj_t)&canio_message_data_set_obj, + (mp_obj_t)&mp_const_none_obj}, +}; + + +//| size: int +//| """The length of the message, or the length of the requested data in the case of an rtr""" +//| +STATIC mp_obj_t canio_message_size_get(const mp_obj_t self_in) { + canio_message_obj_t *self = self_in; + return MP_OBJ_NEW_SMALL_INT(common_hal_canio_message_size_get(self)); +} +MP_DEFINE_CONST_FUN_OBJ_1(canio_message_size_get_obj, canio_message_size_get); + +STATIC mp_obj_t canio_message_size_set(const mp_obj_t self_in, const mp_obj_t size_in) { + canio_message_obj_t *self = self_in; + int size = mp_obj_get_int(size_in); + if(size > 8) { + mp_raise_ValueError(translate("Messages limited to 8 bytes")); + } + common_hal_canio_message_size_set(self, size); + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_2(canio_message_size_set_obj, canio_message_size_set); + + +STATIC const mp_obj_property_t canio_message_size_obj = { + .base.type = &mp_type_property, + .proxy = {(mp_obj_t)&canio_message_size_get_obj, + (mp_obj_t)&canio_message_size_set_obj, + (mp_obj_t)&mp_const_none_obj}, +}; + +//| rtr: bool +//| """True if the message represents a remote transmission request (RTR)""" +//| +STATIC mp_obj_t canio_message_rtr_get(const mp_obj_t self_in) { + canio_message_obj_t *self = self_in; + return mp_obj_new_bool(common_hal_canio_message_rtr_get(self)); +} +MP_DEFINE_CONST_FUN_OBJ_1(canio_message_rtr_get_obj, canio_message_rtr_get); + +STATIC mp_obj_t canio_message_rtr_set(const mp_obj_t self_in, const mp_obj_t rtr) { + canio_message_obj_t *self = self_in; + common_hal_canio_message_size_set(self, mp_obj_is_true(rtr)); + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_2(canio_message_rtr_set_obj, canio_message_rtr_set); + + +STATIC const mp_obj_property_t canio_message_rtr_obj = { + .base.type = &mp_type_property, + .proxy = {(mp_obj_t)&canio_message_rtr_get_obj, + (mp_obj_t)&canio_message_rtr_set_obj, + (mp_obj_t)&mp_const_none_obj}, +}; + + +STATIC const mp_rom_map_elem_t canio_message_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_id), MP_ROM_PTR(&canio_message_id_obj) }, + { MP_ROM_QSTR(MP_QSTR_data), MP_ROM_PTR(&canio_message_data_obj) }, + { MP_ROM_QSTR(MP_QSTR_size), MP_ROM_PTR(&canio_message_size_obj) }, + { MP_ROM_QSTR(MP_QSTR_rtr), MP_ROM_PTR(&canio_message_rtr_obj) }, +}; +STATIC MP_DEFINE_CONST_DICT(canio_message_locals_dict, canio_message_locals_dict_table); + +const mp_obj_type_t canio_message_type = { + { &mp_type_type }, + .name = MP_QSTR_Message, + .make_new = canio_message_make_new, + .locals_dict = (mp_obj_t)&canio_message_locals_dict, +}; diff --git a/shared-bindings/_canio/Message.h b/shared-bindings/_canio/Message.h new file mode 100644 index 000000000..32d6801bc --- /dev/null +++ b/shared-bindings/_canio/Message.h @@ -0,0 +1,31 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2020 Jeff Epler for Adafruit Industries + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#pragma once + +#include "py/obj.h" + +extern const mp_obj_type_t canio_message_type; diff --git a/shared-bindings/_canio/__init__.c b/shared-bindings/_canio/__init__.c new file mode 100644 index 000000000..4da008ff2 --- /dev/null +++ b/shared-bindings/_canio/__init__.c @@ -0,0 +1,73 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2020 Jeff Epler for Adafruit Industries + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +//| """CAN bus access +//| +//| The `_canio` module contains low level classes to support the CAN bus +//| protocol. +//| +//| All classes change hardware state and should be deinitialized when they +//| are no longer needed if the program continues after use. To do so, either +//| call :py:meth:`!deinit` or use a context manager. See +//| :ref:`lifetime-and-contextmanagers` for more info. +//| +//| For example:: +//| +//| import _canio +//| from board import * +//| +//| can = _canio.BUS(board.CANRX, board.CANTX) +//| can.write(408, b"adafruit") +//| can.deinit() +//| +//| This example will write the data 'adafruit' onto the CAN bus to any +//| device listening for message id 408.""" +//| + +#include "py/obj.h" + +#include "shared-bindings/_canio/__init__.h" +#include "shared-bindings/_canio/CAN.h" +#include "shared-bindings/_canio/Match.h" +#include "shared-bindings/_canio/Message.h" + +STATIC const mp_rom_map_elem_t canio_module_globals_table[] = { + { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR__canio) }, + { MP_ROM_QSTR(MP_QSTR_CAN), MP_ROM_PTR(&canio_can_type) }, + { MP_ROM_QSTR(MP_QSTR_Match), MP_ROM_PTR(&canio_match_type) }, + { MP_ROM_QSTR(MP_QSTR_Message), MP_ROM_PTR(&canio_message_type) }, +#if 0 + { MP_ROM_QSTR(MP_QSTR_Listener), MP_ROM_PTR(&canio_listener_type) }, +#endif +}; + + +STATIC MP_DEFINE_CONST_DICT(canio_module_globals, canio_module_globals_table); + +const mp_obj_module_t canio_module = { + .base = { &mp_type_module }, + .globals = (mp_obj_dict_t*)&canio_module_globals, +}; diff --git a/shared-bindings/_canio/__init__.h b/shared-bindings/_canio/__init__.h new file mode 100644 index 000000000..45e76369c --- /dev/null +++ b/shared-bindings/_canio/__init__.h @@ -0,0 +1,29 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2020 Jeff Epler for Adafruit Industries + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#pragma once + +// Nothing now. diff --git a/shared-module/_canio/Match.c b/shared-module/_canio/Match.c new file mode 100644 index 000000000..2b696addb --- /dev/null +++ b/shared-module/_canio/Match.c @@ -0,0 +1,43 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2020 Jeff Epler for Adafruit Industries + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "shared-module/_canio/Match.h" + +void common_hal_canio_match_construct(canio_match_obj_t *self, int address, int mask, bool extended) { + self->address = address; + self->mask = mask; + self->extended = extended; +} + +int common_hal_canio_match_address_get(const canio_match_obj_t *self) { + return self->address; +} +int common_hal_canio_match_mask_get(const canio_match_obj_t *self) { + return self->mask; +} +bool common_hal_canio_match_extended_get(const canio_match_obj_t *self) { + return self->extended; +} diff --git a/shared-module/_canio/Match.h b/shared-module/_canio/Match.h new file mode 100644 index 000000000..099df976d --- /dev/null +++ b/shared-module/_canio/Match.h @@ -0,0 +1,41 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2020 Jeff Epler for Adafruit Industries + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#pragma once + +#include "py/obj.h" + +typedef struct { + mp_obj_base_t base; + int address; + int mask; + bool extended; +} canio_match_obj_t; + +void common_hal_canio_match_construct(canio_match_obj_t *self, int address, int mask, bool extended); +int common_hal_canio_match_address_get(const canio_match_obj_t *self); +int common_hal_canio_match_mask_get(const canio_match_obj_t *self); +bool common_hal_canio_match_extended_get(const canio_match_obj_t *self); diff --git a/shared-module/_canio/Message.c b/shared-module/_canio/Message.c new file mode 100644 index 000000000..df6a40a0a --- /dev/null +++ b/shared-module/_canio/Message.c @@ -0,0 +1,85 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2020 Jeff Epler for Adafruit Industries + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "shared-module/_canio/Message.h" + +#include + +void common_hal_canio_message_construct(canio_message_obj_t *self, int id, void *data, size_t size, bool rtr) +{ + self->id = id; + self->size = size; + self->rtr = rtr; + if (data) { + memcpy(self->data, data, size); + } else { + memset(self->data, 0, size); + } +} + +int common_hal_canio_message_id_get(const canio_message_obj_t *self) +{ + return self->id; +} + +void common_hal_canio_message_id_set(canio_message_obj_t *self, int id) +{ + self->id = id; +} + + +const void *common_hal_canio_message_data_get(const canio_message_obj_t *self) +{ + return self->data; +} + +const void common_hal_canio_message_data_set(canio_message_obj_t *self, const void *data, size_t size) +{ + memcpy(self->data, data, size); +} + + +size_t common_hal_canio_message_size_get(const canio_message_obj_t *self) +{ + return self->size; +} + +void common_hal_canio_message_size_set(canio_message_obj_t *self, size_t size) +{ + memset(self->data, 0, size); + self->size = size; +} + + +bool common_hal_canio_message_rtr_get(const canio_message_obj_t *self) +{ + return self->rtr; +} + +void common_hal_canio_message_rtr_set(canio_message_obj_t *self, bool rtr) +{ + self->rtr = rtr; +} diff --git a/shared-module/_canio/Message.h b/shared-module/_canio/Message.h new file mode 100644 index 000000000..e846f1095 --- /dev/null +++ b/shared-module/_canio/Message.h @@ -0,0 +1,47 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2020 Jeff Epler for Adafruit Industries + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#pragma once + +#include "py/obj.h" + +typedef struct { + mp_obj_base_t base; + int id; + size_t size; + uint8_t data[8]; + bool rtr; +} canio_message_obj_t; + +void common_hal_canio_message_construct(canio_message_obj_t *self, int id, void *data, size_t size, bool rtr); +bool common_hal_canio_message_rtr_get(const canio_message_obj_t *self); +int common_hal_canio_message_id_get(const canio_message_obj_t *self); +const void *common_hal_canio_message_data_get(const canio_message_obj_t *self); +size_t common_hal_canio_message_size_get(const canio_message_obj_t *self); +void common_hal_canio_message_rtr_set(canio_message_obj_t *self, bool rtr); +void common_hal_canio_message_id_set(canio_message_obj_t *self, int id); +void common_hal_canio_message_data_set(canio_message_obj_t *self, const void *data, size_t size); +void common_hal_canio_message_size_set(canio_message_obj_t *self, size_t size); -- cgit v1.2.3 From 65ca1c7bbc84cd88d3aae69d89d2ff2c287ef884 Mon Sep 17 00:00:00 2001 From: Jeff Epler Date: Wed, 16 Sep 2020 11:57:24 -0500 Subject: _canio: Message: Setting data should set the size to match --- shared-module/_canio/Message.c | 1 + 1 file changed, 1 insertion(+) (limited to 'shared-module') diff --git a/shared-module/_canio/Message.c b/shared-module/_canio/Message.c index df6a40a0a..1ac5b8178 100644 --- a/shared-module/_canio/Message.c +++ b/shared-module/_canio/Message.c @@ -58,6 +58,7 @@ const void *common_hal_canio_message_data_get(const canio_message_obj_t *self) const void common_hal_canio_message_data_set(canio_message_obj_t *self, const void *data, size_t size) { + self->size = size; memcpy(self->data, data, size); } -- cgit v1.2.3 From 2cb4707f92ffc65b2f160a7d1ea7d6b28892b548 Mon Sep 17 00:00:00 2001 From: Jeff Epler Date: Thu, 17 Sep 2020 10:57:16 -0500 Subject: Message: add extended address flag --- shared-bindings/_canio/Message.c | 35 ++++++++++++++++++++++++++++++++--- shared-module/_canio/Message.c | 13 ++++++++++++- shared-module/_canio/Message.h | 9 ++++++--- 3 files changed, 50 insertions(+), 7 deletions(-) (limited to 'shared-module') diff --git a/shared-bindings/_canio/Message.c b/shared-bindings/_canio/Message.c index f1cd11d8e..3fa018a83 100644 --- a/shared-bindings/_canio/Message.c +++ b/shared-bindings/_canio/Message.c @@ -32,13 +32,14 @@ #include "py/runtime.h" //| class Message: -//| def __init__(self, id: int=0, data: Optional[bytes] = None, *, size: Optional[int] = None, rtr: bool = False): +//| def __init__(self, id: int=0, data: Optional[bytes] = None, *, size: Optional[int] = None, rtr: bool = False, extended: bool = False): //| """Construct a Message to send on a CAN bus //| //| :param int id: The numeric ID of the message //| :param bytes data: The content of the message //| :param int size: The amount of data requested, for an rtr //| :param bool rtr: True if the message represents an rtr (Remote Transmission Request) +//| :param bool extended: True if the message has an extended identifier, False if it has a standard identifier //| //| In CAN, messages can have a size from 0 to 8 bytes. //| @@ -47,12 +48,13 @@ //| ... //| STATIC mp_obj_t canio_message_make_new(const mp_obj_type_t *type, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { - enum { ARG_id, ARG_data, ARG_size, ARG_rtr, NUM_ARGS }; + enum { ARG_id, ARG_data, ARG_size, ARG_rtr, ARG_extended, NUM_ARGS }; static const mp_arg_t allowed_args[] = { { MP_QSTR_id, MP_ARG_INT, {.u_obj = 0} }, { MP_QSTR_data, MP_ARG_OBJ, {.u_obj = 0} }, { MP_QSTR_size, MP_ARG_INT, {.u_int = -1} }, { MP_QSTR_rtr, MP_ARG_BOOL, {.u_bool = false} }, + { MP_QSTR_extended, MP_ARG_BOOL, {.u_bool = false} }, }; mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; MP_STATIC_ASSERT( MP_ARRAY_SIZE(allowed_args) == NUM_ARGS ); @@ -60,6 +62,7 @@ STATIC mp_obj_t canio_message_make_new(const mp_obj_type_t *type, size_t n_args, mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); bool rtr = args[ARG_rtr].u_bool; + bool extended = args[ARG_extended].u_bool; size_t size = (size_t)args[ARG_size].u_int; bool specified_size = (size != (size_t)-1); bool specified_data = (args[ARG_data].u_obj != NULL); @@ -85,7 +88,7 @@ STATIC mp_obj_t canio_message_make_new(const mp_obj_type_t *type, size_t n_args, canio_message_obj_t *self = m_new_obj(canio_message_obj_t); self->base.type = &canio_message_type; - common_hal_canio_message_construct(self, args[ARG_id].u_int, data.buf, data.len, rtr); + common_hal_canio_message_construct(self, args[ARG_id].u_int, data.buf, data.len, rtr, extended); return self; } @@ -174,6 +177,31 @@ STATIC const mp_obj_property_t canio_message_size_obj = { (mp_obj_t)&mp_const_none_obj}, }; +//| extended: bool +//| """True if the message represents a remote transmission request (RTR)""" +//| +STATIC mp_obj_t canio_message_extended_get(const mp_obj_t self_in) { + canio_message_obj_t *self = self_in; + return mp_obj_new_bool(common_hal_canio_message_extended_get(self)); +} +MP_DEFINE_CONST_FUN_OBJ_1(canio_message_extended_get_obj, canio_message_extended_get); + +STATIC mp_obj_t canio_message_extended_set(const mp_obj_t self_in, const mp_obj_t extended) { + canio_message_obj_t *self = self_in; + common_hal_canio_message_size_set(self, mp_obj_is_true(extended)); + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_2(canio_message_extended_set_obj, canio_message_extended_set); + + +STATIC const mp_obj_property_t canio_message_extended_obj = { + .base.type = &mp_type_property, + .proxy = {(mp_obj_t)&canio_message_extended_get_obj, + (mp_obj_t)&canio_message_extended_set_obj, + (mp_obj_t)&mp_const_none_obj}, +}; + + //| rtr: bool //| """True if the message represents a remote transmission request (RTR)""" //| @@ -204,6 +232,7 @@ STATIC const mp_rom_map_elem_t canio_message_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_data), MP_ROM_PTR(&canio_message_data_obj) }, { MP_ROM_QSTR(MP_QSTR_size), MP_ROM_PTR(&canio_message_size_obj) }, { MP_ROM_QSTR(MP_QSTR_rtr), MP_ROM_PTR(&canio_message_rtr_obj) }, + { MP_ROM_QSTR(MP_QSTR_extended), MP_ROM_PTR(&canio_message_extended_obj) }, }; STATIC MP_DEFINE_CONST_DICT(canio_message_locals_dict, canio_message_locals_dict_table); diff --git a/shared-module/_canio/Message.c b/shared-module/_canio/Message.c index 1ac5b8178..c0403b519 100644 --- a/shared-module/_canio/Message.c +++ b/shared-module/_canio/Message.c @@ -28,11 +28,12 @@ #include -void common_hal_canio_message_construct(canio_message_obj_t *self, int id, void *data, size_t size, bool rtr) +void common_hal_canio_message_construct(canio_message_obj_t *self, int id, void *data, size_t size, bool rtr, bool extended) { self->id = id; self->size = size; self->rtr = rtr; + self->extended = extended; if (data) { memcpy(self->data, data, size); } else { @@ -84,3 +85,13 @@ void common_hal_canio_message_rtr_set(canio_message_obj_t *self, bool rtr) { self->rtr = rtr; } + +bool common_hal_canio_message_extended_get(const canio_message_obj_t *self) +{ + return self->extended; +} + +void common_hal_canio_message_extended_set(canio_message_obj_t *self, bool extended) +{ + self->extended = extended; +} diff --git a/shared-module/_canio/Message.h b/shared-module/_canio/Message.h index e846f1095..b9fd8eaf2 100644 --- a/shared-module/_canio/Message.h +++ b/shared-module/_canio/Message.h @@ -31,17 +31,20 @@ typedef struct { mp_obj_base_t base; int id; - size_t size; uint8_t data[8]; - bool rtr; + size_t size:4; + bool rtr:1; + bool extended:1; } canio_message_obj_t; -void common_hal_canio_message_construct(canio_message_obj_t *self, int id, void *data, size_t size, bool rtr); +void common_hal_canio_message_construct(canio_message_obj_t *self, int id, void *data, size_t size, bool rtr, bool extended); bool common_hal_canio_message_rtr_get(const canio_message_obj_t *self); +bool common_hal_canio_message_extended_get(const canio_message_obj_t *self); int common_hal_canio_message_id_get(const canio_message_obj_t *self); const void *common_hal_canio_message_data_get(const canio_message_obj_t *self); size_t common_hal_canio_message_size_get(const canio_message_obj_t *self); void common_hal_canio_message_rtr_set(canio_message_obj_t *self, bool rtr); +void common_hal_canio_message_extended_set(canio_message_obj_t *self, bool extended); void common_hal_canio_message_id_set(canio_message_obj_t *self, int id); void common_hal_canio_message_data_set(canio_message_obj_t *self, const void *data, size_t size); void common_hal_canio_message_size_set(canio_message_obj_t *self, size_t size); -- cgit v1.2.3 From 44c5b2bbb1a00cf07e1725c76d1920e8c73977ed Mon Sep 17 00:00:00 2001 From: Jeff Epler Date: Thu, 17 Sep 2020 12:44:40 -0500 Subject: Respond to review comments Thanks @tannewt! --- ports/atmel-samd/common-hal/_canio/Listener.c | 1 - shared-bindings/_canio/CAN.c | 17 +++-------------- shared-bindings/_canio/Listener.c | 10 ++++------ shared-bindings/_canio/Match.c | 9 ++++----- shared-bindings/_canio/Match.h | 6 +++++- shared-bindings/_canio/Message.c | 23 +++++++++++------------ shared-bindings/_canio/Message.h | 13 +++++++++++++ shared-module/_canio/Match.c | 6 +++--- shared-module/_canio/Match.h | 5 ----- shared-module/_canio/Message.c | 20 ++++++++++---------- shared-module/_canio/Message.h | 12 ------------ 11 files changed, 53 insertions(+), 69 deletions(-) (limited to 'shared-module') diff --git a/ports/atmel-samd/common-hal/_canio/Listener.c b/ports/atmel-samd/common-hal/_canio/Listener.c index 4d54e9f73..0a5f629f8 100644 --- a/ports/atmel-samd/common-hal/_canio/Listener.c +++ b/ports/atmel-samd/common-hal/_canio/Listener.c @@ -375,7 +375,6 @@ bool common_hal_canio_listener_readinto(canio_listener_obj_t *self, canio_messag } void common_hal_canio_listener_deinit(canio_listener_obj_t *self) { - // free our FIFO, clear our matches, SOMETHING if (self->can) { clear_filters(self); if (self->fifo_idx == 0) { diff --git a/shared-bindings/_canio/CAN.c b/shared-bindings/_canio/CAN.c index 53045c35a..537aa5580 100644 --- a/shared-bindings/_canio/CAN.c +++ b/shared-bindings/_canio/CAN.c @@ -53,8 +53,8 @@ //| connected to a transceiver which controls the H and L pins on a shared //| bus. //| -//| :param ~microcontrller.Pin rx: the pin to receive with. -//| :param ~microcontrller.Pin tx: the pin to transmit with, or None if the peripheral should operate in "silent" mode. +//| :param ~microcontroller.Pin rx: the pin to receive with. +//| :param ~microcontroller.Pin tx: the pin to transmit with, or None if the peripheral should operate in "silent" mode. //| :param int baudrate: The bit rate of the bus in Hz. All devices on the bus must agree on this value. //| :param bool loopback: True if the peripheral will be operated in loopback mode. //| :param bool auto_restart: If True, will restart communications after entering bus-off state @@ -76,13 +76,8 @@ STATIC mp_obj_t canio_can_make_new(const mp_obj_type_t *type, size_t n_args, con mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); -mp_printf(&mp_plat_print, "ARG_rx=%d args[ARG_rx].u_obj=%p\n", ARG_rx, args[ARG_rx].u_obj); -mp_printf(&mp_plat_print, "ARG_tx=%d args[ARG_tx].u_obj=%p\n", ARG_tx, args[ARG_tx].u_obj); - mcu_pin_obj_t *rx_pin = validate_obj_is_free_pin(args[ARG_rx].u_obj); -mp_printf(&mp_plat_print, "rx_pin=%p\n", rx_pin); mcu_pin_obj_t *tx_pin = validate_obj_is_free_pin_or_none(args[ARG_tx].u_obj); -mp_printf(&mp_plat_print, "tx_pin=%p\n", tx_pin); canio_can_obj_t *self = m_new_obj(canio_can_obj_t); self->base.type = &canio_can_type; @@ -94,7 +89,7 @@ mp_printf(&mp_plat_print, "tx_pin=%p\n", tx_pin); } -//| auto_restart: int +//| auto_restart: bool //| """If True, will restart communications after entering bus-off state""" //| STATIC mp_obj_t canio_can_auto_restart_get(mp_obj_t self_in) { @@ -240,12 +235,6 @@ STATIC const mp_obj_property_t canio_can_state_obj = { }; -#if 0 -//| # pending_tx_count: int -//| # """The number of messages waiting to be transmitted. (read-only)""" -//| -#endif - //| def restart(self) -> None: //| """If the device is in the bus off state, restart it.""" //| ... diff --git a/shared-bindings/_canio/Listener.c b/shared-bindings/_canio/Listener.c index a3890f8dd..84b2aacb9 100644 --- a/shared-bindings/_canio/Listener.c +++ b/shared-bindings/_canio/Listener.c @@ -39,7 +39,7 @@ //| //| def read(self) -> Optional[Message]: -//| """Returns a message, after waiting up to self.timeout seconds +//| """Reads a message, after waiting up to self.timeout seconds //| //| If no message is received in time, None is returned. Otherwise, //| a Message is returned.""" @@ -62,10 +62,8 @@ STATIC mp_obj_t canio_listener_read(mp_obj_t self_in) { STATIC MP_DEFINE_CONST_FUN_OBJ_1(canio_listener_read_obj, canio_listener_read); //| def readinto(self, message: Message) -> bool: -//| """Returns a message, after waiting up to self.timeout seconds -//| -//| Returns True (and modifies message) if a message was received, -//| False otherwise.""" +//| """Returns True (and modifies message) if a message was received +//| before ``timeout`` seconds elapsed, False otherwise.""" //| ... //| STATIC mp_obj_t canio_listener_readinto(mp_obj_t self_in, mp_obj_t message) { @@ -115,7 +113,7 @@ STATIC mp_obj_t canio_listener_next(mp_obj_t self_in) { if (common_hal_canio_listener_in_waiting(self)) { return canio_listener_read(self_in); } - return self; + return MP_OBJ_STOP_ITERATION; } STATIC MP_DEFINE_CONST_FUN_OBJ_1(canio_listener_next_obj, canio_listener_next); diff --git a/shared-bindings/_canio/Match.c b/shared-bindings/_canio/Match.c index b71529b73..4ff35906b 100644 --- a/shared-bindings/_canio/Match.c +++ b/shared-bindings/_canio/Match.c @@ -25,7 +25,6 @@ */ #include "shared-bindings/_canio/Match.h" -#include "shared-module/_canio/Match.h" #include "py/objproperty.h" #include "py/runtime.h" @@ -46,7 +45,7 @@ STATIC mp_obj_t canio_match_make_new(const mp_obj_type_t *type, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { enum { ARG_address, ARG_mask, ARG_extended, NUM_ARGS }; static const mp_arg_t allowed_args[] = { - { MP_QSTR_address, MP_ARG_INT | MP_ARG_REQUIRED, {.u_int = 0} }, + { MP_QSTR_address, MP_ARG_INT | MP_ARG_REQUIRED }, { MP_QSTR_mask, MP_ARG_INT, {.u_int = 0} }, { MP_QSTR_extended, MP_ARG_BOOL, {.u_bool = false} }, }; @@ -79,7 +78,7 @@ STATIC mp_obj_t canio_match_make_new(const mp_obj_type_t *type, size_t n_args, c STATIC mp_obj_t canio_match_address_get(mp_obj_t self_in) { canio_match_obj_t *self = self_in; - return MP_OBJ_NEW_SMALL_INT(common_hal_canio_match_address_get(self)); + return MP_OBJ_NEW_SMALL_INT(common_hal_canio_match_get_address(self)); } MP_DEFINE_CONST_FUN_OBJ_1(canio_match_address_get_obj, canio_match_address_get); @@ -97,7 +96,7 @@ const mp_obj_property_t canio_match_address_obj = { STATIC mp_obj_t canio_match_mask_get(mp_obj_t self_in) { canio_match_obj_t *self = self_in; - return MP_OBJ_NEW_SMALL_INT(common_hal_canio_match_mask_get(self)); + return MP_OBJ_NEW_SMALL_INT(common_hal_canio_match_get_mask(self)); } MP_DEFINE_CONST_FUN_OBJ_1(canio_match_mask_get_obj, canio_match_mask_get); @@ -114,7 +113,7 @@ const mp_obj_property_t canio_match_mask_obj = { STATIC mp_obj_t canio_match_extended_get(mp_obj_t self_in) { canio_match_obj_t *self = self_in; - return mp_obj_new_bool(common_hal_canio_match_extended_get(self)); + return mp_obj_new_bool(common_hal_canio_match_get_extended(self)); } MP_DEFINE_CONST_FUN_OBJ_1(canio_match_extended_get_obj, canio_match_extended_get); diff --git a/shared-bindings/_canio/Match.h b/shared-bindings/_canio/Match.h index adf98eb86..5522c2636 100644 --- a/shared-bindings/_canio/Match.h +++ b/shared-bindings/_canio/Match.h @@ -27,7 +27,11 @@ #pragma once #include "py/obj.h" +#include "shared-module/_canio/Match.h" extern const mp_obj_type_t canio_match_type; -// Nothing now. +void common_hal_canio_match_construct(canio_match_obj_t *self, int address, int mask, bool extended); +int common_hal_canio_match_get_address(const canio_match_obj_t *self); +int common_hal_canio_match_get_mask(const canio_match_obj_t *self); +bool common_hal_canio_match_get_extended(const canio_match_obj_t *self); diff --git a/shared-bindings/_canio/Message.c b/shared-bindings/_canio/Message.c index bfaaf52b2..85657e05e 100644 --- a/shared-bindings/_canio/Message.c +++ b/shared-bindings/_canio/Message.c @@ -25,7 +25,6 @@ */ #include "shared-bindings/_canio/Message.h" -#include "shared-module/_canio/Message.h" #include "py/obj.h" #include "py/objproperty.h" @@ -33,7 +32,7 @@ //| class Message: //| def __init__(self, id: int=0, data: Optional[bytes] = None, *, size: Optional[int] = None, rtr: bool = False, extended: bool = False): -//| """Construct a Message to send on a CAN bus +//| """Construct a Message to use with a CAN bus. Provide arguments to create a message to send. Otherwise, use Listener.readinto() to read a message. //| //| :param int id: The numeric ID of the message //| :param bytes data: The content of the message @@ -97,13 +96,13 @@ STATIC mp_obj_t canio_message_make_new(const mp_obj_type_t *type, size_t n_args, //| STATIC mp_obj_t canio_message_id_get(const mp_obj_t self_in) { canio_message_obj_t *self = self_in; - return MP_OBJ_NEW_SMALL_INT(common_hal_canio_message_id_get(self)); + return MP_OBJ_NEW_SMALL_INT(common_hal_canio_message_get_id(self)); } MP_DEFINE_CONST_FUN_OBJ_1(canio_message_id_get_obj, canio_message_id_get); STATIC mp_obj_t canio_message_id_set(const mp_obj_t self_in, const mp_obj_t id) { canio_message_obj_t *self = self_in; - common_hal_canio_message_id_set(self, mp_obj_get_int(id)); + common_hal_canio_message_set_id(self, mp_obj_get_int(id)); return mp_const_none; } MP_DEFINE_CONST_FUN_OBJ_2(canio_message_id_set_obj, canio_message_id_set); @@ -122,7 +121,7 @@ STATIC const mp_obj_property_t canio_message_id_obj = { //| STATIC mp_obj_t canio_message_data_get(const mp_obj_t self_in) { canio_message_obj_t *self = self_in; - return mp_obj_new_bytes((const byte*)common_hal_canio_message_data_get(self), common_hal_canio_message_size_get(self)); + return mp_obj_new_bytes((const byte*)common_hal_canio_message_get_data(self), common_hal_canio_message_get_size(self)); } MP_DEFINE_CONST_FUN_OBJ_1(canio_message_data_get_obj, canio_message_data_get); @@ -133,7 +132,7 @@ STATIC mp_obj_t canio_message_data_set(const mp_obj_t self_in, const mp_obj_t da if (data.len > 8) { mp_raise_ValueError(translate("Messages limited to 8 bytes")); } - common_hal_canio_message_data_set(self, data.buf, data.len); + common_hal_canio_message_set_data(self, data.buf, data.len); return mp_const_none; } MP_DEFINE_CONST_FUN_OBJ_2(canio_message_data_set_obj, canio_message_data_set); @@ -154,7 +153,7 @@ STATIC const mp_obj_property_t canio_message_data_obj = { //| STATIC mp_obj_t canio_message_size_get(const mp_obj_t self_in) { canio_message_obj_t *self = self_in; - return MP_OBJ_NEW_SMALL_INT(common_hal_canio_message_size_get(self)); + return MP_OBJ_NEW_SMALL_INT(common_hal_canio_message_get_size(self)); } MP_DEFINE_CONST_FUN_OBJ_1(canio_message_size_get_obj, canio_message_size_get); @@ -164,7 +163,7 @@ STATIC mp_obj_t canio_message_size_set(const mp_obj_t self_in, const mp_obj_t si if (size > 8) { mp_raise_ValueError(translate("Messages limited to 8 bytes")); } - common_hal_canio_message_size_set(self, size); + common_hal_canio_message_set_size(self, size); return mp_const_none; } MP_DEFINE_CONST_FUN_OBJ_2(canio_message_size_set_obj, canio_message_size_set); @@ -182,13 +181,13 @@ STATIC const mp_obj_property_t canio_message_size_obj = { //| STATIC mp_obj_t canio_message_extended_get(const mp_obj_t self_in) { canio_message_obj_t *self = self_in; - return mp_obj_new_bool(common_hal_canio_message_extended_get(self)); + return mp_obj_new_bool(common_hal_canio_message_get_extended(self)); } MP_DEFINE_CONST_FUN_OBJ_1(canio_message_extended_get_obj, canio_message_extended_get); STATIC mp_obj_t canio_message_extended_set(const mp_obj_t self_in, const mp_obj_t extended) { canio_message_obj_t *self = self_in; - common_hal_canio_message_size_set(self, mp_obj_is_true(extended)); + common_hal_canio_message_set_extended(self, mp_obj_is_true(extended)); return mp_const_none; } MP_DEFINE_CONST_FUN_OBJ_2(canio_message_extended_set_obj, canio_message_extended_set); @@ -207,13 +206,13 @@ STATIC const mp_obj_property_t canio_message_extended_obj = { //| STATIC mp_obj_t canio_message_rtr_get(const mp_obj_t self_in) { canio_message_obj_t *self = self_in; - return mp_obj_new_bool(common_hal_canio_message_rtr_get(self)); + return mp_obj_new_bool(common_hal_canio_message_get_rtr(self)); } MP_DEFINE_CONST_FUN_OBJ_1(canio_message_rtr_get_obj, canio_message_rtr_get); STATIC mp_obj_t canio_message_rtr_set(const mp_obj_t self_in, const mp_obj_t rtr) { canio_message_obj_t *self = self_in; - common_hal_canio_message_size_set(self, mp_obj_is_true(rtr)); + common_hal_canio_message_set_rtr(self, mp_obj_is_true(rtr)); return mp_const_none; } MP_DEFINE_CONST_FUN_OBJ_2(canio_message_rtr_set_obj, canio_message_rtr_set); diff --git a/shared-bindings/_canio/Message.h b/shared-bindings/_canio/Message.h index 32d6801bc..ed739af0d 100644 --- a/shared-bindings/_canio/Message.h +++ b/shared-bindings/_canio/Message.h @@ -27,5 +27,18 @@ #pragma once #include "py/obj.h" +#include "shared-module/_canio/Message.h" extern const mp_obj_type_t canio_message_type; + +void common_hal_canio_message_construct(canio_message_obj_t *self, int id, void *data, size_t size, bool rtr, bool extended); +const void *common_hal_canio_message_get_data(const canio_message_obj_t *self); +void common_hal_canio_message_set_data(canio_message_obj_t *self, const void *data, size_t size); +bool common_hal_canio_message_get_extended(const canio_message_obj_t *self); +void common_hal_canio_message_set_extended(canio_message_obj_t *self, bool extended); +int common_hal_canio_message_get_id(const canio_message_obj_t *self); +void common_hal_canio_message_set_id(canio_message_obj_t *self, int id); +bool common_hal_canio_message_get_rtr(const canio_message_obj_t *self); +void common_hal_canio_message_set_rtr(canio_message_obj_t *self, bool rtr); +size_t common_hal_canio_message_get_size(const canio_message_obj_t *self); +void common_hal_canio_message_set_size(canio_message_obj_t *self, size_t size); diff --git a/shared-module/_canio/Match.c b/shared-module/_canio/Match.c index 2b696addb..3dcde18a7 100644 --- a/shared-module/_canio/Match.c +++ b/shared-module/_canio/Match.c @@ -32,12 +32,12 @@ void common_hal_canio_match_construct(canio_match_obj_t *self, int address, int self->extended = extended; } -int common_hal_canio_match_address_get(const canio_match_obj_t *self) { +int common_hal_canio_match_get_address(const canio_match_obj_t *self) { return self->address; } -int common_hal_canio_match_mask_get(const canio_match_obj_t *self) { +int common_hal_canio_match_get_mask(const canio_match_obj_t *self) { return self->mask; } -bool common_hal_canio_match_extended_get(const canio_match_obj_t *self) { +bool common_hal_canio_match_get_extended(const canio_match_obj_t *self) { return self->extended; } diff --git a/shared-module/_canio/Match.h b/shared-module/_canio/Match.h index 099df976d..25f047f37 100644 --- a/shared-module/_canio/Match.h +++ b/shared-module/_canio/Match.h @@ -34,8 +34,3 @@ typedef struct { int mask; bool extended; } canio_match_obj_t; - -void common_hal_canio_match_construct(canio_match_obj_t *self, int address, int mask, bool extended); -int common_hal_canio_match_address_get(const canio_match_obj_t *self); -int common_hal_canio_match_mask_get(const canio_match_obj_t *self); -bool common_hal_canio_match_extended_get(const canio_match_obj_t *self); diff --git a/shared-module/_canio/Message.c b/shared-module/_canio/Message.c index c0403b519..0caca58f0 100644 --- a/shared-module/_canio/Message.c +++ b/shared-module/_canio/Message.c @@ -41,57 +41,57 @@ void common_hal_canio_message_construct(canio_message_obj_t *self, int id, void } } -int common_hal_canio_message_id_get(const canio_message_obj_t *self) +int common_hal_canio_message_get_id(const canio_message_obj_t *self) { return self->id; } -void common_hal_canio_message_id_set(canio_message_obj_t *self, int id) +void common_hal_canio_message_set_id(canio_message_obj_t *self, int id) { self->id = id; } -const void *common_hal_canio_message_data_get(const canio_message_obj_t *self) +const void *common_hal_canio_message_get_data(const canio_message_obj_t *self) { return self->data; } -const void common_hal_canio_message_data_set(canio_message_obj_t *self, const void *data, size_t size) +const void common_hal_canio_message_set_data(canio_message_obj_t *self, const void *data, size_t size) { self->size = size; memcpy(self->data, data, size); } -size_t common_hal_canio_message_size_get(const canio_message_obj_t *self) +size_t common_hal_canio_message_get_size(const canio_message_obj_t *self) { return self->size; } -void common_hal_canio_message_size_set(canio_message_obj_t *self, size_t size) +void common_hal_canio_message_set_size(canio_message_obj_t *self, size_t size) { memset(self->data, 0, size); self->size = size; } -bool common_hal_canio_message_rtr_get(const canio_message_obj_t *self) +bool common_hal_canio_message_get_rtr(const canio_message_obj_t *self) { return self->rtr; } -void common_hal_canio_message_rtr_set(canio_message_obj_t *self, bool rtr) +void common_hal_canio_message_set_rtr(canio_message_obj_t *self, bool rtr) { self->rtr = rtr; } -bool common_hal_canio_message_extended_get(const canio_message_obj_t *self) +bool common_hal_canio_message_get_extended(const canio_message_obj_t *self) { return self->extended; } -void common_hal_canio_message_extended_set(canio_message_obj_t *self, bool extended) +void common_hal_canio_message_set_extended(canio_message_obj_t *self, bool extended) { self->extended = extended; } diff --git a/shared-module/_canio/Message.h b/shared-module/_canio/Message.h index b9fd8eaf2..b99c5c48e 100644 --- a/shared-module/_canio/Message.h +++ b/shared-module/_canio/Message.h @@ -36,15 +36,3 @@ typedef struct { bool rtr:1; bool extended:1; } canio_message_obj_t; - -void common_hal_canio_message_construct(canio_message_obj_t *self, int id, void *data, size_t size, bool rtr, bool extended); -bool common_hal_canio_message_rtr_get(const canio_message_obj_t *self); -bool common_hal_canio_message_extended_get(const canio_message_obj_t *self); -int common_hal_canio_message_id_get(const canio_message_obj_t *self); -const void *common_hal_canio_message_data_get(const canio_message_obj_t *self); -size_t common_hal_canio_message_size_get(const canio_message_obj_t *self); -void common_hal_canio_message_rtr_set(canio_message_obj_t *self, bool rtr); -void common_hal_canio_message_extended_set(canio_message_obj_t *self, bool extended); -void common_hal_canio_message_id_set(canio_message_obj_t *self, int id); -void common_hal_canio_message_data_set(canio_message_obj_t *self, const void *data, size_t size); -void common_hal_canio_message_size_set(canio_message_obj_t *self, size_t size); -- cgit v1.2.3 From c39ec1581e3fbc59de7f882adf2e6fbb574fb42e Mon Sep 17 00:00:00 2001 From: Jeff Epler Date: Fri, 18 Sep 2020 11:14:59 -0500 Subject: _canio: Message: setting data clears rtr, and vice versa --- shared-bindings/_canio/Message.c | 4 ++-- shared-module/_canio/Message.c | 4 ++++ 2 files changed, 6 insertions(+), 2 deletions(-) (limited to 'shared-module') diff --git a/shared-bindings/_canio/Message.c b/shared-bindings/_canio/Message.c index 85657e05e..c7ef5d458 100644 --- a/shared-bindings/_canio/Message.c +++ b/shared-bindings/_canio/Message.c @@ -117,7 +117,7 @@ STATIC const mp_obj_property_t canio_message_id_obj = { //| data: bytes //| """The content of the message, or dummy content in the case of an rtr. //| -//| Assigning to data also sets the length.""" +//| Assigning to data also sets the length and clears the rtr flag.""" //| STATIC mp_obj_t canio_message_data_get(const mp_obj_t self_in) { canio_message_obj_t *self = self_in; @@ -202,7 +202,7 @@ STATIC const mp_obj_property_t canio_message_extended_obj = { //| rtr: bool -//| """True if the message represents a remote transmission request (RTR)""" +//| """True if the message represents a remote transmission request (RTR). Setting rtr to true zeros out data""" //| STATIC mp_obj_t canio_message_rtr_get(const mp_obj_t self_in) { canio_message_obj_t *self = self_in; diff --git a/shared-module/_canio/Message.c b/shared-module/_canio/Message.c index 0caca58f0..a02bd0127 100644 --- a/shared-module/_canio/Message.c +++ b/shared-module/_canio/Message.c @@ -59,6 +59,7 @@ const void *common_hal_canio_message_get_data(const canio_message_obj_t *self) const void common_hal_canio_message_set_data(canio_message_obj_t *self, const void *data, size_t size) { + self->rtr = false; self->size = size; memcpy(self->data, data, size); } @@ -84,6 +85,9 @@ bool common_hal_canio_message_get_rtr(const canio_message_obj_t *self) void common_hal_canio_message_set_rtr(canio_message_obj_t *self, bool rtr) { self->rtr = rtr; + if (rtr) { + memset(self->data, 0, self->size); + } } bool common_hal_canio_message_get_extended(const canio_message_obj_t *self) -- cgit v1.2.3 From 4869dbdc670bfa8a5f2e0a639495d03984ea0a6a Mon Sep 17 00:00:00 2001 From: Jeff Epler Date: Mon, 21 Sep 2020 16:42:12 -0500 Subject: canio: rename from _canio This reflects our belief that the API is stable enough to avoid incompatible changes during 6.x. --- main.c | 2 +- ports/atmel-samd/common-hal/_canio/CAN.c | 445 -------------------------- ports/atmel-samd/common-hal/_canio/CAN.h | 55 ---- ports/atmel-samd/common-hal/_canio/Listener.c | 391 ---------------------- ports/atmel-samd/common-hal/_canio/Listener.h | 53 --- ports/atmel-samd/common-hal/_canio/__init__.c | 25 -- ports/atmel-samd/common-hal/_canio/__init__.h | 67 ---- ports/atmel-samd/common-hal/canio/CAN.c | 445 ++++++++++++++++++++++++++ ports/atmel-samd/common-hal/canio/CAN.h | 55 ++++ ports/atmel-samd/common-hal/canio/Listener.c | 391 ++++++++++++++++++++++ ports/atmel-samd/common-hal/canio/Listener.h | 53 +++ ports/atmel-samd/common-hal/canio/__init__.c | 25 ++ ports/atmel-samd/common-hal/canio/__init__.h | 67 ++++ py/circuitpy_defns.mk | 14 +- py/circuitpy_mpconfig.h | 2 +- shared-bindings/_canio/CAN.c | 422 ------------------------ shared-bindings/_canio/CAN.h | 54 ---- shared-bindings/_canio/Listener.c | 193 ----------- shared-bindings/_canio/Listener.h | 31 -- shared-bindings/_canio/Match.c | 139 -------- shared-bindings/_canio/Match.h | 37 --- shared-bindings/_canio/Message.c | 212 ------------ shared-bindings/_canio/Message.h | 44 --- shared-bindings/_canio/__init__.c | 124 ------- shared-bindings/_canio/__init__.h | 33 -- shared-bindings/canio/CAN.c | 422 ++++++++++++++++++++++++ shared-bindings/canio/CAN.h | 54 ++++ shared-bindings/canio/Listener.c | 193 +++++++++++ shared-bindings/canio/Listener.h | 31 ++ shared-bindings/canio/Match.c | 139 ++++++++ shared-bindings/canio/Match.h | 37 +++ shared-bindings/canio/Message.c | 212 ++++++++++++ shared-bindings/canio/Message.h | 44 +++ shared-bindings/canio/__init__.c | 124 +++++++ shared-bindings/canio/__init__.h | 33 ++ shared-module/_canio/Match.c | 43 --- shared-module/_canio/Match.h | 36 --- shared-module/_canio/Message.c | 101 ------ shared-module/_canio/Message.h | 38 --- shared-module/canio/Match.c | 43 +++ shared-module/canio/Match.h | 36 +++ shared-module/canio/Message.c | 101 ++++++ shared-module/canio/Message.h | 38 +++ 43 files changed, 2552 insertions(+), 2552 deletions(-) delete mode 100644 ports/atmel-samd/common-hal/_canio/CAN.c delete mode 100644 ports/atmel-samd/common-hal/_canio/CAN.h delete mode 100644 ports/atmel-samd/common-hal/_canio/Listener.c delete mode 100644 ports/atmel-samd/common-hal/_canio/Listener.h delete mode 100644 ports/atmel-samd/common-hal/_canio/__init__.c delete mode 100644 ports/atmel-samd/common-hal/_canio/__init__.h create mode 100644 ports/atmel-samd/common-hal/canio/CAN.c create mode 100644 ports/atmel-samd/common-hal/canio/CAN.h create mode 100644 ports/atmel-samd/common-hal/canio/Listener.c create mode 100644 ports/atmel-samd/common-hal/canio/Listener.h create mode 100644 ports/atmel-samd/common-hal/canio/__init__.c create mode 100644 ports/atmel-samd/common-hal/canio/__init__.h delete mode 100644 shared-bindings/_canio/CAN.c delete mode 100644 shared-bindings/_canio/CAN.h delete mode 100644 shared-bindings/_canio/Listener.c delete mode 100644 shared-bindings/_canio/Listener.h delete mode 100644 shared-bindings/_canio/Match.c delete mode 100644 shared-bindings/_canio/Match.h delete mode 100644 shared-bindings/_canio/Message.c delete mode 100644 shared-bindings/_canio/Message.h delete mode 100644 shared-bindings/_canio/__init__.c delete mode 100644 shared-bindings/_canio/__init__.h create mode 100644 shared-bindings/canio/CAN.c create mode 100644 shared-bindings/canio/CAN.h create mode 100644 shared-bindings/canio/Listener.c create mode 100644 shared-bindings/canio/Listener.h create mode 100644 shared-bindings/canio/Match.c create mode 100644 shared-bindings/canio/Match.h create mode 100644 shared-bindings/canio/Message.c create mode 100644 shared-bindings/canio/Message.h create mode 100644 shared-bindings/canio/__init__.c create mode 100644 shared-bindings/canio/__init__.h delete mode 100644 shared-module/_canio/Match.c delete mode 100644 shared-module/_canio/Match.h delete mode 100644 shared-module/_canio/Message.c delete mode 100644 shared-module/_canio/Message.h create mode 100644 shared-module/canio/Match.c create mode 100644 shared-module/canio/Match.h create mode 100644 shared-module/canio/Message.c create mode 100644 shared-module/canio/Message.h (limited to 'shared-module') diff --git a/main.c b/main.c index 4d34e451d..dbd367a59 100755 --- a/main.c +++ b/main.c @@ -82,7 +82,7 @@ #endif #if CIRCUITPY_CANIO -#include "common-hal/_canio/CAN.h" +#include "common-hal/canio/CAN.h" #endif void do_str(const char *src, mp_parse_input_kind_t input_kind) { diff --git a/ports/atmel-samd/common-hal/_canio/CAN.c b/ports/atmel-samd/common-hal/_canio/CAN.c deleted file mode 100644 index 0d967d7ca..000000000 --- a/ports/atmel-samd/common-hal/_canio/CAN.c +++ /dev/null @@ -1,445 +0,0 @@ -/* - * This file is part of the MicroPython project, http://micropython.org/ - * - * The MIT License (MIT) - * - * Copyright (c) 2020 Jeff Epler for Adafruit Industries - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -#include - -#include "py/runtime.h" -#include "py/mperrno.h" - -#include "peripheral_clk_config.h" - -#include "common-hal/_canio/CAN.h" -#include "shared-bindings/microcontroller/Pin.h" -#include "shared-bindings/util.h" -#include "supervisor/port.h" - -#include "component/can.h" - -#include "genhdr/candata.h" - -STATIC Can * const can_insts[] = CAN_INSTS; - -STATIC canio_can_obj_t *can_objs[MP_ARRAY_SIZE(can_insts)]; - -// This must be placed in the first 64kB of RAM -STATIC COMPILER_SECTION(".canram") canio_can_state_t can_state[MP_ARRAY_SIZE(can_insts)]; - -void common_hal_canio_can_construct(canio_can_obj_t *self, mcu_pin_obj_t *tx, mcu_pin_obj_t *rx, int baudrate, bool loopback, bool silent) -{ - mcu_pin_function_t *tx_function = mcu_find_pin_function(can_tx, tx, -1, MP_QSTR_tx); - int instance = tx_function->instance; - - mcu_pin_function_t *rx_function = mcu_find_pin_function(can_rx, rx, instance, MP_QSTR_rx); - - const uint32_t can_frequency = CONF_CAN0_FREQUENCY; - -#define DIV_ROUND(a, b) (((a) + (b)/2) / (b)) -#define DIV_ROUND_UP(a, b) (((a) + (b) - 1) / (b)) - - uint32_t clocks_per_bit = DIV_ROUND(can_frequency, baudrate); - uint32_t clocks_to_sample = DIV_ROUND(clocks_per_bit * 7, 8); - uint32_t clocks_after_sample = clocks_per_bit - clocks_to_sample; - uint32_t divisor = MAX(DIV_ROUND_UP(clocks_to_sample, 256), DIV_ROUND_UP(clocks_after_sample, 128)); - if (divisor > 32) { - mp_raise_OSError(MP_EINVAL); // baudrate cannot be attained (16kHz or something is lower bound, should never happen) - } - - gpio_set_pin_direction(tx_function->pin, GPIO_DIRECTION_OUT); - gpio_set_pin_function(tx_function->pin, tx_function->function); - common_hal_never_reset_pin(tx_function->obj); - - gpio_set_pin_direction(rx_function->pin, GPIO_DIRECTION_IN); - gpio_set_pin_function(rx_function->pin, rx_function->function); - common_hal_never_reset_pin(rx_function->obj); - - self->tx_pin_number = tx ? common_hal_mcu_pin_number(tx) : COMMON_HAL_MCU_NO_PIN; - self->rx_pin_number = rx ? common_hal_mcu_pin_number(rx) : COMMON_HAL_MCU_NO_PIN; - self->hw = can_insts[instance]; - self->state = &can_state[instance]; - - self->loopback = loopback; - self->silent = silent; - - // Allow configuration change - hri_can_set_CCCR_INIT_bit(self->hw); - while (hri_can_get_CCCR_INIT_bit(self->hw) == 0) { - } - hri_can_set_CCCR_CCE_bit(self->hw); - - if (instance == 0) { - hri_mclk_set_AHBMASK_CAN0_bit(MCLK); - hri_gclk_write_PCHCTRL_reg(GCLK, CAN0_GCLK_ID, CONF_GCLK_CAN0_SRC | (1 << GCLK_PCHCTRL_CHEN_Pos)); - - NVIC_DisableIRQ(CAN0_IRQn); - NVIC_ClearPendingIRQ(CAN0_IRQn); - NVIC_EnableIRQ(CAN0_IRQn); - hri_can_write_ILE_reg(self->hw, CAN_ILE_EINT0); -#ifdef CAN1_GCLK_ID - } else if (instance == 1) { - hri_mclk_set_AHBMASK_CAN1_bit(MCLK); - hri_gclk_write_PCHCTRL_reg(GCLK, CAN1_GCLK_ID, CONF_GCLK_CAN1_SRC | (1 << GCLK_PCHCTRL_CHEN_Pos)); - - NVIC_DisableIRQ(CAN1_IRQn); - NVIC_ClearPendingIRQ(CAN1_IRQn); - NVIC_EnableIRQ(CAN1_IRQn); - hri_can_write_ILE_reg(self->hw, CAN_ILE_EINT0); -#endif - } - - self->hw->CCCR.bit.FDOE = 0; // neither FD nor Bit Rate Switch enabled - self->hw->CCCR.bit.BRSE = 0; - - hri_can_write_MRCFG_reg(self->hw, CAN_MRCFG_QOS(CAN_MRCFG_QOS_DISABLE_Val)); // QoS disabled (no sensitive operation) - - // A "nominal bit" is a header bit. With dual rate CAN FD, this is a slower rate - { - CAN_NBTP_Type btp = { - // 0 means "1 tq", but 2 is subtracted from NTSEG1 for the - // fixed 1 "SYNC" tq - .bit.NTSEG1 = DIV_ROUND(clocks_to_sample, divisor) - 2, - .bit.NTSEG2 = DIV_ROUND(clocks_after_sample, divisor) - 1, - .bit.NBRP = divisor - 1, - .bit.NSJW = DIV_ROUND(clocks_after_sample, divisor * 4), - }; - hri_can_write_NBTP_reg(self->hw, btp.reg); - } - - // A "data bit" is a data bit :) with dula rate CAN FD, this is a higher - // rate. However, CAN FD is not implemented in CircuitPython, and this is - // the same rate as the "nominal rate". - { - CAN_DBTP_Type btp = { - .bit.DTSEG1 = DIV_ROUND(clocks_to_sample, divisor) - 1, - .bit.DTSEG2 = DIV_ROUND(clocks_after_sample, divisor) - 1, - .bit.DBRP = divisor - 1, - .bit.DSJW = DIV_ROUND(clocks_after_sample, divisor * 4), - }; - hri_can_write_DBTP_reg(self->hw, btp.reg); - } - - { - CAN_RXF0C_Type rxf = { - .bit.F0SA = (uint32_t)self->state->rx0_fifo, - .bit.F0S = COMMON_HAL_CANIO_RX_FIFO_SIZE, - }; - hri_can_write_RXF0C_reg(self->hw, rxf.reg); - } - - { - CAN_RXF1C_Type rxf = { - .bit.F1SA = (uint32_t)self->state->rx1_fifo, - .bit.F1S = COMMON_HAL_CANIO_RX_FIFO_SIZE, - }; - hri_can_write_RXF1C_reg(self->hw, rxf.reg); - } - - // All RX data has an 8 byte payload (max) - { - CAN_RXESC_Type esc = { - .bit.F0DS = CAN_RXESC_F0DS_DATA8_Val, - .bit.F1DS = CAN_RXESC_F1DS_DATA8_Val, - .bit.RBDS = CAN_RXESC_RBDS_DATA8_Val, - }; - hri_can_write_RXESC_reg(self->hw, esc.reg); - } - - // All TX data has an 8 byte payload (max) - { - CAN_TXESC_Type esc = { - .bit.TBDS = CAN_TXESC_TBDS_DATA8_Val, - }; - hri_can_write_TXESC_reg(self->hw, esc.reg); - } - - { - CAN_TXBC_Type bc = { - .bit.TBSA = (uint32_t)self->state->tx_fifo, - .bit.NDTB = COMMON_HAL_CANIO_TX_FIFO_SIZE, - .bit.TFQM = 0, // Messages are transmitted in the order submitted - }; - hri_can_write_TXBC_reg(self->hw, bc.reg); - } - - { - CAN_TXEFC_Type efc = { - .bit.EFS = 0, - }; - hri_can_write_TXEFC_reg(self->hw, efc.reg); - } - - { - CAN_GFC_Type gfc = { - .bit.RRFE = 1, - .bit.ANFS = CAN_GFC_ANFS_REJECT_Val, - .bit.ANFE = CAN_GFC_ANFE_REJECT_Val, - }; - hri_can_write_GFC_reg(self->hw, gfc.reg); - } - - { - CAN_SIDFC_Type dfc = { - .bit.LSS = COMMON_HAL_CANIO_RX_FILTER_SIZE, - .bit.FLSSA = (uint32_t)self->state->standard_rx_filter - }; - hri_can_write_SIDFC_reg(self->hw, dfc.reg); - } - - { - CAN_XIDFC_Type dfc = { - .bit.LSE = COMMON_HAL_CANIO_RX_FILTER_SIZE, - .bit.FLESA = (uint32_t)self->state->extended_rx_filter - }; - hri_can_write_XIDFC_reg(self->hw, dfc.reg); - } - - { - CAN_IE_Type ie = { - .bit.EWE = 1, - .bit.EPE = 1, - .bit.BOE = 1, - }; - hri_can_write_IE_reg(self->hw, ie.reg); - } - - hri_can_write_XIDAM_reg(self->hw, CAN_XIDAM_RESETVALUE); - -// silent: The CAN is set in Bus Monitoring Mode by programming CCCR.MON to '1'. (tx pin unused) -// external loopback: The CAN can be set in External Loop Back Mode by programming TEST.LBCK and CCCR.MON to '1'. (rx pin unused) -// internal loopback (silent loopback): Internal Loop Back Mode is entered by programming bits TEST.LBCK and CCCR.MON to '1'. (tx, rx unused) - self->hw->CCCR.bit.MON = silent; - self->hw->CCCR.bit.TEST = loopback; - self->hw->TEST.bit.LBCK = loopback; - - if (instance == 0) { - NVIC_DisableIRQ(CAN0_IRQn); - NVIC_ClearPendingIRQ(CAN0_IRQn); - NVIC_EnableIRQ(CAN0_IRQn); -#ifdef CAN1_GCLK_ID - } else if (instance == 1) { - NVIC_DisableIRQ(CAN1_IRQn); - NVIC_ClearPendingIRQ(CAN1_IRQn); - NVIC_EnableIRQ(CAN1_IRQn); -#endif - } - - hri_can_write_ILE_reg(self->hw, CAN_ILE_EINT0); - // Prevent configuration change - hri_can_clear_CCCR_CCE_bit(self->hw); - hri_can_clear_CCCR_INIT_bit(self->hw); - while (hri_can_get_CCCR_INIT_bit(self->hw)) { - } - - can_objs[instance] = self; -} - -bool common_hal_canio_can_loopback_get(canio_can_obj_t *self) -{ - return self->loopback; -} - -int common_hal_canio_can_baudrate_get(canio_can_obj_t *self) -{ - return self->baudrate; -} - -int common_hal_canio_can_transmit_error_count_get(canio_can_obj_t *self) -{ - return self->hw->ECR.bit.TEC; -} - -int common_hal_canio_can_receive_error_count_get(canio_can_obj_t *self) -{ - return self->hw->ECR.bit.REC; -} - -int common_hal_canio_can_error_warning_state_count_get(canio_can_obj_t *self) -{ - return self->error_warning_state_count; -} - -int common_hal_canio_can_error_passive_state_count_get(canio_can_obj_t *self) -{ - return self->error_passive_state_count; -} - -int common_hal_canio_can_bus_off_state_count_get(canio_can_obj_t *self) -{ - return self->bus_off_state_count; -} - -canio_bus_state_t common_hal_canio_can_state_get(canio_can_obj_t *self) { - CAN_PSR_Type psr = self->hw->PSR; - if (psr.bit.BO) { - return BUS_STATE_OFF; - } - if (psr.bit.EP) { - return BUS_STATE_ERROR_PASSIVE; - } - if (psr.bit.EW) { - return BUS_STATE_ERROR_WARNING; - } - return BUS_STATE_ERROR_ACTIVE; -} - -void common_hal_canio_can_restart(canio_can_obj_t *self) { - if (!self->hw->PSR.bit.BO) { - return; - } - - hri_can_clear_CCCR_INIT_bit(self->hw); - while (hri_can_get_CCCR_INIT_bit(self->hw)) { - } -} - -bool common_hal_canio_can_auto_restart_get(canio_can_obj_t *self) { - return self->auto_restart; -} - -void common_hal_canio_can_auto_restart_set(canio_can_obj_t *self, bool value) { - self->auto_restart = value; -} - -static void maybe_auto_restart(canio_can_obj_t *self) { - if (self->auto_restart) { - common_hal_canio_can_restart(self); - } -} - -void common_hal_canio_can_send(canio_can_obj_t *self, canio_message_obj_t *message) -{ - maybe_auto_restart(self); - - // We have just one dedicated TX buffer, use it! - canio_can_fifo_t *ent = &self->state->tx_fifo[0]; - - ent->txb0.bit.ESI = false; - ent->txb0.bit.XTD = message->extended; - ent->txb0.bit.RTR = message->rtr; - if (message->extended) { - ent->txb0.bit.ID = message->id << 18; - } else { - ent->txb0.bit.ID = message->id << 18; // short addresses are left-justified - } - - ent->txb1.bit.MM = 0; // "message marker" - ent->txb1.bit.EFC = 0; // don't store fifo events to event queue - ent->txb1.bit.FDF = 0; // Classic CAN format - ent->txb1.bit.BRS = 0; // No bit rate switching - ent->txb1.bit.DLC = message->size; - - if (!message->rtr) { - memcpy(ent->data, message->data, message->size); - } - - // TX buffer add request - self->hw->TXBAR.reg = 1; - - // wait 8ms (hard coded for now) for TX to occur - uint64_t deadline = port_get_raw_ticks(NULL) + 8; - while (port_get_raw_ticks(NULL) < deadline && !(self->hw->TXBTO.reg & 1)) { - RUN_BACKGROUND_TASKS; - } -} - -bool common_hal_canio_can_silent_get(canio_can_obj_t *self) { - return self->silent; -} - -bool common_hal_canio_can_deinited(canio_can_obj_t *self) { - return !self->hw; -} - -void common_hal_canio_can_check_for_deinit(canio_can_obj_t *self) { - if (common_hal_canio_can_deinited(self)) { - raise_deinited_error(); - } -} - -void common_hal_canio_can_deinit(canio_can_obj_t *self) -{ - if (self->hw) { - hri_can_set_CCCR_INIT_bit(self->hw); - self->hw = 0; - } - if (self->rx_pin_number != COMMON_HAL_MCU_NO_PIN) { - reset_pin_number(self->rx_pin_number); - self->rx_pin_number = COMMON_HAL_MCU_NO_PIN; - } - if (self->tx_pin_number != COMMON_HAL_MCU_NO_PIN) { - reset_pin_number(self->tx_pin_number); - self->tx_pin_number = COMMON_HAL_MCU_NO_PIN; - } -} - -void common_hal_canio_reset(void) { - memset(can_state, 0, sizeof(can_state)); - - for (size_t i=0; ierror_warning_state_count += 1; - } - if (ir & CAN_IE_EPE) { - self->error_passive_state_count += 1; - } - if (ir & CAN_IE_BOE) { - self->bus_off_state_count += 1; - } - - /* Acknowledge interrupt */ - hri_can_write_IR_reg(hw, ir); -} - -__attribute__((used)) -void CAN0_Handler(void) { - can_handler(0); -} - -#ifdef CAN1_GCLK_ID -__attribute__((used)) -void CAN1_Handler(void) { - can_handler(1); -} -#endif diff --git a/ports/atmel-samd/common-hal/_canio/CAN.h b/ports/atmel-samd/common-hal/_canio/CAN.h deleted file mode 100644 index 1cc34e3ac..000000000 --- a/ports/atmel-samd/common-hal/_canio/CAN.h +++ /dev/null @@ -1,55 +0,0 @@ -/* - * This file is part of the MicroPython project, http://micropython.org/ - * - * The MIT License (MIT) - * - * Copyright (c) 2020 Jeff Epler for Adafruit Industries - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -#pragma once - -#include "py/obj.h" -#include "shared-bindings/_canio/__init__.h" -#include "shared-bindings/_canio/CAN.h" -#include "component/can.h" -#include "common-hal/microcontroller/Pin.h" -#include "common-hal/_canio/__init__.h" -#include "shared-module/_canio/Message.h" - -#define COMMON_HAL_CAN_RX_FIFO_LEN (2) -#define COMMON_HAL_CAN_TX_FIFO_LEN (2) - -typedef struct canio_can_obj { - mp_obj_base_t base; - Can *hw; - canio_can_state_t *state; - volatile uint32_t error_warning_state_count; - volatile uint32_t error_passive_state_count; - volatile uint32_t bus_off_state_count; - int baudrate; - uint8_t rx_pin_number:8; - uint8_t tx_pin_number:8; - bool loopback:1; - bool silent:1; - bool auto_restart:1; - bool fifo0_in_use:1; - bool fifo1_in_use:1; -} canio_can_obj_t; diff --git a/ports/atmel-samd/common-hal/_canio/Listener.c b/ports/atmel-samd/common-hal/_canio/Listener.c deleted file mode 100644 index 0a5f629f8..000000000 --- a/ports/atmel-samd/common-hal/_canio/Listener.c +++ /dev/null @@ -1,391 +0,0 @@ -/* - * This file is part of the MicroPython project, http://micropython.org/ - * - * The MIT License (MIT) - * - * Copyright (c) 2020 Jeff Epler for Adafruit Industries - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -#include -#include - -#include "py/obj.h" -#include "py/runtime.h" - -#include "common-hal/_canio/__init__.h" -#include "common-hal/_canio/Listener.h" -#include "shared-bindings/util.h" -#include "supervisor/shared/tick.h" -#include "component/can.h" - -STATIC void allow_config_change(canio_can_obj_t *can) { - can->hw->CCCR.bit.INIT = 1; - while (!can->hw->CCCR.bit.INIT) { - } - can->hw->CCCR.bit.CCE = 1; -} - -STATIC void prevent_config_change(canio_can_obj_t *can) { - can->hw->CCCR.bit.CCE = 0; - can->hw->CCCR.bit.INIT = 0; - while (can->hw->CCCR.bit.INIT) { - } -} - -__attribute__((unused)) -STATIC void static_assertions(void) { - MP_STATIC_ASSERT(CAN_GFC_ANFE_RXF0_Val + 1 == CAN_GFC_ANFE_RXF1_Val); - MP_STATIC_ASSERT(CAN_GFC_ANFS_RXF0_Val + 1 == CAN_GFC_ANFS_RXF1_Val); - MP_STATIC_ASSERT(CAN_SIDFE_0_SFEC_STF0M_Val + 1 == CAN_SIDFE_0_SFEC_STF1M_Val); - MP_STATIC_ASSERT(CAN_XIDFE_0_EFEC_STF0M_Val + 1 == CAN_XIDFE_0_EFEC_STF1M_Val); -} - -STATIC bool single_address_filter(canio_match_obj_t *match) { - return match->mask == 0 || match->mask == match->address; -} - -STATIC bool standard_filter_in_use(CanMramSidfe *filter) { - return filter->SIDFE_0.bit.SFEC != CAN_SIDFE_0_SFEC_DISABLE_Val; -} - -STATIC bool extended_filter_in_use(CanMramXidfe *filter) { - return filter->XIDFE_0.bit.EFEC != CAN_XIDFE_0_EFEC_DISABLE_Val; -} - -STATIC size_t num_filters_needed(size_t nmatch, canio_match_obj_t **matches, bool extended) { - size_t num_half_filters_needed = 1; - for(size_t i=0; iextended) { - continue; - } - if (single_address_filter(matches[i])) { - num_half_filters_needed += 1; - } else { - num_half_filters_needed += 2; - } - } - return num_half_filters_needed / 2; -} - -STATIC size_t num_filters_available(canio_can_obj_t *can, bool extended) { - size_t available = 0; - if (extended) { - for(size_t i = 0; i < MP_ARRAY_SIZE(can->state->extended_rx_filter); i++) { - if (!extended_filter_in_use(&can->state->extended_rx_filter[i])) { - available++; - } - } - } else { - for(size_t i = 0; i < MP_ARRAY_SIZE(can->state->standard_rx_filter); i++) { - if (!standard_filter_in_use(&can->state->standard_rx_filter[i])) { - available++; - } - } - } - return available; -} - -STATIC void clear_filters(canio_listener_obj_t *self) { - canio_can_obj_t *can = self->can; - int fifo = self->fifo_idx; - - // If it was a global accept, clear it - allow_config_change(can); - if (can->hw->GFC.bit.ANFS == CAN_GFC_ANFS_RXF0 + fifo) { - can->hw->GFC.bit.ANFS = CAN_GFC_ANFS_REJECT_Val; - } - if (can->hw->GFC.bit.ANFE == CAN_GFC_ANFE_RXF0 + fifo) { - can->hw->GFC.bit.ANFE = CAN_GFC_ANFE_REJECT_Val; - } - prevent_config_change(can); - - // For each filter entry, if it pointed at this FIFO set it to DISABLE - for(size_t i = 0; i < MP_ARRAY_SIZE(can->state->extended_rx_filter); i++) { - int val = CAN_XIDFE_0_EFEC_STF0M_Val + fifo; - if (can->state->extended_rx_filter[i].XIDFE_0.bit.EFEC == val) { - can->state->extended_rx_filter[i].XIDFE_0.bit.EFEC = CAN_XIDFE_0_EFEC_DISABLE_Val; - } - } - for(size_t i = 0; i < MP_ARRAY_SIZE(can->state->standard_rx_filter); i++) { - int val = CAN_SIDFE_0_SFEC_STF1M_Val + fifo; - if (can->state->standard_rx_filter[i].SIDFE_0.bit.SFEC == val) { - can->state->standard_rx_filter[i].SIDFE_0.bit.SFEC = CAN_SIDFE_0_SFEC_DISABLE_Val; - } - } -} - -STATIC CanMramXidfe *next_extended_filter(canio_listener_obj_t *self, CanMramXidfe *start) { - CanMramXidfe *end = &self->can->state->extended_rx_filter[MP_ARRAY_SIZE(self->can->state->extended_rx_filter)]; - if (start == NULL) { - start = self->can->state->extended_rx_filter; - } else { - start = start + 1; - } - while (extended_filter_in_use(start)) { - if (start == end) { - return NULL; - } - start = start + 1; - } - return start; -} - -STATIC CanMramSidfe *next_standard_filter(canio_listener_obj_t *self, CanMramSidfe *start) { - CanMramSidfe *end = &self->can->state->standard_rx_filter[MP_ARRAY_SIZE(self->can->state->standard_rx_filter)]; - if (start == NULL) { - start = self->can->state->standard_rx_filter; - } else { - start = start + 1; - } - while (standard_filter_in_use(start)) { - if (start == end) { - return NULL; - } - start = start + 1; - } - return start; -} - -STATIC void install_standard_filter(CanMramSidfe *standard, int id1, int id2, int sfec, int sft) { - assert(standard); - CAN_SIDFE_0_Type val = { - .bit.SFID1 = id1, - .bit.SFID2 = id2, - .bit.SFEC = sfec, - .bit.SFT = sft, - }; - standard->SIDFE_0 = val; -} - -STATIC void install_extended_filter(CanMramXidfe *extended, int id1, int id2, int efec, int eft) { - assert(extended); - CAN_XIDFE_0_Type val0 = { - .bit.EFID1 = id1, - .bit.EFEC = efec, - }; - CAN_XIDFE_1_Type val1 = { - .bit.EFID2 = id2, - .bit.EFT = eft, - }; - // Set entry 0 second, because it has the enable bits (XIDFE_0_EFEC) - extended->XIDFE_1 = val1; - extended->XIDFE_0 = val0; -} - - -#define NO_ADDRESS (-1) -void set_filters(canio_listener_obj_t *self, size_t nmatch, canio_match_obj_t **matches) { - int fifo = self->fifo_idx; - - if (!nmatch) { - allow_config_change(self->can); - self->can->hw->GFC.bit.ANFS = CAN_GFC_ANFS_RXF0_Val + fifo; - self->can->hw->GFC.bit.ANFE = CAN_GFC_ANFE_RXF0_Val + fifo; - self->can->hw->CCCR.bit.CCE = 0; - prevent_config_change(self->can); - return; - } - - CanMramSidfe *standard = next_standard_filter(self, NULL); - CanMramXidfe *extended = next_extended_filter(self, NULL); - - int first_address = NO_ADDRESS; - - // step 1: single address standard matches - // we have to gather up pairs and stuff them in a single filter entry - for(size_t i = 0; iextended) { - continue; - } - if (!single_address_filter(match)) { - continue; - } - if (first_address != NO_ADDRESS) { - install_standard_filter(standard, first_address, match->address, CAN_SIDFE_0_SFEC_STF0M_Val + fifo, CAN_SIDFE_0_SFT_DUAL_Val); - first_address = NO_ADDRESS; - standard = next_standard_filter(self, standard); - } else { - first_address = match->address; - } - } - // step 1.5. odd single address standard match - if (first_address != NO_ADDRESS) { - install_standard_filter(standard, first_address, first_address, CAN_SIDFE_0_SFEC_STF0M_Val + fifo, CAN_SIDFE_0_SFT_DUAL_Val); - standard = next_standard_filter(self, standard); - first_address = NO_ADDRESS; - } - - // step 2: standard mask filter - for(size_t i = 0; iextended) { - continue; - } - if (single_address_filter(match)) { - continue; - } - install_standard_filter(standard, match->address, match->mask, CAN_SIDFE_0_SFEC_STF0M_Val + fifo, CAN_SIDFE_0_SFT_CLASSIC_Val); - standard = next_standard_filter(self, standard); - } - - // step 3: single address extended matches - // we have to gather up pairs and stuff them in a single filter entry - for(size_t i = 0; iextended) { - continue; - } - if (!single_address_filter(match)) { - continue; - } - if (first_address != NO_ADDRESS) { - install_extended_filter(extended, first_address, match->address, CAN_XIDFE_0_EFEC_STF0M_Val + fifo, CAN_XIDFE_1_EFT_DUAL_Val); - first_address = NO_ADDRESS; - extended = next_extended_filter(self, extended); - } else { - first_address = match->address; - } - } - // step 3.5. odd single address standard match - if (first_address != NO_ADDRESS) { - install_extended_filter(extended, first_address, first_address, CAN_XIDFE_0_EFEC_STF0M_Val + fifo, CAN_XIDFE_1_EFT_DUAL_Val); - extended = next_extended_filter(self, extended); - first_address = NO_ADDRESS; - } - - // step 4: extended mask filters - for(size_t i = 0; iextended) { - continue; - } - if (single_address_filter(match)) { - continue; - } - install_extended_filter(extended, match->address, match->mask, CAN_XIDFE_0_EFEC_STF0M_Val + fifo, CAN_XIDFE_1_EFT_CLASSIC_Val); - extended = next_extended_filter(self, extended); - } - - // phew, easy(!) -} - - -void common_hal_canio_listener_construct(canio_listener_obj_t *self, canio_can_obj_t *can, size_t nmatch, canio_match_obj_t **matches, float timeout) { - if (!can->fifo0_in_use) { - self->fifo_idx = 0; - self->fifo = can->state->rx0_fifo; - self->hw = (canio_rxfifo_reg_t*)&can->hw->RXF0C; - can->hw->IR.reg = CAN_IR_RF0N | CAN_IR_RF0W | CAN_IR_RF0F | CAN_IR_RF0L; - can->fifo0_in_use = true; - } else if (!can->fifo1_in_use) { - self->fifo_idx = 1; - self->fifo = can->state->rx1_fifo; - self->hw = (canio_rxfifo_reg_t*)&can->hw->RXF1C; - can->fifo1_in_use = true; - can->hw->IR.reg = CAN_IR_RF1N | CAN_IR_RF1W | CAN_IR_RF1F | CAN_IR_RF1L; - } else { - mp_raise_ValueError(translate("All RX FIFOs in use")); - } - - if (!nmatch) { - if (can->hw->GFC.bit.ANFS == CAN_GFC_ANFS_RXF1_Val - self->fifo_idx) { - mp_raise_ValueError(translate("Already have all-matches listener")); - } - if (can->hw->GFC.bit.ANFE == CAN_GFC_ANFE_RXF1_Val - self->fifo_idx) { - mp_raise_ValueError(translate("Already have all-matches listener")); - } - } - - if (num_filters_needed(nmatch, matches, false) > num_filters_available(can, false)) { - mp_raise_ValueError(translate("Filters too complex")); - } - - if (num_filters_needed(nmatch, matches, true) > num_filters_available(can, true)) { - mp_raise_ValueError(translate("Filters too complex")); - } - - // Nothing can fail now so it's safe to assign self->can - self->can = can; - set_filters(self, nmatch, matches); - common_hal_canio_listener_set_timeout(self, timeout); -} - -void common_hal_canio_listener_set_timeout(canio_listener_obj_t *self, float timeout) { - self->timeout_ms = (int)MICROPY_FLOAT_C_FUN(ceil)(timeout * 1000); -} - -float common_hal_canio_listener_get_timeout(canio_listener_obj_t *self) { - return self->timeout_ms / 1000.0f; -} - -void common_hal_canio_listener_check_for_deinit(canio_listener_obj_t *self) { - if (!self->can) { - raise_deinited_error(); - } - common_hal_canio_can_check_for_deinit(self->can); -} - -int common_hal_canio_listener_in_waiting(canio_listener_obj_t *self) { - return self->hw->RXFS.bit.F0FL; -} - -bool common_hal_canio_listener_readinto(canio_listener_obj_t *self, canio_message_obj_t *message) { - if (!common_hal_canio_listener_in_waiting(self)) { - uint64_t deadline = supervisor_ticks_ms64() + self->timeout_ms; - do { - if (supervisor_ticks_ms64() > deadline) { - return false; - } - } while (!common_hal_canio_listener_in_waiting(self)); - } - int index = self->hw->RXFS.bit.F0GI; - canio_can_fifo_t *hw_message = &self->fifo[index]; - message->extended = hw_message->rxb0.bit.XTD; - if (message->extended) { - message->id = hw_message->rxb0.bit.ID; - } else { - message->id = hw_message->rxb0.bit.ID >> 18; // short addresses are left-justified - } - message->rtr = hw_message->rxb0.bit.RTR; - message->size = hw_message->rxb1.bit.DLC; - if (!message->rtr) { - memcpy(message->data, hw_message->data, message->size); - } - self->hw->RXFA.bit.F0AI = index; - return true; -} - -void common_hal_canio_listener_deinit(canio_listener_obj_t *self) { - if (self->can) { - clear_filters(self); - if (self->fifo_idx == 0) { - self->can->fifo0_in_use = false; - } - if (self->fifo_idx == 1) { - self->can->fifo1_in_use = false; - } - } - self->fifo_idx = -1; - self->fifo = NULL; - self->can = NULL; - self->hw = NULL; -} diff --git a/ports/atmel-samd/common-hal/_canio/Listener.h b/ports/atmel-samd/common-hal/_canio/Listener.h deleted file mode 100644 index cc6770e6e..000000000 --- a/ports/atmel-samd/common-hal/_canio/Listener.h +++ /dev/null @@ -1,53 +0,0 @@ -/* - * This file is part of the MicroPython project, http://micropython.org/ - * - * The MIT License (MIT) - * - * Copyright (c) 2020 Jeff Epler for Adafruit Industries - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -#pragma once - -#include "common-hal/_canio/CAN.h" -#include "shared-module/_canio/Match.h" - -typedef struct { - __IO CAN_RXF0C_Type RXFC; /**< \brief (R/W 32) Rx FIFO n Configuration */ - __I CAN_RXF0S_Type RXFS; /**< \brief (R/ 32) Rx FIFO n Status */ - __IO CAN_RXF0A_Type RXFA; /**< \brief (R/W 32) Rx FIFO n Acknowledge */ -} canio_rxfifo_reg_t; - -typedef struct { - mp_obj_base_t base; - canio_can_obj_t *can; - canio_can_fifo_t *fifo; - canio_rxfifo_reg_t *hw; - uint32_t timeout_ms; - uint8_t fifo_idx; -} canio_listener_obj_t; - -void common_hal_canio_listener_construct(canio_listener_obj_t *self, canio_can_obj_t *can, size_t nmatch, canio_match_obj_t **matches, float timeout); -void common_hal_canio_listener_check_for_deinit(canio_listener_obj_t *self); -void common_hal_canio_listener_deinit(canio_listener_obj_t *self); -bool common_hal_canio_listener_readinto(canio_listener_obj_t *self, canio_message_obj_t *message); -int common_hal_canio_listener_in_waiting(canio_listener_obj_t *self); -float common_hal_canio_listener_get_timeout(canio_listener_obj_t *self); -void common_hal_canio_listener_set_timeout(canio_listener_obj_t *self, float timeout); diff --git a/ports/atmel-samd/common-hal/_canio/__init__.c b/ports/atmel-samd/common-hal/_canio/__init__.c deleted file mode 100644 index 7932bfc2d..000000000 --- a/ports/atmel-samd/common-hal/_canio/__init__.c +++ /dev/null @@ -1,25 +0,0 @@ -/* - * This file is part of the MicroPython project, http://micropython.org/ - * - * The MIT License (MIT) - * - * Copyright (c) 2020 Jeff Epler for Adafruit Industries - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ diff --git a/ports/atmel-samd/common-hal/_canio/__init__.h b/ports/atmel-samd/common-hal/_canio/__init__.h deleted file mode 100644 index cb491ab9e..000000000 --- a/ports/atmel-samd/common-hal/_canio/__init__.h +++ /dev/null @@ -1,67 +0,0 @@ -/* - * This file is part of the MicroPython project, http://micropython.org/ - * - * The MIT License (MIT) - * - * Copyright (c) 2020 Jeff Epler for Adafruit Industries - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -#pragma once - -#include "hal/utils/include/utils.h" -#include "component/can.h" - -#define COMMON_HAL_CANIO_MAX_MESSAGE_LENGTH (8) -#define COMMON_HAL_CANIO_RX_FIFO_SIZE (3) -#define COMMON_HAL_CANIO_RX_FILTER_SIZE (4) -#define COMMON_HAL_CANIO_TX_FIFO_SIZE (1) - -// This appears to be a typo (transposition error) in the ASF4 headers -// It's called the "Extended ID Filter Entry" -typedef CanMramXifde CanMramXidfe; - -typedef struct canio_listener canio_listener_t; -typedef struct canio_can canio_can_t; - -typedef struct { - union { - CAN_RXBE_0_Type rxb0; - CAN_TXBE_0_Type txb0; - CAN_RXF0E_0_Type rxf0; - }; - union { - CAN_RXBE_1_Type rxb1; - CAN_TXBE_1_Type txb1; - CAN_RXF0E_1_Type rxf1; - }; - COMPILER_ALIGNED(4) - uint8_t data[COMMON_HAL_CANIO_MAX_MESSAGE_LENGTH]; -} canio_can_fifo_t; - -typedef uint32_t canio_can_filter_t; - -typedef struct { - canio_can_fifo_t tx_fifo[COMMON_HAL_CANIO_TX_FIFO_SIZE]; - canio_can_fifo_t rx0_fifo[COMMON_HAL_CANIO_RX_FIFO_SIZE]; - canio_can_fifo_t rx1_fifo[COMMON_HAL_CANIO_RX_FIFO_SIZE]; - CanMramSidfe standard_rx_filter[COMMON_HAL_CANIO_RX_FILTER_SIZE]; - CanMramXifde extended_rx_filter[COMMON_HAL_CANIO_RX_FILTER_SIZE]; -} canio_can_state_t; diff --git a/ports/atmel-samd/common-hal/canio/CAN.c b/ports/atmel-samd/common-hal/canio/CAN.c new file mode 100644 index 000000000..01cc03dea --- /dev/null +++ b/ports/atmel-samd/common-hal/canio/CAN.c @@ -0,0 +1,445 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2020 Jeff Epler for Adafruit Industries + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include + +#include "py/runtime.h" +#include "py/mperrno.h" + +#include "peripheral_clk_config.h" + +#include "common-hal/canio/CAN.h" +#include "shared-bindings/microcontroller/Pin.h" +#include "shared-bindings/util.h" +#include "supervisor/port.h" + +#include "component/can.h" + +#include "genhdr/candata.h" + +STATIC Can * const can_insts[] = CAN_INSTS; + +STATIC canio_can_obj_t *can_objs[MP_ARRAY_SIZE(can_insts)]; + +// This must be placed in the first 64kB of RAM +STATIC COMPILER_SECTION(".canram") canio_can_state_t can_state[MP_ARRAY_SIZE(can_insts)]; + +void common_hal_canio_can_construct(canio_can_obj_t *self, mcu_pin_obj_t *tx, mcu_pin_obj_t *rx, int baudrate, bool loopback, bool silent) +{ + mcu_pin_function_t *tx_function = mcu_find_pin_function(can_tx, tx, -1, MP_QSTR_tx); + int instance = tx_function->instance; + + mcu_pin_function_t *rx_function = mcu_find_pin_function(can_rx, rx, instance, MP_QSTR_rx); + + const uint32_t can_frequency = CONF_CAN0_FREQUENCY; + +#define DIV_ROUND(a, b) (((a) + (b)/2) / (b)) +#define DIV_ROUND_UP(a, b) (((a) + (b) - 1) / (b)) + + uint32_t clocks_per_bit = DIV_ROUND(can_frequency, baudrate); + uint32_t clocks_to_sample = DIV_ROUND(clocks_per_bit * 7, 8); + uint32_t clocks_after_sample = clocks_per_bit - clocks_to_sample; + uint32_t divisor = MAX(DIV_ROUND_UP(clocks_to_sample, 256), DIV_ROUND_UP(clocks_after_sample, 128)); + if (divisor > 32) { + mp_raise_OSError(MP_EINVAL); // baudrate cannot be attained (16kHz or something is lower bound, should never happen) + } + + gpio_set_pin_direction(tx_function->pin, GPIO_DIRECTION_OUT); + gpio_set_pin_function(tx_function->pin, tx_function->function); + common_hal_never_reset_pin(tx_function->obj); + + gpio_set_pin_direction(rx_function->pin, GPIO_DIRECTION_IN); + gpio_set_pin_function(rx_function->pin, rx_function->function); + common_hal_never_reset_pin(rx_function->obj); + + self->tx_pin_number = tx ? common_hal_mcu_pin_number(tx) : COMMON_HAL_MCU_NO_PIN; + self->rx_pin_number = rx ? common_hal_mcu_pin_number(rx) : COMMON_HAL_MCU_NO_PIN; + self->hw = can_insts[instance]; + self->state = &can_state[instance]; + + self->loopback = loopback; + self->silent = silent; + + // Allow configuration change + hri_can_set_CCCR_INIT_bit(self->hw); + while (hri_can_get_CCCR_INIT_bit(self->hw) == 0) { + } + hri_can_set_CCCR_CCE_bit(self->hw); + + if (instance == 0) { + hri_mclk_set_AHBMASK_CAN0_bit(MCLK); + hri_gclk_write_PCHCTRL_reg(GCLK, CAN0_GCLK_ID, CONF_GCLK_CAN0_SRC | (1 << GCLK_PCHCTRL_CHEN_Pos)); + + NVIC_DisableIRQ(CAN0_IRQn); + NVIC_ClearPendingIRQ(CAN0_IRQn); + NVIC_EnableIRQ(CAN0_IRQn); + hri_can_write_ILE_reg(self->hw, CAN_ILE_EINT0); +#ifdef CAN1_GCLK_ID + } else if (instance == 1) { + hri_mclk_set_AHBMASK_CAN1_bit(MCLK); + hri_gclk_write_PCHCTRL_reg(GCLK, CAN1_GCLK_ID, CONF_GCLK_CAN1_SRC | (1 << GCLK_PCHCTRL_CHEN_Pos)); + + NVIC_DisableIRQ(CAN1_IRQn); + NVIC_ClearPendingIRQ(CAN1_IRQn); + NVIC_EnableIRQ(CAN1_IRQn); + hri_can_write_ILE_reg(self->hw, CAN_ILE_EINT0); +#endif + } + + self->hw->CCCR.bit.FDOE = 0; // neither FD nor Bit Rate Switch enabled + self->hw->CCCR.bit.BRSE = 0; + + hri_can_write_MRCFG_reg(self->hw, CAN_MRCFG_QOS(CAN_MRCFG_QOS_DISABLE_Val)); // QoS disabled (no sensitive operation) + + // A "nominal bit" is a header bit. With dual rate CAN FD, this is a slower rate + { + CAN_NBTP_Type btp = { + // 0 means "1 tq", but 2 is subtracted from NTSEG1 for the + // fixed 1 "SYNC" tq + .bit.NTSEG1 = DIV_ROUND(clocks_to_sample, divisor) - 2, + .bit.NTSEG2 = DIV_ROUND(clocks_after_sample, divisor) - 1, + .bit.NBRP = divisor - 1, + .bit.NSJW = DIV_ROUND(clocks_after_sample, divisor * 4), + }; + hri_can_write_NBTP_reg(self->hw, btp.reg); + } + + // A "data bit" is a data bit :) with dula rate CAN FD, this is a higher + // rate. However, CAN FD is not implemented in CircuitPython, and this is + // the same rate as the "nominal rate". + { + CAN_DBTP_Type btp = { + .bit.DTSEG1 = DIV_ROUND(clocks_to_sample, divisor) - 1, + .bit.DTSEG2 = DIV_ROUND(clocks_after_sample, divisor) - 1, + .bit.DBRP = divisor - 1, + .bit.DSJW = DIV_ROUND(clocks_after_sample, divisor * 4), + }; + hri_can_write_DBTP_reg(self->hw, btp.reg); + } + + { + CAN_RXF0C_Type rxf = { + .bit.F0SA = (uint32_t)self->state->rx0_fifo, + .bit.F0S = COMMON_HAL_CANIO_RX_FIFO_SIZE, + }; + hri_can_write_RXF0C_reg(self->hw, rxf.reg); + } + + { + CAN_RXF1C_Type rxf = { + .bit.F1SA = (uint32_t)self->state->rx1_fifo, + .bit.F1S = COMMON_HAL_CANIO_RX_FIFO_SIZE, + }; + hri_can_write_RXF1C_reg(self->hw, rxf.reg); + } + + // All RX data has an 8 byte payload (max) + { + CAN_RXESC_Type esc = { + .bit.F0DS = CAN_RXESC_F0DS_DATA8_Val, + .bit.F1DS = CAN_RXESC_F1DS_DATA8_Val, + .bit.RBDS = CAN_RXESC_RBDS_DATA8_Val, + }; + hri_can_write_RXESC_reg(self->hw, esc.reg); + } + + // All TX data has an 8 byte payload (max) + { + CAN_TXESC_Type esc = { + .bit.TBDS = CAN_TXESC_TBDS_DATA8_Val, + }; + hri_can_write_TXESC_reg(self->hw, esc.reg); + } + + { + CAN_TXBC_Type bc = { + .bit.TBSA = (uint32_t)self->state->tx_fifo, + .bit.NDTB = COMMON_HAL_CANIO_TX_FIFO_SIZE, + .bit.TFQM = 0, // Messages are transmitted in the order submitted + }; + hri_can_write_TXBC_reg(self->hw, bc.reg); + } + + { + CAN_TXEFC_Type efc = { + .bit.EFS = 0, + }; + hri_can_write_TXEFC_reg(self->hw, efc.reg); + } + + { + CAN_GFC_Type gfc = { + .bit.RRFE = 1, + .bit.ANFS = CAN_GFC_ANFS_REJECT_Val, + .bit.ANFE = CAN_GFC_ANFE_REJECT_Val, + }; + hri_can_write_GFC_reg(self->hw, gfc.reg); + } + + { + CAN_SIDFC_Type dfc = { + .bit.LSS = COMMON_HAL_CANIO_RX_FILTER_SIZE, + .bit.FLSSA = (uint32_t)self->state->standard_rx_filter + }; + hri_can_write_SIDFC_reg(self->hw, dfc.reg); + } + + { + CAN_XIDFC_Type dfc = { + .bit.LSE = COMMON_HAL_CANIO_RX_FILTER_SIZE, + .bit.FLESA = (uint32_t)self->state->extended_rx_filter + }; + hri_can_write_XIDFC_reg(self->hw, dfc.reg); + } + + { + CAN_IE_Type ie = { + .bit.EWE = 1, + .bit.EPE = 1, + .bit.BOE = 1, + }; + hri_can_write_IE_reg(self->hw, ie.reg); + } + + hri_can_write_XIDAM_reg(self->hw, CAN_XIDAM_RESETVALUE); + +// silent: The CAN is set in Bus Monitoring Mode by programming CCCR.MON to '1'. (tx pin unused) +// external loopback: The CAN can be set in External Loop Back Mode by programming TEST.LBCK and CCCR.MON to '1'. (rx pin unused) +// internal loopback (silent loopback): Internal Loop Back Mode is entered by programming bits TEST.LBCK and CCCR.MON to '1'. (tx, rx unused) + self->hw->CCCR.bit.MON = silent; + self->hw->CCCR.bit.TEST = loopback; + self->hw->TEST.bit.LBCK = loopback; + + if (instance == 0) { + NVIC_DisableIRQ(CAN0_IRQn); + NVIC_ClearPendingIRQ(CAN0_IRQn); + NVIC_EnableIRQ(CAN0_IRQn); +#ifdef CAN1_GCLK_ID + } else if (instance == 1) { + NVIC_DisableIRQ(CAN1_IRQn); + NVIC_ClearPendingIRQ(CAN1_IRQn); + NVIC_EnableIRQ(CAN1_IRQn); +#endif + } + + hri_can_write_ILE_reg(self->hw, CAN_ILE_EINT0); + // Prevent configuration change + hri_can_clear_CCCR_CCE_bit(self->hw); + hri_can_clear_CCCR_INIT_bit(self->hw); + while (hri_can_get_CCCR_INIT_bit(self->hw)) { + } + + can_objs[instance] = self; +} + +bool common_hal_canio_can_loopback_get(canio_can_obj_t *self) +{ + return self->loopback; +} + +int common_hal_canio_can_baudrate_get(canio_can_obj_t *self) +{ + return self->baudrate; +} + +int common_hal_canio_can_transmit_error_count_get(canio_can_obj_t *self) +{ + return self->hw->ECR.bit.TEC; +} + +int common_hal_canio_can_receive_error_count_get(canio_can_obj_t *self) +{ + return self->hw->ECR.bit.REC; +} + +int common_hal_canio_can_error_warning_state_count_get(canio_can_obj_t *self) +{ + return self->error_warning_state_count; +} + +int common_hal_canio_can_error_passive_state_count_get(canio_can_obj_t *self) +{ + return self->error_passive_state_count; +} + +int common_hal_canio_can_bus_off_state_count_get(canio_can_obj_t *self) +{ + return self->bus_off_state_count; +} + +canio_bus_state_t common_hal_canio_can_state_get(canio_can_obj_t *self) { + CAN_PSR_Type psr = self->hw->PSR; + if (psr.bit.BO) { + return BUS_STATE_OFF; + } + if (psr.bit.EP) { + return BUS_STATE_ERROR_PASSIVE; + } + if (psr.bit.EW) { + return BUS_STATE_ERROR_WARNING; + } + return BUS_STATE_ERROR_ACTIVE; +} + +void common_hal_canio_can_restart(canio_can_obj_t *self) { + if (!self->hw->PSR.bit.BO) { + return; + } + + hri_can_clear_CCCR_INIT_bit(self->hw); + while (hri_can_get_CCCR_INIT_bit(self->hw)) { + } +} + +bool common_hal_canio_can_auto_restart_get(canio_can_obj_t *self) { + return self->auto_restart; +} + +void common_hal_canio_can_auto_restart_set(canio_can_obj_t *self, bool value) { + self->auto_restart = value; +} + +static void maybe_auto_restart(canio_can_obj_t *self) { + if (self->auto_restart) { + common_hal_canio_can_restart(self); + } +} + +void common_hal_canio_can_send(canio_can_obj_t *self, canio_message_obj_t *message) +{ + maybe_auto_restart(self); + + // We have just one dedicated TX buffer, use it! + canio_can_fifo_t *ent = &self->state->tx_fifo[0]; + + ent->txb0.bit.ESI = false; + ent->txb0.bit.XTD = message->extended; + ent->txb0.bit.RTR = message->rtr; + if (message->extended) { + ent->txb0.bit.ID = message->id << 18; + } else { + ent->txb0.bit.ID = message->id << 18; // short addresses are left-justified + } + + ent->txb1.bit.MM = 0; // "message marker" + ent->txb1.bit.EFC = 0; // don't store fifo events to event queue + ent->txb1.bit.FDF = 0; // Classic CAN format + ent->txb1.bit.BRS = 0; // No bit rate switching + ent->txb1.bit.DLC = message->size; + + if (!message->rtr) { + memcpy(ent->data, message->data, message->size); + } + + // TX buffer add request + self->hw->TXBAR.reg = 1; + + // wait 8ms (hard coded for now) for TX to occur + uint64_t deadline = port_get_raw_ticks(NULL) + 8; + while (port_get_raw_ticks(NULL) < deadline && !(self->hw->TXBTO.reg & 1)) { + RUN_BACKGROUND_TASKS; + } +} + +bool common_hal_canio_can_silent_get(canio_can_obj_t *self) { + return self->silent; +} + +bool common_hal_canio_can_deinited(canio_can_obj_t *self) { + return !self->hw; +} + +void common_hal_canio_can_check_for_deinit(canio_can_obj_t *self) { + if (common_hal_canio_can_deinited(self)) { + raise_deinited_error(); + } +} + +void common_hal_canio_can_deinit(canio_can_obj_t *self) +{ + if (self->hw) { + hri_can_set_CCCR_INIT_bit(self->hw); + self->hw = 0; + } + if (self->rx_pin_number != COMMON_HAL_MCU_NO_PIN) { + reset_pin_number(self->rx_pin_number); + self->rx_pin_number = COMMON_HAL_MCU_NO_PIN; + } + if (self->tx_pin_number != COMMON_HAL_MCU_NO_PIN) { + reset_pin_number(self->tx_pin_number); + self->tx_pin_number = COMMON_HAL_MCU_NO_PIN; + } +} + +void common_hal_canio_reset(void) { + memset(can_state, 0, sizeof(can_state)); + + for (size_t i=0; ierror_warning_state_count += 1; + } + if (ir & CAN_IE_EPE) { + self->error_passive_state_count += 1; + } + if (ir & CAN_IE_BOE) { + self->bus_off_state_count += 1; + } + + /* Acknowledge interrupt */ + hri_can_write_IR_reg(hw, ir); +} + +__attribute__((used)) +void CAN0_Handler(void) { + can_handler(0); +} + +#ifdef CAN1_GCLK_ID +__attribute__((used)) +void CAN1_Handler(void) { + can_handler(1); +} +#endif diff --git a/ports/atmel-samd/common-hal/canio/CAN.h b/ports/atmel-samd/common-hal/canio/CAN.h new file mode 100644 index 000000000..cdea60e7d --- /dev/null +++ b/ports/atmel-samd/common-hal/canio/CAN.h @@ -0,0 +1,55 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2020 Jeff Epler for Adafruit Industries + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#pragma once + +#include "py/obj.h" +#include "shared-bindings/canio/__init__.h" +#include "shared-bindings/canio/CAN.h" +#include "component/can.h" +#include "common-hal/microcontroller/Pin.h" +#include "common-hal/canio/__init__.h" +#include "shared-module/canio/Message.h" + +#define COMMON_HAL_CAN_RX_FIFO_LEN (2) +#define COMMON_HAL_CAN_TX_FIFO_LEN (2) + +typedef struct canio_can_obj { + mp_obj_base_t base; + Can *hw; + canio_can_state_t *state; + volatile uint32_t error_warning_state_count; + volatile uint32_t error_passive_state_count; + volatile uint32_t bus_off_state_count; + int baudrate; + uint8_t rx_pin_number:8; + uint8_t tx_pin_number:8; + bool loopback:1; + bool silent:1; + bool auto_restart:1; + bool fifo0_in_use:1; + bool fifo1_in_use:1; +} canio_can_obj_t; diff --git a/ports/atmel-samd/common-hal/canio/Listener.c b/ports/atmel-samd/common-hal/canio/Listener.c new file mode 100644 index 000000000..bf8b3288d --- /dev/null +++ b/ports/atmel-samd/common-hal/canio/Listener.c @@ -0,0 +1,391 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2020 Jeff Epler for Adafruit Industries + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include + +#include "py/obj.h" +#include "py/runtime.h" + +#include "common-hal/canio/__init__.h" +#include "common-hal/canio/Listener.h" +#include "shared-bindings/util.h" +#include "supervisor/shared/tick.h" +#include "component/can.h" + +STATIC void allow_config_change(canio_can_obj_t *can) { + can->hw->CCCR.bit.INIT = 1; + while (!can->hw->CCCR.bit.INIT) { + } + can->hw->CCCR.bit.CCE = 1; +} + +STATIC void prevent_config_change(canio_can_obj_t *can) { + can->hw->CCCR.bit.CCE = 0; + can->hw->CCCR.bit.INIT = 0; + while (can->hw->CCCR.bit.INIT) { + } +} + +__attribute__((unused)) +STATIC void static_assertions(void) { + MP_STATIC_ASSERT(CAN_GFC_ANFE_RXF0_Val + 1 == CAN_GFC_ANFE_RXF1_Val); + MP_STATIC_ASSERT(CAN_GFC_ANFS_RXF0_Val + 1 == CAN_GFC_ANFS_RXF1_Val); + MP_STATIC_ASSERT(CAN_SIDFE_0_SFEC_STF0M_Val + 1 == CAN_SIDFE_0_SFEC_STF1M_Val); + MP_STATIC_ASSERT(CAN_XIDFE_0_EFEC_STF0M_Val + 1 == CAN_XIDFE_0_EFEC_STF1M_Val); +} + +STATIC bool single_address_filter(canio_match_obj_t *match) { + return match->mask == 0 || match->mask == match->address; +} + +STATIC bool standard_filter_in_use(CanMramSidfe *filter) { + return filter->SIDFE_0.bit.SFEC != CAN_SIDFE_0_SFEC_DISABLE_Val; +} + +STATIC bool extended_filter_in_use(CanMramXidfe *filter) { + return filter->XIDFE_0.bit.EFEC != CAN_XIDFE_0_EFEC_DISABLE_Val; +} + +STATIC size_t num_filters_needed(size_t nmatch, canio_match_obj_t **matches, bool extended) { + size_t num_half_filters_needed = 1; + for(size_t i=0; iextended) { + continue; + } + if (single_address_filter(matches[i])) { + num_half_filters_needed += 1; + } else { + num_half_filters_needed += 2; + } + } + return num_half_filters_needed / 2; +} + +STATIC size_t num_filters_available(canio_can_obj_t *can, bool extended) { + size_t available = 0; + if (extended) { + for(size_t i = 0; i < MP_ARRAY_SIZE(can->state->extended_rx_filter); i++) { + if (!extended_filter_in_use(&can->state->extended_rx_filter[i])) { + available++; + } + } + } else { + for(size_t i = 0; i < MP_ARRAY_SIZE(can->state->standard_rx_filter); i++) { + if (!standard_filter_in_use(&can->state->standard_rx_filter[i])) { + available++; + } + } + } + return available; +} + +STATIC void clear_filters(canio_listener_obj_t *self) { + canio_can_obj_t *can = self->can; + int fifo = self->fifo_idx; + + // If it was a global accept, clear it + allow_config_change(can); + if (can->hw->GFC.bit.ANFS == CAN_GFC_ANFS_RXF0 + fifo) { + can->hw->GFC.bit.ANFS = CAN_GFC_ANFS_REJECT_Val; + } + if (can->hw->GFC.bit.ANFE == CAN_GFC_ANFE_RXF0 + fifo) { + can->hw->GFC.bit.ANFE = CAN_GFC_ANFE_REJECT_Val; + } + prevent_config_change(can); + + // For each filter entry, if it pointed at this FIFO set it to DISABLE + for(size_t i = 0; i < MP_ARRAY_SIZE(can->state->extended_rx_filter); i++) { + int val = CAN_XIDFE_0_EFEC_STF0M_Val + fifo; + if (can->state->extended_rx_filter[i].XIDFE_0.bit.EFEC == val) { + can->state->extended_rx_filter[i].XIDFE_0.bit.EFEC = CAN_XIDFE_0_EFEC_DISABLE_Val; + } + } + for(size_t i = 0; i < MP_ARRAY_SIZE(can->state->standard_rx_filter); i++) { + int val = CAN_SIDFE_0_SFEC_STF1M_Val + fifo; + if (can->state->standard_rx_filter[i].SIDFE_0.bit.SFEC == val) { + can->state->standard_rx_filter[i].SIDFE_0.bit.SFEC = CAN_SIDFE_0_SFEC_DISABLE_Val; + } + } +} + +STATIC CanMramXidfe *next_extended_filter(canio_listener_obj_t *self, CanMramXidfe *start) { + CanMramXidfe *end = &self->can->state->extended_rx_filter[MP_ARRAY_SIZE(self->can->state->extended_rx_filter)]; + if (start == NULL) { + start = self->can->state->extended_rx_filter; + } else { + start = start + 1; + } + while (extended_filter_in_use(start)) { + if (start == end) { + return NULL; + } + start = start + 1; + } + return start; +} + +STATIC CanMramSidfe *next_standard_filter(canio_listener_obj_t *self, CanMramSidfe *start) { + CanMramSidfe *end = &self->can->state->standard_rx_filter[MP_ARRAY_SIZE(self->can->state->standard_rx_filter)]; + if (start == NULL) { + start = self->can->state->standard_rx_filter; + } else { + start = start + 1; + } + while (standard_filter_in_use(start)) { + if (start == end) { + return NULL; + } + start = start + 1; + } + return start; +} + +STATIC void install_standard_filter(CanMramSidfe *standard, int id1, int id2, int sfec, int sft) { + assert(standard); + CAN_SIDFE_0_Type val = { + .bit.SFID1 = id1, + .bit.SFID2 = id2, + .bit.SFEC = sfec, + .bit.SFT = sft, + }; + standard->SIDFE_0 = val; +} + +STATIC void install_extended_filter(CanMramXidfe *extended, int id1, int id2, int efec, int eft) { + assert(extended); + CAN_XIDFE_0_Type val0 = { + .bit.EFID1 = id1, + .bit.EFEC = efec, + }; + CAN_XIDFE_1_Type val1 = { + .bit.EFID2 = id2, + .bit.EFT = eft, + }; + // Set entry 0 second, because it has the enable bits (XIDFE_0_EFEC) + extended->XIDFE_1 = val1; + extended->XIDFE_0 = val0; +} + + +#define NO_ADDRESS (-1) +void set_filters(canio_listener_obj_t *self, size_t nmatch, canio_match_obj_t **matches) { + int fifo = self->fifo_idx; + + if (!nmatch) { + allow_config_change(self->can); + self->can->hw->GFC.bit.ANFS = CAN_GFC_ANFS_RXF0_Val + fifo; + self->can->hw->GFC.bit.ANFE = CAN_GFC_ANFE_RXF0_Val + fifo; + self->can->hw->CCCR.bit.CCE = 0; + prevent_config_change(self->can); + return; + } + + CanMramSidfe *standard = next_standard_filter(self, NULL); + CanMramXidfe *extended = next_extended_filter(self, NULL); + + int first_address = NO_ADDRESS; + + // step 1: single address standard matches + // we have to gather up pairs and stuff them in a single filter entry + for(size_t i = 0; iextended) { + continue; + } + if (!single_address_filter(match)) { + continue; + } + if (first_address != NO_ADDRESS) { + install_standard_filter(standard, first_address, match->address, CAN_SIDFE_0_SFEC_STF0M_Val + fifo, CAN_SIDFE_0_SFT_DUAL_Val); + first_address = NO_ADDRESS; + standard = next_standard_filter(self, standard); + } else { + first_address = match->address; + } + } + // step 1.5. odd single address standard match + if (first_address != NO_ADDRESS) { + install_standard_filter(standard, first_address, first_address, CAN_SIDFE_0_SFEC_STF0M_Val + fifo, CAN_SIDFE_0_SFT_DUAL_Val); + standard = next_standard_filter(self, standard); + first_address = NO_ADDRESS; + } + + // step 2: standard mask filter + for(size_t i = 0; iextended) { + continue; + } + if (single_address_filter(match)) { + continue; + } + install_standard_filter(standard, match->address, match->mask, CAN_SIDFE_0_SFEC_STF0M_Val + fifo, CAN_SIDFE_0_SFT_CLASSIC_Val); + standard = next_standard_filter(self, standard); + } + + // step 3: single address extended matches + // we have to gather up pairs and stuff them in a single filter entry + for(size_t i = 0; iextended) { + continue; + } + if (!single_address_filter(match)) { + continue; + } + if (first_address != NO_ADDRESS) { + install_extended_filter(extended, first_address, match->address, CAN_XIDFE_0_EFEC_STF0M_Val + fifo, CAN_XIDFE_1_EFT_DUAL_Val); + first_address = NO_ADDRESS; + extended = next_extended_filter(self, extended); + } else { + first_address = match->address; + } + } + // step 3.5. odd single address standard match + if (first_address != NO_ADDRESS) { + install_extended_filter(extended, first_address, first_address, CAN_XIDFE_0_EFEC_STF0M_Val + fifo, CAN_XIDFE_1_EFT_DUAL_Val); + extended = next_extended_filter(self, extended); + first_address = NO_ADDRESS; + } + + // step 4: extended mask filters + for(size_t i = 0; iextended) { + continue; + } + if (single_address_filter(match)) { + continue; + } + install_extended_filter(extended, match->address, match->mask, CAN_XIDFE_0_EFEC_STF0M_Val + fifo, CAN_XIDFE_1_EFT_CLASSIC_Val); + extended = next_extended_filter(self, extended); + } + + // phew, easy(!) +} + + +void common_hal_canio_listener_construct(canio_listener_obj_t *self, canio_can_obj_t *can, size_t nmatch, canio_match_obj_t **matches, float timeout) { + if (!can->fifo0_in_use) { + self->fifo_idx = 0; + self->fifo = can->state->rx0_fifo; + self->hw = (canio_rxfifo_reg_t*)&can->hw->RXF0C; + can->hw->IR.reg = CAN_IR_RF0N | CAN_IR_RF0W | CAN_IR_RF0F | CAN_IR_RF0L; + can->fifo0_in_use = true; + } else if (!can->fifo1_in_use) { + self->fifo_idx = 1; + self->fifo = can->state->rx1_fifo; + self->hw = (canio_rxfifo_reg_t*)&can->hw->RXF1C; + can->fifo1_in_use = true; + can->hw->IR.reg = CAN_IR_RF1N | CAN_IR_RF1W | CAN_IR_RF1F | CAN_IR_RF1L; + } else { + mp_raise_ValueError(translate("All RX FIFOs in use")); + } + + if (!nmatch) { + if (can->hw->GFC.bit.ANFS == CAN_GFC_ANFS_RXF1_Val - self->fifo_idx) { + mp_raise_ValueError(translate("Already have all-matches listener")); + } + if (can->hw->GFC.bit.ANFE == CAN_GFC_ANFE_RXF1_Val - self->fifo_idx) { + mp_raise_ValueError(translate("Already have all-matches listener")); + } + } + + if (num_filters_needed(nmatch, matches, false) > num_filters_available(can, false)) { + mp_raise_ValueError(translate("Filters too complex")); + } + + if (num_filters_needed(nmatch, matches, true) > num_filters_available(can, true)) { + mp_raise_ValueError(translate("Filters too complex")); + } + + // Nothing can fail now so it's safe to assign self->can + self->can = can; + set_filters(self, nmatch, matches); + common_hal_canio_listener_set_timeout(self, timeout); +} + +void common_hal_canio_listener_set_timeout(canio_listener_obj_t *self, float timeout) { + self->timeout_ms = (int)MICROPY_FLOAT_C_FUN(ceil)(timeout * 1000); +} + +float common_hal_canio_listener_get_timeout(canio_listener_obj_t *self) { + return self->timeout_ms / 1000.0f; +} + +void common_hal_canio_listener_check_for_deinit(canio_listener_obj_t *self) { + if (!self->can) { + raise_deinited_error(); + } + common_hal_canio_can_check_for_deinit(self->can); +} + +int common_hal_canio_listener_in_waiting(canio_listener_obj_t *self) { + return self->hw->RXFS.bit.F0FL; +} + +bool common_hal_canio_listener_readinto(canio_listener_obj_t *self, canio_message_obj_t *message) { + if (!common_hal_canio_listener_in_waiting(self)) { + uint64_t deadline = supervisor_ticks_ms64() + self->timeout_ms; + do { + if (supervisor_ticks_ms64() > deadline) { + return false; + } + } while (!common_hal_canio_listener_in_waiting(self)); + } + int index = self->hw->RXFS.bit.F0GI; + canio_can_fifo_t *hw_message = &self->fifo[index]; + message->extended = hw_message->rxb0.bit.XTD; + if (message->extended) { + message->id = hw_message->rxb0.bit.ID; + } else { + message->id = hw_message->rxb0.bit.ID >> 18; // short addresses are left-justified + } + message->rtr = hw_message->rxb0.bit.RTR; + message->size = hw_message->rxb1.bit.DLC; + if (!message->rtr) { + memcpy(message->data, hw_message->data, message->size); + } + self->hw->RXFA.bit.F0AI = index; + return true; +} + +void common_hal_canio_listener_deinit(canio_listener_obj_t *self) { + if (self->can) { + clear_filters(self); + if (self->fifo_idx == 0) { + self->can->fifo0_in_use = false; + } + if (self->fifo_idx == 1) { + self->can->fifo1_in_use = false; + } + } + self->fifo_idx = -1; + self->fifo = NULL; + self->can = NULL; + self->hw = NULL; +} diff --git a/ports/atmel-samd/common-hal/canio/Listener.h b/ports/atmel-samd/common-hal/canio/Listener.h new file mode 100644 index 000000000..a51a9fc37 --- /dev/null +++ b/ports/atmel-samd/common-hal/canio/Listener.h @@ -0,0 +1,53 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2020 Jeff Epler for Adafruit Industries + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#pragma once + +#include "common-hal/canio/CAN.h" +#include "shared-module/canio/Match.h" + +typedef struct { + __IO CAN_RXF0C_Type RXFC; /**< \brief (R/W 32) Rx FIFO n Configuration */ + __I CAN_RXF0S_Type RXFS; /**< \brief (R/ 32) Rx FIFO n Status */ + __IO CAN_RXF0A_Type RXFA; /**< \brief (R/W 32) Rx FIFO n Acknowledge */ +} canio_rxfifo_reg_t; + +typedef struct { + mp_obj_base_t base; + canio_can_obj_t *can; + canio_can_fifo_t *fifo; + canio_rxfifo_reg_t *hw; + uint32_t timeout_ms; + uint8_t fifo_idx; +} canio_listener_obj_t; + +void common_hal_canio_listener_construct(canio_listener_obj_t *self, canio_can_obj_t *can, size_t nmatch, canio_match_obj_t **matches, float timeout); +void common_hal_canio_listener_check_for_deinit(canio_listener_obj_t *self); +void common_hal_canio_listener_deinit(canio_listener_obj_t *self); +bool common_hal_canio_listener_readinto(canio_listener_obj_t *self, canio_message_obj_t *message); +int common_hal_canio_listener_in_waiting(canio_listener_obj_t *self); +float common_hal_canio_listener_get_timeout(canio_listener_obj_t *self); +void common_hal_canio_listener_set_timeout(canio_listener_obj_t *self, float timeout); diff --git a/ports/atmel-samd/common-hal/canio/__init__.c b/ports/atmel-samd/common-hal/canio/__init__.c new file mode 100644 index 000000000..7932bfc2d --- /dev/null +++ b/ports/atmel-samd/common-hal/canio/__init__.c @@ -0,0 +1,25 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2020 Jeff Epler for Adafruit Industries + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ diff --git a/ports/atmel-samd/common-hal/canio/__init__.h b/ports/atmel-samd/common-hal/canio/__init__.h new file mode 100644 index 000000000..cb491ab9e --- /dev/null +++ b/ports/atmel-samd/common-hal/canio/__init__.h @@ -0,0 +1,67 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2020 Jeff Epler for Adafruit Industries + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#pragma once + +#include "hal/utils/include/utils.h" +#include "component/can.h" + +#define COMMON_HAL_CANIO_MAX_MESSAGE_LENGTH (8) +#define COMMON_HAL_CANIO_RX_FIFO_SIZE (3) +#define COMMON_HAL_CANIO_RX_FILTER_SIZE (4) +#define COMMON_HAL_CANIO_TX_FIFO_SIZE (1) + +// This appears to be a typo (transposition error) in the ASF4 headers +// It's called the "Extended ID Filter Entry" +typedef CanMramXifde CanMramXidfe; + +typedef struct canio_listener canio_listener_t; +typedef struct canio_can canio_can_t; + +typedef struct { + union { + CAN_RXBE_0_Type rxb0; + CAN_TXBE_0_Type txb0; + CAN_RXF0E_0_Type rxf0; + }; + union { + CAN_RXBE_1_Type rxb1; + CAN_TXBE_1_Type txb1; + CAN_RXF0E_1_Type rxf1; + }; + COMPILER_ALIGNED(4) + uint8_t data[COMMON_HAL_CANIO_MAX_MESSAGE_LENGTH]; +} canio_can_fifo_t; + +typedef uint32_t canio_can_filter_t; + +typedef struct { + canio_can_fifo_t tx_fifo[COMMON_HAL_CANIO_TX_FIFO_SIZE]; + canio_can_fifo_t rx0_fifo[COMMON_HAL_CANIO_RX_FIFO_SIZE]; + canio_can_fifo_t rx1_fifo[COMMON_HAL_CANIO_RX_FIFO_SIZE]; + CanMramSidfe standard_rx_filter[COMMON_HAL_CANIO_RX_FILTER_SIZE]; + CanMramXifde extended_rx_filter[COMMON_HAL_CANIO_RX_FILTER_SIZE]; +} canio_can_state_t; diff --git a/py/circuitpy_defns.mk b/py/circuitpy_defns.mk index 2614dc011..98fa7a5f2 100644 --- a/py/circuitpy_defns.mk +++ b/py/circuitpy_defns.mk @@ -143,7 +143,7 @@ ifeq ($(CIRCUITPY_CAMERA),1) SRC_PATTERNS += camera/% endif ifeq ($(CIRCUITPY_CANIO),1) -SRC_PATTERNS += _canio/% +SRC_PATTERNS += canio/% endif ifeq ($(CIRCUITPY_COUNTIO),1) SRC_PATTERNS += countio/% @@ -318,9 +318,9 @@ SRC_COMMON_HAL_ALL = \ busio/__init__.c \ camera/__init__.c \ camera/Camera.c \ - _canio/CAN.c \ - _canio/Listener.c \ - _canio/__init__.c \ + canio/CAN.c \ + canio/Listener.c \ + canio/__init__.c \ countio/Counter.c \ countio/__init__.c \ digitalio/DigitalInOut.c \ @@ -390,7 +390,7 @@ $(filter $(SRC_PATTERNS), \ _bleio/Address.c \ _bleio/Attribute.c \ _bleio/ScanEntry.c \ - _canio/Match.c \ + canio/Match.c \ _eve/__init__.c \ camera/ImageFormat.c \ digitalio/Direction.c \ @@ -409,8 +409,8 @@ SRC_SHARED_MODULE_ALL = \ _bleio/Attribute.c \ _bleio/ScanEntry.c \ _bleio/ScanResults.c \ - _canio/Match.c \ - _canio/Message.c \ + canio/Match.c \ + canio/Message.c \ _eve/__init__.c \ _pixelbuf/PixelBuf.c \ _pixelbuf/__init__.c \ diff --git a/py/circuitpy_mpconfig.h b/py/circuitpy_mpconfig.h index d1b12f354..0583ae1c9 100644 --- a/py/circuitpy_mpconfig.h +++ b/py/circuitpy_mpconfig.h @@ -338,7 +338,7 @@ extern const struct _mp_obj_module_t camera_module; #if CIRCUITPY_CANIO extern const struct _mp_obj_module_t canio_module; -#define CANIO_MODULE { MP_OBJ_NEW_QSTR(MP_QSTR__canio), (mp_obj_t)&canio_module }, +#define CANIO_MODULE { MP_OBJ_NEW_QSTR(MP_QSTR_canio), (mp_obj_t)&canio_module }, #else #define CANIO_MODULE #endif diff --git a/shared-bindings/_canio/CAN.c b/shared-bindings/_canio/CAN.c deleted file mode 100644 index 38aed85d3..000000000 --- a/shared-bindings/_canio/CAN.c +++ /dev/null @@ -1,422 +0,0 @@ -/* - * This file is part of the MicroPython project, http://micropython.org/ - * - * The MIT License (MIT) - * - * Copyright (c) 2020 Jeff Epler for Adafruit Industries - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -#include "py/enum.h" -#include "common-hal/_canio/CAN.h" -#include "common-hal/_canio/Listener.h" -#include "shared-bindings/_canio/__init__.h" -#include "shared-bindings/_canio/CAN.h" -#include "shared-bindings/_canio/Listener.h" -#include "shared-bindings/_canio/Match.h" -#include "shared-bindings/_canio/Message.h" -#include "shared-bindings/microcontroller/Pin.h" - -#include "py/objproperty.h" -#include "py/runtime.h" - -//| -//| class CAN: -//| """CAN bus protocol""" -//| -//| def __init__(self, -//| tx: microcontroller.Pin, -//| rx: microcontroller.Pin, -//| *, -//| baudrate: int = 250000, -//| loopback: bool = False, -//| silent: bool = False, -//| auto_restart: bool = False, -//| ): -//| """A common shared-bus protocol. The rx and tx pins are generally -//| connected to a transceiver which controls the H and L pins on a -//| shared bus. -//| -//| :param ~microcontroller.Pin rx: the pin to receive with -//| :param ~microcontroller.Pin tx: the pin to transmit with -//| :param int baudrate: The bit rate of the bus in Hz. All devices on the bus must agree on this value. -//| :param bool loopback: When True the ``rx`` pin's value is ignored, and the device receives the packets it sends. -//| :param bool silent: When True the ``tx`` pin is always driven to the high logic level. This mode can be used to "sniff" a CAN bus without interfering. -//| :param bool auto_restart: If True, will restart communications after entering bus-off state -//| """ -//| ... -//| -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) { - enum { ARG_rx, ARG_tx, ARG_baudrate, ARG_loopback, ARG_silent, ARG_auto_restart, NUM_ARGS }; - static const mp_arg_t allowed_args[] = { - { MP_QSTR_tx, MP_ARG_OBJ | MP_ARG_REQUIRED }, - { MP_QSTR_rx, MP_ARG_OBJ | MP_ARG_REQUIRED }, - { MP_QSTR_baudrate, MP_ARG_INT, {.u_int = 250000} }, - { MP_QSTR_loopback, MP_ARG_BOOL, {.u_bool = false} }, - { MP_QSTR_silent, MP_ARG_BOOL, {.u_bool = false} }, - { MP_QSTR_auto_restart, MP_ARG_BOOL, {.u_bool = false} }, - }; - mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; - MP_STATIC_ASSERT( MP_ARRAY_SIZE(allowed_args) == NUM_ARGS ); - - mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); - - mcu_pin_obj_t *rx_pin = validate_obj_is_free_pin_or_none(args[ARG_rx].u_obj); - mcu_pin_obj_t *tx_pin = validate_obj_is_free_pin_or_none(args[ARG_tx].u_obj); - if (!rx_pin && !tx_pin) { - mp_raise_ValueError(translate("tx and rx cannot both be None")); - } - - canio_can_obj_t *self = m_new_obj(canio_can_obj_t); - self->base.type = &canio_can_type; - common_hal_canio_can_construct(self, tx_pin, rx_pin, args[ARG_baudrate].u_int, args[ARG_loopback].u_bool, args[ARG_silent].u_bool); - - common_hal_canio_can_auto_restart_set(self, args[ARG_auto_restart].u_bool); - - return MP_OBJ_FROM_PTR(self); -} - - -//| auto_restart: bool -//| """If True, will restart communications after entering bus-off state""" -//| -STATIC mp_obj_t canio_can_auto_restart_get(mp_obj_t self_in) { - canio_can_obj_t *self = MP_OBJ_TO_PTR(self_in); - common_hal_canio_can_check_for_deinit(self); - return mp_obj_new_bool(common_hal_canio_can_auto_restart_get(self)); -} -MP_DEFINE_CONST_FUN_OBJ_1(canio_can_auto_restart_get_obj, canio_can_auto_restart_get); - -STATIC mp_obj_t canio_can_auto_restart_set(mp_obj_t self_in, mp_obj_t flag_in) { - canio_can_obj_t *self = MP_OBJ_TO_PTR(self_in); - common_hal_canio_can_check_for_deinit(self); - common_hal_canio_can_auto_restart_set(self, mp_obj_is_true(flag_in)); - return mp_const_none; -} -MP_DEFINE_CONST_FUN_OBJ_2(canio_can_auto_restart_set_obj, canio_can_auto_restart_set); - -STATIC const mp_obj_property_t canio_can_auto_restart_obj = { - .base.type = &mp_type_property, - .proxy = {(mp_obj_t)&canio_can_auto_restart_get_obj, - (mp_obj_t)&canio_can_auto_restart_set_obj, - (mp_obj_t)mp_const_none}, -}; - - -//| baudrate: int -//| """The baud rate (read-only)""" -//| -STATIC mp_obj_t canio_can_baudrate_get(mp_obj_t self_in) { - canio_can_obj_t *self = MP_OBJ_TO_PTR(self_in); - common_hal_canio_can_check_for_deinit(self); - return MP_OBJ_NEW_SMALL_INT(common_hal_canio_can_baudrate_get(self)); -} -MP_DEFINE_CONST_FUN_OBJ_1(canio_can_baudrate_get_obj, canio_can_baudrate_get); - -STATIC const mp_obj_property_t canio_can_baudrate_obj = { - .base.type = &mp_type_property, - .proxy = {(mp_obj_t)&canio_can_baudrate_get_obj, - (mp_obj_t)mp_const_none, - (mp_obj_t)mp_const_none}, -}; - -//| transmit_error_count: int -//| """The number of transmit errors (read-only). Increased for a detected transmission error, decreased for successful transmission. Limited to the range from 0 to 255 inclusive. Also called TEC.""" -//| -STATIC mp_obj_t canio_can_transmit_error_count_get(mp_obj_t self_in) { - canio_can_obj_t *self = MP_OBJ_TO_PTR(self_in); - common_hal_canio_can_check_for_deinit(self); - return MP_OBJ_NEW_SMALL_INT(common_hal_canio_can_transmit_error_count_get(self)); -} -MP_DEFINE_CONST_FUN_OBJ_1(canio_can_transmit_error_count_get_obj, canio_can_transmit_error_count_get); - -STATIC const mp_obj_property_t canio_can_transmit_error_count_obj = { - .base.type = &mp_type_property, - .proxy = {(mp_obj_t)&canio_can_transmit_error_count_get_obj, - (mp_obj_t)mp_const_none, - (mp_obj_t)mp_const_none}, -}; - -//| receive_error_count: int -//| """The number of receive errors (read-only). Increased for a detected reception error, decreased for successful reception. Limited to the range from 0 to 255 inclusive. Also called REC.""" -//| -STATIC mp_obj_t canio_can_receive_error_count_get(mp_obj_t self_in) { - canio_can_obj_t *self = MP_OBJ_TO_PTR(self_in); - common_hal_canio_can_check_for_deinit(self); - return MP_OBJ_NEW_SMALL_INT(common_hal_canio_can_receive_error_count_get(self)); -} -MP_DEFINE_CONST_FUN_OBJ_1(canio_can_receive_error_count_get_obj, canio_can_receive_error_count_get); - -STATIC const mp_obj_property_t canio_can_receive_error_count_obj = { - .base.type = &mp_type_property, - .proxy = {(mp_obj_t)&canio_can_receive_error_count_get_obj, - (mp_obj_t)mp_const_none, - (mp_obj_t)mp_const_none}, -}; - -//| error_warning_state_count: int -//| """The number of times the controller enterted the Error Warning state (read-only). This number wraps around to 0 after an implementation-defined number of errors.""" -//| -STATIC mp_obj_t canio_can_error_warning_state_count_get(mp_obj_t self_in) { - canio_can_obj_t *self = MP_OBJ_TO_PTR(self_in); - common_hal_canio_can_check_for_deinit(self); - return MP_OBJ_NEW_SMALL_INT(common_hal_canio_can_error_warning_state_count_get(self)); -} -MP_DEFINE_CONST_FUN_OBJ_1(canio_can_error_warning_state_count_get_obj, canio_can_error_warning_state_count_get); - -STATIC const mp_obj_property_t canio_can_error_warning_state_count_obj = { - .base.type = &mp_type_property, - .proxy = {(mp_obj_t)&canio_can_error_warning_state_count_get_obj, - (mp_obj_t)mp_const_none, - (mp_obj_t)mp_const_none}, -}; - -//| error_passive_state_count: int -//| """The number of times the controller enterted the Error Passive state (read-only). This number wraps around to 0 after an implementation-defined number of errors.""" -//| -STATIC mp_obj_t canio_can_error_passive_state_count_get(mp_obj_t self_in) { - canio_can_obj_t *self = MP_OBJ_TO_PTR(self_in); - common_hal_canio_can_check_for_deinit(self); - return MP_OBJ_NEW_SMALL_INT(common_hal_canio_can_error_passive_state_count_get(self)); -} -MP_DEFINE_CONST_FUN_OBJ_1(canio_can_error_passive_state_count_get_obj, canio_can_error_passive_state_count_get); - -STATIC const mp_obj_property_t canio_can_error_passive_state_count_obj = { - .base.type = &mp_type_property, - .proxy = {(mp_obj_t)&canio_can_error_passive_state_count_get_obj, - (mp_obj_t)mp_const_none, - (mp_obj_t)mp_const_none}, -}; - -//| bus_off_state_count: int -//| """The number of times the controller enterted the Bus Off state (read-only). This number wraps around to 0 after an implementation-defined number of errors.""" -//| -STATIC mp_obj_t canio_can_bus_off_state_count_get(mp_obj_t self_in) { - canio_can_obj_t *self = MP_OBJ_TO_PTR(self_in); - common_hal_canio_can_check_for_deinit(self); - return MP_OBJ_NEW_SMALL_INT(common_hal_canio_can_bus_off_state_count_get(self)); -} -MP_DEFINE_CONST_FUN_OBJ_1(canio_can_bus_off_state_count_get_obj, canio_can_bus_off_state_count_get); - -STATIC const mp_obj_property_t canio_can_bus_off_state_count_obj = { - .base.type = &mp_type_property, - .proxy = {(mp_obj_t)&canio_can_bus_off_state_count_get_obj, - (mp_obj_t)mp_const_none, - (mp_obj_t)mp_const_none}, -}; - -//| state: State -//| """The current state of the bus.""" -STATIC mp_obj_t canio_can_state_get(mp_obj_t self_in) { - canio_can_obj_t *self = MP_OBJ_TO_PTR(self_in); - common_hal_canio_can_check_for_deinit(self); - return cp_enum_find(&canio_bus_state_type, common_hal_canio_can_state_get(self)); -} - -MP_DEFINE_CONST_FUN_OBJ_1(canio_can_state_get_obj, canio_can_state_get); - -STATIC const mp_obj_property_t canio_can_state_obj = { - .base.type = &mp_type_property, - .proxy = {(mp_obj_t)&canio_can_state_get_obj, - (mp_obj_t)mp_const_none, - (mp_obj_t)mp_const_none}, -}; - - -//| def restart(self) -> None: -//| """If the device is in the bus off state, restart it.""" -//| ... -//| -STATIC mp_obj_t canio_can_restart(mp_obj_t self_in) { - canio_can_obj_t *self = MP_OBJ_TO_PTR(self_in); - common_hal_canio_can_check_for_deinit(self); - common_hal_canio_can_restart(self); - return mp_const_none; -} -STATIC MP_DEFINE_CONST_FUN_OBJ_1(canio_can_restart_obj, canio_can_restart); - -//| def listen(self, match: Optional[Sequence[Match]]=None, *, timeout: float=10) -> Listener: -//| """Start receiving messages that match any one of the filters. -//| -//| Creating a listener is an expensive operation and can interfere with reception of messages by other listeners. -//| -//| There is an implementation-defined maximum number of listeners and limit to the complexity of the filters. -//| -//| If the hardware cannot support all the requested matches, a ValueError is raised. Note that generally there are some number of hardware filters shared among all fifos. -//| -//| A message can be received by at most one Listener. If more than one listener matches a message, it is undefined which one actually receives it. -//| -//| An empty filter list causes all messages to be accepted. -//| -//| Timeout dictates how long readinto, read and next() will block.""" -//| ... -//| -STATIC mp_obj_t canio_can_listen(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { - canio_can_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]); - common_hal_canio_can_check_for_deinit(self); - - enum { ARG_match, ARG_timeout, NUM_ARGS }; - static const mp_arg_t allowed_args[] = { - { MP_QSTR_match, MP_ARG_OBJ, {.u_obj = 0} }, - { MP_QSTR_timeout, MP_ARG_OBJ, {.u_obj = 0} }, - }; - mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; - MP_STATIC_ASSERT( MP_ARRAY_SIZE(allowed_args) == NUM_ARGS ); - - mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); - - size_t nmatch = 0; - mp_obj_t *match_objects = NULL; - - if (args[ARG_match].u_obj) { - mp_obj_get_array(args[ARG_match].u_obj, &nmatch, &match_objects); - } - - canio_match_obj_t *matches[nmatch]; - for (size_t i=0; iname); - } - matches[i] = MP_OBJ_TO_PTR(match_objects[i]); - } - - float timeout = args[ARG_timeout].u_obj ? mp_obj_get_float(args[ARG_timeout].u_obj) : 10.0f; - canio_listener_obj_t *listener = m_new_obj(canio_listener_obj_t); - listener->base.type = &canio_listener_type; - common_hal_canio_listener_construct(listener, self, nmatch, matches, timeout); - return listener; -} -MP_DEFINE_CONST_FUN_OBJ_KW(canio_can_listen_obj, 1, canio_can_listen); - -//| loopback: bool -//| """True if the device was created in loopback mode, False otherwise""" -//| -STATIC mp_obj_t canio_can_loopback_get(mp_obj_t self_in) { - canio_can_obj_t *self = MP_OBJ_TO_PTR(self_in); - common_hal_canio_can_check_for_deinit(self); - return mp_obj_new_bool(common_hal_canio_can_loopback_get(self)); -} -MP_DEFINE_CONST_FUN_OBJ_1(canio_can_loopback_get_obj, canio_can_loopback_get); - -STATIC const mp_obj_property_t canio_can_loopback_obj = { - .base.type = &mp_type_property, - .proxy = {(mp_obj_t)&canio_can_loopback_get_obj, - (mp_obj_t)mp_const_none, - (mp_obj_t)mp_const_none}, -}; - - -//| def send(message: Message) -> None: -//| """Send a message on the bus with the given data and id. -//| If the message could not be sent due to a full fifo or a bus error condition, RuntimeError is raised. -//| """ -//| ... -//| -STATIC mp_obj_t canio_can_send(mp_obj_t self_in, mp_obj_t message_in) { - canio_can_obj_t *self = MP_OBJ_TO_PTR(self_in); - common_hal_canio_can_check_for_deinit(self); - mp_obj_type_t *message_type = mp_obj_get_type(message_in); - if (message_type != &canio_message_type) { - mp_raise_TypeError_varg(translate("expected '%q' but got '%q'"), MP_QSTR_Message, message_type->name); - } - - canio_message_obj_t *message = message_in; - common_hal_canio_can_send(self, message); - return mp_const_none; -} -MP_DEFINE_CONST_FUN_OBJ_2(canio_can_send_obj, canio_can_send); - -//| silent: bool -//| """True if the device was created in silent mode, False otherwise""" -//| -STATIC mp_obj_t canio_can_silent_get(mp_obj_t self_in) { - canio_can_obj_t *self = MP_OBJ_TO_PTR(self_in); - common_hal_canio_can_check_for_deinit(self); - return mp_obj_new_bool(common_hal_canio_can_silent_get(self)); -} -MP_DEFINE_CONST_FUN_OBJ_1(canio_can_silent_get_obj, canio_can_silent_get); - -STATIC const mp_obj_property_t canio_can_silent_obj = { - .base.type = &mp_type_property, - .proxy = {(mp_obj_t)&canio_can_silent_get_obj, - (mp_obj_t)mp_const_none, - (mp_obj_t)mp_const_none}, -}; - - -//| def deinit(self) -> None: -//| """Deinitialize this object, freeing its hardware resources""" -//| ... -//| -STATIC mp_obj_t canio_can_deinit(mp_obj_t self_in) { - canio_can_obj_t *self = MP_OBJ_TO_PTR(self_in); - common_hal_canio_can_deinit(self); - return mp_const_none; -} -STATIC MP_DEFINE_CONST_FUN_OBJ_1(canio_can_deinit_obj, canio_can_deinit); - -//| def __enter__(self) -> CAN: -//| """Returns self, to allow the object to be used in a `with` statement for resource control""" -//| ... -//| -STATIC mp_obj_t canio_can_enter(mp_obj_t self_in) { - canio_can_obj_t *self = MP_OBJ_TO_PTR(self_in); - common_hal_canio_can_check_for_deinit(self); - return mp_const_none; -} -STATIC MP_DEFINE_CONST_FUN_OBJ_1(canio_can_enter_obj, canio_can_enter); - -//| def __exit__(self, unused1, unused2, unused3) -> None: -//| """Calls deinit()""" -//| ... -STATIC mp_obj_t canio_can_exit(size_t num_args, const mp_obj_t args[]) { - canio_can_obj_t *self = MP_OBJ_TO_PTR(args[0]); - common_hal_canio_can_deinit(self); - return mp_const_none; -} -STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(canio_can_exit_obj, 4, 4, canio_can_exit); - -STATIC const mp_rom_map_elem_t canio_can_locals_dict_table[] = { - { MP_ROM_QSTR(MP_QSTR___enter__), MP_ROM_PTR(&canio_can_enter_obj) }, - { MP_ROM_QSTR(MP_QSTR___exit__), MP_ROM_PTR(&canio_can_exit_obj) }, - { MP_ROM_QSTR(MP_QSTR_auto_restart), MP_ROM_PTR(&canio_can_auto_restart_obj) }, - { MP_ROM_QSTR(MP_QSTR_baudrate), MP_ROM_PTR(&canio_can_baudrate_obj) }, - { MP_ROM_QSTR(MP_QSTR_bus_off_state_count), MP_ROM_PTR(&canio_can_bus_off_state_count_obj) }, - { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&canio_can_deinit_obj) }, - { MP_ROM_QSTR(MP_QSTR_error_passive_state_count), MP_ROM_PTR(&canio_can_error_passive_state_count_obj) }, - { MP_ROM_QSTR(MP_QSTR_error_warning_state_count), MP_ROM_PTR(&canio_can_error_warning_state_count_obj) }, - { MP_ROM_QSTR(MP_QSTR_listen), MP_ROM_PTR(&canio_can_listen_obj) }, - { MP_ROM_QSTR(MP_QSTR_loopback), MP_ROM_PTR(&canio_can_loopback_obj) }, - { MP_ROM_QSTR(MP_QSTR_receive_error_count), MP_ROM_PTR(&canio_can_receive_error_count_obj) }, - { MP_ROM_QSTR(MP_QSTR_restart), MP_ROM_PTR(&canio_can_restart_obj) }, - { MP_ROM_QSTR(MP_QSTR_send), MP_ROM_PTR(&canio_can_send_obj) }, - { MP_ROM_QSTR(MP_QSTR_silent), MP_ROM_PTR(&canio_can_silent_obj) }, - { MP_ROM_QSTR(MP_QSTR_state), MP_ROM_PTR(&canio_can_state_obj) }, - { MP_ROM_QSTR(MP_QSTR_transmit_error_count), MP_ROM_PTR(&canio_can_transmit_error_count_obj) }, -}; -STATIC MP_DEFINE_CONST_DICT(canio_can_locals_dict, canio_can_locals_dict_table); - -const mp_obj_type_t canio_can_type = { - { &mp_type_type }, - .name = MP_QSTR_CAN, - .make_new = canio_can_make_new, - .locals_dict = (mp_obj_t)&canio_can_locals_dict, -}; diff --git a/shared-bindings/_canio/CAN.h b/shared-bindings/_canio/CAN.h deleted file mode 100644 index c591c8e6b..000000000 --- a/shared-bindings/_canio/CAN.h +++ /dev/null @@ -1,54 +0,0 @@ -/* - * This file is part of the MicroPython project, http://micropython.org/ - * - * The MIT License (MIT) - * - * Copyright (c) 2020 Jeff Epler for Adafruit Industries - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -#pragma once - -#include "py/obj.h" -#include "shared-bindings/microcontroller/Pin.h" -#include "shared-bindings/_canio/Message.h" - -extern const mp_obj_type_t canio_can_type; - -typedef struct canio_can_obj canio_can_obj_t; - -void common_hal_canio_can_construct(canio_can_obj_t *self, mcu_pin_obj_t *tx, mcu_pin_obj_t *rx, int baudrate, bool loopback, bool silent); -bool common_hal_canio_can_auto_restart_get(canio_can_obj_t *self); -bool common_hal_canio_can_deinited(canio_can_obj_t *self); -int common_hal_canio_can_baudrate_get(canio_can_obj_t *self); -int common_hal_canio_can_bus_off_state_count_get(canio_can_obj_t *self); -int common_hal_canio_can_error_passive_state_count_get(canio_can_obj_t *self); -int common_hal_canio_can_error_warning_state_count_get(canio_can_obj_t *self); -bool common_hal_canio_can_loopback_get(canio_can_obj_t *self); -int common_hal_canio_can_receive_error_count_get(canio_can_obj_t *self); -canio_bus_state_t common_hal_canio_can_state_get(canio_can_obj_t *self); -bool common_hal_canio_can_silent_get(canio_can_obj_t *self); -int common_hal_canio_can_transmit_error_count_get(canio_can_obj_t *self); -void common_hal_canio_can_auto_restart_set(canio_can_obj_t *self, bool auto_restart); -void common_hal_canio_can_check_for_deinit(canio_can_obj_t *self); -void common_hal_canio_can_deinit(canio_can_obj_t *self); -void common_hal_canio_can_restart(canio_can_obj_t *self); -void common_hal_canio_can_send(canio_can_obj_t *self, canio_message_obj_t *message); -void common_hal_canio_reset(void); diff --git a/shared-bindings/_canio/Listener.c b/shared-bindings/_canio/Listener.c deleted file mode 100644 index 6186f3bbd..000000000 --- a/shared-bindings/_canio/Listener.c +++ /dev/null @@ -1,193 +0,0 @@ -/* - * This file is part of the MicroPython project, http://micropython.org/ - * - * The MIT License (MIT) - * - * Copyright (c) 2020 Jeff Epler for Adafruit Industries - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -#include "shared-bindings/_canio/Listener.h" -#include "shared-bindings/_canio/Message.h" -#include "common-hal/_canio/Listener.h" - -#include "py/runtime.h" -#include "py/objproperty.h" - -//| class Listener: -//| """Listens for CAN message -//| -//| _canio.Listener is not constructed directly, but instead by calling the -//| Listen method of a _canio.CAN object.""" -//| - -//| def read(self) -> Optional[Message]: -//| """Reads a message, after waiting up to self.timeout seconds -//| -//| If no message is received in time, None is returned. Otherwise, -//| a Message is returned.""" -//| ... -//| -STATIC mp_obj_t canio_listener_read(mp_obj_t self_in) { - canio_listener_obj_t *self = MP_OBJ_TO_PTR(self_in); - common_hal_canio_listener_check_for_deinit(self); - - canio_message_obj_t *message = m_new_obj(canio_message_obj_t); - self->base.type = &canio_message_type; - - if (common_hal_canio_listener_readinto(self, message)) { - return message; - } else { - m_free(message); // message did not escape into vm - } - return mp_const_none; -} -STATIC MP_DEFINE_CONST_FUN_OBJ_1(canio_listener_read_obj, canio_listener_read); - -//| def readinto(self, message: Message) -> bool: -//| """Returns True (and modifies message) if a message was received -//| before ``timeout`` seconds elapsed, False otherwise.""" -//| ... -//| -STATIC mp_obj_t canio_listener_readinto(mp_obj_t self_in, mp_obj_t message) { - canio_listener_obj_t *self = MP_OBJ_TO_PTR(self_in); - mp_obj_type_t *type = mp_obj_get_type(message); - if (type != &canio_message_type) { - mp_raise_TypeError_varg(translate("expected '%q' but got '%q'"), MP_QSTR_Message, type->name); - } - common_hal_canio_listener_check_for_deinit(self); - return mp_obj_new_bool(common_hal_canio_listener_readinto(self, message)); -} -STATIC MP_DEFINE_CONST_FUN_OBJ_2(canio_listener_readinto_obj, canio_listener_readinto); - -//| def in_waiting(self) -> int: -//| """Returns the number of messages waiting""" -//| ... -//| -STATIC mp_obj_t canio_listener_in_waiting(mp_obj_t self_in) { - canio_listener_obj_t *self = MP_OBJ_TO_PTR(self_in); - common_hal_canio_listener_check_for_deinit(self); - return MP_OBJ_NEW_SMALL_INT(common_hal_canio_listener_in_waiting(self)); -} -STATIC MP_DEFINE_CONST_FUN_OBJ_1(canio_listener_in_waiting_obj, canio_listener_in_waiting); - -//| def __iter__(self): -//| """Returns self, unless the object is deinitialized""" -//| ... -//| -STATIC mp_obj_t canio_listener_iter(mp_obj_t self_in) { - canio_listener_obj_t *self = MP_OBJ_TO_PTR(self_in); - common_hal_canio_listener_check_for_deinit(self); - return self; -} -STATIC MP_DEFINE_CONST_FUN_OBJ_1(canio_listener_iter_obj, canio_listener_iter); - -//| def __next__(self): -//| """Reads a message, after waiting up to self.timeout seconds -//| -//| If no message is received in time, raises StopIteration. Otherwise, -//| a Message is returned.""" -//| ... -//| -STATIC mp_obj_t canio_listener_next(mp_obj_t self_in) { - mp_obj_t result = canio_listener_read(self_in); - if (result == mp_const_none) { - return MP_OBJ_STOP_ITERATION; - } - return result; -} -STATIC MP_DEFINE_CONST_FUN_OBJ_1(canio_listener_next_obj, canio_listener_next); - -//| def deinit(self) -> None: -//| """Deinitialize this object, freeing its hardware resources""" -//| ... -//| -STATIC mp_obj_t canio_listener_deinit(mp_obj_t self_in) { - canio_listener_obj_t *self = MP_OBJ_TO_PTR(self_in); - common_hal_canio_listener_deinit(self); - return mp_const_none; -} -STATIC MP_DEFINE_CONST_FUN_OBJ_1(canio_listener_deinit_obj, canio_listener_deinit); - -//| def __enter__(self) -> CAN: -//| """Returns self, to allow the object to be used in a `with` statement for resource control""" -//| ... -//| -STATIC mp_obj_t canio_listener_enter(mp_obj_t self_in) { - canio_listener_obj_t *self = MP_OBJ_TO_PTR(self_in); - common_hal_canio_listener_check_for_deinit(self); - return mp_const_none; -} -STATIC MP_DEFINE_CONST_FUN_OBJ_1(canio_listener_enter_obj, canio_listener_enter); - -//| def __exit__(self, unused1, unused2, unused3) -> None: -//| """Calls deinit()""" -//| ... -STATIC mp_obj_t canio_listener_exit(size_t num_args, const mp_obj_t args[]) { - canio_listener_obj_t *self = MP_OBJ_TO_PTR(args[0]); - common_hal_canio_listener_deinit(self); - return mp_const_none; -} -STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(canio_listener_exit_obj, 4, 4, canio_listener_exit); - - -//| timeout : float -STATIC mp_obj_t canio_listener_timeout_get(mp_obj_t self_in) { - canio_listener_obj_t *self = MP_OBJ_TO_PTR(self_in); - common_hal_canio_listener_check_for_deinit(self); - return mp_obj_new_float(common_hal_canio_listener_get_timeout(self)); -} -STATIC MP_DEFINE_CONST_FUN_OBJ_1(canio_listener_timeout_get_obj, canio_listener_timeout_get); - -STATIC mp_obj_t canio_listener_timeout_set(mp_obj_t self_in, mp_obj_t timeout_in) { - canio_listener_obj_t *self = MP_OBJ_TO_PTR(self_in); - common_hal_canio_listener_check_for_deinit(self); - common_hal_canio_listener_set_timeout(self, mp_obj_get_float(timeout_in)); - return mp_const_none; -} -STATIC MP_DEFINE_CONST_FUN_OBJ_2(canio_listener_timeout_set_obj, canio_listener_timeout_set); - -STATIC const mp_obj_property_t canio_listener_timeout_obj = { - .base.type = &mp_type_property, - .proxy = {(mp_obj_t)&canio_listener_timeout_get_obj, - (mp_obj_t)&canio_listener_timeout_set_obj, - (mp_obj_t)mp_const_none}, -}; - - - -STATIC const mp_rom_map_elem_t canio_listener_locals_dict_table[] = { - { MP_ROM_QSTR(MP_QSTR___enter__), MP_ROM_PTR(&canio_listener_enter_obj) }, - { MP_ROM_QSTR(MP_QSTR___exit__), MP_ROM_PTR(&canio_listener_exit_obj) }, - { MP_ROM_QSTR(MP_QSTR___iter__), MP_ROM_PTR(&canio_listener_iter_obj) }, - { MP_ROM_QSTR(MP_QSTR___next__), MP_ROM_PTR(&canio_listener_next_obj) }, - { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&canio_listener_deinit_obj) }, - { MP_ROM_QSTR(MP_QSTR_in_waiting), MP_ROM_PTR(&canio_listener_in_waiting_obj) }, - { MP_ROM_QSTR(MP_QSTR_read), MP_ROM_PTR(&canio_listener_read_obj) }, - { MP_ROM_QSTR(MP_QSTR_readinto), MP_ROM_PTR(&canio_listener_readinto_obj) }, - { MP_ROM_QSTR(MP_QSTR_timeout), MP_ROM_PTR(&canio_listener_timeout_obj) }, -}; -STATIC MP_DEFINE_CONST_DICT(canio_listener_locals_dict, canio_listener_locals_dict_table); - -const mp_obj_type_t canio_listener_type = { - { &mp_type_type }, - .name = MP_QSTR_Listener, - .locals_dict = (mp_obj_dict_t*)&canio_listener_locals_dict, -}; diff --git a/shared-bindings/_canio/Listener.h b/shared-bindings/_canio/Listener.h deleted file mode 100644 index eaa3490df..000000000 --- a/shared-bindings/_canio/Listener.h +++ /dev/null @@ -1,31 +0,0 @@ -/* - * This file is part of the MicroPython project, http://micropython.org/ - * - * The MIT License (MIT) - * - * Copyright (c) 2020 Jeff Epler for Adafruit Industries - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -#pragma once - -#include "py/obj.h" - -extern const mp_obj_type_t canio_listener_type; diff --git a/shared-bindings/_canio/Match.c b/shared-bindings/_canio/Match.c deleted file mode 100644 index 4ff35906b..000000000 --- a/shared-bindings/_canio/Match.c +++ /dev/null @@ -1,139 +0,0 @@ -/* - * This file is part of the MicroPython project, http://micropython.org/ - * - * The MIT License (MIT) - * - * Copyright (c) 2020 Jeff Epler for Adafruit Industries - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -#include "shared-bindings/_canio/Match.h" - -#include "py/objproperty.h" -#include "py/runtime.h" - -//| class Match: -//| """Describe CAN bus messages to match""" -//| -//| -//| def __init__(self, address: int, *, mask: int = 0, extended: bool = False): -//| """Construct a Match with the given properties. -//| -//| If mask is nonzero, then the filter is for any sender which matches all -//| the nonzero bits in mask. Otherwise, it matches exactly the given address. -//| If extended is true then only extended addresses are matched, otherwise -//| only standard addresses are matched.""" -//| - -STATIC mp_obj_t canio_match_make_new(const mp_obj_type_t *type, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { - enum { ARG_address, ARG_mask, ARG_extended, NUM_ARGS }; - static const mp_arg_t allowed_args[] = { - { MP_QSTR_address, MP_ARG_INT | MP_ARG_REQUIRED }, - { MP_QSTR_mask, MP_ARG_INT, {.u_int = 0} }, - { MP_QSTR_extended, MP_ARG_BOOL, {.u_bool = false} }, - }; - mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; - MP_STATIC_ASSERT( MP_ARRAY_SIZE(allowed_args) == NUM_ARGS ); - - mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); - - int address_bits = args[ARG_extended].u_bool ? 0x1fffffff : 0x7ff; - int address = args[ARG_address].u_int; - int mask = args[ARG_mask].u_int; - - if (address & ~address_bits) { - mp_raise_ValueError_varg(translate("%q out of range"), MP_QSTR_address); - } - - if (mask & ~address_bits) { - mp_raise_ValueError_varg(translate("%q out of range"), MP_QSTR_mask); - } - - canio_match_obj_t *self = m_new_obj(canio_match_obj_t); - self->base.type = &canio_match_type; - common_hal_canio_match_construct(self, args[ARG_address].u_int, args[ARG_mask].u_int, args[ARG_extended].u_bool); - return self; -} - -//| address: int -//| """The address to match""" -//| - -STATIC mp_obj_t canio_match_address_get(mp_obj_t self_in) { - canio_match_obj_t *self = self_in; - return MP_OBJ_NEW_SMALL_INT(common_hal_canio_match_get_address(self)); -} -MP_DEFINE_CONST_FUN_OBJ_1(canio_match_address_get_obj, canio_match_address_get); - -const mp_obj_property_t canio_match_address_obj = { - .base.type = &mp_type_property, - .proxy = {(mp_obj_t)&canio_match_address_get_obj, - (mp_obj_t)&mp_const_none_obj, - (mp_obj_t)&mp_const_none_obj}, -}; - -//| -//| mask: int -//| """The optional mask of addresses to match""" -//| - -STATIC mp_obj_t canio_match_mask_get(mp_obj_t self_in) { - canio_match_obj_t *self = self_in; - return MP_OBJ_NEW_SMALL_INT(common_hal_canio_match_get_mask(self)); -} -MP_DEFINE_CONST_FUN_OBJ_1(canio_match_mask_get_obj, canio_match_mask_get); - -const mp_obj_property_t canio_match_mask_obj = { - .base.type = &mp_type_property, - .proxy = {(mp_obj_t)&canio_match_mask_get_obj, - (mp_obj_t)&mp_const_none_obj, - (mp_obj_t)&mp_const_none_obj}, -}; - -//| extended: bool -//| """True to match extended addresses, False to match standard addresses""" -//| - -STATIC mp_obj_t canio_match_extended_get(mp_obj_t self_in) { - canio_match_obj_t *self = self_in; - return mp_obj_new_bool(common_hal_canio_match_get_extended(self)); -} -MP_DEFINE_CONST_FUN_OBJ_1(canio_match_extended_get_obj, canio_match_extended_get); - -const mp_obj_property_t canio_match_extended_obj = { - .base.type = &mp_type_property, - .proxy = {(mp_obj_t)&canio_match_extended_get_obj, - (mp_obj_t)&mp_const_none_obj, - (mp_obj_t)&mp_const_none_obj}, -}; - -STATIC const mp_rom_map_elem_t canio_match_locals_dict_table[] = { - { MP_ROM_QSTR(MP_QSTR_address), MP_ROM_PTR(&canio_match_address_obj) }, - { MP_ROM_QSTR(MP_QSTR_mask), MP_ROM_PTR(&canio_match_mask_obj) }, - { MP_ROM_QSTR(MP_QSTR_extended), MP_ROM_PTR(&canio_match_extended_obj) }, -}; -STATIC MP_DEFINE_CONST_DICT(canio_match_locals_dict, canio_match_locals_dict_table); - -const mp_obj_type_t canio_match_type = { - { &mp_type_type }, - .name = MP_QSTR_Match, - .make_new = canio_match_make_new, - .locals_dict = (mp_obj_dict_t*)&canio_match_locals_dict, -}; diff --git a/shared-bindings/_canio/Match.h b/shared-bindings/_canio/Match.h deleted file mode 100644 index 5522c2636..000000000 --- a/shared-bindings/_canio/Match.h +++ /dev/null @@ -1,37 +0,0 @@ -/* - * This file is part of the MicroPython project, http://micropython.org/ - * - * The MIT License (MIT) - * - * Copyright (c) 2020 Jeff Epler for Adafruit Industries - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -#pragma once - -#include "py/obj.h" -#include "shared-module/_canio/Match.h" - -extern const mp_obj_type_t canio_match_type; - -void common_hal_canio_match_construct(canio_match_obj_t *self, int address, int mask, bool extended); -int common_hal_canio_match_get_address(const canio_match_obj_t *self); -int common_hal_canio_match_get_mask(const canio_match_obj_t *self); -bool common_hal_canio_match_get_extended(const canio_match_obj_t *self); diff --git a/shared-bindings/_canio/Message.c b/shared-bindings/_canio/Message.c deleted file mode 100644 index 487ac9bfd..000000000 --- a/shared-bindings/_canio/Message.c +++ /dev/null @@ -1,212 +0,0 @@ -/* - * This file is part of the MicroPython project, http://micropython.org/ - * - * The MIT License (MIT) - * - * Copyright (c) 2020 Jeff Epler for Adafruit Industries - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -#include "shared-bindings/_canio/Message.h" - -#include "py/obj.h" -#include "py/objproperty.h" -#include "py/runtime.h" - -//| class Message: -//| def __init__(self, id: int=0, data: Optional[bytes] = None, *, size: Optional[int] = None, rtr: bool = False, extended: bool = False): -//| """Construct a Message to use with a CAN bus. Provide arguments to create a message to send. Otherwise, use Listener.readinto() to read a message. -//| -//| :param int id: The numeric ID of the message -//| :param bytes data: The content of the message -//| :param int size: The amount of data requested, for an rtr -//| :param bool rtr: True if the message represents an rtr (Remote Transmission Request) -//| :param bool extended: True if the message has an extended identifier, False if it has a standard identifier -//| -//| In CAN, messages can have a size from 0 to 8 bytes. -//| -//| For a non-rtr message, specify `data`. For an rtr-message, specify either `data` (a dummy buffer of the requested size) or `size`. -//| """ -//| ... -//| -STATIC mp_obj_t canio_message_make_new(const mp_obj_type_t *type, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { - enum { ARG_id, ARG_data, ARG_size, ARG_rtr, ARG_extended, NUM_ARGS }; - static const mp_arg_t allowed_args[] = { - { MP_QSTR_id, MP_ARG_INT, {.u_obj = 0} }, - { MP_QSTR_data, MP_ARG_OBJ, {.u_obj = 0} }, - { MP_QSTR_size, MP_ARG_INT, {.u_int = -1} }, - { MP_QSTR_rtr, MP_ARG_BOOL, {.u_bool = false} }, - { MP_QSTR_extended, MP_ARG_BOOL, {.u_bool = false} }, - }; - mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; - MP_STATIC_ASSERT( MP_ARRAY_SIZE(allowed_args) == NUM_ARGS ); - - mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); - - bool rtr = args[ARG_rtr].u_bool; - bool extended = args[ARG_extended].u_bool; - size_t size = (size_t)args[ARG_size].u_int; - bool specified_size = (size != (size_t)-1); - bool specified_data = (args[ARG_data].u_obj != NULL); - - if (specified_size && specified_data) { - mp_raise_TypeError(translate("specify size or data, but not both")); - } - - mp_buffer_info_t data; - if (specified_data) { - mp_get_buffer_raise(args[ARG_data].u_obj, &data, MP_BUFFER_READ); - } else if (specified_size) { - data.buf = 0; - data.len = size; - } else { - data.buf = 0; - data.len = 0; - } - - if (data.len > 8) { - mp_raise_ValueError(translate("Messages limited to 8 bytes")); - } - - canio_message_obj_t *self = m_new_obj(canio_message_obj_t); - self->base.type = &canio_message_type; - common_hal_canio_message_construct(self, args[ARG_id].u_int, data.buf, data.len, rtr, extended); - return self; -} - -//| id: int -//| """The numeric ID of the message""" -//| -STATIC mp_obj_t canio_message_id_get(const mp_obj_t self_in) { - canio_message_obj_t *self = self_in; - return MP_OBJ_NEW_SMALL_INT(common_hal_canio_message_get_id(self)); -} -MP_DEFINE_CONST_FUN_OBJ_1(canio_message_id_get_obj, canio_message_id_get); - -STATIC mp_obj_t canio_message_id_set(const mp_obj_t self_in, const mp_obj_t id) { - canio_message_obj_t *self = self_in; - common_hal_canio_message_set_id(self, mp_obj_get_int(id)); - return mp_const_none; -} -MP_DEFINE_CONST_FUN_OBJ_2(canio_message_id_set_obj, canio_message_id_set); - -STATIC const mp_obj_property_t canio_message_id_obj = { - .base.type = &mp_type_property, - .proxy = {(mp_obj_t)&canio_message_id_get_obj, - (mp_obj_t)&canio_message_id_set_obj, - (mp_obj_t)&mp_const_none_obj}, -}; - -//| data: bytes -//| """The content of the message, or dummy content in the case of an rtr. -//| -//| Assigning to data also sets the length and clears the rtr flag.""" -//| -STATIC mp_obj_t canio_message_data_get(const mp_obj_t self_in) { - canio_message_obj_t *self = self_in; - return mp_obj_new_bytes((const byte*)common_hal_canio_message_get_data(self), common_hal_canio_message_get_size(self)); -} -MP_DEFINE_CONST_FUN_OBJ_1(canio_message_data_get_obj, canio_message_data_get); - -STATIC mp_obj_t canio_message_data_set(const mp_obj_t self_in, const mp_obj_t data_in) { - canio_message_obj_t *self = self_in; - mp_buffer_info_t data; - mp_get_buffer_raise(data_in, &data, MP_BUFFER_READ); - if (data.len > 8) { - mp_raise_ValueError(translate("Messages limited to 8 bytes")); - } - common_hal_canio_message_set_data(self, data.buf, data.len); - return mp_const_none; -} -MP_DEFINE_CONST_FUN_OBJ_2(canio_message_data_set_obj, canio_message_data_set); - - -STATIC const mp_obj_property_t canio_message_data_obj = { - .base.type = &mp_type_property, - .proxy = {(mp_obj_t)&canio_message_data_get_obj, - (mp_obj_t)&canio_message_data_set_obj, - (mp_obj_t)&mp_const_none_obj}, -}; - - -//| extended: bool -//| """True if the message represents a remote transmission request (RTR)""" -//| -STATIC mp_obj_t canio_message_extended_get(const mp_obj_t self_in) { - canio_message_obj_t *self = self_in; - return mp_obj_new_bool(common_hal_canio_message_get_extended(self)); -} -MP_DEFINE_CONST_FUN_OBJ_1(canio_message_extended_get_obj, canio_message_extended_get); - -STATIC mp_obj_t canio_message_extended_set(const mp_obj_t self_in, const mp_obj_t extended) { - canio_message_obj_t *self = self_in; - common_hal_canio_message_set_extended(self, mp_obj_is_true(extended)); - return mp_const_none; -} -MP_DEFINE_CONST_FUN_OBJ_2(canio_message_extended_set_obj, canio_message_extended_set); - - -STATIC const mp_obj_property_t canio_message_extended_obj = { - .base.type = &mp_type_property, - .proxy = {(mp_obj_t)&canio_message_extended_get_obj, - (mp_obj_t)&canio_message_extended_set_obj, - (mp_obj_t)&mp_const_none_obj}, -}; - - -//| rtr: bool -//| """True if the message represents a remote transmission request (RTR). Setting rtr to true zeros out data""" -//| -STATIC mp_obj_t canio_message_rtr_get(const mp_obj_t self_in) { - canio_message_obj_t *self = self_in; - return mp_obj_new_bool(common_hal_canio_message_get_rtr(self)); -} -MP_DEFINE_CONST_FUN_OBJ_1(canio_message_rtr_get_obj, canio_message_rtr_get); - -STATIC mp_obj_t canio_message_rtr_set(const mp_obj_t self_in, const mp_obj_t rtr) { - canio_message_obj_t *self = self_in; - common_hal_canio_message_set_rtr(self, mp_obj_is_true(rtr)); - return mp_const_none; -} -MP_DEFINE_CONST_FUN_OBJ_2(canio_message_rtr_set_obj, canio_message_rtr_set); - - -STATIC const mp_obj_property_t canio_message_rtr_obj = { - .base.type = &mp_type_property, - .proxy = {(mp_obj_t)&canio_message_rtr_get_obj, - (mp_obj_t)&canio_message_rtr_set_obj, - (mp_obj_t)&mp_const_none_obj}, -}; - - -STATIC const mp_rom_map_elem_t canio_message_locals_dict_table[] = { - { MP_ROM_QSTR(MP_QSTR_id), MP_ROM_PTR(&canio_message_id_obj) }, - { MP_ROM_QSTR(MP_QSTR_data), MP_ROM_PTR(&canio_message_data_obj) }, - { MP_ROM_QSTR(MP_QSTR_rtr), MP_ROM_PTR(&canio_message_rtr_obj) }, - { MP_ROM_QSTR(MP_QSTR_extended), MP_ROM_PTR(&canio_message_extended_obj) }, -}; -STATIC MP_DEFINE_CONST_DICT(canio_message_locals_dict, canio_message_locals_dict_table); - -const mp_obj_type_t canio_message_type = { - { &mp_type_type }, - .name = MP_QSTR_Message, - .make_new = canio_message_make_new, - .locals_dict = (mp_obj_t)&canio_message_locals_dict, -}; diff --git a/shared-bindings/_canio/Message.h b/shared-bindings/_canio/Message.h deleted file mode 100644 index ed739af0d..000000000 --- a/shared-bindings/_canio/Message.h +++ /dev/null @@ -1,44 +0,0 @@ -/* - * This file is part of the MicroPython project, http://micropython.org/ - * - * The MIT License (MIT) - * - * Copyright (c) 2020 Jeff Epler for Adafruit Industries - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -#pragma once - -#include "py/obj.h" -#include "shared-module/_canio/Message.h" - -extern const mp_obj_type_t canio_message_type; - -void common_hal_canio_message_construct(canio_message_obj_t *self, int id, void *data, size_t size, bool rtr, bool extended); -const void *common_hal_canio_message_get_data(const canio_message_obj_t *self); -void common_hal_canio_message_set_data(canio_message_obj_t *self, const void *data, size_t size); -bool common_hal_canio_message_get_extended(const canio_message_obj_t *self); -void common_hal_canio_message_set_extended(canio_message_obj_t *self, bool extended); -int common_hal_canio_message_get_id(const canio_message_obj_t *self); -void common_hal_canio_message_set_id(canio_message_obj_t *self, int id); -bool common_hal_canio_message_get_rtr(const canio_message_obj_t *self); -void common_hal_canio_message_set_rtr(canio_message_obj_t *self, bool rtr); -size_t common_hal_canio_message_get_size(const canio_message_obj_t *self); -void common_hal_canio_message_set_size(canio_message_obj_t *self, size_t size); diff --git a/shared-bindings/_canio/__init__.c b/shared-bindings/_canio/__init__.c deleted file mode 100644 index 29e43c5c4..000000000 --- a/shared-bindings/_canio/__init__.c +++ /dev/null @@ -1,124 +0,0 @@ -/* - * This file is part of the MicroPython project, http://micropython.org/ - * - * The MIT License (MIT) - * - * Copyright (c) 2020 Jeff Epler for Adafruit Industries - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -//| """CAN bus access -//| -//| The `_canio` module contains low level classes to support the CAN bus -//| protocol. -//| -//| CAN and Listener classes change hardware state and should be deinitialized when they -//| are no longer needed if the program continues after use. To do so, either -//| call :py:meth:`!deinit` or use a context manager. See -//| :ref:`lifetime-and-contextmanagers` for more info. -//| -//| For example:: -//| -//| import _canio -//| from board import * -//| -//| can = _canio.CAN(board.CAN_RX, board.CAN_TX, baudrate=1000000) -//| message = _canio.Message(id=0x0408, data="adafruit" -//| can.write(message)) -//| can.deinit() -//| -//| This example will write the data 'adafruit' onto the CAN bus to any -//| device listening for message id 0x0408. -//| -//| A CAN bus involves a transceiver, which is often a separate chip with a "standby" pin. -//| If your board has a CAN_STANDBY pin, ensure to set it to an output with the value False -//| to enable the transceiver. -//| -//| Other implementations of the CAN device may exist (for instance, attached -//| via an SPI bus). If so their constructor arguments may differ, but -//| otherwise we encourage implementors to follow the API that the core uses. -//| """ -//| - -#include "py/obj.h" -#include "py/enum.h" - -#include "shared-bindings/_canio/__init__.h" -#include "shared-bindings/_canio/CAN.h" -#include "shared-bindings/_canio/Match.h" -#include "shared-bindings/_canio/Message.h" -#include "shared-bindings/_canio/Listener.h" - -MAKE_ENUM_VALUE(canio_bus_state_type, bus_state, ERROR_ACTIVE, BUS_STATE_ERROR_ACTIVE); -MAKE_ENUM_VALUE(canio_bus_state_type, bus_state, ERROR_PASSIVE, BUS_STATE_ERROR_PASSIVE); -MAKE_ENUM_VALUE(canio_bus_state_type, bus_state, ERROR_WARNING, BUS_STATE_ERROR_WARNING); -MAKE_ENUM_VALUE(canio_bus_state_type, bus_state, BUS_OFF, BUS_STATE_OFF); - -//| class BusState: -//| """The state of the CAN bus""" -//| -//| ERROR_ACTIVE: object -//| """The bus is in the normal (active) state""" -//| -//| ERROR_WARNING: object -//| """The bus is in the normal (active) state, but a moderate number of errors have occurred recently. -//| -//| NOTE: Not all implementations may use ERROR_WARNING. Do not rely on seeing ERROR_WARNING before ERROR_PASSIVE.""" -//| -//| ERROR_PASSIVE: object -//| """The bus is in the passive state due to the number of errors that have occurred recently. -//| -//| This device will acknowledge packets it receives, but cannot transmit messages. -//| If additional errors occur, this device may progress to BUS_OFF. -//| If it successfully acknowledges other packets on the bus, it can return to ERROR_WARNING or ERROR_ACTIVE and transmit packets. -//| """ -//| -//| BUS_OFF: object -//| """The bus has turned off due to the number of errors that have -//| occurred recently. It must be restarted before it will send or receive -//| packets. This device will neither send or acknowledge packets on the bus.""" -//| -MAKE_ENUM_MAP(canio_bus_state) { - MAKE_ENUM_MAP_ENTRY(bus_state, ERROR_ACTIVE), - MAKE_ENUM_MAP_ENTRY(bus_state, ERROR_PASSIVE), - MAKE_ENUM_MAP_ENTRY(bus_state, ERROR_WARNING), - MAKE_ENUM_MAP_ENTRY(bus_state, BUS_OFF), -}; -STATIC MP_DEFINE_CONST_DICT(canio_bus_state_locals_dict, canio_bus_state_locals_table); - -MAKE_PRINTER(_canio, canio_bus_state); - -MAKE_ENUM_TYPE(_canio, BusState, canio_bus_state); - -STATIC const mp_rom_map_elem_t canio_module_globals_table[] = { - { MP_ROM_QSTR(MP_QSTR_BusState), MP_ROM_PTR(&canio_bus_state_type) }, - { MP_ROM_QSTR(MP_QSTR_CAN), MP_ROM_PTR(&canio_can_type) }, - { MP_ROM_QSTR(MP_QSTR_Listener), MP_ROM_PTR(&canio_listener_type) }, - { MP_ROM_QSTR(MP_QSTR_Match), MP_ROM_PTR(&canio_match_type) }, - { MP_ROM_QSTR(MP_QSTR_Message), MP_ROM_PTR(&canio_message_type) }, - { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR__canio) }, -}; - -STATIC MP_DEFINE_CONST_DICT(canio_module_globals, canio_module_globals_table); - -const mp_obj_module_t canio_module = { - .base = { &mp_type_module }, - .globals = (mp_obj_dict_t*)&canio_module_globals, -}; diff --git a/shared-bindings/_canio/__init__.h b/shared-bindings/_canio/__init__.h deleted file mode 100644 index e24eba92c..000000000 --- a/shared-bindings/_canio/__init__.h +++ /dev/null @@ -1,33 +0,0 @@ -/* - * This file is part of the MicroPython project, http://micropython.org/ - * - * The MIT License (MIT) - * - * Copyright (c) 2020 Jeff Epler for Adafruit Industries - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -#pragma once - -typedef enum { - BUS_STATE_ERROR_ACTIVE, BUS_STATE_ERROR_PASSIVE, BUS_STATE_ERROR_WARNING, BUS_STATE_OFF -} canio_bus_state_t; - -extern const mp_obj_type_t canio_bus_state_type; diff --git a/shared-bindings/canio/CAN.c b/shared-bindings/canio/CAN.c new file mode 100644 index 000000000..482d11546 --- /dev/null +++ b/shared-bindings/canio/CAN.c @@ -0,0 +1,422 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2020 Jeff Epler for Adafruit Industries + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "py/enum.h" +#include "common-hal/canio/CAN.h" +#include "common-hal/canio/Listener.h" +#include "shared-bindings/canio/__init__.h" +#include "shared-bindings/canio/CAN.h" +#include "shared-bindings/canio/Listener.h" +#include "shared-bindings/canio/Match.h" +#include "shared-bindings/canio/Message.h" +#include "shared-bindings/microcontroller/Pin.h" + +#include "py/objproperty.h" +#include "py/runtime.h" + +//| +//| class CAN: +//| """CAN bus protocol""" +//| +//| def __init__(self, +//| tx: microcontroller.Pin, +//| rx: microcontroller.Pin, +//| *, +//| baudrate: int = 250000, +//| loopback: bool = False, +//| silent: bool = False, +//| auto_restart: bool = False, +//| ): +//| """A common shared-bus protocol. The rx and tx pins are generally +//| connected to a transceiver which controls the H and L pins on a +//| shared bus. +//| +//| :param ~microcontroller.Pin rx: the pin to receive with +//| :param ~microcontroller.Pin tx: the pin to transmit with +//| :param int baudrate: The bit rate of the bus in Hz. All devices on the bus must agree on this value. +//| :param bool loopback: When True the ``rx`` pin's value is ignored, and the device receives the packets it sends. +//| :param bool silent: When True the ``tx`` pin is always driven to the high logic level. This mode can be used to "sniff" a CAN bus without interfering. +//| :param bool auto_restart: If True, will restart communications after entering bus-off state +//| """ +//| ... +//| +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) { + enum { ARG_rx, ARG_tx, ARG_baudrate, ARG_loopback, ARG_silent, ARG_auto_restart, NUM_ARGS }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_tx, MP_ARG_OBJ | MP_ARG_REQUIRED }, + { MP_QSTR_rx, MP_ARG_OBJ | MP_ARG_REQUIRED }, + { MP_QSTR_baudrate, MP_ARG_INT, {.u_int = 250000} }, + { MP_QSTR_loopback, MP_ARG_BOOL, {.u_bool = false} }, + { MP_QSTR_silent, MP_ARG_BOOL, {.u_bool = false} }, + { MP_QSTR_auto_restart, MP_ARG_BOOL, {.u_bool = false} }, + }; + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + MP_STATIC_ASSERT( MP_ARRAY_SIZE(allowed_args) == NUM_ARGS ); + + mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + mcu_pin_obj_t *rx_pin = validate_obj_is_free_pin_or_none(args[ARG_rx].u_obj); + mcu_pin_obj_t *tx_pin = validate_obj_is_free_pin_or_none(args[ARG_tx].u_obj); + if (!rx_pin && !tx_pin) { + mp_raise_ValueError(translate("tx and rx cannot both be None")); + } + + canio_can_obj_t *self = m_new_obj(canio_can_obj_t); + self->base.type = &canio_can_type; + common_hal_canio_can_construct(self, tx_pin, rx_pin, args[ARG_baudrate].u_int, args[ARG_loopback].u_bool, args[ARG_silent].u_bool); + + common_hal_canio_can_auto_restart_set(self, args[ARG_auto_restart].u_bool); + + return MP_OBJ_FROM_PTR(self); +} + + +//| auto_restart: bool +//| """If True, will restart communications after entering bus-off state""" +//| +STATIC mp_obj_t canio_can_auto_restart_get(mp_obj_t self_in) { + canio_can_obj_t *self = MP_OBJ_TO_PTR(self_in); + common_hal_canio_can_check_for_deinit(self); + return mp_obj_new_bool(common_hal_canio_can_auto_restart_get(self)); +} +MP_DEFINE_CONST_FUN_OBJ_1(canio_can_auto_restart_get_obj, canio_can_auto_restart_get); + +STATIC mp_obj_t canio_can_auto_restart_set(mp_obj_t self_in, mp_obj_t flag_in) { + canio_can_obj_t *self = MP_OBJ_TO_PTR(self_in); + common_hal_canio_can_check_for_deinit(self); + common_hal_canio_can_auto_restart_set(self, mp_obj_is_true(flag_in)); + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_2(canio_can_auto_restart_set_obj, canio_can_auto_restart_set); + +STATIC const mp_obj_property_t canio_can_auto_restart_obj = { + .base.type = &mp_type_property, + .proxy = {(mp_obj_t)&canio_can_auto_restart_get_obj, + (mp_obj_t)&canio_can_auto_restart_set_obj, + (mp_obj_t)mp_const_none}, +}; + + +//| baudrate: int +//| """The baud rate (read-only)""" +//| +STATIC mp_obj_t canio_can_baudrate_get(mp_obj_t self_in) { + canio_can_obj_t *self = MP_OBJ_TO_PTR(self_in); + common_hal_canio_can_check_for_deinit(self); + return MP_OBJ_NEW_SMALL_INT(common_hal_canio_can_baudrate_get(self)); +} +MP_DEFINE_CONST_FUN_OBJ_1(canio_can_baudrate_get_obj, canio_can_baudrate_get); + +STATIC const mp_obj_property_t canio_can_baudrate_obj = { + .base.type = &mp_type_property, + .proxy = {(mp_obj_t)&canio_can_baudrate_get_obj, + (mp_obj_t)mp_const_none, + (mp_obj_t)mp_const_none}, +}; + +//| transmit_error_count: int +//| """The number of transmit errors (read-only). Increased for a detected transmission error, decreased for successful transmission. Limited to the range from 0 to 255 inclusive. Also called TEC.""" +//| +STATIC mp_obj_t canio_can_transmit_error_count_get(mp_obj_t self_in) { + canio_can_obj_t *self = MP_OBJ_TO_PTR(self_in); + common_hal_canio_can_check_for_deinit(self); + return MP_OBJ_NEW_SMALL_INT(common_hal_canio_can_transmit_error_count_get(self)); +} +MP_DEFINE_CONST_FUN_OBJ_1(canio_can_transmit_error_count_get_obj, canio_can_transmit_error_count_get); + +STATIC const mp_obj_property_t canio_can_transmit_error_count_obj = { + .base.type = &mp_type_property, + .proxy = {(mp_obj_t)&canio_can_transmit_error_count_get_obj, + (mp_obj_t)mp_const_none, + (mp_obj_t)mp_const_none}, +}; + +//| receive_error_count: int +//| """The number of receive errors (read-only). Increased for a detected reception error, decreased for successful reception. Limited to the range from 0 to 255 inclusive. Also called REC.""" +//| +STATIC mp_obj_t canio_can_receive_error_count_get(mp_obj_t self_in) { + canio_can_obj_t *self = MP_OBJ_TO_PTR(self_in); + common_hal_canio_can_check_for_deinit(self); + return MP_OBJ_NEW_SMALL_INT(common_hal_canio_can_receive_error_count_get(self)); +} +MP_DEFINE_CONST_FUN_OBJ_1(canio_can_receive_error_count_get_obj, canio_can_receive_error_count_get); + +STATIC const mp_obj_property_t canio_can_receive_error_count_obj = { + .base.type = &mp_type_property, + .proxy = {(mp_obj_t)&canio_can_receive_error_count_get_obj, + (mp_obj_t)mp_const_none, + (mp_obj_t)mp_const_none}, +}; + +//| error_warning_state_count: int +//| """The number of times the controller enterted the Error Warning state (read-only). This number wraps around to 0 after an implementation-defined number of errors.""" +//| +STATIC mp_obj_t canio_can_error_warning_state_count_get(mp_obj_t self_in) { + canio_can_obj_t *self = MP_OBJ_TO_PTR(self_in); + common_hal_canio_can_check_for_deinit(self); + return MP_OBJ_NEW_SMALL_INT(common_hal_canio_can_error_warning_state_count_get(self)); +} +MP_DEFINE_CONST_FUN_OBJ_1(canio_can_error_warning_state_count_get_obj, canio_can_error_warning_state_count_get); + +STATIC const mp_obj_property_t canio_can_error_warning_state_count_obj = { + .base.type = &mp_type_property, + .proxy = {(mp_obj_t)&canio_can_error_warning_state_count_get_obj, + (mp_obj_t)mp_const_none, + (mp_obj_t)mp_const_none}, +}; + +//| error_passive_state_count: int +//| """The number of times the controller enterted the Error Passive state (read-only). This number wraps around to 0 after an implementation-defined number of errors.""" +//| +STATIC mp_obj_t canio_can_error_passive_state_count_get(mp_obj_t self_in) { + canio_can_obj_t *self = MP_OBJ_TO_PTR(self_in); + common_hal_canio_can_check_for_deinit(self); + return MP_OBJ_NEW_SMALL_INT(common_hal_canio_can_error_passive_state_count_get(self)); +} +MP_DEFINE_CONST_FUN_OBJ_1(canio_can_error_passive_state_count_get_obj, canio_can_error_passive_state_count_get); + +STATIC const mp_obj_property_t canio_can_error_passive_state_count_obj = { + .base.type = &mp_type_property, + .proxy = {(mp_obj_t)&canio_can_error_passive_state_count_get_obj, + (mp_obj_t)mp_const_none, + (mp_obj_t)mp_const_none}, +}; + +//| bus_off_state_count: int +//| """The number of times the controller enterted the Bus Off state (read-only). This number wraps around to 0 after an implementation-defined number of errors.""" +//| +STATIC mp_obj_t canio_can_bus_off_state_count_get(mp_obj_t self_in) { + canio_can_obj_t *self = MP_OBJ_TO_PTR(self_in); + common_hal_canio_can_check_for_deinit(self); + return MP_OBJ_NEW_SMALL_INT(common_hal_canio_can_bus_off_state_count_get(self)); +} +MP_DEFINE_CONST_FUN_OBJ_1(canio_can_bus_off_state_count_get_obj, canio_can_bus_off_state_count_get); + +STATIC const mp_obj_property_t canio_can_bus_off_state_count_obj = { + .base.type = &mp_type_property, + .proxy = {(mp_obj_t)&canio_can_bus_off_state_count_get_obj, + (mp_obj_t)mp_const_none, + (mp_obj_t)mp_const_none}, +}; + +//| state: State +//| """The current state of the bus.""" +STATIC mp_obj_t canio_can_state_get(mp_obj_t self_in) { + canio_can_obj_t *self = MP_OBJ_TO_PTR(self_in); + common_hal_canio_can_check_for_deinit(self); + return cp_enum_find(&canio_bus_state_type, common_hal_canio_can_state_get(self)); +} + +MP_DEFINE_CONST_FUN_OBJ_1(canio_can_state_get_obj, canio_can_state_get); + +STATIC const mp_obj_property_t canio_can_state_obj = { + .base.type = &mp_type_property, + .proxy = {(mp_obj_t)&canio_can_state_get_obj, + (mp_obj_t)mp_const_none, + (mp_obj_t)mp_const_none}, +}; + + +//| def restart(self) -> None: +//| """If the device is in the bus off state, restart it.""" +//| ... +//| +STATIC mp_obj_t canio_can_restart(mp_obj_t self_in) { + canio_can_obj_t *self = MP_OBJ_TO_PTR(self_in); + common_hal_canio_can_check_for_deinit(self); + common_hal_canio_can_restart(self); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(canio_can_restart_obj, canio_can_restart); + +//| def listen(self, match: Optional[Sequence[Match]]=None, *, timeout: float=10) -> Listener: +//| """Start receiving messages that match any one of the filters. +//| +//| Creating a listener is an expensive operation and can interfere with reception of messages by other listeners. +//| +//| There is an implementation-defined maximum number of listeners and limit to the complexity of the filters. +//| +//| If the hardware cannot support all the requested matches, a ValueError is raised. Note that generally there are some number of hardware filters shared among all fifos. +//| +//| A message can be received by at most one Listener. If more than one listener matches a message, it is undefined which one actually receives it. +//| +//| An empty filter list causes all messages to be accepted. +//| +//| Timeout dictates how long readinto, read and next() will block.""" +//| ... +//| +STATIC mp_obj_t canio_can_listen(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + canio_can_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]); + common_hal_canio_can_check_for_deinit(self); + + enum { ARG_match, ARG_timeout, NUM_ARGS }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_match, MP_ARG_OBJ, {.u_obj = 0} }, + { MP_QSTR_timeout, MP_ARG_OBJ, {.u_obj = 0} }, + }; + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + MP_STATIC_ASSERT( MP_ARRAY_SIZE(allowed_args) == NUM_ARGS ); + + mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + size_t nmatch = 0; + mp_obj_t *match_objects = NULL; + + if (args[ARG_match].u_obj) { + mp_obj_get_array(args[ARG_match].u_obj, &nmatch, &match_objects); + } + + canio_match_obj_t *matches[nmatch]; + for (size_t i=0; iname); + } + matches[i] = MP_OBJ_TO_PTR(match_objects[i]); + } + + float timeout = args[ARG_timeout].u_obj ? mp_obj_get_float(args[ARG_timeout].u_obj) : 10.0f; + canio_listener_obj_t *listener = m_new_obj(canio_listener_obj_t); + listener->base.type = &canio_listener_type; + common_hal_canio_listener_construct(listener, self, nmatch, matches, timeout); + return listener; +} +MP_DEFINE_CONST_FUN_OBJ_KW(canio_can_listen_obj, 1, canio_can_listen); + +//| loopback: bool +//| """True if the device was created in loopback mode, False otherwise""" +//| +STATIC mp_obj_t canio_can_loopback_get(mp_obj_t self_in) { + canio_can_obj_t *self = MP_OBJ_TO_PTR(self_in); + common_hal_canio_can_check_for_deinit(self); + return mp_obj_new_bool(common_hal_canio_can_loopback_get(self)); +} +MP_DEFINE_CONST_FUN_OBJ_1(canio_can_loopback_get_obj, canio_can_loopback_get); + +STATIC const mp_obj_property_t canio_can_loopback_obj = { + .base.type = &mp_type_property, + .proxy = {(mp_obj_t)&canio_can_loopback_get_obj, + (mp_obj_t)mp_const_none, + (mp_obj_t)mp_const_none}, +}; + + +//| def send(message: Message) -> None: +//| """Send a message on the bus with the given data and id. +//| If the message could not be sent due to a full fifo or a bus error condition, RuntimeError is raised. +//| """ +//| ... +//| +STATIC mp_obj_t canio_can_send(mp_obj_t self_in, mp_obj_t message_in) { + canio_can_obj_t *self = MP_OBJ_TO_PTR(self_in); + common_hal_canio_can_check_for_deinit(self); + mp_obj_type_t *message_type = mp_obj_get_type(message_in); + if (message_type != &canio_message_type) { + mp_raise_TypeError_varg(translate("expected '%q' but got '%q'"), MP_QSTR_Message, message_type->name); + } + + canio_message_obj_t *message = message_in; + common_hal_canio_can_send(self, message); + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_2(canio_can_send_obj, canio_can_send); + +//| silent: bool +//| """True if the device was created in silent mode, False otherwise""" +//| +STATIC mp_obj_t canio_can_silent_get(mp_obj_t self_in) { + canio_can_obj_t *self = MP_OBJ_TO_PTR(self_in); + common_hal_canio_can_check_for_deinit(self); + return mp_obj_new_bool(common_hal_canio_can_silent_get(self)); +} +MP_DEFINE_CONST_FUN_OBJ_1(canio_can_silent_get_obj, canio_can_silent_get); + +STATIC const mp_obj_property_t canio_can_silent_obj = { + .base.type = &mp_type_property, + .proxy = {(mp_obj_t)&canio_can_silent_get_obj, + (mp_obj_t)mp_const_none, + (mp_obj_t)mp_const_none}, +}; + + +//| def deinit(self) -> None: +//| """Deinitialize this object, freeing its hardware resources""" +//| ... +//| +STATIC mp_obj_t canio_can_deinit(mp_obj_t self_in) { + canio_can_obj_t *self = MP_OBJ_TO_PTR(self_in); + common_hal_canio_can_deinit(self); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(canio_can_deinit_obj, canio_can_deinit); + +//| def __enter__(self) -> CAN: +//| """Returns self, to allow the object to be used in a `with` statement for resource control""" +//| ... +//| +STATIC mp_obj_t canio_can_enter(mp_obj_t self_in) { + canio_can_obj_t *self = MP_OBJ_TO_PTR(self_in); + common_hal_canio_can_check_for_deinit(self); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(canio_can_enter_obj, canio_can_enter); + +//| def __exit__(self, unused1, unused2, unused3) -> None: +//| """Calls deinit()""" +//| ... +STATIC mp_obj_t canio_can_exit(size_t num_args, const mp_obj_t args[]) { + canio_can_obj_t *self = MP_OBJ_TO_PTR(args[0]); + common_hal_canio_can_deinit(self); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(canio_can_exit_obj, 4, 4, canio_can_exit); + +STATIC const mp_rom_map_elem_t canio_can_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR___enter__), MP_ROM_PTR(&canio_can_enter_obj) }, + { MP_ROM_QSTR(MP_QSTR___exit__), MP_ROM_PTR(&canio_can_exit_obj) }, + { MP_ROM_QSTR(MP_QSTR_auto_restart), MP_ROM_PTR(&canio_can_auto_restart_obj) }, + { MP_ROM_QSTR(MP_QSTR_baudrate), MP_ROM_PTR(&canio_can_baudrate_obj) }, + { MP_ROM_QSTR(MP_QSTR_bus_off_state_count), MP_ROM_PTR(&canio_can_bus_off_state_count_obj) }, + { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&canio_can_deinit_obj) }, + { MP_ROM_QSTR(MP_QSTR_error_passive_state_count), MP_ROM_PTR(&canio_can_error_passive_state_count_obj) }, + { MP_ROM_QSTR(MP_QSTR_error_warning_state_count), MP_ROM_PTR(&canio_can_error_warning_state_count_obj) }, + { MP_ROM_QSTR(MP_QSTR_listen), MP_ROM_PTR(&canio_can_listen_obj) }, + { MP_ROM_QSTR(MP_QSTR_loopback), MP_ROM_PTR(&canio_can_loopback_obj) }, + { MP_ROM_QSTR(MP_QSTR_receive_error_count), MP_ROM_PTR(&canio_can_receive_error_count_obj) }, + { MP_ROM_QSTR(MP_QSTR_restart), MP_ROM_PTR(&canio_can_restart_obj) }, + { MP_ROM_QSTR(MP_QSTR_send), MP_ROM_PTR(&canio_can_send_obj) }, + { MP_ROM_QSTR(MP_QSTR_silent), MP_ROM_PTR(&canio_can_silent_obj) }, + { MP_ROM_QSTR(MP_QSTR_state), MP_ROM_PTR(&canio_can_state_obj) }, + { MP_ROM_QSTR(MP_QSTR_transmit_error_count), MP_ROM_PTR(&canio_can_transmit_error_count_obj) }, +}; +STATIC MP_DEFINE_CONST_DICT(canio_can_locals_dict, canio_can_locals_dict_table); + +const mp_obj_type_t canio_can_type = { + { &mp_type_type }, + .name = MP_QSTR_CAN, + .make_new = canio_can_make_new, + .locals_dict = (mp_obj_t)&canio_can_locals_dict, +}; diff --git a/shared-bindings/canio/CAN.h b/shared-bindings/canio/CAN.h new file mode 100644 index 000000000..66c972c28 --- /dev/null +++ b/shared-bindings/canio/CAN.h @@ -0,0 +1,54 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2020 Jeff Epler for Adafruit Industries + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#pragma once + +#include "py/obj.h" +#include "shared-bindings/microcontroller/Pin.h" +#include "shared-bindings/canio/Message.h" + +extern const mp_obj_type_t canio_can_type; + +typedef struct canio_can_obj canio_can_obj_t; + +void common_hal_canio_can_construct(canio_can_obj_t *self, mcu_pin_obj_t *tx, mcu_pin_obj_t *rx, int baudrate, bool loopback, bool silent); +bool common_hal_canio_can_auto_restart_get(canio_can_obj_t *self); +bool common_hal_canio_can_deinited(canio_can_obj_t *self); +int common_hal_canio_can_baudrate_get(canio_can_obj_t *self); +int common_hal_canio_can_bus_off_state_count_get(canio_can_obj_t *self); +int common_hal_canio_can_error_passive_state_count_get(canio_can_obj_t *self); +int common_hal_canio_can_error_warning_state_count_get(canio_can_obj_t *self); +bool common_hal_canio_can_loopback_get(canio_can_obj_t *self); +int common_hal_canio_can_receive_error_count_get(canio_can_obj_t *self); +canio_bus_state_t common_hal_canio_can_state_get(canio_can_obj_t *self); +bool common_hal_canio_can_silent_get(canio_can_obj_t *self); +int common_hal_canio_can_transmit_error_count_get(canio_can_obj_t *self); +void common_hal_canio_can_auto_restart_set(canio_can_obj_t *self, bool auto_restart); +void common_hal_canio_can_check_for_deinit(canio_can_obj_t *self); +void common_hal_canio_can_deinit(canio_can_obj_t *self); +void common_hal_canio_can_restart(canio_can_obj_t *self); +void common_hal_canio_can_send(canio_can_obj_t *self, canio_message_obj_t *message); +void common_hal_canio_reset(void); diff --git a/shared-bindings/canio/Listener.c b/shared-bindings/canio/Listener.c new file mode 100644 index 000000000..0b50e5835 --- /dev/null +++ b/shared-bindings/canio/Listener.c @@ -0,0 +1,193 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2020 Jeff Epler for Adafruit Industries + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "shared-bindings/canio/Listener.h" +#include "shared-bindings/canio/Message.h" +#include "common-hal/canio/Listener.h" + +#include "py/runtime.h" +#include "py/objproperty.h" + +//| class Listener: +//| """Listens for CAN message +//| +//| _canio.Listener is not constructed directly, but instead by calling the +//| Listen method of a _canio.CAN object.""" +//| + +//| def read(self) -> Optional[Message]: +//| """Reads a message, after waiting up to self.timeout seconds +//| +//| If no message is received in time, None is returned. Otherwise, +//| a Message is returned.""" +//| ... +//| +STATIC mp_obj_t canio_listener_read(mp_obj_t self_in) { + canio_listener_obj_t *self = MP_OBJ_TO_PTR(self_in); + common_hal_canio_listener_check_for_deinit(self); + + canio_message_obj_t *message = m_new_obj(canio_message_obj_t); + self->base.type = &canio_message_type; + + if (common_hal_canio_listener_readinto(self, message)) { + return message; + } else { + m_free(message); // message did not escape into vm + } + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(canio_listener_read_obj, canio_listener_read); + +//| def readinto(self, message: Message) -> bool: +//| """Returns True (and modifies message) if a message was received +//| before ``timeout`` seconds elapsed, False otherwise.""" +//| ... +//| +STATIC mp_obj_t canio_listener_readinto(mp_obj_t self_in, mp_obj_t message) { + canio_listener_obj_t *self = MP_OBJ_TO_PTR(self_in); + mp_obj_type_t *type = mp_obj_get_type(message); + if (type != &canio_message_type) { + mp_raise_TypeError_varg(translate("expected '%q' but got '%q'"), MP_QSTR_Message, type->name); + } + common_hal_canio_listener_check_for_deinit(self); + return mp_obj_new_bool(common_hal_canio_listener_readinto(self, message)); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(canio_listener_readinto_obj, canio_listener_readinto); + +//| def in_waiting(self) -> int: +//| """Returns the number of messages waiting""" +//| ... +//| +STATIC mp_obj_t canio_listener_in_waiting(mp_obj_t self_in) { + canio_listener_obj_t *self = MP_OBJ_TO_PTR(self_in); + common_hal_canio_listener_check_for_deinit(self); + return MP_OBJ_NEW_SMALL_INT(common_hal_canio_listener_in_waiting(self)); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(canio_listener_in_waiting_obj, canio_listener_in_waiting); + +//| def __iter__(self): +//| """Returns self, unless the object is deinitialized""" +//| ... +//| +STATIC mp_obj_t canio_listener_iter(mp_obj_t self_in) { + canio_listener_obj_t *self = MP_OBJ_TO_PTR(self_in); + common_hal_canio_listener_check_for_deinit(self); + return self; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(canio_listener_iter_obj, canio_listener_iter); + +//| def __next__(self): +//| """Reads a message, after waiting up to self.timeout seconds +//| +//| If no message is received in time, raises StopIteration. Otherwise, +//| a Message is returned.""" +//| ... +//| +STATIC mp_obj_t canio_listener_next(mp_obj_t self_in) { + mp_obj_t result = canio_listener_read(self_in); + if (result == mp_const_none) { + return MP_OBJ_STOP_ITERATION; + } + return result; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(canio_listener_next_obj, canio_listener_next); + +//| def deinit(self) -> None: +//| """Deinitialize this object, freeing its hardware resources""" +//| ... +//| +STATIC mp_obj_t canio_listener_deinit(mp_obj_t self_in) { + canio_listener_obj_t *self = MP_OBJ_TO_PTR(self_in); + common_hal_canio_listener_deinit(self); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(canio_listener_deinit_obj, canio_listener_deinit); + +//| def __enter__(self) -> CAN: +//| """Returns self, to allow the object to be used in a `with` statement for resource control""" +//| ... +//| +STATIC mp_obj_t canio_listener_enter(mp_obj_t self_in) { + canio_listener_obj_t *self = MP_OBJ_TO_PTR(self_in); + common_hal_canio_listener_check_for_deinit(self); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(canio_listener_enter_obj, canio_listener_enter); + +//| def __exit__(self, unused1, unused2, unused3) -> None: +//| """Calls deinit()""" +//| ... +STATIC mp_obj_t canio_listener_exit(size_t num_args, const mp_obj_t args[]) { + canio_listener_obj_t *self = MP_OBJ_TO_PTR(args[0]); + common_hal_canio_listener_deinit(self); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(canio_listener_exit_obj, 4, 4, canio_listener_exit); + + +//| timeout : float +STATIC mp_obj_t canio_listener_timeout_get(mp_obj_t self_in) { + canio_listener_obj_t *self = MP_OBJ_TO_PTR(self_in); + common_hal_canio_listener_check_for_deinit(self); + return mp_obj_new_float(common_hal_canio_listener_get_timeout(self)); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(canio_listener_timeout_get_obj, canio_listener_timeout_get); + +STATIC mp_obj_t canio_listener_timeout_set(mp_obj_t self_in, mp_obj_t timeout_in) { + canio_listener_obj_t *self = MP_OBJ_TO_PTR(self_in); + common_hal_canio_listener_check_for_deinit(self); + common_hal_canio_listener_set_timeout(self, mp_obj_get_float(timeout_in)); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(canio_listener_timeout_set_obj, canio_listener_timeout_set); + +STATIC const mp_obj_property_t canio_listener_timeout_obj = { + .base.type = &mp_type_property, + .proxy = {(mp_obj_t)&canio_listener_timeout_get_obj, + (mp_obj_t)&canio_listener_timeout_set_obj, + (mp_obj_t)mp_const_none}, +}; + + + +STATIC const mp_rom_map_elem_t canio_listener_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR___enter__), MP_ROM_PTR(&canio_listener_enter_obj) }, + { MP_ROM_QSTR(MP_QSTR___exit__), MP_ROM_PTR(&canio_listener_exit_obj) }, + { MP_ROM_QSTR(MP_QSTR___iter__), MP_ROM_PTR(&canio_listener_iter_obj) }, + { MP_ROM_QSTR(MP_QSTR___next__), MP_ROM_PTR(&canio_listener_next_obj) }, + { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&canio_listener_deinit_obj) }, + { MP_ROM_QSTR(MP_QSTR_in_waiting), MP_ROM_PTR(&canio_listener_in_waiting_obj) }, + { MP_ROM_QSTR(MP_QSTR_read), MP_ROM_PTR(&canio_listener_read_obj) }, + { MP_ROM_QSTR(MP_QSTR_readinto), MP_ROM_PTR(&canio_listener_readinto_obj) }, + { MP_ROM_QSTR(MP_QSTR_timeout), MP_ROM_PTR(&canio_listener_timeout_obj) }, +}; +STATIC MP_DEFINE_CONST_DICT(canio_listener_locals_dict, canio_listener_locals_dict_table); + +const mp_obj_type_t canio_listener_type = { + { &mp_type_type }, + .name = MP_QSTR_Listener, + .locals_dict = (mp_obj_dict_t*)&canio_listener_locals_dict, +}; diff --git a/shared-bindings/canio/Listener.h b/shared-bindings/canio/Listener.h new file mode 100644 index 000000000..eaa3490df --- /dev/null +++ b/shared-bindings/canio/Listener.h @@ -0,0 +1,31 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2020 Jeff Epler for Adafruit Industries + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#pragma once + +#include "py/obj.h" + +extern const mp_obj_type_t canio_listener_type; diff --git a/shared-bindings/canio/Match.c b/shared-bindings/canio/Match.c new file mode 100644 index 000000000..ff5d028fa --- /dev/null +++ b/shared-bindings/canio/Match.c @@ -0,0 +1,139 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2020 Jeff Epler for Adafruit Industries + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "shared-bindings/canio/Match.h" + +#include "py/objproperty.h" +#include "py/runtime.h" + +//| class Match: +//| """Describe CAN bus messages to match""" +//| +//| +//| def __init__(self, address: int, *, mask: int = 0, extended: bool = False): +//| """Construct a Match with the given properties. +//| +//| If mask is nonzero, then the filter is for any sender which matches all +//| the nonzero bits in mask. Otherwise, it matches exactly the given address. +//| If extended is true then only extended addresses are matched, otherwise +//| only standard addresses are matched.""" +//| + +STATIC mp_obj_t canio_match_make_new(const mp_obj_type_t *type, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + enum { ARG_address, ARG_mask, ARG_extended, NUM_ARGS }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_address, MP_ARG_INT | MP_ARG_REQUIRED }, + { MP_QSTR_mask, MP_ARG_INT, {.u_int = 0} }, + { MP_QSTR_extended, MP_ARG_BOOL, {.u_bool = false} }, + }; + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + MP_STATIC_ASSERT( MP_ARRAY_SIZE(allowed_args) == NUM_ARGS ); + + mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + int address_bits = args[ARG_extended].u_bool ? 0x1fffffff : 0x7ff; + int address = args[ARG_address].u_int; + int mask = args[ARG_mask].u_int; + + if (address & ~address_bits) { + mp_raise_ValueError_varg(translate("%q out of range"), MP_QSTR_address); + } + + if (mask & ~address_bits) { + mp_raise_ValueError_varg(translate("%q out of range"), MP_QSTR_mask); + } + + canio_match_obj_t *self = m_new_obj(canio_match_obj_t); + self->base.type = &canio_match_type; + common_hal_canio_match_construct(self, args[ARG_address].u_int, args[ARG_mask].u_int, args[ARG_extended].u_bool); + return self; +} + +//| address: int +//| """The address to match""" +//| + +STATIC mp_obj_t canio_match_address_get(mp_obj_t self_in) { + canio_match_obj_t *self = self_in; + return MP_OBJ_NEW_SMALL_INT(common_hal_canio_match_get_address(self)); +} +MP_DEFINE_CONST_FUN_OBJ_1(canio_match_address_get_obj, canio_match_address_get); + +const mp_obj_property_t canio_match_address_obj = { + .base.type = &mp_type_property, + .proxy = {(mp_obj_t)&canio_match_address_get_obj, + (mp_obj_t)&mp_const_none_obj, + (mp_obj_t)&mp_const_none_obj}, +}; + +//| +//| mask: int +//| """The optional mask of addresses to match""" +//| + +STATIC mp_obj_t canio_match_mask_get(mp_obj_t self_in) { + canio_match_obj_t *self = self_in; + return MP_OBJ_NEW_SMALL_INT(common_hal_canio_match_get_mask(self)); +} +MP_DEFINE_CONST_FUN_OBJ_1(canio_match_mask_get_obj, canio_match_mask_get); + +const mp_obj_property_t canio_match_mask_obj = { + .base.type = &mp_type_property, + .proxy = {(mp_obj_t)&canio_match_mask_get_obj, + (mp_obj_t)&mp_const_none_obj, + (mp_obj_t)&mp_const_none_obj}, +}; + +//| extended: bool +//| """True to match extended addresses, False to match standard addresses""" +//| + +STATIC mp_obj_t canio_match_extended_get(mp_obj_t self_in) { + canio_match_obj_t *self = self_in; + return mp_obj_new_bool(common_hal_canio_match_get_extended(self)); +} +MP_DEFINE_CONST_FUN_OBJ_1(canio_match_extended_get_obj, canio_match_extended_get); + +const mp_obj_property_t canio_match_extended_obj = { + .base.type = &mp_type_property, + .proxy = {(mp_obj_t)&canio_match_extended_get_obj, + (mp_obj_t)&mp_const_none_obj, + (mp_obj_t)&mp_const_none_obj}, +}; + +STATIC const mp_rom_map_elem_t canio_match_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_address), MP_ROM_PTR(&canio_match_address_obj) }, + { MP_ROM_QSTR(MP_QSTR_mask), MP_ROM_PTR(&canio_match_mask_obj) }, + { MP_ROM_QSTR(MP_QSTR_extended), MP_ROM_PTR(&canio_match_extended_obj) }, +}; +STATIC MP_DEFINE_CONST_DICT(canio_match_locals_dict, canio_match_locals_dict_table); + +const mp_obj_type_t canio_match_type = { + { &mp_type_type }, + .name = MP_QSTR_Match, + .make_new = canio_match_make_new, + .locals_dict = (mp_obj_dict_t*)&canio_match_locals_dict, +}; diff --git a/shared-bindings/canio/Match.h b/shared-bindings/canio/Match.h new file mode 100644 index 000000000..88996d730 --- /dev/null +++ b/shared-bindings/canio/Match.h @@ -0,0 +1,37 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2020 Jeff Epler for Adafruit Industries + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#pragma once + +#include "py/obj.h" +#include "shared-module/canio/Match.h" + +extern const mp_obj_type_t canio_match_type; + +void common_hal_canio_match_construct(canio_match_obj_t *self, int address, int mask, bool extended); +int common_hal_canio_match_get_address(const canio_match_obj_t *self); +int common_hal_canio_match_get_mask(const canio_match_obj_t *self); +bool common_hal_canio_match_get_extended(const canio_match_obj_t *self); diff --git a/shared-bindings/canio/Message.c b/shared-bindings/canio/Message.c new file mode 100644 index 000000000..11de6ded9 --- /dev/null +++ b/shared-bindings/canio/Message.c @@ -0,0 +1,212 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2020 Jeff Epler for Adafruit Industries + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "shared-bindings/canio/Message.h" + +#include "py/obj.h" +#include "py/objproperty.h" +#include "py/runtime.h" + +//| class Message: +//| def __init__(self, id: int=0, data: Optional[bytes] = None, *, size: Optional[int] = None, rtr: bool = False, extended: bool = False): +//| """Construct a Message to use with a CAN bus. Provide arguments to create a message to send. Otherwise, use Listener.readinto() to read a message. +//| +//| :param int id: The numeric ID of the message +//| :param bytes data: The content of the message +//| :param int size: The amount of data requested, for an rtr +//| :param bool rtr: True if the message represents an rtr (Remote Transmission Request) +//| :param bool extended: True if the message has an extended identifier, False if it has a standard identifier +//| +//| In CAN, messages can have a size from 0 to 8 bytes. +//| +//| For a non-rtr message, specify `data`. For an rtr-message, specify either `data` (a dummy buffer of the requested size) or `size`. +//| """ +//| ... +//| +STATIC mp_obj_t canio_message_make_new(const mp_obj_type_t *type, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + enum { ARG_id, ARG_data, ARG_size, ARG_rtr, ARG_extended, NUM_ARGS }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_id, MP_ARG_INT, {.u_obj = 0} }, + { MP_QSTR_data, MP_ARG_OBJ, {.u_obj = 0} }, + { MP_QSTR_size, MP_ARG_INT, {.u_int = -1} }, + { MP_QSTR_rtr, MP_ARG_BOOL, {.u_bool = false} }, + { MP_QSTR_extended, MP_ARG_BOOL, {.u_bool = false} }, + }; + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + MP_STATIC_ASSERT( MP_ARRAY_SIZE(allowed_args) == NUM_ARGS ); + + mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + bool rtr = args[ARG_rtr].u_bool; + bool extended = args[ARG_extended].u_bool; + size_t size = (size_t)args[ARG_size].u_int; + bool specified_size = (size != (size_t)-1); + bool specified_data = (args[ARG_data].u_obj != NULL); + + if (specified_size && specified_data) { + mp_raise_TypeError(translate("specify size or data, but not both")); + } + + mp_buffer_info_t data; + if (specified_data) { + mp_get_buffer_raise(args[ARG_data].u_obj, &data, MP_BUFFER_READ); + } else if (specified_size) { + data.buf = 0; + data.len = size; + } else { + data.buf = 0; + data.len = 0; + } + + if (data.len > 8) { + mp_raise_ValueError(translate("Messages limited to 8 bytes")); + } + + canio_message_obj_t *self = m_new_obj(canio_message_obj_t); + self->base.type = &canio_message_type; + common_hal_canio_message_construct(self, args[ARG_id].u_int, data.buf, data.len, rtr, extended); + return self; +} + +//| id: int +//| """The numeric ID of the message""" +//| +STATIC mp_obj_t canio_message_id_get(const mp_obj_t self_in) { + canio_message_obj_t *self = self_in; + return MP_OBJ_NEW_SMALL_INT(common_hal_canio_message_get_id(self)); +} +MP_DEFINE_CONST_FUN_OBJ_1(canio_message_id_get_obj, canio_message_id_get); + +STATIC mp_obj_t canio_message_id_set(const mp_obj_t self_in, const mp_obj_t id) { + canio_message_obj_t *self = self_in; + common_hal_canio_message_set_id(self, mp_obj_get_int(id)); + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_2(canio_message_id_set_obj, canio_message_id_set); + +STATIC const mp_obj_property_t canio_message_id_obj = { + .base.type = &mp_type_property, + .proxy = {(mp_obj_t)&canio_message_id_get_obj, + (mp_obj_t)&canio_message_id_set_obj, + (mp_obj_t)&mp_const_none_obj}, +}; + +//| data: bytes +//| """The content of the message, or dummy content in the case of an rtr. +//| +//| Assigning to data also sets the length and clears the rtr flag.""" +//| +STATIC mp_obj_t canio_message_data_get(const mp_obj_t self_in) { + canio_message_obj_t *self = self_in; + return mp_obj_new_bytes((const byte*)common_hal_canio_message_get_data(self), common_hal_canio_message_get_size(self)); +} +MP_DEFINE_CONST_FUN_OBJ_1(canio_message_data_get_obj, canio_message_data_get); + +STATIC mp_obj_t canio_message_data_set(const mp_obj_t self_in, const mp_obj_t data_in) { + canio_message_obj_t *self = self_in; + mp_buffer_info_t data; + mp_get_buffer_raise(data_in, &data, MP_BUFFER_READ); + if (data.len > 8) { + mp_raise_ValueError(translate("Messages limited to 8 bytes")); + } + common_hal_canio_message_set_data(self, data.buf, data.len); + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_2(canio_message_data_set_obj, canio_message_data_set); + + +STATIC const mp_obj_property_t canio_message_data_obj = { + .base.type = &mp_type_property, + .proxy = {(mp_obj_t)&canio_message_data_get_obj, + (mp_obj_t)&canio_message_data_set_obj, + (mp_obj_t)&mp_const_none_obj}, +}; + + +//| extended: bool +//| """True if the message represents a remote transmission request (RTR)""" +//| +STATIC mp_obj_t canio_message_extended_get(const mp_obj_t self_in) { + canio_message_obj_t *self = self_in; + return mp_obj_new_bool(common_hal_canio_message_get_extended(self)); +} +MP_DEFINE_CONST_FUN_OBJ_1(canio_message_extended_get_obj, canio_message_extended_get); + +STATIC mp_obj_t canio_message_extended_set(const mp_obj_t self_in, const mp_obj_t extended) { + canio_message_obj_t *self = self_in; + common_hal_canio_message_set_extended(self, mp_obj_is_true(extended)); + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_2(canio_message_extended_set_obj, canio_message_extended_set); + + +STATIC const mp_obj_property_t canio_message_extended_obj = { + .base.type = &mp_type_property, + .proxy = {(mp_obj_t)&canio_message_extended_get_obj, + (mp_obj_t)&canio_message_extended_set_obj, + (mp_obj_t)&mp_const_none_obj}, +}; + + +//| rtr: bool +//| """True if the message represents a remote transmission request (RTR). Setting rtr to true zeros out data""" +//| +STATIC mp_obj_t canio_message_rtr_get(const mp_obj_t self_in) { + canio_message_obj_t *self = self_in; + return mp_obj_new_bool(common_hal_canio_message_get_rtr(self)); +} +MP_DEFINE_CONST_FUN_OBJ_1(canio_message_rtr_get_obj, canio_message_rtr_get); + +STATIC mp_obj_t canio_message_rtr_set(const mp_obj_t self_in, const mp_obj_t rtr) { + canio_message_obj_t *self = self_in; + common_hal_canio_message_set_rtr(self, mp_obj_is_true(rtr)); + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_2(canio_message_rtr_set_obj, canio_message_rtr_set); + + +STATIC const mp_obj_property_t canio_message_rtr_obj = { + .base.type = &mp_type_property, + .proxy = {(mp_obj_t)&canio_message_rtr_get_obj, + (mp_obj_t)&canio_message_rtr_set_obj, + (mp_obj_t)&mp_const_none_obj}, +}; + + +STATIC const mp_rom_map_elem_t canio_message_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_id), MP_ROM_PTR(&canio_message_id_obj) }, + { MP_ROM_QSTR(MP_QSTR_data), MP_ROM_PTR(&canio_message_data_obj) }, + { MP_ROM_QSTR(MP_QSTR_rtr), MP_ROM_PTR(&canio_message_rtr_obj) }, + { MP_ROM_QSTR(MP_QSTR_extended), MP_ROM_PTR(&canio_message_extended_obj) }, +}; +STATIC MP_DEFINE_CONST_DICT(canio_message_locals_dict, canio_message_locals_dict_table); + +const mp_obj_type_t canio_message_type = { + { &mp_type_type }, + .name = MP_QSTR_Message, + .make_new = canio_message_make_new, + .locals_dict = (mp_obj_t)&canio_message_locals_dict, +}; diff --git a/shared-bindings/canio/Message.h b/shared-bindings/canio/Message.h new file mode 100644 index 000000000..34b632e84 --- /dev/null +++ b/shared-bindings/canio/Message.h @@ -0,0 +1,44 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2020 Jeff Epler for Adafruit Industries + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#pragma once + +#include "py/obj.h" +#include "shared-module/canio/Message.h" + +extern const mp_obj_type_t canio_message_type; + +void common_hal_canio_message_construct(canio_message_obj_t *self, int id, void *data, size_t size, bool rtr, bool extended); +const void *common_hal_canio_message_get_data(const canio_message_obj_t *self); +void common_hal_canio_message_set_data(canio_message_obj_t *self, const void *data, size_t size); +bool common_hal_canio_message_get_extended(const canio_message_obj_t *self); +void common_hal_canio_message_set_extended(canio_message_obj_t *self, bool extended); +int common_hal_canio_message_get_id(const canio_message_obj_t *self); +void common_hal_canio_message_set_id(canio_message_obj_t *self, int id); +bool common_hal_canio_message_get_rtr(const canio_message_obj_t *self); +void common_hal_canio_message_set_rtr(canio_message_obj_t *self, bool rtr); +size_t common_hal_canio_message_get_size(const canio_message_obj_t *self); +void common_hal_canio_message_set_size(canio_message_obj_t *self, size_t size); diff --git a/shared-bindings/canio/__init__.c b/shared-bindings/canio/__init__.c new file mode 100644 index 000000000..bc191913d --- /dev/null +++ b/shared-bindings/canio/__init__.c @@ -0,0 +1,124 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2020 Jeff Epler for Adafruit Industries + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +//| """CAN bus access +//| +//| The `_canio` module contains low level classes to support the CAN bus +//| protocol. +//| +//| CAN and Listener classes change hardware state and should be deinitialized when they +//| are no longer needed if the program continues after use. To do so, either +//| call :py:meth:`!deinit` or use a context manager. See +//| :ref:`lifetime-and-contextmanagers` for more info. +//| +//| For example:: +//| +//| import _canio +//| from board import * +//| +//| can = _canio.CAN(board.CAN_RX, board.CAN_TX, baudrate=1000000) +//| message = _canio.Message(id=0x0408, data="adafruit" +//| can.write(message)) +//| can.deinit() +//| +//| This example will write the data 'adafruit' onto the CAN bus to any +//| device listening for message id 0x0408. +//| +//| A CAN bus involves a transceiver, which is often a separate chip with a "standby" pin. +//| If your board has a CAN_STANDBY pin, ensure to set it to an output with the value False +//| to enable the transceiver. +//| +//| Other implementations of the CAN device may exist (for instance, attached +//| via an SPI bus). If so their constructor arguments may differ, but +//| otherwise we encourage implementors to follow the API that the core uses. +//| """ +//| + +#include "py/obj.h" +#include "py/enum.h" + +#include "shared-bindings/canio/__init__.h" +#include "shared-bindings/canio/CAN.h" +#include "shared-bindings/canio/Match.h" +#include "shared-bindings/canio/Message.h" +#include "shared-bindings/canio/Listener.h" + +MAKE_ENUM_VALUE(canio_bus_state_type, bus_state, ERROR_ACTIVE, BUS_STATE_ERROR_ACTIVE); +MAKE_ENUM_VALUE(canio_bus_state_type, bus_state, ERROR_PASSIVE, BUS_STATE_ERROR_PASSIVE); +MAKE_ENUM_VALUE(canio_bus_state_type, bus_state, ERROR_WARNING, BUS_STATE_ERROR_WARNING); +MAKE_ENUM_VALUE(canio_bus_state_type, bus_state, BUS_OFF, BUS_STATE_OFF); + +//| class BusState: +//| """The state of the CAN bus""" +//| +//| ERROR_ACTIVE: object +//| """The bus is in the normal (active) state""" +//| +//| ERROR_WARNING: object +//| """The bus is in the normal (active) state, but a moderate number of errors have occurred recently. +//| +//| NOTE: Not all implementations may use ERROR_WARNING. Do not rely on seeing ERROR_WARNING before ERROR_PASSIVE.""" +//| +//| ERROR_PASSIVE: object +//| """The bus is in the passive state due to the number of errors that have occurred recently. +//| +//| This device will acknowledge packets it receives, but cannot transmit messages. +//| If additional errors occur, this device may progress to BUS_OFF. +//| If it successfully acknowledges other packets on the bus, it can return to ERROR_WARNING or ERROR_ACTIVE and transmit packets. +//| """ +//| +//| BUS_OFF: object +//| """The bus has turned off due to the number of errors that have +//| occurred recently. It must be restarted before it will send or receive +//| packets. This device will neither send or acknowledge packets on the bus.""" +//| +MAKE_ENUM_MAP(canio_bus_state) { + MAKE_ENUM_MAP_ENTRY(bus_state, ERROR_ACTIVE), + MAKE_ENUM_MAP_ENTRY(bus_state, ERROR_PASSIVE), + MAKE_ENUM_MAP_ENTRY(bus_state, ERROR_WARNING), + MAKE_ENUM_MAP_ENTRY(bus_state, BUS_OFF), +}; +STATIC MP_DEFINE_CONST_DICT(canio_bus_state_locals_dict, canio_bus_state_locals_table); + +MAKE_PRINTER(_canio, canio_bus_state); + +MAKE_ENUM_TYPE(_canio, BusState, canio_bus_state); + +STATIC const mp_rom_map_elem_t canio_module_globals_table[] = { + { MP_ROM_QSTR(MP_QSTR_BusState), MP_ROM_PTR(&canio_bus_state_type) }, + { MP_ROM_QSTR(MP_QSTR_CAN), MP_ROM_PTR(&canio_can_type) }, + { MP_ROM_QSTR(MP_QSTR_Listener), MP_ROM_PTR(&canio_listener_type) }, + { MP_ROM_QSTR(MP_QSTR_Match), MP_ROM_PTR(&canio_match_type) }, + { MP_ROM_QSTR(MP_QSTR_Message), MP_ROM_PTR(&canio_message_type) }, + { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR__canio) }, +}; + +STATIC MP_DEFINE_CONST_DICT(canio_module_globals, canio_module_globals_table); + +const mp_obj_module_t canio_module = { + .base = { &mp_type_module }, + .globals = (mp_obj_dict_t*)&canio_module_globals, +}; diff --git a/shared-bindings/canio/__init__.h b/shared-bindings/canio/__init__.h new file mode 100644 index 000000000..e24eba92c --- /dev/null +++ b/shared-bindings/canio/__init__.h @@ -0,0 +1,33 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2020 Jeff Epler for Adafruit Industries + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#pragma once + +typedef enum { + BUS_STATE_ERROR_ACTIVE, BUS_STATE_ERROR_PASSIVE, BUS_STATE_ERROR_WARNING, BUS_STATE_OFF +} canio_bus_state_t; + +extern const mp_obj_type_t canio_bus_state_type; diff --git a/shared-module/_canio/Match.c b/shared-module/_canio/Match.c deleted file mode 100644 index 3dcde18a7..000000000 --- a/shared-module/_canio/Match.c +++ /dev/null @@ -1,43 +0,0 @@ -/* - * This file is part of the MicroPython project, http://micropython.org/ - * - * The MIT License (MIT) - * - * Copyright (c) 2020 Jeff Epler for Adafruit Industries - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -#include "shared-module/_canio/Match.h" - -void common_hal_canio_match_construct(canio_match_obj_t *self, int address, int mask, bool extended) { - self->address = address; - self->mask = mask; - self->extended = extended; -} - -int common_hal_canio_match_get_address(const canio_match_obj_t *self) { - return self->address; -} -int common_hal_canio_match_get_mask(const canio_match_obj_t *self) { - return self->mask; -} -bool common_hal_canio_match_get_extended(const canio_match_obj_t *self) { - return self->extended; -} diff --git a/shared-module/_canio/Match.h b/shared-module/_canio/Match.h deleted file mode 100644 index 25f047f37..000000000 --- a/shared-module/_canio/Match.h +++ /dev/null @@ -1,36 +0,0 @@ -/* - * This file is part of the MicroPython project, http://micropython.org/ - * - * The MIT License (MIT) - * - * Copyright (c) 2020 Jeff Epler for Adafruit Industries - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -#pragma once - -#include "py/obj.h" - -typedef struct { - mp_obj_base_t base; - int address; - int mask; - bool extended; -} canio_match_obj_t; diff --git a/shared-module/_canio/Message.c b/shared-module/_canio/Message.c deleted file mode 100644 index a02bd0127..000000000 --- a/shared-module/_canio/Message.c +++ /dev/null @@ -1,101 +0,0 @@ -/* - * This file is part of the MicroPython project, http://micropython.org/ - * - * The MIT License (MIT) - * - * Copyright (c) 2020 Jeff Epler for Adafruit Industries - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -#include "shared-module/_canio/Message.h" - -#include - -void common_hal_canio_message_construct(canio_message_obj_t *self, int id, void *data, size_t size, bool rtr, bool extended) -{ - self->id = id; - self->size = size; - self->rtr = rtr; - self->extended = extended; - if (data) { - memcpy(self->data, data, size); - } else { - memset(self->data, 0, size); - } -} - -int common_hal_canio_message_get_id(const canio_message_obj_t *self) -{ - return self->id; -} - -void common_hal_canio_message_set_id(canio_message_obj_t *self, int id) -{ - self->id = id; -} - - -const void *common_hal_canio_message_get_data(const canio_message_obj_t *self) -{ - return self->data; -} - -const void common_hal_canio_message_set_data(canio_message_obj_t *self, const void *data, size_t size) -{ - self->rtr = false; - self->size = size; - memcpy(self->data, data, size); -} - - -size_t common_hal_canio_message_get_size(const canio_message_obj_t *self) -{ - return self->size; -} - -void common_hal_canio_message_set_size(canio_message_obj_t *self, size_t size) -{ - memset(self->data, 0, size); - self->size = size; -} - - -bool common_hal_canio_message_get_rtr(const canio_message_obj_t *self) -{ - return self->rtr; -} - -void common_hal_canio_message_set_rtr(canio_message_obj_t *self, bool rtr) -{ - self->rtr = rtr; - if (rtr) { - memset(self->data, 0, self->size); - } -} - -bool common_hal_canio_message_get_extended(const canio_message_obj_t *self) -{ - return self->extended; -} - -void common_hal_canio_message_set_extended(canio_message_obj_t *self, bool extended) -{ - self->extended = extended; -} diff --git a/shared-module/_canio/Message.h b/shared-module/_canio/Message.h deleted file mode 100644 index b99c5c48e..000000000 --- a/shared-module/_canio/Message.h +++ /dev/null @@ -1,38 +0,0 @@ -/* - * This file is part of the MicroPython project, http://micropython.org/ - * - * The MIT License (MIT) - * - * Copyright (c) 2020 Jeff Epler for Adafruit Industries - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -#pragma once - -#include "py/obj.h" - -typedef struct { - mp_obj_base_t base; - int id; - uint8_t data[8]; - size_t size:4; - bool rtr:1; - bool extended:1; -} canio_message_obj_t; diff --git a/shared-module/canio/Match.c b/shared-module/canio/Match.c new file mode 100644 index 000000000..9e33b956f --- /dev/null +++ b/shared-module/canio/Match.c @@ -0,0 +1,43 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2020 Jeff Epler for Adafruit Industries + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "shared-module/canio/Match.h" + +void common_hal_canio_match_construct(canio_match_obj_t *self, int address, int mask, bool extended) { + self->address = address; + self->mask = mask; + self->extended = extended; +} + +int common_hal_canio_match_get_address(const canio_match_obj_t *self) { + return self->address; +} +int common_hal_canio_match_get_mask(const canio_match_obj_t *self) { + return self->mask; +} +bool common_hal_canio_match_get_extended(const canio_match_obj_t *self) { + return self->extended; +} diff --git a/shared-module/canio/Match.h b/shared-module/canio/Match.h new file mode 100644 index 000000000..25f047f37 --- /dev/null +++ b/shared-module/canio/Match.h @@ -0,0 +1,36 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2020 Jeff Epler for Adafruit Industries + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#pragma once + +#include "py/obj.h" + +typedef struct { + mp_obj_base_t base; + int address; + int mask; + bool extended; +} canio_match_obj_t; diff --git a/shared-module/canio/Message.c b/shared-module/canio/Message.c new file mode 100644 index 000000000..b8ebb7859 --- /dev/null +++ b/shared-module/canio/Message.c @@ -0,0 +1,101 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2020 Jeff Epler for Adafruit Industries + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "shared-module/canio/Message.h" + +#include + +void common_hal_canio_message_construct(canio_message_obj_t *self, int id, void *data, size_t size, bool rtr, bool extended) +{ + self->id = id; + self->size = size; + self->rtr = rtr; + self->extended = extended; + if (data) { + memcpy(self->data, data, size); + } else { + memset(self->data, 0, size); + } +} + +int common_hal_canio_message_get_id(const canio_message_obj_t *self) +{ + return self->id; +} + +void common_hal_canio_message_set_id(canio_message_obj_t *self, int id) +{ + self->id = id; +} + + +const void *common_hal_canio_message_get_data(const canio_message_obj_t *self) +{ + return self->data; +} + +const void common_hal_canio_message_set_data(canio_message_obj_t *self, const void *data, size_t size) +{ + self->rtr = false; + self->size = size; + memcpy(self->data, data, size); +} + + +size_t common_hal_canio_message_get_size(const canio_message_obj_t *self) +{ + return self->size; +} + +void common_hal_canio_message_set_size(canio_message_obj_t *self, size_t size) +{ + memset(self->data, 0, size); + self->size = size; +} + + +bool common_hal_canio_message_get_rtr(const canio_message_obj_t *self) +{ + return self->rtr; +} + +void common_hal_canio_message_set_rtr(canio_message_obj_t *self, bool rtr) +{ + self->rtr = rtr; + if (rtr) { + memset(self->data, 0, self->size); + } +} + +bool common_hal_canio_message_get_extended(const canio_message_obj_t *self) +{ + return self->extended; +} + +void common_hal_canio_message_set_extended(canio_message_obj_t *self, bool extended) +{ + self->extended = extended; +} diff --git a/shared-module/canio/Message.h b/shared-module/canio/Message.h new file mode 100644 index 000000000..b99c5c48e --- /dev/null +++ b/shared-module/canio/Message.h @@ -0,0 +1,38 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2020 Jeff Epler for Adafruit Industries + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#pragma once + +#include "py/obj.h" + +typedef struct { + mp_obj_base_t base; + int id; + uint8_t data[8]; + size_t size:4; + bool rtr:1; + bool extended:1; +} canio_message_obj_t; -- cgit v1.2.3 From f21dc253e094854670b829f6258aac3722eefc26 Mon Sep 17 00:00:00 2001 From: Mark Roberts Date: Mon, 21 Sep 2020 18:42:16 -0400 Subject: Initial commit bool column_and_page_addressing --- shared-bindings/displayio/Display.c | 5 ++++- shared-bindings/displayio/Display.h | 3 ++- shared-module/displayio/Display.c | 4 +++- shared-module/displayio/Display.h | 2 ++ 4 files changed, 11 insertions(+), 3 deletions(-) (limited to 'shared-module') diff --git a/shared-bindings/displayio/Display.c b/shared-bindings/displayio/Display.c index f36aeed18..634156f56 100644 --- a/shared-bindings/displayio/Display.c +++ b/shared-bindings/displayio/Display.c @@ -105,6 +105,7 @@ //| :param bool auto_brightness: If True, brightness is controlled via an ambient light sensor or other mechanism. //| :param bool single_byte_bounds: Display column and row commands use single bytes //| :param bool data_as_commands: Treat all init and boundary data as SPI commands. Certain displays require this. +//| :param bool column_and_page_addressing: Special quirk for SH1107, use upper/lower column set and page set //| :param bool auto_refresh: Automatically refresh the screen //| :param int native_frames_per_second: Number of display refreshes per second that occur with the given init_sequence. //| :param bool backlight_on_high: If True, pulling the backlight pin high turns the backlight on.""" @@ -139,6 +140,7 @@ STATIC mp_obj_t displayio_display_make_new(const mp_obj_type_t *type, size_t n_a { MP_QSTR_auto_refresh, MP_ARG_BOOL | MP_ARG_KW_ONLY, {.u_bool = true} }, { MP_QSTR_native_frames_per_second, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 60} }, { MP_QSTR_backlight_on_high, MP_ARG_BOOL | MP_ARG_KW_ONLY, {.u_bool = true} }, + { MP_QSTR_column_and_page_addressing, MP_ARG_BOOL | MP_ARG_KW_ONLY, {.u_bool = false} }, }; mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); @@ -180,7 +182,8 @@ STATIC mp_obj_t displayio_display_make_new(const mp_obj_type_t *type, size_t n_a args[ARG_data_as_commands].u_bool, args[ARG_auto_refresh].u_bool, args[ARG_native_frames_per_second].u_int, - args[ARG_backlight_on_high].u_bool + args[ARG_backlight_on_high].u_bool, + args[ARG_column_and_page_addressing].u_bool ); return self; diff --git a/shared-bindings/displayio/Display.h b/shared-bindings/displayio/Display.h index e69c5b6b5..d6274a2b2 100644 --- a/shared-bindings/displayio/Display.h +++ b/shared-bindings/displayio/Display.h @@ -45,7 +45,8 @@ void common_hal_displayio_display_construct(displayio_display_obj_t* self, uint8_t set_column_command, uint8_t set_row_command, uint8_t write_ram_command, uint8_t set_vertical_scroll, uint8_t* init_sequence, uint16_t init_sequence_len, const mcu_pin_obj_t* backlight_pin, uint16_t brightness_command, mp_float_t brightness, bool auto_brightness, - bool single_byte_bounds, bool data_as_commands, bool auto_refresh, uint16_t native_frames_per_second, bool backlight_on_high); + bool single_byte_bounds, bool data_as_commands, bool auto_refresh, uint16_t native_frames_per_second, + bool backlight_on_high, bool column_and_page_addressing); bool common_hal_displayio_display_show(displayio_display_obj_t* self, displayio_group_t* root_group); diff --git a/shared-module/displayio/Display.c b/shared-module/displayio/Display.c index 021159c0d..d3e7ee175 100644 --- a/shared-module/displayio/Display.c +++ b/shared-module/displayio/Display.c @@ -48,7 +48,8 @@ void common_hal_displayio_display_construct(displayio_display_obj_t* self, uint8_t set_row_command, uint8_t write_ram_command, uint8_t set_vertical_scroll, uint8_t* init_sequence, uint16_t init_sequence_len, const mcu_pin_obj_t* backlight_pin, uint16_t brightness_command, mp_float_t brightness, bool auto_brightness, - bool single_byte_bounds, bool data_as_commands, bool auto_refresh, uint16_t native_frames_per_second, bool backlight_on_high) { + bool single_byte_bounds, bool data_as_commands, bool auto_refresh, uint16_t native_frames_per_second, + bool backlight_on_high), bool column_and_page_addressing { // Turn off auto-refresh as we init. self->auto_refresh = false; uint16_t ram_width = 0x100; @@ -68,6 +69,7 @@ void common_hal_displayio_display_construct(displayio_display_obj_t* self, self->first_manual_refresh = !auto_refresh; self->data_as_commands = data_as_commands; self->backlight_on_high = backlight_on_high; + self->column_and_page_addressing = column_and_page_addressing; self->native_frames_per_second = native_frames_per_second; self->native_ms_per_frame = 1000 / native_frames_per_second; diff --git a/shared-module/displayio/Display.h b/shared-module/displayio/Display.h index bdb861aa0..86c2a9360 100644 --- a/shared-module/displayio/Display.h +++ b/shared-module/displayio/Display.h @@ -60,6 +60,8 @@ typedef struct { bool auto_brightness; bool updating_backlight; bool backlight_on_high; + // new quirk for sh1107 + bool column_and_page_addressing; } displayio_display_obj_t; void displayio_display_background(displayio_display_obj_t* self); -- cgit v1.2.3 From 08189edf247244c616b0bd4c58fdb678b6c53d0e Mon Sep 17 00:00:00 2001 From: Mark Roberts Date: Mon, 21 Sep 2020 21:07:42 -0400 Subject: Quirk coded up for ...set_region_to_update --- shared-module/displayio/Display.c | 2 +- shared-module/displayio/display_core.c | 16 ++++++++++++++++ 2 files changed, 17 insertions(+), 1 deletion(-) (limited to 'shared-module') diff --git a/shared-module/displayio/Display.c b/shared-module/displayio/Display.c index d3e7ee175..b0806af29 100644 --- a/shared-module/displayio/Display.c +++ b/shared-module/displayio/Display.c @@ -49,7 +49,7 @@ void common_hal_displayio_display_construct(displayio_display_obj_t* self, uint8_t* init_sequence, uint16_t init_sequence_len, const mcu_pin_obj_t* backlight_pin, uint16_t brightness_command, mp_float_t brightness, bool auto_brightness, bool single_byte_bounds, bool data_as_commands, bool auto_refresh, uint16_t native_frames_per_second, - bool backlight_on_high), bool column_and_page_addressing { + bool backlight_on_high, bool column_and_page_addressing) { // Turn off auto-refresh as we init. self->auto_refresh = false; uint16_t ram_width = 0x100; diff --git a/shared-module/displayio/display_core.c b/shared-module/displayio/display_core.c index 43f2d1937..f046ab9e4 100644 --- a/shared-module/displayio/display_core.c +++ b/shared-module/displayio/display_core.c @@ -253,8 +253,16 @@ void displayio_display_core_set_region_to_update(displayio_display_core_t* self, data[data_length++] = x2 >> 8; data[data_length++] = x2 & 0xff; } + // Quirk for SH1107 "column_and_page_addressing" + // Column lower command = 0x00, Column upper command = 0x10 + if (column_and_page_addressing) { + data[0] = 0x00 | (x1 & 0x0F); + data[1] = 0x10 | (x1 >> 4); + data_length = 2; + } self->send(self->bus, data_type, chip_select, data, data_length); displayio_display_core_end_transaction(self); + if (set_current_column_command != NO_COMMAND) { uint8_t command = set_current_column_command; displayio_display_core_begin_transaction(self); @@ -283,6 +291,14 @@ void displayio_display_core_set_region_to_update(displayio_display_core_t* self, data[data_length++] = y2 >> 8; data[data_length++] = y2 & 0xff; } + // Quirk for SH1107 "column_and_page_addressing" + // Page address command = 0xB0 + if (column_and_page_addressing) { + data[0] = 0xB0 | (y1 & 0x07); + data_length = 1; + } + self->send(self->bus, data_type, chip_select, data, data_length); + self->send(self->bus, data_type, chip_select, data, data_length); displayio_display_core_end_transaction(self); -- cgit v1.2.3 From 5536e574dba604b86ef5f6e8c4d86bc408ef8ac5 Mon Sep 17 00:00:00 2001 From: Mark Roberts Date: Mon, 21 Sep 2020 22:08:16 -0400 Subject: Changes to compile cleanly --- .gitignore | 1 + shared-bindings/displayio/Display.c | 2 +- shared-module/displayio/Display.c | 4 +++- shared-module/displayio/EPaperDisplay.c | 4 +++- shared-module/displayio/display_core.c | 5 ++++- shared-module/displayio/display_core.h | 5 ++++- 6 files changed, 16 insertions(+), 5 deletions(-) (limited to 'shared-module') diff --git a/.gitignore b/.gitignore index 03cd38f35..a8814be45 100644 --- a/.gitignore +++ b/.gitignore @@ -80,6 +80,7 @@ TAGS *.mo .vscode +.idea # Python Virtual Environments #################### diff --git a/shared-bindings/displayio/Display.c b/shared-bindings/displayio/Display.c index 634156f56..2ae237350 100644 --- a/shared-bindings/displayio/Display.c +++ b/shared-bindings/displayio/Display.c @@ -112,7 +112,7 @@ //| ... //| STATIC mp_obj_t displayio_display_make_new(const mp_obj_type_t *type, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { - enum { ARG_display_bus, ARG_init_sequence, ARG_width, ARG_height, ARG_colstart, ARG_rowstart, ARG_rotation, ARG_color_depth, ARG_grayscale, ARG_pixels_in_byte_share_row, ARG_bytes_per_cell, ARG_reverse_pixels_in_byte, ARG_reverse_bytes_in_word, ARG_set_column_command, ARG_set_row_command, ARG_write_ram_command, ARG_set_vertical_scroll, ARG_backlight_pin, ARG_brightness_command, ARG_brightness, ARG_auto_brightness, ARG_single_byte_bounds, ARG_data_as_commands, ARG_auto_refresh, ARG_native_frames_per_second, ARG_backlight_on_high }; + enum { ARG_display_bus, ARG_init_sequence, ARG_width, ARG_height, ARG_colstart, ARG_rowstart, ARG_rotation, ARG_color_depth, ARG_grayscale, ARG_pixels_in_byte_share_row, ARG_bytes_per_cell, ARG_reverse_pixels_in_byte, ARG_reverse_bytes_in_word, ARG_set_column_command, ARG_set_row_command, ARG_write_ram_command, ARG_set_vertical_scroll, ARG_backlight_pin, ARG_brightness_command, ARG_brightness, ARG_auto_brightness, ARG_single_byte_bounds, ARG_data_as_commands, ARG_auto_refresh, ARG_native_frames_per_second, ARG_backlight_on_high, ARG_column_and_page_addressing }; static const mp_arg_t allowed_args[] = { { MP_QSTR_display_bus, MP_ARG_REQUIRED | MP_ARG_OBJ }, { MP_QSTR_init_sequence, MP_ARG_REQUIRED | MP_ARG_OBJ }, diff --git a/shared-module/displayio/Display.c b/shared-module/displayio/Display.c index b0806af29..b6979c0b2 100644 --- a/shared-module/displayio/Display.c +++ b/shared-module/displayio/Display.c @@ -288,7 +288,9 @@ STATIC bool _refresh_area(displayio_display_obj_t* self, const displayio_area_t* } remaining_rows -= rows_per_buffer; - displayio_display_core_set_region_to_update(&self->core, self->set_column_command, self->set_row_command, NO_COMMAND, NO_COMMAND, self->data_as_commands, false, &subrectangle); + displayio_display_core_set_region_to_update(&self->core, self->set_column_command, + self->set_row_command, NO_COMMAND, NO_COMMAND, self->data_as_commands, false, + &subrectangle, self->column_and_page_addressing); uint16_t subrectangle_size_bytes; if (self->core.colorspace.depth >= 8) { diff --git a/shared-module/displayio/EPaperDisplay.c b/shared-module/displayio/EPaperDisplay.c index 6d9e915b4..397ceb4fd 100644 --- a/shared-module/displayio/EPaperDisplay.c +++ b/shared-module/displayio/EPaperDisplay.c @@ -239,7 +239,9 @@ bool displayio_epaperdisplay_refresh_area(displayio_epaperdisplay_obj_t* self, c uint16_t remaining_rows = displayio_area_height(&clipped); if (self->set_row_window_command != NO_COMMAND) { - displayio_display_core_set_region_to_update(&self->core, self->set_column_window_command, self->set_row_window_command, self->set_current_column_command, self->set_current_row_command, false, self->chip_select, &clipped); + displayio_display_core_set_region_to_update(&self->core, self->set_column_window_command, + self->set_row_window_command, self->set_current_column_command, self->set_current_row_command, + false, self->chip_select, &clipped, false); } uint8_t write_command = self->write_black_ram_command; diff --git a/shared-module/displayio/display_core.c b/shared-module/displayio/display_core.c index f046ab9e4..f01fda092 100644 --- a/shared-module/displayio/display_core.c +++ b/shared-module/displayio/display_core.c @@ -208,7 +208,10 @@ void displayio_display_core_end_transaction(displayio_display_core_t* self) { self->end_transaction(self->bus); } -void displayio_display_core_set_region_to_update(displayio_display_core_t* self, uint8_t column_command, uint8_t row_command, uint16_t set_current_column_command, uint16_t set_current_row_command, bool data_as_commands, bool always_toggle_chip_select, displayio_area_t* area) { +void displayio_display_core_set_region_to_update(displayio_display_core_t* self, uint8_t column_command, + uint8_t row_command, uint16_t set_current_column_command, uint16_t set_current_row_command, + bool data_as_commands, bool always_toggle_chip_select, + displayio_area_t* area, bool column_and_page_addressing) { uint16_t x1 = area->x1; uint16_t x2 = area->x2; uint16_t y1 = area->y1; diff --git a/shared-module/displayio/display_core.h b/shared-module/displayio/display_core.h index e4fd62d4a..1c880be44 100644 --- a/shared-module/displayio/display_core.h +++ b/shared-module/displayio/display_core.h @@ -74,7 +74,10 @@ bool displayio_display_core_bus_free(displayio_display_core_t *self); bool displayio_display_core_begin_transaction(displayio_display_core_t* self); void displayio_display_core_end_transaction(displayio_display_core_t* self); -void displayio_display_core_set_region_to_update(displayio_display_core_t* self, uint8_t column_command, uint8_t row_command, uint16_t set_current_column_command, uint16_t set_current_row_command, bool data_as_commands, bool always_toggle_chip_select, displayio_area_t* area); +void displayio_display_core_set_region_to_update(displayio_display_core_t* self, uint8_t column_command, + uint8_t row_command, uint16_t set_current_column_command, uint16_t set_current_row_command, + bool data_as_commands, bool always_toggle_chip_select, + displayio_area_t* area, bool column_and_page_addressing); void release_display_core(displayio_display_core_t* self); -- cgit v1.2.3 From dbf8a9ad69fa93b7ad9b85df22208e08790e5795 Mon Sep 17 00:00:00 2001 From: root Date: Tue, 22 Sep 2020 10:25:31 -0500 Subject: Changed delay calls to avoid conflicts with qspi_disable --- shared-module/displayio/FourWire.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'shared-module') diff --git a/shared-module/displayio/FourWire.c b/shared-module/displayio/FourWire.c index 726116208..8c56d7ab6 100644 --- a/shared-module/displayio/FourWire.c +++ b/shared-module/displayio/FourWire.c @@ -87,9 +87,9 @@ bool common_hal_displayio_fourwire_reset(mp_obj_t obj) { return false; } common_hal_digitalio_digitalinout_set_value(&self->reset, false); - common_hal_time_delay_ms(1); + common_hal_mcu_delay_us(1000); common_hal_digitalio_digitalinout_set_value(&self->reset, true); - common_hal_time_delay_ms(1); + common_hal_mcu_delay_us(1000); return true; } -- cgit v1.2.3 From 5a176c2c67cff17415d1a713ed2ee3cbf94dd020 Mon Sep 17 00:00:00 2001 From: Mark Roberts Date: Tue, 22 Sep 2020 13:41:25 -0400 Subject: Removed redundant send of page setting --- shared-module/displayio/display_core.c | 1 - 1 file changed, 1 deletion(-) (limited to 'shared-module') diff --git a/shared-module/displayio/display_core.c b/shared-module/displayio/display_core.c index f01fda092..19e45e6b6 100644 --- a/shared-module/displayio/display_core.c +++ b/shared-module/displayio/display_core.c @@ -302,7 +302,6 @@ void displayio_display_core_set_region_to_update(displayio_display_core_t* self, } self->send(self->bus, data_type, chip_select, data, data_length); - self->send(self->bus, data_type, chip_select, data, data_length); displayio_display_core_end_transaction(self); if (set_current_row_command != NO_COMMAND) { -- cgit v1.2.3 From 06a3d152664a97cc0a2f2faee86d2f5ea4e063e2 Mon Sep 17 00:00:00 2001 From: Mark Roberts Date: Thu, 24 Sep 2020 22:07:33 -0400 Subject: Mostly-working-version with comments --- shared-bindings/displayio/Display.c | 18 ++++++++++++----- shared-bindings/displayio/Display.h | 2 +- shared-module/displayio/Display.c | 36 ++++++++++++++++++++++++++------- shared-module/displayio/Display.h | 2 +- shared-module/displayio/EPaperDisplay.c | 1 + shared-module/displayio/display_core.c | 33 ++++++++++++++++-------------- shared-module/displayio/display_core.h | 2 +- 7 files changed, 64 insertions(+), 30 deletions(-) (limited to 'shared-module') diff --git a/shared-bindings/displayio/Display.c b/shared-bindings/displayio/Display.c index 2ae237350..a81736e46 100644 --- a/shared-bindings/displayio/Display.c +++ b/shared-bindings/displayio/Display.c @@ -105,14 +105,22 @@ //| :param bool auto_brightness: If True, brightness is controlled via an ambient light sensor or other mechanism. //| :param bool single_byte_bounds: Display column and row commands use single bytes //| :param bool data_as_commands: Treat all init and boundary data as SPI commands. Certain displays require this. -//| :param bool column_and_page_addressing: Special quirk for SH1107, use upper/lower column set and page set +//| :param bool SH1107_addressing: Special quirk for SH1107, use upper/lower column set and page set //| :param bool auto_refresh: Automatically refresh the screen //| :param int native_frames_per_second: Number of display refreshes per second that occur with the given init_sequence. //| :param bool backlight_on_high: If True, pulling the backlight pin high turns the backlight on.""" //| ... //| -STATIC mp_obj_t displayio_display_make_new(const mp_obj_type_t *type, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { - enum { ARG_display_bus, ARG_init_sequence, ARG_width, ARG_height, ARG_colstart, ARG_rowstart, ARG_rotation, ARG_color_depth, ARG_grayscale, ARG_pixels_in_byte_share_row, ARG_bytes_per_cell, ARG_reverse_pixels_in_byte, ARG_reverse_bytes_in_word, ARG_set_column_command, ARG_set_row_command, ARG_write_ram_command, ARG_set_vertical_scroll, ARG_backlight_pin, ARG_brightness_command, ARG_brightness, ARG_auto_brightness, ARG_single_byte_bounds, ARG_data_as_commands, ARG_auto_refresh, ARG_native_frames_per_second, ARG_backlight_on_high, ARG_column_and_page_addressing }; +STATIC mp_obj_t displayio_display_make_new(const mp_obj_type_t *type, size_t n_args, + const mp_obj_t *pos_args, mp_map_t *kw_args) { + enum { ARG_display_bus, ARG_init_sequence, ARG_width, ARG_height, ARG_colstart, ARG_rowstart, + ARG_rotation, ARG_color_depth, ARG_grayscale, ARG_pixels_in_byte_share_row, + ARG_bytes_per_cell, ARG_reverse_pixels_in_byte, ARG_reverse_bytes_in_word, + ARG_set_column_command, ARG_set_row_command, ARG_write_ram_command, + ARG_set_vertical_scroll, ARG_backlight_pin, ARG_brightness_command, + ARG_brightness, ARG_auto_brightness, ARG_single_byte_bounds, ARG_data_as_commands, + ARG_auto_refresh, ARG_native_frames_per_second, ARG_backlight_on_high, + ARG_SH1107_addressing }; static const mp_arg_t allowed_args[] = { { MP_QSTR_display_bus, MP_ARG_REQUIRED | MP_ARG_OBJ }, { MP_QSTR_init_sequence, MP_ARG_REQUIRED | MP_ARG_OBJ }, @@ -140,7 +148,7 @@ STATIC mp_obj_t displayio_display_make_new(const mp_obj_type_t *type, size_t n_a { MP_QSTR_auto_refresh, MP_ARG_BOOL | MP_ARG_KW_ONLY, {.u_bool = true} }, { MP_QSTR_native_frames_per_second, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 60} }, { MP_QSTR_backlight_on_high, MP_ARG_BOOL | MP_ARG_KW_ONLY, {.u_bool = true} }, - { MP_QSTR_column_and_page_addressing, MP_ARG_BOOL | MP_ARG_KW_ONLY, {.u_bool = false} }, + { MP_QSTR_SH1107_addressing, MP_ARG_BOOL | MP_ARG_KW_ONLY, {.u_bool = false} } }; mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); @@ -183,7 +191,7 @@ STATIC mp_obj_t displayio_display_make_new(const mp_obj_type_t *type, size_t n_a args[ARG_auto_refresh].u_bool, args[ARG_native_frames_per_second].u_int, args[ARG_backlight_on_high].u_bool, - args[ARG_column_and_page_addressing].u_bool + args[ARG_SH1107_addressing].u_bool ); return self; diff --git a/shared-bindings/displayio/Display.h b/shared-bindings/displayio/Display.h index d6274a2b2..c1704eaad 100644 --- a/shared-bindings/displayio/Display.h +++ b/shared-bindings/displayio/Display.h @@ -46,7 +46,7 @@ void common_hal_displayio_display_construct(displayio_display_obj_t* self, uint8_t* init_sequence, uint16_t init_sequence_len, const mcu_pin_obj_t* backlight_pin, uint16_t brightness_command, mp_float_t brightness, bool auto_brightness, bool single_byte_bounds, bool data_as_commands, bool auto_refresh, uint16_t native_frames_per_second, - bool backlight_on_high, bool column_and_page_addressing); + bool backlight_on_high, bool SH1107_addressing); bool common_hal_displayio_display_show(displayio_display_obj_t* self, displayio_group_t* root_group); diff --git a/shared-module/displayio/Display.c b/shared-module/displayio/Display.c index b6979c0b2..afc4b7564 100644 --- a/shared-module/displayio/Display.c +++ b/shared-module/displayio/Display.c @@ -49,7 +49,8 @@ void common_hal_displayio_display_construct(displayio_display_obj_t* self, uint8_t* init_sequence, uint16_t init_sequence_len, const mcu_pin_obj_t* backlight_pin, uint16_t brightness_command, mp_float_t brightness, bool auto_brightness, bool single_byte_bounds, bool data_as_commands, bool auto_refresh, uint16_t native_frames_per_second, - bool backlight_on_high, bool column_and_page_addressing) { + bool backlight_on_high, bool SH1107_addressing) { + // Turn off auto-refresh as we init. self->auto_refresh = false; uint16_t ram_width = 0x100; @@ -69,7 +70,7 @@ void common_hal_displayio_display_construct(displayio_display_obj_t* self, self->first_manual_refresh = !auto_refresh; self->data_as_commands = data_as_commands; self->backlight_on_high = backlight_on_high; - self->column_and_page_addressing = column_and_page_addressing; + self->SH1107_addressing = SH1107_addressing; self->native_frames_per_second = native_frames_per_second; self->native_ms_per_frame = 1000 / native_frames_per_second; @@ -242,11 +243,23 @@ STATIC bool _refresh_area(displayio_display_obj_t* self, const displayio_area_t* if (!displayio_display_core_clip_area(&self->core, area, &clipped)) { return true; } - uint16_t subrectangles = 1; uint16_t rows_per_buffer = displayio_area_height(&clipped); uint8_t pixels_per_word = (sizeof(uint32_t) * 8) / self->core.colorspace.depth; uint16_t pixels_per_buffer = displayio_area_size(&clipped); - if (displayio_area_size(&clipped) > buffer_size * pixels_per_word) { + + uint16_t subrectangles = 1; + // for SH1107 and other boundary constrained controllers + // write one single row at a time + if (self->SH1107_addressing) { + subrectangles = rows_per_buffer; // vertical (column mode) write each separately (height times) + } + + // Skip this recalculation of subrectangles if SH1107 (each subrectangle is a single row) + // [mdroberts1243] I am worried/confused about the pixels_in_byte_share_row calculation though + // since it makes sense to be on a byte boundary (actually a page boundary too) + // seems to work as is though. + if ((displayio_area_size(&clipped) > buffer_size * pixels_per_word) + && (!self->SH1107_addressing)) { rows_per_buffer = buffer_size * pixels_per_word / displayio_area_width(&clipped); if (rows_per_buffer == 0) { rows_per_buffer = 1; @@ -283,14 +296,23 @@ STATIC bool _refresh_area(displayio_display_obj_t* self, const displayio_area_t* .x2 = clipped.x2, .y2 = clipped.y1 + rows_per_buffer * (j + 1) }; - if (remaining_rows < rows_per_buffer) { + if (self->SH1107_addressing) { + // one row only for SH1107 in vertical (column) mode + subrectangle.y1 = clipped.y1 + j; + subrectangle.y2 = clipped.y1 + (j + 1); + }; + if ((remaining_rows < rows_per_buffer) && (!self->SH1107_addressing)) { subrectangle.y2 = subrectangle.y1 + remaining_rows; } - remaining_rows -= rows_per_buffer; + if (self->SH1107_addressing) { + remaining_rows -= 1; + } else { + remaining_rows -= rows_per_buffer; + } displayio_display_core_set_region_to_update(&self->core, self->set_column_command, self->set_row_command, NO_COMMAND, NO_COMMAND, self->data_as_commands, false, - &subrectangle, self->column_and_page_addressing); + &subrectangle, self->SH1107_addressing); uint16_t subrectangle_size_bytes; if (self->core.colorspace.depth >= 8) { diff --git a/shared-module/displayio/Display.h b/shared-module/displayio/Display.h index 86c2a9360..cc9cd54c4 100644 --- a/shared-module/displayio/Display.h +++ b/shared-module/displayio/Display.h @@ -61,7 +61,7 @@ typedef struct { bool updating_backlight; bool backlight_on_high; // new quirk for sh1107 - bool column_and_page_addressing; + bool SH1107_addressing; } displayio_display_obj_t; void displayio_display_background(displayio_display_obj_t* self); diff --git a/shared-module/displayio/EPaperDisplay.c b/shared-module/displayio/EPaperDisplay.c index 397ceb4fd..3391a56b4 100644 --- a/shared-module/displayio/EPaperDisplay.c +++ b/shared-module/displayio/EPaperDisplay.c @@ -238,6 +238,7 @@ bool displayio_epaperdisplay_refresh_area(displayio_epaperdisplay_obj_t* self, c for (uint8_t pass = 0; pass < passes; pass++) { uint16_t remaining_rows = displayio_area_height(&clipped); + // added false parameter at end for SH1107_addressing quirk if (self->set_row_window_command != NO_COMMAND) { displayio_display_core_set_region_to_update(&self->core, self->set_column_window_command, self->set_row_window_command, self->set_current_column_command, self->set_current_row_command, diff --git a/shared-module/displayio/display_core.c b/shared-module/displayio/display_core.c index 19e45e6b6..4e36e4dd1 100644 --- a/shared-module/displayio/display_core.c +++ b/shared-module/displayio/display_core.c @@ -41,7 +41,7 @@ #include #define DISPLAYIO_CORE_DEBUG(...) (void)0 -// #define DISPLAYIO_CORE_DEBUG(...) mp_printf(&mp_plat_print __VA_OPT__(,) __VA_ARGS__) +//#define DISPLAYIO_CORE_DEBUG(...) mp_printf(&mp_plat_print __VA_OPT__(,) __VA_ARGS__) void displayio_display_core_construct(displayio_display_core_t* self, mp_obj_t bus, uint16_t width, uint16_t height, uint16_t ram_width, uint16_t ram_height, int16_t colstart, int16_t rowstart, uint16_t rotation, @@ -57,7 +57,7 @@ void displayio_display_core_construct(displayio_display_core_t* self, self->colstart = colstart; self->rowstart = rowstart; self->last_refresh = 0; - + // (framebufferdisplay already validated its 'bus' is a buffer-protocol object) if (bus) { if (MP_OBJ_IS_TYPE(bus, &displayio_parallelbus_type)) { @@ -211,7 +211,7 @@ void displayio_display_core_end_transaction(displayio_display_core_t* self) { void displayio_display_core_set_region_to_update(displayio_display_core_t* self, uint8_t column_command, uint8_t row_command, uint16_t set_current_column_command, uint16_t set_current_row_command, bool data_as_commands, bool always_toggle_chip_select, - displayio_area_t* area, bool column_and_page_addressing) { + displayio_area_t* area, bool SH1107_addressing) { uint16_t x1 = area->x1; uint16_t x2 = area->x2; uint16_t y1 = area->y1; @@ -256,12 +256,13 @@ void displayio_display_core_set_region_to_update(displayio_display_core_t* self, data[data_length++] = x2 >> 8; data[data_length++] = x2 & 0xff; } - // Quirk for SH1107 "column_and_page_addressing" - // Column lower command = 0x00, Column upper command = 0x10 - if (column_and_page_addressing) { - data[0] = 0x00 | (x1 & 0x0F); - data[1] = 0x10 | (x1 >> 4); - data_length = 2; + // Quirk for SH1107 "SH1107_addressing" + // Note... column is y! page is x! + // Page address command = 0xB0 + if (SH1107_addressing) { + // set the page to our x value + data[0] = 0xB0 | (x1 & 0x07); + data_length = 1; } self->send(self->bus, data_type, chip_select, data, data_length); displayio_display_core_end_transaction(self); @@ -294,11 +295,13 @@ void displayio_display_core_set_region_to_update(displayio_display_core_t* self, data[data_length++] = y2 >> 8; data[data_length++] = y2 & 0xff; } - // Quirk for SH1107 "column_and_page_addressing" - // Page address command = 0xB0 - if (column_and_page_addressing) { - data[0] = 0xB0 | (y1 & 0x07); - data_length = 1; + // Quirk for SH1107 "SH1107_addressing" + // Note... column is y! page is x! + // Column lower command = 0x00, Column upper command = 0x10 + if (SH1107_addressing) { + data[0] = y1 & 0x0F; // 0x00 to 0x0F + data[1] = (y1 >> 4 & 0x0F) | 0x10; // 0x10 to 0x17 + data_length = 2; } self->send(self->bus, data_type, chip_select, data, data_length); @@ -319,7 +322,7 @@ void displayio_display_core_start_refresh(displayio_display_core_t* self) { void displayio_display_core_finish_refresh(displayio_display_core_t* self) { if (self->current_group != NULL) { - DISPLAYIO_CORE_DEBUG("displayiocore group_finish_refresh\n"); +// DISPLAYIO_CORE_DEBUG("displayiocore group_finish_refresh\n"); displayio_group_finish_refresh(self->current_group); } self->full_refresh = false; diff --git a/shared-module/displayio/display_core.h b/shared-module/displayio/display_core.h index 1c880be44..ad9998a2f 100644 --- a/shared-module/displayio/display_core.h +++ b/shared-module/displayio/display_core.h @@ -77,7 +77,7 @@ void displayio_display_core_end_transaction(displayio_display_core_t* self); void displayio_display_core_set_region_to_update(displayio_display_core_t* self, uint8_t column_command, uint8_t row_command, uint16_t set_current_column_command, uint16_t set_current_row_command, bool data_as_commands, bool always_toggle_chip_select, - displayio_area_t* area, bool column_and_page_addressing); + displayio_area_t* area, bool SH1107_addressing); void release_display_core(displayio_display_core_t* self); -- cgit v1.2.3 From 19dbff67f2a4921ccbe06fdf29e229225e8aed2d Mon Sep 17 00:00:00 2001 From: Mark Roberts Date: Fri, 25 Sep 2020 00:26:39 -0400 Subject: Fixed page set mask to be four bits! --- shared-module/displayio/display_core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'shared-module') diff --git a/shared-module/displayio/display_core.c b/shared-module/displayio/display_core.c index 4e36e4dd1..6e05b4757 100644 --- a/shared-module/displayio/display_core.c +++ b/shared-module/displayio/display_core.c @@ -261,7 +261,7 @@ void displayio_display_core_set_region_to_update(displayio_display_core_t* self, // Page address command = 0xB0 if (SH1107_addressing) { // set the page to our x value - data[0] = 0xB0 | (x1 & 0x07); + data[0] = 0xB0 | (x1 & 0x0F); data_length = 1; } self->send(self->bus, data_type, chip_select, data, data_length); -- cgit v1.2.3 From b9d68bc5a6b7b63f52da6c7034d379d6de51be7e Mon Sep 17 00:00:00 2001 From: Scott Shawcroft Date: Fri, 25 Sep 2020 11:07:22 -0700 Subject: Change I2C default to 100khz Greater that 100khz is technically out of the original spec. Background here: https://github.com/adafruit/Adafruit_CircuitPython_CLUE/issues/36 --- shared-bindings/busio/I2C.c | 4 ++-- shared-module/board/__init__.c | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'shared-module') diff --git a/shared-bindings/busio/I2C.c b/shared-bindings/busio/I2C.c index 157e779fd..8b456dbd3 100644 --- a/shared-bindings/busio/I2C.c +++ b/shared-bindings/busio/I2C.c @@ -39,7 +39,7 @@ //| class I2C: //| """Two wire serial protocol""" //| -//| def __init__(self, scl: microcontroller.Pin, sda: microcontroller.Pin, *, frequency: int = 400000, timeout: int = 255) -> None: +//| def __init__(self, scl: microcontroller.Pin, sda: microcontroller.Pin, *, frequency: int = 100000, timeout: int = 255) -> None: //| //| """I2C is a two-wire protocol for communicating between devices. At the //| physical level it consists of 2 wires: SCL and SDA, the clock and data @@ -70,7 +70,7 @@ STATIC mp_obj_t busio_i2c_make_new(const mp_obj_type_t *type, size_t n_args, con static const mp_arg_t allowed_args[] = { { MP_QSTR_scl, MP_ARG_REQUIRED | MP_ARG_OBJ }, { MP_QSTR_sda, MP_ARG_REQUIRED | MP_ARG_OBJ }, - { MP_QSTR_frequency, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 400000} }, + { MP_QSTR_frequency, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 100000} }, { MP_QSTR_timeout, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 255} }, }; mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; diff --git a/shared-module/board/__init__.c b/shared-module/board/__init__.c index 7d99f2d4e..fb4f731b8 100644 --- a/shared-module/board/__init__.c +++ b/shared-module/board/__init__.c @@ -61,7 +61,7 @@ mp_obj_t common_hal_board_create_i2c(void) { busio_i2c_obj_t *self = &i2c_obj; self->base.type = &busio_i2c_type; - common_hal_busio_i2c_construct(self, DEFAULT_I2C_BUS_SCL, DEFAULT_I2C_BUS_SDA, 400000, 0); + common_hal_busio_i2c_construct(self, DEFAULT_I2C_BUS_SCL, DEFAULT_I2C_BUS_SDA, 100000, 0); i2c_singleton = (mp_obj_t)self; return i2c_singleton; } -- cgit v1.2.3 From b92154357145f4e7d976306490ef33b5d5fe9c92 Mon Sep 17 00:00:00 2001 From: Mark Roberts Date: Fri, 25 Sep 2020 21:27:29 -0400 Subject: Requested changes take 1 --- .../atmel-samd/boards/hallowing_m0_express/board.c | 3 ++- .../atmel-samd/boards/hallowing_m4_express/board.c | 3 ++- ports/atmel-samd/boards/monster_m4sk/board.c | 3 ++- ports/atmel-samd/boards/pewpew_m4/board.c | 3 ++- ports/atmel-samd/boards/pybadge/board.c | 3 ++- ports/atmel-samd/boards/pybadge_airlift/board.c | 3 ++- ports/atmel-samd/boards/pygamer/board.c | 3 ++- ports/atmel-samd/boards/pygamer_advance/board.c | 3 ++- ports/atmel-samd/boards/pyportal/board.c | 3 ++- ports/atmel-samd/boards/pyportal_titano/board.c | 3 ++- .../boards/seeeduino_wio_terminal/board.c | 3 ++- ports/nrf/boards/clue_nrf52840_express/board.c | 3 ++- ports/nrf/boards/hiibot_bluefi/board.c | 3 ++- .../boards/makerdiary_nrf52840_m2_devkit/board.c | 3 ++- ports/nrf/boards/ohs2020_badge/board.c | 3 ++- ports/stm/boards/meowbit_v121/board.c | 3 ++- shared-module/displayio/Display.c | 25 ++++++---------------- shared-module/displayio/display_core.c | 4 ++-- 18 files changed, 41 insertions(+), 36 deletions(-) (limited to 'shared-module') diff --git a/ports/atmel-samd/boards/hallowing_m0_express/board.c b/ports/atmel-samd/boards/hallowing_m0_express/board.c index 4717e6ceb..14a2bdb81 100644 --- a/ports/atmel-samd/boards/hallowing_m0_express/board.c +++ b/ports/atmel-samd/boards/hallowing_m0_express/board.c @@ -110,7 +110,8 @@ void board_init(void) { false, // data_as_commands true, // auto_refresh 60, // native_frames_per_second - true); // backlight_on_high + true, // backlight_on_high + false); // not SH1107 } bool board_requests_safe_mode(void) { diff --git a/ports/atmel-samd/boards/hallowing_m4_express/board.c b/ports/atmel-samd/boards/hallowing_m4_express/board.c index 7da1d8128..61e797d65 100644 --- a/ports/atmel-samd/boards/hallowing_m4_express/board.c +++ b/ports/atmel-samd/boards/hallowing_m4_express/board.c @@ -91,7 +91,8 @@ void board_init(void) { false, // data_as_commands true, // auto_refresh 60, // native_frames_per_second - true); // backlight_on_high + true, // backlight_on_high + false); // not SH1107 } bool board_requests_safe_mode(void) { diff --git a/ports/atmel-samd/boards/monster_m4sk/board.c b/ports/atmel-samd/boards/monster_m4sk/board.c index 4dd65f8c9..45fea9d52 100644 --- a/ports/atmel-samd/boards/monster_m4sk/board.c +++ b/ports/atmel-samd/boards/monster_m4sk/board.c @@ -92,7 +92,8 @@ void board_init(void) { false, // data_as_commands true, // auto_refresh 60, // native_frames_per_second - true); // backlight_on_high + true, // backlight_on_high + false); // SH1107_addressing } bool board_requests_safe_mode(void) { diff --git a/ports/atmel-samd/boards/pewpew_m4/board.c b/ports/atmel-samd/boards/pewpew_m4/board.c index 52a52b4b7..d02e0dc01 100644 --- a/ports/atmel-samd/boards/pewpew_m4/board.c +++ b/ports/atmel-samd/boards/pewpew_m4/board.c @@ -143,7 +143,8 @@ void board_init(void) { false, // data_as_commands false, // auto_refresh 20, // native_frames_per_second - true); // backlight_on_high + true, // backlight_on_high + false); // SH1107_addressing } bool board_requests_safe_mode(void) { diff --git a/ports/atmel-samd/boards/pybadge/board.c b/ports/atmel-samd/boards/pybadge/board.c index 45298acc2..35f228c75 100644 --- a/ports/atmel-samd/boards/pybadge/board.c +++ b/ports/atmel-samd/boards/pybadge/board.c @@ -114,7 +114,8 @@ void board_init(void) { false, // data_as_commands true, // auto_refresh 60, // native_frames_per_second - true); // backlight_on_high + true, // backlight_on_high + false); // SH1107_addressing } bool board_requests_safe_mode(void) { diff --git a/ports/atmel-samd/boards/pybadge_airlift/board.c b/ports/atmel-samd/boards/pybadge_airlift/board.c index 7495c7d48..fe3e4a017 100644 --- a/ports/atmel-samd/boards/pybadge_airlift/board.c +++ b/ports/atmel-samd/boards/pybadge_airlift/board.c @@ -92,7 +92,8 @@ void board_init(void) { false, // data_as_commands true, // auto_refresh 60, // native_frames_per_second - true); // backlight_on_high + true, // backlight_on_high + false); // SH1107_addressing } bool board_requests_safe_mode(void) { diff --git a/ports/atmel-samd/boards/pygamer/board.c b/ports/atmel-samd/boards/pygamer/board.c index 2e83440ea..b478b5947 100644 --- a/ports/atmel-samd/boards/pygamer/board.c +++ b/ports/atmel-samd/boards/pygamer/board.c @@ -114,7 +114,8 @@ void board_init(void) { false, // data_as_commands true, // auto_refresh 60, // native_frames_per_second - true); // backlight_on_high + true, // backlight_on_high + false); // SH1107_addressing } bool board_requests_safe_mode(void) { diff --git a/ports/atmel-samd/boards/pygamer_advance/board.c b/ports/atmel-samd/boards/pygamer_advance/board.c index 330446b6f..7dfe07c00 100644 --- a/ports/atmel-samd/boards/pygamer_advance/board.c +++ b/ports/atmel-samd/boards/pygamer_advance/board.c @@ -92,7 +92,8 @@ void board_init(void) { false, // data_as_commands true, // auto_refresh 60, // native_frames_per_second - true); // backlight_on_high + true, // backlight_on_high + false); // SH1107_addressing } bool board_requests_safe_mode(void) { diff --git a/ports/atmel-samd/boards/pyportal/board.c b/ports/atmel-samd/boards/pyportal/board.c index d14b6b6a5..cd94f6887 100644 --- a/ports/atmel-samd/boards/pyportal/board.c +++ b/ports/atmel-samd/boards/pyportal/board.c @@ -100,7 +100,8 @@ void board_init(void) { false, // data_as_commands true, // auto_refresh 60, // native_frames_per_second - true); // backlight_on_high + true, // backlight_on_high + false); // SH1107_addressing } bool board_requests_safe_mode(void) { diff --git a/ports/atmel-samd/boards/pyportal_titano/board.c b/ports/atmel-samd/boards/pyportal_titano/board.c index 0ee2e68aa..dc417f5d1 100644 --- a/ports/atmel-samd/boards/pyportal_titano/board.c +++ b/ports/atmel-samd/boards/pyportal_titano/board.c @@ -117,7 +117,8 @@ void board_init(void) { false, // data_as_commands true, // auto_refresh 60, // native_frames_per_second - true); // backlight_on_high + true, // backlight_on_high + false); // SH1107_addressing } bool board_requests_safe_mode(void) { diff --git a/ports/atmel-samd/boards/seeeduino_wio_terminal/board.c b/ports/atmel-samd/boards/seeeduino_wio_terminal/board.c index b7fc736eb..58d0beca8 100644 --- a/ports/atmel-samd/boards/seeeduino_wio_terminal/board.c +++ b/ports/atmel-samd/boards/seeeduino_wio_terminal/board.c @@ -105,7 +105,8 @@ void board_init(void) { false, // data_as_commands true, // auto_refresh 60, // native_frames_per_second - true); // backlight_on_high + true, // backlight_on_high + false); // SH1107_addressing } bool board_requests_safe_mode(void) { diff --git a/ports/nrf/boards/clue_nrf52840_express/board.c b/ports/nrf/boards/clue_nrf52840_express/board.c index 45452a35e..523bd7677 100644 --- a/ports/nrf/boards/clue_nrf52840_express/board.c +++ b/ports/nrf/boards/clue_nrf52840_express/board.c @@ -91,7 +91,8 @@ void board_init(void) { false, // data_as_commands true, // auto_refresh 60, // native_frames_per_second - true); // backlight_on_high + true, // backlight_on_high + false); // not SH1107 } bool board_requests_safe_mode(void) { diff --git a/ports/nrf/boards/hiibot_bluefi/board.c b/ports/nrf/boards/hiibot_bluefi/board.c index 6b53cab13..93e31aef0 100644 --- a/ports/nrf/boards/hiibot_bluefi/board.c +++ b/ports/nrf/boards/hiibot_bluefi/board.c @@ -92,7 +92,8 @@ void board_init(void) { false, // data_as_commands true, // auto_refresh 60, // native_frames_per_second - true); // backlight_on_high + true, // backlight_on_high + false); // SH1107_addressing } bool board_requests_safe_mode(void) { diff --git a/ports/nrf/boards/makerdiary_nrf52840_m2_devkit/board.c b/ports/nrf/boards/makerdiary_nrf52840_m2_devkit/board.c index e7f946f4d..e08d00dac 100644 --- a/ports/nrf/boards/makerdiary_nrf52840_m2_devkit/board.c +++ b/ports/nrf/boards/makerdiary_nrf52840_m2_devkit/board.c @@ -92,7 +92,8 @@ void board_init(void) { false, // data_as_commands true, // auto_refresh 60, // native_frames_per_second - true); // backlight_on_high + true, // backlight_on_high + false); // SH1107_addressing } bool board_requests_safe_mode(void) { diff --git a/ports/nrf/boards/ohs2020_badge/board.c b/ports/nrf/boards/ohs2020_badge/board.c index 9fcf9d2bf..ec52690ce 100644 --- a/ports/nrf/boards/ohs2020_badge/board.c +++ b/ports/nrf/boards/ohs2020_badge/board.c @@ -91,7 +91,8 @@ void board_init(void) { false, // data_as_commands true, // auto_refresh 60, // native_frames_per_second - false); // backlight_on_high + false, // backlight_on_high + false); // SH1107_addressing } bool board_requests_safe_mode(void) { diff --git a/ports/stm/boards/meowbit_v121/board.c b/ports/stm/boards/meowbit_v121/board.c index b74f13516..f67b4a49d 100644 --- a/ports/stm/boards/meowbit_v121/board.c +++ b/ports/stm/boards/meowbit_v121/board.c @@ -111,7 +111,8 @@ void board_init(void) { false, // data_as_commands true, // auto_refresh 60, // native_frames_per_second - true); // backlight_on_high + true, // backlight_on_high + false); // SH1107_addressing } bool board_requests_safe_mode(void) { diff --git a/shared-module/displayio/Display.c b/shared-module/displayio/Display.c index afc4b7564..9864e9f9d 100644 --- a/shared-module/displayio/Display.c +++ b/shared-module/displayio/Display.c @@ -252,14 +252,8 @@ STATIC bool _refresh_area(displayio_display_obj_t* self, const displayio_area_t* // write one single row at a time if (self->SH1107_addressing) { subrectangles = rows_per_buffer; // vertical (column mode) write each separately (height times) - } - - // Skip this recalculation of subrectangles if SH1107 (each subrectangle is a single row) - // [mdroberts1243] I am worried/confused about the pixels_in_byte_share_row calculation though - // since it makes sense to be on a byte boundary (actually a page boundary too) - // seems to work as is though. - if ((displayio_area_size(&clipped) > buffer_size * pixels_per_word) - && (!self->SH1107_addressing)) { + rows_per_buffer = 1; + } else if (displayio_area_size(&clipped) > buffer_size * pixels_per_word) { rows_per_buffer = buffer_size * pixels_per_word / displayio_area_width(&clipped); if (rows_per_buffer == 0) { rows_per_buffer = 1; @@ -297,18 +291,13 @@ STATIC bool _refresh_area(displayio_display_obj_t* self, const displayio_area_t* .y2 = clipped.y1 + rows_per_buffer * (j + 1) }; if (self->SH1107_addressing) { - // one row only for SH1107 in vertical (column) mode - subrectangle.y1 = clipped.y1 + j; - subrectangle.y2 = clipped.y1 + (j + 1); - }; - if ((remaining_rows < rows_per_buffer) && (!self->SH1107_addressing)) { + // one row only for SH1107 in vertical (column) mode + subrectangle.y1 = clipped.y1 + j; + subrectangle.y2 = clipped.y1 + (j + 1); + } else if (remaining_rows < rows_per_buffer) { subrectangle.y2 = subrectangle.y1 + remaining_rows; } - if (self->SH1107_addressing) { - remaining_rows -= 1; - } else { - remaining_rows -= rows_per_buffer; - } + remaining_rows -= rows_per_buffer; displayio_display_core_set_region_to_update(&self->core, self->set_column_command, self->set_row_command, NO_COMMAND, NO_COMMAND, self->data_as_commands, false, diff --git a/shared-module/displayio/display_core.c b/shared-module/displayio/display_core.c index 6e05b4757..eb8c8f3b4 100644 --- a/shared-module/displayio/display_core.c +++ b/shared-module/displayio/display_core.c @@ -41,7 +41,7 @@ #include #define DISPLAYIO_CORE_DEBUG(...) (void)0 -//#define DISPLAYIO_CORE_DEBUG(...) mp_printf(&mp_plat_print __VA_OPT__(,) __VA_ARGS__) +// #define DISPLAYIO_CORE_DEBUG(...) mp_printf(&mp_plat_print __VA_OPT__(,) __VA_ARGS__) void displayio_display_core_construct(displayio_display_core_t* self, mp_obj_t bus, uint16_t width, uint16_t height, uint16_t ram_width, uint16_t ram_height, int16_t colstart, int16_t rowstart, uint16_t rotation, @@ -322,7 +322,7 @@ void displayio_display_core_start_refresh(displayio_display_core_t* self) { void displayio_display_core_finish_refresh(displayio_display_core_t* self) { if (self->current_group != NULL) { -// DISPLAYIO_CORE_DEBUG("displayiocore group_finish_refresh\n"); + DISPLAYIO_CORE_DEBUG("displayiocore group_finish_refresh\n"); displayio_group_finish_refresh(self->current_group); } self->full_refresh = false; -- cgit v1.2.3 From 79ca430ddf25a71c73d6219fb68160fb405c3777 Mon Sep 17 00:00:00 2001 From: Jeff Epler Date: Thu, 24 Sep 2020 13:58:45 -0500 Subject: Match: address -> id --- ports/atmel-samd/common-hal/canio/Listener.c | 60 ++++++++++++++-------------- shared-bindings/canio/Match.c | 46 ++++++++++----------- shared-bindings/canio/Match.h | 4 +- shared-module/canio/Match.c | 8 ++-- shared-module/canio/Match.h | 2 +- 5 files changed, 60 insertions(+), 60 deletions(-) (limited to 'shared-module') diff --git a/ports/atmel-samd/common-hal/canio/Listener.c b/ports/atmel-samd/common-hal/canio/Listener.c index 02cfde9cc..d21ebbb31 100644 --- a/ports/atmel-samd/common-hal/canio/Listener.c +++ b/ports/atmel-samd/common-hal/canio/Listener.c @@ -58,8 +58,8 @@ STATIC void static_assertions(void) { MP_STATIC_ASSERT(CAN_XIDFE_0_EFEC_STF0M_Val + 1 == CAN_XIDFE_0_EFEC_STF1M_Val); } -STATIC bool single_address_filter(canio_match_obj_t *match) { - return match->mask == 0 || match->mask == match->address; +STATIC bool single_id_filter(canio_match_obj_t *match) { + return match->mask == 0 || match->mask == match->id; } STATIC bool standard_filter_in_use(CanMramSidfe *filter) { @@ -76,7 +76,7 @@ STATIC size_t num_filters_needed(size_t nmatch, canio_match_obj_t **matches, boo if (extended != matches[i]->extended) { continue; } - if (single_address_filter(matches[i])) { + if (single_id_filter(matches[i])) { num_half_filters_needed += 1; } else { num_half_filters_needed += 2; @@ -191,7 +191,7 @@ STATIC void install_extended_filter(CanMramXidfe *extended, int id1, int id2, in } -#define NO_ADDRESS (-1) +#define NO_ID (-1) void set_filters(canio_listener_obj_t *self, size_t nmatch, canio_match_obj_t **matches) { int fifo = self->fifo_idx; @@ -207,31 +207,31 @@ void set_filters(canio_listener_obj_t *self, size_t nmatch, canio_match_obj_t ** CanMramSidfe *standard = next_standard_filter(self, NULL); CanMramXidfe *extended = next_extended_filter(self, NULL); - int first_address = NO_ADDRESS; + int first_id = NO_ID; - // step 1: single address standard matches + // step 1: single id standard matches // we have to gather up pairs and stuff them in a single filter entry for(size_t i = 0; iextended) { continue; } - if (!single_address_filter(match)) { + if (!single_id_filter(match)) { continue; } - if (first_address != NO_ADDRESS) { - install_standard_filter(standard, first_address, match->address, CAN_SIDFE_0_SFEC_STF0M_Val + fifo, CAN_SIDFE_0_SFT_DUAL_Val); - first_address = NO_ADDRESS; + if (first_id != NO_ID) { + install_standard_filter(standard, first_id, match->id, CAN_SIDFE_0_SFEC_STF0M_Val + fifo, CAN_SIDFE_0_SFT_DUAL_Val); + first_id = NO_ID; standard = next_standard_filter(self, standard); } else { - first_address = match->address; + first_id = match->id; } } - // step 1.5. odd single address standard match - if (first_address != NO_ADDRESS) { - install_standard_filter(standard, first_address, first_address, CAN_SIDFE_0_SFEC_STF0M_Val + fifo, CAN_SIDFE_0_SFT_DUAL_Val); + // step 1.5. odd single id standard match + if (first_id != NO_ID) { + install_standard_filter(standard, first_id, first_id, CAN_SIDFE_0_SFEC_STF0M_Val + fifo, CAN_SIDFE_0_SFT_DUAL_Val); standard = next_standard_filter(self, standard); - first_address = NO_ADDRESS; + first_id = NO_ID; } // step 2: standard mask filter @@ -240,36 +240,36 @@ void set_filters(canio_listener_obj_t *self, size_t nmatch, canio_match_obj_t ** if (match->extended) { continue; } - if (single_address_filter(match)) { + if (single_id_filter(match)) { continue; } - install_standard_filter(standard, match->address, match->mask, CAN_SIDFE_0_SFEC_STF0M_Val + fifo, CAN_SIDFE_0_SFT_CLASSIC_Val); + install_standard_filter(standard, match->id, match->mask, CAN_SIDFE_0_SFEC_STF0M_Val + fifo, CAN_SIDFE_0_SFT_CLASSIC_Val); standard = next_standard_filter(self, standard); } - // step 3: single address extended matches + // step 3: single id extended matches // we have to gather up pairs and stuff them in a single filter entry for(size_t i = 0; iextended) { continue; } - if (!single_address_filter(match)) { + if (!single_id_filter(match)) { continue; } - if (first_address != NO_ADDRESS) { - install_extended_filter(extended, first_address, match->address, CAN_XIDFE_0_EFEC_STF0M_Val + fifo, CAN_XIDFE_1_EFT_DUAL_Val); - first_address = NO_ADDRESS; + if (first_id != NO_ID) { + install_extended_filter(extended, first_id, match->id, CAN_XIDFE_0_EFEC_STF0M_Val + fifo, CAN_XIDFE_1_EFT_DUAL_Val); + first_id = NO_ID; extended = next_extended_filter(self, extended); } else { - first_address = match->address; + first_id = match->id; } } - // step 3.5. odd single address standard match - if (first_address != NO_ADDRESS) { - install_extended_filter(extended, first_address, first_address, CAN_XIDFE_0_EFEC_STF0M_Val + fifo, CAN_XIDFE_1_EFT_DUAL_Val); + // step 3.5. odd single id standard match + if (first_id != NO_ID) { + install_extended_filter(extended, first_id, first_id, CAN_XIDFE_0_EFEC_STF0M_Val + fifo, CAN_XIDFE_1_EFT_DUAL_Val); extended = next_extended_filter(self, extended); - first_address = NO_ADDRESS; + first_id = NO_ID; } // step 4: extended mask filters @@ -278,10 +278,10 @@ void set_filters(canio_listener_obj_t *self, size_t nmatch, canio_match_obj_t ** if (!match->extended) { continue; } - if (single_address_filter(match)) { + if (single_id_filter(match)) { continue; } - install_extended_filter(extended, match->address, match->mask, CAN_XIDFE_0_EFEC_STF0M_Val + fifo, CAN_XIDFE_1_EFT_CLASSIC_Val); + install_extended_filter(extended, match->id, match->mask, CAN_XIDFE_0_EFEC_STF0M_Val + fifo, CAN_XIDFE_1_EFT_CLASSIC_Val); extended = next_extended_filter(self, extended); } @@ -363,7 +363,7 @@ bool common_hal_canio_listener_readinto(canio_listener_obj_t *self, canio_messag if (message->extended) { message->id = hw_message->rxf0.bit.ID; } else { - message->id = hw_message->rxf0.bit.ID >> 18; // short addresses are left-justified + message->id = hw_message->rxf0.bit.ID >> 18; // short ids are left-justified } message->rtr = hw_message->rxf0.bit.RTR; message->size = hw_message->rxf1.bit.DLC; diff --git a/shared-bindings/canio/Match.c b/shared-bindings/canio/Match.c index ff5d028fa..91a9dd02a 100644 --- a/shared-bindings/canio/Match.c +++ b/shared-bindings/canio/Match.c @@ -33,19 +33,19 @@ //| """Describe CAN bus messages to match""" //| //| -//| def __init__(self, address: int, *, mask: int = 0, extended: bool = False): +//| def __init__(self, id: int, *, mask: int = 0, extended: bool = False): //| """Construct a Match with the given properties. //| -//| If mask is nonzero, then the filter is for any sender which matches all -//| the nonzero bits in mask. Otherwise, it matches exactly the given address. -//| If extended is true then only extended addresses are matched, otherwise -//| only standard addresses are matched.""" +//| If mask is nonzero, then the filter is for any id which matches all +//| the nonzero bits in mask. Otherwise, it matches exactly the given id. +//| If extended is true then only extended ids are matched, otherwise +//| only standard ids are matched.""" //| STATIC mp_obj_t canio_match_make_new(const mp_obj_type_t *type, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { - enum { ARG_address, ARG_mask, ARG_extended, NUM_ARGS }; + enum { ARG_id, ARG_mask, ARG_extended, NUM_ARGS }; static const mp_arg_t allowed_args[] = { - { MP_QSTR_address, MP_ARG_INT | MP_ARG_REQUIRED }, + { MP_QSTR_id, MP_ARG_INT | MP_ARG_REQUIRED }, { MP_QSTR_mask, MP_ARG_INT, {.u_int = 0} }, { MP_QSTR_extended, MP_ARG_BOOL, {.u_bool = false} }, }; @@ -54,44 +54,44 @@ STATIC mp_obj_t canio_match_make_new(const mp_obj_type_t *type, size_t n_args, c mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); - int address_bits = args[ARG_extended].u_bool ? 0x1fffffff : 0x7ff; - int address = args[ARG_address].u_int; + int id_bits = args[ARG_extended].u_bool ? 0x1fffffff : 0x7ff; + int id = args[ARG_id].u_int; int mask = args[ARG_mask].u_int; - if (address & ~address_bits) { - mp_raise_ValueError_varg(translate("%q out of range"), MP_QSTR_address); + if (id & ~id_bits) { + mp_raise_ValueError_varg(translate("%q out of range"), MP_QSTR_id); } - if (mask & ~address_bits) { + if (mask & ~id_bits) { mp_raise_ValueError_varg(translate("%q out of range"), MP_QSTR_mask); } canio_match_obj_t *self = m_new_obj(canio_match_obj_t); self->base.type = &canio_match_type; - common_hal_canio_match_construct(self, args[ARG_address].u_int, args[ARG_mask].u_int, args[ARG_extended].u_bool); + common_hal_canio_match_construct(self, args[ARG_id].u_int, args[ARG_mask].u_int, args[ARG_extended].u_bool); return self; } -//| address: int -//| """The address to match""" +//| id: int +//| """The id to match""" //| -STATIC mp_obj_t canio_match_address_get(mp_obj_t self_in) { +STATIC mp_obj_t canio_match_id_get(mp_obj_t self_in) { canio_match_obj_t *self = self_in; - return MP_OBJ_NEW_SMALL_INT(common_hal_canio_match_get_address(self)); + return MP_OBJ_NEW_SMALL_INT(common_hal_canio_match_get_id(self)); } -MP_DEFINE_CONST_FUN_OBJ_1(canio_match_address_get_obj, canio_match_address_get); +MP_DEFINE_CONST_FUN_OBJ_1(canio_match_id_get_obj, canio_match_id_get); -const mp_obj_property_t canio_match_address_obj = { +const mp_obj_property_t canio_match_id_obj = { .base.type = &mp_type_property, - .proxy = {(mp_obj_t)&canio_match_address_get_obj, + .proxy = {(mp_obj_t)&canio_match_id_get_obj, (mp_obj_t)&mp_const_none_obj, (mp_obj_t)&mp_const_none_obj}, }; //| //| mask: int -//| """The optional mask of addresses to match""" +//| """The optional mask of ids to match""" //| STATIC mp_obj_t canio_match_mask_get(mp_obj_t self_in) { @@ -108,7 +108,7 @@ const mp_obj_property_t canio_match_mask_obj = { }; //| extended: bool -//| """True to match extended addresses, False to match standard addresses""" +//| """True to match extended ids, False to match standard ides""" //| STATIC mp_obj_t canio_match_extended_get(mp_obj_t self_in) { @@ -125,7 +125,7 @@ const mp_obj_property_t canio_match_extended_obj = { }; STATIC const mp_rom_map_elem_t canio_match_locals_dict_table[] = { - { MP_ROM_QSTR(MP_QSTR_address), MP_ROM_PTR(&canio_match_address_obj) }, + { MP_ROM_QSTR(MP_QSTR_id), MP_ROM_PTR(&canio_match_id_obj) }, { MP_ROM_QSTR(MP_QSTR_mask), MP_ROM_PTR(&canio_match_mask_obj) }, { MP_ROM_QSTR(MP_QSTR_extended), MP_ROM_PTR(&canio_match_extended_obj) }, }; diff --git a/shared-bindings/canio/Match.h b/shared-bindings/canio/Match.h index 88996d730..01a75fd1c 100644 --- a/shared-bindings/canio/Match.h +++ b/shared-bindings/canio/Match.h @@ -31,7 +31,7 @@ extern const mp_obj_type_t canio_match_type; -void common_hal_canio_match_construct(canio_match_obj_t *self, int address, int mask, bool extended); -int common_hal_canio_match_get_address(const canio_match_obj_t *self); +void common_hal_canio_match_construct(canio_match_obj_t *self, int id, int mask, bool extended); +int common_hal_canio_match_get_id(const canio_match_obj_t *self); int common_hal_canio_match_get_mask(const canio_match_obj_t *self); bool common_hal_canio_match_get_extended(const canio_match_obj_t *self); diff --git a/shared-module/canio/Match.c b/shared-module/canio/Match.c index 9e33b956f..b4e8616e9 100644 --- a/shared-module/canio/Match.c +++ b/shared-module/canio/Match.c @@ -26,14 +26,14 @@ #include "shared-module/canio/Match.h" -void common_hal_canio_match_construct(canio_match_obj_t *self, int address, int mask, bool extended) { - self->address = address; +void common_hal_canio_match_construct(canio_match_obj_t *self, int id, int mask, bool extended) { + self->id = id; self->mask = mask; self->extended = extended; } -int common_hal_canio_match_get_address(const canio_match_obj_t *self) { - return self->address; +int common_hal_canio_match_get_id(const canio_match_obj_t *self) { + return self->id; } int common_hal_canio_match_get_mask(const canio_match_obj_t *self) { return self->mask; diff --git a/shared-module/canio/Match.h b/shared-module/canio/Match.h index 25f047f37..b52191d7c 100644 --- a/shared-module/canio/Match.h +++ b/shared-module/canio/Match.h @@ -30,7 +30,7 @@ typedef struct { mp_obj_base_t base; - int address; + int id; int mask; bool extended; } canio_match_obj_t; -- cgit v1.2.3 From 8d45be1cd99c6fbfcb69877ab335e010810c54fd Mon Sep 17 00:00:00 2001 From: Jeff Epler Date: Thu, 24 Sep 2020 15:25:06 -0500 Subject: canio: Split RemoteTransmissionRequest to its own class It reuses most of canio.Message's implementation, and structure --- shared-bindings/canio/CAN.c | 6 +- shared-bindings/canio/Listener.c | 6 +- shared-bindings/canio/Message.c | 132 ++++++++++++++++++++++++--------------- shared-bindings/canio/Message.h | 7 ++- shared-bindings/canio/__init__.c | 1 + shared-module/canio/Message.c | 10 ++- 6 files changed, 99 insertions(+), 63 deletions(-) (limited to 'shared-module') diff --git a/shared-bindings/canio/CAN.c b/shared-bindings/canio/CAN.c index ff27bb204..6b7a3878e 100644 --- a/shared-bindings/canio/CAN.c +++ b/shared-bindings/canio/CAN.c @@ -265,7 +265,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_1(canio_can_restart_obj, canio_can_restart); //| //| An empty filter list causes all messages to be accepted. //| -//| Timeout dictates how long readinto, read and next() will block.""" +//| Timeout dictates how long receive() and next() will block.""" //| ... //| STATIC mp_obj_t canio_can_listen(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { @@ -334,8 +334,8 @@ STATIC mp_obj_t canio_can_send(mp_obj_t self_in, mp_obj_t message_in) { canio_can_obj_t *self = MP_OBJ_TO_PTR(self_in); common_hal_canio_can_check_for_deinit(self); mp_obj_type_t *message_type = mp_obj_get_type(message_in); - if (message_type != &canio_message_type) { - mp_raise_TypeError_varg(translate("expected '%q' but got '%q'"), MP_QSTR_Message, message_type->name); + if (message_type != &canio_message_type && message_type != &canio_remote_transmission_request_type) { + mp_raise_TypeError_varg(translate("expected '%q' or '%q' but got '%q'"), MP_QSTR_Message, MP_QSTR_RemoteTransmissionRequest, message_type->name); } canio_message_obj_t *message = message_in; diff --git a/shared-bindings/canio/Listener.c b/shared-bindings/canio/Listener.c index 5159c8481..9f3fe05c5 100644 --- a/shared-bindings/canio/Listener.c +++ b/shared-bindings/canio/Listener.c @@ -50,9 +50,13 @@ STATIC mp_obj_t canio_listener_receive(mp_obj_t self_in) { common_hal_canio_listener_check_for_deinit(self); canio_message_obj_t *message = m_new_obj(canio_message_obj_t); - message->base.type = &canio_message_type; if (common_hal_canio_listener_receiveinto(self, message)) { + if (message->rtr) { + message->base.type = &canio_remote_transmission_request_type; + } else { + message->base.type = &canio_message_type; + } return message; } else { m_free(message); // message did not escape into vm diff --git a/shared-bindings/canio/Message.c b/shared-bindings/canio/Message.c index 8d1828fba..ae03c25e7 100644 --- a/shared-bindings/canio/Message.c +++ b/shared-bindings/canio/Message.c @@ -31,28 +31,22 @@ #include "py/runtime.h" //| class Message: -//| def __init__(self, id: int=0, data: Optional[bytes] = None, *, size: Optional[int] = None, rtr: bool = False, extended: bool = False): -//| """Construct a Message to use with a CAN bus. Provide arguments to create a message to send. Otherwise, use Listener.readinto() to read a message. +//| def __init__(self, id: int, data: bytes, *, extended: bool = False): +//| """Construct a Message to send on a CAN bus. //| //| :param int id: The numeric ID of the message //| :param bytes data: The content of the message -//| :param int size: The amount of data requested, for an rtr -//| :param bool rtr: True if the message represents an rtr (Remote Transmission Request) //| :param bool extended: True if the message has an extended identifier, False if it has a standard identifier //| -//| In CAN, messages can have a size from 0 to 8 bytes. -//| -//| For a non-rtr message, specify ``data``. For an rtr-message, specify either ``data`` (a dummy buffer of the requested size) or ``size``. +//| In CAN, messages can have a length from 0 to 8 bytes. //| """ //| ... //| STATIC mp_obj_t canio_message_make_new(const mp_obj_type_t *type, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { - enum { ARG_id, ARG_data, ARG_size, ARG_rtr, ARG_extended, NUM_ARGS }; + enum { ARG_id, ARG_data, ARG_extended, NUM_ARGS }; static const mp_arg_t allowed_args[] = { - { MP_QSTR_id, MP_ARG_INT, {.u_obj = 0} }, - { MP_QSTR_data, MP_ARG_OBJ, {.u_obj = 0} }, - { MP_QSTR_size, MP_ARG_INT, {.u_int = -1} }, - { MP_QSTR_rtr, MP_ARG_BOOL, {.u_bool = false} }, + { MP_QSTR_id, MP_ARG_INT | MP_ARG_REQUIRED }, + { MP_QSTR_data, MP_ARG_OBJ | MP_ARG_REQUIRED }, { MP_QSTR_extended, MP_ARG_BOOL, {.u_bool = false} }, }; mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; @@ -60,26 +54,8 @@ STATIC mp_obj_t canio_message_make_new(const mp_obj_type_t *type, size_t n_args, mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); - bool rtr = args[ARG_rtr].u_bool; - bool extended = args[ARG_extended].u_bool; - size_t size = (size_t)args[ARG_size].u_int; - bool specified_size = (size != (size_t)-1); - bool specified_data = (args[ARG_data].u_obj != NULL); - - if (specified_size && specified_data) { - mp_raise_TypeError(translate("specify size or data, but not both")); - } - mp_buffer_info_t data; - if (specified_data) { - mp_get_buffer_raise(args[ARG_data].u_obj, &data, MP_BUFFER_READ); - } else if (specified_size) { - data.buf = 0; - data.len = size; - } else { - data.buf = 0; - data.len = 0; - } + mp_get_buffer_raise(args[ARG_data].u_obj, &data, MP_BUFFER_READ); if (data.len > 8) { mp_raise_ValueError(translate("Messages limited to 8 bytes")); @@ -87,7 +63,7 @@ STATIC mp_obj_t canio_message_make_new(const mp_obj_type_t *type, size_t n_args, canio_message_obj_t *self = m_new_obj(canio_message_obj_t); self->base.type = &canio_message_type; - common_hal_canio_message_construct(self, args[ARG_id].u_int, data.buf, data.len, rtr, extended); + common_hal_canio_message_construct(self, args[ARG_id].u_int, data.buf, data.len, args[ARG_extended].u_bool); return self; } @@ -115,13 +91,11 @@ STATIC const mp_obj_property_t canio_message_id_obj = { }; //| data: bytes -//| """The content of the message, or dummy content in the case of an rtr. -//| -//| Assigning to data also clears the rtr flag, if it was set.""" +//| """The content of the message""" //| STATIC mp_obj_t canio_message_data_get(const mp_obj_t self_in) { canio_message_obj_t *self = self_in; - return mp_obj_new_bytes((const byte*)common_hal_canio_message_get_data(self), common_hal_canio_message_get_size(self)); + return mp_obj_new_bytes((const byte*)common_hal_canio_message_get_data(self), common_hal_canio_message_get_length(self)); } MP_DEFINE_CONST_FUN_OBJ_1(canio_message_data_get_obj, canio_message_data_get); @@ -147,7 +121,7 @@ STATIC const mp_obj_property_t canio_message_data_obj = { //| extended: bool -//| """True if the message represents a remote transmission request (RTR)""" +//| """True if the message's id is an extended id""" //| STATIC mp_obj_t canio_message_extended_get(const mp_obj_t self_in) { canio_message_obj_t *self = self_in; @@ -170,36 +144,80 @@ STATIC const mp_obj_property_t canio_message_extended_obj = { (mp_obj_t)&mp_const_none_obj}, }; +//| class RemoteTransmissionRequest: +//| def __init__(self, id: int, length: int, *, extended: bool = False): +//| """Construct a Message to send on a CAN bus. +//| +//| :param int id: The numeric ID of the requested message +//| :param int length: The length of the requested message +//| :param bool extended: True if the message has an extended identifier, False if it has a standard identifier +//| +//| In CAN, messages can have a length from 0 to 8 bytes. +//| """ +//| ... +//| +STATIC mp_obj_t canio_remote_transmission_request_make_new(const mp_obj_type_t *type, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + enum { ARG_id, ARG_length, ARG_extended, NUM_ARGS }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_id, MP_ARG_INT | MP_ARG_REQUIRED }, + { MP_QSTR_length, MP_ARG_INT | MP_ARG_REQUIRED }, + { MP_QSTR_extended, MP_ARG_BOOL, {.u_bool = false} }, + }; + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + MP_STATIC_ASSERT( MP_ARRAY_SIZE(allowed_args) == NUM_ARGS ); + + mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + int length = args[ARG_length].u_int; + if (length < 0 || length > 8) { + mp_raise_ValueError(translate("Messages limited to 8 bytes")); + } -//| rtr: bool -//| """True if the message represents a remote transmission request (RTR). Setting rtr to true zeros out data""" + canio_message_obj_t *self = m_new_obj(canio_message_obj_t); + self->base.type = &canio_remote_transmission_request_type; + common_hal_canio_message_construct(self, args[ARG_id].u_int, NULL, length, args[ARG_extended].u_bool); + return self; +} + +//| extended: bool +//| """True if the message's id is an extended id""" +//| + +//| id: int +//| """The numeric ID of the message""" +//| + +//| length: int +//| """The length of the requested message.""" //| -STATIC mp_obj_t canio_message_rtr_get(const mp_obj_t self_in) { +STATIC mp_obj_t canio_remote_transmission_request_length_get(const mp_obj_t self_in) { canio_message_obj_t *self = self_in; - return mp_obj_new_bool(common_hal_canio_message_get_rtr(self)); + return MP_OBJ_NEW_SMALL_INT(common_hal_canio_message_get_length(self)); } -MP_DEFINE_CONST_FUN_OBJ_1(canio_message_rtr_get_obj, canio_message_rtr_get); +MP_DEFINE_CONST_FUN_OBJ_1(canio_remote_transmission_request_length_get_obj, canio_remote_transmission_request_length_get); -STATIC mp_obj_t canio_message_rtr_set(const mp_obj_t self_in, const mp_obj_t rtr) { +STATIC mp_obj_t canio_remote_transmission_request_length_set(const mp_obj_t self_in, const mp_obj_t length_in) { canio_message_obj_t *self = self_in; - common_hal_canio_message_set_rtr(self, mp_obj_is_true(rtr)); + int length = mp_obj_get_int(length_in); + if (length < 0 || length > 8) { + mp_raise_ValueError(translate("Messages limited to 8 bytes")); + } + common_hal_canio_remote_transmission_request_set_length(self, length); return mp_const_none; } -MP_DEFINE_CONST_FUN_OBJ_2(canio_message_rtr_set_obj, canio_message_rtr_set); +MP_DEFINE_CONST_FUN_OBJ_2(canio_remote_transmission_request_length_set_obj, canio_remote_transmission_request_length_set); -STATIC const mp_obj_property_t canio_message_rtr_obj = { +STATIC const mp_obj_property_t canio_remote_transmission_request_length_obj = { .base.type = &mp_type_property, - .proxy = {(mp_obj_t)&canio_message_rtr_get_obj, - (mp_obj_t)&canio_message_rtr_set_obj, + .proxy = {(mp_obj_t)&canio_remote_transmission_request_length_get_obj, + (mp_obj_t)&canio_remote_transmission_request_length_set_obj, (mp_obj_t)&mp_const_none_obj}, }; - STATIC const mp_rom_map_elem_t canio_message_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_id), MP_ROM_PTR(&canio_message_id_obj) }, { MP_ROM_QSTR(MP_QSTR_data), MP_ROM_PTR(&canio_message_data_obj) }, - { MP_ROM_QSTR(MP_QSTR_rtr), MP_ROM_PTR(&canio_message_rtr_obj) }, { MP_ROM_QSTR(MP_QSTR_extended), MP_ROM_PTR(&canio_message_extended_obj) }, }; STATIC MP_DEFINE_CONST_DICT(canio_message_locals_dict, canio_message_locals_dict_table); @@ -210,3 +228,17 @@ const mp_obj_type_t canio_message_type = { .make_new = canio_message_make_new, .locals_dict = (mp_obj_t)&canio_message_locals_dict, }; + +STATIC const mp_rom_map_elem_t canio_remote_transmission_request_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_id), MP_ROM_PTR(&canio_message_id_obj) }, + { MP_ROM_QSTR(MP_QSTR_length), MP_ROM_PTR(&canio_remote_transmission_request_length_obj) }, + { MP_ROM_QSTR(MP_QSTR_extended), MP_ROM_PTR(&canio_message_extended_obj) }, +}; +STATIC MP_DEFINE_CONST_DICT(canio_remote_transmission_request_locals_dict, canio_remote_transmission_request_locals_dict_table); + +const mp_obj_type_t canio_remote_transmission_request_type = { + { &mp_type_type }, + .name = MP_QSTR_RemoteTransmissionRequest, + .make_new = canio_remote_transmission_request_make_new, + .locals_dict = (mp_obj_t)&canio_remote_transmission_request_locals_dict, +}; diff --git a/shared-bindings/canio/Message.h b/shared-bindings/canio/Message.h index 34b632e84..96716864c 100644 --- a/shared-bindings/canio/Message.h +++ b/shared-bindings/canio/Message.h @@ -30,8 +30,9 @@ #include "shared-module/canio/Message.h" extern const mp_obj_type_t canio_message_type; +extern const mp_obj_type_t canio_remote_transmission_request_type; -void common_hal_canio_message_construct(canio_message_obj_t *self, int id, void *data, size_t size, bool rtr, bool extended); +void common_hal_canio_message_construct(canio_message_obj_t *self, int id, void *data, size_t size, bool extended); const void *common_hal_canio_message_get_data(const canio_message_obj_t *self); void common_hal_canio_message_set_data(canio_message_obj_t *self, const void *data, size_t size); bool common_hal_canio_message_get_extended(const canio_message_obj_t *self); @@ -40,5 +41,5 @@ int common_hal_canio_message_get_id(const canio_message_obj_t *self); void common_hal_canio_message_set_id(canio_message_obj_t *self, int id); bool common_hal_canio_message_get_rtr(const canio_message_obj_t *self); void common_hal_canio_message_set_rtr(canio_message_obj_t *self, bool rtr); -size_t common_hal_canio_message_get_size(const canio_message_obj_t *self); -void common_hal_canio_message_set_size(canio_message_obj_t *self, size_t size); +size_t common_hal_canio_message_get_length(const canio_message_obj_t *self); +void common_hal_canio_remote_transmission_request_set_length(canio_message_obj_t *self, size_t length); diff --git a/shared-bindings/canio/__init__.c b/shared-bindings/canio/__init__.c index 409cc20cf..f29d3ab8a 100644 --- a/shared-bindings/canio/__init__.c +++ b/shared-bindings/canio/__init__.c @@ -113,6 +113,7 @@ STATIC const mp_rom_map_elem_t canio_module_globals_table[] = { { MP_ROM_QSTR(MP_QSTR_Listener), MP_ROM_PTR(&canio_listener_type) }, { MP_ROM_QSTR(MP_QSTR_Match), MP_ROM_PTR(&canio_match_type) }, { MP_ROM_QSTR(MP_QSTR_Message), MP_ROM_PTR(&canio_message_type) }, + { MP_ROM_QSTR(MP_QSTR_RemoteTransmissionRequest), MP_ROM_PTR(&canio_remote_transmission_request_type) }, { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR__canio) }, }; diff --git a/shared-module/canio/Message.c b/shared-module/canio/Message.c index b8ebb7859..86a3b7106 100644 --- a/shared-module/canio/Message.c +++ b/shared-module/canio/Message.c @@ -28,16 +28,14 @@ #include -void common_hal_canio_message_construct(canio_message_obj_t *self, int id, void *data, size_t size, bool rtr, bool extended) +void common_hal_canio_message_construct(canio_message_obj_t *self, int id, void *data, size_t size, bool extended) { self->id = id; self->size = size; - self->rtr = rtr; + self->rtr = !data; self->extended = extended; if (data) { memcpy(self->data, data, size); - } else { - memset(self->data, 0, size); } } @@ -65,12 +63,12 @@ const void common_hal_canio_message_set_data(canio_message_obj_t *self, const vo } -size_t common_hal_canio_message_get_size(const canio_message_obj_t *self) +size_t common_hal_canio_message_get_length(const canio_message_obj_t *self) { return self->size; } -void common_hal_canio_message_set_size(canio_message_obj_t *self, size_t size) +void common_hal_canio_remote_transmission_request_set_length(canio_message_obj_t *self, size_t size) { memset(self->data, 0, size); self->size = size; -- cgit v1.2.3 From a4cc3ad6cb75845e0dc75ede97b8287bb1af0317 Mon Sep 17 00:00:00 2001 From: Jeff Epler Date: Sat, 26 Sep 2020 09:44:11 -0500 Subject: canio: RemoteTransmissionRequest: Split implementation, keep one structure This already begins obscuring things, because now there are two sets of shared-module functions for manipulating the same structure, e.g., common_hal_canio_remote_transmission_request_get_id and common_hal_canio_message_get_id --- py/circuitpy_defns.mk | 1 + shared-bindings/canio/Message.c | 85 ----------- shared-bindings/canio/Message.h | 2 - shared-bindings/canio/RemoteTransmissionRequest.c | 164 ++++++++++++++++++++++ shared-bindings/canio/RemoteTransmissionRequest.h | 42 ++++++ shared-module/canio/Message.c | 20 --- shared-module/canio/RemoteTransmissionRequest.c | 68 +++++++++ shared-module/canio/RemoteTransmissionRequest.h | 33 +++++ 8 files changed, 308 insertions(+), 107 deletions(-) create mode 100644 shared-bindings/canio/RemoteTransmissionRequest.c create mode 100644 shared-bindings/canio/RemoteTransmissionRequest.h create mode 100644 shared-module/canio/RemoteTransmissionRequest.c create mode 100644 shared-module/canio/RemoteTransmissionRequest.h (limited to 'shared-module') diff --git a/py/circuitpy_defns.mk b/py/circuitpy_defns.mk index 98fa7a5f2..76c0a4db6 100644 --- a/py/circuitpy_defns.mk +++ b/py/circuitpy_defns.mk @@ -411,6 +411,7 @@ SRC_SHARED_MODULE_ALL = \ _bleio/ScanResults.c \ canio/Match.c \ canio/Message.c \ + canio/RemoteTransmissionRequest.c \ _eve/__init__.c \ _pixelbuf/PixelBuf.c \ _pixelbuf/__init__.c \ diff --git a/shared-bindings/canio/Message.c b/shared-bindings/canio/Message.c index ae03c25e7..e47e997c7 100644 --- a/shared-bindings/canio/Message.c +++ b/shared-bindings/canio/Message.c @@ -144,77 +144,6 @@ STATIC const mp_obj_property_t canio_message_extended_obj = { (mp_obj_t)&mp_const_none_obj}, }; -//| class RemoteTransmissionRequest: -//| def __init__(self, id: int, length: int, *, extended: bool = False): -//| """Construct a Message to send on a CAN bus. -//| -//| :param int id: The numeric ID of the requested message -//| :param int length: The length of the requested message -//| :param bool extended: True if the message has an extended identifier, False if it has a standard identifier -//| -//| In CAN, messages can have a length from 0 to 8 bytes. -//| """ -//| ... -//| -STATIC mp_obj_t canio_remote_transmission_request_make_new(const mp_obj_type_t *type, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { - enum { ARG_id, ARG_length, ARG_extended, NUM_ARGS }; - static const mp_arg_t allowed_args[] = { - { MP_QSTR_id, MP_ARG_INT | MP_ARG_REQUIRED }, - { MP_QSTR_length, MP_ARG_INT | MP_ARG_REQUIRED }, - { MP_QSTR_extended, MP_ARG_BOOL, {.u_bool = false} }, - }; - mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; - MP_STATIC_ASSERT( MP_ARRAY_SIZE(allowed_args) == NUM_ARGS ); - - mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); - - int length = args[ARG_length].u_int; - if (length < 0 || length > 8) { - mp_raise_ValueError(translate("Messages limited to 8 bytes")); - } - - canio_message_obj_t *self = m_new_obj(canio_message_obj_t); - self->base.type = &canio_remote_transmission_request_type; - common_hal_canio_message_construct(self, args[ARG_id].u_int, NULL, length, args[ARG_extended].u_bool); - return self; -} - -//| extended: bool -//| """True if the message's id is an extended id""" -//| - -//| id: int -//| """The numeric ID of the message""" -//| - -//| length: int -//| """The length of the requested message.""" -//| -STATIC mp_obj_t canio_remote_transmission_request_length_get(const mp_obj_t self_in) { - canio_message_obj_t *self = self_in; - return MP_OBJ_NEW_SMALL_INT(common_hal_canio_message_get_length(self)); -} -MP_DEFINE_CONST_FUN_OBJ_1(canio_remote_transmission_request_length_get_obj, canio_remote_transmission_request_length_get); - -STATIC mp_obj_t canio_remote_transmission_request_length_set(const mp_obj_t self_in, const mp_obj_t length_in) { - canio_message_obj_t *self = self_in; - int length = mp_obj_get_int(length_in); - if (length < 0 || length > 8) { - mp_raise_ValueError(translate("Messages limited to 8 bytes")); - } - common_hal_canio_remote_transmission_request_set_length(self, length); - return mp_const_none; -} -MP_DEFINE_CONST_FUN_OBJ_2(canio_remote_transmission_request_length_set_obj, canio_remote_transmission_request_length_set); - - -STATIC const mp_obj_property_t canio_remote_transmission_request_length_obj = { - .base.type = &mp_type_property, - .proxy = {(mp_obj_t)&canio_remote_transmission_request_length_get_obj, - (mp_obj_t)&canio_remote_transmission_request_length_set_obj, - (mp_obj_t)&mp_const_none_obj}, -}; - STATIC const mp_rom_map_elem_t canio_message_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_id), MP_ROM_PTR(&canio_message_id_obj) }, { MP_ROM_QSTR(MP_QSTR_data), MP_ROM_PTR(&canio_message_data_obj) }, @@ -228,17 +157,3 @@ const mp_obj_type_t canio_message_type = { .make_new = canio_message_make_new, .locals_dict = (mp_obj_t)&canio_message_locals_dict, }; - -STATIC const mp_rom_map_elem_t canio_remote_transmission_request_locals_dict_table[] = { - { MP_ROM_QSTR(MP_QSTR_id), MP_ROM_PTR(&canio_message_id_obj) }, - { MP_ROM_QSTR(MP_QSTR_length), MP_ROM_PTR(&canio_remote_transmission_request_length_obj) }, - { MP_ROM_QSTR(MP_QSTR_extended), MP_ROM_PTR(&canio_message_extended_obj) }, -}; -STATIC MP_DEFINE_CONST_DICT(canio_remote_transmission_request_locals_dict, canio_remote_transmission_request_locals_dict_table); - -const mp_obj_type_t canio_remote_transmission_request_type = { - { &mp_type_type }, - .name = MP_QSTR_RemoteTransmissionRequest, - .make_new = canio_remote_transmission_request_make_new, - .locals_dict = (mp_obj_t)&canio_remote_transmission_request_locals_dict, -}; diff --git a/shared-bindings/canio/Message.h b/shared-bindings/canio/Message.h index 96716864c..adcdb095c 100644 --- a/shared-bindings/canio/Message.h +++ b/shared-bindings/canio/Message.h @@ -39,7 +39,5 @@ bool common_hal_canio_message_get_extended(const canio_message_obj_t *self); void common_hal_canio_message_set_extended(canio_message_obj_t *self, bool extended); int common_hal_canio_message_get_id(const canio_message_obj_t *self); void common_hal_canio_message_set_id(canio_message_obj_t *self, int id); -bool common_hal_canio_message_get_rtr(const canio_message_obj_t *self); -void common_hal_canio_message_set_rtr(canio_message_obj_t *self, bool rtr); size_t common_hal_canio_message_get_length(const canio_message_obj_t *self); void common_hal_canio_remote_transmission_request_set_length(canio_message_obj_t *self, size_t length); diff --git a/shared-bindings/canio/RemoteTransmissionRequest.c b/shared-bindings/canio/RemoteTransmissionRequest.c new file mode 100644 index 000000000..4e3f67417 --- /dev/null +++ b/shared-bindings/canio/RemoteTransmissionRequest.c @@ -0,0 +1,164 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2020 Jeff Epler for Adafruit Industries + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "shared-bindings/canio/RemoteTransmissionRequest.h" + +#include "py/obj.h" +#include "py/objproperty.h" +#include "py/runtime.h" + +//| class RemoteTransmissionRequest: +//| def __init__(self, id: int, length: int, *, extended: bool = False): +//| """Construct a RemoteTransmissionRequest to send on a CAN bus. +//| +//| :param int id: The numeric ID of the requested message +//| :param int length: The length of the requested message +//| :param bool extended: True if the message has an extended identifier, False if it has a standard identifier +//| +//| In CAN, messages can have a length from 0 to 8 bytes. +//| """ +//| ... +//| +STATIC mp_obj_t canio_remote_transmission_request_make_new(const mp_obj_type_t *type, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + enum { ARG_id, ARG_length, ARG_extended, NUM_ARGS }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_id, MP_ARG_INT | MP_ARG_REQUIRED }, + { MP_QSTR_length, MP_ARG_INT | MP_ARG_REQUIRED }, + { MP_QSTR_extended, MP_ARG_BOOL, {.u_bool = false} }, + }; + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + MP_STATIC_ASSERT( MP_ARRAY_SIZE(allowed_args) == NUM_ARGS ); + + mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + int length = args[ARG_length].u_int; + if (length < 0 || length > 8) { + mp_raise_ValueError(translate("RemoteTransmissionRequests limited to 8 bytes")); + } + + canio_remote_transmission_request_obj_t *self = m_new_obj(canio_remote_transmission_request_obj_t); + self->base.type = &canio_remote_transmission_request_type; + common_hal_canio_remote_transmission_request_construct(self, args[ARG_id].u_int, length, args[ARG_extended].u_bool); + return self; +} + + +//| id: int +//| """The numeric ID of the message""" +//| +STATIC mp_obj_t canio_remote_transmission_request_id_get(const mp_obj_t self_in) { + canio_remote_transmission_request_obj_t *self = self_in; + return MP_OBJ_NEW_SMALL_INT(common_hal_canio_remote_transmission_request_get_id(self)); +} +MP_DEFINE_CONST_FUN_OBJ_1(canio_remote_transmission_request_id_get_obj, canio_remote_transmission_request_id_get); + +STATIC mp_obj_t canio_remote_transmission_request_id_set(const mp_obj_t self_in, const mp_obj_t id) { + canio_remote_transmission_request_obj_t *self = self_in; + common_hal_canio_remote_transmission_request_set_id(self, mp_obj_get_int(id)); + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_2(canio_remote_transmission_request_id_set_obj, canio_remote_transmission_request_id_set); + +STATIC const mp_obj_property_t canio_remote_transmission_request_id_obj = { + .base.type = &mp_type_property, + .proxy = {(mp_obj_t)&canio_remote_transmission_request_id_get_obj, + (mp_obj_t)&canio_remote_transmission_request_id_set_obj, + (mp_obj_t)&mp_const_none_obj}, +}; + +//| extended: bool +//| """True if the message's id is an extended id""" +//| +STATIC mp_obj_t canio_remote_transmission_request_extended_get(const mp_obj_t self_in) { + canio_remote_transmission_request_obj_t *self = self_in; + return mp_obj_new_bool(common_hal_canio_remote_transmission_request_get_extended(self)); +} +MP_DEFINE_CONST_FUN_OBJ_1(canio_remote_transmission_request_extended_get_obj, canio_remote_transmission_request_extended_get); + +STATIC mp_obj_t canio_remote_transmission_request_extended_set(const mp_obj_t self_in, const mp_obj_t extended) { + canio_remote_transmission_request_obj_t *self = self_in; + common_hal_canio_remote_transmission_request_set_extended(self, mp_obj_is_true(extended)); + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_2(canio_remote_transmission_request_extended_set_obj, canio_remote_transmission_request_extended_set); + + +STATIC const mp_obj_property_t canio_remote_transmission_request_extended_obj = { + .base.type = &mp_type_property, + .proxy = {(mp_obj_t)&canio_remote_transmission_request_extended_get_obj, + (mp_obj_t)&canio_remote_transmission_request_extended_set_obj, + (mp_obj_t)&mp_const_none_obj}, +}; + +//| extended: bool +//| """True if the message's id is an extended id""" +//| + +//| id: int +//| """The numeric ID of the message""" +//| + +//| length: int +//| """The length of the requested message.""" +//| +STATIC mp_obj_t canio_remote_transmission_request_length_get(const mp_obj_t self_in) { + canio_remote_transmission_request_obj_t *self = self_in; + return MP_OBJ_NEW_SMALL_INT(common_hal_canio_remote_transmission_request_get_length(self)); +} +MP_DEFINE_CONST_FUN_OBJ_1(canio_remote_transmission_request_length_get_obj, canio_remote_transmission_request_length_get); + +STATIC mp_obj_t canio_remote_transmission_request_length_set(const mp_obj_t self_in, const mp_obj_t length_in) { + canio_remote_transmission_request_obj_t *self = self_in; + int length = mp_obj_get_int(length_in); + if (length < 0 || length > 8) { + mp_raise_ValueError(translate("RemoteTransmissionRequests limited to 8 bytes")); + } + common_hal_canio_remote_transmission_request_set_length(self, length); + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_2(canio_remote_transmission_request_length_set_obj, canio_remote_transmission_request_length_set); + + +STATIC const mp_obj_property_t canio_remote_transmission_request_length_obj = { + .base.type = &mp_type_property, + .proxy = {(mp_obj_t)&canio_remote_transmission_request_length_get_obj, + (mp_obj_t)&canio_remote_transmission_request_length_set_obj, + (mp_obj_t)&mp_const_none_obj}, +}; + +STATIC const mp_rom_map_elem_t canio_remote_transmission_request_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_id), MP_ROM_PTR(&canio_remote_transmission_request_id_obj) }, + { MP_ROM_QSTR(MP_QSTR_length), MP_ROM_PTR(&canio_remote_transmission_request_length_obj) }, + { MP_ROM_QSTR(MP_QSTR_extended), MP_ROM_PTR(&canio_remote_transmission_request_extended_obj) }, +}; +STATIC MP_DEFINE_CONST_DICT(canio_remote_transmission_request_locals_dict, canio_remote_transmission_request_locals_dict_table); + +const mp_obj_type_t canio_remote_transmission_request_type = { + { &mp_type_type }, + .name = MP_QSTR_RemoteTransmissionRequest, + .make_new = canio_remote_transmission_request_make_new, + .locals_dict = (mp_obj_t)&canio_remote_transmission_request_locals_dict, +}; diff --git a/shared-bindings/canio/RemoteTransmissionRequest.h b/shared-bindings/canio/RemoteTransmissionRequest.h new file mode 100644 index 000000000..8956587b3 --- /dev/null +++ b/shared-bindings/canio/RemoteTransmissionRequest.h @@ -0,0 +1,42 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2020 Jeff Epler for Adafruit Industries + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#pragma once + +#include "py/obj.h" +#include "shared-module/canio/RemoteTransmissionRequest.h" + +extern const mp_obj_type_t canio_remote_transmission_request_type; + +void common_hal_canio_remote_transmission_request_construct(canio_remote_transmission_request_obj_t *self, int id, size_t size, bool extended); +const void *common_hal_canio_remote_transmission_request_get_data(const canio_remote_transmission_request_obj_t *self); +void common_hal_canio_remote_transmission_request_set_data(canio_remote_transmission_request_obj_t *self, const void *data, size_t size); +bool common_hal_canio_remote_transmission_request_get_extended(const canio_remote_transmission_request_obj_t *self); +void common_hal_canio_remote_transmission_request_set_extended(canio_remote_transmission_request_obj_t *self, bool extended); +int common_hal_canio_remote_transmission_request_get_id(const canio_remote_transmission_request_obj_t *self); +void common_hal_canio_remote_transmission_request_set_id(canio_remote_transmission_request_obj_t *self, int id); +size_t common_hal_canio_remote_transmission_request_get_length(const canio_remote_transmission_request_obj_t *self); +void common_hal_canio_remote_transmission_request_set_length(canio_remote_transmission_request_obj_t *self, size_t length); diff --git a/shared-module/canio/Message.c b/shared-module/canio/Message.c index 86a3b7106..34c2e61f7 100644 --- a/shared-module/canio/Message.c +++ b/shared-module/canio/Message.c @@ -68,26 +68,6 @@ size_t common_hal_canio_message_get_length(const canio_message_obj_t *self) return self->size; } -void common_hal_canio_remote_transmission_request_set_length(canio_message_obj_t *self, size_t size) -{ - memset(self->data, 0, size); - self->size = size; -} - - -bool common_hal_canio_message_get_rtr(const canio_message_obj_t *self) -{ - return self->rtr; -} - -void common_hal_canio_message_set_rtr(canio_message_obj_t *self, bool rtr) -{ - self->rtr = rtr; - if (rtr) { - memset(self->data, 0, self->size); - } -} - bool common_hal_canio_message_get_extended(const canio_message_obj_t *self) { return self->extended; diff --git a/shared-module/canio/RemoteTransmissionRequest.c b/shared-module/canio/RemoteTransmissionRequest.c new file mode 100644 index 000000000..00c9334b0 --- /dev/null +++ b/shared-module/canio/RemoteTransmissionRequest.c @@ -0,0 +1,68 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2020 Jeff Epler for Adafruit Industries + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "shared-module/canio/RemoteTransmissionRequest.h" +#include "shared-bindings/canio/RemoteTransmissionRequest.h" + +#include + +void common_hal_canio_remote_transmission_request_construct(canio_remote_transmission_request_obj_t *self, int id, size_t size, bool extended) +{ + self->id = id; + self->size = size; + self->rtr = true; + self->extended = extended; +} + +int common_hal_canio_remote_transmission_request_get_id(const canio_remote_transmission_request_obj_t *self) +{ + return self->id; +} + +void common_hal_canio_remote_transmission_request_set_id(canio_remote_transmission_request_obj_t *self, int id) +{ + self->id = id; +} + +size_t common_hal_canio_remote_transmission_request_get_length(const canio_remote_transmission_request_obj_t *self) +{ + return self->size; +} + +void common_hal_canio_remote_transmission_request_set_length(canio_remote_transmission_request_obj_t *self, size_t size) +{ + self->size = size; +} + +bool common_hal_canio_remote_transmission_request_get_extended(const canio_remote_transmission_request_obj_t *self) +{ + return self->extended; +} + +void common_hal_canio_remote_transmission_request_set_extended(canio_remote_transmission_request_obj_t *self, bool extended) +{ + self->extended = extended; +} diff --git a/shared-module/canio/RemoteTransmissionRequest.h b/shared-module/canio/RemoteTransmissionRequest.h new file mode 100644 index 000000000..2f09b19c6 --- /dev/null +++ b/shared-module/canio/RemoteTransmissionRequest.h @@ -0,0 +1,33 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2020 Jeff Epler for Adafruit Industries + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#pragma once + +#include "py/obj.h" + +#include "shared-bindings/canio/Message.h" + +typedef canio_message_obj_t canio_remote_transmission_request_obj_t; -- cgit v1.2.3 From f4e36fc7f6719cb938b6e11b3e5242b149600d7d Mon Sep 17 00:00:00 2001 From: Jeff Epler Date: Mon, 28 Sep 2020 17:14:39 -0500 Subject: CAN: Use mp_obj_t insteaed of canio_message_obj_t, get rid of rtr field --- ports/atmel-samd/common-hal/canio/CAN.c | 8 +++++--- ports/atmel-samd/common-hal/canio/Listener.c | 12 +++++++----- shared-bindings/canio/CAN.h | 2 +- shared-bindings/canio/Listener.c | 14 ++++---------- shared-bindings/canio/Listener.h | 2 +- shared-module/canio/Message.c | 2 -- shared-module/canio/Message.h | 1 - shared-module/canio/RemoteTransmissionRequest.c | 1 - 8 files changed, 18 insertions(+), 24 deletions(-) (limited to 'shared-module') diff --git a/ports/atmel-samd/common-hal/canio/CAN.c b/ports/atmel-samd/common-hal/canio/CAN.c index 4f28698fb..ec6b75951 100644 --- a/ports/atmel-samd/common-hal/canio/CAN.c +++ b/ports/atmel-samd/common-hal/canio/CAN.c @@ -328,16 +328,18 @@ static void maybe_auto_restart(canio_can_obj_t *self) { } } -void common_hal_canio_can_send(canio_can_obj_t *self, canio_message_obj_t *message) +void common_hal_canio_can_send(canio_can_obj_t *self, mp_obj_t message_in) { maybe_auto_restart(self); + canio_message_obj_t *message = message_in;; // We have just one dedicated TX buffer, use it! canio_can_tx_buffer_t *ent = &self->state->tx_buffer[0]; + bool rtr = message->base.type == &canio_remote_transmission_request_type; ent->txb0.bit.ESI = false; ent->txb0.bit.XTD = message->extended; - ent->txb0.bit.RTR = message->rtr; + ent->txb0.bit.RTR = rtr; if (message->extended) { ent->txb0.bit.ID = message->id; } else { @@ -350,7 +352,7 @@ void common_hal_canio_can_send(canio_can_obj_t *self, canio_message_obj_t *messa ent->txb1.bit.BRS = 0; // No bit rate switching ent->txb1.bit.DLC = message->size; - if (!message->rtr) { + if (!rtr) { memcpy(ent->data, message->data, message->size); } diff --git a/ports/atmel-samd/common-hal/canio/Listener.c b/ports/atmel-samd/common-hal/canio/Listener.c index 483802fa4..b27c8cd1b 100644 --- a/ports/atmel-samd/common-hal/canio/Listener.c +++ b/ports/atmel-samd/common-hal/canio/Listener.c @@ -349,30 +349,32 @@ int common_hal_canio_listener_in_waiting(canio_listener_obj_t *self) { return self->hw->RXFS.bit.F0FL; } -bool common_hal_canio_listener_receiveinto(canio_listener_obj_t *self, canio_message_obj_t *message) { +mp_obj_t common_hal_canio_listener_receive(canio_listener_obj_t *self) { if (!common_hal_canio_listener_in_waiting(self)) { uint64_t deadline = supervisor_ticks_ms64() + self->timeout_ms; do { if (supervisor_ticks_ms64() > deadline) { - return false; + return NULL; } } while (!common_hal_canio_listener_in_waiting(self)); } int index = self->hw->RXFS.bit.F0GI; canio_can_rx_fifo_t *hw_message = &self->fifo[index]; + bool rtr = hw_message->rxf0.bit.RTR; + canio_message_obj_t *message = m_new_obj(canio_message_obj_t); + message->base.type = rtr ? &canio_remote_transmission_request_type : &canio_message_type; message->extended = hw_message->rxf0.bit.XTD; if (message->extended) { message->id = hw_message->rxf0.bit.ID; } else { message->id = hw_message->rxf0.bit.ID >> 18; // short ids are left-justified } - message->rtr = hw_message->rxf0.bit.RTR; message->size = hw_message->rxf1.bit.DLC; - if (!message->rtr) { + if (!rtr) { memcpy(message->data, hw_message->data, message->size); } self->hw->RXFA.bit.F0AI = index; - return true; + return message; } void common_hal_canio_listener_deinit(canio_listener_obj_t *self) { diff --git a/shared-bindings/canio/CAN.h b/shared-bindings/canio/CAN.h index 08166dfd4..8d61bc8ed 100644 --- a/shared-bindings/canio/CAN.h +++ b/shared-bindings/canio/CAN.h @@ -51,5 +51,5 @@ void common_hal_canio_can_auto_restart_set(canio_can_obj_t *self, bool auto_rest void common_hal_canio_can_check_for_deinit(canio_can_obj_t *self); void common_hal_canio_can_deinit(canio_can_obj_t *self); void common_hal_canio_can_restart(canio_can_obj_t *self); -void common_hal_canio_can_send(canio_can_obj_t *self, canio_message_obj_t *message); +void common_hal_canio_can_send(canio_can_obj_t *self, mp_obj_t message); void common_hal_canio_reset(void); diff --git a/shared-bindings/canio/Listener.c b/shared-bindings/canio/Listener.c index 7b0e59063..e5a9a2f83 100644 --- a/shared-bindings/canio/Listener.c +++ b/shared-bindings/canio/Listener.c @@ -49,17 +49,11 @@ STATIC mp_obj_t canio_listener_receive(mp_obj_t self_in) { canio_listener_obj_t *self = MP_OBJ_TO_PTR(self_in); common_hal_canio_listener_check_for_deinit(self); - canio_message_obj_t *message = m_new_obj(canio_message_obj_t); - - if (common_hal_canio_listener_receiveinto(self, message)) { - if (message->rtr) { - message->base.type = &canio_remote_transmission_request_type; - } else { - message->base.type = &canio_message_type; - } + mp_obj_t message = common_hal_canio_listener_receive(self); + // note: receive fills out the type field of the message + + if (message) { return message; - } else { - m_free(message); // message did not escape into vm } return mp_const_none; } diff --git a/shared-bindings/canio/Listener.h b/shared-bindings/canio/Listener.h index d925fa265..527ffe4cb 100644 --- a/shared-bindings/canio/Listener.h +++ b/shared-bindings/canio/Listener.h @@ -37,7 +37,7 @@ typedef struct canio_listener_obj canio_listener_obj_t; void common_hal_canio_listener_construct(canio_listener_obj_t *self, canio_can_obj_t *can, size_t nmatch, canio_match_obj_t **matches, float timeout); void common_hal_canio_listener_check_for_deinit(canio_listener_obj_t *self); void common_hal_canio_listener_deinit(canio_listener_obj_t *self); -bool common_hal_canio_listener_receiveinto(canio_listener_obj_t *self, canio_message_obj_t *message); +mp_obj_t common_hal_canio_listener_receive(canio_listener_obj_t *self); int common_hal_canio_listener_in_waiting(canio_listener_obj_t *self); float common_hal_canio_listener_get_timeout(canio_listener_obj_t *self); void common_hal_canio_listener_set_timeout(canio_listener_obj_t *self, float timeout); diff --git a/shared-module/canio/Message.c b/shared-module/canio/Message.c index 34c2e61f7..a1df4f693 100644 --- a/shared-module/canio/Message.c +++ b/shared-module/canio/Message.c @@ -32,7 +32,6 @@ void common_hal_canio_message_construct(canio_message_obj_t *self, int id, void { self->id = id; self->size = size; - self->rtr = !data; self->extended = extended; if (data) { memcpy(self->data, data, size); @@ -57,7 +56,6 @@ const void *common_hal_canio_message_get_data(const canio_message_obj_t *self) const void common_hal_canio_message_set_data(canio_message_obj_t *self, const void *data, size_t size) { - self->rtr = false; self->size = size; memcpy(self->data, data, size); } diff --git a/shared-module/canio/Message.h b/shared-module/canio/Message.h index b99c5c48e..1ca0d42e2 100644 --- a/shared-module/canio/Message.h +++ b/shared-module/canio/Message.h @@ -33,6 +33,5 @@ typedef struct { int id; uint8_t data[8]; size_t size:4; - bool rtr:1; bool extended:1; } canio_message_obj_t; diff --git a/shared-module/canio/RemoteTransmissionRequest.c b/shared-module/canio/RemoteTransmissionRequest.c index 00c9334b0..9b4d5632f 100644 --- a/shared-module/canio/RemoteTransmissionRequest.c +++ b/shared-module/canio/RemoteTransmissionRequest.c @@ -33,7 +33,6 @@ void common_hal_canio_remote_transmission_request_construct(canio_remote_transmi { self->id = id; self->size = size; - self->rtr = true; self->extended = extended; } -- cgit v1.2.3 From db74f97e60e58c22e6ce73bd068d9279e3daee57 Mon Sep 17 00:00:00 2001 From: Mark Roberts Date: Mon, 28 Sep 2020 19:10:47 -0400 Subject: modified _stage/__init__.c call to set region to update --- shared-module/_stage/__init__.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'shared-module') diff --git a/shared-module/_stage/__init__.c b/shared-module/_stage/__init__.c index 0323c32cb..6dfc18880 100644 --- a/shared-module/_stage/__init__.c +++ b/shared-module/_stage/__init__.c @@ -45,7 +45,7 @@ void render_stage(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, area.y2 = y1; displayio_display_core_set_region_to_update( &display->core, display->set_column_command, display->set_row_command, - NO_COMMAND, NO_COMMAND, display->data_as_commands, false, &area); + NO_COMMAND, NO_COMMAND, display->data_as_commands, false, &area, display->SH1107_addressing); while (!displayio_display_core_begin_transaction(&display->core)) { RUN_BACKGROUND_TASKS; -- cgit v1.2.3 From 9f19a8a7600ad59851953a7c0454d09245eadf4d Mon Sep 17 00:00:00 2001 From: Mark Roberts Date: Tue, 29 Sep 2020 15:37:06 -0400 Subject: Ran pre-commit locally --- shared-bindings/displayio/Display.c | 16 ++++++++-------- shared-bindings/displayio/Display.h | 2 +- shared-module/displayio/Display.c | 8 ++++---- shared-module/displayio/EPaperDisplay.c | 4 ++-- shared-module/displayio/display_core.c | 8 ++++---- shared-module/displayio/display_core.h | 6 +++--- 6 files changed, 22 insertions(+), 22 deletions(-) (limited to 'shared-module') diff --git a/shared-bindings/displayio/Display.c b/shared-bindings/displayio/Display.c index a81736e46..e78a893b0 100644 --- a/shared-bindings/displayio/Display.c +++ b/shared-bindings/displayio/Display.c @@ -111,15 +111,15 @@ //| :param bool backlight_on_high: If True, pulling the backlight pin high turns the backlight on.""" //| ... //| -STATIC mp_obj_t displayio_display_make_new(const mp_obj_type_t *type, size_t n_args, +STATIC mp_obj_t displayio_display_make_new(const mp_obj_type_t *type, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { - enum { ARG_display_bus, ARG_init_sequence, ARG_width, ARG_height, ARG_colstart, ARG_rowstart, - ARG_rotation, ARG_color_depth, ARG_grayscale, ARG_pixels_in_byte_share_row, - ARG_bytes_per_cell, ARG_reverse_pixels_in_byte, ARG_reverse_bytes_in_word, - ARG_set_column_command, ARG_set_row_command, ARG_write_ram_command, - ARG_set_vertical_scroll, ARG_backlight_pin, ARG_brightness_command, - ARG_brightness, ARG_auto_brightness, ARG_single_byte_bounds, ARG_data_as_commands, - ARG_auto_refresh, ARG_native_frames_per_second, ARG_backlight_on_high, + enum { ARG_display_bus, ARG_init_sequence, ARG_width, ARG_height, ARG_colstart, ARG_rowstart, + ARG_rotation, ARG_color_depth, ARG_grayscale, ARG_pixels_in_byte_share_row, + ARG_bytes_per_cell, ARG_reverse_pixels_in_byte, ARG_reverse_bytes_in_word, + ARG_set_column_command, ARG_set_row_command, ARG_write_ram_command, + ARG_set_vertical_scroll, ARG_backlight_pin, ARG_brightness_command, + ARG_brightness, ARG_auto_brightness, ARG_single_byte_bounds, ARG_data_as_commands, + ARG_auto_refresh, ARG_native_frames_per_second, ARG_backlight_on_high, ARG_SH1107_addressing }; static const mp_arg_t allowed_args[] = { { MP_QSTR_display_bus, MP_ARG_REQUIRED | MP_ARG_OBJ }, diff --git a/shared-bindings/displayio/Display.h b/shared-bindings/displayio/Display.h index c1704eaad..f9fbc157c 100644 --- a/shared-bindings/displayio/Display.h +++ b/shared-bindings/displayio/Display.h @@ -45,7 +45,7 @@ void common_hal_displayio_display_construct(displayio_display_obj_t* self, uint8_t set_column_command, uint8_t set_row_command, uint8_t write_ram_command, uint8_t set_vertical_scroll, uint8_t* init_sequence, uint16_t init_sequence_len, const mcu_pin_obj_t* backlight_pin, uint16_t brightness_command, mp_float_t brightness, bool auto_brightness, - bool single_byte_bounds, bool data_as_commands, bool auto_refresh, uint16_t native_frames_per_second, + bool single_byte_bounds, bool data_as_commands, bool auto_refresh, uint16_t native_frames_per_second, bool backlight_on_high, bool SH1107_addressing); bool common_hal_displayio_display_show(displayio_display_obj_t* self, diff --git a/shared-module/displayio/Display.c b/shared-module/displayio/Display.c index 9864e9f9d..f2b8e0447 100644 --- a/shared-module/displayio/Display.c +++ b/shared-module/displayio/Display.c @@ -48,7 +48,7 @@ void common_hal_displayio_display_construct(displayio_display_obj_t* self, uint8_t set_row_command, uint8_t write_ram_command, uint8_t set_vertical_scroll, uint8_t* init_sequence, uint16_t init_sequence_len, const mcu_pin_obj_t* backlight_pin, uint16_t brightness_command, mp_float_t brightness, bool auto_brightness, - bool single_byte_bounds, bool data_as_commands, bool auto_refresh, uint16_t native_frames_per_second, + bool single_byte_bounds, bool data_as_commands, bool auto_refresh, uint16_t native_frames_per_second, bool backlight_on_high, bool SH1107_addressing) { // Turn off auto-refresh as we init. @@ -246,7 +246,7 @@ STATIC bool _refresh_area(displayio_display_obj_t* self, const displayio_area_t* uint16_t rows_per_buffer = displayio_area_height(&clipped); uint8_t pixels_per_word = (sizeof(uint32_t) * 8) / self->core.colorspace.depth; uint16_t pixels_per_buffer = displayio_area_size(&clipped); - + uint16_t subrectangles = 1; // for SH1107 and other boundary constrained controllers // write one single row at a time @@ -299,8 +299,8 @@ STATIC bool _refresh_area(displayio_display_obj_t* self, const displayio_area_t* } remaining_rows -= rows_per_buffer; - displayio_display_core_set_region_to_update(&self->core, self->set_column_command, - self->set_row_command, NO_COMMAND, NO_COMMAND, self->data_as_commands, false, + displayio_display_core_set_region_to_update(&self->core, self->set_column_command, + self->set_row_command, NO_COMMAND, NO_COMMAND, self->data_as_commands, false, &subrectangle, self->SH1107_addressing); uint16_t subrectangle_size_bytes; diff --git a/shared-module/displayio/EPaperDisplay.c b/shared-module/displayio/EPaperDisplay.c index 3391a56b4..5b055e62e 100644 --- a/shared-module/displayio/EPaperDisplay.c +++ b/shared-module/displayio/EPaperDisplay.c @@ -240,8 +240,8 @@ bool displayio_epaperdisplay_refresh_area(displayio_epaperdisplay_obj_t* self, c // added false parameter at end for SH1107_addressing quirk if (self->set_row_window_command != NO_COMMAND) { - displayio_display_core_set_region_to_update(&self->core, self->set_column_window_command, - self->set_row_window_command, self->set_current_column_command, self->set_current_row_command, + displayio_display_core_set_region_to_update(&self->core, self->set_column_window_command, + self->set_row_window_command, self->set_current_column_command, self->set_current_row_command, false, self->chip_select, &clipped, false); } diff --git a/shared-module/displayio/display_core.c b/shared-module/displayio/display_core.c index eb8c8f3b4..c592202fb 100644 --- a/shared-module/displayio/display_core.c +++ b/shared-module/displayio/display_core.c @@ -57,7 +57,7 @@ void displayio_display_core_construct(displayio_display_core_t* self, self->colstart = colstart; self->rowstart = rowstart; self->last_refresh = 0; - + // (framebufferdisplay already validated its 'bus' is a buffer-protocol object) if (bus) { if (MP_OBJ_IS_TYPE(bus, &displayio_parallelbus_type)) { @@ -208,9 +208,9 @@ void displayio_display_core_end_transaction(displayio_display_core_t* self) { self->end_transaction(self->bus); } -void displayio_display_core_set_region_to_update(displayio_display_core_t* self, uint8_t column_command, - uint8_t row_command, uint16_t set_current_column_command, uint16_t set_current_row_command, - bool data_as_commands, bool always_toggle_chip_select, +void displayio_display_core_set_region_to_update(displayio_display_core_t* self, uint8_t column_command, + uint8_t row_command, uint16_t set_current_column_command, uint16_t set_current_row_command, + bool data_as_commands, bool always_toggle_chip_select, displayio_area_t* area, bool SH1107_addressing) { uint16_t x1 = area->x1; uint16_t x2 = area->x2; diff --git a/shared-module/displayio/display_core.h b/shared-module/displayio/display_core.h index ad9998a2f..3b45f7946 100644 --- a/shared-module/displayio/display_core.h +++ b/shared-module/displayio/display_core.h @@ -74,9 +74,9 @@ bool displayio_display_core_bus_free(displayio_display_core_t *self); bool displayio_display_core_begin_transaction(displayio_display_core_t* self); void displayio_display_core_end_transaction(displayio_display_core_t* self); -void displayio_display_core_set_region_to_update(displayio_display_core_t* self, uint8_t column_command, - uint8_t row_command, uint16_t set_current_column_command, uint16_t set_current_row_command, - bool data_as_commands, bool always_toggle_chip_select, +void displayio_display_core_set_region_to_update(displayio_display_core_t* self, uint8_t column_command, + uint8_t row_command, uint16_t set_current_column_command, uint16_t set_current_row_command, + bool data_as_commands, bool always_toggle_chip_select, displayio_area_t* area, bool SH1107_addressing); void release_display_core(displayio_display_core_t* self); -- cgit v1.2.3 From ef245ef54ebab7c483a935dbfb100e2ab100f0ea Mon Sep 17 00:00:00 2001 From: Mark Roberts Date: Tue, 29 Sep 2020 19:48:14 -0400 Subject: Removed redundant subrectangle sizing code --- shared-module/displayio/Display.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) (limited to 'shared-module') diff --git a/shared-module/displayio/Display.c b/shared-module/displayio/Display.c index f2b8e0447..37d72a82f 100644 --- a/shared-module/displayio/Display.c +++ b/shared-module/displayio/Display.c @@ -290,11 +290,7 @@ STATIC bool _refresh_area(displayio_display_obj_t* self, const displayio_area_t* .x2 = clipped.x2, .y2 = clipped.y1 + rows_per_buffer * (j + 1) }; - if (self->SH1107_addressing) { - // one row only for SH1107 in vertical (column) mode - subrectangle.y1 = clipped.y1 + j; - subrectangle.y2 = clipped.y1 + (j + 1); - } else if (remaining_rows < rows_per_buffer) { + if (remaining_rows < rows_per_buffer) { subrectangle.y2 = subrectangle.y1 + remaining_rows; } remaining_rows -= rows_per_buffer; -- cgit v1.2.3 From d1bda47d94c2ab9e42a74de4a5209df73e46a4ea Mon Sep 17 00:00:00 2001 From: FoamyGuy Date: Wed, 30 Sep 2020 14:03:03 -0500 Subject: removing top level displayio background check --- shared-module/displayio/__init__.c | 9 --------- 1 file changed, 9 deletions(-) (limited to 'shared-module') diff --git a/shared-module/displayio/__init__.c b/shared-module/displayio/__init__.c index 101dac4b3..5161923d6 100644 --- a/shared-module/displayio/__init__.c +++ b/shared-module/displayio/__init__.c @@ -40,8 +40,6 @@ STATIC bool any_display_uses_this_framebuffer(mp_obj_base_t *obj) { } #endif -// Check for recursive calls to displayio_background. -bool displayio_background_in_progress = false; void displayio_background(void) { if (mp_hal_is_interrupted()) { @@ -52,11 +50,6 @@ void displayio_background(void) { return; } - if (displayio_background_in_progress) { - // Don't allow recursive calls to this routine. - return; - } - displayio_background_in_progress = true; for (uint8_t i = 0; i < CIRCUITPY_DISPLAY_LIMIT; i++) { @@ -75,8 +68,6 @@ void displayio_background(void) { } } - // All done. - displayio_background_in_progress = false; } void common_hal_displayio_release_displays(void) { -- cgit v1.2.3 From a739d314f1a9f5fee6517eb425a2c691969fd7f7 Mon Sep 17 00:00:00 2001 From: Scott Shawcroft Date: Tue, 29 Sep 2020 13:04:39 -0700 Subject: Add Metro ESP32S2 Also fix two bugs: * Crash when resetting board.SPI when it hasn't been inited. * Reading back the output value is always false. Fixes #3353 --- .../esp32s2/boards/adafruit_metro_esp32s2/board.c | 43 +++++++++++++++++++ .../boards/adafruit_metro_esp32s2/mpconfigboard.h | 48 ++++++++++++++++++++++ .../boards/adafruit_metro_esp32s2/mpconfigboard.mk | 17 ++++++++ ports/esp32s2/boards/adafruit_metro_esp32s2/pins.c | 44 ++++++++++++++++++++ .../boards/adafruit_metro_esp32s2/sdkconfig | 33 +++++++++++++++ ports/esp32s2/common-hal/digitalio/DigitalInOut.c | 18 +++++++- ports/esp32s2/common-hal/digitalio/DigitalInOut.h | 1 + shared-module/board/__init__.c | 4 +- 8 files changed, 205 insertions(+), 3 deletions(-) create mode 100644 ports/esp32s2/boards/adafruit_metro_esp32s2/board.c create mode 100644 ports/esp32s2/boards/adafruit_metro_esp32s2/mpconfigboard.h create mode 100644 ports/esp32s2/boards/adafruit_metro_esp32s2/mpconfigboard.mk create mode 100644 ports/esp32s2/boards/adafruit_metro_esp32s2/pins.c create mode 100644 ports/esp32s2/boards/adafruit_metro_esp32s2/sdkconfig (limited to 'shared-module') diff --git a/ports/esp32s2/boards/adafruit_metro_esp32s2/board.c b/ports/esp32s2/boards/adafruit_metro_esp32s2/board.c new file mode 100644 index 000000000..7380be6da --- /dev/null +++ b/ports/esp32s2/boards/adafruit_metro_esp32s2/board.c @@ -0,0 +1,43 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2020 Scott Shawcroft for Adafruit Industries + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "boards/board.h" +#include "mpconfigboard.h" +#include "shared-bindings/microcontroller/Pin.h" + +void board_init(void) { + // USB + common_hal_never_reset_pin(&pin_GPIO19); + common_hal_never_reset_pin(&pin_GPIO20); +} + +bool board_requests_safe_mode(void) { + return false; +} + +void reset_board(void) { + +} diff --git a/ports/esp32s2/boards/adafruit_metro_esp32s2/mpconfigboard.h b/ports/esp32s2/boards/adafruit_metro_esp32s2/mpconfigboard.h new file mode 100644 index 000000000..7280aab9c --- /dev/null +++ b/ports/esp32s2/boards/adafruit_metro_esp32s2/mpconfigboard.h @@ -0,0 +1,48 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2019 Scott Shawcroft for Adafruit Industries + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +//Micropython setup + +#define MICROPY_HW_BOARD_NAME "Metro ESP32S2" +#define MICROPY_HW_MCU_NAME "ESP32S2" + +#define MICROPY_HW_NEOPIXEL (&pin_GPIO45) + +#define CIRCUITPY_BOOT_BUTTON (&pin_GPIO0) + +#define BOARD_USER_SAFE_MODE_ACTION translate("pressing boot button at start up.\n") + +#define AUTORESET_DELAY_MS 500 + +#define DEFAULT_I2C_BUS_SCL (&pin_GPIO34) +#define DEFAULT_I2C_BUS_SDA (&pin_GPIO33) + +#define DEFAULT_SPI_BUS_SCK (&pin_GPIO36) +#define DEFAULT_SPI_BUS_MOSI (&pin_GPIO35) +#define DEFAULT_SPI_BUS_MISO (&pin_GPIO37) + +#define DEFAULT_UART_BUS_RX (&pin_GPIO5) +#define DEFAULT_UART_BUS_TX (&pin_GPIO6) diff --git a/ports/esp32s2/boards/adafruit_metro_esp32s2/mpconfigboard.mk b/ports/esp32s2/boards/adafruit_metro_esp32s2/mpconfigboard.mk new file mode 100644 index 000000000..e78098d64 --- /dev/null +++ b/ports/esp32s2/boards/adafruit_metro_esp32s2/mpconfigboard.mk @@ -0,0 +1,17 @@ +USB_VID = 0x239A +USB_PID = 0x80E0 +USB_PRODUCT = "Metro ESP32S2" +USB_MANUFACTURER = "Adafruit" + +INTERNAL_FLASH_FILESYSTEM = 1 +LONGINT_IMPL = MPZ + +# The default queue depth of 16 overflows on release builds, +# so increase it to 32. +CFLAGS += -DCFG_TUD_TASK_QUEUE_SZ=32 + +CIRCUITPY_ESP_FLASH_MODE=dio +CIRCUITPY_ESP_FLASH_FREQ=40m +CIRCUITPY_ESP_FLASH_SIZE=4MB + +CIRCUITPY_MODULE=wrover diff --git a/ports/esp32s2/boards/adafruit_metro_esp32s2/pins.c b/ports/esp32s2/boards/adafruit_metro_esp32s2/pins.c new file mode 100644 index 000000000..08d2b2a1a --- /dev/null +++ b/ports/esp32s2/boards/adafruit_metro_esp32s2/pins.c @@ -0,0 +1,44 @@ +#include "shared-bindings/board/__init__.h" + +STATIC const mp_rom_map_elem_t board_global_dict_table[] = { + { MP_OBJ_NEW_QSTR(MP_QSTR_A0), MP_ROM_PTR(&pin_GPIO17) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_A1), MP_ROM_PTR(&pin_GPIO18) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_A2), MP_ROM_PTR(&pin_GPIO1) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_A3), MP_ROM_PTR(&pin_GPIO2) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_A4), MP_ROM_PTR(&pin_GPIO3) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_A5), MP_ROM_PTR(&pin_GPIO4) }, + + { MP_OBJ_NEW_QSTR(MP_QSTR_D0), MP_ROM_PTR(&pin_GPIO5) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_RX), MP_ROM_PTR(&pin_GPIO5) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_D1), MP_ROM_PTR(&pin_GPIO6) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_TX), MP_ROM_PTR(&pin_GPIO6) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_D2), MP_ROM_PTR(&pin_GPIO7) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_D3), MP_ROM_PTR(&pin_GPIO8) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_D4), MP_ROM_PTR(&pin_GPIO9) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_D5), MP_ROM_PTR(&pin_GPIO10) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_D6), MP_ROM_PTR(&pin_GPIO11) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_D7), MP_ROM_PTR(&pin_GPIO12) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_D8), MP_ROM_PTR(&pin_GPIO13) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_D9), MP_ROM_PTR(&pin_GPIO14) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_D10), MP_ROM_PTR(&pin_GPIO15) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_D11), MP_ROM_PTR(&pin_GPIO16) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_D12), MP_ROM_PTR(&pin_GPIO21) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_D13), MP_ROM_PTR(&pin_GPIO42) }, + + { MP_OBJ_NEW_QSTR(MP_QSTR_SDA),MP_ROM_PTR(&pin_GPIO33) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_SCL),MP_ROM_PTR(&pin_GPIO34) }, + + { MP_OBJ_NEW_QSTR(MP_QSTR_NEOPIXEL), MP_ROM_PTR(&pin_GPIO45) }, + + { MP_OBJ_NEW_QSTR(MP_QSTR_DEBUG_RX), MP_ROM_PTR(&pin_GPIO38) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_DEBUG_TX), MP_ROM_PTR(&pin_GPIO37) }, + + { MP_OBJ_NEW_QSTR(MP_QSTR_SCK), MP_ROM_PTR(&pin_GPIO36) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_MOSI),MP_ROM_PTR(&pin_GPIO35) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_MISO),MP_ROM_PTR(&pin_GPIO37) }, + + { MP_ROM_QSTR(MP_QSTR_I2C), MP_ROM_PTR(&board_i2c_obj) }, + { MP_ROM_QSTR(MP_QSTR_SPI), MP_ROM_PTR(&board_spi_obj) }, + { MP_ROM_QSTR(MP_QSTR_UART), MP_ROM_PTR(&board_uart_obj) }, +}; +MP_DEFINE_CONST_DICT(board_module_globals, board_global_dict_table); diff --git a/ports/esp32s2/boards/adafruit_metro_esp32s2/sdkconfig b/ports/esp32s2/boards/adafruit_metro_esp32s2/sdkconfig new file mode 100644 index 000000000..9d8bbde96 --- /dev/null +++ b/ports/esp32s2/boards/adafruit_metro_esp32s2/sdkconfig @@ -0,0 +1,33 @@ +CONFIG_ESP32S2_SPIRAM_SUPPORT=y + +# +# SPI RAM config +# +# CONFIG_SPIRAM_TYPE_AUTO is not set +CONFIG_SPIRAM_TYPE_ESPPSRAM16=y +# CONFIG_SPIRAM_TYPE_ESPPSRAM32 is not set +# CONFIG_SPIRAM_TYPE_ESPPSRAM64 is not set +CONFIG_SPIRAM_SIZE=2097152 + +# +# PSRAM clock and cs IO for ESP32S2 +# +CONFIG_DEFAULT_PSRAM_CLK_IO=30 +CONFIG_DEFAULT_PSRAM_CS_IO=26 +# end of PSRAM clock and cs IO for ESP32S2 + +# CONFIG_SPIRAM_FETCH_INSTRUCTIONS is not set +# CONFIG_SPIRAM_RODATA is not set +# CONFIG_SPIRAM_SPEED_80M is not set +CONFIG_SPIRAM_SPEED_40M=y +# CONFIG_SPIRAM_SPEED_26M is not set +# CONFIG_SPIRAM_SPEED_20M is not set +CONFIG_SPIRAM=y +CONFIG_SPIRAM_BOOT_INIT=y +# CONFIG_SPIRAM_IGNORE_NOTFOUND is not set +CONFIG_SPIRAM_USE_MEMMAP=y +# CONFIG_SPIRAM_USE_CAPS_ALLOC is not set +# CONFIG_SPIRAM_USE_MALLOC is not set +CONFIG_SPIRAM_MEMTEST=y +# CONFIG_SPIRAM_ALLOW_BSS_SEG_EXTERNAL_MEMORY is not set +# end of SPI RAM config diff --git a/ports/esp32s2/common-hal/digitalio/DigitalInOut.c b/ports/esp32s2/common-hal/digitalio/DigitalInOut.c index fb3ee10ad..d27985181 100644 --- a/ports/esp32s2/common-hal/digitalio/DigitalInOut.c +++ b/ports/esp32s2/common-hal/digitalio/DigitalInOut.c @@ -42,6 +42,16 @@ digitalinout_result_t common_hal_digitalio_digitalinout_construct( claim_pin(pin); self->pin = pin; + gpio_config_t config; + config.pin_bit_mask = 1ull << pin->number; + config.mode = GPIO_MODE_INPUT; + config.pull_up_en = GPIO_PULLUP_DISABLE; + config.pull_down_en = GPIO_PULLDOWN_DISABLE; + config.intr_type = GPIO_INTR_DISABLE; + if (gpio_config(&config) != ESP_OK) { + return DIGITALINOUT_PIN_BUSY; + } + return DIGITALINOUT_OK; } @@ -67,7 +77,7 @@ void common_hal_digitalio_digitalinout_switch_to_input( digitalinout_result_t common_hal_digitalio_digitalinout_switch_to_output( digitalio_digitalinout_obj_t *self, bool value, digitalio_drive_mode_t drive_mode) { - gpio_set_level(self->pin->number, value); + common_hal_digitalio_digitalinout_set_value(self, value); return common_hal_digitalio_digitalinout_set_drive_mode(self, drive_mode); } @@ -82,12 +92,16 @@ digitalio_direction_t common_hal_digitalio_digitalinout_get_direction( void common_hal_digitalio_digitalinout_set_value( digitalio_digitalinout_obj_t *self, bool value) { + self->output_value = value; gpio_set_level(self->pin->number, value); } bool common_hal_digitalio_digitalinout_get_value( digitalio_digitalinout_obj_t *self) { - return gpio_get_level(self->pin->number) == 1; + if (common_hal_digitalio_digitalinout_get_direction(self) == DIRECTION_INPUT) { + return gpio_get_level(self->pin->number) == 1; + } + return self->output_value; } digitalinout_result_t common_hal_digitalio_digitalinout_set_drive_mode( diff --git a/ports/esp32s2/common-hal/digitalio/DigitalInOut.h b/ports/esp32s2/common-hal/digitalio/DigitalInOut.h index 6877f1741..c09c5502d 100644 --- a/ports/esp32s2/common-hal/digitalio/DigitalInOut.h +++ b/ports/esp32s2/common-hal/digitalio/DigitalInOut.h @@ -33,6 +33,7 @@ typedef struct { mp_obj_base_t base; const mcu_pin_obj_t *pin; + bool output_value; } digitalio_digitalinout_obj_t; #endif // MICROPY_INCLUDED_ESP32S2_COMMON_HAL_DIGITALIO_DIGITALINOUT_H diff --git a/shared-module/board/__init__.c b/shared-module/board/__init__.c index fb4f731b8..39b68a0f1 100644 --- a/shared-module/board/__init__.c +++ b/shared-module/board/__init__.c @@ -167,7 +167,9 @@ void reset_board_busses(void) { } #endif // make sure SPI lock is not held over a soft reset - common_hal_busio_spi_unlock(&spi_obj); + if (spi_singleton != NULL) { + common_hal_busio_spi_unlock(spi_singleton); + } if (!display_using_spi) { spi_singleton = NULL; } -- cgit v1.2.3 From 422a7d4013ddaec7df5df9104e5d9ea533b31d1a Mon Sep 17 00:00:00 2001 From: FoamyGuy Date: Wed, 30 Sep 2020 17:25:58 -0500 Subject: remove remaining top level displayio background check --- shared-module/displayio/__init__.c | 1 - 1 file changed, 1 deletion(-) (limited to 'shared-module') diff --git a/shared-module/displayio/__init__.c b/shared-module/displayio/__init__.c index 5161923d6..a9bb3b21b 100644 --- a/shared-module/displayio/__init__.c +++ b/shared-module/displayio/__init__.c @@ -50,7 +50,6 @@ void displayio_background(void) { return; } - displayio_background_in_progress = true; for (uint8_t i = 0; i < CIRCUITPY_DISPLAY_LIMIT; i++) { if (displays[i].display.base.type == NULL || displays[i].display.base.type == &mp_type_NoneType) { -- cgit v1.2.3 From d7c3f811afd924bae8e0b009a4cfadd6fab29584 Mon Sep 17 00:00:00 2001 From: Jeff Epler Date: Thu, 1 Oct 2020 09:21:39 -0500 Subject: sharpdisplay: Fix memory corruption across soft-reset It was incorrect to NULL out the pointer to our heap allocated buffer in `reset`, because subsequent to framebuffer_reset, but while the heap was still active, we could call `get_bufinfo` again, leading to a fresh allocation on the heap that is about to be destroyed. Typical stack trace: ``` #1 0x0006c368 in sharpdisplay_framebuffer_get_bufinfo #2 0x0006ad6e in _refresh_display #3 0x0006b168 in framebufferio_framebufferdisplay_background #4 0x00069d22 in displayio_background #5 0x00045496 in supervisor_background_tasks #6 0x000446e8 in background_callback_run_all #7 0x00045546 in supervisor_run_background_tasks_if_tick #8 0x0005b042 in common_hal_neopixel_write #9 0x00044c4c in clear_temp_status #10 0x000497de in spi_flash_flush_keep_cache #11 0x00049a66 in supervisor_external_flash_flush #12 0x00044b22 in supervisor_flash_flush #13 0x0004490e in filesystem_flush #14 0x00043e18 in cleanup_after_vm #15 0x0004414c in run_repl #16 0x000441ce in main ``` When this happened -- which was inconsistent -- the display would keep some heap allocation across reset which is exactly what we need to avoid. NULLing the pointer in reconstruct follows what RGBMatrix does, and that code is a bit more battle-tested anyway. If I had a motivation for structuring the SharpMemory code differently, I can no longer recall it. Testing performed: Ran my complicated calculator program over multiple iterations without observing signs of heap corruption. Closes: #3473 --- shared-module/sharpdisplay/SharpMemoryFramebuffer.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) (limited to 'shared-module') diff --git a/shared-module/sharpdisplay/SharpMemoryFramebuffer.c b/shared-module/sharpdisplay/SharpMemoryFramebuffer.c index 71e00d7f0..c23446828 100644 --- a/shared-module/sharpdisplay/SharpMemoryFramebuffer.c +++ b/shared-module/sharpdisplay/SharpMemoryFramebuffer.c @@ -90,10 +90,6 @@ bool common_hal_sharpdisplay_framebuffer_get_pixels_in_byte_share_row(sharpdispl } void common_hal_sharpdisplay_framebuffer_reset(sharpdisplay_framebuffer_obj_t *self) { - if (!allocation_from_ptr(self->bufinfo.buf)) { - self->bufinfo.buf = NULL; - } - if (self->bus != &self->inline_bus #if BOARD_SPI && self->bus != common_hal_board_get_spi() @@ -105,7 +101,9 @@ void common_hal_sharpdisplay_framebuffer_reset(sharpdisplay_framebuffer_obj_t *s } void common_hal_sharpdisplay_framebuffer_reconstruct(sharpdisplay_framebuffer_obj_t *self) { - + if (!allocation_from_ptr(self->bufinfo.buf)) { + self->bufinfo.buf = NULL; + } } void common_hal_sharpdisplay_framebuffer_get_bufinfo(sharpdisplay_framebuffer_obj_t *self, mp_buffer_info_t *bufinfo) { -- cgit v1.2.3 From b1592564b286ca7a5374e77eba2c2efc768ffae9 Mon Sep 17 00:00:00 2001 From: Jeff Epler Date: Fri, 2 Oct 2020 15:07:36 -0500 Subject: displayio: Fix matrixportal crash An RGBMatrix has no bus and no bus_free method. It is always possible to refresh the display. This was not a problem before, but the fix I suggested (#3449) added a call to core_bus_free when a FramebufferDisplay was being refreshed. This was not caught during testing. This is a band-aid fix and it brings to light a second problem in which a SharpDisplay + FrameBuffer will not have a 'bus' object, and yet does operate using a shared SPI bus. This kind of display will need a "bus-free" like function to be added, or it can have problems like #3309. --- shared-module/displayio/display_core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'shared-module') diff --git a/shared-module/displayio/display_core.c b/shared-module/displayio/display_core.c index 68572c44f..35d0c74a4 100644 --- a/shared-module/displayio/display_core.c +++ b/shared-module/displayio/display_core.c @@ -197,7 +197,7 @@ bool displayio_display_core_get_dither(displayio_display_core_t* self){ } bool displayio_display_core_bus_free(displayio_display_core_t *self) { - return self->bus_free(self->bus); + return !self->bus || self->bus_free(self->bus); } bool displayio_display_core_begin_transaction(displayio_display_core_t* self) { -- cgit v1.2.3 From 5e38bb98cbcc2d1ab607b19d11e628def4f48f4c Mon Sep 17 00:00:00 2001 From: Jeff Epler Date: Sat, 10 Oct 2020 14:30:37 -0500 Subject: rgbmatrix: update protomatter to 1.0.5 tag this is compile-tested on stm32f405 feather matrixportal nrf52840 feather but not actually tested-tested. --- lib/protomatter | 2 +- py/circuitpy_defns.mk | 4 ++-- shared-bindings/rgbmatrix/RGBMatrix.h | 2 +- shared-module/rgbmatrix/RGBMatrix.c | 12 ++++++------ shared-module/rgbmatrix/RGBMatrix.h | 2 +- shared-module/rgbmatrix/allocator.h | 4 ++-- 6 files changed, 13 insertions(+), 13 deletions(-) (limited to 'shared-module') diff --git a/lib/protomatter b/lib/protomatter index 5f07ec618..de6b7704c 160000 --- a/lib/protomatter +++ b/lib/protomatter @@ -1 +1 @@ -Subproject commit 5f07ec6188852794a94138763e612844842f13e4 +Subproject commit de6b7704c530d886ad8dfa0fa1864764d86117ee diff --git a/py/circuitpy_defns.mk b/py/circuitpy_defns.mk index 76c0a4db6..525e0b2bf 100644 --- a/py/circuitpy_defns.mk +++ b/py/circuitpy_defns.mk @@ -528,10 +528,10 @@ SRC_MOD += $(addprefix lib/mp3/src/, \ $(BUILD)/lib/mp3/src/buffers.o: CFLAGS += -include "py/misc.h" -D'MPDEC_ALLOCATOR(x)=m_malloc(x,0)' -D'MPDEC_FREE(x)=m_free(x)' endif ifeq ($(CIRCUITPY_RGBMATRIX),1) -SRC_MOD += $(addprefix lib/protomatter/, \ +SRC_MOD += $(addprefix lib/protomatter/src/, \ core.c \ ) -$(BUILD)/lib/protomatter/core.o: CFLAGS += -include "shared-module/rgbmatrix/allocator.h" -DCIRCUITPY -Wno-missing-braces +$(BUILD)/lib/protomatter/src/core.o: CFLAGS += -include "shared-module/rgbmatrix/allocator.h" -DCIRCUITPY -Wno-missing-braces endif # All possible sources are listed here, and are filtered by SRC_PATTERNS. diff --git a/shared-bindings/rgbmatrix/RGBMatrix.h b/shared-bindings/rgbmatrix/RGBMatrix.h index 1dc5a406c..bfe37c340 100644 --- a/shared-bindings/rgbmatrix/RGBMatrix.h +++ b/shared-bindings/rgbmatrix/RGBMatrix.h @@ -27,7 +27,7 @@ #pragma once #include "shared-module/rgbmatrix/RGBMatrix.h" -#include "lib/protomatter/core.h" +#include "lib/protomatter/src/core.h" extern const mp_obj_type_t rgbmatrix_RGBMatrix_type; diff --git a/shared-module/rgbmatrix/RGBMatrix.c b/shared-module/rgbmatrix/RGBMatrix.c index 3007ca4db..a77518130 100644 --- a/shared-module/rgbmatrix/RGBMatrix.c +++ b/shared-module/rgbmatrix/RGBMatrix.c @@ -78,10 +78,10 @@ void common_hal_rgbmatrix_rgbmatrix_reconstruct(rgbmatrix_rgbmatrix_obj_t* self, // verify that the matrix is big enough mp_get_index(mp_obj_get_type(self->framebuffer), self->bufinfo.len, MP_OBJ_NEW_SMALL_INT(self->bufsize-1), false); } else { - _PM_FREE(self->bufinfo.buf); - _PM_FREE(self->protomatter.rgbPins); - _PM_FREE(self->protomatter.addr); - _PM_FREE(self->protomatter.screenData); + _PM_free(self->bufinfo.buf); + _PM_free(self->protomatter.rgbPins); + _PM_free(self->protomatter.addr); + _PM_free(self->protomatter.screenData); self->framebuffer = NULL; self->bufinfo.buf = common_hal_rgbmatrix_allocator_impl(self->bufsize); @@ -164,13 +164,13 @@ void common_hal_rgbmatrix_rgbmatrix_deinit(rgbmatrix_rgbmatrix_obj_t* self) { free_pin(&self->oe_pin); if (self->protomatter.rgbPins) { - _PM_free(&self->protomatter); + _PM_deallocate(&self->protomatter); } memset(&self->protomatter, 0, sizeof(self->protomatter)); // If it was supervisor-allocated, it is supervisor-freed and the pointer // is zeroed, otherwise the pointer is just zeroed - _PM_FREE(self->bufinfo.buf); + _PM_free(self->bufinfo.buf); self->base.type = NULL; // If a framebuffer was passed in to the constructor, NULL the reference diff --git a/shared-module/rgbmatrix/RGBMatrix.h b/shared-module/rgbmatrix/RGBMatrix.h index 19d7d5f2e..6dbc6fd41 100644 --- a/shared-module/rgbmatrix/RGBMatrix.h +++ b/shared-module/rgbmatrix/RGBMatrix.h @@ -26,7 +26,7 @@ #pragma once -#include "lib/protomatter/core.h" +#include "lib/protomatter/src/core.h" extern const mp_obj_type_t rgbmatrix_RGBMatrix_type; typedef struct { diff --git a/shared-module/rgbmatrix/allocator.h b/shared-module/rgbmatrix/allocator.h index 323fa5ec0..3431046d5 100644 --- a/shared-module/rgbmatrix/allocator.h +++ b/shared-module/rgbmatrix/allocator.h @@ -31,7 +31,7 @@ #include "py/misc.h" #include "supervisor/memory.h" -#define _PM_ALLOCATOR common_hal_rgbmatrix_allocator_impl -#define _PM_FREE(x) (common_hal_rgbmatrix_free_impl((x)), (x)=NULL, (void)0) +#define _PM_allocate common_hal_rgbmatrix_allocator_impl +#define _PM_free(x) (common_hal_rgbmatrix_free_impl((x)), (x)=NULL, (void)0) extern void *common_hal_rgbmatrix_allocator_impl(size_t sz); extern void common_hal_rgbmatrix_free_impl(void *); -- cgit v1.2.3 From 774f2e16ba166b5976a46519c38ea894f897dca4 Mon Sep 17 00:00:00 2001 From: Jeff Epler Date: Sun, 11 Oct 2020 21:09:08 -0500 Subject: displayio, framebufferio: Remove spurious call to supervisor_start_terminal A call to supervisor_start_terminal remained in common_hal_displayio_display_construct and was copied to other display _construct functions, even though it was also being done in displayio_display_core_construct when that was factored out. Originally, this was harmless, except it created an extra allocation. When investigating #3482, I found that this bug became harmful, especially for displays that were created in Python code, because it caused a supervisor allocation to leak. I believe that it is safe to merge #3482 after this PR is merged. --- shared-module/displayio/Display.c | 2 -- shared-module/displayio/EPaperDisplay.c | 2 -- shared-module/framebufferio/FramebufferDisplay.c | 2 -- 3 files changed, 6 deletions(-) (limited to 'shared-module') diff --git a/shared-module/displayio/Display.c b/shared-module/displayio/Display.c index bb7e40f41..499c00ffb 100644 --- a/shared-module/displayio/Display.c +++ b/shared-module/displayio/Display.c @@ -107,8 +107,6 @@ void common_hal_displayio_display_construct(displayio_display_obj_t* self, i += 2 + data_size; } - supervisor_start_terminal(width, height); - // Always set the backlight type in case we're reusing memory. self->backlight_inout.base.type = &mp_type_NoneType; if (backlight_pin != NULL && common_hal_mcu_pin_is_free(backlight_pin)) { diff --git a/shared-module/displayio/EPaperDisplay.c b/shared-module/displayio/EPaperDisplay.c index 5b055e62e..46c7ea82e 100644 --- a/shared-module/displayio/EPaperDisplay.c +++ b/shared-module/displayio/EPaperDisplay.c @@ -90,8 +90,6 @@ void common_hal_displayio_epaperdisplay_construct(displayio_epaperdisplay_obj_t* // TODO: Clear } - supervisor_start_terminal(width, height); - // Set the group after initialization otherwise we may send pixels while we delay in // initialization. common_hal_displayio_epaperdisplay_show(self, &circuitpython_splash); diff --git a/shared-module/framebufferio/FramebufferDisplay.c b/shared-module/framebufferio/FramebufferDisplay.c index 5163c3a7b..6b506c7fa 100644 --- a/shared-module/framebufferio/FramebufferDisplay.c +++ b/shared-module/framebufferio/FramebufferDisplay.c @@ -96,8 +96,6 @@ void common_hal_framebufferio_framebufferdisplay_construct(framebufferio_framebu common_hal_framebufferio_framebufferdisplay_set_rotation(self, rotation); } - supervisor_start_terminal(self->core.width, self->core.height); - // Set the group after initialization otherwise we may send pixels while we delay in // initialization. common_hal_framebufferio_framebufferdisplay_show(self, &circuitpython_splash); -- cgit v1.2.3 From 9696dbfd388aa4c21b686d4566832964c31f8035 Mon Sep 17 00:00:00 2001 From: Jeff Epler Date: Mon, 12 Oct 2020 13:26:58 -0500 Subject: rgbmatrix: Don't crash when setting brightness=0 If the display is paused, `_PM_swapbuffer_maybe` will never return. So, when brightness is 0, refresh does nothing. This makes it necessary to update the display when unpausing. Closes: #3524 --- shared-module/rgbmatrix/RGBMatrix.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'shared-module') diff --git a/shared-module/rgbmatrix/RGBMatrix.c b/shared-module/rgbmatrix/RGBMatrix.c index 3007ca4db..abd6d500f 100644 --- a/shared-module/rgbmatrix/RGBMatrix.c +++ b/shared-module/rgbmatrix/RGBMatrix.c @@ -190,6 +190,8 @@ void common_hal_rgbmatrix_rgbmatrix_set_paused(rgbmatrix_rgbmatrix_obj_t* self, _PM_stop(&self->protomatter); } else if (!paused && self->paused) { _PM_resume(&self->protomatter); + _PM_convert_565(&self->protomatter, self->bufinfo.buf, self->width); + _PM_swapbuffer_maybe(&self->protomatter); } self->paused = paused; } @@ -199,8 +201,10 @@ bool common_hal_rgbmatrix_rgbmatrix_get_paused(rgbmatrix_rgbmatrix_obj_t* self) } void common_hal_rgbmatrix_rgbmatrix_refresh(rgbmatrix_rgbmatrix_obj_t* self) { - _PM_convert_565(&self->protomatter, self->bufinfo.buf, self->width); - _PM_swapbuffer_maybe(&self->protomatter); + if (!self->paused) { + _PM_convert_565(&self->protomatter, self->bufinfo.buf, self->width); + _PM_swapbuffer_maybe(&self->protomatter); + } } int common_hal_rgbmatrix_rgbmatrix_get_width(rgbmatrix_rgbmatrix_obj_t* self) { -- cgit v1.2.3 From 57b44928a38b5a2328e0fd4fe8f2baee11062229 Mon Sep 17 00:00:00 2001 From: Jensen Date: Thu, 8 Oct 2020 21:40:55 -0500 Subject: displayio: Pass transparent_color to ColorConverter Signed-off-by: Jensen --- shared-bindings/displayio/ColorConverter.c | 5 ++++- shared-bindings/displayio/ColorConverter.h | 2 +- shared-module/displayio/ColorConverter.c | 12 +++++++++++- shared-module/displayio/ColorConverter.h | 1 + 4 files changed, 17 insertions(+), 3 deletions(-) (limited to 'shared-module') diff --git a/shared-bindings/displayio/ColorConverter.c b/shared-bindings/displayio/ColorConverter.c index a2b6699ef..d2cbcfc73 100644 --- a/shared-bindings/displayio/ColorConverter.c +++ b/shared-bindings/displayio/ColorConverter.c @@ -43,6 +43,7 @@ //| """Create a ColorConverter object to convert color formats. Only supports RGB888 to RGB565 //| currently. //| :param bool dither: Adds random noise to dither the output image""" +//| :param bool transparent_color: Sets one color in the colorset to transparent""" //| ... //| @@ -50,9 +51,11 @@ //| STATIC mp_obj_t displayio_colorconverter_make_new(const mp_obj_type_t *type, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { enum { ARG_dither}; + enum { ARG_transparent_color }; static const mp_arg_t allowed_args[] = { { MP_QSTR_dither, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = false} }, + { MP_QSTR_transparent_color, MP_ARG_KW_ONLY | MP_ARG_INT, {.uint32_t = 0} }, }; mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); @@ -60,7 +63,7 @@ STATIC mp_obj_t displayio_colorconverter_make_new(const mp_obj_type_t *type, siz displayio_colorconverter_t *self = m_new_obj(displayio_colorconverter_t); self->base.type = &displayio_colorconverter_type; - common_hal_displayio_colorconverter_construct(self, args[ARG_dither].u_bool); + common_hal_displayio_colorconverter_construct(self, args[ARG_dither].u_bool, args[ARG_transparent_color].uint32_t); return MP_OBJ_FROM_PTR(self); } diff --git a/shared-bindings/displayio/ColorConverter.h b/shared-bindings/displayio/ColorConverter.h index d550d81be..146ad80bd 100644 --- a/shared-bindings/displayio/ColorConverter.h +++ b/shared-bindings/displayio/ColorConverter.h @@ -33,7 +33,7 @@ extern const mp_obj_type_t displayio_colorconverter_type; -void common_hal_displayio_colorconverter_construct(displayio_colorconverter_t* self, bool dither); +void common_hal_displayio_colorconverter_construct(displayio_colorconverter_t* self, bool dither, uint32_t transparent_color); void common_hal_displayio_colorconverter_convert(displayio_colorconverter_t *colorconverter, const _displayio_colorspace_t* colorspace, uint32_t input_color, uint32_t* output_color); void common_hal_displayio_colorconverter_set_dither(displayio_colorconverter_t* self, bool dither); diff --git a/shared-module/displayio/ColorConverter.c b/shared-module/displayio/ColorConverter.c index c2c3214aa..c23286d04 100644 --- a/shared-module/displayio/ColorConverter.c +++ b/shared-module/displayio/ColorConverter.c @@ -39,8 +39,9 @@ uint32_t displayio_colorconverter_dither_noise_2(uint32_t x, uint32_t y) { return displayio_colorconverter_dither_noise_1(x + y * 0xFFFF); } -void common_hal_displayio_colorconverter_construct(displayio_colorconverter_t* self, bool dither) { +void common_hal_displayio_colorconverter_construct(displayio_colorconverter_t* self, bool dither, uint32_t transparent_color) { self->dither = dither; + self->transparent_color = transparent_color; } uint16_t displayio_colorconverter_compute_rgb565(uint32_t color_rgb888) { @@ -161,6 +162,9 @@ void displayio_colorconverter_convert(displayio_colorconverter_t *self, const _d } output_color->pixel = packed; output_color->opaque = true; + if (self->transparent_color == pixel) { + output_color->opaque = false; + } return; } else if (colorspace->tricolor) { uint8_t luma = displayio_colorconverter_compute_luma(pixel); @@ -170,6 +174,9 @@ void displayio_colorconverter_convert(displayio_colorconverter_t *self, const _d output_color->pixel = 0; } output_color->opaque = true; + if (self->transparent_color == pixel) { + output_color->opaque = false; + } return; } uint8_t pixel_hue = displayio_colorconverter_compute_hue(pixel); @@ -179,6 +186,9 @@ void displayio_colorconverter_convert(displayio_colorconverter_t *self, const _d uint8_t luma = displayio_colorconverter_compute_luma(pixel); output_color->pixel = luma >> (8 - colorspace->depth); output_color->opaque = true; + if (self->transparent_color == pixel) { + output_color->opaque = false; + } return; } output_color->opaque = false; diff --git a/shared-module/displayio/ColorConverter.h b/shared-module/displayio/ColorConverter.h index 10b1604a4..b402625ef 100644 --- a/shared-module/displayio/ColorConverter.h +++ b/shared-module/displayio/ColorConverter.h @@ -36,6 +36,7 @@ typedef struct { mp_obj_base_t base; bool dither; + uint32_t transparent_color; } displayio_colorconverter_t; bool displayio_colorconverter_needs_refresh(displayio_colorconverter_t *self); -- cgit v1.2.3 From b359e2945ac9914c31afc7e692a4f46a837a854d Mon Sep 17 00:00:00 2001 From: Jensen Date: Sun, 11 Oct 2020 13:18:09 -0500 Subject: displayio: Add make_transparent and make_opaque to ColorConvertor --- shared-bindings/displayio/ColorConverter.c | 7 ++----- shared-bindings/displayio/ColorConverter.h | 5 ++++- shared-module/displayio/ColorConverter.c | 29 ++++++++++++++++++----------- 3 files changed, 24 insertions(+), 17 deletions(-) (limited to 'shared-module') diff --git a/shared-bindings/displayio/ColorConverter.c b/shared-bindings/displayio/ColorConverter.c index d2cbcfc73..c02dfdb6d 100644 --- a/shared-bindings/displayio/ColorConverter.c +++ b/shared-bindings/displayio/ColorConverter.c @@ -43,7 +43,6 @@ //| """Create a ColorConverter object to convert color formats. Only supports RGB888 to RGB565 //| currently. //| :param bool dither: Adds random noise to dither the output image""" -//| :param bool transparent_color: Sets one color in the colorset to transparent""" //| ... //| @@ -51,11 +50,9 @@ //| STATIC mp_obj_t displayio_colorconverter_make_new(const mp_obj_type_t *type, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { enum { ARG_dither}; - enum { ARG_transparent_color }; static const mp_arg_t allowed_args[] = { - { MP_QSTR_dither, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = false} }, - { MP_QSTR_transparent_color, MP_ARG_KW_ONLY | MP_ARG_INT, {.uint32_t = 0} }, + { MP_QSTR_dither, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = false} } }; mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); @@ -63,7 +60,7 @@ STATIC mp_obj_t displayio_colorconverter_make_new(const mp_obj_type_t *type, siz displayio_colorconverter_t *self = m_new_obj(displayio_colorconverter_t); self->base.type = &displayio_colorconverter_type; - common_hal_displayio_colorconverter_construct(self, args[ARG_dither].u_bool, args[ARG_transparent_color].uint32_t); + common_hal_displayio_colorconverter_construct(self, args[ARG_dither].u_bool); return MP_OBJ_FROM_PTR(self); } diff --git a/shared-bindings/displayio/ColorConverter.h b/shared-bindings/displayio/ColorConverter.h index 146ad80bd..441f7c7ae 100644 --- a/shared-bindings/displayio/ColorConverter.h +++ b/shared-bindings/displayio/ColorConverter.h @@ -33,10 +33,13 @@ extern const mp_obj_type_t displayio_colorconverter_type; -void common_hal_displayio_colorconverter_construct(displayio_colorconverter_t* self, bool dither, uint32_t transparent_color); +void common_hal_displayio_colorconverter_construct(displayio_colorconverter_t* self, bool dither); void common_hal_displayio_colorconverter_convert(displayio_colorconverter_t *colorconverter, const _displayio_colorspace_t* colorspace, uint32_t input_color, uint32_t* output_color); void common_hal_displayio_colorconverter_set_dither(displayio_colorconverter_t* self, bool dither); bool common_hal_displayio_colorconverter_get_dither(displayio_colorconverter_t* self); +void common_hal_displayio_colorconverter_make_transparent(displayio_colorconverter_t* self, uint32_t transparent_color); +void common_hal_displayio_colorconverter_make_opaque(displayio_colorconverter_t* self, uint32_t transparent_color); + #endif // MICROPY_INCLUDED_SHARED_BINDINGS_DISPLAYIO_COLORCONVERTER_H diff --git a/shared-module/displayio/ColorConverter.c b/shared-module/displayio/ColorConverter.c index c23286d04..0a1a7dc06 100644 --- a/shared-module/displayio/ColorConverter.c +++ b/shared-module/displayio/ColorConverter.c @@ -39,9 +39,8 @@ uint32_t displayio_colorconverter_dither_noise_2(uint32_t x, uint32_t y) { return displayio_colorconverter_dither_noise_1(x + y * 0xFFFF); } -void common_hal_displayio_colorconverter_construct(displayio_colorconverter_t* self, bool dither, uint32_t transparent_color) { +void common_hal_displayio_colorconverter_construct(displayio_colorconverter_t* self, bool dither) { self->dither = dither; - self->transparent_color = transparent_color; } uint16_t displayio_colorconverter_compute_rgb565(uint32_t color_rgb888) { @@ -129,9 +128,26 @@ bool common_hal_displayio_colorconverter_get_dither(displayio_colorconverter_t* return self->dither; } +void common_hal_displayio_colorconverter_make_transparent(displayio_colorconverter_t* self, uint32_t transparent_color) { + self->transparent_color = transparent_color; + // TODO: Does this require refreshing like the other modules? +} + +void common_hal_displayio_colorconverter_make_opaque(displayio_colorconverter_t* self, uint32_t transparent_color) { + if (self->transparent_color == transparent_color) { + m_del(uint8_t, self, transparent_color); + } + // TODO: Does this require refreshing like the other modules? +} + void displayio_colorconverter_convert(displayio_colorconverter_t *self, const _displayio_colorspace_t* colorspace, const displayio_input_pixel_t *input_pixel, displayio_output_pixel_t *output_color) { uint32_t pixel = input_pixel->pixel; + if (self->transparent_color == pixel) { + output_color->opaque = false; + return; + } + if (self->dither){ uint8_t randr = (displayio_colorconverter_dither_noise_2(input_pixel->tile_x,input_pixel->tile_y)); uint8_t randg = (displayio_colorconverter_dither_noise_2(input_pixel->tile_x+33,input_pixel->tile_y)); @@ -162,9 +178,6 @@ void displayio_colorconverter_convert(displayio_colorconverter_t *self, const _d } output_color->pixel = packed; output_color->opaque = true; - if (self->transparent_color == pixel) { - output_color->opaque = false; - } return; } else if (colorspace->tricolor) { uint8_t luma = displayio_colorconverter_compute_luma(pixel); @@ -174,9 +187,6 @@ void displayio_colorconverter_convert(displayio_colorconverter_t *self, const _d output_color->pixel = 0; } output_color->opaque = true; - if (self->transparent_color == pixel) { - output_color->opaque = false; - } return; } uint8_t pixel_hue = displayio_colorconverter_compute_hue(pixel); @@ -186,9 +196,6 @@ void displayio_colorconverter_convert(displayio_colorconverter_t *self, const _d uint8_t luma = displayio_colorconverter_compute_luma(pixel); output_color->pixel = luma >> (8 - colorspace->depth); output_color->opaque = true; - if (self->transparent_color == pixel) { - output_color->opaque = false; - } return; } output_color->opaque = false; -- cgit v1.2.3 From 337019626a8cd0632cd2a6f6bae4ae09ae26cf16 Mon Sep 17 00:00:00 2001 From: Jensen Date: Sun, 11 Oct 2020 17:29:16 -0500 Subject: displayio: Add make_transparent to ColorConverter --- locale/circuitpython.pot | 24 +++++++++++++++++++--- shared-bindings/displayio/ColorConverter.c | 32 ++++++++++++++++++++++++++++++ shared-module/displayio/ColorConverter.c | 12 +++++++---- 3 files changed, 61 insertions(+), 7 deletions(-) (limited to 'shared-module') diff --git a/locale/circuitpython.pot b/locale/circuitpython.pot index c4951f78f..081e2df9f 100644 --- a/locale/circuitpython.pot +++ b/locale/circuitpython.pot @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2020-09-29 20:14-0500\n" +"POT-Creation-Date: 2020-10-12 20:47-0500\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -285,6 +285,7 @@ msgid "All I2C peripherals are in use" msgstr "" #: ports/atmel-samd/common-hal/canio/Listener.c +#: ports/stm/common-hal/canio/Listener.c msgid "All RX FIFOs in use" msgstr "" @@ -892,6 +893,7 @@ msgid "File exists" msgstr "" #: ports/atmel-samd/common-hal/canio/Listener.c +#: ports/stm/common-hal/canio/Listener.c msgid "Filters too complex" msgstr "" @@ -928,7 +930,8 @@ msgid "Group full" msgstr "" #: ports/mimxrt10xx/common-hal/busio/SPI.c ports/stm/common-hal/busio/I2C.c -#: ports/stm/common-hal/busio/SPI.c ports/stm/common-hal/sdioio/SDCard.c +#: ports/stm/common-hal/busio/SPI.c ports/stm/common-hal/canio/CAN.c +#: ports/stm/common-hal/sdioio/SDCard.c msgid "Hardware busy, try alternative pins" msgstr "" @@ -998,7 +1001,8 @@ msgid "Invalid %q pin" msgstr "" #: ports/stm/common-hal/busio/I2C.c ports/stm/common-hal/busio/SPI.c -#: ports/stm/common-hal/busio/UART.c ports/stm/common-hal/sdioio/SDCard.c +#: ports/stm/common-hal/busio/UART.c ports/stm/common-hal/canio/CAN.c +#: ports/stm/common-hal/sdioio/SDCard.c msgid "Invalid %q pin selection" msgstr "" @@ -3144,6 +3148,7 @@ msgstr "" msgid "pow() with 3 arguments requires integers" msgstr "" +#: ports/esp32s2/boards/adafruit_metro_esp32s2/mpconfigboard.h #: ports/esp32s2/boards/electroniccats_bastwifi/mpconfigboard.h #: ports/esp32s2/boards/espressif_kaluga_1/mpconfigboard.h #: ports/esp32s2/boards/espressif_saola_1_wroom/mpconfigboard.h @@ -3151,6 +3156,7 @@ msgstr "" #: ports/esp32s2/boards/microdev_micro_s2/mpconfigboard.h #: ports/esp32s2/boards/muselab_nanoesp32_s2/mpconfigboard.h #: ports/esp32s2/boards/unexpectedmaker_feathers2/mpconfigboard.h +#: ports/esp32s2/boards/unexpectedmaker_feathers2_prerelease/mpconfigboard.h msgid "pressing boot button at start up.\n" msgstr "" @@ -3388,6 +3394,18 @@ msgstr "" msgid "too many values to unpack (expected %d)" msgstr "" +#: shared-bindings/displayio/ColorConverter.c +msgid "transparent_color should be an int" +msgstr "" + +#: shared-module/displayio/ColorConverter.c +msgid "transparent_color value is already set" +msgstr "" + +#: shared-module/displayio/ColorConverter.c +msgid "transparent_color value is not transparent" +msgstr "" + #: extmod/ulab/code/approx/approx.c msgid "trapz is defined for 1D arrays of equal length" msgstr "" diff --git a/shared-bindings/displayio/ColorConverter.c b/shared-bindings/displayio/ColorConverter.c index c02dfdb6d..a041bbe59 100644 --- a/shared-bindings/displayio/ColorConverter.c +++ b/shared-bindings/displayio/ColorConverter.c @@ -110,9 +110,41 @@ const mp_obj_property_t displayio_colorconverter_dither_obj = { (mp_obj_t)&mp_const_none_obj}, }; +//| def make_transparent(self, pixel: int) -> None: +//| """Sets a pixel to not opaque.""" +//| +STATIC mp_obj_t displayio_colorconverter_make_transparent(mp_obj_t self_in, mp_obj_t transparent_color_obj) { + displayio_colorconverter_t *self = MP_OBJ_TO_PTR(self_in); + + mp_int_t transparent_color; + if (!mp_obj_get_int_maybe(transparent_color_obj, &transparent_color)) { + mp_raise_ValueError(translate("transparent_color should be an int")); + } + common_hal_displayio_colorconverter_make_transparent(self, transparent_color); + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_2(displayio_colorconverter_make_transparent_obj, displayio_colorconverter_make_transparent); + +//| def make_opaque(self, pixel: int) -> None: +//| """Sets a pixel to opaque.""" +//| +STATIC mp_obj_t displayio_colorconverter_make_opaque(mp_obj_t self_in, mp_obj_t transparent_color_obj) { + displayio_colorconverter_t *self = MP_OBJ_TO_PTR(self_in); + + mp_int_t transparent_color; + if (!mp_obj_get_int_maybe(transparent_color_obj, &transparent_color)) { + mp_raise_ValueError(translate("transparent_color should be an int")); + } + common_hal_displayio_colorconverter_make_opaque(self, transparent_color); + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_2(displayio_colorconverter_make_opaque_obj, displayio_colorconverter_make_opaque); + STATIC const mp_rom_map_elem_t displayio_colorconverter_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_convert), MP_ROM_PTR(&displayio_colorconverter_convert_obj) }, { MP_ROM_QSTR(MP_QSTR_dither), MP_ROM_PTR(&displayio_colorconverter_dither_obj) }, + { MP_ROM_QSTR(MP_QSTR_make_transparent), MP_ROM_PTR(&displayio_colorconverter_make_transparent_obj) }, + { MP_ROM_QSTR(MP_QSTR_make_opaque), MP_ROM_PTR(&displayio_colorconverter_make_opaque_obj) }, }; STATIC MP_DEFINE_CONST_DICT(displayio_colorconverter_locals_dict, displayio_colorconverter_locals_dict_table); diff --git a/shared-module/displayio/ColorConverter.c b/shared-module/displayio/ColorConverter.c index 0a1a7dc06..fef71cdf5 100644 --- a/shared-module/displayio/ColorConverter.c +++ b/shared-module/displayio/ColorConverter.c @@ -27,6 +27,7 @@ #include "shared-bindings/displayio/ColorConverter.h" #include "py/misc.h" +#include "py/runtime.h" uint32_t displayio_colorconverter_dither_noise_1 (uint32_t n) { @@ -129,15 +130,18 @@ bool common_hal_displayio_colorconverter_get_dither(displayio_colorconverter_t* } void common_hal_displayio_colorconverter_make_transparent(displayio_colorconverter_t* self, uint32_t transparent_color) { + if (self->transparent_color) { + mp_raise_RuntimeError(translate("transparent_color value is already set")); + } self->transparent_color = transparent_color; - // TODO: Does this require refreshing like the other modules? } void common_hal_displayio_colorconverter_make_opaque(displayio_colorconverter_t* self, uint32_t transparent_color) { - if (self->transparent_color == transparent_color) { - m_del(uint8_t, self, transparent_color); + if (self->transparent_color != transparent_color) { + mp_raise_RuntimeError(translate("transparent_color value is not transparent")); } - // TODO: Does this require refreshing like the other modules? + // 0x1000000 will never equal a valid color + self->transparent_color = 0x1000000; } void displayio_colorconverter_convert(displayio_colorconverter_t *self, const _displayio_colorspace_t* colorspace, const displayio_input_pixel_t *input_pixel, displayio_output_pixel_t *output_color) { -- cgit v1.2.3 From 2517e4b486563724771074da88bc7fd6eda02532 Mon Sep 17 00:00:00 2001 From: Jensen Date: Wed, 14 Oct 2020 21:51:22 -0500 Subject: displayio: ColorConverter handle if opaque color is black --- shared-bindings/displayio/ColorConverter.c | 15 +++++---------- shared-bindings/displayio/ColorConverter.h | 2 +- shared-module/displayio/ColorConverter.c | 9 +++------ 3 files changed, 9 insertions(+), 17 deletions(-) (limited to 'shared-module') diff --git a/shared-bindings/displayio/ColorConverter.c b/shared-bindings/displayio/ColorConverter.c index a041bbe59..40550af82 100644 --- a/shared-bindings/displayio/ColorConverter.c +++ b/shared-bindings/displayio/ColorConverter.c @@ -117,7 +117,7 @@ STATIC mp_obj_t displayio_colorconverter_make_transparent(mp_obj_t self_in, mp_o displayio_colorconverter_t *self = MP_OBJ_TO_PTR(self_in); mp_int_t transparent_color; - if (!mp_obj_get_int_maybe(transparent_color_obj, &transparent_color)) { + if (!mp_obj_get_int(&transparent_color)) { mp_raise_ValueError(translate("transparent_color should be an int")); } common_hal_displayio_colorconverter_make_transparent(self, transparent_color); @@ -125,20 +125,15 @@ STATIC mp_obj_t displayio_colorconverter_make_transparent(mp_obj_t self_in, mp_o } MP_DEFINE_CONST_FUN_OBJ_2(displayio_colorconverter_make_transparent_obj, displayio_colorconverter_make_transparent); -//| def make_opaque(self, pixel: int) -> None: +//| def make_opaque(self) -> None: //| """Sets a pixel to opaque.""" //| -STATIC mp_obj_t displayio_colorconverter_make_opaque(mp_obj_t self_in, mp_obj_t transparent_color_obj) { +STATIC mp_obj_t displayio_colorconverter_make_opaque(mp_obj_t self_in) { displayio_colorconverter_t *self = MP_OBJ_TO_PTR(self_in); - - mp_int_t transparent_color; - if (!mp_obj_get_int_maybe(transparent_color_obj, &transparent_color)) { - mp_raise_ValueError(translate("transparent_color should be an int")); - } - common_hal_displayio_colorconverter_make_opaque(self, transparent_color); + common_hal_displayio_colorconverter_make_opaque(self); return mp_const_none; } -MP_DEFINE_CONST_FUN_OBJ_2(displayio_colorconverter_make_opaque_obj, displayio_colorconverter_make_opaque); +MP_DEFINE_CONST_FUN_OBJ_1(displayio_colorconverter_make_opaque_obj, displayio_colorconverter_make_opaque); STATIC const mp_rom_map_elem_t displayio_colorconverter_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_convert), MP_ROM_PTR(&displayio_colorconverter_convert_obj) }, diff --git a/shared-bindings/displayio/ColorConverter.h b/shared-bindings/displayio/ColorConverter.h index 441f7c7ae..e4ddd1972 100644 --- a/shared-bindings/displayio/ColorConverter.h +++ b/shared-bindings/displayio/ColorConverter.h @@ -40,6 +40,6 @@ void common_hal_displayio_colorconverter_set_dither(displayio_colorconverter_t* bool common_hal_displayio_colorconverter_get_dither(displayio_colorconverter_t* self); void common_hal_displayio_colorconverter_make_transparent(displayio_colorconverter_t* self, uint32_t transparent_color); -void common_hal_displayio_colorconverter_make_opaque(displayio_colorconverter_t* self, uint32_t transparent_color); +void common_hal_displayio_colorconverter_make_opaque(displayio_colorconverter_t* self); #endif // MICROPY_INCLUDED_SHARED_BINDINGS_DISPLAYIO_COLORCONVERTER_H diff --git a/shared-module/displayio/ColorConverter.c b/shared-module/displayio/ColorConverter.c index fef71cdf5..4089b2265 100644 --- a/shared-module/displayio/ColorConverter.c +++ b/shared-module/displayio/ColorConverter.c @@ -130,16 +130,13 @@ bool common_hal_displayio_colorconverter_get_dither(displayio_colorconverter_t* } void common_hal_displayio_colorconverter_make_transparent(displayio_colorconverter_t* self, uint32_t transparent_color) { - if (self->transparent_color) { - mp_raise_RuntimeError(translate("transparent_color value is already set")); + if (self->transparent_color >= 0x1000000) { + mp_raise_RuntimeError(translate("Only one color can be transparent at a time")); } self->transparent_color = transparent_color; } -void common_hal_displayio_colorconverter_make_opaque(displayio_colorconverter_t* self, uint32_t transparent_color) { - if (self->transparent_color != transparent_color) { - mp_raise_RuntimeError(translate("transparent_color value is not transparent")); - } +void common_hal_displayio_colorconverter_make_opaque(displayio_colorconverter_t* self) { // 0x1000000 will never equal a valid color self->transparent_color = 0x1000000; } -- cgit v1.2.3 From 88d07ef35b686ffd66487de81564396aac0818b8 Mon Sep 17 00:00:00 2001 From: Jeff Epler Date: Tue, 13 Oct 2020 16:57:09 -0500 Subject: displayio: further ensure just one start_terminal call @cwalther determined that for boards with 2 displays (monster m4sk), start_terminal would be called for each one, leaking supervisor heap entries. Determine, by comparing addresses, whether the display being acted on is the first display (number zero) and do (or do not) call start_terminal. stop_terminal can safely be called multiple times, so there's no need to guard against calling it more than once. Slight behavioral change: The terminal size would follow the displays[0] size, not the displays[1] size --- shared-module/displayio/Display.c | 6 ++++-- shared-module/displayio/display_core.c | 5 ++++- shared-module/framebufferio/FramebufferDisplay.c | 6 ++++-- 3 files changed, 12 insertions(+), 5 deletions(-) (limited to 'shared-module') diff --git a/shared-module/displayio/Display.c b/shared-module/displayio/Display.c index 499c00ffb..7c8c9280b 100644 --- a/shared-module/displayio/Display.c +++ b/shared-module/displayio/Display.c @@ -347,8 +347,10 @@ void common_hal_displayio_display_set_rotation(displayio_display_obj_t* self, in self->core.height = tmp; } displayio_display_core_set_rotation(&self->core, rotation); - supervisor_stop_terminal(); - supervisor_start_terminal(self->core.width, self->core.height); + if (self == &displays[0].display) { + supervisor_stop_terminal(); + supervisor_start_terminal(self->core.width, self->core.height); + } if (self->core.current_group != NULL) { displayio_group_update_transform(self->core.current_group, &self->core.transform); } diff --git a/shared-module/displayio/display_core.c b/shared-module/displayio/display_core.c index 60a8ef213..411f9f373 100644 --- a/shared-module/displayio/display_core.c +++ b/shared-module/displayio/display_core.c @@ -85,7 +85,10 @@ void displayio_display_core_construct(displayio_display_core_t* self, self->bus = bus; - supervisor_start_terminal(width, height); + // (offsetof core is equal in all display types) + if (self == &displays[0].display.core) { + supervisor_start_terminal(width, height); + } self->width = width; self->height = height; diff --git a/shared-module/framebufferio/FramebufferDisplay.c b/shared-module/framebufferio/FramebufferDisplay.c index 6b506c7fa..03e121c91 100644 --- a/shared-module/framebufferio/FramebufferDisplay.c +++ b/shared-module/framebufferio/FramebufferDisplay.c @@ -280,8 +280,10 @@ void common_hal_framebufferio_framebufferdisplay_set_rotation(framebufferio_fram self->core.height = tmp; } displayio_display_core_set_rotation(&self->core, rotation); - supervisor_stop_terminal(); - supervisor_start_terminal(self->core.width, self->core.height); + if (self == &displays[0].framebuffer_display) { + supervisor_stop_terminal(); + supervisor_start_terminal(self->core.width, self->core.height); + } if (self->core.current_group != NULL) { displayio_group_update_transform(self->core.current_group, &self->core.transform); } -- cgit v1.2.3 From 74c07a4bdcc942e57668f1a2181e00d1213864a7 Mon Sep 17 00:00:00 2001 From: Jensen Date: Fri, 16 Oct 2020 19:48:41 -0500 Subject: displayio: Add in opaque pixel option for future --- locale/circuitpython.pot | 6 +----- shared-bindings/displayio/ColorConverter.c | 8 +++++--- shared-bindings/displayio/ColorConverter.h | 2 +- shared-module/displayio/ColorConverter.c | 4 +++- 4 files changed, 10 insertions(+), 10 deletions(-) (limited to 'shared-module') diff --git a/locale/circuitpython.pot b/locale/circuitpython.pot index c4b40d361..35143e04e 100644 --- a/locale/circuitpython.pot +++ b/locale/circuitpython.pot @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2020-10-14 22:22-0500\n" +"POT-Creation-Date: 2020-10-16 19:50-0500\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -3408,10 +3408,6 @@ msgstr "" msgid "too many values to unpack (expected %d)" msgstr "" -#: shared-bindings/displayio/ColorConverter.c -msgid "transparent_color should be an int" -msgstr "" - #: extmod/ulab/code/approx/approx.c msgid "trapz is defined for 1D arrays of equal length" msgstr "" diff --git a/shared-bindings/displayio/ColorConverter.c b/shared-bindings/displayio/ColorConverter.c index 4e41ceff1..e47a961a5 100644 --- a/shared-bindings/displayio/ColorConverter.c +++ b/shared-bindings/displayio/ColorConverter.c @@ -125,12 +125,14 @@ MP_DEFINE_CONST_FUN_OBJ_2(displayio_colorconverter_make_transparent_obj, display //| def make_opaque(self) -> None: //| """Sets a pixel to opaque.""" //| -STATIC mp_obj_t displayio_colorconverter_make_opaque(mp_obj_t self_in) { +STATIC mp_obj_t displayio_colorconverter_make_opaque(mp_obj_t self_in, mp_obj_t transparent_color_obj) { displayio_colorconverter_t *self = MP_OBJ_TO_PTR(self_in); - common_hal_displayio_colorconverter_make_opaque(self); + + mp_int_t transparent_color = mp_obj_get_int(&transparent_color); + common_hal_displayio_colorconverter_make_opaque(self, transparent_color); return mp_const_none; } -MP_DEFINE_CONST_FUN_OBJ_1(displayio_colorconverter_make_opaque_obj, displayio_colorconverter_make_opaque); +MP_DEFINE_CONST_FUN_OBJ_2(displayio_colorconverter_make_opaque_obj, displayio_colorconverter_make_opaque); STATIC const mp_rom_map_elem_t displayio_colorconverter_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_convert), MP_ROM_PTR(&displayio_colorconverter_convert_obj) }, diff --git a/shared-bindings/displayio/ColorConverter.h b/shared-bindings/displayio/ColorConverter.h index e4ddd1972..441f7c7ae 100644 --- a/shared-bindings/displayio/ColorConverter.h +++ b/shared-bindings/displayio/ColorConverter.h @@ -40,6 +40,6 @@ void common_hal_displayio_colorconverter_set_dither(displayio_colorconverter_t* bool common_hal_displayio_colorconverter_get_dither(displayio_colorconverter_t* self); void common_hal_displayio_colorconverter_make_transparent(displayio_colorconverter_t* self, uint32_t transparent_color); -void common_hal_displayio_colorconverter_make_opaque(displayio_colorconverter_t* self); +void common_hal_displayio_colorconverter_make_opaque(displayio_colorconverter_t* self, uint32_t transparent_color); #endif // MICROPY_INCLUDED_SHARED_BINDINGS_DISPLAYIO_COLORCONVERTER_H diff --git a/shared-module/displayio/ColorConverter.c b/shared-module/displayio/ColorConverter.c index 4089b2265..d1a4f16a9 100644 --- a/shared-module/displayio/ColorConverter.c +++ b/shared-module/displayio/ColorConverter.c @@ -136,7 +136,9 @@ void common_hal_displayio_colorconverter_make_transparent(displayio_colorconvert self->transparent_color = transparent_color; } -void common_hal_displayio_colorconverter_make_opaque(displayio_colorconverter_t* self) { +void common_hal_displayio_colorconverter_make_opaque(displayio_colorconverter_t* self, uint32_t transparent_color) { + (void) transparent_color; + // 0x1000000 will never equal a valid color self->transparent_color = 0x1000000; } -- cgit v1.2.3 From fc3f2a3f7f670f28d1a57eb61dfbf065463c906a Mon Sep 17 00:00:00 2001 From: Jensen Date: Fri, 16 Oct 2020 20:05:39 -0500 Subject: displayio: Remove trailing whitespace --- shared-module/displayio/ColorConverter.c | 1 - 1 file changed, 1 deletion(-) (limited to 'shared-module') diff --git a/shared-module/displayio/ColorConverter.c b/shared-module/displayio/ColorConverter.c index d1a4f16a9..dc64da03d 100644 --- a/shared-module/displayio/ColorConverter.c +++ b/shared-module/displayio/ColorConverter.c @@ -138,7 +138,6 @@ void common_hal_displayio_colorconverter_make_transparent(displayio_colorconvert void common_hal_displayio_colorconverter_make_opaque(displayio_colorconverter_t* self, uint32_t transparent_color) { (void) transparent_color; - // 0x1000000 will never equal a valid color self->transparent_color = 0x1000000; } -- cgit v1.2.3 From b520498c733356afdc418bd5a9841c7496a3926e Mon Sep 17 00:00:00 2001 From: Jeff Epler Date: Thu, 1 Oct 2020 10:30:35 -0500 Subject: sharpdisplay: Re-use supervisor allocations if possible This is enabled by #3482 I was unable to determine why previously I had added sizeof(void*) to the GC heap allocation, so I removed that code as a mistake. --- shared-module/sharpdisplay/SharpMemoryFramebuffer.c | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) (limited to 'shared-module') diff --git a/shared-module/sharpdisplay/SharpMemoryFramebuffer.c b/shared-module/sharpdisplay/SharpMemoryFramebuffer.c index c23446828..b199e98d6 100644 --- a/shared-module/sharpdisplay/SharpMemoryFramebuffer.c +++ b/shared-module/sharpdisplay/SharpMemoryFramebuffer.c @@ -34,21 +34,22 @@ #include "shared-module/sharpdisplay/SharpMemoryFramebuffer.h" #include "supervisor/memory.h" +#include "supervisor/shared/safe_mode.h" #define SHARPMEM_BIT_WRITECMD_LSB (0x80) #define SHARPMEM_BIT_VCOM_LSB (0x40) -static inline void *hybrid_alloc(size_t sz) { - if (gc_alloc_possible()) { - return m_malloc(sz + sizeof(void*), true); - } else { - supervisor_allocation *allocation = allocate_memory(align32_size(sz), false); - if (!allocation) { - return NULL; - } +static void *hybrid_alloc(size_t sz) { + supervisor_allocation *allocation = allocate_memory(align32_size(sz), false); + if (allocation) { memset(allocation->ptr, 0, sz); return allocation->ptr; } + if (gc_alloc_possible()) { + return m_malloc(sz, true); + } + reset_into_safe_mode(MEM_MANAGE); + return NULL; // unreached } static inline void hybrid_free(void *ptr_in) { @@ -155,7 +156,8 @@ void common_hal_sharpdisplay_framebuffer_construct(sharpdisplay_framebuffer_obj_ int row_stride = common_hal_sharpdisplay_framebuffer_get_row_stride(self); self->bufinfo.len = row_stride * height + 2; - self->bufinfo.buf = gc_alloc(self->bufinfo.len, false, true); + // re-use a supervisor allocation if possible + self->bufinfo.buf = hybrid_alloc(self->bufinfo.len); uint8_t *data = self->bufinfo.buf; *data++ = SHARPMEM_BIT_WRITECMD_LSB; -- cgit v1.2.3 From 1117edae63df7b66f1575980bf54d6836f9a8aa8 Mon Sep 17 00:00:00 2001 From: Christian Walther Date: Sat, 24 Oct 2020 17:13:10 +0200 Subject: Fix erroneous claim of board.I2C() by deinited display. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit At the end of a session that called displayio.release_displays() (and did not initialize a new display), a board.I2C() bus that was previously used by a display would wrongly be considered still in use. While I can’t think of any unrecoverable problem this would cause in the next session, it violates the assumption that a soft reboot resets everything not needed by displays, potentially leading to confusion. By itself, this change does not fix the problem yet - rather, it introduces the same issue as in #3581 for SPI. This needs to be solved in the same way for I2C and SPI. --- shared-module/board/__init__.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'shared-module') diff --git a/shared-module/board/__init__.c b/shared-module/board/__init__.c index 39b68a0f1..856103b7b 100644 --- a/shared-module/board/__init__.c +++ b/shared-module/board/__init__.c @@ -139,7 +139,7 @@ void reset_board_busses(void) { bool display_using_i2c = false; #if CIRCUITPY_DISPLAYIO for (uint8_t i = 0; i < CIRCUITPY_DISPLAY_LIMIT; i++) { - if (displays[i].i2cdisplay_bus.bus == i2c_singleton) { + if (displays[i].bus_base.type == &displayio_i2cdisplay_type && displays[i].i2cdisplay_bus.bus == i2c_singleton) { display_using_i2c = true; break; } -- cgit v1.2.3 From f4f80e07ca3dc2f5a93484e5342540837a94a505 Mon Sep 17 00:00:00 2001 From: Christian Walther Date: Sat, 24 Oct 2020 17:23:17 +0200 Subject: Fix lost board.SPI and board.I2C after being used by display. Fixes #3581. Pins were marked as never_reset by common_hal_displayio_fourwire_construct() and common_hal_sharpdisplay_framebuffer_construct(), but these marks were never removed, so at the end of a session after displayio.release_displays(), {spi|i2c}_singleton would be set to NULL but the pins would not be reset. In the next session, board.SPI() and board.I2C() were unable to reconstruct the object because the pins were still in use. For symmetry with creation of the singleton, add deinitialization before setting it to NULL in reset_board_busses(). This makes the pins resettable, so that reset_port(), moved behind it, then resets them. --- main.c | 4 +++- shared-module/board/__init__.c | 14 +++++++++----- 2 files changed, 12 insertions(+), 6 deletions(-) (limited to 'shared-module') diff --git a/main.c b/main.c index b43b3b8c8..80b163f60 100755 --- a/main.c +++ b/main.c @@ -234,10 +234,12 @@ void cleanup_after_vm(supervisor_allocation* heap) { common_hal_canio_reset(); #endif - reset_port(); + // reset_board_busses() first because it may release pins from the never_reset state, so that + // reset_port() can reset them. #if CIRCUITPY_BOARD reset_board_busses(); #endif + reset_port(); reset_board(); reset_status_led(); } diff --git a/shared-module/board/__init__.c b/shared-module/board/__init__.c index 856103b7b..967b430d2 100644 --- a/shared-module/board/__init__.c +++ b/shared-module/board/__init__.c @@ -145,8 +145,11 @@ void reset_board_busses(void) { } } #endif - if (!display_using_i2c) { - i2c_singleton = NULL; + if (i2c_singleton != NULL) { + if (!display_using_i2c) { + common_hal_busio_i2c_deinit(i2c_singleton); + i2c_singleton = NULL; + } } #endif #if BOARD_SPI @@ -169,9 +172,10 @@ void reset_board_busses(void) { // make sure SPI lock is not held over a soft reset if (spi_singleton != NULL) { common_hal_busio_spi_unlock(spi_singleton); - } - if (!display_using_spi) { - spi_singleton = NULL; + if (!display_using_spi) { + common_hal_busio_spi_deinit(spi_singleton); + spi_singleton = NULL; + } } #endif #if BOARD_UART -- cgit v1.2.3 From 99a3750a2cfd1da8cdd266ca9a0367f0c3a54092 Mon Sep 17 00:00:00 2001 From: Christian Walther Date: Sat, 24 Oct 2020 17:50:11 +0200 Subject: Fix lost board.SPI and board.I2C after explicitly deiniting them. After calling board.SPI().deinit(), calling board.SPI() again would return the unusable deinited object and there was no way of getting it back into an initialized state until the end of the session. --- shared-bindings/board/__init__.c | 10 ++++++++-- shared-module/board/__init__.c | 10 ++++------ 2 files changed, 12 insertions(+), 8 deletions(-) (limited to 'shared-module') diff --git a/shared-bindings/board/__init__.c b/shared-bindings/board/__init__.c index 6837fc41c..717698408 100644 --- a/shared-bindings/board/__init__.c +++ b/shared-bindings/board/__init__.c @@ -28,6 +28,12 @@ #include "py/runtime.h" #include "shared-bindings/board/__init__.h" +#if BOARD_I2C +#include "shared-bindings/busio/I2C.h" +#endif +#if BOARD_SPI +#include "shared-bindings/busio/SPI.h" +#endif //| """Board specific pin names //| @@ -45,7 +51,7 @@ #if BOARD_I2C mp_obj_t board_i2c(void) { mp_obj_t singleton = common_hal_board_get_i2c(); - if (singleton != NULL) { + if (singleton != NULL && !common_hal_busio_i2c_deinited(singleton)) { return singleton; } assert_pin_free(DEFAULT_I2C_BUS_SDA); @@ -69,7 +75,7 @@ MP_DEFINE_CONST_FUN_OBJ_0(board_i2c_obj, board_i2c); #if BOARD_SPI mp_obj_t board_spi(void) { mp_obj_t singleton = common_hal_board_get_spi(); - if (singleton != NULL) { + if (singleton != NULL && !common_hal_busio_spi_deinited(singleton)) { return singleton; } assert_pin_free(DEFAULT_SPI_BUS_SCK); diff --git a/shared-module/board/__init__.c b/shared-module/board/__init__.c index 967b430d2..2f1c34e56 100644 --- a/shared-module/board/__init__.c +++ b/shared-module/board/__init__.c @@ -55,9 +55,8 @@ mp_obj_t common_hal_board_get_i2c(void) { } mp_obj_t common_hal_board_create_i2c(void) { - if (i2c_singleton != NULL) { - return i2c_singleton; - } + // All callers have either already verified this or come so early that it can't be otherwise. + assert(i2c_singleton == NULL || common_hal_busio_i2c_deinited(i2c_singleton)); busio_i2c_obj_t *self = &i2c_obj; self->base.type = &busio_i2c_type; @@ -79,9 +78,8 @@ mp_obj_t common_hal_board_get_spi(void) { } mp_obj_t common_hal_board_create_spi(void) { - if (spi_singleton != NULL) { - return spi_singleton; - } + // All callers have either already verified this or come so early that it can't be otherwise. + assert(spi_singleton == NULL || common_hal_busio_spi_deinited(spi_singleton)); busio_spi_obj_t *self = &spi_obj; self->base.type = &busio_spi_type; -- cgit v1.2.3 From 0d1649880f1c23ec6c9c0a4834f3712a8495f9d8 Mon Sep 17 00:00:00 2001 From: Scott Shawcroft Date: Mon, 26 Oct 2020 16:58:00 -0700 Subject: Add grayscale EInk support --- shared-bindings/displayio/EPaperDisplay.c | 35 +++++++++++++++++++++++++------ shared-bindings/displayio/EPaperDisplay.h | 2 +- shared-module/displayio/ColorConverter.c | 9 ++++---- shared-module/displayio/EPaperDisplay.c | 15 ++++++++----- shared-module/displayio/EPaperDisplay.h | 1 + shared-module/displayio/Palette.h | 1 + shared-module/displayio/display_core.c | 1 + 7 files changed, 48 insertions(+), 16 deletions(-) (limited to 'shared-module') diff --git a/shared-bindings/displayio/EPaperDisplay.c b/shared-bindings/displayio/EPaperDisplay.c index 8be4ee4c4..e0326d9c8 100644 --- a/shared-bindings/displayio/EPaperDisplay.c +++ b/shared-bindings/displayio/EPaperDisplay.c @@ -49,7 +49,19 @@ //| Most people should not use this class directly. Use a specific display driver instead that will //| contain the startup and shutdown sequences at minimum.""" //| -//| def __init__(self, display_bus: _DisplayBus, start_sequence: ReadableBuffer, stop_sequence: ReadableBuffer, *, width: int, height: int, ram_width: int, ram_height: int, colstart: int = 0, rowstart: int = 0, rotation: int = 0, set_column_window_command: Optional[int] = None, set_row_window_command: Optional[int] = None, single_byte_bounds: bool = False, write_black_ram_command: int, black_bits_inverted: bool = False, write_color_ram_command: Optional[int] = None, color_bits_inverted: bool = False, highlight_color: int = 0x000000, refresh_display_command: int, refresh_time: float = 40, busy_pin: Optional[microcontroller.Pin] = None, busy_state: bool = True, seconds_per_frame: float = 180, always_toggle_chip_select: bool = False) -> None: +//| def __init__(self, display_bus: _DisplayBus, +//| start_sequence: ReadableBuffer, stop_sequence: ReadableBuffer, *, +//| width: int, height: int, ram_width: int, ram_height: int, +//| colstart: int = 0, rowstart: int = 0, rotation: int = 0, +//| set_column_window_command: Optional[int] = None, +//| set_row_window_command: Optional[int] = None, single_byte_bounds: bool = False, +//| write_black_ram_command: int, black_bits_inverted: bool = False, +//| write_color_ram_command: Optional[int] = None, +//| color_bits_inverted: bool = False, highlight_color: int = 0x000000, +//| refresh_display_command: int, refresh_time: float = 40, +//| busy_pin: Optional[microcontroller.Pin] = None, busy_state: bool = True, +//| seconds_per_frame: float = 180, always_toggle_chip_select: bool = False, +//| grayscale: bool = False) -> None: //| """Create a EPaperDisplay object on the given display bus (`displayio.FourWire` or `displayio.ParallelBus`). //| //| The ``start_sequence`` and ``stop_sequence`` are bitpacked to minimize the ram impact. Every @@ -84,11 +96,18 @@ //| :param microcontroller.Pin busy_pin: Pin used to signify the display is busy //| :param bool busy_state: State of the busy pin when the display is busy //| :param float seconds_per_frame: Minimum number of seconds between screen refreshes -//| :param bool always_toggle_chip_select: When True, chip select is toggled every byte""" +//| :param bool always_toggle_chip_select: When True, chip select is toggled every byte +//| :param bool grayscale: When true, the color ram is the low bit of 2-bit grayscale""" //| ... //| STATIC mp_obj_t displayio_epaperdisplay_make_new(const mp_obj_type_t *type, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { - enum { ARG_display_bus, ARG_start_sequence, ARG_stop_sequence, ARG_width, ARG_height, ARG_ram_width, ARG_ram_height, ARG_colstart, ARG_rowstart, ARG_rotation, ARG_set_column_window_command, ARG_set_row_window_command, ARG_set_current_column_command, ARG_set_current_row_command, ARG_write_black_ram_command, ARG_black_bits_inverted, ARG_write_color_ram_command, ARG_color_bits_inverted, ARG_highlight_color, ARG_refresh_display_command, ARG_refresh_time, ARG_busy_pin, ARG_busy_state, ARG_seconds_per_frame, ARG_always_toggle_chip_select }; + enum { ARG_display_bus, ARG_start_sequence, ARG_stop_sequence, ARG_width, ARG_height, + ARG_ram_width, ARG_ram_height, ARG_colstart, ARG_rowstart, ARG_rotation, + ARG_set_column_window_command, ARG_set_row_window_command, ARG_set_current_column_command, + ARG_set_current_row_command, ARG_write_black_ram_command, ARG_black_bits_inverted, + ARG_write_color_ram_command, ARG_color_bits_inverted, ARG_highlight_color, + ARG_refresh_display_command, ARG_refresh_time, ARG_busy_pin, ARG_busy_state, + ARG_seconds_per_frame, ARG_always_toggle_chip_select, ARG_grayscale }; static const mp_arg_t allowed_args[] = { { MP_QSTR_display_bus, MP_ARG_REQUIRED | MP_ARG_OBJ }, { MP_QSTR_start_sequence, MP_ARG_REQUIRED | MP_ARG_OBJ }, @@ -115,6 +134,7 @@ STATIC mp_obj_t displayio_epaperdisplay_make_new(const mp_obj_type_t *type, size { MP_QSTR_busy_state, MP_ARG_BOOL | MP_ARG_KW_ONLY, {.u_bool = true} }, { MP_QSTR_seconds_per_frame, MP_ARG_OBJ | MP_ARG_KW_ONLY, {.u_obj = MP_OBJ_NEW_SMALL_INT(180)} }, { MP_QSTR_always_toggle_chip_select, MP_ARG_BOOL | MP_ARG_KW_ONLY, {.u_bool = false} }, + { MP_QSTR_grayscale, MP_ARG_BOOL | MP_ARG_KW_ONLY, {.u_bool = false} }, }; mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); @@ -151,11 +171,14 @@ STATIC mp_obj_t displayio_epaperdisplay_make_new(const mp_obj_type_t *type, size self, display_bus, start_bufinfo.buf, start_bufinfo.len, stop_bufinfo.buf, stop_bufinfo.len, - args[ARG_width].u_int, args[ARG_height].u_int, args[ARG_ram_width].u_int, args[ARG_ram_height].u_int, args[ARG_colstart].u_int, args[ARG_rowstart].u_int, rotation, + args[ARG_width].u_int, args[ARG_height].u_int, args[ARG_ram_width].u_int, args[ARG_ram_height].u_int, + args[ARG_colstart].u_int, args[ARG_rowstart].u_int, rotation, args[ARG_set_column_window_command].u_int, args[ARG_set_row_window_command].u_int, args[ARG_set_current_column_command].u_int, args[ARG_set_current_row_command].u_int, - args[ARG_write_black_ram_command].u_int, args[ARG_black_bits_inverted].u_bool, write_color_ram_command, args[ARG_color_bits_inverted].u_bool, highlight_color, args[ARG_refresh_display_command].u_int, refresh_time, - busy_pin, args[ARG_busy_state].u_bool, seconds_per_frame, args[ARG_always_toggle_chip_select].u_bool + args[ARG_write_black_ram_command].u_int, args[ARG_black_bits_inverted].u_bool, write_color_ram_command, + args[ARG_color_bits_inverted].u_bool, highlight_color, args[ARG_refresh_display_command].u_int, refresh_time, + busy_pin, args[ARG_busy_state].u_bool, seconds_per_frame, + args[ARG_always_toggle_chip_select].u_bool, args[ARG_grayscale].u_bool ); return self; diff --git a/shared-bindings/displayio/EPaperDisplay.h b/shared-bindings/displayio/EPaperDisplay.h index e4b81c883..352de899a 100644 --- a/shared-bindings/displayio/EPaperDisplay.h +++ b/shared-bindings/displayio/EPaperDisplay.h @@ -44,7 +44,7 @@ void common_hal_displayio_epaperdisplay_construct(displayio_epaperdisplay_obj_t* uint16_t set_column_window_command, uint16_t set_row_window_command, uint16_t set_current_column_command, uint16_t set_current_row_command, uint16_t write_black_ram_command, bool black_bits_inverted, uint16_t write_color_ram_command, bool color_bits_inverted, uint32_t highlight_color, uint16_t refresh_display_command, mp_float_t refresh_time, - const mcu_pin_obj_t* busy_pin, bool busy_state, mp_float_t seconds_per_frame, bool always_toggle_chip_select); + const mcu_pin_obj_t* busy_pin, bool busy_state, mp_float_t seconds_per_frame, bool always_toggle_chip_select, bool grayscale); bool common_hal_displayio_epaperdisplay_refresh(displayio_epaperdisplay_obj_t* self); diff --git a/shared-module/displayio/ColorConverter.c b/shared-module/displayio/ColorConverter.c index dc64da03d..03ec99ceb 100644 --- a/shared-module/displayio/ColorConverter.c +++ b/shared-module/displayio/ColorConverter.c @@ -165,9 +165,9 @@ void displayio_colorconverter_convert(displayio_colorconverter_t *self, const _d g8 = MIN(255,g8 + (randg&0x03)); } else { int bitmask = 0xFF >> colorspace->depth; - b8 = MIN(255,b8 + (randb&bitmask)); - r8 = MIN(255,r8 + (randr&bitmask)); - g8 = MIN(255,g8 + (randg&bitmask)); + b8 = MIN(255,b8 + (randb & bitmask)); + r8 = MIN(255,r8 + (randr & bitmask)); + g8 = MIN(255,g8 + (randg & bitmask)); } pixel = r8 << 16 | g8 << 8 | b8; } @@ -196,7 +196,8 @@ void displayio_colorconverter_convert(displayio_colorconverter_t *self, const _d return; } else if (colorspace->grayscale && colorspace->depth <= 8) { uint8_t luma = displayio_colorconverter_compute_luma(pixel); - output_color->pixel = luma >> (8 - colorspace->depth); + size_t bitmask = (1 << colorspace->depth) - 1; + output_color->pixel = (luma >> colorspace->grayscale_bit) & bitmask; output_color->opaque = true; return; } diff --git a/shared-module/displayio/EPaperDisplay.c b/shared-module/displayio/EPaperDisplay.c index 46c7ea82e..514b99a13 100644 --- a/shared-module/displayio/EPaperDisplay.c +++ b/shared-module/displayio/EPaperDisplay.c @@ -49,7 +49,7 @@ void common_hal_displayio_epaperdisplay_construct(displayio_epaperdisplay_obj_t* uint16_t set_column_window_command, uint16_t set_row_window_command, uint16_t set_current_column_command, uint16_t set_current_row_command, uint16_t write_black_ram_command, bool black_bits_inverted, uint16_t write_color_ram_command, bool color_bits_inverted, uint32_t highlight_color, uint16_t refresh_display_command, mp_float_t refresh_time, - const mcu_pin_obj_t* busy_pin, bool busy_state, mp_float_t seconds_per_frame, bool chip_select) { + const mcu_pin_obj_t* busy_pin, bool busy_state, mp_float_t seconds_per_frame, bool chip_select, bool grayscale) { if (highlight_color != 0x000000) { self->core.colorspace.tricolor = true; self->core.colorspace.tricolor_hue = displayio_colorconverter_compute_hue(highlight_color); @@ -72,6 +72,7 @@ void common_hal_displayio_epaperdisplay_construct(displayio_epaperdisplay_obj_t* self->refreshing = false; self->milliseconds_per_frame = seconds_per_frame * 1000; self->chip_select = chip_select ? CHIP_SELECT_TOGGLE_EVERY_BYTE : CHIP_SELECT_UNTOUCHED; + self->grayscale = grayscale; self->start_sequence = start_sequence; self->start_sequence_len = start_sequence_len; @@ -230,17 +231,16 @@ bool displayio_epaperdisplay_refresh_area(displayio_epaperdisplay_obj_t* self, c uint32_t mask[mask_length]; uint8_t passes = 1; - if (self->core.colorspace.tricolor) { + if (self->core.colorspace.tricolor || self->grayscale) { passes = 2; } for (uint8_t pass = 0; pass < passes; pass++) { uint16_t remaining_rows = displayio_area_height(&clipped); - // added false parameter at end for SH1107_addressing quirk if (self->set_row_window_command != NO_COMMAND) { displayio_display_core_set_region_to_update(&self->core, self->set_column_window_command, self->set_row_window_command, self->set_current_column_command, self->set_current_row_command, - false, self->chip_select, &clipped, false); + false, self->chip_select, &clipped, false /* SH1107_addressing */); } uint8_t write_command = self->write_black_ram_command; @@ -270,8 +270,13 @@ bool displayio_epaperdisplay_refresh_area(displayio_epaperdisplay_obj_t* self, c memset(buffer, 0, buffer_size * sizeof(buffer[0])); self->core.colorspace.grayscale = true; + self->core.colorspace.grayscale_bit = 7; if (pass == 1) { - self->core.colorspace.grayscale = false; + if (self->grayscale) { // 4-color grayscale + self->core.colorspace.grayscale_bit = 6; + } else { // Tri-color + self->core.colorspace.grayscale = false; + } } displayio_display_core_fill_area(&self->core, &subrectangle, mask, buffer); diff --git a/shared-module/displayio/EPaperDisplay.h b/shared-module/displayio/EPaperDisplay.h index 3b9f6e368..4103fe5fc 100644 --- a/shared-module/displayio/EPaperDisplay.h +++ b/shared-module/displayio/EPaperDisplay.h @@ -55,6 +55,7 @@ typedef struct { bool black_bits_inverted; bool color_bits_inverted; bool refreshing; + bool grayscale; display_chip_select_behavior_t chip_select; } displayio_epaperdisplay_obj_t; diff --git a/shared-module/displayio/Palette.h b/shared-module/displayio/Palette.h index da72f250f..993912cc5 100644 --- a/shared-module/displayio/Palette.h +++ b/shared-module/displayio/Palette.h @@ -37,6 +37,7 @@ typedef struct { uint8_t bytes_per_cell; uint8_t tricolor_hue; uint8_t tricolor_luma; + uint8_t grayscale_bit; // The lowest grayscale bit. Normally 8 - depth. bool grayscale; bool tricolor; bool pixels_in_byte_share_row; diff --git a/shared-module/displayio/display_core.c b/shared-module/displayio/display_core.c index 411f9f373..57d33b565 100644 --- a/shared-module/displayio/display_core.c +++ b/shared-module/displayio/display_core.c @@ -48,6 +48,7 @@ void displayio_display_core_construct(displayio_display_core_t* self, uint16_t color_depth, bool grayscale, bool pixels_in_byte_share_row, uint8_t bytes_per_cell, bool reverse_pixels_in_byte, bool reverse_bytes_in_word) { self->colorspace.depth = color_depth; self->colorspace.grayscale = grayscale; + self->colorspace.grayscale_bit = 8 - color_depth; self->colorspace.pixels_in_byte_share_row = pixels_in_byte_share_row; self->colorspace.bytes_per_cell = bytes_per_cell; self->colorspace.reverse_pixels_in_byte = reverse_pixels_in_byte; -- cgit v1.2.3