HardFOC Core
API reference
Loading...
Searching...
No Matches
Classes | Macros | Typedefs | Enumerations | Functions
hf_co_driver.h File 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)
 

Detailed Description

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:

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

Macro Definition Documentation

◆ HF_CO_BUSOFF_RETRY_CALLS

#define HF_CO_BUSOFF_RETRY_CALLS   100U

CO_CANmodule_process() calls between bus-off recovery requests while a port stays bus-off.

◆ HF_CO_CAN_MAX_LEN

#define HF_CO_CAN_MAX_LEN   8U

Largest payload CANopenNode buffers carry: 8 on classic builds, 64 with HF_CO_CAN_FD.

◆ HF_CO_FRAME_BRS

#define HF_CO_FRAME_BRS   0x08U

bit-rate switch

◆ HF_CO_FRAME_ESI

#define HF_CO_FRAME_ESI   0x10U

error state indicator

◆ HF_CO_FRAME_EXT

#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

◆ HF_CO_FRAME_FDF

#define HF_CO_FRAME_FDF   0x04U

FD frame format

◆ HF_CO_FRAME_MAX_LEN

#define HF_CO_FRAME_MAX_LEN   64U

Largest payload of any frame (CAN FD).

◆ HF_CO_FRAME_RTR

#define HF_CO_FRAME_RTR   0x02U

remote request

◆ HF_CO_MAX_DRIVERS

#define HF_CO_MAX_DRIVERS   2U

Driver instances available from hf_co_driver_acquire() (static pool, no heap).

◆ HF_CO_MAX_PORTS

#define HF_CO_MAX_PORTS   4U

Ports one CANmodule can fan out to.

◆ HF_CO_PORT_ERROR_SOURCE

#define HF_CO_PORT_ERROR_SOURCE   0x01U

The port is a physical bus: its counters drive CANerrorStatus (warning/passive/bus-off).

◆ HF_CO_RX_RING_LEN

#define HF_CO_RX_RING_LEN   64U

Frames each port's RX ring holds (power of two).

Typedef Documentation

◆ hf_co_rx_policy_fn

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.

◆ hf_co_tx_policy_fn

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.

◆ hf_co_wake_fn

typedef void(* hf_co_wake_fn) (void *ctx)

Wake the thread that calls CO_process(). Must be ISR-safe.

Enumeration Type Documentation

◆ 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 

◆ hf_co_tx_result_t

Result of a non-blocking port send. Same order as hf::can::TxResult.

Enumerator
HF_CO_TX_OK 

queued for transmission

HF_CO_TX_QUEUE_FULL 

no room now; the frame stays pending and is retried

HF_CO_TX_BUS_OFF 

controller bus-off; the frame is dropped for this port

HF_CO_TX_NOT_ALLOWED 

the port cannot carry this frame; dropped for this port

Function Documentation

◆ hf_co_driver_acquire()

hf_co_driver_t * hf_co_driver_acquire ( void  )

Take a driver instance from the static pool (NULL when all are in use).

◆ hf_co_driver_attach_port()

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.

Parameters
max_lenlargest payload the port carries (8 classic, 64 FD)
flagsHF_CO_PORT_* bits
Returns
false on a bad argument or an occupied index

◆ hf_co_driver_detach_port()

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.

◆ hf_co_driver_get_stats()

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.

◆ hf_co_driver_release()

void hf_co_driver_release ( hf_co_driver_t *  drv)

Return drv to the pool. Detach the ports and stop calling CO first.

◆ hf_co_driver_rx_drain()

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).

Returns
frames taken from the rings

◆ hf_co_driver_rx_offer()

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.

◆ hf_co_driver_rx_pending()

uint32_t hf_co_driver_rx_pending ( const hf_co_driver_t *  drv)

Frames waiting in the RX rings.

◆ hf_co_driver_rx_push()

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).

Returns
false if the frame was dropped

◆ hf_co_driver_set_policy()

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).

◆ hf_co_driver_set_wake()

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.

◆ hf_co_driver_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.

◆ hf_co_driver_tx_pending()

uint32_t hf_co_driver_tx_pending ( const hf_co_driver_t *  drv)

CANopenNode TX buffers still pending on at least one port.