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:
Jason
2026-03-19 09:28:19 +02:00
parent fda8aab7a2
commit 28a66889ad
57 changed files with 2311 additions and 0 deletions
@@ -0,0 +1,5 @@
/* shim: redirect adf4382.h -> our mock types */
#ifndef ADF4382_H_SHIM
#define ADF4382_H_SHIM
#include "ad_driver_mock.h"
#endif
@@ -0,0 +1,95 @@
/* shim: adf4382a_manager.h -- provides the manager API using mock types
*
* The real adf4382a_manager.h includes adf4382.h and no_os_spi.h via
* quoted includes, which the compiler resolves to the same-directory
* copies BEFORE checking -I paths. This shim replaces it for test code
* so all types come from our mocks.
*
* Note: adf4382a_manager.c is compiled separately with the correct -I
* order, so IT gets the shim versions of adf4382.h etc. Test .c files
* include THIS file instead.
*/
#ifndef ADF4382A_MANAGER_H_SHIM
#define ADF4382A_MANAGER_H_SHIM
#include "stm32_hal_mock.h"
#include "ad_driver_mock.h"
/* ---- Constants (copied from real adf4382a_manager.h) ---- */
/* GPIO Definitions — these are the manager.h pin mappings (the buggy ones) */
#define TX_CE_Pin GPIO_PIN_0
#define TX_CE_GPIO_Port GPIOG
#define TX_CS_Pin GPIO_PIN_1
#define TX_CS_GPIO_Port GPIOG
#define TX_DELADJ_Pin GPIO_PIN_2
#define TX_DELADJ_GPIO_Port GPIOG
#define TX_DELSTR_Pin GPIO_PIN_3
#define TX_DELSTR_GPIO_Port GPIOG
#define TX_LKDET_Pin GPIO_PIN_4
#define TX_LKDET_GPIO_Port GPIOG
#define RX_CE_Pin GPIO_PIN_5
#define RX_CE_GPIO_Port GPIOG
#define RX_CS_Pin GPIO_PIN_6
#define RX_CS_GPIO_Port GPIOG
#define RX_DELADJ_Pin GPIO_PIN_7
#define RX_DELADJ_GPIO_Port GPIOG
#define RX_DELSTR_Pin GPIO_PIN_8
#define RX_DELSTR_GPIO_Port GPIOG
#define RX_LKDET_Pin GPIO_PIN_9
#define RX_LKDET_GPIO_Port GPIOG
/* Frequency definitions */
#define REF_FREQ_HZ 300000000ULL
#define TX_FREQ_HZ 10500000000ULL
#define RX_FREQ_HZ 10380000000ULL
#define SYNC_CLOCK_FREQ 60000000ULL
/* SPI Configuration */
#define ADF4382A_SPI_DEVICE_ID 4
#define ADF4382A_SPI_SPEED_HZ 10000000
/* Phase delay configuration */
#define DELADJ_MAX_DUTY_CYCLE 1000
#define DELADJ_PULSE_WIDTH_US 10
#define PHASE_SHIFT_MAX_PS 10000
/* Error codes */
#define ADF4382A_MANAGER_OK 0
#define ADF4382A_MANAGER_ERROR_INVALID -1
#define ADF4382A_MANAGER_ERROR_NOT_INIT -2
#define ADF4382A_MANAGER_ERROR_SPI -3
typedef enum {
SYNC_METHOD_EZSYNC = 0,
SYNC_METHOD_TIMED = 1
} SyncMethod;
typedef struct {
struct adf4382_dev *tx_dev;
struct adf4382_dev *rx_dev;
struct no_os_spi_init_param spi_tx_param;
struct no_os_spi_init_param spi_rx_param;
bool initialized;
SyncMethod sync_method;
uint16_t tx_phase_shift_ps;
uint16_t rx_phase_shift_ps;
} ADF4382A_Manager;
/* Public functions */
int ADF4382A_Manager_Init(ADF4382A_Manager *manager, SyncMethod method);
int ADF4382A_Manager_Deinit(ADF4382A_Manager *manager);
int ADF4382A_SetupTimedSync(ADF4382A_Manager *manager);
int ADF4382A_SetupEZSync(ADF4382A_Manager *manager);
int ADF4382A_TriggerTimedSync(ADF4382A_Manager *manager);
int ADF4382A_TriggerEZSync(ADF4382A_Manager *manager);
int ADF4382A_CheckLockStatus(ADF4382A_Manager *manager, bool *tx_locked, bool *rx_locked);
int ADF4382A_SetOutputPower(ADF4382A_Manager *manager, uint8_t tx_power, uint8_t rx_power);
int ADF4382A_EnableOutputs(ADF4382A_Manager *manager, bool tx_enable, bool rx_enable);
int ADF4382A_SetPhaseShift(ADF4382A_Manager *manager, uint16_t tx_phase_ps, uint16_t rx_phase_ps);
int ADF4382A_GetPhaseShift(ADF4382A_Manager *manager, uint16_t *tx_phase_ps, uint16_t *rx_phase_ps);
int ADF4382A_SetFinePhaseShift(ADF4382A_Manager *manager, uint8_t device, uint16_t duty_cycle);
int ADF4382A_StrobePhaseShift(ADF4382A_Manager *manager, uint8_t device);
#endif /* ADF4382A_MANAGER_H_SHIM */
@@ -0,0 +1,18 @@
/* shim: diag_log.h -- disable DIAG macros for test builds */
#ifndef DIAG_LOG_H_SHIM
#define DIAG_LOG_H_SHIM
/* Silence all DIAG output during unit tests */
#define DIAG_DISABLE
#define DIAG(tag, fmt, ...) ((void)0)
#define DIAG_WARN(tag, fmt, ...) ((void)0)
#define DIAG_ERR(tag, fmt, ...) ((void)0)
#define DIAG_REG(tag, name, val) ((void)0)
#define DIAG_REG32(tag, name, val) ((void)0)
#define DIAG_GPIO(tag, name, port, pin) ((void)0)
#define DIAG_BOOL(tag, name, val) ((void)0)
#define DIAG_SECTION(name) ((void)0)
#define DIAG_ELAPSED(tag, name, t) ((void)0)
#endif
@@ -0,0 +1,136 @@
/* shim: redirect main.h -> our mock + pin defines from real main.h */
#ifndef MAIN_H_SHIM
#define MAIN_H_SHIM
#include "stm32_hal_mock.h"
#ifdef __cplusplus
extern "C" {
#endif
extern uint8_t GUI_start_flag_received;
extern uint8_t USB_Buffer[64];
void Error_Handler(void);
/* Pin definitions from real main.h (CubeMX-generated) */
#define AD9523_PD_Pin GPIO_PIN_3
#define AD9523_PD_GPIO_Port GPIOF
#define AD9523_REF_SEL_Pin GPIO_PIN_4
#define AD9523_REF_SEL_GPIO_Port GPIOF
#define AD9523_SYNC_Pin GPIO_PIN_5
#define AD9523_SYNC_GPIO_Port GPIOF
#define AD9523_RESET_Pin GPIO_PIN_6
#define AD9523_RESET_GPIO_Port GPIOF
#define AD9523_CS_Pin GPIO_PIN_7
#define AD9523_CS_GPIO_Port GPIOF
#define AD9523_STATUS0_Pin GPIO_PIN_8
#define AD9523_STATUS0_GPIO_Port GPIOF
#define AD9523_STATUS1_Pin GPIO_PIN_9
#define AD9523_STATUS1_GPIO_Port GPIOF
#define AD9523_EEPROM_SEL_Pin GPIO_PIN_10
#define AD9523_EEPROM_SEL_GPIO_Port GPIOF
#define ADAR_1_CS_3V3_Pin GPIO_PIN_0
#define ADAR_1_CS_3V3_GPIO_Port GPIOA
#define ADAR_2_CS_3V3_Pin GPIO_PIN_1
#define ADAR_2_CS_3V3_GPIO_Port GPIOA
#define ADAR_3_CS_3V3_Pin GPIO_PIN_2
#define ADAR_3_CS_3V3_GPIO_Port GPIOA
#define ADAR_4_CS_3V3_Pin GPIO_PIN_3
#define ADAR_4_CS_3V3_GPIO_Port GPIOA
#define LED_1_Pin GPIO_PIN_12
#define LED_1_GPIO_Port GPIOF
#define LED_2_Pin GPIO_PIN_13
#define LED_2_GPIO_Port GPIOF
#define LED_3_Pin GPIO_PIN_14
#define LED_3_GPIO_Port GPIOF
#define LED_4_Pin GPIO_PIN_15
#define LED_4_GPIO_Port GPIOF
#define EN_P_5V0_PA1_Pin GPIO_PIN_0
#define EN_P_5V0_PA1_GPIO_Port GPIOG
#define EN_P_5V0_PA2_Pin GPIO_PIN_1
#define EN_P_5V0_PA2_GPIO_Port GPIOG
#define EN_P_5V0_PA3_Pin GPIO_PIN_2
#define EN_P_5V0_PA3_GPIO_Port GPIOG /* was GPIO_PIN_2 */
#define EN_P_5V5_PA_Pin GPIO_PIN_3
#define EN_P_5V5_PA_GPIO_Port GPIOG
#define EN_P_1V8_CLOCK_Pin GPIO_PIN_4
#define EN_P_1V8_CLOCK_GPIO_Port GPIOG
#define EN_P_3V3_CLOCK_Pin GPIO_PIN_5
#define EN_P_3V3_CLOCK_GPIO_Port GPIOG
#define ADF4382_RX_LKDET_Pin GPIO_PIN_6
#define ADF4382_RX_LKDET_GPIO_Port GPIOG
#define ADF4382_RX_DELADJ_Pin GPIO_PIN_7
#define ADF4382_RX_DELADJ_GPIO_Port GPIOG
#define ADF4382_RX_DELSTR_Pin GPIO_PIN_8
#define ADF4382_RX_DELSTR_GPIO_Port GPIOG
#define ADF4382_RX_CE_Pin GPIO_PIN_9
#define ADF4382_RX_CE_GPIO_Port GPIOG /* was GPIO_PIN_9 */
#define ADF4382_RX_CS_Pin GPIO_PIN_10
#define ADF4382_RX_CS_GPIO_Port GPIOG /* was GPIO_PIN_10 */
#define ADF4382_TX_LKDET_Pin GPIO_PIN_11
#define ADF4382_TX_LKDET_GPIO_Port GPIOG
#define ADF4382_TX_DELSTR_Pin GPIO_PIN_12
#define ADF4382_TX_DELSTR_GPIO_Port GPIOG
#define ADF4382_TX_DELADJ_Pin GPIO_PIN_13
#define ADF4382_TX_DELADJ_GPIO_Port GPIOG
#define ADF4382_TX_CS_Pin GPIO_PIN_14
#define ADF4382_TX_CS_GPIO_Port GPIOG
#define ADF4382_TX_CE_Pin GPIO_PIN_15
#define ADF4382_TX_CE_GPIO_Port GPIOG
/* Power enables (GPIOE) */
#define EN_P_1V0_FPGA_Pin GPIO_PIN_7
#define EN_P_1V0_FPGA_GPIO_Port GPIOE
#define EN_P_1V8_FPGA_Pin GPIO_PIN_8
#define EN_P_1V8_FPGA_GPIO_Port GPIOE
#define EN_P_3V3_FPGA_Pin GPIO_PIN_9
#define EN_P_3V3_FPGA_GPIO_Port GPIOE
#define EN_P_5V0_ADAR_Pin GPIO_PIN_10
#define EN_P_5V0_ADAR_GPIO_Port GPIOE
#define EN_P_3V3_ADAR12_Pin GPIO_PIN_11
#define EN_P_3V3_ADAR12_GPIO_Port GPIOE
#define EN_P_3V3_ADAR34_Pin GPIO_PIN_12
#define EN_P_3V3_ADAR34_GPIO_Port GPIOE
#define EN_P_3V3_ADTR_Pin GPIO_PIN_13
#define EN_P_3V3_ADTR_GPIO_Port GPIOE
#define EN_P_3V3_SW_Pin GPIO_PIN_14
#define EN_P_3V3_SW_GPIO_Port GPIOE
#define EN_P_3V3_VDD_SW_Pin GPIO_PIN_15
#define EN_P_3V3_VDD_SW_GPIO_Port GPIOE
/* GPIOD pins */
#define STEPPER_CW_P_Pin GPIO_PIN_4
#define STEPPER_CW_P_GPIO_Port GPIOD
#define STEPPER_CLK_P_Pin GPIO_PIN_5
#define STEPPER_CLK_P_GPIO_Port GPIOD
#define EN_DIS_RFPA_VDD_Pin GPIO_PIN_6
#define EN_DIS_RFPA_VDD_GPIO_Port GPIOD
#define EN_DIS_COOLING_Pin GPIO_PIN_7
#define EN_DIS_COOLING_GPIO_Port GPIOD
/* DAC pins */
#define DAC_1_VG_CLR_Pin GPIO_PIN_4
#define DAC_1_VG_CLR_GPIO_Port GPIOB
#define DAC_1_VG_LDAC_Pin GPIO_PIN_5
#define DAC_1_VG_LDAC_GPIO_Port GPIOB
#define DAC_2_VG_CLR_Pin GPIO_PIN_8
#define DAC_2_VG_CLR_GPIO_Port GPIOB
#define DAC_2_VG_LDAC_Pin GPIO_PIN_9
#define DAC_2_VG_LDAC_GPIO_Port GPIOB
/* IMU interrupt pins */
#define MAG_DRDY_Pin GPIO_PIN_6
#define MAG_DRDY_GPIO_Port GPIOC
#define ACC_INT_Pin GPIO_PIN_7
#define ACC_INT_GPIO_Port GPIOC
#define GYR_INT_Pin GPIO_PIN_8
#define GYR_INT_GPIO_Port GPIOC
#ifdef __cplusplus
}
#endif
#endif /* MAIN_H_SHIM */
@@ -0,0 +1,7 @@
/* shim: redirect no_os_delay.h -> our mock */
#ifndef NO_OS_DELAY_H_SHIM
#define NO_OS_DELAY_H_SHIM
#include "stm32_hal_mock.h"
/* no_os_udelay and no_os_mdelay declared in stm32_hal_mock.h */
struct no_os_time { uint32_t s; uint32_t us; };
#endif
@@ -0,0 +1,5 @@
/* shim: redirect no_os_spi.h -> our mock types */
#ifndef NO_OS_SPI_H_SHIM
#define NO_OS_SPI_H_SHIM
#include "ad_driver_mock.h"
#endif
@@ -0,0 +1,10 @@
/* shim: redirect no_os_units.h -> minimal defines */
#ifndef NO_OS_UNITS_H_SHIM
#define NO_OS_UNITS_H_SHIM
#define MEGA 1000000ULL
#define NANO 1000000000ULL
#define PICO 1000000000000ULL
#define KHZ_PER_MHZ 1000ULL
#endif
@@ -0,0 +1,25 @@
/* shim: redirect no_os_util.h -> minimal defines */
#ifndef NO_OS_UTIL_H_SHIM
#define NO_OS_UTIL_H_SHIM
#include <stdint.h>
#ifndef NO_OS_BIT
#define NO_OS_BIT(x) (1UL << (x))
#endif
#ifndef NO_OS_GENMASK
#define NO_OS_GENMASK(h, l) (((~0UL) << (l)) & (~0UL >> (31 - (h))))
#endif
static inline uint32_t no_os_field_prep(uint32_t mask, uint32_t val) {
int shift = __builtin_ctz(mask);
return (val << shift) & mask;
}
static inline uint32_t no_os_field_get(uint32_t mask, uint32_t val) {
int shift = __builtin_ctz(mask);
return (val & mask) >> shift;
}
#endif
@@ -0,0 +1,5 @@
/* shim: redirect stm32f7xx_hal.h -> our mock */
#ifndef STM32F7XX_HAL_H_SHIM
#define STM32F7XX_HAL_H_SHIM
#include "stm32_hal_mock.h"
#endif