#include #include #include #define main AppFirmwareMain #define static #include "../Core/Src/main.c" #undef static #undef main #include "../Core/Src/stm32f4xx_it.c" TIM_TypeDef TestTim5; GPIO_TypeDef TestGpioE; GPIO_TypeDef TestGpioF; GPIO_TypeDef TestGpioI; USART_TypeDef TestUsart1; OS_EVENT TestFrameSem; IRQn_Type TestNvicIrq; uint32_t TestNvicPreemptPriority; uint32_t TestNvicSubPriority; uint32_t TestHalTickCallCount; uint32_t TestOsCpuSysTickCallCount; HAL_StatusTypeDef TestReceiveResults[4U]; uint32_t TestReceiveResultCount; uint32_t TestReceiveCallCount; uint32_t TestReceiveErrorInjectionCall; uint32_t TestAbortReceiveCallCount; uint32_t TestUartFlagClearCallCount; uint8_t TestRecoveryCallOrder[4U]; uint32_t TestRecoveryCallOrderLength; uint32_t TestSemPostCallCount; uint8_t OSRunning; static void TestResetFakes(void) { (void)memset(&TestTim5, 0, sizeof(TestTim5)); (void)memset(&TestGpioE, 0, sizeof(TestGpioE)); (void)memset(&TestGpioF, 0, sizeof(TestGpioF)); (void)memset(&TestGpioI, 0, sizeof(TestGpioI)); (void)memset(&TestUsart1, 0, sizeof(TestUsart1)); (void)memset(&TestFrameSem, 0, sizeof(TestFrameSem)); (void)memset(&Uart1Handle, 0, sizeof(Uart1Handle)); (void)memset(TestReceiveResults, 0, sizeof(TestReceiveResults)); TestNvicIrq = 0; TestNvicPreemptPriority = 0U; TestNvicSubPriority = 0U; TestHalTickCallCount = 0U; TestOsCpuSysTickCallCount = 0U; TestReceiveResultCount = 0U; TestReceiveCallCount = 0U; TestReceiveErrorInjectionCall = 0U; TestAbortReceiveCallCount = 0U; TestUartFlagClearCallCount = 0U; (void)memset(TestRecoveryCallOrder, 0, sizeof(TestRecoveryCallOrder)); TestRecoveryCallOrderLength = 0U; TestSemPostCallCount = 0U; OSRunning = 0U; ModbusUartLastErrorCode = 0U; ModbusUartLastRxState = 0U; ModbusUartRecoveryCount = 0U; ModbusUartRecoveryFailureCount = 0U; ModbusUartRxArmCount = 0U; ModbusUartRxArmFailureCount = 0U; ModbusUartLastRxByte = 0U; ModbusLastCompleteFrameLength = 0U; ModbusFrameSem = &TestFrameSem; ModbusReceptionNeedsRecovery = 0U; } static void TestSysTickUsesKernelAwarePriority(void) { TestResetFakes(); AppInitSystemTick(); assert(TestNvicIrq == SysTick_IRQn); assert(TestNvicPreemptPriority == CPU_CFG_KA_IPL_BOUNDARY); assert(TestNvicSubPriority == 0U); } static void TestSysTickDelegatesToOsPort(void) { TestResetFakes(); OSRunning = OS_TRUE; SysTick_Handler(); assert(TestHalTickCallCount == 1U); assert(TestOsCpuSysTickCallCount == 1U); } static void TestReceiveRecoveryRetriesAfterBusy(void) { TestResetFakes(); Uart1Handle.Instance = USART1; TestReceiveResults[0U] = HAL_BUSY; TestReceiveResults[1U] = HAL_OK; TestReceiveResultCount = 2U; assert(AppRecoverUartReception() == HAL_OK); assert(TestReceiveCallCount == 2U); assert(TestAbortReceiveCallCount == 2U); assert(TestRecoveryCallOrderLength == 4U); assert(TestRecoveryCallOrder[0U] == 2U); assert(TestRecoveryCallOrder[1U] == 1U); assert(TestRecoveryCallOrder[2U] == 2U); assert(TestRecoveryCallOrder[3U] == 1U); assert(TestUartFlagClearCallCount == 2U); } static void TestUartErrorClearsFlagsBeforeRecovery(void) { TestResetFakes(); Uart1Handle.Instance = USART1; Uart1Handle.ErrorCode = HAL_UART_ERROR_ORE; HAL_UART_ErrorCallback(&Uart1Handle); assert(ModbusReceptionNeedsRecovery == 1U); assert(TestUartFlagClearCallCount == 1U); assert(TestReceiveCallCount == 0U); } static void TestUartErrorDefersRecoveryToTask(void) { TestResetFakes(); Uart1Handle.Instance = USART1; Uart1Handle.ErrorCode = HAL_UART_ERROR_ORE; HAL_UART_ErrorCallback(&Uart1Handle); assert(ModbusReceptionNeedsRecovery == 1U); assert(TestSemPostCallCount == 1U); assert(TestReceiveCallCount == 0U); } static void TestPendingRecoveryKeepsConcurrentErrorRequest(void) { TestResetFakes(); Uart1Handle.Instance = USART1; ModbusReceptionNeedsRecovery = 1U; TestReceiveErrorInjectionCall = 1U; assert(AppRecoverPendingUartReception() == HAL_OK); assert(TestReceiveCallCount == 1U); assert(TestSemPostCallCount == 1U); assert(ModbusReceptionNeedsRecovery == 1U); } static void TestReceptionWatchdogRearmsWhenHalStateIsLost(void) { TestResetFakes(); Uart1Handle.Instance = USART1; Uart1Handle.RxState = HAL_UART_STATE_READY; TestReceiveResults[0U] = HAL_OK; TestReceiveResultCount = 1U; assert(AppEnsureUartReception() == HAL_OK); assert(TestAbortReceiveCallCount == 1U); assert(TestReceiveCallCount == 1U); assert(ModbusUartRecoveryCount == 1U); } int main(void) { TestSysTickUsesKernelAwarePriority(); TestSysTickDelegatesToOsPort(); TestReceiveRecoveryRetriesAfterBusy(); TestUartErrorClearsFlagsBeforeRecovery(); TestUartErrorDefersRecoveryToTask(); TestPendingRecoveryKeepsConcurrentErrorRequest(); TestReceptionWatchdogRearmsWhenHalStateIsLost(); return 0; } void HAL_Init(void) { } HAL_StatusTypeDef HAL_RCC_OscConfig(const RCC_OscInitTypeDef *config) { (void)config; return HAL_OK; } HAL_StatusTypeDef HAL_RCC_ClockConfig(const RCC_ClkInitTypeDef *config, uint32_t latency) { (void)config; (void)latency; return HAL_OK; } void HAL_GPIO_Init(GPIO_TypeDef *port, const GPIO_InitTypeDef *config) { (void)port; (void)config; } void HAL_GPIO_WritePin(GPIO_TypeDef *port, uint16_t pin, GPIO_PinState state) { (void)port; (void)pin; (void)state; } HAL_StatusTypeDef HAL_UART_Init(UART_HandleTypeDef *uartHandle) { (void)uartHandle; return HAL_OK; } HAL_StatusTypeDef HAL_UART_Receive_IT(UART_HandleTypeDef *uartHandle, uint8_t *data, uint16_t size) { HAL_StatusTypeDef result; (void)uartHandle; (void)data; (void)size; if (TestRecoveryCallOrderLength < sizeof(TestRecoveryCallOrder)) { TestRecoveryCallOrder[TestRecoveryCallOrderLength++] = 1U; } result = HAL_OK; if (TestReceiveCallCount < TestReceiveResultCount) { result = TestReceiveResults[TestReceiveCallCount]; } TestReceiveCallCount++; if (result == HAL_OK) { uartHandle->RxState = HAL_UART_STATE_BUSY_RX; } if ((TestReceiveErrorInjectionCall != 0U) && (TestReceiveCallCount == TestReceiveErrorInjectionCall)) { Uart1Handle.ErrorCode = HAL_UART_ERROR_ORE; HAL_UART_ErrorCallback(&Uart1Handle); } return result; } HAL_StatusTypeDef HAL_UART_AbortReceive_IT(UART_HandleTypeDef *uartHandle) { (void)uartHandle; TestAbortReceiveCallCount++; if (TestRecoveryCallOrderLength < sizeof(TestRecoveryCallOrder)) { TestRecoveryCallOrder[TestRecoveryCallOrderLength++] = 2U; } return HAL_OK; } HAL_StatusTypeDef HAL_UART_Transmit_IT(UART_HandleTypeDef *uartHandle, uint8_t *data, uint16_t size) { (void)uartHandle; (void)data; (void)size; return HAL_OK; } HAL_StatusTypeDef HAL_UART_AbortTransmit_IT(UART_HandleTypeDef *uartHandle) { (void)uartHandle; return HAL_OK; } void HAL_UART_IRQHandler(UART_HandleTypeDef *uartHandle) { (void)uartHandle; } void HAL_NVIC_SetPriority(IRQn_Type irqn, uint32_t preemptPriority, uint32_t subPriority) { TestNvicIrq = irqn; TestNvicPreemptPriority = preemptPriority; TestNvicSubPriority = subPriority; } void HAL_NVIC_EnableIRQ(IRQn_Type irqn) { (void)irqn; } void HAL_IncTick(void) { TestHalTickCallCount++; } void OSInit(void) { } void OSStart(void) { } INT8U OSTaskCreateExt(void (*task)(void *), void *argument, OS_STK *stackTop, INT8U priority, INT16U taskId, OS_STK *stackBottom, INT32U stackSize, void *extension, INT16U options) { (void)task; (void)argument; (void)stackTop; (void)priority; (void)taskId; (void)stackBottom; (void)stackSize; (void)extension; (void)options; return OS_ERR_NONE; } OS_EVENT *OSSemCreate(INT16U count) { (void)count; return &TestFrameSem; } void OSSemPend(OS_EVENT *event, uint32_t timeout, INT8U *error) { (void)event; (void)timeout; if (error != NULL) { *error = OS_ERR_NONE; } } INT8U OSSemPost(OS_EVENT *event) { (void)event; TestSemPostCallCount++; return OS_ERR_NONE; } void OSTaskSuspend(INT8U priority) { (void)priority; } void OSTimeDly(uint32_t ticks) { (void)ticks; } uint32_t OSTimeGet(void) { return 0U; } void OSIntEnter(void) { } void OSIntExit(void) { } void OSTimeTick(void) { } void OS_CPU_SysTickHandler(void) { TestOsCpuSysTickCallCount++; } MODBUS_STATUS ModbusBackupRestore(MODBUS_SLAVE *slave) { (void)slave; return MODBUS_STATUS_OK; } MODBUS_STATUS ModbusBackupSave(const MODBUS_SLAVE *slave) { (void)slave; return MODBUS_STATUS_OK; }