/* * This file is part of the MicroPython project, http://micropython.org/ * * The MIT License (MIT) * * Copyright (c) 2024-2026 Angus Gratton * * 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. */ #ifndef MICROPY_INCLUDED_EXTMOD_MACHINE_CAN_PORT_H #define MICROPY_INCLUDED_EXTMOD_MACHINE_CAN_PORT_H #include "py/obj.h" #include "py/objarray.h" #include "py/runtime.h" #include "shared/runtime/mpirq.h" // This header is included into both extmod/machine_can.c and port-specific // machine_can.c implementations and provides shared (static) function // declarations to both. // // In a MicroPython build including this header from port-specific machine_can.c // include is a no-op (as the file is included directly into // extmod/machine_can.c). However, including it anyway means that Language // Servers and IDEs can correctly analyse the machine_can.c file while the // developer is writing it. typedef enum { MP_CAN_STATE_STOPPED, MP_CAN_STATE_ACTIVE, MP_CAN_STATE_WARNING, MP_CAN_STATE_PASSIVE, MP_CAN_STATE_BUS_OFF, } machine_can_state_t; typedef enum { MP_CAN_MODE_NORMAL, MP_CAN_MODE_SLEEP, MP_CAN_MODE_LOOPBACK, MP_CAN_MODE_SILENT, MP_CAN_MODE_SILENT_LOOPBACK, MP_CAN_MODE_MAX, } machine_can_mode_t; // CAN IRQ Flags // (currently the same for all ports) #define MP_CAN_IRQ_TX (1 << 0) #define MP_CAN_IRQ_RX (1 << 1) #define MP_CAN_IRQ_TX_FAILED (1 << 2) #define MP_CAN_IRQ_STATE (1 << 3) // Transmit buffer index is encoded into the irq().flags() response for MP_CAN_IRQ_TX #define MP_CAN_IRQ_IDX_SHIFT 16 #define MP_CAN_IRQ_IDX_MASK 0xFF #if MICROPY_HW_ENABLE_FDCAN #define MP_CAN_MAX_LEN 64 #else #define MP_CAN_MAX_LEN 8 #endif struct machine_can_port; // These values appear in the same order as the result of CAN.get_counters() typedef struct { mp_uint_t tec; mp_uint_t rec; mp_uint_t num_warning; // Number of "Error Warning" transitions mp_uint_t num_passive; // Number of "Error Passive" transitions mp_uint_t num_bus_off; // Number of "Bus-Off" transitions mp_uint_t tx_pending; mp_uint_t rx_pending; mp_uint_t rx_overruns; } machine_can_counters_t; typedef struct _machine_can_obj_t { mp_obj_base_t base; mp_uint_t can_idx; // Timing register settings byte tseg1; byte tseg2; byte brp; byte sjw; machine_can_mode_t mode; mp_irq_obj_t *mp_irq_obj; uint16_t mp_irq_trigger; mp_uint_t rx_error_flags; // Assumed some of these counters are updated from different port ISRs, etc. and some // are updated by calling machine_can_port_update_counters() machine_can_counters_t counters; struct machine_can_port *port; } machine_can_obj_t; // Indexes for recv result list typedef enum { RECV_ARG_ID, RECV_ARG_DATA, RECV_ARG_FLAGS, RECV_ARG_ERRORS, RECV_ARG_LEN, // Overall length, not an index } recv_arg_idx_t; #define CAN_STD_ID_MASK 0x7FF #define CAN_EXT_ID_MASK 0x1fffffff // CAN Message Flags #define CAN_MSG_FLAG_RTR (1 << 0) #define CAN_MSG_FLAG_EXT_ID (1 << 1) #define CAN_MSG_FLAG_FD_F (1 << 2) #define CAN_MSG_FLAG_BRS (1 << 3) #define CAN_MSG_FLAG_UNORDERED (1 << 4) // CAN recv() Error Flags #define CAN_RECV_ERR_FULL (1 << 0) #define CAN_RECV_ERR_OVERRUN (1 << 1) #define CAN_RECV_ERR_ESI (1 << 2) // The port must provide implementations of these low-level CAN functions static int machine_can_port_f_clock(const machine_can_obj_t *self); static bool machine_can_port_supports_mode(const machine_can_obj_t *self, machine_can_mode_t mode); static void machine_can_port_clear_filters(machine_can_obj_t *self); static mp_uint_t machine_can_port_max_data_len(mp_uint_t flags); // The extmod layer calls this function in a loop with incrementing filter_idx // values. It's up to the port how to apply the filters from here, and to raise // an exception if there are too many. // // If the CAN_FILTERS_STD_EXT_SEPARATE flag is set to 1, filter_idx will // enumerate standard id filters separately to extended id filters (the // CAN_MSG_FLAG_EXT_ID bit in 'flags' differentiates the type). static void machine_can_port_set_filter(machine_can_obj_t *self, int filter_idx, mp_uint_t can_id, mp_uint_t mask, mp_uint_t flags); // Update interrupt configuration based on the new contents of 'self' static void machine_can_update_irqs(machine_can_obj_t *self); // Return the irq().flags() result. Calling this function may also update the hardware state machine. static mp_uint_t machine_can_port_irq_flags(machine_can_obj_t *self); static void machine_can_port_init(machine_can_obj_t *self); static void machine_can_port_deinit(machine_can_obj_t *self); static mp_int_t machine_can_port_send(machine_can_obj_t *self, mp_uint_t id, const byte *data, size_t data_len, mp_uint_t flags); static bool machine_can_port_cancel_send(machine_can_obj_t *self, mp_uint_t idx); static bool machine_can_port_recv(machine_can_obj_t *self, void *data, size_t *dlen, mp_uint_t *id, mp_uint_t *flags, mp_uint_t *errors); static machine_can_state_t machine_can_port_get_state(machine_can_obj_t *self); static void machine_can_port_restart(machine_can_obj_t *self); // Updates values in self->counters (which counters are updated by this function versus from ISRs and the like // is port specific static void machine_can_port_update_counters(machine_can_obj_t *self); // Hook for port to fill in the final item of the get_timings() result list with controller-specific values static mp_obj_t machine_can_port_get_additional_timings(machine_can_obj_t *self, mp_obj_t optional_arg); // This function is only optionally defined by the port. If macro CAN_PORT_PRINT_FUNCTION is not set // then a default machine_can_print function will be used. static void machine_can_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind); #endif // MICROPY_INCLUDED_EXTMOD_MACHINE_CAN_PORT_H