|
HardFOC Core
API reference
|
C interface of the generic CANopenNode driver (CO_driver_hardfoc.c). More...
#include <stdbool.h>#include <stddef.h>#include <stdint.h>Go to the source code of this file.
Classes | |
| struct | hf_co_frame_t |
| struct | hf_co_port_status_t |
| struct | hf_co_port_ops_t |
| struct | hf_co_port_stats_t |
Macros | |
| #define | HF_CO_CAN_MAX_LEN 8U |
| #define | HF_CO_MAX_PORTS 4U |
| #define | HF_CO_RX_RING_LEN 64U |
| #define | HF_CO_MAX_DRIVERS 2U |
| #define | HF_CO_BUSOFF_RETRY_CALLS 100U |
| #define | HF_CO_FRAME_MAX_LEN 64U |
| #define | HF_CO_FRAME_EXT 0x01U |
| #define | HF_CO_FRAME_RTR 0x02U |
| #define | HF_CO_FRAME_FDF 0x04U |
| #define | HF_CO_FRAME_BRS 0x08U |
| #define | HF_CO_FRAME_ESI 0x10U |
| #define | HF_CO_PORT_ERROR_SOURCE 0x01U |
Typedefs | |
| typedef bool(* | hf_co_rx_policy_fn) (void *ctx, uint8_t port, uint16_t rx_index, const void *consumer, const hf_co_frame_t *frame) |
| typedef bool(* | hf_co_tx_policy_fn) (void *ctx, uint8_t port, uint16_t tx_index, const hf_co_frame_t *frame) |
| typedef void(* | hf_co_wake_fn) (void *ctx) |
Enumerations | |
| enum | hf_co_tx_result_t { HF_CO_TX_OK = 0 , HF_CO_TX_QUEUE_FULL = 1 , HF_CO_TX_BUS_OFF = 2 , HF_CO_TX_NOT_ALLOWED = 3 } |
| enum | hf_co_bus_state_t { HF_CO_BUS_STOPPED = 0 , HF_CO_BUS_ERROR_ACTIVE = 1 , HF_CO_BUS_ERROR_WARNING = 2 , HF_CO_BUS_ERROR_PASSIVE = 3 , HF_CO_BUS_OFF = 4 } |
Functions | |
| hf_co_driver_t * | hf_co_driver_acquire (void) |
| void | hf_co_driver_release (hf_co_driver_t *drv) |
| bool | hf_co_driver_attach_port (hf_co_driver_t *drv, uint8_t index, const hf_co_port_ops_t *ops, void *ctx, uint8_t max_len, uint8_t flags) |
| void | hf_co_driver_detach_port (hf_co_driver_t *drv, uint8_t index) |
| void | hf_co_driver_set_policy (hf_co_driver_t *drv, hf_co_rx_policy_fn rx, hf_co_tx_policy_fn tx, void *ctx) |
| void | hf_co_driver_set_wake (hf_co_driver_t *drv, hf_co_wake_fn wake, void *ctx) |
| bool | hf_co_driver_rx_push (hf_co_driver_t *drv, uint8_t port, const hf_co_frame_t *frame) |
| bool | hf_co_driver_rx_offer (hf_co_driver_t *drv, uint8_t port, const hf_co_frame_t *frame) |
| void | hf_co_driver_tx_done (hf_co_driver_t *drv, uint8_t port) |
| uint32_t | hf_co_driver_rx_drain (hf_co_driver_t *drv, uint32_t max) |
| uint32_t | hf_co_driver_rx_pending (const hf_co_driver_t *drv) |
| uint32_t | hf_co_driver_tx_pending (const hf_co_driver_t *drv) |
| void | hf_co_driver_get_stats (const hf_co_driver_t *drv, uint8_t port, hf_co_port_stats_t *out) |
C interface of the generic CANopenNode driver (CO_driver_hardfoc.c).
One CANopenNode CO_CANmodule_t fans out to up to HF_CO_MAX_PORTS CAN ports. A port is any transport that can send a frame without blocking and report received frames: the TWAI controller (EspTwaiPort), SocketCAN (LinuxSocketCanPort), the host pipe bus (PipePort), later FDCAN and the wireless tunnels. C++ ports implement hf::can::ICanPort (HfCanPort.h) and are attached with hf::can::CoPortBinding (HfCoPortBinding.h); this header is the C seam underneath.
Threading contract:
hf_co_driver_rx_push() and hf_co_driver_tx_done() are ISR-safe and lock-free. Each port has its own single-producer ring, so one port must push from one context (its ISR or its reader thread).CO_CANmodule_process() (called by CO_process()) or from hf_co_driver_rx_drain(), in thread context. CANopenNode's RX callbacks therefore never run in an ISR.CO_CANsend() hands the frame to every port inside the stack's CAN-send lock. Port send callbacks must not block. A port that answers "queue full" keeps the frame pending in its CANopenNode buffer; it is re-sent in buffer (priority) order from CO_CANmodule_process(), which the port can request at once with hf_co_driver_tx_done().Error status: CO_CANmodule_process() reads every port attached with HF_CO_PORT_ERROR_SOURCE and maps TEC/REC/bus-off and RX overruns to the CO_CAN_ERR* bits that CO_Emergency turns into EMCY messages. A bus-off port gets its recover callback (for EspCan: RequestBusRecovery()), repeated every HF_CO_BUSOFF_RETRY_CALLS process calls while it stays bus-off.
SPDX-License-Identifier: GPL-3.0-or-later
| #define HF_CO_BUSOFF_RETRY_CALLS 100U |
CO_CANmodule_process() calls between bus-off recovery requests while a port stays bus-off.
| #define HF_CO_CAN_MAX_LEN 8U |
Largest payload CANopenNode buffers carry: 8 on classic builds, 64 with HF_CO_CAN_FD.
| #define HF_CO_FRAME_BRS 0x08U |
bit-rate switch
| #define HF_CO_FRAME_ESI 0x10U |
error state indicator
| #define HF_CO_FRAME_EXT 0x01U |
hf_co_frame_t::flags bits. Same values as hf::can::frame_flag and vortex::contracts::frame_flag. 29-bit identifier
| #define HF_CO_FRAME_FDF 0x04U |
FD frame format
| #define HF_CO_FRAME_MAX_LEN 64U |
Largest payload of any frame (CAN FD).
| #define HF_CO_FRAME_RTR 0x02U |
remote request
| #define HF_CO_MAX_DRIVERS 2U |
Driver instances available from hf_co_driver_acquire() (static pool, no heap).
| #define HF_CO_MAX_PORTS 4U |
Ports one CANmodule can fan out to.
| #define HF_CO_PORT_ERROR_SOURCE 0x01U |
The port is a physical bus: its counters drive CANerrorStatus (warning/passive/bus-off).
| #define HF_CO_RX_RING_LEN 64U |
Frames each port's RX ring holds (power of two).
| typedef bool(* hf_co_rx_policy_fn) (void *ctx, uint8_t port, uint16_t rx_index, const void *consumer, const hf_co_frame_t *frame) |
RX policy: may frame from port reach the consumer in CANopenNode RX buffer rx_index (whose object is consumer)? Thread context.
| typedef bool(* hf_co_tx_policy_fn) (void *ctx, uint8_t port, uint16_t tx_index, const hf_co_frame_t *frame) |
TX policy: may frame from CANopenNode TX buffer tx_index leave on port? Called with the CO CAN-send lock held: decide, do not block.
| typedef void(* hf_co_wake_fn) (void *ctx) |
Wake the thread that calls CO_process(). Must be ISR-safe.
| enum hf_co_bus_state_t |
Controller error state. Same order as hf::can::BusState.
| Enumerator | |
|---|---|
| HF_CO_BUS_STOPPED | |
| HF_CO_BUS_ERROR_ACTIVE | |
| HF_CO_BUS_ERROR_WARNING | |
| HF_CO_BUS_ERROR_PASSIVE | |
| HF_CO_BUS_OFF | |
| enum hf_co_tx_result_t |
Result of a non-blocking port send. Same order as hf::can::TxResult.
| hf_co_driver_t * hf_co_driver_acquire | ( | void | ) |
Take a driver instance from the static pool (NULL when all are in use).
| bool hf_co_driver_attach_port | ( | hf_co_driver_t * | drv, |
| uint8_t | index, | ||
| const hf_co_port_ops_t * | ops, | ||
| void * | ctx, | ||
| uint8_t | max_len, | ||
| uint8_t | flags | ||
| ) |
Attach a port at index.
| max_len | largest payload the port carries (8 classic, 64 FD) |
| flags | HF_CO_PORT_* bits |
| void hf_co_driver_detach_port | ( | hf_co_driver_t * | drv, |
| uint8_t | index | ||
| ) |
Detach the port at index. Its pending TX frames are dropped.
| void hf_co_driver_get_stats | ( | const hf_co_driver_t * | drv, |
| uint8_t | port, | ||
| hf_co_port_stats_t * | out | ||
| ) |
Copy the statistics of port.
| void hf_co_driver_release | ( | hf_co_driver_t * | drv | ) |
Return drv to the pool. Detach the ports and stop calling CO first.
| uint32_t hf_co_driver_rx_drain | ( | hf_co_driver_t * | drv, |
| uint32_t | max | ||
| ) |
Dispatch up to max queued RX frames to CANopenNode (0 = all queued). Thread context. CO_CANmodule_process() calls this; call it directly to drain earlier (for example from an RT thread before CO_process_SYNC).
| bool hf_co_driver_rx_offer | ( | hf_co_driver_t * | drv, |
| uint8_t | port, | ||
| const hf_co_frame_t * | frame | ||
| ) |
Like hf_co_driver_rx_push(), for ports that apply back-pressure: a full ring returns false without counting an overrun, and the port offers the frame again later.
| uint32_t hf_co_driver_rx_pending | ( | const hf_co_driver_t * | drv | ) |
Frames waiting in the RX rings.
| bool hf_co_driver_rx_push | ( | hf_co_driver_t * | drv, |
| uint8_t | port, | ||
| const hf_co_frame_t * | frame | ||
| ) |
Store a received frame for dispatch. ISR-safe, lock-free, single producer per port. Frames longer than HF_CO_CAN_MAX_LEN are rejected (counted).
| void hf_co_driver_set_policy | ( | hf_co_driver_t * | drv, |
| hf_co_rx_policy_fn | rx, | ||
| hf_co_tx_policy_fn | tx, | ||
| void * | ctx | ||
| ) |
Install the router policy (either function may be NULL = allow).
| void hf_co_driver_set_wake | ( | hf_co_driver_t * | drv, |
| hf_co_wake_fn | wake, | ||
| void * | ctx | ||
| ) |
Install the wake hook called after every RX push and TX-done.
| void hf_co_driver_tx_done | ( | hf_co_driver_t * | drv, |
| uint8_t | port | ||
| ) |
The port has room again (TX-done). ISR-safe: marks the retry and wakes.
| uint32_t hf_co_driver_tx_pending | ( | const hf_co_driver_t * | drv | ) |
CANopenNode TX buffers still pending on at least one port.