diff --git a/.github/workflows/UnitTestsHOOTL.yml b/.github/workflows/UnitTestsHOOTL.yml index 93a480a81..0a61a96f1 100644 --- a/.github/workflows/UnitTestsHOOTL.yml +++ b/.github/workflows/UnitTestsHOOTL.yml @@ -32,6 +32,7 @@ jobs: SCCACHE_LOG: "info" SCCACHE_ERROR_LOG: ${{ github.workspace }}/sccache-error.log SCCACHE_SERVER_PORT: ${{ matrix.prefix == 'Debug' && '4226' || (matrix.prefix == 'Release' && '4227' || (matrix.prefix == 'MinSizeRel' && '4228' || '4229')) }} + FETCHCONTENT_DIR: ${{ github.workspace }}/Lib/Vendor/FetchContent steps: - name: Checkout Repository uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 @@ -43,14 +44,24 @@ jobs: with: release: ${{ env.ARM_GCC_VERSION }} + - name: Setup FetchContent Cache + continue-on-error: true + uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0 + with: + path: ${{ env.FETCHCONTENT_DIR }} + key: fetchcontent-${{ runner.os }}-${{ hashFiles('Lib/cmake/cube.cmake', 'CMakeLists.txt', 'Testbench/testbench.cmake') }} + restore-keys: | + fetchcontent-${{ runner.os }}- + - name: Setup Cache id: cache-setup continue-on-error: true uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0 with: path: ${{ env.SCCACHE_DIR }} - key: sccache-${{ runner.os }}-${{ env.ARM_GCC_VERSION }}-${{ github.job }}-${{ matrix.prefix }}-${{ github.ref_name }} + key: sccache-${{ runner.os }}-${{ env.ARM_GCC_VERSION }}-${{ github.job }}-${{ matrix.prefix }}-${{ github.ref_name }}-${{ github.sha }} restore-keys: | + sccache-${{ runner.os }}-${{ env.ARM_GCC_VERSION }}-${{ github.job }}-${{ matrix.prefix }}-${{ github.ref_name }}-${{ github.sha }} sccache-${{ runner.os }}-${{ env.ARM_GCC_VERSION }}-${{ github.job }}-${{ matrix.prefix }}-${{ github.ref_name }} sccache-${{ runner.os }}-${{ env.ARM_GCC_VERSION }}-${{ github.job }}-${{ matrix.prefix }}-main sccache-${{ runner.os }}-${{ env.ARM_GCC_VERSION }}-${{ github.job }}-${{ matrix.prefix }}- @@ -199,12 +210,22 @@ jobs: SCCACHE_DIR: ${{ github.workspace }}/sccache SCCACHE_LOG: "info" SCCACHE_ERROR_LOG: ${{ github.workspace }}/sccache-error.log + FETCHCONTENT_DIR: ${{ github.workspace }}/Lib/Vendor/FetchContent steps: - name: Checkout Repository uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: fetch-depth: 1 + - name: Setup FetchContent Cache + continue-on-error: true + uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0 + with: + path: ${{ env.FETCHCONTENT_DIR }} + key: fetchcontent-${{ runner.os }}-${{ hashFiles('Lib/cmake/cube.cmake', 'CMakeLists.txt', 'Testbench/testbench.cmake', 'BLINKY/blinky.cmake') }} + restore-keys: | + fetchcontent-${{ runner.os }}- + - name: Setup Cache id: cache-setup continue-on-error: true diff --git a/CMakeLists.txt b/CMakeLists.txt index eec67ef56..975552ca8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,9 +1,5 @@ cmake_minimum_required(VERSION 3.25) project(Firmware) -enable_language( - C - ASM -) set(CMAKE_C_STANDARD 11) set(CMAKE_C_STANDARD_REQUIRED ON) set(CMAKE_C_EXTENSIONS ON) @@ -106,6 +102,11 @@ else() message(STATUS "Not using ccache: ccache not found in PATH") endif() +enable_language( + C + ASM +) + # Globals set(LIB_PATH "Lib") set(platform_path "${LIB_PATH}/Platform") diff --git a/Lib/Peripherals/CubeCAN/Inc/CubeCAN.h b/Lib/Peripherals/CubeCAN/Inc/CubeCAN.h index 0f609862b..c13cf0dfa 100644 --- a/Lib/Peripherals/CubeCAN/Inc/CubeCAN.h +++ b/Lib/Peripherals/CubeCAN/Inc/CubeCAN.h @@ -24,7 +24,8 @@ typedef struct CubeCAN_Private_Handle CubeCAN_Handle; * This union allows for easy access to the individual components of a CAN identifier, including the receive node ID, message ID, and transmit node ID. * It also provides a raw 32-bit representation of the identifier which can be used to specify custom CAN IDs. * - * @warning The values of the fields are not validated and may not represent a valid CAN identifier. It is the responsibility of the user to ensure that the values are valid and conform to the CAN protocol. + * @warning The values of the fields are not validated and may not represent a valid CAN identifier. It is the responsibility of the user to ensure that the values are valid and conform to the CAN + * protocol. * @warning Do not use the _ field directly, as it may lead to undefined behavior. Use the provided fields instead. * * @note Setting any bit past the 29th bit is undefined behavior and may lead to unexpected results. @@ -39,7 +40,7 @@ typedef union { GRCAN_NODE_ID tx_node_id : 8; uint32_t _ : 4; }; -} CAN_Identifier; +} CubeCAN_Identifier; /** * @brief Union for user-defined context data in CubeCAN configuration. @@ -64,7 +65,7 @@ typedef union { * @warning The callback function should not call any CubeCAN functions, as it may lead to undefined behavior. * @warning It is the responsibility of the callback function to verify the integrity of the received data and handle any errors or null inputs. */ -typedef void (*CubeCAN_RxCallback)(const CubeCAN_Config_Context *const context, const CAN_Identifier *const identifier, const uint8_t *const data, const uint8_t size); +typedef void (*CubeCAN_RxCallback)(const CubeCAN_Config_Context *const context, const CubeCAN_Identifier *const identifier, const uint8_t *const data, const uint8_t size); /** * @brief Configuration structure for CubeCAN CAN. @@ -112,6 +113,17 @@ HAL_StatusTypeDef CubeCAN_Exit(CubeCAN_Handle *handle); */ void CubeCAN_Tick(void); +/** + * @brief Sends a CAN message using the CubeCAN CAN handle, with the specified custom identifier, data payload, and size. + * @param handle Pointer to the CubeCAN CAN handle. + * @param custom_id The custom identifier for the message. + * @param data Pointer to the data payload of the message. + * @param size The size of the data payload in bytes. + * @return HAL_StatusTypeDef indicating the success or failure of the operation. + * @note The size of the data payload must not exceed FDCAN_MAX_DATA_BYTES (64 bytes). If the size exceeds this limit, the function will return HAL_ERROR. + */ +HAL_StatusTypeDef CubeCAN_Send_Custom(CubeCAN_Handle *const handle, const GRCAN_CUSTOM_ID custom_id, const void *const data, const uint8_t size); + /** * @brief Sends a CAN message using the CubeCAN CAN handle, with the specified receive node, message ID, data payload, and size. * @param handle Pointer to the CubeCAN CAN handle. @@ -124,25 +136,4 @@ void CubeCAN_Tick(void); */ HAL_StatusTypeDef CubeCAN_Send(CubeCAN_Handle *const handle, const GRCAN_NODE_ID rx_node, const GRCAN_MSG_ID msg_id, const void *const data, const uint8_t size); -/** - * @brief Constructs a CAN message identifier from the given transmitting node ID, receiving node ID, and message ID. - * - * @param identifier Pointer to the CAN_Identifier structure containing the node and message IDs. - * - * @return The constructed 29-bit CAN message extended identifier. - */ -uint32_t CubeCAN_Construct_Identifier(const CAN_Identifier *const identifier); - -/** - * @brief Deconstructs a 29-bit CAN message extended identifier into its constituent transmitting node ID, receiving node ID, and message ID. - * - * @param message_id The 29-bit CAN message extended identifier to be deconstructed. - * - * @return A CAN_Identifier structure containing the deconstructed node and message IDs. - * - * @warning The function does not guarantee that the returned structure will represent a valid CAN message identifier. - * @warning The function does not support custom IDs. - */ -CAN_Identifier CubeCAN_Deconstruct_Identifier(const uint32_t message_id); - #endif diff --git a/Lib/Peripherals/CubeCAN/README.md b/Lib/Peripherals/CubeCAN/README.md index 45c9dbecf..72f6df673 100644 --- a/Lib/Peripherals/CubeCAN/README.md +++ b/Lib/Peripherals/CubeCAN/README.md @@ -36,7 +36,7 @@ Add a file named `CubeCAN_Config.h` to your project, generally `Application/Inc/ #### Configuration Requirements -- `CUBEMX_CAN_TX_QUEUE_SIZE`: Must be a power of two. Defines the transmission queue depth; when the queue fills, the oldest message is dropped and `CubeCAN_Send()` returns `HAL_BUSY`. +- `CUBEMX_CAN_TX_QUEUE_SIZE`: Must be a power of two. Defines the transmission queue depth; when the queue fills, the oldest message is dropped and `CubeCAN_Send()` and `CubeCAN_Send_Custom()` return `HAL_BUSY`. - `CUBEMX_CAN_MAX_INSTANCES`: Must be 1-3 depending on your chip's available FDCAN peripherals. Omit this definition to automatically select the maximum supported by your MCU. From there just ensure that you have configured CAN through STM32CubeMX and setup a global variable for each `CubeCAN_Handle` you wish to use. @@ -59,7 +59,7 @@ Ensure you have setup some mechanism to call `CubeCAN_Tick()` frequently (a STM3 #### Transmission -Call `CubeCAN_Send()` to queue a message for transmission. Messages are queued in a lock-free ring buffer and processed in FIFO order. +Call `CubeCAN_Send()` or `CubeCAN_Send_Custom()` to queue a message for transmission. Messages are queued in a lock-free ring buffer and processed in FIFO order. - **Returns `HAL_OK`**: Message successfully queued - **Returns `HAL_BUSY`**: Transmission queue is full; the oldest queued message was dropped to make room for the new one @@ -91,7 +91,7 @@ flowchart TD Entrance --> Choice{"Functions"} Choice --> Exit(["CubeCAN_Exit()"]) Exit -.-> |"AVOID"| Entrance - Choice --> Send(["CubeCAN_Send()"]) + Choice --> Send(["CubeCAN_Send()\nCubeCAN_Send_Custom()"]) Choice --> |"Call Often\n(User Setup)"| Tick(["CubeCAN_Tick()"]) Send -.-> Queue("CubeCAN_Private_QueueTx()") Data -.-> Tick @@ -126,7 +126,7 @@ CubeCAN is designed to handle concurrent access from multiple execution contexts #### Overview - `tx_head` and `tx_tail` are atomic `uint32_t` variables that implement a lock-free ring buffer -- `CubeCAN_Send()` and `CubeCAN_Tick()` use critical sections (interrupt blocking) when necessary +- `CubeCAN_Send()`, `CubeCAN_Send_Custom()`, and `CubeCAN_Tick()` use critical sections (interrupt blocking) when necessary - Atomic operations use `memory_order_relaxed` within ISRs and `memory_order_release`/`memory_order_acquire` for inter-context synchronization - The queue size must be a power of two, allowing fast wraparound via bitwise AND instead of expensive modulo operations @@ -139,7 +139,7 @@ Interrupt protection is used only in: #### ISR Interaction -- Safe to call `CubeCAN_Send()` from `main()` or any ISR +- Safe to call `CubeCAN_Send()` or `CubeCAN_Send_Custom()` from `main()` or any ISR - Safe to call `CubeCAN_Tick()` from `main()` or any ISR - Do not call any CubeCAN function from `CubeCAN_RxCallback()`, use it only to write data to shared memory (with concurrency safety as needed) @@ -184,7 +184,7 @@ We currently provide compile time static assertions to validate: - `CUBEMX_CAN_TX_QUEUE_SIZE` is a power of two and non-zero (allows faster ring-buffer wrapping) - `CUBEMX_CAN_MAX_INSTANCES` requires management of 1 to 3 interfaces (optional parameter, otherwise automatically chooses the maximum possible) -A single runtime check `CubeCAN_Private_InternalOneTimeChecks()` is called once on first call to `CubeCAN_Entrance()` which validates that the compiled bit-packing for `CAN_Identifier` is correct, if it is not the CAN peripheral entrance fails and returns `null`. Sadly this cannot be a compile-time check. +A single runtime check `CubeCAN_Private_InternalOneTimeChecks()` is called once on first call to `CubeCAN_Entrance()` which validates that the compiled bit-packing for `CubeCAN_Identifier` is correct, if it is not the CAN peripheral entrance fails and returns `null`. Sadly this cannot be a compile-time check. ### Globals diff --git a/Lib/Peripherals/CubeCAN/Src/PrivateInc/internal.h b/Lib/Peripherals/CubeCAN/Src/PrivateInc/internal.h index 2579c6185..fb9e57fd6 100644 --- a/Lib/Peripherals/CubeCAN/Src/PrivateInc/internal.h +++ b/Lib/Peripherals/CubeCAN/Src/PrivateInc/internal.h @@ -120,7 +120,7 @@ HAL_StatusTypeDef CubeCAN_Private_InternalOneTimeChecks(void); * @param handle Pointer to the CubeCAN CAN handle. * @return HAL_StatusTypeDef indicating the success or failure of the operation. */ -HAL_StatusTypeDef CubeCAN_Private_SendQueuedMessage(const CubeCAN_Handle *const handle); +HAL_StatusTypeDef CubeCAN_Private_SendQueuedMessage(CubeCAN_Handle *const handle); /** * @brief Attempts to recover the FDCAN peripheral associated with the given CubeCAN CAN handle. @@ -193,4 +193,15 @@ HAL_StatusTypeDef CubeCAN_Private_Stop(CubeCAN_Handle *const handle); */ HAL_StatusTypeDef CubeCAN_Private_Release(CubeCAN_Handle *const handle); +/** + * @brief Sends a CAN message using the CubeCAN CAN handle, with the specified identifier, data payload, and size. + * @param handle Pointer to the CubeCAN CAN handle. + * @param id The identifier for the message. + * @param data Pointer to the data payload of the message. + * @param size The size of the data payload in bytes. + * @return HAL_StatusTypeDef indicating the success or failure of the operation. + * @note The size of the data payload must not exceed FDCAN_MAX_DATA_BYTES (64 bytes). If the size exceeds this limit, the function will return HAL_ERROR. + */ +HAL_StatusTypeDef CubeCAN_Private_Send(CubeCAN_Handle *const handle, const CubeCAN_Identifier id, const void *const data, const uint8_t size); + #endif diff --git a/Lib/Peripherals/CubeCAN/Src/can_assert.c b/Lib/Peripherals/CubeCAN/Src/can_assert.c index 22090a2c2..4119e6e83 100644 --- a/Lib/Peripherals/CubeCAN/Src/can_assert.c +++ b/Lib/Peripherals/CubeCAN/Src/can_assert.c @@ -27,4 +27,4 @@ static_assert(CUBEMX_CAN_MAX_INSTANCES >= 1 && CUBEMX_CAN_MAX_INSTANCES <= 3, "C static_assert(sizeof(GRCAN_BUS_ID) <= sizeof(void *), "GRCAN_BUS_ID must fit within a pointer-sized type to support being unioned with a pointer in CubeCAN_Config"); -static_assert(sizeof(CAN_Identifier) == sizeof(uint32_t), "CAN_Identifier must be 32 bits in size"); +static_assert(sizeof(CubeCAN_Identifier) == sizeof(uint32_t), "CAN_Identifier must be 32 bits in size"); diff --git a/Lib/Peripherals/CubeCAN/Src/can_init.c b/Lib/Peripherals/CubeCAN/Src/can_init.c index d5c178136..3a5cd7a1c 100644 --- a/Lib/Peripherals/CubeCAN/Src/can_init.c +++ b/Lib/Peripherals/CubeCAN/Src/can_init.c @@ -13,15 +13,19 @@ static bool cubecan_internal_checks_passed = false; HAL_StatusTypeDef CubeCAN_Private_InternalOneTimeChecks(void) { - CAN_Identifier test_id = {.raw_id = 0x01122233}; + CubeCAN_Identifier test_id = {.raw_id = 0x01122233}; if (test_id._ != 0 || test_id.tx_node_id != 0x11 || test_id.msg_id != 0x222 || test_id.rx_node_id != 0x33) { - LOGOMATIC_ERROR("CubeCAN_Private_InternalOneTimeChecks: CAN_Identifier bitfield order is incorrect on this platform, expected TX ID 0x11, MSG ID 0x222, RX ID 0x33 for raw_id 0x01122233, got TX ID 0x%02X, MSG ID 0x%03X, RX ID 0x%02X\n", test_id.tx_node_id, test_id.msg_id, test_id.rx_node_id); + LOGOMATIC_ERROR("CubeCAN_Private_InternalOneTimeChecks: CAN_Identifier bitfield order is incorrect on this platform, expected TX ID 0x11, MSG ID 0x222, RX ID 0x33 for raw_id " + "0x01122233, got TX ID 0x%02X, MSG ID 0x%03X, RX ID 0x%02X\n", + test_id.tx_node_id, test_id.msg_id, test_id.rx_node_id); return HAL_ERROR; } test_id.raw_id = 0xA013FF; if (test_id._ != 0 || test_id.tx_node_id != 0x0A || test_id.msg_id != 0x013 || test_id.rx_node_id != 0xFF) { - LOGOMATIC_ERROR("CubeCAN_Private_InternalOneTimeChecks: CAN_Identifier bitfield order is incorrect on this platform, expected TX ID 0x0A, MSG ID 0x013, RX ID 0xFF for raw_id 0x0A013FF, got TX ID 0x%02X, MSG ID 0x%03X, RX ID 0x%02X\n", test_id.tx_node_id, test_id.msg_id, test_id.rx_node_id); + LOGOMATIC_ERROR("CubeCAN_Private_InternalOneTimeChecks: CAN_Identifier bitfield order is incorrect on this platform, expected TX ID 0x0A, MSG ID 0x013, RX ID 0xFF for raw_id " + "0x0A013FF, got TX ID 0x%02X, MSG ID 0x%03X, RX ID 0x%02X\n", + test_id.tx_node_id, test_id.msg_id, test_id.rx_node_id); return HAL_ERROR; } diff --git a/Lib/Peripherals/CubeCAN/Src/can_rx.c b/Lib/Peripherals/CubeCAN/Src/can_rx.c index 2e345b0a6..d752644c7 100644 --- a/Lib/Peripherals/CubeCAN/Src/can_rx.c +++ b/Lib/Peripherals/CubeCAN/Src/can_rx.c @@ -51,7 +51,7 @@ void HAL_FDCAN_RxFifo0Callback(FDCAN_HandleTypeDef *hfdcan, uint32_t RxFifo0ITs) while (HAL_FDCAN_GetRxFifoFillLevel(hfdcan, FDCAN_RX_FIFO0) > 0U) { if (HAL_FDCAN_GetRxMessage(hfdcan, FDCAN_RX_FIFO0, &rx_header, rx_data) == HAL_OK) { - CAN_Identifier id = {.raw_id = rx_header.Identifier}; + CubeCAN_Identifier id = {.raw_id = rx_header.Identifier}; uint8_t size = CubeCAN_Private_DlcToBytes(rx_header.DataLength); rx_callback(&context, &id, rx_data, size); } else { diff --git a/Lib/Peripherals/CubeCAN/Src/can_tx.c b/Lib/Peripherals/CubeCAN/Src/can_tx.c index b72ea2a0d..ba44adb3a 100644 --- a/Lib/Peripherals/CubeCAN/Src/can_tx.c +++ b/Lib/Peripherals/CubeCAN/Src/can_tx.c @@ -6,6 +6,7 @@ #include "CriticalSection.h" #include "CubeCAN.h" #include "CubeCAN_Config.h" +#include "GRCAN_CUSTOM_ID.h" #include "Logomatic.h" #include "PrivateInc/internal.h" #include "main.h" @@ -71,7 +72,7 @@ void CubeCAN_Tick(void) } } -HAL_StatusTypeDef CubeCAN_Send(CubeCAN_Handle *const handle, const GRCAN_NODE_ID rx_node, const GRCAN_MSG_ID msg_id, const void *const data, const uint8_t size) +HAL_StatusTypeDef CubeCAN_Private_Send(CubeCAN_Handle *const handle, const CubeCAN_Identifier id, const void *const data, const uint8_t size) { if (handle == NULL || data == NULL || size > FDCAN_MAX_DATA_BYTES) { return HAL_ERROR; @@ -103,13 +104,11 @@ HAL_StatusTypeDef CubeCAN_Send(CubeCAN_Handle *const handle, const GRCAN_NODE_ID return HAL_ERROR; } - const CAN_Identifier identifier_struct = {.tx_node_id = handle->config.sending_node_id, .rx_node_id = rx_node, .msg_id = msg_id}; - const FDCAN_TxHeaderTypeDef header = {.BitRateSwitch = brs, .DataLength = dlc, .ErrorStateIndicator = FDCAN_ESI_ACTIVE, .FDFormat = fdformat, - .Identifier = identifier_struct.raw_id, + .Identifier = id.raw_id, .IdType = FDCAN_EXTENDED_ID, .MessageMarker = 0U, // TODO We can do cool things with this to track transmission queue statistics .TxEventFifoControl = FDCAN_NO_TX_EVENTS, @@ -121,6 +120,22 @@ HAL_StatusTypeDef CubeCAN_Send(CubeCAN_Handle *const handle, const GRCAN_NODE_ID return CubeCAN_Private_QueueTx(handle, &message); } +HAL_StatusTypeDef CubeCAN_Send_Custom(CubeCAN_Handle *const handle, const GRCAN_CUSTOM_ID custom_id, const void *const data, const uint8_t size) +{ + CubeCAN_Identifier id = {.raw_id = custom_id}; + return CubeCAN_Private_Send(handle, id, data, size); +} + +HAL_StatusTypeDef CubeCAN_Send(CubeCAN_Handle *const handle, const GRCAN_NODE_ID rx_node, const GRCAN_MSG_ID msg_id, const void *const data, const uint8_t size) +{ + if (handle == NULL) { + return HAL_ERROR; + } + + CubeCAN_Identifier id = {.rx_node_id = rx_node, .msg_id = msg_id, .tx_node_id = handle->config.sending_node_id}; + return CubeCAN_Private_Send(handle, id, data, size); +} + HAL_StatusTypeDef CubeCAN_Private_QueueTx(CubeCAN_Handle *handle, const GRCAN_Private_TxMessage *message) { if (handle == NULL || message == NULL) { @@ -147,7 +162,7 @@ HAL_StatusTypeDef CubeCAN_Private_QueueTx(CubeCAN_Handle *handle, const GRCAN_Pr return status; } -HAL_StatusTypeDef CubeCAN_Private_SendQueuedMessage(const CubeCAN_Handle *const handle) +HAL_StatusTypeDef CubeCAN_Private_SendQueuedMessage(CubeCAN_Handle *const handle) { if (handle == NULL || handle->hfdcan == NULL) { LOGOMATIC_ERROR("CubeCAN_Private_SendQueuedMessage: invalid null parameter\n"); diff --git a/Lib/Peripherals/CubeCAN/Test/cubecan_rx_failure_test.c b/Lib/Peripherals/CubeCAN/Test/cubecan_rx_failure_test.c index 99df49a48..368de41f6 100644 --- a/Lib/Peripherals/CubeCAN/Test/cubecan_rx_failure_test.c +++ b/Lib/Peripherals/CubeCAN/Test/cubecan_rx_failure_test.c @@ -7,7 +7,7 @@ static uint32_t callback_count; -static void receive_callback(const CubeCAN_Config_Context *context, const CAN_Identifier *identifier, const uint8_t *data, uint8_t size) +static void receive_callback(const CubeCAN_Config_Context *context, const CubeCAN_Identifier *identifier, const uint8_t *data, uint8_t size) { UNUSED(context); UNUSED(identifier); diff --git a/Lib/Peripherals/CubeCAN/Test/cubecan_rx_test.c b/Lib/Peripherals/CubeCAN/Test/cubecan_rx_test.c index c391a041b..313030eb5 100644 --- a/Lib/Peripherals/CubeCAN/Test/cubecan_rx_test.c +++ b/Lib/Peripherals/CubeCAN/Test/cubecan_rx_test.c @@ -6,12 +6,12 @@ #include "main.h" static uint32_t callback_count; -static CAN_Identifier callback_ids[2]; +static CubeCAN_Identifier callback_ids[2]; static uint8_t callback_data[2][64]; static uint8_t callback_sizes[2]; static uint32_t callback_context; -static void receive_callback(const CubeCAN_Config_Context *context, const CAN_Identifier *identifier, const uint8_t *data, uint8_t size) +static void receive_callback(const CubeCAN_Config_Context *context, const CubeCAN_Identifier *identifier, const uint8_t *data, uint8_t size) { const uint32_t index = callback_count++; callback_context = context->busid_user_context; diff --git a/Lib/Peripherals/CubeCAN/Test/cubecan_utils_test.c b/Lib/Peripherals/CubeCAN/Test/cubecan_utils_test.c index 149eba222..9ef0f2472 100644 --- a/Lib/Peripherals/CubeCAN/Test/cubecan_utils_test.c +++ b/Lib/Peripherals/CubeCAN/Test/cubecan_utils_test.c @@ -17,13 +17,13 @@ int main(void) assert(CubeCAN_Private_BytesToDlc(11U) == FDCAN_DLC_BYTES_0 && "Unsupported byte counts should be rejected"); assert(CubeCAN_Private_DlcToBytes(0x10U) == 0U && "Unsupported dlc values should map to 0B"); - const CAN_Identifier identifier = {.tx_node_id = GRCAN_TireTemp_FL, .rx_node_id = GRCAN_BrakeTemp_RR, .msg_id = GRCAN_TIRE_TEMP_FRAME_7}; - const CAN_Identifier decoded = {.raw_id = identifier.raw_id}; + const CubeCAN_Identifier identifier = {.tx_node_id = GRCAN_TireTemp_FL, .rx_node_id = GRCAN_BrakeTemp_RR, .msg_id = GRCAN_TIRE_TEMP_FRAME_7}; + const CubeCAN_Identifier decoded = {.raw_id = identifier.raw_id}; assert(decoded.tx_node_id == identifier.tx_node_id && "Identifier round-trip should preserve tx node"); assert(decoded.rx_node_id == identifier.rx_node_id && "Identifier round-trip should preserve rx node"); assert(decoded.msg_id == identifier.msg_id && "Identifier round-trip should preserve message id"); - const CAN_Identifier wire_identifier = {.raw_id = 0x01122233U}; + const CubeCAN_Identifier wire_identifier = {.raw_id = 0x01122233U}; assert(wire_identifier.tx_node_id == 0x11U && "CAN identifier should decode the tx node from the wire format"); assert(wire_identifier.msg_id == 0x222U && "CAN identifier should decode the message id from the wire format"); assert(wire_identifier.rx_node_id == 0x33U && "CAN identifier should decode the rx node from the wire format"); diff --git a/Lib/Utils/CubeVCP/Src/PrivateInc/internal.h b/Lib/Utils/CubeVCP/Src/PrivateInc/internal.h index 71e88bb52..b2fcfdeae 100644 --- a/Lib/Utils/CubeVCP/Src/PrivateInc/internal.h +++ b/Lib/Utils/CubeVCP/Src/PrivateInc/internal.h @@ -106,16 +106,6 @@ extern uint8_t vcp_callback_staging[]; */ extern uint8_t vcp_rx_buffer[]; -/** - * @brief Index of the next byte to be written in the current VCP reception buffer. - * - * This atomic variable is used to keep track of the index where the next byte should be written in the current VCP reception buffer. - * When the buffer fills or a newline is received, the callback is invoked and this index is reset to 0. - * - * @warning Requires atomic operations to ensure thread safety when accessed from multiple contexts - */ -extern uint16_t vcp_rx_index; - /** * @brief Index of the current RX buffer (0 or 1) being written to by the ISR. * diff --git a/Lib/Utils/CubeVCP/Src/vcp_global.c b/Lib/Utils/CubeVCP/Src/vcp_global.c index cc1f0755e..088479a0d 100644 --- a/Lib/Utils/CubeVCP/Src/vcp_global.c +++ b/Lib/Utils/CubeVCP/Src/vcp_global.c @@ -14,7 +14,6 @@ _Atomic uint16_t vcp_ring_head; _Atomic uint16_t vcp_ring_tail; _Atomic bool vcp_tx_active; -uint16_t vcp_rx_index; uint8_t vcp_rx_byte; uint8_t vcp_rx_buffer[CUBE_VCP_RX_BUFFER_SIZE]; uint8_t vcp_callback_staging[CUBE_VCP_RX_BUFFER_SIZE]; diff --git a/Lib/Utils/CubeVCP/Src/vcp_rx.c b/Lib/Utils/CubeVCP/Src/vcp_rx.c index 9255db438..92fdadac0 100644 --- a/Lib/Utils/CubeVCP/Src/vcp_rx.c +++ b/Lib/Utils/CubeVCP/Src/vcp_rx.c @@ -8,6 +8,16 @@ #include "PrivateInc/internal.h" #include "main.h" +/** + * @brief Index of the next byte to be written in the current VCP reception buffer. + * + * This variable is used to keep track of the index where the next byte should be written in the current VCP reception buffer. + * When the buffer fills or a newline is received, the callback is invoked and this index is reset to 0. + * + * @note Does not require atomic operations since it is only accessed from the ISR context. + */ +static uint16_t vcp_rx_index = 0; + HAL_StatusTypeDef CubeVCP_EnableRx(CubeVCP_Rx_Callback callback) { static bool enabled = false; @@ -29,8 +39,7 @@ HAL_StatusTypeDef CubeVCP_EnableRx(CubeVCP_Rx_Callback callback) } vcp_rx_callback = callback; - - atomic_store_explicit(&vcp_rx_index, 0, memory_order_relaxed); + vcp_rx_index = 0; HAL_StatusTypeDef status = HAL_UART_Receive_IT(vcp_uart_handle, &vcp_rx_byte, 1); diff --git a/Lib/Utils/CubeVCP/Test/main.h b/Lib/Utils/CubeVCP/Test/main.h index a185eb320..bc3e4d3d9 100644 --- a/Lib/Utils/CubeVCP/Test/main.h +++ b/Lib/Utils/CubeVCP/Test/main.h @@ -4,7 +4,13 @@ #ifndef CUBEVCP_TEST_MAIN_H #define CUBEVCP_TEST_MAIN_H +#ifndef __weak +#if defined(_WIN32) +#define __weak +#else #define __weak __attribute__((weak)) +#endif +#endif typedef enum { HAL_OK = 0x00, diff --git a/Lib/cmake/HOOTL.cmake b/Lib/cmake/HOOTL.cmake index bd3858b2a..722f5c2de 100644 --- a/Lib/cmake/HOOTL.cmake +++ b/Lib/cmake/HOOTL.cmake @@ -20,7 +20,6 @@ add_compile_options( -fshort-enums -fdata-sections -ffunction-sections - -fstack-usage -fno-lto -Wall -Wextra @@ -37,6 +36,10 @@ else() add_link_options(-Wl,--fatal-warnings) endif() +if(WIN32) # Windows has different bitfield layout and semantics + add_compile_options(-mno-ms-bitfields) +endif() + if(ADDRESS_SANITIZER) message(STATUS "Address sanitizer enabled for tests") diff --git a/Testbench/CUBEMXTESTING/Application/Inc/CANdler.h b/Testbench/CUBEMXTESTING/Application/Inc/CANdler.h index 4950e32d2..8fc54bba0 100644 --- a/Testbench/CUBEMXTESTING/Application/Inc/CANdler.h +++ b/Testbench/CUBEMXTESTING/Application/Inc/CANdler.h @@ -3,7 +3,7 @@ #ifndef CANDLER_H #define CANDLER_H -void CANdler_Callback(const CubeCAN_Config_Context *const context, const CAN_Identifier *const identifier, const uint8_t *const data, const uint8_t size); +void CANdler_Callback(const CubeCAN_Config_Context *const context, const CubeCAN_Identifier *const identifier, const uint8_t *const data, const uint8_t size); void CANdler_VCP_Callback(const uint8_t *const data, const uint16_t size); #endif diff --git a/Testbench/CUBEMXTESTING/Application/Src/CANdler.c b/Testbench/CUBEMXTESTING/Application/Src/CANdler.c index 5e573cdb7..52524ac91 100644 --- a/Testbench/CUBEMXTESTING/Application/Src/CANdler.c +++ b/Testbench/CUBEMXTESTING/Application/Src/CANdler.c @@ -8,7 +8,7 @@ int value; -void CANdler_Callback(const CubeCAN_Config_Context *const context, const CAN_Identifier *const identifier, const uint8_t *const data, const uint8_t size) +void CANdler_Callback(const CubeCAN_Config_Context *const context, const CubeCAN_Identifier *const identifier, const uint8_t *const data, const uint8_t size) { value++; @@ -23,7 +23,7 @@ void CANdler_Callback(const CubeCAN_Config_Context *const context, const CAN_Ide const GRCAN_NODE_ID rx_node = identifier->rx_node_id; const GRCAN_MSG_ID msg_id = identifier->msg_id; - LOGOMATIC_VERBOSE("Received on bus %d with node %d -> %d with message %d and size %u\t%.*s\n", busid, tx_node, rx_node, msg_id, size, size, (const char *const)data); + LOGOMATIC_DEBUG("Received on bus %d with node %d -> %d with message %d and size %u\t%.*s\n", busid, tx_node, rx_node, msg_id, size, size, (const char *const)data); } void CANdler_VCP_Callback(const uint8_t *const data, const uint16_t size)