CAN CoreX 2.3.1
Table-driven CAN, CAN FD, ISO-TP, network simulation, and bus monitoring library
Loading...
Searching...
No Matches
can_corex.h
Go to the documentation of this file.
1/*
2 * This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
5 *
6 * Author: Adrian Pietrzak
7 * GitHub: https://github.com/AdrianPietrzak1998
8 * Created: Aug 20, 2025
9 */
10
11#ifndef CAN_COREX_CAN_COREX_H_
12#define CAN_COREX_CAN_COREX_H_
13
14#include <limits.h>
15#include <stdint.h>
16
17#ifdef __cplusplus
18extern "C"
19{
20#endif
21
22#define CCX_VERSION_MAJOR 2
23#define CCX_VERSION_MINOR 3
24#define CCX_VERSION_PATCH 1
25#define CCX_VERSION_STRING "2.3.1"
26
36
45#ifndef CCX_TICK_FROM_FUNC
46#define CCX_TICK_FROM_FUNC 0
47#endif
48
55#ifndef CCX_HR_TICK_FROM_FUNC
56#define CCX_HR_TICK_FROM_FUNC 0
57#endif
58
65#ifndef CCX_RX_BUFFER_SIZE
66#define CCX_RX_BUFFER_SIZE 48
67#endif
68
75#ifndef CCX_TX_BUFFER_SIZE
76#define CCX_TX_BUFFER_SIZE 48
77#endif
78
86#if defined(DOXYGEN)
87#define CCX_ENABLE_CANFD 1
88#elif !defined(CCX_ENABLE_CANFD)
89#define CCX_ENABLE_CANFD 0
90#endif
91
109#if CCX_ENABLE_CANFD
110#define CCX_DLC_ANY 16
111#else
112#define CCX_DLC_ANY 15
113#endif
114
123#ifndef CCX_RX_HASH_SIZE
124#define CCX_RX_HASH_SIZE 64
125#endif
126
127 /* ============================================================
128 * Time base type configuration
129 *
130 * Primary time base:
131 * - used by core CAN RX/TX logic
132 * - expressed by CCX_TIME_t / CCX_MAX_TIMEOUT
133 * - public unit is always milliseconds
134 *
135 * High-resolution time base:
136 * - used by HR-aware modules such as ISO-TP and bus monitor
137 * - expressed by CCX_HR_TIME_t / CCX_HR_MAX_TIMEOUT
138 * - public unit is microseconds when HR is enabled
139 * - public unit falls back to milliseconds when HR is disabled
140 *
141 * Configuration is width-based and unsigned only.
142 * Signed tick types are intentionally not supported because the library relies
143 * on wraparound subtraction for timeout arithmetic.
144 *
145 * If no custom width macro is defined, uint32_t is used by default.
146 * ============================================================ */
147
148#ifdef CCX_TIME_BASE_TYPE_CUSTOM
149#error \
150 "CCX_TIME_BASE_TYPE_CUSTOM is no longer supported. Define exactly one of CCX_TIME_BASE_TYPE_CUSTOM_IS_UINT8/16/32/64."
151#endif
152
153#ifdef CCX_HR_TIME_BASE_TYPE_CUSTOM
154#error \
155 "CCX_HR_TIME_BASE_TYPE_CUSTOM is no longer supported. Define exactly one of CCX_HR_TIME_BASE_TYPE_CUSTOM_IS_UINT8/16/32/64."
156#endif
157
158#if defined(CCX_TIME_BASE_TYPE_CUSTOM_IS_INT8) || defined(CCX_TIME_BASE_TYPE_CUSTOM_IS_INT16) || \
159 defined(CCX_TIME_BASE_TYPE_CUSTOM_IS_INT32) || defined(CCX_TIME_BASE_TYPE_CUSTOM_IS_INT64)
160#error \
161 "Signed primary time base types were a bug and must not be used. Use exactly one of CCX_TIME_BASE_TYPE_CUSTOM_IS_UINT16/32/64."
162#endif
163
164#if defined(CCX_HR_TIME_BASE_TYPE_CUSTOM_IS_INT8) || defined(CCX_HR_TIME_BASE_TYPE_CUSTOM_IS_INT16) || \
165 defined(CCX_HR_TIME_BASE_TYPE_CUSTOM_IS_INT32) || defined(CCX_HR_TIME_BASE_TYPE_CUSTOM_IS_INT64)
166#error \
167 "Signed high-resolution time base types were a bug and must not be used. Use exactly one of CCX_HR_TIME_BASE_TYPE_CUSTOM_IS_UINT16/32/64."
168#endif
169
170#if defined(CCX_TIME_BASE_TYPE_CUSTOM_IS_UINT8)
171#error \
172 "CCX_TIME_BASE_TYPE_CUSTOM_IS_UINT8 is not supported because uint8_t has too small a range for this library. Use exactly one of CCX_TIME_BASE_TYPE_CUSTOM_IS_UINT16/32/64."
173 typedef volatile uint16_t CCX_TIME_t;
174#define CCX_TIME_BASE_SCALAR uint16_t
175#define CCX_MAX_TIMEOUT UINT16_MAX
176#elif defined(CCX_TIME_BASE_TYPE_CUSTOM_IS_UINT16)
177typedef volatile uint16_t CCX_TIME_t;
178#define CCX_TIME_BASE_SCALAR uint16_t
179#define CCX_MAX_TIMEOUT UINT16_MAX
180#elif defined(CCX_TIME_BASE_TYPE_CUSTOM_IS_UINT32)
181typedef volatile uint32_t CCX_TIME_t;
182#define CCX_TIME_BASE_SCALAR uint32_t
183#define CCX_MAX_TIMEOUT UINT32_MAX
184#elif defined(CCX_TIME_BASE_TYPE_CUSTOM_IS_UINT64)
185typedef volatile uint64_t CCX_TIME_t;
186#define CCX_TIME_BASE_SCALAR uint64_t
187#define CCX_MAX_TIMEOUT UINT64_MAX
188#else
189typedef volatile uint32_t CCX_TIME_t;
190#define CCX_TIME_BASE_SCALAR uint32_t
191#define CCX_MAX_TIMEOUT UINT32_MAX
192#endif
193
194#ifndef CCX_DISABLE_HIGH_RES_TIMEBASE
195
196#if defined(CCX_HR_TIME_BASE_TYPE_CUSTOM_IS_UINT8)
197#error \
198 "CCX_HR_TIME_BASE_TYPE_CUSTOM_IS_UINT8 is not supported because uint8_t has too small a range for this library. Use exactly one of CCX_HR_TIME_BASE_TYPE_CUSTOM_IS_UINT16/32/64."
199 typedef volatile uint16_t CCX_HR_TIME_t;
200#define CCX_HR_TIME_BASE_SCALAR uint16_t
201#define CCX_HR_MAX_TIMEOUT UINT16_MAX
202#elif defined(CCX_HR_TIME_BASE_TYPE_CUSTOM_IS_UINT16)
203 typedef volatile uint16_t CCX_HR_TIME_t;
204#define CCX_HR_TIME_BASE_SCALAR uint16_t
205#define CCX_HR_MAX_TIMEOUT UINT16_MAX
206#elif defined(CCX_HR_TIME_BASE_TYPE_CUSTOM_IS_UINT32)
207 typedef volatile uint32_t CCX_HR_TIME_t;
208#define CCX_HR_TIME_BASE_SCALAR uint32_t
209#define CCX_HR_MAX_TIMEOUT UINT32_MAX
210#elif defined(CCX_HR_TIME_BASE_TYPE_CUSTOM_IS_UINT64)
211 typedef volatile uint64_t CCX_HR_TIME_t;
212#define CCX_HR_TIME_BASE_SCALAR uint64_t
213#define CCX_HR_MAX_TIMEOUT UINT64_MAX
214#else
215 typedef volatile uint16_t CCX_HR_TIME_t;
216#define CCX_HR_TIME_BASE_SCALAR uint16_t
217#define CCX_HR_MAX_TIMEOUT UINT16_MAX
218#endif
219
220#else
221
222typedef CCX_TIME_t CCX_HR_TIME_t;
223#define CCX_HR_TIME_BASE_SCALAR CCX_TIME_BASE_SCALAR
224#define CCX_HR_MAX_TIMEOUT CCX_MAX_TIMEOUT
225
226#endif
227
228#define CCX_INTERNAL_MS_FROM_US_CEIL(us) (((us) == 0U) ? 0U : (((us)-1U) / 1000U) + 1U)
229
230#ifdef CCX_DISABLE_HIGH_RES_TIMEBASE
231#define CCX_HR_TIME(us) ((CCX_HR_TIME_t)CCX_INTERNAL_MS_FROM_US_CEIL(us))
232#else
233#define CCX_HR_TIME(us) ((CCX_HR_TIME_t)(us))
234#endif
235
246 typedef enum
247 {
248 CCX_BUS_BUSY = 0,
249 CCX_BUS_FREE
251
255 typedef enum
256 {
259 } CCX_ide_t;
260
261#if CCX_ENABLE_CANFD
281#endif
282
310
311 typedef enum
312 {
313 CCX_MSG_UNREG,
314 CCX_MSG_REG
315 } CCX_MsgRegStatus_t;
316
317 typedef enum
318 {
319 CCX_OK = 0,
320 CCX_NULL_PTR,
321 CCX_WRONG_ARG,
322 CCX_BUS_TOO_BUSY,
323 CCX_MISSING_TIMEBASE
324 } CCX_Status_t;
325
335 typedef struct
336 {
337 uint32_t ID;
338#if CCX_ENABLE_CANFD
339 uint8_t Data[64];
340#else
341 uint8_t Data[8];
342#endif
343 uint8_t DLC : 4;
344 uint8_t IDE_flag : 1; /* use CCX_ide_t values */
345#if CCX_ENABLE_CANFD
346 uint8_t FrameFormat : 2; /* use CCX_frame_format_t values */
347 uint8_t ESI : 1; /* error state indicator (set by RX hardware) */
348#endif
350
351 typedef struct CCX_instance_t CCX_instance_t;
352
353#include "can_corex_bus.h"
354
389 typedef struct
390 {
391 uint32_t ID;
392#if CCX_ENABLE_CANFD
393 uint8_t DLC : 5; /* 0-15 = exact FD DLC; 16 (CCX_DLC_ANY) = wildcard */
394 uint8_t IDE_flag : 1; /* use CCX_ide_t values */
395 uint8_t FrameFormat : 2; /* CLASSIC→match classic frames; FD/FD_BRS→match FD frames */
396#else
397 uint8_t DLC : 4;
398 uint8_t IDE_flag : 1; /* use CCX_ide_t values */
399#endif
400 void *UserData;
401 CCX_TIME_t TimeOut;
402 void (*Parser)(const CCX_instance_t *Instance, CCX_message_t *Msg, uint16_t Slot, void *UserData);
403 void (*TimeoutCallback)(CCX_instance_t *Instance, uint16_t Slot, void *UserData);
404 CCX_TIME_t LastTick;
406
444 typedef struct
445 {
446 uint32_t ID;
447 uint8_t *Data;
448 uint8_t DLC : 4;
449 uint8_t IDE_flag : 1; /* use CCX_ide_t values */
450#if CCX_ENABLE_CANFD
451 uint8_t FrameFormat : 2; /* use CCX_frame_format_t values */
452#endif
453 void *UserData;
454 CCX_TIME_t SendFreq;
455 void (*Parser)(const CCX_instance_t *Instance, uint8_t *DataToSend, uint16_t Slot, void *UserData);
456 CCX_TIME_t LastTick;
458
460 {
461
462 void (*SendFunction)(const CCX_instance_t *Instance, const CCX_message_t *msg);
463 CCX_BusIsFree_t (*BusCheck)(const CCX_instance_t *Instance);
464
467 volatile uint16_t RxTail, RxHead, TxTail, TxHead;
468 CCX_TIME_t RxReceivedTick[CCX_RX_BUFFER_SIZE];
469
470 CCX_RX_table_t *CCX_RX_table;
471 CCX_TX_table_t *CCX_TX_table;
472 uint16_t RxTableSize, TxTableSize;
473 void (*Parser_unreg_msg)(const CCX_instance_t *Instance, CCX_message_t *Msg);
474
475 /* New fields for v1.3.0 - added at the end for compatibility */
479 CCX_instance_t *Instance,
480 const CCX_message_t *msg);
481
482#if defined(CCX_RX_SEARCH_HASH)
483 uint16_t RxHashTable[CCX_RX_HASH_SIZE];
484#endif
485 };
486
487 CCX_Status_t CCX_RX_PushMsg(CCX_instance_t *Instance, const CCX_message_t *msg);
488 CCX_Status_t CCX_TX_PushMsg(CCX_instance_t *Instance, const CCX_message_t *msg);
489 uint16_t CCX_RX_GetDepth(const CCX_instance_t *Instance);
490 uint16_t CCX_TX_GetDepth(const CCX_instance_t *Instance);
491 uint16_t CCX_RX_GetFree(const CCX_instance_t *Instance);
492 uint16_t CCX_TX_GetFree(const CCX_instance_t *Instance);
493 void CCX_FlushRx(CCX_instance_t *Instance);
494 void CCX_FlushTx(CCX_instance_t *Instance);
495 void CCX_Flush(CCX_instance_t *Instance);
496 void CCX_Reset(CCX_instance_t *Instance);
497 CCX_Status_t CCX_Poll(CCX_instance_t *Instance);
498 CCX_Status_t CCX_Init(CCX_instance_t *Instance, CCX_RX_table_t *CCX_RX_table, CCX_TX_table_t *CCX_TX_table,
499 uint16_t RxTableSize, uint16_t TxTableSize,
500 void (*SendFunction)(const CCX_instance_t *Instance, const CCX_message_t *msg),
501 CCX_BusIsFree_t (*BusCheck)(const CCX_instance_t *Instance),
502 void (*ParserUnregMsg)(const CCX_instance_t *Instance, CCX_message_t *Msg));
503
504#if CCX_TICK_FROM_FUNC
513 void CCX_tick_function_register(CCX_TIME_BASE_SCALAR (*Function)(void));
514#else
523void CCX_tick_variable_register(CCX_TIME_t *Variable);
524#endif
525
526#ifndef CCX_DISABLE_HIGH_RES_TIMEBASE
527#if CCX_HR_TICK_FROM_FUNC
528 void CCX_high_res_tick_function_register(CCX_HR_TIME_BASE_SCALAR (*Function)(void));
529#else
530 void CCX_high_res_tick_variable_register(CCX_HR_TIME_t *Variable);
531#endif
532#endif
533
534 uint8_t CCX_IsPrimaryTickRegistered(void);
535 uint8_t CCX_IsHighResTickRegistered(void);
536
537#if CCX_TICK_FROM_FUNC
538 extern CCX_TIME_BASE_SCALAR (*CCX_get_tick)(void);
539#define CCX_GetPrimaryTick() ((CCX_get_tick != NULL) ? (CCX_TIME_t)CCX_get_tick() : ((CCX_TIME_t)0))
540#else
541extern CCX_TIME_t *CCX_tick;
542#define CCX_GetPrimaryTick() ((CCX_tick != NULL) ? (*CCX_tick) : ((CCX_TIME_t)0))
543#endif
544
545#ifdef CCX_DISABLE_HIGH_RES_TIMEBASE
546#define CCX_GetHighResTick() ((CCX_HR_TIME_t)CCX_GetPrimaryTick())
547#else
548#if CCX_HR_TICK_FROM_FUNC
549extern CCX_HR_TIME_BASE_SCALAR (*CCX_get_high_res_tick)(void);
550#define CCX_GetHighResTick() \
551 ((CCX_get_high_res_tick != NULL) ? (CCX_HR_TIME_t)CCX_get_high_res_tick() : ((CCX_HR_TIME_t)0))
552#else
553extern CCX_HR_TIME_t *CCX_high_res_tick;
554#define CCX_GetHighResTick() ((CCX_high_res_tick != NULL) ? (*CCX_high_res_tick) : ((CCX_HR_TIME_t)0))
555#endif
556#endif
557
567
576
605
628
629 /* ========================================================================
630 * CAN FD API (v2.0, requires CCX_ENABLE_CANFD=1)
631 * ======================================================================== */
632
633#if CCX_ENABLE_CANFD
634
641 typedef enum
642 {
643 CCX_FD_DLC_0B = 0, /* 0 bytes */
644 CCX_FD_DLC_1B = 1, /* 1 byte */
645 CCX_FD_DLC_2B = 2, /* 2 bytes */
646 CCX_FD_DLC_3B = 3, /* 3 bytes */
647 CCX_FD_DLC_4B = 4, /* 4 bytes */
648 CCX_FD_DLC_5B = 5, /* 5 bytes */
649 CCX_FD_DLC_6B = 6, /* 6 bytes */
650 CCX_FD_DLC_7B = 7, /* 7 bytes */
651 CCX_FD_DLC_8B = 8, /* 8 bytes */
652 CCX_FD_DLC_12B = 9, /* 12 bytes */
653 CCX_FD_DLC_16B = 10, /* 16 bytes */
654 CCX_FD_DLC_20B = 11, /* 20 bytes */
655 CCX_FD_DLC_24B = 12, /* 24 bytes */
656 CCX_FD_DLC_32B = 13, /* 32 bytes */
657 CCX_FD_DLC_48B = 14, /* 48 bytes */
658 CCX_FD_DLC_64B = 15, /* 64 bytes */
659 } CCX_FD_DLC_t;
660
662 extern const uint8_t CCX_FD_DLC_TO_LEN[16];
663
673 uint8_t CCX_FD_LenToDLC(uint8_t len);
674
683 static inline uint8_t CCX_MsgPayloadLen(const CCX_message_t *msg)
684 {
685 return (msg->FrameFormat != CCX_FRAME_FORMAT_CLASSIC) ? CCX_FD_DLC_TO_LEN[msg->DLC] : msg->DLC;
686 }
687
688#endif /* CCX_ENABLE_CANFD */
689
691
692#ifdef __cplusplus
693}
694#endif
695
696#endif /* CAN_COREX_CAN_COREX_H_ */
Bus monitoring public API.
CCX_BusIsFree_t
Enumeration indicating the status of the CAN bus.
Definition can_corex.h:247
void CCX_ResetGlobalStats(CCX_instance_t *Instance)
Reset global statistics.
void CCX_RX_RebuildHash(CCX_instance_t *Instance)
Rebuild hash table for RX message lookup.
void CCX_tick_variable_register(CCX_TIME_t *Variable)
Registers the system tick source variable.
const CCX_GlobalStats_t * CCX_GetGlobalStats(const CCX_instance_t *Instance)
Get global statistics.
#define CCX_TX_BUFFER_SIZE
Size of the CAN transmit buffer.
Definition can_corex.h:76
CCX_FD_DLC_t
Named CAN FD DLC values.
Definition can_corex.h:642
uint8_t CCX_FD_LenToDLC(uint8_t len)
Convert byte length to the smallest valid CAN FD DLC.
#define CCX_RX_HASH_SIZE
Size of the hash table for RX message lookup (used when CCX_RX_SEARCH_HASH is defined).
Definition can_corex.h:124
CCX_frame_format_t
CAN frame format selection.
Definition can_corex.h:276
#define CCX_RX_BUFFER_SIZE
Size of the CAN receive buffer.
Definition can_corex.h:66
void CCX_OnMessageTransmitted(CCX_instance_t *Instance, const CCX_message_t *msg)
Notify library that a message was successfully transmitted.
const uint8_t CCX_FD_DLC_TO_LEN[16]
DLC-to-payload-length lookup table: index 0-15, values {0,1,2,3,4,5,6,7,8,12,16,20,...
CCX_ide_t
CAN identifier type (standard 11-bit or extended 29-bit).
Definition can_corex.h:256
@ CCX_FRAME_FORMAT_CLASSIC
Classic CAN 2.0, max 8-byte payload.
Definition can_corex.h:277
@ CCX_FRAME_FORMAT_FD
CAN FD without bit-rate switch (BRS=0).
Definition can_corex.h:278
@ CCX_FRAME_FORMAT_FD_BRS
CAN FD with bit-rate switch (BRS=1).
Definition can_corex.h:279
@ CCX_ID_EXTENDED
Extended 29-bit identifier.
Definition can_corex.h:258
@ CCX_ID_STANDARD
Standard 11-bit identifier.
Definition can_corex.h:257
Bus monitor configuration and state.
Definition can_corex_bus.h:150
Global statistics for CAN instance.
Definition can_corex.h:299
uint32_t parser_calls_count
Total number of parser function invocations.
Definition can_corex.h:305
uint32_t tx_buffer_overflows
Number of times TX buffer was full.
Definition can_corex.h:304
uint32_t timeout_calls_count
Total number of timeout callback invocations.
Definition can_corex.h:306
uint16_t peak_tx_depth
Highest TX buffer depth observed since stats reset.
Definition can_corex.h:308
uint32_t total_rx_messages
Total messages received and pushed to RX buffer.
Definition can_corex.h:300
uint32_t rx_buffer_overflows
Number of times RX buffer was full.
Definition can_corex.h:303
uint32_t total_tx_messages
Total messages successfully transmitted (call CCX_OnMessageTransmitted from ISR).
Definition can_corex.h:302
uint16_t peak_rx_depth
Highest RX buffer depth observed since stats reset.
Definition can_corex.h:307
CAN RX table entry structure.
Definition can_corex.h:390
CAN TX table entry structure.
Definition can_corex.h:445
Definition can_corex.h:460
void(* OnMessageTransmitted)(CCX_instance_t *Instance, const CCX_message_t *msg)
Callback for TX complete (optional, for user notification).
Definition can_corex.h:478
CCX_BusMonitor_t * BusMonitor
Bus monitoring (NULL = disabled).
Definition can_corex.h:477
CCX_GlobalStats_t GlobalStats
Global statistics (always enabled).
Definition can_corex.h:476
Structure representing a CAN message.
Definition can_corex.h:336