/ 9_Firmware / 9_1_Microcontroller / tests / stm32_hal_mock.c
stm32_hal_mock.c
  1  /*******************************************************************************
  2   * stm32_hal_mock.c -- Spy/recording implementation of STM32 HAL stubs
  3   ******************************************************************************/
  4  #include "stm32_hal_mock.h"
  5  #include "ad_driver_mock.h"
  6  #include <stdio.h>
  7  #include <stdlib.h>
  8  
  9  /* ========================= GPIO port instances ==================== */
 10  GPIO_TypeDef gpio_a = { .id = 0xA };
 11  GPIO_TypeDef gpio_b = { .id = 0xB };
 12  GPIO_TypeDef gpio_c = { .id = 0xC };
 13  GPIO_TypeDef gpio_d = { .id = 0xD };
 14  GPIO_TypeDef gpio_e = { .id = 0xE };
 15  GPIO_TypeDef gpio_f = { .id = 0xF };
 16  GPIO_TypeDef gpio_g = { .id = 0x6 };  /* 0x6 for GPIOG -- avoids overlap */
 17  
 18  /* ========================= Peripheral instances =================== */
 19  SPI_HandleTypeDef  hspi1 = { .id = 1 };
 20  SPI_HandleTypeDef  hspi4 = { .id = 4 };
 21  I2C_HandleTypeDef  hi2c1 = { .id = 1 };
 22  I2C_HandleTypeDef  hi2c2 = { .id = 2 };
 23  UART_HandleTypeDef huart3 = { .id = 3 };
 24  ADC_HandleTypeDef  hadc3 = { .id = 3 };
 25  TIM_HandleTypeDef  htim3 = { .id = 3 };
 26  
 27  /* ========================= Spy log ================================ */
 28  SpyRecord spy_log[SPY_MAX_RECORDS];
 29  int       spy_count = 0;
 30  
 31  /* ========================= Mock tick (forward decl for spy_reset) == */
 32  uint32_t mock_tick = 0;
 33  
 34  /* ========================= Printf control ========================= */
 35  int mock_printf_enabled = 0;
 36  
 37  /* ========================= Mock GPIO read ========================= */
 38  #define GPIO_READ_TABLE_SIZE 32
 39  static struct {
 40      GPIO_TypeDef *port;
 41      uint16_t      pin;
 42      GPIO_PinState val;
 43  } gpio_read_table[GPIO_READ_TABLE_SIZE];
 44  
 45  void spy_reset(void)
 46  {
 47      spy_count = 0;
 48      memset(spy_log, 0, sizeof(spy_log));
 49      mock_tick = 0;
 50      mock_printf_enabled = 0;
 51      memset(gpio_read_table, 0, sizeof(gpio_read_table));
 52  }
 53  
 54  const SpyRecord *spy_get(int index)
 55  {
 56      if (index < 0 || index >= spy_count) return NULL;
 57      return &spy_log[index];
 58  }
 59  
 60  int spy_count_type(SpyCallType type)
 61  {
 62      int count = 0;
 63      for (int i = 0; i < spy_count; i++) {
 64          if (spy_log[i].type == type) count++;
 65      }
 66      return count;
 67  }
 68  
 69  int spy_find_nth(SpyCallType type, int n)
 70  {
 71      int found = 0;
 72      for (int i = 0; i < spy_count; i++) {
 73          if (spy_log[i].type == type) {
 74              if (found == n) return i;
 75              found++;
 76          }
 77      }
 78      return -1;
 79  }
 80  
 81  static void spy_push(SpyRecord rec)
 82  {
 83      if (spy_count < SPY_MAX_RECORDS) {
 84          spy_log[spy_count++] = rec;
 85      }
 86  }
 87  
 88  /* ========================= Mock tick API ========================== */
 89  
 90  void mock_set_tick(uint32_t tick)   { mock_tick = tick; }
 91  void mock_advance_tick(uint32_t d)  { mock_tick += d; }
 92  
 93  /* ========================= Mock GPIO read API ===================== */
 94  
 95  void mock_gpio_set_read(GPIO_TypeDef *port, uint16_t pin, GPIO_PinState val)
 96  {
 97      for (int i = 0; i < GPIO_READ_TABLE_SIZE; i++) {
 98          if (gpio_read_table[i].port == port && gpio_read_table[i].pin == pin) {
 99              gpio_read_table[i].val = val;
100              return;
101          }
102          if (gpio_read_table[i].port == NULL) {
103              gpio_read_table[i].port = port;
104              gpio_read_table[i].pin  = pin;
105              gpio_read_table[i].val  = val;
106              return;
107          }
108      }
109  }
110  
111  /* ========================= HAL Implementations ==================== */
112  
113  void HAL_GPIO_WritePin(GPIO_TypeDef *GPIOx, uint16_t GPIO_Pin, GPIO_PinState PinState)
114  {
115      spy_push((SpyRecord){
116          .type  = SPY_GPIO_WRITE,
117          .port  = GPIOx,
118          .pin   = GPIO_Pin,
119          .value = (uint32_t)PinState,
120          .extra = NULL
121      });
122  }
123  
124  GPIO_PinState HAL_GPIO_ReadPin(GPIO_TypeDef *GPIOx, uint16_t GPIO_Pin)
125  {
126      GPIO_PinState result = GPIO_PIN_RESET;
127      for (int i = 0; i < GPIO_READ_TABLE_SIZE; i++) {
128          if (gpio_read_table[i].port == GPIOx && gpio_read_table[i].pin == GPIO_Pin) {
129              result = gpio_read_table[i].val;
130              break;
131          }
132      }
133      spy_push((SpyRecord){
134          .type  = SPY_GPIO_READ,
135          .port  = GPIOx,
136          .pin   = GPIO_Pin,
137          .value = (uint32_t)result,
138          .extra = NULL
139      });
140      return result;
141  }
142  
143  void HAL_GPIO_TogglePin(GPIO_TypeDef *GPIOx, uint16_t GPIO_Pin)
144  {
145      spy_push((SpyRecord){
146          .type  = SPY_GPIO_TOGGLE,
147          .port  = GPIOx,
148          .pin   = GPIO_Pin,
149          .value = 0,
150          .extra = NULL
151      });
152  }
153  
154  uint32_t HAL_GetTick(void)
155  {
156      spy_push((SpyRecord){
157          .type  = SPY_HAL_GET_TICK,
158          .port  = NULL,
159          .pin   = 0,
160          .value = mock_tick,
161          .extra = NULL
162      });
163      return mock_tick;
164  }
165  
166  void HAL_Delay(uint32_t Delay)
167  {
168      spy_push((SpyRecord){
169          .type  = SPY_HAL_DELAY,
170          .port  = NULL,
171          .pin   = 0,
172          .value = Delay,
173          .extra = NULL
174      });
175      mock_tick += Delay;
176  }
177  
178  HAL_StatusTypeDef HAL_UART_Transmit(UART_HandleTypeDef *huart, uint8_t *pData,
179                                       uint16_t Size, uint32_t Timeout)
180  {
181      spy_push((SpyRecord){
182          .type  = SPY_UART_TX,
183          .port  = NULL,
184          .pin   = Size,
185          .value = Timeout,
186          .extra = huart
187      });
188      return HAL_OK;
189  }
190  
191  /* ========================= no_os delay stubs ====================== */
192  
193  void no_os_udelay(uint32_t usecs)
194  {
195      spy_push((SpyRecord){
196          .type  = SPY_NO_OS_UDELAY,
197          .port  = NULL,
198          .pin   = 0,
199          .value = usecs,
200          .extra = NULL
201      });
202  }
203  
204  void no_os_mdelay(uint32_t msecs)
205  {
206      spy_push((SpyRecord){
207          .type  = SPY_HAL_DELAY,
208          .port  = NULL,
209          .pin   = 0,
210          .value = msecs,
211          .extra = NULL
212      });
213      mock_tick += msecs;
214  }
215  
216  /* ========================= ADS7830 stub =========================== */
217  
218  uint8_t ADS7830_Measure_SingleEnded(ADC_HandleTypeDef *hadc, uint8_t channel)
219  {
220      spy_push((SpyRecord){
221          .type  = SPY_ADS7830_MEASURE,
222          .port  = NULL,
223          .pin   = channel,
224          .value = 100,  /* stub: always return 100 (~64.7 C) */
225          .extra = hadc
226      });
227      return 100;
228  }
229  
230  /* ========================= TIM PWM stubs ========================== */
231  
232  HAL_StatusTypeDef HAL_TIM_PWM_Start(TIM_HandleTypeDef *htim, uint32_t Channel)
233  {
234      spy_push((SpyRecord){
235          .type  = SPY_TIM_PWM_START,
236          .port  = NULL,
237          .pin   = (uint16_t)Channel,
238          .value = htim->id,
239          .extra = htim
240      });
241      return HAL_OK;
242  }
243  
244  HAL_StatusTypeDef HAL_TIM_PWM_Stop(TIM_HandleTypeDef *htim, uint32_t Channel)
245  {
246      spy_push((SpyRecord){
247          .type  = SPY_TIM_PWM_STOP,
248          .port  = NULL,
249          .pin   = (uint16_t)Channel,
250          .value = htim->id,
251          .extra = htim
252      });
253      return HAL_OK;
254  }
255  
256  void mock_tim_set_compare(TIM_HandleTypeDef *htim, uint32_t Channel, uint32_t Compare)
257  {
258      spy_push((SpyRecord){
259          .type  = SPY_TIM_SET_COMPARE,
260          .port  = NULL,
261          .pin   = (uint16_t)Channel,
262          .value = Compare,
263          .extra = htim
264      });
265  }
266  
267  /* ========================= SPI stubs ============================== */
268  
269  HAL_StatusTypeDef HAL_SPI_TransmitReceive(SPI_HandleTypeDef *hspi, uint8_t *pTxData, uint8_t *pRxData, uint16_t Size, uint32_t Timeout)
270  {
271      spy_push((SpyRecord){
272          .type  = SPY_SPI_TRANSMIT_RECEIVE,
273          .port  = NULL,
274          .pin   = Size,
275          .value = Timeout,
276          .extra = hspi
277      });
278      return HAL_OK;
279  }
280  
281  HAL_StatusTypeDef HAL_SPI_Transmit(SPI_HandleTypeDef *hspi, uint8_t *pData, uint16_t Size, uint32_t Timeout)
282  {
283      spy_push((SpyRecord){
284          .type  = SPY_SPI_TRANSMIT,
285          .port  = NULL,
286          .pin   = Size,
287          .value = Timeout,
288          .extra = hspi
289      });
290      return HAL_OK;
291  }
292  
293  /* Stub for platform_noos_stm32.c GPIO functions */
294  void hal_set_gpio_by_index(uint8_t idx, uint8_t value) {
295      (void)idx; (void)value;
296  }
297  
298  /* ========================= Mock stm32_spi_ops ===================== */
299  
300  /* Stub SPI platform ops -- real adf4382a_manager.c references &stm32_spi_ops.
301   * In tests, adf4382_init() is mocked so no_os_spi_init() is never called.
302   * We provide a non-NULL struct so tests can assert platform_ops != NULL. */
303  static int mock_spi_init_stub(void) { return 0; }
304  
305  const struct no_os_spi_platform_ops stm32_spi_ops = {
306      .init = mock_spi_init_stub,
307  };