From 11a6e6bd23104f33c18d0320a6e328e09658e850 Mon Sep 17 00:00:00 2001 From: Ilia Date: Wed, 15 Jul 2026 15:46:23 +0300 Subject: [PATCH 1/2] feat: stop hardcoding fdcan in platformspecific --- platform_specific/fdcan/config.cmake | 2 + platform_specific/fdcan/fdcan_config.h | 25 +++ platform_specific/fdcan/stm32g0b1.cpp | 163 ++++++++++------- platform_specific/fdcan/stm32h753xx.cpp | 234 ++++++++++++------------ 4 files changed, 243 insertions(+), 181 deletions(-) create mode 100644 platform_specific/fdcan/fdcan_config.h diff --git a/platform_specific/fdcan/config.cmake b/platform_specific/fdcan/config.cmake index 6860050..233e5d7 100644 --- a/platform_specific/fdcan/config.cmake +++ b/platform_specific/fdcan/config.cmake @@ -1,6 +1,8 @@ set(DRONECAN_PLATFORM_SOURCES ) +list(APPEND DRONECAN_PLATFORM_HEADERS ${CMAKE_CURRENT_LIST_DIR}) + if(APP_PLATFORM STREQUAL "stm32g0b1") list(APPEND DRONECAN_PLATFORM_SOURCES ${CMAKE_CURRENT_LIST_DIR}/stm32g0b1.cpp) elseif(APP_PLATFORM STREQUAL "stm32h753xx") diff --git a/platform_specific/fdcan/fdcan_config.h b/platform_specific/fdcan/fdcan_config.h new file mode 100644 index 0000000..a7f3461 --- /dev/null +++ b/platform_specific/fdcan/fdcan_config.h @@ -0,0 +1,25 @@ +#ifndef LIBDCNODE_PLATFORM_SPECIFIC_FDCAN_CONFIG_H_ +#define LIBDCNODE_PLATFORM_SPECIFIC_FDCAN_CONFIG_H_ + +#include +#include + +#include "main.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct { + FDCAN_HandleTypeDef* handle; + uint8_t interface_id; +} DronecanFdcanInterfaceConfig; + +int16_t dronecanFdcanConfigure(const DronecanFdcanInterfaceConfig* interfaces, + size_t interface_count); + +#ifdef __cplusplus +} +#endif + +#endif // LIBDCNODE_PLATFORM_SPECIFIC_FDCAN_CONFIG_H_ diff --git a/platform_specific/fdcan/stm32g0b1.cpp b/platform_specific/fdcan/stm32g0b1.cpp index c4b92be..a9a23dd 100644 --- a/platform_specific/fdcan/stm32g0b1.cpp +++ b/platform_specific/fdcan/stm32g0b1.cpp @@ -6,113 +6,146 @@ */ #include "libdcnode/can_driver.h" +#include "fdcan_config.h" #include -#include "main.h" +namespace { -#ifndef NUM_OF_CAN_BUSES - #define NUM_OF_CAN_BUSES 1 -#endif +constexpr size_t MAX_INTERFACES = 2U; -extern FDCAN_HandleTypeDef hfdcan1; -extern FDCAN_HandleTypeDef hfdcan2; - -typedef struct { +struct CanDriver { FDCAN_HandleTypeDef* handler; FDCAN_TxHeaderTypeDef tx_header; + uint8_t interface_id; uint8_t rx_buf[8]; size_t err_counter; size_t tx_counter; size_t rx_counter; -} CanDriver; - -static CanDriver driver[NUM_OF_CAN_BUSES] = { - {.handler = &hfdcan1, .tx_header = {}, .rx_buf = {}, .err_counter = 0, .tx_counter = 0, .rx_counter = 0}, -#if NUM_OF_CAN_BUSES >= 2 - {.handler = &hfdcan2, .tx_header = {}, .rx_buf = {}, .err_counter = 0, .tx_counter = 0, .rx_counter = 0} -#endif }; -void canDriverSetInterfaceName(const char* interface_name) { +CanDriver drivers[MAX_INTERFACES]{}; +size_t driver_count = 0U; +bool started = false; + +bool isConfigurationValid(const DronecanFdcanInterfaceConfig* interfaces, + const size_t interface_count) { + if (interfaces == nullptr || interface_count == 0U || interface_count > MAX_INTERFACES) { + return false; + } + for (size_t idx = 0U; idx < interface_count; idx++) { + if (interfaces[idx].handle == nullptr) { + return false; + } + for (size_t other = 0U; other < idx; other++) { + if (interfaces[idx].handle == interfaces[other].handle || + interfaces[idx].interface_id == interfaces[other].interface_id) { + return false; + } + } + } + return true; +} + +} // namespace + +extern "C" int16_t dronecanFdcanConfigure( + const DronecanFdcanInterfaceConfig* interfaces, + const size_t interface_count) { + if (started || !isConfigurationValid(interfaces, interface_count)) { + return -1; + } + + drivers[0] = {}; + drivers[1] = {}; + driver_count = interface_count; + for (size_t idx = 0U; idx < interface_count; idx++) { + drivers[idx].handler = interfaces[idx].handle; + drivers[idx].interface_id = interfaces[idx].interface_id; + } + return 0; +} + +extern "C" void canDriverSetInterfaceName(const char* interface_name) { (void)interface_name; } -int16_t canDriverInit(uint32_t can_speed, uint8_t can_driver_idx) { +extern "C" int16_t canDriverInit(uint32_t can_speed, uint8_t can_driver_idx) { (void)can_speed; - if (can_driver_idx >= NUM_OF_CAN_BUSES) { + if (can_driver_idx >= driver_count) { return -1; } - driver[can_driver_idx].tx_header.IdType = FDCAN_EXTENDED_ID; - driver[can_driver_idx].tx_header.TxFrameType = FDCAN_DATA_FRAME; - driver[can_driver_idx].tx_header.ErrorStateIndicator = FDCAN_ESI_ACTIVE; - driver[can_driver_idx].tx_header.BitRateSwitch = FDCAN_BRS_OFF; - driver[can_driver_idx].tx_header.FDFormat = FDCAN_CLASSIC_CAN; - driver[can_driver_idx].tx_header.TxEventFifoControl = FDCAN_NO_TX_EVENTS; - driver[can_driver_idx].tx_header.MessageMarker = 0; - - FDCAN_FilterTypeDef sFilterConfig; - sFilterConfig.IdType = FDCAN_EXTENDED_ID; - sFilterConfig.FilterIndex = 0; - sFilterConfig.FilterType = FDCAN_FILTER_MASK; - sFilterConfig.FilterConfig = FDCAN_FILTER_DISABLE; - - if (HAL_FDCAN_ConfigFilter(driver[can_driver_idx].handler, &sFilterConfig) != HAL_OK) { - return -1; - } else if (HAL_FDCAN_Start(driver[can_driver_idx].handler) != HAL_OK) { + CanDriver& driver = drivers[can_driver_idx]; + driver.tx_header.IdType = FDCAN_EXTENDED_ID; + driver.tx_header.TxFrameType = FDCAN_DATA_FRAME; + driver.tx_header.ErrorStateIndicator = FDCAN_ESI_ACTIVE; + driver.tx_header.BitRateSwitch = FDCAN_BRS_OFF; + driver.tx_header.FDFormat = FDCAN_CLASSIC_CAN; + driver.tx_header.TxEventFifoControl = FDCAN_NO_TX_EVENTS; + driver.tx_header.MessageMarker = 0U; + + FDCAN_FilterTypeDef filter_config{}; + filter_config.IdType = FDCAN_EXTENDED_ID; + filter_config.FilterIndex = 0U; + filter_config.FilterType = FDCAN_FILTER_MASK; + filter_config.FilterConfig = FDCAN_FILTER_DISABLE; + + if (HAL_FDCAN_ConfigFilter(driver.handler, &filter_config) != HAL_OK || + HAL_FDCAN_Start(driver.handler) != HAL_OK) { return -1; } + started = true; return 0; } -int16_t canDriverReceive(CanardCANFrame* const rx_frame, uint8_t can_driver_idx) { - if (rx_frame == NULL || can_driver_idx >= NUM_OF_CAN_BUSES) { +extern "C" int16_t canDriverReceive(CanardCANFrame* const rx_frame, + uint8_t can_driver_idx) { + if (rx_frame == nullptr || can_driver_idx >= driver_count) { return 0; } - FDCAN_RxHeaderTypeDef rx_header; - - HAL_StatusTypeDef res = HAL_FDCAN_GetRxMessage(driver[can_driver_idx].handler, - FDCAN_RX_FIFO0, - &rx_header, - driver[can_driver_idx].rx_buf); - if (res != HAL_OK) { + CanDriver& driver = drivers[can_driver_idx]; + FDCAN_RxHeaderTypeDef rx_header{}; + if (HAL_FDCAN_GetRxMessage(driver.handler, + FDCAN_RX_FIFO0, + &rx_header, + driver.rx_buf) != HAL_OK) { return 0; } - driver[can_driver_idx].rx_counter++; - rx_frame->id = (CANARD_CAN_EXT_ID_MASK & (rx_header.Identifier)) | CANARD_CAN_FRAME_EFF; - rx_frame->data_len = rx_header.DataLength >> 16U; - rx_frame->iface_id = can_driver_idx; - memcpy(rx_frame->data, driver[can_driver_idx].rx_buf, rx_frame->data_len); + driver.rx_counter++; + rx_frame->id = (CANARD_CAN_EXT_ID_MASK & rx_header.Identifier) | CANARD_CAN_FRAME_EFF; + rx_frame->data_len = static_cast(rx_header.DataLength >> 16U); + rx_frame->iface_id = driver.interface_id; + memcpy(rx_frame->data, driver.rx_buf, rx_frame->data_len); return 1; } -int16_t canDriverTransmit(const CanardCANFrame* const tx_frame, uint8_t can_driver_idx) { - if (tx_frame == NULL || can_driver_idx >= NUM_OF_CAN_BUSES) { +extern "C" int16_t canDriverTransmit(const CanardCANFrame* const tx_frame, + uint8_t can_driver_idx) { + if (tx_frame == nullptr || can_driver_idx >= driver_count) { return 0; } - driver[can_driver_idx].tx_header.Identifier = tx_frame->id; - driver[can_driver_idx].tx_header.DataLength = tx_frame->data_len << 16U; - - HAL_StatusTypeDef res = HAL_FDCAN_AddMessageToTxFifoQ(driver[can_driver_idx].handler, - &driver[can_driver_idx].tx_header, - (uint8_t*)tx_frame->data); - if (res == HAL_OK) { - driver[can_driver_idx].tx_counter++; - return 1; - } else { + CanDriver& driver = drivers[can_driver_idx]; + driver.tx_header.Identifier = tx_frame->id; + driver.tx_header.DataLength = static_cast(tx_frame->data_len) << 16U; + if (HAL_FDCAN_AddMessageToTxFifoQ(driver.handler, + &driver.tx_header, + const_cast(tx_frame->data)) != HAL_OK) { return 0; } + + driver.tx_counter++; + return 1; } -uint64_t canDriverGetErrorCount() { - return driver[0].err_counter; +extern "C" uint64_t canDriverGetErrorCount() { + return driver_count > 0U ? drivers[0].err_counter : 0U; } -uint64_t canDriverGetRxOverflowCount() { - return 0; +extern "C" uint64_t canDriverGetRxOverflowCount() { + return 0U; } diff --git a/platform_specific/fdcan/stm32h753xx.cpp b/platform_specific/fdcan/stm32h753xx.cpp index 07dbc23..7ce9273 100644 --- a/platform_specific/fdcan/stm32h753xx.cpp +++ b/platform_specific/fdcan/stm32h753xx.cpp @@ -6,170 +6,172 @@ */ #include "libdcnode/can_driver.h" +#include "fdcan_config.h" #include -#include "main.h" +namespace { -#ifndef NUM_OF_CAN_BUSES - #define NUM_OF_CAN_BUSES 1 -#endif +constexpr size_t MAX_INTERFACES = 2U; -#ifndef DRONECAN_FDCAN_PRIMARY - #define DRONECAN_FDCAN_PRIMARY 1 -#endif - -extern FDCAN_HandleTypeDef hfdcan1; -extern FDCAN_HandleTypeDef hfdcan2; - -typedef struct { +struct CanDriver { FDCAN_HandleTypeDef* handler; FDCAN_TxHeaderTypeDef tx_header; + uint8_t interface_id; uint8_t rx_buf[8]; - size_t err_counter; - size_t tx_counter; - size_t rx_counter; -} CanDriver; - -static CanDriver driver[NUM_OF_CAN_BUSES] = { -#if DRONECAN_FDCAN_PRIMARY == 2 - {.handler = &hfdcan2, .tx_header = {}, .rx_buf = {}, .err_counter = 0, .tx_counter = 0, .rx_counter = 0}, -#if NUM_OF_CAN_BUSES >= 2 - {.handler = &hfdcan1, .tx_header = {}, .rx_buf = {}, .err_counter = 0, .tx_counter = 0, .rx_counter = 0} -#endif -#else - {.handler = &hfdcan1, .tx_header = {}, .rx_buf = {}, .err_counter = 0, .tx_counter = 0, .rx_counter = 0}, -#if NUM_OF_CAN_BUSES >= 2 - {.handler = &hfdcan2, .tx_header = {}, .rx_buf = {}, .err_counter = 0, .tx_counter = 0, .rx_counter = 0} -#endif -#endif + uint32_t err_counter; + uint32_t tx_counter; + uint32_t rx_counter; }; -void canDriverSetInterfaceName(const char* interface_name) { - (void)interface_name; -} +CanDriver drivers[MAX_INTERFACES]{}; +size_t driver_count = 0U; +bool started = false; +size_t next_receive = 0U; -static int16_t canDriverInitPhysical(uint8_t physical_idx) { - if (physical_idx >= NUM_OF_CAN_BUSES) { - return -1; +bool isConfigurationValid(const DronecanFdcanInterfaceConfig* interfaces, + const size_t interface_count) { + if (interfaces == nullptr || interface_count == 0U || interface_count > MAX_INTERFACES) { + return false; } - - driver[physical_idx].tx_header.IdType = FDCAN_EXTENDED_ID; - driver[physical_idx].tx_header.TxFrameType = FDCAN_DATA_FRAME; - driver[physical_idx].tx_header.ErrorStateIndicator = FDCAN_ESI_ACTIVE; - driver[physical_idx].tx_header.BitRateSwitch = FDCAN_BRS_OFF; - driver[physical_idx].tx_header.FDFormat = FDCAN_CLASSIC_CAN; - driver[physical_idx].tx_header.TxEventFifoControl = FDCAN_NO_TX_EVENTS; - driver[physical_idx].tx_header.MessageMarker = 0; - - HAL_StatusTypeDef res = HAL_FDCAN_ConfigGlobalFilter( - driver[physical_idx].handler, - FDCAN_ACCEPT_IN_RX_FIFO0, - FDCAN_ACCEPT_IN_RX_FIFO0, - FDCAN_REJECT_REMOTE, - FDCAN_REJECT_REMOTE); - if (res != HAL_OK) { - driver[physical_idx].err_counter++; - return -1; + for (size_t idx = 0U; idx < interface_count; idx++) { + if (interfaces[idx].handle == nullptr) { + return false; + } + for (size_t other = 0U; other < idx; other++) { + if (interfaces[idx].handle == interfaces[other].handle || + interfaces[idx].interface_id == interfaces[other].interface_id) { + return false; + } + } } + return true; +} + +void initializeTxHeader(FDCAN_TxHeaderTypeDef& header) { + header = {}; + header.IdType = FDCAN_EXTENDED_ID; + header.TxFrameType = FDCAN_DATA_FRAME; + header.ErrorStateIndicator = FDCAN_ESI_ACTIVE; + header.BitRateSwitch = FDCAN_BRS_OFF; + header.FDFormat = FDCAN_CLASSIC_CAN; + header.TxEventFifoControl = FDCAN_NO_TX_EVENTS; +} - res = HAL_FDCAN_Start(driver[physical_idx].handler); - if (res != HAL_OK) { - driver[physical_idx].err_counter++; +} // namespace + +extern "C" int16_t dronecanFdcanConfigure( + const DronecanFdcanInterfaceConfig* interfaces, + const size_t interface_count) { + if (started || !isConfigurationValid(interfaces, interface_count)) { return -1; } - + drivers[0] = {}; + drivers[1] = {}; + driver_count = interface_count; + next_receive = 0U; + for (size_t idx = 0U; idx < interface_count; idx++) { + drivers[idx].handler = interfaces[idx].handle; + drivers[idx].interface_id = interfaces[idx].interface_id; + } return 0; } -int16_t canDriverInit(uint32_t can_speed, uint8_t can_driver_idx) { +extern "C" void canDriverSetInterfaceName(const char* interface_name) { + (void)interface_name; +} + +extern "C" int16_t canDriverInit(uint32_t can_speed, uint8_t can_driver_idx) { (void)can_speed; - if (can_driver_idx != CAN_DRIVER_FIRST) { + if (can_driver_idx != CAN_DRIVER_FIRST || driver_count == 0U || started) { return -1; } - - for (uint8_t physical_idx = 0; physical_idx < NUM_OF_CAN_BUSES; physical_idx++) { - const int16_t res = canDriverInitPhysical(physical_idx); - if (res < 0) { - return res; + for (size_t idx = 0U; idx < driver_count; idx++) { + initializeTxHeader(drivers[idx].tx_header); + if (HAL_FDCAN_ConfigGlobalFilter(drivers[idx].handler, + FDCAN_ACCEPT_IN_RX_FIFO0, + FDCAN_ACCEPT_IN_RX_FIFO0, + FDCAN_REJECT_REMOTE, + FDCAN_REJECT_REMOTE) != HAL_OK || + HAL_FDCAN_Start(drivers[idx].handler) != HAL_OK) { + drivers[idx].err_counter++; + return -1; } } - + started = true; return 0; } -int16_t canDriverReceive(CanardCANFrame* const rx_frame, uint8_t can_driver_idx) { - if (rx_frame == NULL || can_driver_idx != CAN_DRIVER_FIRST) { +extern "C" int16_t canDriverReceive(CanardCANFrame* const rx_frame, + uint8_t can_driver_idx) { + if (rx_frame == nullptr || can_driver_idx != CAN_DRIVER_FIRST || !started) { return 0; } - - static uint8_t next_physical_idx = 0; - for (uint8_t attempt = 0; attempt < NUM_OF_CAN_BUSES; attempt++) { - const uint8_t physical_idx = static_cast((next_physical_idx + attempt) % NUM_OF_CAN_BUSES); - FDCAN_RxHeaderTypeDef rx_header; - - HAL_StatusTypeDef res = HAL_FDCAN_GetRxMessage(driver[physical_idx].handler, - FDCAN_RX_FIFO0, - &rx_header, - driver[physical_idx].rx_buf); - if (res != HAL_OK) { + for (size_t attempt = 0U; attempt < driver_count; attempt++) { + const size_t idx = (next_receive + attempt) % driver_count; + FDCAN_RxHeaderTypeDef header{}; + if (HAL_FDCAN_GetRxMessage(drivers[idx].handler, + FDCAN_RX_FIFO0, + &header, + drivers[idx].rx_buf) != HAL_OK) { continue; } - - driver[physical_idx].rx_counter++; - rx_frame->id = (CANARD_CAN_EXT_ID_MASK & (rx_header.Identifier)) | CANARD_CAN_FRAME_EFF; - rx_frame->data_len = static_cast(rx_header.DataLength); - rx_frame->iface_id = physical_idx; - memcpy(rx_frame->data, driver[physical_idx].rx_buf, rx_frame->data_len); - next_physical_idx = static_cast((physical_idx + 1) % NUM_OF_CAN_BUSES); + if (header.IdType != FDCAN_EXTENDED_ID || header.RxFrameType != FDCAN_DATA_FRAME || + header.FDFormat != FDCAN_CLASSIC_CAN) { + drivers[idx].err_counter++; + continue; + } + const uint8_t data_len = static_cast(header.DataLength); + if (data_len > sizeof(rx_frame->data)) { + drivers[idx].err_counter++; + continue; + } + rx_frame->id = (header.Identifier & CANARD_CAN_EXT_ID_MASK) | CANARD_CAN_FRAME_EFF; + rx_frame->data_len = data_len; + rx_frame->iface_id = drivers[idx].interface_id; + memcpy(rx_frame->data, drivers[idx].rx_buf, data_len); + drivers[idx].rx_counter++; + next_receive = (idx + 1U) % driver_count; return 1; } - return 0; } -int16_t canDriverTransmit(const CanardCANFrame* const tx_frame, uint8_t can_driver_idx) { - if (tx_frame == NULL || can_driver_idx != CAN_DRIVER_FIRST) { +extern "C" int16_t canDriverTransmit(const CanardCANFrame* const tx_frame, + uint8_t can_driver_idx) { + if (tx_frame == nullptr || can_driver_idx != CAN_DRIVER_FIRST || !started || + tx_frame->data_len > sizeof(tx_frame->data)) { return 0; } - bool sent = false; - for (uint8_t physical_idx = 0; physical_idx < NUM_OF_CAN_BUSES; physical_idx++) { - driver[physical_idx].tx_header.Identifier = tx_frame->id & CANARD_CAN_EXT_ID_MASK; - driver[physical_idx].tx_header.DataLength = tx_frame->data_len; - - HAL_StatusTypeDef res = HAL_FDCAN_AddMessageToTxFifoQ( - driver[physical_idx].handler, - &driver[physical_idx].tx_header, - (uint8_t*)tx_frame->data); - if (res == HAL_OK) { - driver[physical_idx].tx_counter++; + for (size_t idx = 0U; idx < driver_count; idx++) { + drivers[idx].tx_header.Identifier = tx_frame->id & CANARD_CAN_EXT_ID_MASK; + drivers[idx].tx_header.DataLength = tx_frame->data_len; + if (HAL_FDCAN_AddMessageToTxFifoQ(drivers[idx].handler, + &drivers[idx].tx_header, + const_cast(tx_frame->data)) == HAL_OK) { + drivers[idx].tx_counter++; sent = true; } else { - driver[physical_idx].err_counter++; + drivers[idx].err_counter++; } } - return sent ? 1 : 0; } -uint64_t canDriverGetErrorCount() { - uint64_t errors = 0; - for (uint8_t idx = 0; idx < NUM_OF_CAN_BUSES; idx++) { - FDCAN_ProtocolStatusTypeDef protocol_status = {}; - FDCAN_ErrorCountersTypeDef error_counters = {}; - (void)HAL_FDCAN_GetProtocolStatus(driver[idx].handler, &protocol_status); - (void)HAL_FDCAN_GetErrorCounters(driver[idx].handler, &error_counters); - errors += driver[idx].err_counter; - errors += protocol_status.BusOff; - errors += protocol_status.Warning; - errors += protocol_status.ErrorPassive; - errors += error_counters.TxErrorCnt; - errors += error_counters.RxErrorCnt; +extern "C" uint64_t canDriverGetErrorCount() { + uint64_t errors = 0U; + for (size_t idx = 0U; idx < driver_count; idx++) { + FDCAN_ProtocolStatusTypeDef protocol{}; + FDCAN_ErrorCountersTypeDef counters{}; + (void)HAL_FDCAN_GetProtocolStatus(drivers[idx].handler, &protocol); + (void)HAL_FDCAN_GetErrorCounters(drivers[idx].handler, &counters); + errors += drivers[idx].err_counter + protocol.BusOff + protocol.Warning + + protocol.ErrorPassive + counters.TxErrorCnt + counters.RxErrorCnt; } return errors; } -uint64_t canDriverGetRxOverflowCount() { - return 0; +extern "C" uint64_t canDriverGetRxOverflowCount() { + return 0U; } From f2d61f77d94397158ce60effa4a7abb492c915b3 Mon Sep 17 00:00:00 2001 From: Ilia Date: Thu, 16 Jul 2026 14:06:01 +0300 Subject: [PATCH 2/2] feat: get rid of platform specific fdcan --- docs/migration_guide_v0_5_to_v0_6.md | 7 +- examples/ubuntu/CMakeLists.txt | 2 +- platform_specific/fdcan/config.cmake | 12 -- platform_specific/fdcan/fdcan_config.h | 25 ---- platform_specific/fdcan/stm32g0b1.cpp | 151 -------------------- platform_specific/fdcan/stm32h753xx.cpp | 177 ------------------------ 6 files changed, 6 insertions(+), 368 deletions(-) delete mode 100644 platform_specific/fdcan/config.cmake delete mode 100644 platform_specific/fdcan/fdcan_config.h delete mode 100644 platform_specific/fdcan/stm32g0b1.cpp delete mode 100644 platform_specific/fdcan/stm32h753xx.cpp diff --git a/docs/migration_guide_v0_5_to_v0_6.md b/docs/migration_guide_v0_5_to_v0_6.md index 3b955ae..107076e 100644 --- a/docs/migration_guide_v0_5_to_v0_6.md +++ b/docs/migration_guide_v0_5_to_v0_6.md @@ -40,8 +40,8 @@ v0.6.0 turns libdcnode into a standalone CMake library with explicit integration # libdcnode add_subdirectory(${ROOT_DIR} ${CMAKE_BINARY_DIR}/libdcnode) -# platform config -set(CAN_PLATFORM socketcan) # bxcan, fdcan, socketcan +# optional bundled platform config +set(CAN_PLATFORM socketcan) # bxcan or socketcan include(${ROOT_DIR}/platform_specific/${CAN_PLATFORM}/config.cmake) # libparams @@ -54,6 +54,9 @@ target_include_directories(${PROJECT_NAME} PRIVATE ... ${DRONECAN_PLATFORM_HEADE target_link_libraries(${PROJECT_NAME} PRIVATE libdcnode::libdcnode) ``` +FDCAN applications provide their `canDriver*` callbacks from the application +peripheral layer and pass them through `PlatformApi`. + 2. **Update includes** ```cpp diff --git a/examples/ubuntu/CMakeLists.txt b/examples/ubuntu/CMakeLists.txt index d779f3d..e3b404f 100644 --- a/examples/ubuntu/CMakeLists.txt +++ b/examples/ubuntu/CMakeLists.txt @@ -12,7 +12,7 @@ cmake_path(GET EXAMPLES_DIR PARENT_PATH ROOT_DIR) add_subdirectory(${ROOT_DIR} ${CMAKE_BINARY_DIR}/libdcnode) # 2. libcanver -set(CAN_PLATFORM socketcan) # Options: bxcan, fdcan or socketcan +set(CAN_PLATFORM socketcan) # Options: bxcan or socketcan include(${ROOT_DIR}/platform_specific/${CAN_PLATFORM}/config.cmake) # 3. libparams diff --git a/platform_specific/fdcan/config.cmake b/platform_specific/fdcan/config.cmake deleted file mode 100644 index 233e5d7..0000000 --- a/platform_specific/fdcan/config.cmake +++ /dev/null @@ -1,12 +0,0 @@ -set(DRONECAN_PLATFORM_SOURCES -) - -list(APPEND DRONECAN_PLATFORM_HEADERS ${CMAKE_CURRENT_LIST_DIR}) - -if(APP_PLATFORM STREQUAL "stm32g0b1") - list(APPEND DRONECAN_PLATFORM_SOURCES ${CMAKE_CURRENT_LIST_DIR}/stm32g0b1.cpp) -elseif(APP_PLATFORM STREQUAL "stm32h753xx") - list(APPEND DRONECAN_PLATFORM_SOURCES ${CMAKE_CURRENT_LIST_DIR}/stm32h753xx.cpp) -else() - message(FATAL_ERROR "FDCAN DroneCAN platform is unsupported for APP_PLATFORM='${APP_PLATFORM}'.") -endif() diff --git a/platform_specific/fdcan/fdcan_config.h b/platform_specific/fdcan/fdcan_config.h deleted file mode 100644 index a7f3461..0000000 --- a/platform_specific/fdcan/fdcan_config.h +++ /dev/null @@ -1,25 +0,0 @@ -#ifndef LIBDCNODE_PLATFORM_SPECIFIC_FDCAN_CONFIG_H_ -#define LIBDCNODE_PLATFORM_SPECIFIC_FDCAN_CONFIG_H_ - -#include -#include - -#include "main.h" - -#ifdef __cplusplus -extern "C" { -#endif - -typedef struct { - FDCAN_HandleTypeDef* handle; - uint8_t interface_id; -} DronecanFdcanInterfaceConfig; - -int16_t dronecanFdcanConfigure(const DronecanFdcanInterfaceConfig* interfaces, - size_t interface_count); - -#ifdef __cplusplus -} -#endif - -#endif // LIBDCNODE_PLATFORM_SPECIFIC_FDCAN_CONFIG_H_ diff --git a/platform_specific/fdcan/stm32g0b1.cpp b/platform_specific/fdcan/stm32g0b1.cpp deleted file mode 100644 index a9a23dd..0000000 --- a/platform_specific/fdcan/stm32g0b1.cpp +++ /dev/null @@ -1,151 +0,0 @@ -/* - * Copyright (C) 2023 Dmitry Ponomarev - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - */ - -#include "libdcnode/can_driver.h" -#include "fdcan_config.h" - -#include - -namespace { - -constexpr size_t MAX_INTERFACES = 2U; - -struct CanDriver { - FDCAN_HandleTypeDef* handler; - FDCAN_TxHeaderTypeDef tx_header; - uint8_t interface_id; - uint8_t rx_buf[8]; - size_t err_counter; - size_t tx_counter; - size_t rx_counter; -}; - -CanDriver drivers[MAX_INTERFACES]{}; -size_t driver_count = 0U; -bool started = false; - -bool isConfigurationValid(const DronecanFdcanInterfaceConfig* interfaces, - const size_t interface_count) { - if (interfaces == nullptr || interface_count == 0U || interface_count > MAX_INTERFACES) { - return false; - } - for (size_t idx = 0U; idx < interface_count; idx++) { - if (interfaces[idx].handle == nullptr) { - return false; - } - for (size_t other = 0U; other < idx; other++) { - if (interfaces[idx].handle == interfaces[other].handle || - interfaces[idx].interface_id == interfaces[other].interface_id) { - return false; - } - } - } - return true; -} - -} // namespace - -extern "C" int16_t dronecanFdcanConfigure( - const DronecanFdcanInterfaceConfig* interfaces, - const size_t interface_count) { - if (started || !isConfigurationValid(interfaces, interface_count)) { - return -1; - } - - drivers[0] = {}; - drivers[1] = {}; - driver_count = interface_count; - for (size_t idx = 0U; idx < interface_count; idx++) { - drivers[idx].handler = interfaces[idx].handle; - drivers[idx].interface_id = interfaces[idx].interface_id; - } - return 0; -} - -extern "C" void canDriverSetInterfaceName(const char* interface_name) { - (void)interface_name; -} - -extern "C" int16_t canDriverInit(uint32_t can_speed, uint8_t can_driver_idx) { - (void)can_speed; - if (can_driver_idx >= driver_count) { - return -1; - } - - CanDriver& driver = drivers[can_driver_idx]; - driver.tx_header.IdType = FDCAN_EXTENDED_ID; - driver.tx_header.TxFrameType = FDCAN_DATA_FRAME; - driver.tx_header.ErrorStateIndicator = FDCAN_ESI_ACTIVE; - driver.tx_header.BitRateSwitch = FDCAN_BRS_OFF; - driver.tx_header.FDFormat = FDCAN_CLASSIC_CAN; - driver.tx_header.TxEventFifoControl = FDCAN_NO_TX_EVENTS; - driver.tx_header.MessageMarker = 0U; - - FDCAN_FilterTypeDef filter_config{}; - filter_config.IdType = FDCAN_EXTENDED_ID; - filter_config.FilterIndex = 0U; - filter_config.FilterType = FDCAN_FILTER_MASK; - filter_config.FilterConfig = FDCAN_FILTER_DISABLE; - - if (HAL_FDCAN_ConfigFilter(driver.handler, &filter_config) != HAL_OK || - HAL_FDCAN_Start(driver.handler) != HAL_OK) { - return -1; - } - - started = true; - return 0; -} - -extern "C" int16_t canDriverReceive(CanardCANFrame* const rx_frame, - uint8_t can_driver_idx) { - if (rx_frame == nullptr || can_driver_idx >= driver_count) { - return 0; - } - - CanDriver& driver = drivers[can_driver_idx]; - FDCAN_RxHeaderTypeDef rx_header{}; - if (HAL_FDCAN_GetRxMessage(driver.handler, - FDCAN_RX_FIFO0, - &rx_header, - driver.rx_buf) != HAL_OK) { - return 0; - } - - driver.rx_counter++; - rx_frame->id = (CANARD_CAN_EXT_ID_MASK & rx_header.Identifier) | CANARD_CAN_FRAME_EFF; - rx_frame->data_len = static_cast(rx_header.DataLength >> 16U); - rx_frame->iface_id = driver.interface_id; - memcpy(rx_frame->data, driver.rx_buf, rx_frame->data_len); - return 1; -} - -extern "C" int16_t canDriverTransmit(const CanardCANFrame* const tx_frame, - uint8_t can_driver_idx) { - if (tx_frame == nullptr || can_driver_idx >= driver_count) { - return 0; - } - - CanDriver& driver = drivers[can_driver_idx]; - driver.tx_header.Identifier = tx_frame->id; - driver.tx_header.DataLength = static_cast(tx_frame->data_len) << 16U; - if (HAL_FDCAN_AddMessageToTxFifoQ(driver.handler, - &driver.tx_header, - const_cast(tx_frame->data)) != HAL_OK) { - return 0; - } - - driver.tx_counter++; - return 1; -} - -extern "C" uint64_t canDriverGetErrorCount() { - return driver_count > 0U ? drivers[0].err_counter : 0U; -} - -extern "C" uint64_t canDriverGetRxOverflowCount() { - return 0U; -} diff --git a/platform_specific/fdcan/stm32h753xx.cpp b/platform_specific/fdcan/stm32h753xx.cpp deleted file mode 100644 index 7ce9273..0000000 --- a/platform_specific/fdcan/stm32h753xx.cpp +++ /dev/null @@ -1,177 +0,0 @@ -/* - * Copyright (C) 2026 Ilia Kliantsevich - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - */ - -#include "libdcnode/can_driver.h" -#include "fdcan_config.h" - -#include - -namespace { - -constexpr size_t MAX_INTERFACES = 2U; - -struct CanDriver { - FDCAN_HandleTypeDef* handler; - FDCAN_TxHeaderTypeDef tx_header; - uint8_t interface_id; - uint8_t rx_buf[8]; - uint32_t err_counter; - uint32_t tx_counter; - uint32_t rx_counter; -}; - -CanDriver drivers[MAX_INTERFACES]{}; -size_t driver_count = 0U; -bool started = false; -size_t next_receive = 0U; - -bool isConfigurationValid(const DronecanFdcanInterfaceConfig* interfaces, - const size_t interface_count) { - if (interfaces == nullptr || interface_count == 0U || interface_count > MAX_INTERFACES) { - return false; - } - for (size_t idx = 0U; idx < interface_count; idx++) { - if (interfaces[idx].handle == nullptr) { - return false; - } - for (size_t other = 0U; other < idx; other++) { - if (interfaces[idx].handle == interfaces[other].handle || - interfaces[idx].interface_id == interfaces[other].interface_id) { - return false; - } - } - } - return true; -} - -void initializeTxHeader(FDCAN_TxHeaderTypeDef& header) { - header = {}; - header.IdType = FDCAN_EXTENDED_ID; - header.TxFrameType = FDCAN_DATA_FRAME; - header.ErrorStateIndicator = FDCAN_ESI_ACTIVE; - header.BitRateSwitch = FDCAN_BRS_OFF; - header.FDFormat = FDCAN_CLASSIC_CAN; - header.TxEventFifoControl = FDCAN_NO_TX_EVENTS; -} - -} // namespace - -extern "C" int16_t dronecanFdcanConfigure( - const DronecanFdcanInterfaceConfig* interfaces, - const size_t interface_count) { - if (started || !isConfigurationValid(interfaces, interface_count)) { - return -1; - } - drivers[0] = {}; - drivers[1] = {}; - driver_count = interface_count; - next_receive = 0U; - for (size_t idx = 0U; idx < interface_count; idx++) { - drivers[idx].handler = interfaces[idx].handle; - drivers[idx].interface_id = interfaces[idx].interface_id; - } - return 0; -} - -extern "C" void canDriverSetInterfaceName(const char* interface_name) { - (void)interface_name; -} - -extern "C" int16_t canDriverInit(uint32_t can_speed, uint8_t can_driver_idx) { - (void)can_speed; - if (can_driver_idx != CAN_DRIVER_FIRST || driver_count == 0U || started) { - return -1; - } - for (size_t idx = 0U; idx < driver_count; idx++) { - initializeTxHeader(drivers[idx].tx_header); - if (HAL_FDCAN_ConfigGlobalFilter(drivers[idx].handler, - FDCAN_ACCEPT_IN_RX_FIFO0, - FDCAN_ACCEPT_IN_RX_FIFO0, - FDCAN_REJECT_REMOTE, - FDCAN_REJECT_REMOTE) != HAL_OK || - HAL_FDCAN_Start(drivers[idx].handler) != HAL_OK) { - drivers[idx].err_counter++; - return -1; - } - } - started = true; - return 0; -} - -extern "C" int16_t canDriverReceive(CanardCANFrame* const rx_frame, - uint8_t can_driver_idx) { - if (rx_frame == nullptr || can_driver_idx != CAN_DRIVER_FIRST || !started) { - return 0; - } - for (size_t attempt = 0U; attempt < driver_count; attempt++) { - const size_t idx = (next_receive + attempt) % driver_count; - FDCAN_RxHeaderTypeDef header{}; - if (HAL_FDCAN_GetRxMessage(drivers[idx].handler, - FDCAN_RX_FIFO0, - &header, - drivers[idx].rx_buf) != HAL_OK) { - continue; - } - if (header.IdType != FDCAN_EXTENDED_ID || header.RxFrameType != FDCAN_DATA_FRAME || - header.FDFormat != FDCAN_CLASSIC_CAN) { - drivers[idx].err_counter++; - continue; - } - const uint8_t data_len = static_cast(header.DataLength); - if (data_len > sizeof(rx_frame->data)) { - drivers[idx].err_counter++; - continue; - } - rx_frame->id = (header.Identifier & CANARD_CAN_EXT_ID_MASK) | CANARD_CAN_FRAME_EFF; - rx_frame->data_len = data_len; - rx_frame->iface_id = drivers[idx].interface_id; - memcpy(rx_frame->data, drivers[idx].rx_buf, data_len); - drivers[idx].rx_counter++; - next_receive = (idx + 1U) % driver_count; - return 1; - } - return 0; -} - -extern "C" int16_t canDriverTransmit(const CanardCANFrame* const tx_frame, - uint8_t can_driver_idx) { - if (tx_frame == nullptr || can_driver_idx != CAN_DRIVER_FIRST || !started || - tx_frame->data_len > sizeof(tx_frame->data)) { - return 0; - } - bool sent = false; - for (size_t idx = 0U; idx < driver_count; idx++) { - drivers[idx].tx_header.Identifier = tx_frame->id & CANARD_CAN_EXT_ID_MASK; - drivers[idx].tx_header.DataLength = tx_frame->data_len; - if (HAL_FDCAN_AddMessageToTxFifoQ(drivers[idx].handler, - &drivers[idx].tx_header, - const_cast(tx_frame->data)) == HAL_OK) { - drivers[idx].tx_counter++; - sent = true; - } else { - drivers[idx].err_counter++; - } - } - return sent ? 1 : 0; -} - -extern "C" uint64_t canDriverGetErrorCount() { - uint64_t errors = 0U; - for (size_t idx = 0U; idx < driver_count; idx++) { - FDCAN_ProtocolStatusTypeDef protocol{}; - FDCAN_ErrorCountersTypeDef counters{}; - (void)HAL_FDCAN_GetProtocolStatus(drivers[idx].handler, &protocol); - (void)HAL_FDCAN_GetErrorCounters(drivers[idx].handler, &counters); - errors += drivers[idx].err_counter + protocol.BusOff + protocol.Warning + - protocol.ErrorPassive + counters.TxErrorCnt + counters.RxErrorCnt; - } - return errors; -} - -extern "C" uint64_t canDriverGetRxOverflowCount() { - return 0U; -}