The BaseCan class provides a comprehensive CAN bus abstraction that serves as the
unified interface for all Controller Area Network operations in the HardFOC system.
It supports both classic CAN and CAN-FD protocols, message filtering, error
handling, and works across different CAN controller implementations.
โจ Key Features
๐ CAN 2.0A/2.0B Support - Classic CAN protocols (CAN-FD support varies by hardware)
/**
* @brief Initialize the CAN controller
* @return hf_can_err_t error code
*
* ๐ Sets up CAN hardware, configures pins, and prepares for communication.
* Must be called before any CAN operations.
*
* @example
* EspCan can(config);
* if (can.Initialize() == hf_can_err_t::CAN_SUCCESS) {
* // CAN ready for use
* }
*/virtualhf_can_err_tInitialize()noexcept=0;/**
* @brief Deinitialize the CAN controller
* @return hf_can_err_t error code
*
* ๐งน Cleanly shuts down CAN hardware and releases resources.
*/virtualhf_can_err_tDeinitialize()noexcept=0;/**
* @brief Check if CAN is initialized
* @return true if initialized, false otherwise
*
* โ Query initialization status without side effects.
*/[[nodiscard]]boolIsInitialized()constnoexcept;/**
* @brief Ensure CAN is initialized (lazy initialization)
* @return true if initialized successfully, false otherwise
*
* ๐ Automatically initializes CAN if not already initialized.
*/boolEnsureInitialized()noexcept;/**
* @brief Ensure CAN is deinitialized (lazy deinitialization)
* @return true if deinitialized successfully, false otherwise
*
* ๐ Automatically deinitializes CAN if currently initialized.
*/boolEnsureDeinitialized()noexcept;
/**
* @brief Reset CAN operation statistics
* @return hf_can_err_t error code
*
* ๐ Clears all accumulated statistics counters.
*/virtualhf_can_err_tResetStatistics()noexcept;/**
* @brief Reset CAN diagnostic information
* @return hf_can_err_t error code
*
* ๐ Clears diagnostic information and error counters.
*/virtualhf_can_err_tResetDiagnostics()noexcept;/**
* @brief Get CAN operation statistics
* @param statistics Reference to store statistics data
* @return hf_can_err_t error code
*
* ๐ Retrieves comprehensive statistics about CAN operations.
*/virtualhf_can_err_tGetStatistics(hf_can_statistics_t&statistics)constnoexcept;/**
* @brief Get CAN diagnostic information
* @param diagnostics Reference to store diagnostics data
* @return hf_can_err_t error code
*
* ๐ Retrieves diagnostic information about CAN health and status.
*/virtualhf_can_err_tGetDiagnostics(hf_can_diagnostics_t&diagnostics)constnoexcept;
structhf_can_message_t{// === Core CAN Message Fields ===uint32_tid;///< Message ID (11 or 29-bit)uint8_tdlc;///< Data length code (0-8 for classic CAN)uint8_tdata[8];///< Message data (max 8 bytes for classic CAN)// === Standard CAN Flags ===boolis_extended;///< Extended ID flag (29-bit vs 11-bit)boolis_rtr;///< Remote transmission request flagboolis_ss;///< Single shot flag (no retransmission)boolis_self;///< Self reception request flagbooldlc_non_comp;///< DLC is non-compliant (> 8 for classic CAN)// === Metadata and Diagnostics ===uint64_ttimestamp_us;///< Precise timestamp in microsecondsuint32_tsequence_number;///< Message sequence numberuint8_tcontroller_id;///< Originating controller IDuint8_tretry_count;///< Number of transmission retriesuint8_terror_count;///< Associated error count// === CAN-FD Extended Fields ===boolis_canfd;///< CAN-FD frame flagboolis_brs;///< Bit Rate Switching flag (CAN-FD)boolis_esi;///< Error State Indicator flag (CAN-FD)uint8_tcanfd_dlc;///< CAN-FD DLC (can be > 8)// === Helper Methods ===uint8_tGetMaxDataLength()constnoexcept;///< Get max data length for frame typeboolIsValidDLC(uint8_tdlc)constnoexcept;///< Validate DLC for frame typeuint8_tGetEffectiveDLC()constnoexcept;///< Get effective DLC valueboolSetDLC(uint8_tdlc)noexcept;///< Set DLC for current frame typevoidSetStandardFrame()noexcept;///< Set standard frame formatvoidSetExtendedFrame()noexcept;///< Set extended frame formatvoidSetDataFrame()noexcept;///< Set data frame (not remote)voidSetRemoteFrame()noexcept;///< Set remote framevoidSetSingleShot()noexcept;///< Set single shot transmissionvoidSetSelfReception()noexcept;///< Enable self receptionboolIsValidId()constnoexcept;///< Validate message ID};
โ๏ธ CAN Configuration Structure
1
2
3
4
5
6
7
8
9
structhf_can_config_t{hf_pin_num_ttx_pin;///< CAN TX pinhf_pin_num_trx_pin;///< CAN RX pinhf_baud_rate_tbaudrate;///< CAN baudrate (bps)boolloopback_mode;///< Enable loopback mode for testingboolsilent_mode;///< Enable silent mode (listen-only)uint16_ttx_queue_size;///< TX queue size (implementation-dependent)uint16_trx_queue_size;///< RX queue size (implementation-dependent)};
structhf_can_status_t{uint32_ttx_error_count;///< Transmit error counteruint32_trx_error_count;///< Receive error counteruint32_ttx_failed_count;///< Failed transmission countuint32_trx_missed_count;///< Missed reception countboolbus_off;///< Bus-off stateboolerror_warning;///< Error warning stateboolerror_passive;///< Error passive state// CAN-FD specific statusboolcanfd_enabled;///< CAN-FD mode is activeboolcanfd_brs_enabled;///< Bit Rate Switching is enableduint32_tnominal_baudrate;///< Nominal bit rate (arbitration phase)uint32_tdata_baudrate;///< Data bit rate (data phase for CAN-FD)uint32_tcanfd_tx_count;///< Number of CAN-FD frames transmitteduint32_tcanfd_rx_count;///< Number of CAN-FD frames receiveduint32_tbrs_tx_count;///< Number of BRS frames transmitteduint32_tbrs_rx_count;///< Number of BRS frames receiveduint32_tform_errors;///< CAN-FD form errorsuint32_tstuff_errors;///< Stuff errorsuint32_tcrc_errors;///< CRC errorsuint32_tbit_errors;///< Bit errorsuint32_tack_errors;///< Acknowledgment errors};
structhf_can_statistics_t{// Message countersuint64_tmessages_sent;///< Total messages successfully sentuint64_tmessages_received;///< Total messages successfully receiveduint64_tbytes_transmitted;///< Total bytes transmitteduint64_tbytes_received;///< Total bytes received// Error countersuint32_tsend_failures;///< Failed send operationsuint32_treceive_failures;///< Failed receive operationsuint32_tbus_error_count;///< Total bus errorsuint32_tarbitration_lost_count;///< Arbitration lost eventsuint32_ttx_failed_count;///< Transmission failuresuint32_tbus_off_events;///< Bus-off occurrencesuint32_terror_warning_events;///< Error warning events// Performance metricsuint64_tuptime_seconds;///< Total uptime in secondsuint32_tlast_activity_timestamp;///< Last activity timestamphf_can_err_tlast_error;///< Last error encountered// Queue statisticsuint32_ttx_queue_peak;///< Peak TX queue usageuint32_trx_queue_peak;///< Peak RX queue usageuint32_ttx_queue_overflows;///< TX queue overflow countuint32_trx_queue_overflows;///< RX queue overflow count};
๐ CAN Diagnostics Structure
1
2
3
4
5
6
7
8
9
10
structhf_can_diagnostics_t{uint32_ttx_error_count;///< Transmit error counteruint32_trx_error_count;///< Receive error counteruint32_ttx_queue_peak;///< Peak TX queue usageuint32_trx_queue_peak;///< Peak RX queue usageuint32_tlast_error_timestamp;///< Timestamp of last erroruint32_tcontroller_resets;///< Number of controller resetsuint32_tbus_load_percentage;///< Current bus load percentagefloatbit_error_rate;///< Bit error rate (errors/bits)};
#include"mcu/esp32/EspCan.h"// Create CAN instancehf_can_config_tconfig={.tx_pin=5,.rx_pin=4,.baudrate=500000,.loopback_mode=false,.silent_mode=false,.tx_queue_size=10,.rx_queue_size=10};EspCancan(config);voidsetup(){// Initialize CANif(can.Initialize()==hf_can_err_t::CAN_SUCCESS){printf("โ CAN initialized successfully\n");}}voidsend_status_message(){hf_can_message_tmsg;msg.id=0x100;// Status message IDmsg.dlc=8;// 8 bytes of datamsg.is_extended=false;msg.is_rtr=false;// Pack status datamsg.data[0]=0x01;// Status bytemsg.data[1]=0x02;// Temperaturemsg.data[2]=0x03;// Voltagemsg.data[3]=0x04;// Currentmsg.data[4]=0x05;// Speedmsg.data[5]=0x06;// Positionmsg.data[6]=0x07;// Error flagsmsg.data[7]=0x08;// Checksumhf_can_err_tresult=can.SendMessage(msg,1000);if(result!=hf_can_err_t::CAN_SUCCESS){printf("โ Send failed: %s\n",HfCanErrToString(result));}else{printf("โ Message sent successfully\n");}}
#include"mcu/esp32/EspCan.h"EspCancan(config);voidsetup_filtering(){// Initialize CANcan.Initialize();// Accept only status messages (0x100-0x1FF)can.SetAcceptanceFilter(0x100,0x700,false);// Accept only command messages (0x200-0x2FF)can.SetAcceptanceFilter(0x200,0x700,false);// Accept only diagnostic messages (0x7DF-0x7FF)can.SetAcceptanceFilter(0x7DF,0x7E0,false);printf("โ Message filtering configured\n");}voidreceive_filtered_messages(){hf_can_message_tmsg;while(true){if(can.ReceiveMessage(msg,100)==hf_can_err_t::CAN_SUCCESS){// Only filtered messages will be receivedprintf("๐ฅ Filtered message ID: 0x%03X\n",msg.id);}}}
#include"mcu/esp32/EspCan.h"EspCancan(config);// Callback function for received messagesvoidon_can_message(consthf_can_message_t&msg){printf("๐ Async received ID: 0x%03X\n",msg.id);// Process message in callback contextswitch(msg.id){case0x100:// Handle status messagebreak;case0x200:// Handle command messagebreak;}}voidsetup_async_reception(){// Initialize CANcan.Initialize();// Set receive callbackcan.SetReceiveCallback(on_can_message);printf("โ Asynchronous reception enabled\n");}voidmain_loop(){while(true){// Main application logic// Messages will be handled automatically by callbackvTaskDelay(pdMS_TO_TICKS(100));}}
#include"mcu/esp32/EspCan.h"classMotorController{private:EspCancan*;uint32_tmotor_id*;public:MotorController(consthf_can_config_t&config,uint32_tmotor_id):can*(config),motor_id*(motor_id){}boolinitialize(){returncan*.Initialize()==hf_can_err_t::CAN_SUCCESS;}voidset_speed(floatspeed_rpm){hf_can_message_tmsg;msg.id=0x200+motor_id*;// Command message for this motormsg.dlc=4;msg.is_extended=false;msg.is_rtr=false;// Pack speed commanduint16_tspeed_raw=static_cast<uint16_t>(speed_rpm);msg.data[0]=0x01;// Command type: set speedmsg.data[1]=speed_raw&0xFF;msg.data[2]=(speed_raw>>8)&0xFF;msg.data[3]=calculate_checksum(msg.data,3);hf_can_err_tresult=can*.SendMessage(msg,1000);if(result!=hf_can_err_t::CAN_SUCCESS){printf("โ Speed command failed: %s\n",HfCanErrToString(result));}}voidrequest_status(){hf_can_message_tmsg;msg.id=0x100+motor_id*;// Status request for this motormsg.dlc=0;msg.is_extended=false;msg.is_rtr=true;// Remote framecan*.SendMessage(msg,1000);}voidmonitor_status(){hf_can_status_tstatus;if(can*.GetStatus(status)==hf_can_err_t::CAN_SUCCESS){printf("๐ CAN Status - TX errors: %u, RX errors: %u, Bus off: %s\n",status.tx_error_count,status.rx_error_count,status.bus_off?"Yes":"No");}}private:uint8_tcalculate_checksum(constuint8_t*data,uint8_tlength){uint8_tchecksum=0;for(uint8_ti=0;i<length;i++){checksum^=data[i];}returnchecksum;}};
// โ Always check initializationif(can.Initialize()!=hf_can_err_t::CAN_SUCCESS){printf("โ CAN initialization failed\n");returnfalse;}// โ Use appropriate timeoutscan.SendMessage(msg,1000);// 1 second timeout for critical messagescan.ReceiveMessage(msg,100);// 100ms timeout for non-blocking receive// โ Handle all error codeshf_can_err_tresult=can.SendMessage(msg,timeout);if(result!=hf_can_err_t::CAN_SUCCESS){printf("โ ๏ธ Send error: %s\n",HfCanErrToString(result));// Handle specific error typesif(result==hf_can_err_t::CAN_ERR_BUS_OFF){// Bus off - restart controllercan.Deinitialize();can.Initialize();}}// โ Use message filtering for efficiencycan.SetAcceptanceFilter(0x100,0x700,false);// Only accept status messages// โ Monitor bus healthhf_can_status_tstatus;if(can.GetStatus(status)==hf_can_err_t::CAN_SUCCESS){if(status.bus_off){printf("๐จ Bus off detected!\n");}if(status.tx_error_count>100){printf("โ ๏ธ High TX error count: %u\n",status.tx_error_count);}}
โ Common Pitfalls
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// โ Don't ignore initializationcan.SendMessage(msg);// May fail silently// โ Don't use infinite timeouts in real-time systemscan.ReceiveMessage(msg,UINT32_MAX);// May block forever// โ Don't ignore error codescan.SendMessage(msg);// Error handling missing// โ Don't assume message reception// Always check return values for receive operations// โ Don't use without proper bus termination// CAN bus requires proper termination resistors// โ Don't ignore bus-off state// Bus-off requires controller restart
// ๐ Use batch operations for multiple messageshf_can_message_tmessages[10];// ... populate messagesuint32_tsent=can.SendMessageBatch(messages,10,1000);// ๐ Use callbacks for high-frequency receptioncan.SetReceiveCallback(on_message);// Non-blocking reception// ๐ Use appropriate queue sizeshf_can_config_tconfig={.tx_queue_size=20,// Larger for high-frequency transmission.rx_queue_size=50// Larger for high-frequency reception};// ๐ Use message filtering to reduce CPU loadcan.SetAcceptanceFilter(target_id,mask,extended);// ๐ Monitor statistics for performance tuninghf_can_statistics_tstats;can.GetStatistics(stats);if(stats.tx_queue_overflows>0){printf("โ ๏ธ TX queue overflow - increase queue size\n");}