Add MCU firmware test harness with 8 bug-confirming tests
Complete test infrastructure for the observe-before-fix methodology: - stm32_hal_mock: HAL stub types + spy/recording ring buffer (512 entries) - ad_driver_mock: ADF4382/AD9523 mock drivers with configurable returns - 9 shim headers redirecting real #includes to mock types - Makefile with individual (test_bug1..8) and aggregate (test) targets All 8 tests pass, confirming: #1 Timed sync init ordering (SetupTimedSync before initialized=true) #2 AD9523 double setup (first call before reset release) #3 TriggerTimedSync no-op (prints messages, no HW action) #4 Phase shift before init error check #5 SetFinePhaseShift GPIO-only placeholder (no PWM) #6 Timer variable collision (last_check vs last_check1) #7 GPIO pin mapping conflict (manager.h vs CubeMX main.h) #8 uart_print/uart_println commented out
This commit is contained in:
1 parent
fda8aab7a2
commit
28a66889ad
57 files changed
+2311
No files matched your search
@@ -0,0 +1,226 @@
|
||||
/*******************************************************************************
|
||||
* stm32_hal_mock.c -- Spy/recording implementation of STM32 HAL stubs
|
||||
******************************************************************************/
|
||||
#include "stm32_hal_mock.h"
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
/* ========================= GPIO port instances ==================== */
|
||||
GPIO_TypeDef gpio_a = { .id = 0xA };
|
||||
GPIO_TypeDef gpio_b = { .id = 0xB };
|
||||
GPIO_TypeDef gpio_c = { .id = 0xC };
|
||||
GPIO_TypeDef gpio_d = { .id = 0xD };
|
||||
GPIO_TypeDef gpio_e = { .id = 0xE };
|
||||
GPIO_TypeDef gpio_f = { .id = 0xF };
|
||||
GPIO_TypeDef gpio_g = { .id = 0x6 }; /* 0x6 for GPIOG -- avoids overlap */
|
||||
|
||||
/* ========================= Peripheral instances =================== */
|
||||
SPI_HandleTypeDef hspi1 = { .id = 1 };
|
||||
SPI_HandleTypeDef hspi4 = { .id = 4 };
|
||||
I2C_HandleTypeDef hi2c1 = { .id = 1 };
|
||||
I2C_HandleTypeDef hi2c2 = { .id = 2 };
|
||||
UART_HandleTypeDef huart3 = { .id = 3 };
|
||||
ADC_HandleTypeDef hadc3 = { .id = 3 };
|
||||
|
||||
/* ========================= Spy log ================================ */
|
||||
SpyRecord spy_log[SPY_MAX_RECORDS];
|
||||
int spy_count = 0;
|
||||
|
||||
/* ========================= Mock tick (forward decl for spy_reset) == */
|
||||
uint32_t mock_tick = 0;
|
||||
|
||||
/* ========================= Printf control ========================= */
|
||||
int mock_printf_enabled = 0;
|
||||
|
||||
/* ========================= Mock GPIO read ========================= */
|
||||
#define GPIO_READ_TABLE_SIZE 32
|
||||
static struct {
|
||||
GPIO_TypeDef *port;
|
||||
uint16_t pin;
|
||||
GPIO_PinState val;
|
||||
} gpio_read_table[GPIO_READ_TABLE_SIZE];
|
||||
|
||||
void spy_reset(void)
|
||||
{
|
||||
spy_count = 0;
|
||||
memset(spy_log, 0, sizeof(spy_log));
|
||||
mock_tick = 0;
|
||||
mock_printf_enabled = 0;
|
||||
memset(gpio_read_table, 0, sizeof(gpio_read_table));
|
||||
}
|
||||
|
||||
const SpyRecord *spy_get(int index)
|
||||
{
|
||||
if (index < 0 || index >= spy_count) return NULL;
|
||||
return &spy_log[index];
|
||||
}
|
||||
|
||||
int spy_count_type(SpyCallType type)
|
||||
{
|
||||
int count = 0;
|
||||
for (int i = 0; i < spy_count; i++) {
|
||||
if (spy_log[i].type == type) count++;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
int spy_find_nth(SpyCallType type, int n)
|
||||
{
|
||||
int found = 0;
|
||||
for (int i = 0; i < spy_count; i++) {
|
||||
if (spy_log[i].type == type) {
|
||||
if (found == n) return i;
|
||||
found++;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void spy_push(SpyRecord rec)
|
||||
{
|
||||
if (spy_count < SPY_MAX_RECORDS) {
|
||||
spy_log[spy_count++] = rec;
|
||||
}
|
||||
}
|
||||
|
||||
/* ========================= Mock tick API ========================== */
|
||||
|
||||
void mock_set_tick(uint32_t tick) { mock_tick = tick; }
|
||||
void mock_advance_tick(uint32_t d) { mock_tick += d; }
|
||||
|
||||
/* ========================= Mock GPIO read API ===================== */
|
||||
|
||||
void mock_gpio_set_read(GPIO_TypeDef *port, uint16_t pin, GPIO_PinState val)
|
||||
{
|
||||
for (int i = 0; i < GPIO_READ_TABLE_SIZE; i++) {
|
||||
if (gpio_read_table[i].port == port && gpio_read_table[i].pin == pin) {
|
||||
gpio_read_table[i].val = val;
|
||||
return;
|
||||
}
|
||||
if (gpio_read_table[i].port == NULL) {
|
||||
gpio_read_table[i].port = port;
|
||||
gpio_read_table[i].pin = pin;
|
||||
gpio_read_table[i].val = val;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* ========================= HAL Implementations ==================== */
|
||||
|
||||
void HAL_GPIO_WritePin(GPIO_TypeDef *GPIOx, uint16_t GPIO_Pin, GPIO_PinState PinState)
|
||||
{
|
||||
spy_push((SpyRecord){
|
||||
.type = SPY_GPIO_WRITE,
|
||||
.port = GPIOx,
|
||||
.pin = GPIO_Pin,
|
||||
.value = (uint32_t)PinState,
|
||||
.extra = NULL
|
||||
});
|
||||
}
|
||||
|
||||
GPIO_PinState HAL_GPIO_ReadPin(GPIO_TypeDef *GPIOx, uint16_t GPIO_Pin)
|
||||
{
|
||||
GPIO_PinState result = GPIO_PIN_RESET;
|
||||
for (int i = 0; i < GPIO_READ_TABLE_SIZE; i++) {
|
||||
if (gpio_read_table[i].port == GPIOx && gpio_read_table[i].pin == GPIO_Pin) {
|
||||
result = gpio_read_table[i].val;
|
||||
break;
|
||||
}
|
||||
}
|
||||
spy_push((SpyRecord){
|
||||
.type = SPY_GPIO_READ,
|
||||
.port = GPIOx,
|
||||
.pin = GPIO_Pin,
|
||||
.value = (uint32_t)result,
|
||||
.extra = NULL
|
||||
});
|
||||
return result;
|
||||
}
|
||||
|
||||
void HAL_GPIO_TogglePin(GPIO_TypeDef *GPIOx, uint16_t GPIO_Pin)
|
||||
{
|
||||
spy_push((SpyRecord){
|
||||
.type = SPY_GPIO_TOGGLE,
|
||||
.port = GPIOx,
|
||||
.pin = GPIO_Pin,
|
||||
.value = 0,
|
||||
.extra = NULL
|
||||
});
|
||||
}
|
||||
|
||||
uint32_t HAL_GetTick(void)
|
||||
{
|
||||
spy_push((SpyRecord){
|
||||
.type = SPY_HAL_GET_TICK,
|
||||
.port = NULL,
|
||||
.pin = 0,
|
||||
.value = mock_tick,
|
||||
.extra = NULL
|
||||
});
|
||||
return mock_tick;
|
||||
}
|
||||
|
||||
void HAL_Delay(uint32_t Delay)
|
||||
{
|
||||
spy_push((SpyRecord){
|
||||
.type = SPY_HAL_DELAY,
|
||||
.port = NULL,
|
||||
.pin = 0,
|
||||
.value = Delay,
|
||||
.extra = NULL
|
||||
});
|
||||
mock_tick += Delay;
|
||||
}
|
||||
|
||||
HAL_StatusTypeDef HAL_UART_Transmit(UART_HandleTypeDef *huart, uint8_t *pData,
|
||||
uint16_t Size, uint32_t Timeout)
|
||||
{
|
||||
spy_push((SpyRecord){
|
||||
.type = SPY_UART_TX,
|
||||
.port = NULL,
|
||||
.pin = Size,
|
||||
.value = Timeout,
|
||||
.extra = huart
|
||||
});
|
||||
return HAL_OK;
|
||||
}
|
||||
|
||||
/* ========================= no_os delay stubs ====================== */
|
||||
|
||||
void no_os_udelay(uint32_t usecs)
|
||||
{
|
||||
spy_push((SpyRecord){
|
||||
.type = SPY_NO_OS_UDELAY,
|
||||
.port = NULL,
|
||||
.pin = 0,
|
||||
.value = usecs,
|
||||
.extra = NULL
|
||||
});
|
||||
}
|
||||
|
||||
void no_os_mdelay(uint32_t msecs)
|
||||
{
|
||||
spy_push((SpyRecord){
|
||||
.type = SPY_HAL_DELAY,
|
||||
.port = NULL,
|
||||
.pin = 0,
|
||||
.value = msecs,
|
||||
.extra = NULL
|
||||
});
|
||||
mock_tick += msecs;
|
||||
}
|
||||
|
||||
/* ========================= ADS7830 stub =========================== */
|
||||
|
||||
uint8_t ADS7830_Measure_SingleEnded(ADC_HandleTypeDef *hadc, uint8_t channel)
|
||||
{
|
||||
spy_push((SpyRecord){
|
||||
.type = SPY_ADS7830_MEASURE,
|
||||
.port = NULL,
|
||||
.pin = channel,
|
||||
.value = 100, /* stub: always return 100 (~64.7 C) */
|
||||
.extra = hadc
|
||||
});
|
||||
return 100;
|
||||
}
|
||||
Reference in new issue
Block a user