diff --git a/Core/Src/main.c b/Core/Src/main.c index d62d1fe..5b46c23 100644 --- a/Core/Src/main.c +++ b/Core/Src/main.c @@ -77,7 +77,7 @@ static void MX_TIM3_Init(void); void StartDefaultTask(void *argument); /* USER CODE BEGIN PFP */ - +void buzzer_manager_task(void *); /* USER CODE END PFP */ /* Private user code ---------------------------------------------------------*/ @@ -158,6 +158,13 @@ int main(void) ul_ulog_init(); + static const osThreadAttr_t buzzer_task_attrs = { + .name = "buzzer", + .stack_size = 64 * 4, + .priority = (osPriority_t) osPriorityHigh, + }; + (void) osThreadNew(buzzer_manager_task, NULL, &buzzer_task_attrs); + /* USER CODE END RTOS_THREADS */ diff --git a/KPI_Rover/Buzzer/driver.c b/KPI_Rover/Buzzer/driver.c new file mode 100644 index 0000000..71a5be5 --- /dev/null +++ b/KPI_Rover/Buzzer/driver.c @@ -0,0 +1,284 @@ +#include + +#include "stm32f4xx_hal.h" + +#include "generic.h" +#include "driver.h" + +#define BUZZER_BLOCKING_TIME_LIMIT 1000 + +#define CHECK_ERROR(condition, err_value) do { \ + if (condition) { \ + errors = (err_value); \ + goto fail; \ + } \ + } while (0) + + +static uint8_t count_bits_16bit(uint16_t value) +{ + uint8_t result = 0; + + for ( ; value; value >>= 1) + result += value & 1; + + return result; +} + +static uint32_t Buzzer_SetON(struct BuzzerObject * const self) +{ + uint32_t errors = 0; + + CHECK_ERROR(!self->c.initialized, BUZZER_NOT_INITIALIZED_ERROR); + + HAL_GPIO_WritePin(self->c.GPIO_port, self->c.GPIO_pin, GPIO_PIN_SET); + +fail: + return errors; +} + +static uint32_t Buzzer_SetOFF(struct BuzzerObject * const self) +{ + uint32_t errors = 0; + + CHECK_ERROR(!self->c.initialized, BUZZER_NOT_INITIALIZED_ERROR); + + HAL_GPIO_WritePin(self->c.GPIO_port, self->c.GPIO_pin, GPIO_PIN_RESET); + +fail: + return errors; +} + + +static void Buzzer_OFF_Enter(struct BuzzerObject * const self, const struct BuzzerEvent * const ev) +{ + Buzzer_SetOFF(self); +} + +static void Buzzer_OFF_Handle(struct BuzzerObject * const self) +{ + +} + +static void Buzzer_OFF_Leave(struct BuzzerObject * const self) +{ + Buzzer_SetOFF(self); +} + + +static void Buzzer_ON_Enter(struct BuzzerObject * const self, const struct BuzzerEvent * const ev) +{ + Buzzer_SetON(self); +} + +static void Buzzer_ON_Handle(struct BuzzerObject * const self) +{ + +} + +static void Buzzer_ON_Leave(struct BuzzerObject * const self) +{ + Buzzer_SetON(self); +} + + +static void Buzzer_PULSE_Enter(struct BuzzerObject * const self, const struct BuzzerEvent * const ev) +{ + self->ps.config.pulse_on_for = ev->pulse_on_for; + self->ps.config.pulse_off_for = ev->pulse_off_for; + self->ps.config.pulse_total_for = ev->pulse_total_for; + + self->ps.current_state = BUZZER_TO_ON; +} + +static void Buzzer_PULSE_Handle(struct BuzzerObject * const self) +{ + uint32_t tss; + + switch (self->ps.current_state) { + case BUZZER_TO_ON: + Buzzer_SetON(self); + self->ps.current_state_since = HAL_GetTick(); + + tss = ticks_elapsed_since(self->s.current_state_since); + + if ((tss + self->ps.config.pulse_on_for) >= self->ps.config.pulse_total_for) { + self->ps.current_state = BUZZER_FINAL_DELAY; + self->ps.state_lifetime_override = self->ps.config.pulse_total_for - tss; + } else { + self->ps.current_state = BUZZER_DELAY_BEFORE_OFF; + } + + break; + case BUZZER_DELAY_BEFORE_OFF: + if (ticks_elapsed_since(self->ps.current_state_since) >= self->ps.config.pulse_on_for) + self->ps.current_state = BUZZER_TO_OFF; + + break; + case BUZZER_TO_OFF: + Buzzer_SetOFF(self); + self->ps.current_state_since = HAL_GetTick(); + + tss = ticks_elapsed_since(self->s.current_state_since); + + if ((tss + self->ps.config.pulse_off_for) >= self->ps.config.pulse_total_for) { + self->ps.current_state = BUZZER_FINAL_DELAY; + self->ps.state_lifetime_override = self->ps.config.pulse_total_for - tss; + } else { + self->ps.current_state = BUZZER_DELAY_BEFORE_ON; + } + + break; + case BUZZER_DELAY_BEFORE_ON: + if (ticks_elapsed_since(self->ps.current_state_since) >= self->ps.config.pulse_off_for) + self->ps.current_state = BUZZER_TO_ON; + + break; + case BUZZER_FINAL_DELAY: + if (ticks_elapsed_since(self->ps.current_state_since) < self->ps.state_lifetime_override) + break; + + self->e.ev = TO_OFF; + break; + } +} + +static void Buzzer_PULSE_Leave(struct BuzzerObject * const self) +{ + Buzzer_SetOFF(self); +} + + +static void Buzzer_Reset(struct BuzzerObject * const self) +{ + switch (self->s.current_state) { + case BUZZER_OFF: + Buzzer_OFF_Leave(self); + break; + case BUZZER_ON: + Buzzer_ON_Leave(self); + break; + case BUZZER_PULSE: + Buzzer_PULSE_Leave(self); + break; + case IMPOSSIBLE_STATE: + default: + break; + } + + self->s.current_state = BUZZER_OFF; +} + +static void Buzzer_ProcessEvent(struct BuzzerObject * const self) +{ + if (self->e.ev == NO_EVENT || self->e.ev == IMPOSSIBLE_EVENT) + return; + + switch (self->s.current_state) { + case BUZZER_ON: + Buzzer_ON_Leave(self); + break; + case BUZZER_OFF: + Buzzer_OFF_Leave(self); + break; + case BUZZER_PULSE: + Buzzer_PULSE_Leave(self); + break; + default: + break; + } + + switch (self->e.ev) { + case TO_ON: + self->s.current_state = BUZZER_ON; + Buzzer_ON_Enter(self, &(self->e)); + break; + case TO_OFF: + self->s.current_state = BUZZER_OFF; + Buzzer_OFF_Enter(self, &(self->e)); + break; + case TO_PULSE: + self->s.current_state = BUZZER_PULSE; + Buzzer_PULSE_Enter(self, &(self->e)); + break; + default: + self->s.current_state = IMPOSSIBLE_STATE; + break; + } + + self->s.current_state_since = HAL_GetTick(); + self->e.ev = NO_EVENT; +} + + +uint32_t Buzzer_ConfigurePort(struct BuzzerObject * const self, const GPIO_TypeDef * const gpio_port, const uint16_t gpio_pin) +{ + Buzzer_Reset(self); + + uint32_t errors = 0; + + CHECK_ERROR(count_bits_16bit(gpio_pin) != 1, BUZZER_PIN_ERROR); + + self->c.GPIO_port = (GPIO_TypeDef *) gpio_port; + self->c.GPIO_pin = (uint16_t) gpio_pin; + + self->c.initialized = 1; + + return errors; + +fail: + self->c.initialized = 0; + return errors; +} + + +uint32_t Buzzer_Enable(struct BuzzerObject * const self) +{ + self->e.ev = TO_ON; + return 0; +} + +uint32_t Buzzer_Disable(struct BuzzerObject * const self) +{ + self->e.ev = TO_OFF; + return 0; +} + +uint32_t Buzzer_Pulse(struct BuzzerObject * const self, const uint32_t on_time_ms, const uint32_t period_time_ms, const uint32_t total_active_time_ms) +{ + uint32_t errors = 0; + + const uint32_t off_time_ms = period_time_ms - on_time_ms; + + CHECK_ERROR(!on_time_ms, BUZZER_ZERO_ONTIME_ERROR); + CHECK_ERROR(!off_time_ms, BUZZER_ZERO_OFFTIME_ERROR); + CHECK_ERROR(!total_active_time_ms, BUZZER_ZERO_ACTIVE_TIME_ERROR); + + self->e.pulse_on_for = on_time_ms; + self->e.pulse_off_for = off_time_ms; + self->e.pulse_total_for = total_active_time_ms; + + self->e.ev = TO_PULSE; + +fail: + return errors; +} + +void Buzzer_TimerTask(struct BuzzerObject * const self) +{ + (void) Buzzer_ProcessEvent(self); + + switch (self->s.current_state) { + case BUZZER_OFF: + Buzzer_OFF_Handle(self); + break; + case BUZZER_ON: + Buzzer_ON_Handle(self); + break; + case BUZZER_PULSE: + Buzzer_PULSE_Handle(self); + break; + default: + break; + } +} diff --git a/KPI_Rover/Buzzer/driver.h b/KPI_Rover/Buzzer/driver.h new file mode 100644 index 0000000..6e8a7a3 --- /dev/null +++ b/KPI_Rover/Buzzer/driver.h @@ -0,0 +1,86 @@ +#ifndef __BUZZER_DRIVER +#define __BUZZER_DRIVER + +#include "stm32f4xx_hal.h" + +#define BUZZER_PIN_ERROR 0x1U +#define BUZZER_NOT_INITIALIZED_ERROR 0x2U +#define BUZZER_HAL_ERROR 0x3U +#define BUZZER_VALUE_ERROR 0x4U +#define BUZZER_ZERO_ONTIME_ERROR 0x5U +#define BUZZER_ZERO_OFFTIME_ERROR 0x6U +#define BUZZER_ZERO_ACTIVE_TIME_ERROR 0x7U +#define BUZZER_TIMER_BUSY 0x8U + + +enum BuzzerEventType { + NO_EVENT, + IMPOSSIBLE_EVENT, + TO_ON, + TO_OFF, + TO_PULSE +}; + +struct BuzzerEvent { + enum BuzzerEventType ev; + uint32_t pulse_on_for; + uint32_t pulse_off_for; + uint32_t pulse_total_for; +}; + + +enum BuzzerGlobalStateType { + IMPOSSIBLE_STATE, + BUZZER_OFF, + BUZZER_ON, + BUZZER_PULSE +}; + +struct BuzzerGlobalState { + enum BuzzerGlobalStateType current_state; + uint32_t current_state_since; +}; + + +enum BuzzerPulseSubStateType { + BUZZER_TO_ON, + BUZZER_DELAY_BEFORE_OFF, + BUZZER_TO_OFF, + BUZZER_DELAY_BEFORE_ON, + BUZZER_FINAL_DELAY +}; + +struct BuzzerPulseConfig { + uint32_t pulse_on_for; + uint32_t pulse_off_for; + uint32_t pulse_total_for; +}; + +struct BuzzerPulseSubState { + enum BuzzerPulseSubStateType current_state; + struct BuzzerPulseConfig config; + uint32_t current_state_since; + uint32_t state_lifetime_override; +}; + + +struct BuzzerConfig { + GPIO_TypeDef *GPIO_port; + uint16_t GPIO_pin; + int8_t initialized; +}; + +struct BuzzerObject { + struct BuzzerConfig c; + struct BuzzerGlobalState s; + struct BuzzerPulseSubState ps; + struct BuzzerEvent e; +}; + +uint32_t Buzzer_ConfigurePort(struct BuzzerObject * const self, const GPIO_TypeDef * const gpio_port, const uint16_t gpio_pin); +uint32_t Buzzer_Enable(struct BuzzerObject * const self); +uint32_t Buzzer_Disable(struct BuzzerObject * const self); +uint32_t Buzzer_Pulse(struct BuzzerObject * const self, const uint32_t on_time_ms, const uint32_t period_time_ms, const uint32_t total_active_time_ms); +void Buzzer_TimerTask(struct BuzzerObject * const self); + +#endif /* __BUZZER_DRIVER */ diff --git a/KPI_Rover/Buzzer/generic.c b/KPI_Rover/Buzzer/generic.c new file mode 100644 index 0000000..156d1e4 --- /dev/null +++ b/KPI_Rover/Buzzer/generic.c @@ -0,0 +1,14 @@ +#include "stm32f4xx_hal.h" + +#include "generic.h" + +uint32_t ticks_elapsed(const uint32_t old_ticks, const uint32_t new_ticks) +{ + return (uint32_t) (((uint32_t) new_ticks) - ((uint32_t) old_ticks)); +} + +uint32_t ticks_elapsed_since(const uint32_t old_ticks) +{ + int32_t current_ticks = HAL_GetTick(); + return (uint32_t) (((uint32_t) current_ticks) - ((uint32_t) old_ticks)); +} diff --git a/KPI_Rover/Buzzer/generic.h b/KPI_Rover/Buzzer/generic.h new file mode 100644 index 0000000..060a3f7 --- /dev/null +++ b/KPI_Rover/Buzzer/generic.h @@ -0,0 +1,9 @@ +#ifndef __GENERIC_H +#define __GENERIC_H + + +uint32_t ticks_elapsed(const uint32_t old_ticks, const uint32_t new_ticks); +uint32_t ticks_elapsed_since(const uint32_t old_ticks); + + +#endif /* __GENERIC_H */ diff --git a/KPI_Rover/Buzzer/manager.c b/KPI_Rover/Buzzer/manager.c new file mode 100644 index 0000000..c36a715 --- /dev/null +++ b/KPI_Rover/Buzzer/manager.c @@ -0,0 +1,66 @@ +#include "FreeRTOS.h" +#include "timers.h" + +#include "cmsis_os2.h" + +#include "ul_ulog.h" + +#include "driver.h" + +#define LEN(x) ( sizeof(x) / sizeof(x[0]) ) + +static osTimerId_t timer_handle; +static StaticTimer_t timer; +static struct BuzzerObject bo[1]; + +static void buzzer_timer_callback(void *d) +{ + for (uint32_t i = 0; i < LEN(bo); i++) + Buzzer_TimerTask(&(bo[i])); +} + +void buzzer_manager_task(void *d) +{ + if (Buzzer_ConfigurePort(&(bo[0]), GPIOD, GPIO_PIN_15)) + { + ULOG_ERROR("Failed to configure buzzer driver port"); + osThreadExit(); + } + + { + osTimerAttr_t timer_attrs = { + .name = NULL, + .attr_bits = 0, + .cb_mem = &timer, + .cb_size = sizeof(timer) + }; + + timer_handle = osTimerNew(buzzer_timer_callback, osTimerPeriodic, (void *) 0, &timer_attrs); + + if (timer_handle != (&timer)) { + ULOG_ERROR("Failed to create a timer"); + osThreadExit(); + } + + if (osTimerStart(timer_handle, 10) != osOK) { + ULOG_ERROR("Failed to start a timer"); + osThreadExit(); + } + } + + for ( ; ; ) + { + Buzzer_Enable(&(bo[0])); + osDelay(3000); + Buzzer_Disable(&(bo[0])); + osDelay(3000); + Buzzer_Pulse(&(bo[0]), 500, 1000, 5000); + osDelay(5000); + Buzzer_Pulse(&(bo[0]), 200, 1000, 5000); + osDelay(5000); + Buzzer_Pulse(&(bo[0]), 100, 300, 5000); + osDelay(5000); + Buzzer_Pulse(&(bo[0]), 250, 300, 5000); + osDelay(1000); // intentionally shorter delay; any next command must abort any previous one + } +} diff --git a/KPI_Rover/Buzzer/mock-suite/CMakeLists.txt b/KPI_Rover/Buzzer/mock-suite/CMakeLists.txt new file mode 100644 index 0000000..e3cd2ca --- /dev/null +++ b/KPI_Rover/Buzzer/mock-suite/CMakeLists.txt @@ -0,0 +1,45 @@ +set(CFLAGS -Og -g3 -Wall -Wpedantic -Wno-pointer-to-int-cast) +set(CPPFLAGS -std=c++20 -Og -g3 -Wall -Wpedantic) + +cmake_minimum_required(VERSION 3.25.1) + +project(buzzer_testing) + +include(FetchContent) +FetchContent_Declare( + googletest + URL https://github.com/google/googletest/archive/03597a01ee50ed33e9dfd640b249b4be3799d395.zip +) + +FetchContent_MakeAvailable(googletest) + +add_library(scheduler STATIC src/scheduler.c) +add_library(timers STATIC src/timers.c) +add_library(stm32f4xx_hal_gpio STATIC src/stm32f4xx_hal_gpio.c) +add_library(stm32f4xx_hal_systick STATIC src/stm32f4xx_hal_systick.c) +add_library(cmsis_os2 STATIC src/cmsis_os2.c) +add_library(driver STATIC ../driver.c) +add_library(generic STATIC ../generic.c) + +add_executable(buzzer-driver test/buzzer-driver.cpp) + +target_include_directories(scheduler PRIVATE . inc) +target_include_directories(timers PRIVATE . inc) +target_include_directories(stm32f4xx_hal_gpio PRIVATE inc) +target_include_directories(stm32f4xx_hal_systick PRIVATE inc) +target_include_directories(driver PRIVATE .. . inc) +target_include_directories(cmsis_os2 PRIVATE . inc) +target_include_directories(generic PRIVATE . inc) +target_include_directories(buzzer-driver PRIVATE .. . inc ${CMAKE_BINARY_DIR}/googletest) + +target_link_libraries(scheduler timers) +target_link_libraries(driver timers stm32f4xx_hal_gpio stm32f4xx_hal_systick) +target_link_libraries(cmsis_os2 timers) +target_link_libraries(buzzer-driver gtest gtest_main scheduler timers stm32f4xx_hal_gpio driver cmsis_os2 generic) + +target_compile_options(scheduler PRIVATE ${CFLAGS}) +target_compile_options(timers PRIVATE ${CFLAGS}) +target_compile_options(stm32f4xx_hal_gpio PRIVATE ${CFLAGS}) +target_compile_options(driver PRIVATE ${CFLAGS}) +target_compile_options(cmsis_os2 PRIVATE ${CFLAGS}) +target_compile_options(buzzer-driver PRIVATE ${CPPFLAGS}) diff --git a/KPI_Rover/Buzzer/mock-suite/config.h b/KPI_Rover/Buzzer/mock-suite/config.h new file mode 100644 index 0000000..d97d68c --- /dev/null +++ b/KPI_Rover/Buzzer/mock-suite/config.h @@ -0,0 +1,13 @@ +#ifndef __CONFIG_H +#define __CONFIG_H + + +/* --- Color settings --- */ +#define COLOR_ENABLE 1 + + +/* --- Timer settings --- */ +#define TIMER_QUEUE_SIZE 16 + + +#endif /* __CONFIG_H */ diff --git a/KPI_Rover/Buzzer/mock-suite/inc/FreeRTOS.h b/KPI_Rover/Buzzer/mock-suite/inc/FreeRTOS.h new file mode 100644 index 0000000..b115d94 --- /dev/null +++ b/KPI_Rover/Buzzer/mock-suite/inc/FreeRTOS.h @@ -0,0 +1,18 @@ +#ifndef __FREERTOS_H +#define __FREERTOS_H + + +#include + +typedef int32_t TickType_t; + +#define pdFALSE 0 +#define pdTRUE 1 + +#define pdFAIL (pdFALSE) +#define pdPASS (pdTRUE) + +#define pdMS_TO_TICKS(ms) (TickType_t) ms + + +#endif /* __FREERTOS_H */ diff --git a/KPI_Rover/Buzzer/mock-suite/inc/cmsis_os2.h b/KPI_Rover/Buzzer/mock-suite/inc/cmsis_os2.h new file mode 100644 index 0000000..377cb6f --- /dev/null +++ b/KPI_Rover/Buzzer/mock-suite/inc/cmsis_os2.h @@ -0,0 +1,31 @@ +#ifndef __CMSIS_OS2_H +#define __CMSIS_OS2_H + +#include +#include "timers.h" + +typedef StaticTimer_t * osTimerId_t; + +typedef enum osStatus_t { + osOK, + osError, + osErrorTimeout, + osErrorResource, + osErrorParameter, + osErrorNoMemory, + osErrorISR, + osStatusReserved = 0x7FFFFFFF +} osStatus_t; + +typedef struct { + char *name; + uint32_t attr_bits; + TimerHandle_t cb_mem; + size_t cb_size; +} osTimerAttr_t; + +osTimerId_t osTimerNew(TimerCallbackFunction_t cb, uint32_t repeat, void * arg, osTimerAttr_t * attrs); +osStatus_t osTimerStart(osTimerId_t id, uint32_t interval); + + +#endif /* __CMSIS_OS2_H */ diff --git a/KPI_Rover/Buzzer/mock-suite/inc/colors.h b/KPI_Rover/Buzzer/mock-suite/inc/colors.h new file mode 100644 index 0000000..62efa50 --- /dev/null +++ b/KPI_Rover/Buzzer/mock-suite/inc/colors.h @@ -0,0 +1,17 @@ +#ifndef __COLORS_H +#define __COLORS_H + +#include "config.h" + +#if COLOR_ENABLE == 1 + #define COLOR_RESET "\x1b[0m" + #define COLOR_RED "\x1b[0;31m" + #define COLOR_GREEN "\x1b[0;32m" +#else + #define COLOR_RESET "" + #define COLOR_RED "" + #define COLOR_GREEN "" +#endif /* COLOR_ENABLE == 1 */ + + +#endif /* __COLORS_H */ diff --git a/KPI_Rover/Buzzer/mock-suite/inc/fail.h b/KPI_Rover/Buzzer/mock-suite/inc/fail.h new file mode 100644 index 0000000..d521ad5 --- /dev/null +++ b/KPI_Rover/Buzzer/mock-suite/inc/fail.h @@ -0,0 +1,55 @@ +#ifndef __FAIL_H +#define __FAIL_H + + +#define FAIL_ON(expression, return_on_fail, prefix, counter) \ + do { \ + if (!(expression)) { \ + printf("[%s %s:%d] %s: generic check \"%s\" fails\n", \ + (prefix), __FILE__, __LINE__, __func__, #expression); \ + (counter)++; \ + return (return_on_fail); \ + } \ + } while (0) + +#define FAIL_ON_EQ(exp1, exp2, return_on_fail, prefix, counter) \ + do { \ + if ((exp1) == (exp2)) { \ + printf("[%s %s:%d] %s: check %s (0x%08x) != %s (0x%08x) fails\n", \ + (prefix), __FILE__, __LINE__, __func__, #exp1, (unsigned int) (exp1), #exp2, (unsigned int) (exp2)); \ + (counter)++; \ + return (return_on_fail); \ + } \ + } while (0) + +#define FAIL_ON_LE(exp1, exp2, return_on_fail, prefix, counter) \ + do { \ + if ((exp1) <= (exp2)) { \ + printf("[%s %s:%d] %s: check %s (0x%08x) > %s (0x%08x) fails\n", \ + (prefix), __FILE__, __LINE__, __func__, #exp1, (unsigned int) (exp1), #exp2, (unsigned int) (exp2)); \ + (counter)++; \ + return (return_on_fail); \ + } \ + } while (0) + +#define WARN_ON_EQ(exp1, exp2, prefix, counter) \ + do { \ + if ((exp1) == (exp2)) { \ + printf("[%s %s:%d] %s: check %s (0x%08x) != %s (0x%08x) fails, continuing\n", \ + (prefix), __FILE__, __LINE__, __func__, #exp1, (unsigned int) (exp1), #exp2, (unsigned int) (exp2)); \ + (counter)++; \ + } \ + } while (0) + +#define REPORT_COUNTER(counter) \ + do { \ + issues += (counter); \ + if ((counter) == 1) \ + printf("[ISSUE] %s has been triggered %d time\n", \ + #counter, (counter)); \ + else if ((counter) >= 1) \ + printf("[ISSUE] %s has been triggered %d times\n", #counter, (counter)); \ + } while (0) + + +#endif /* __FAIL_H */ diff --git a/KPI_Rover/Buzzer/mock-suite/inc/main.h b/KPI_Rover/Buzzer/mock-suite/inc/main.h new file mode 100644 index 0000000..be59c11 --- /dev/null +++ b/KPI_Rover/Buzzer/mock-suite/inc/main.h @@ -0,0 +1,10 @@ +#ifndef __MAIN_H +#define __MAIN_H + + +#include "stm32f4xx_hal_gpio.h" +#include "stm32f4xx_hal_gpio_ex.h" +#include "stm32f4xx_hal_systick.h" + + +#endif /* __MAIN_H */ diff --git a/KPI_Rover/Buzzer/mock-suite/inc/scheduler.h b/KPI_Rover/Buzzer/mock-suite/inc/scheduler.h new file mode 100644 index 0000000..71ac41b --- /dev/null +++ b/KPI_Rover/Buzzer/mock-suite/inc/scheduler.h @@ -0,0 +1,9 @@ +#ifndef __SCHEDULER_H +#define __SCHEDULER_H + +#include "stdint.h" + +void scheduler_run_for(uint32_t ticks); + + +#endif /* __SCHEDULER_H */ diff --git a/KPI_Rover/Buzzer/mock-suite/inc/stm32f4xx_hal.h b/KPI_Rover/Buzzer/mock-suite/inc/stm32f4xx_hal.h new file mode 100644 index 0000000..31705a3 --- /dev/null +++ b/KPI_Rover/Buzzer/mock-suite/inc/stm32f4xx_hal.h @@ -0,0 +1,10 @@ +#ifndef __STM32F4XX_HAL_H +#define __STM32F4XX_HAL_H + + +#include "stm32f4xx_hal_gpio.h" +#include "stm32f4xx_hal_gpio_ex.h" +#include "stm32f4xx_hal_systick.h" + + +#endif /* __STM32F4XX_HAL_H */ diff --git a/KPI_Rover/Buzzer/mock-suite/inc/stm32f4xx_hal_gpio.h b/KPI_Rover/Buzzer/mock-suite/inc/stm32f4xx_hal_gpio.h new file mode 100644 index 0000000..547b287 --- /dev/null +++ b/KPI_Rover/Buzzer/mock-suite/inc/stm32f4xx_hal_gpio.h @@ -0,0 +1,43 @@ +#ifndef __STM32F4XX_HAL_GPIO_H +#define __STM32F4XX_HAL_GPIO_H + + +#include + +#define GPIO_PIN_0 ((uint16_t)0x0001) +#define GPIO_PIN_1 ((uint16_t)0x0002) +#define GPIO_PIN_2 ((uint16_t)0x0004) +#define GPIO_PIN_3 ((uint16_t)0x0008) +#define GPIO_PIN_4 ((uint16_t)0x0010) +#define GPIO_PIN_5 ((uint16_t)0x0020) +#define GPIO_PIN_6 ((uint16_t)0x0040) +#define GPIO_PIN_7 ((uint16_t)0x0080) +#define GPIO_PIN_8 ((uint16_t)0x0100) +#define GPIO_PIN_9 ((uint16_t)0x0200) +#define GPIO_PIN_10 ((uint16_t)0x0400) +#define GPIO_PIN_11 ((uint16_t)0x0800) +#define GPIO_PIN_12 ((uint16_t)0x1000) +#define GPIO_PIN_13 ((uint16_t)0x2000) +#define GPIO_PIN_14 ((uint16_t)0x4000) +#define GPIO_PIN_15 ((uint16_t)0x8000) +#define GPIO_PIN_All ((uint16_t)0xFFFF) + +typedef enum { + GPIO_PIN_RESET = 0, + GPIO_PIN_SET +} GPIO_PinState; + +typedef struct { + uint32_t ODR; +} GPIO_TypeDef; + +void gpio_init(void); + +void HAL_GPIO_WritePin( + GPIO_TypeDef* GPIOx, + uint16_t GPIO_Pin, + GPIO_PinState PinState +); + + +#endif /* __STM32F4XX_HAL_GPIO_H */ diff --git a/KPI_Rover/Buzzer/mock-suite/inc/stm32f4xx_hal_gpio_ex.h b/KPI_Rover/Buzzer/mock-suite/inc/stm32f4xx_hal_gpio_ex.h new file mode 100644 index 0000000..d6b9abd --- /dev/null +++ b/KPI_Rover/Buzzer/mock-suite/inc/stm32f4xx_hal_gpio_ex.h @@ -0,0 +1,10 @@ +#ifndef __STM32F4XX_HAL_GPIO_EX_H +#define __STM32F4XX_HAL_GPIO_EX_H + + +#include "stm32f4xx_hal_gpio.h" + +extern GPIO_TypeDef *GPIOD; + + +#endif /* __STM32F4XX_HAL_GPIO_EX_H */ diff --git a/KPI_Rover/Buzzer/mock-suite/inc/stm32f4xx_hal_systick.h b/KPI_Rover/Buzzer/mock-suite/inc/stm32f4xx_hal_systick.h new file mode 100644 index 0000000..b50b812 --- /dev/null +++ b/KPI_Rover/Buzzer/mock-suite/inc/stm32f4xx_hal_systick.h @@ -0,0 +1,11 @@ +#ifndef __STM32F4XX_HAL_SYSTICK_H +#define __STM32F4XX_HAL_SYSTICK_H + +#include + +extern uint32_t system_ticks; + +uint32_t HAL_GetTick(void); + + +#endif /* __STM32F4XX_HAL_SYSTICK_H */ diff --git a/KPI_Rover/Buzzer/mock-suite/inc/test.h b/KPI_Rover/Buzzer/mock-suite/inc/test.h new file mode 100644 index 0000000..196e8df --- /dev/null +++ b/KPI_Rover/Buzzer/mock-suite/inc/test.h @@ -0,0 +1,34 @@ +#ifndef __TEST_H +#define __TEST_H + + +#include + +#include "colors.h" + +#define INIT(...) int failed_tests = 0, passed_tests = 0; + +#define TEST(test_func) \ + do { \ + int return_code = test_func(); \ + if (return_code != 0) { \ + printf(COLOR_RED "TEST FAILED" COLOR_RESET ": %s, return code %08x\n", #test_func, (unsigned int) return_code); \ + failed_tests++; \ + } else { \ + printf(COLOR_GREEN "TEST PASSED" COLOR_RESET ": %s\n", #test_func); \ + passed_tests++; \ + } \ + } while (0) + +#define SUMMARY(...) \ + do { \ + if (failed_tests) { \ + printf("--- " COLOR_GREEN "%d" COLOR_RESET " passed / " COLOR_RED "%d" COLOR_RESET " failed ---\n", passed_tests, failed_tests); \ + } else { \ + printf("--- " COLOR_GREEN "%d" COLOR_RESET " passed ---\n", passed_tests); \ + } \ + return !!failed_tests; \ + } while (0) + + +#endif /* __TEST_H */ diff --git a/KPI_Rover/Buzzer/mock-suite/inc/timers.h b/KPI_Rover/Buzzer/mock-suite/inc/timers.h new file mode 100644 index 0000000..fc0f2ac --- /dev/null +++ b/KPI_Rover/Buzzer/mock-suite/inc/timers.h @@ -0,0 +1,57 @@ +#include "FreeRTOS.h" + +#include "config.h" + +#define TIMER_CREATED ( (uint8_t) 0x1 ) +#define TIMER_ACTIVE ( (uint8_t) 0x2 ) + + +typedef uint32_t UBaseType_t; +typedef int32_t BaseType_t; + +typedef struct StaticTimer_t * TimerHandle_t; + +typedef void (*TimerCallbackFunction_t)(TimerHandle_t xTimer); + +struct StaticTimer_t { + uint8_t status; + TickType_t timer_ticks_left; + + void * pvTimerID; + UBaseType_t uxAutoReload; + TickType_t xTimerPeriodInTicks; + TimerCallbackFunction_t pxCallbackFunction; +}; + +typedef struct StaticTimer_t StaticTimer_t; + + +void timers_init(void); +void timers_run(void); +uint32_t timers_check_health(void); +TimerHandle_t *get_timer_queue(void); + +TimerHandle_t xTimerCreateStatic( + const char * const pcTimerName, + const TickType_t xTimerPeriodInTicks, + const UBaseType_t uxAutoReload, + void * const pvTimerID, + TimerCallbackFunction_t pxCallbackFunction, + StaticTimer_t *pxTimerBuffer +); + +BaseType_t xTimerStop( + TimerHandle_t xTimer, + TickType_t xTicksToWait +); + +BaseType_t xTimerChangePeriod( + TimerHandle_t xTimer, + TickType_t xNewPeriod, + TickType_t xTicksToWait +); + +BaseType_t xTimerStart( + TimerHandle_t xTimer, + TickType_t xTicksToWait +); diff --git a/KPI_Rover/Buzzer/mock-suite/src/cmsis_os2.c b/KPI_Rover/Buzzer/mock-suite/src/cmsis_os2.c new file mode 100644 index 0000000..e87c626 --- /dev/null +++ b/KPI_Rover/Buzzer/mock-suite/src/cmsis_os2.c @@ -0,0 +1,12 @@ +#include "cmsis_os2.h" + +osTimerId_t osTimerNew(TimerCallbackFunction_t cb, uint32_t repeat, void * arg, osTimerAttr_t * attrs) +{ + return xTimerCreateStatic(NULL, 0, repeat, arg, cb, attrs->cb_mem); +} + +osStatus_t osTimerStart(osTimerId_t id, uint32_t interval) +{ + id->xTimerPeriodInTicks = interval; + return xTimerStart(id, 0); +} diff --git a/KPI_Rover/Buzzer/mock-suite/src/scheduler.c b/KPI_Rover/Buzzer/mock-suite/src/scheduler.c new file mode 100644 index 0000000..f0f7a58 --- /dev/null +++ b/KPI_Rover/Buzzer/mock-suite/src/scheduler.c @@ -0,0 +1,24 @@ +#define SCHEDULER_EMULATE_TIMERS 1 + +#include +#include + +uint32_t system_ticks = 0; + +#include "scheduler.h" + +#if SCHEDULER_EMULATE_TIMERS == 1 + #include "timers.h" +#endif /* SCHEDULER_EMULATE_TIMERS == 1 */ + +void scheduler_run_for(uint32_t ticks) +{ + for (int i = 0; i < ticks; i++) + { + system_ticks++; + +#if SCHEDULER_EMULATE_TIMERS == 1 + timers_run(); +#endif /* SCHEDULER_EMULATE_TIMERS == 1 */ + } +} diff --git a/KPI_Rover/Buzzer/mock-suite/src/stm32f4xx_hal_gpio.c b/KPI_Rover/Buzzer/mock-suite/src/stm32f4xx_hal_gpio.c new file mode 100644 index 0000000..4bd51ee --- /dev/null +++ b/KPI_Rover/Buzzer/mock-suite/src/stm32f4xx_hal_gpio.c @@ -0,0 +1,30 @@ +#include + +#include "stm32f4xx_hal_gpio.h" + +static GPIO_TypeDef GPIOs[11]; // GPIOA - GPIOK +GPIO_TypeDef *GPIOD; + +void gpio_init(void) +{ + // Notice: GPIO A & B registers have specific non-zero values at startup + memset(GPIOs, 0, sizeof(GPIOs)); + + GPIOD = &(GPIOs[3]); +} + +uint32_t gpio_check_health(void) +{ + return 0; +} + +void HAL_GPIO_WritePin( + GPIO_TypeDef* GPIOx, + uint16_t GPIO_Pin, + GPIO_PinState PinState) +{ + if (PinState == GPIO_PIN_RESET) + GPIOx->ODR &= ~GPIO_Pin; + else + GPIOx->ODR |= GPIO_Pin; +} diff --git a/KPI_Rover/Buzzer/mock-suite/src/stm32f4xx_hal_systick.c b/KPI_Rover/Buzzer/mock-suite/src/stm32f4xx_hal_systick.c new file mode 100644 index 0000000..eaadfa0 --- /dev/null +++ b/KPI_Rover/Buzzer/mock-suite/src/stm32f4xx_hal_systick.c @@ -0,0 +1,8 @@ +#include "stm32f4xx_hal_systick.h" + +extern uint32_t system_ticks; + +uint32_t HAL_GetTick(void) +{ + return system_ticks; +} diff --git a/KPI_Rover/Buzzer/mock-suite/src/timers.c b/KPI_Rover/Buzzer/mock-suite/src/timers.c new file mode 100644 index 0000000..3c887be --- /dev/null +++ b/KPI_Rover/Buzzer/mock-suite/src/timers.c @@ -0,0 +1,170 @@ +#include +#include + +#include "timers.h" + +#include "fail.h" + + +static uint32_t null_timer_ptr_count = 0; +static uint32_t static_timer_recreation_count = 0; +static uint32_t non_positive_timer_period_count = 0; +static uint32_t null_callback_function_specified_count = 0; +static uint32_t operated_on_active_timer_count = 0; +static uint32_t timer_queue_overflow_count = 0; + +static TimerHandle_t timer_queue[TIMER_QUEUE_SIZE]; + +static int register_timer(TimerHandle_t t) +{ + TimerHandle_t *vacant_timer = NULL; + + for (int i = 0; i < TIMER_QUEUE_SIZE; i++) { + if (timer_queue[i] == t) + return 0; + + if (timer_queue[i]) + continue; + + if (!vacant_timer) + vacant_timer = &(timer_queue[i]); + } + + if (vacant_timer) { + *vacant_timer = t; + return 0; + } else { + return -1; + } +} + +static int unregister_timer(TimerHandle_t t) +{ + for (int i = 0; i < TIMER_QUEUE_SIZE; i++) { + if (timer_queue[i] != t) + continue; + + timer_queue[i] = NULL; + return i; + } + + return -1; +} + +void timers_init(void) +{ + memset(timer_queue, 0, sizeof(timer_queue)); +} + +uint32_t timers_check_health(void) +{ + uint32_t issues = 0; + + REPORT_COUNTER(null_timer_ptr_count); + REPORT_COUNTER(static_timer_recreation_count); + REPORT_COUNTER(non_positive_timer_period_count); + REPORT_COUNTER(null_callback_function_specified_count); + REPORT_COUNTER(operated_on_active_timer_count); + REPORT_COUNTER(timer_queue_overflow_count); + + return issues; +} + +void timers_run(void) +{ + TimerHandle_t chosen_timer = NULL; + + for (int i = 0; i < TIMER_QUEUE_SIZE; i++) { + if (timer_queue[i] == NULL) + continue; + + if (timer_queue[i]->status & TIMER_ACTIVE) + timer_queue[i]->timer_ticks_left--; + + if (timer_queue[i]->timer_ticks_left > 0) + continue; + + timer_queue[i]->status &= ~TIMER_ACTIVE; + + if (chosen_timer == NULL) { + chosen_timer = timer_queue[i]; + timer_queue[i] = NULL; + + if (chosen_timer->uxAutoReload) + xTimerStart(chosen_timer, chosen_timer->xTimerPeriodInTicks); + } + } + + if (chosen_timer) + chosen_timer->pxCallbackFunction(chosen_timer); +} + +TimerHandle_t *get_timer_queue(void) +{ + return timer_queue; +} + +TimerHandle_t xTimerCreateStatic( + const char * const pcTimerName, + const TickType_t xTimerPeriodInTicks, + const UBaseType_t uxAutoReload, + void * const pvTimerID, + TimerCallbackFunction_t pxCallbackFunction, + StaticTimer_t *pxTimerBuffer) +{ + FAIL_ON_EQ(pxTimerBuffer, NULL, NULL, "WARN", null_timer_ptr_count); + + FAIL_ON_EQ(pxTimerBuffer->status & TIMER_CREATED, TIMER_CREATED, pxTimerBuffer, "CRIT", static_timer_recreation_count); + pxTimerBuffer->status = TIMER_CREATED; + + pxTimerBuffer->xTimerPeriodInTicks = xTimerPeriodInTicks; + + pxTimerBuffer->uxAutoReload = uxAutoReload; + + FAIL_ON_EQ(pxCallbackFunction, NULL, NULL, "WARN", null_callback_function_specified_count); + pxTimerBuffer->pxCallbackFunction = pxCallbackFunction; + + pxTimerBuffer->pvTimerID = pvTimerID; + + return pxTimerBuffer; +} + +BaseType_t xTimerStop( + TimerHandle_t xTimer, + TickType_t xTicksToWait) +{ + FAIL_ON_EQ(xTimer, NULL, pdFAIL, "WARN", null_timer_ptr_count); + xTimer->status &= ~TIMER_ACTIVE; + + (void) unregister_timer(xTimer); + + return pdPASS; +} + +BaseType_t xTimerChangePeriod( + TimerHandle_t xTimer, + TickType_t xNewPeriod, + TickType_t xTicksToWait) +{ + FAIL_ON_EQ(xTimer, NULL, pdFAIL, "WARN", null_timer_ptr_count); + WARN_ON_EQ(xTimer->status & TIMER_ACTIVE, TIMER_ACTIVE, "WARN", operated_on_active_timer_count); + + FAIL_ON_LE(xNewPeriod, 0, pdFAIL, "ERROR", non_positive_timer_period_count); + + xTimer->xTimerPeriodInTicks = xNewPeriod; + + return pdPASS; +} + +BaseType_t xTimerStart( + TimerHandle_t xTimer, + TickType_t xTicksToWait) +{ + FAIL_ON_EQ(xTimer, NULL, pdFAIL, "WARN", null_timer_ptr_count); + xTimer->status |= TIMER_ACTIVE; + xTimer->timer_ticks_left = xTimer->xTimerPeriodInTicks; + + FAIL_ON_EQ(register_timer(xTimer), -1, pdFAIL, "WARN", timer_queue_overflow_count); + + return pdPASS; +} diff --git a/KPI_Rover/Buzzer/mock-suite/test/buzzer-driver.c b/KPI_Rover/Buzzer/mock-suite/test/buzzer-driver.c new file mode 100644 index 0000000..c92ad41 --- /dev/null +++ b/KPI_Rover/Buzzer/mock-suite/test/buzzer-driver.c @@ -0,0 +1,226 @@ +#include +#include + +#include "main.h" +#include "scheduler.h" +#include "cmsis_os2.h" +#include "test.h" + +#include "driver.h" + +#define LEN(a) sizeof(a) / sizeof(a[0]) + +#define PREP(...) \ + struct BuzzerObject bo; \ + struct StaticTimer_t tim; \ + memset(&bo, 0, sizeof(bo)); \ + memset(&tim, 0, sizeof(tim)); \ + system_ticks = 0; \ + gpio_init(); \ + timers_init(); \ + osTimerAttr_t attr = { \ + .name = NULL, \ + .attr_bits = 0, \ + .cb_mem = &tim, \ + .cb_size = sizeof(tim) \ + }; \ + osTimerNew(timer_cb, 1, &bo, &attr); \ + osTimerStart(&tim, 10) + +void timer_cb(TimerHandle_t const tim_ptr) +{ + Buzzer_TimerTask(tim_ptr->pvTimerID); +} + +int driver_configure_correct(void) +{ + PREP(); + + for (int i = 0x8000; i > 0; i >>= 1) + if (Buzzer_ConfigurePort(&bo, GPIOD, i)) + return i; + + return 0; +} + +int driver_configure_wrong(void) +{ + PREP(); + + uint16_t broken_values[] = { + 0xF000, + 0xFFFF, + 0x0000, + 0xA5A5, + 0xDEAD, + 0xBEEF + }; + + for (int i = 0; i < LEN(broken_values); i++) + if (BUZZER_PIN_ERROR != Buzzer_ConfigurePort(&bo, GPIOD, broken_values[i])) + return i+1; + + return 0; +} + +int driver_enable_correct(void) +{ + PREP(); + + if (Buzzer_ConfigurePort(&bo, GPIOD, 0x8000)) + return 1; + + if (Buzzer_Enable(&bo)) + return 2; + + scheduler_run_for(15); + + if (!(GPIOD->ODR & 0x8000)) + return 3; + + return 0; +} + +int driver_enable_wrong(void) +{ + PREP(); + + if (BUZZER_PIN_ERROR != Buzzer_ConfigurePort(&bo, GPIOD, 0xF000)) + return 1; + + Buzzer_Enable(&bo); + + scheduler_run_for(15); + + if (GPIOD->ODR & 0xF000) + return 2; + + return 0; +} + +int driver_disable_correct(void) +{ + PREP(); + GPIOD->ODR = 0x1; + + if (Buzzer_ConfigurePort(&bo, GPIOD, 0x0001)) + return 1; + + if (Buzzer_Disable(&bo)) + return 2; + + scheduler_run_for(15); + + if (GPIOD->ODR & 0x0001) + return 3; + + return 0; +} + +int driver_disable_wrong(void) +{ + PREP(); + GPIOD->ODR = 0x1; + + if (BUZZER_PIN_ERROR != Buzzer_ConfigurePort(&bo, GPIOD, 0x0101)) + return 1; + + Buzzer_Disable(&bo); + + scheduler_run_for(15); + + if (!(GPIOD->ODR & 0x0001)) + return 2; + + return 0; +} + + +int driver_pulse_correct(void) +{ + PREP(); + + if (Buzzer_ConfigurePort(&bo, GPIOD, 0x0001)) + return 1; + + if (Buzzer_Pulse(&bo, 200, 500, 2000)) + return 2; + + scheduler_run_for(15); + + if (!(GPIOD->ODR & 0x0001)) + return 3; + + scheduler_run_for(210); + + if (GPIOD->ODR & 0x0001) + return 4; + + scheduler_run_for(310); + + if (!(GPIOD->ODR & 0x0001)) + return 5; + + scheduler_run_for(210); + + if (GPIOD->ODR & 0x0001) + return 6; + + scheduler_run_for(1310); + + if (GPIOD->ODR & 0x0001) + return 7; + + return 0; +} + +int driver_preemptive_pulse_stop(void) +{ + PREP(); + + if (Buzzer_ConfigurePort(&bo, GPIOD, 0x0001)) + return 1; + + if (Buzzer_Pulse(&bo, 100, 200, 1000)) + return 2; + + scheduler_run_for(530); + + if (Buzzer_Disable(&bo)) + return 3; + + scheduler_run_for(15); + + if (GPIOD->ODR & 1) + return 4; + + return 0; +} + +int dummy_broken_test(void) +{ + PREP(); + + return Buzzer_ConfigurePort(&bo, GPIOD, 0xF000); +} + +int main(void) +{ + INIT(); + + TEST(driver_configure_correct); + TEST(driver_configure_wrong); + + TEST(driver_enable_correct); + TEST(driver_enable_wrong); + + TEST(driver_disable_correct); + TEST(driver_disable_wrong); + + TEST(driver_pulse_correct); + TEST(driver_preemptive_pulse_stop); + + TEST(dummy_broken_test); + + SUMMARY(); +} diff --git a/KPI_Rover/Buzzer/mock-suite/test/buzzer-driver.cpp b/KPI_Rover/Buzzer/mock-suite/test/buzzer-driver.cpp new file mode 100644 index 0000000..a896722 --- /dev/null +++ b/KPI_Rover/Buzzer/mock-suite/test/buzzer-driver.cpp @@ -0,0 +1,165 @@ +#include + +#include +#include + +#include + +extern "C" { +#include "main.h" +#include "scheduler.h" +#include "cmsis_os2.h" +//#include "test.h" + +#include "driver.h" +} + +#define LEN(a) sizeof(a) / sizeof(a[0]) + +#define PREP(...) \ + struct BuzzerObject bo; \ + struct StaticTimer_t tim; \ + memset(&bo, 0, sizeof(bo)); \ + memset(&tim, 0, sizeof(tim)); \ + system_ticks = 0; \ + gpio_init(); \ + timers_init(); \ + osTimerAttr_t attr = { \ + .name = NULL, \ + .attr_bits = 0, \ + .cb_mem = &tim, \ + .cb_size = sizeof(tim) \ + }; \ + osTimerNew(timer_cb, 1, &bo, &attr); \ + osTimerStart(&tim, 10) + +void timer_cb(TimerHandle_t const tim_ptr) +{ + Buzzer_TimerTask((struct BuzzerObject *) tim_ptr->pvTimerID); +} + +TEST(buzzer_driver, configure_correct) +{ + PREP(); + + for (int i = 0x8000; i > 0; i >>= 1) + EXPECT_EQ(Buzzer_ConfigurePort(&bo, GPIOD, i), 0) << i << " fails the configuration" << ::std::endl; +} + +TEST(buzzer_driver, configure_wrong) +{ + PREP(); + + uint16_t broken_values[] = { + 0xF000, + 0xFFFF, + 0x0000, + 0xA5A5, + 0xDEAD, + 0xBEEF + }; + + for (unsigned int i = 0; i < LEN(broken_values); i++) + EXPECT_EQ(BUZZER_PIN_ERROR, Buzzer_ConfigurePort(&bo, GPIOD, broken_values[i])) << i << " does not cause pin error" << ::std::endl; +} + +TEST(buzzer_driver, enable_correct) +{ + PREP(); + + EXPECT_EQ(0, Buzzer_ConfigurePort(&bo, GPIOD, 0x8000)); + + Buzzer_Enable(&bo); + + scheduler_run_for(15); + + EXPECT_EQ(0x8000, GPIOD->ODR); +} + +TEST(buzzer_driver, enable_wrong) +{ + PREP(); + + EXPECT_EQ(BUZZER_PIN_ERROR, Buzzer_ConfigurePort(&bo, GPIOD, 0xF000)); + + Buzzer_Enable(&bo); + + scheduler_run_for(15); + + EXPECT_EQ(0x0000, GPIOD->ODR); +} + +TEST(buzzer_driver, disable_correct) +{ + PREP(); + GPIOD->ODR = 0x0001; + + EXPECT_EQ(0, Buzzer_ConfigurePort(&bo, GPIOD, 0x0001)); + + Buzzer_Disable(&bo); + + scheduler_run_for(15); + + EXPECT_EQ(0x0000, GPIOD->ODR); +} + +TEST(buzzer_driver, disable_wrong) +{ + PREP(); + GPIOD->ODR = 0x0001; + + EXPECT_EQ(BUZZER_PIN_ERROR, Buzzer_ConfigurePort(&bo, GPIOD, 0x0101)); + + Buzzer_Disable(&bo); + + scheduler_run_for(15); + + EXPECT_EQ(0x0001, GPIOD->ODR); +} + + +TEST(buzzer_driver, pulse_correct) +{ + PREP(); + + EXPECT_EQ(0, Buzzer_ConfigurePort(&bo, GPIOD, 0x0001)); + + EXPECT_EQ(0, Buzzer_Pulse(&bo, 200, 500, 2000)); + + scheduler_run_for(15); + + EXPECT_EQ(0x0001, GPIOD->ODR); + + scheduler_run_for(210); + + EXPECT_EQ(0x0000, GPIOD->ODR); + + scheduler_run_for(310); + + EXPECT_EQ(0x0001, GPIOD->ODR); + + scheduler_run_for(210); + + EXPECT_EQ(0x0000, GPIOD->ODR); + + scheduler_run_for(1310); + + EXPECT_EQ(0x0000, GPIOD->ODR); +} + +TEST(buzzer_driver, preemptive_pulse_stop) +{ + PREP(); + + EXPECT_EQ(0, Buzzer_ConfigurePort(&bo, GPIOD, 0x0001)); + + Buzzer_Pulse(&bo, 100, 200, 1000); + + scheduler_run_for(530); + + Buzzer_Disable(&bo); + + scheduler_run_for(15); + + EXPECT_EQ(0x0000, GPIOD->ODR); +}