mirror of
https://github.com/micropython/micropython.git
synced 2026-04-30 04:40:13 +02:00
022570445b
API is different to the original machine.CAN proposal, as numerous shortcomings were found during initial implementation. This work was funded through GitHub Sponsors. Signed-off-by: Angus Gratton <angus@redyak.com.au>
189 lines
6.8 KiB
C
189 lines
6.8 KiB
C
/*
|
|
* 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
|