From fd02fb65ae3c769f77fcb080f80fdceb23aae7ef Mon Sep 17 00:00:00 2001 From: hasslesstech Date: Sat, 19 Jul 2025 14:59:37 +0300 Subject: [PATCH 01/13] Issue #15: Add buzzer driver implementation --- KPI_Rover/Buzzer/driver.c | 91 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 91 insertions(+) create mode 100644 KPI_Rover/Buzzer/driver.c diff --git a/KPI_Rover/Buzzer/driver.c b/KPI_Rover/Buzzer/driver.c new file mode 100644 index 0000000..3bdb93e --- /dev/null +++ b/KPI_Rover/Buzzer/driver.c @@ -0,0 +1,91 @@ +#include "stm32f4xx_hal.h" + +#include "FreeRTOS.h" +#include "task.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 CHECK_ERROR(condition, err_value) do { \ + if (condition) { \ + errors = (err_value); \ + goto fail; \ + } \ + } while (0) + +static GPIO_TypeDef *GPIO_buzzer_port; +static uint16_t GPIO_buzzer_pin; +static int buzzer_initialized; + +unsigned int Buzzer_ConfigurePort(const GPIO_TypeDef * const gpio_port, const uint16_t gpio_pin) +{ + unsigned int errors = 0; + + CHECK_ERROR(gpio_pin > 15, BUZZER_PIN_ERROR); + + GPIO_buzzer_port = (GPIO_TypeDef *) gpio_port; + GPIO_buzzer_pin = (uint16_t) gpio_pin; + + buzzer_initialized = 1; + + return errors; + +fail: + buzzer_initialized = 0; + return errors; +} + +unsigned int Buzzer_Enable(void) +{ + unsigned int errors = 0; + + CHECK_ERROR(!buzzer_initialized, BUZZER_NOT_INITIALIZED_ERROR); + + HAL_GPIO_WritePin(GPIO_buzzer_port, GPIO_buzzer_pin, GPIO_PIN_SET); + +fail: + return errors; +} + +unsigned int Buzzer_Disable(void) +{ + unsigned int errors = 0; + + CHECK_ERROR(!buzzer_initialized, BUZZER_NOT_INITIALIZED_ERROR); + + HAL_GPIO_WritePin(GPIO_buzzer_port, GPIO_buzzer_pin, GPIO_PIN_RESET); + +fail: + return errors; +} + +unsigned int Buzzer_Pulse(const unsigned int on_time_ms, const unsigned int period_time_ms, const unsigned int total_active_time_ms) +{ + unsigned int errors = 0; + + CHECK_ERROR(!buzzer_initialized, BUZZER_NOT_INITIALIZED_ERROR); + + const TickType_t on_time_ticks = pdMS_TO_TICKS(on_time_ms); + CHECK_ERROR(!on_time_ticks, BUZZER_ZERO_ONTIME_ERROR); + + const TickType_t off_time_ticks = pdMS_TO_TICKS(period_time_ms) - on_time_ticks; + CHECK_ERROR(!off_time_ticks, BUZZER_ZERO_OFFTIME_ERROR); + + const unsigned int total_beep_amount = total_active_time_ms / period_time_ms; + + for (unsigned int i = 0; i < total_beep_amount; i++) + { + Buzzer_Enable(); + vTaskDelay(on_time_ticks); + Buzzer_Disable(); + vTaskDelay(off_time_ticks); + } + +fail: + Buzzer_Disable(); + return errors; +} From 91b6900a9dfa31a1c83cdee5b421039cb155c422 Mon Sep 17 00:00:00 2001 From: hasslesstech Date: Sat, 26 Jul 2025 16:55:40 +0300 Subject: [PATCH 02/13] Issue #15: Extract definitions from driver.c into their separate file driver.h --- KPI_Rover/Buzzer/driver.c | 7 +------ KPI_Rover/Buzzer/driver.h | 18 ++++++++++++++++++ 2 files changed, 19 insertions(+), 6 deletions(-) create mode 100644 KPI_Rover/Buzzer/driver.h diff --git a/KPI_Rover/Buzzer/driver.c b/KPI_Rover/Buzzer/driver.c index 3bdb93e..4abb232 100644 --- a/KPI_Rover/Buzzer/driver.c +++ b/KPI_Rover/Buzzer/driver.c @@ -3,12 +3,7 @@ #include "FreeRTOS.h" #include "task.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 +#include "driver.h" #define CHECK_ERROR(condition, err_value) do { \ if (condition) { \ diff --git a/KPI_Rover/Buzzer/driver.h b/KPI_Rover/Buzzer/driver.h new file mode 100644 index 0000000..c4a49e0 --- /dev/null +++ b/KPI_Rover/Buzzer/driver.h @@ -0,0 +1,18 @@ +#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 + +unsigned int Buzzer_ConfigurePort(const GPIO_TypeDef * const gpio_port, const uint16_t gpio_pin); +unsigned int Buzzer_Enable(void); +unsigned int Buzzer_Disable(void); +unsigned int Buzzer_Pulse(const unsigned int on_time_ms, const unsigned int period_time_ms, const unsigned int total_active_time_ms); + +#endif /* __BUZZER_DRIVER */ From ee933aa4a8533456bf54d8f89a7ae8924ea28a00 Mon Sep 17 00:00:00 2001 From: hasslesstech Date: Fri, 1 Aug 2025 14:14:07 +0300 Subject: [PATCH 03/13] Issue #15: Add buzzer manager task --- KPI_Rover/Buzzer/manager.c | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 KPI_Rover/Buzzer/manager.c diff --git a/KPI_Rover/Buzzer/manager.c b/KPI_Rover/Buzzer/manager.c new file mode 100644 index 0000000..d26fb04 --- /dev/null +++ b/KPI_Rover/Buzzer/manager.c @@ -0,0 +1,27 @@ +#include "FreeRTOS.h" +#include "task.h" + +#include "ul_ulog.h" + +#include "driver.h" + +void buzzer_manager_task(void *d) +{ + if (Buzzer_ConfigurePort(GPIOD, GPIO_PIN_15)) + { + ULOG_ERROR("Failed to configure buzzer driver port"); + vTaskDelete(NULL); + } + + for ( ; ; ) + { + Buzzer_Enable(); + vTaskDelay(pdMS_TO_TICKS(3000)); + Buzzer_Disable(); + vTaskDelay(pdMS_TO_TICKS(3000)); + Buzzer_Pulse(500, 1000, 5000); + Buzzer_Pulse(200, 1000, 5000); + Buzzer_Pulse(100, 300, 5000); + Buzzer_Pulse(250, 300, 5000); + } +} From f23af02fd8586978a496dae4ab3912c69034ca9b Mon Sep 17 00:00:00 2001 From: hasslesstech Date: Fri, 1 Aug 2025 20:02:14 +0300 Subject: [PATCH 04/13] Issue #15: fix configuration sanity check --- KPI_Rover/Buzzer/driver.c | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/KPI_Rover/Buzzer/driver.c b/KPI_Rover/Buzzer/driver.c index 4abb232..12678cc 100644 --- a/KPI_Rover/Buzzer/driver.c +++ b/KPI_Rover/Buzzer/driver.c @@ -16,11 +16,27 @@ static GPIO_TypeDef *GPIO_buzzer_port; static uint16_t GPIO_buzzer_pin; static int buzzer_initialized; +static unsigned int count_bits_16bit(uint16_t value) +{ + unsigned int mask = 0x8000, + result = 0; + + while (mask) + { + if (value & mask) + result++; + + mask >>= 1; + } + + return result; +} + unsigned int Buzzer_ConfigurePort(const GPIO_TypeDef * const gpio_port, const uint16_t gpio_pin) { unsigned int errors = 0; - CHECK_ERROR(gpio_pin > 15, BUZZER_PIN_ERROR); + CHECK_ERROR(count_bits_16bit(gpio_pin) != 1, BUZZER_PIN_ERROR); GPIO_buzzer_port = (GPIO_TypeDef *) gpio_port; GPIO_buzzer_pin = (uint16_t) gpio_pin; From 31408ae500b9745165aaf208e720e654a09ca6dc Mon Sep 17 00:00:00 2001 From: hasslesstech Date: Fri, 1 Aug 2025 20:22:48 +0300 Subject: [PATCH 05/13] Issue #15: improve total timing precision of pulse function --- KPI_Rover/Buzzer/driver.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/KPI_Rover/Buzzer/driver.c b/KPI_Rover/Buzzer/driver.c index 12678cc..c576be4 100644 --- a/KPI_Rover/Buzzer/driver.c +++ b/KPI_Rover/Buzzer/driver.c @@ -86,6 +86,8 @@ unsigned int Buzzer_Pulse(const unsigned int on_time_ms, const unsigned int peri const TickType_t off_time_ticks = pdMS_TO_TICKS(period_time_ms) - on_time_ticks; CHECK_ERROR(!off_time_ticks, BUZZER_ZERO_OFFTIME_ERROR); + const TickType_t last_on_time_ticks = pdMS_TO_TICKS(total_active_time_ms % period_time_ms); + const unsigned int total_beep_amount = total_active_time_ms / period_time_ms; for (unsigned int i = 0; i < total_beep_amount; i++) @@ -96,6 +98,13 @@ unsigned int Buzzer_Pulse(const unsigned int on_time_ms, const unsigned int peri vTaskDelay(off_time_ticks); } + if (last_on_time_ticks) + { + Buzzer_Enable(); + vTaskDelay(last_on_time_ticks); + Buzzer_Disable(); + } + fail: Buzzer_Disable(); return errors; From 5e86956de395a8806677387dc3d68ecb8633270c Mon Sep 17 00:00:00 2001 From: hasslesstech Date: Fri, 1 Aug 2025 20:28:48 +0300 Subject: [PATCH 06/13] Issue #15: add new task for buzzer manager --- Core/Src/main.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/Core/Src/main.c b/Core/Src/main.c index d62d1fe..07dd08f 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 = 16 * 4, + .priority = (osPriority_t) osPriorityHigh, + }; + (void) osThreadNew(buzzer_manager_task, NULL, &buzzer_task_attrs); + /* USER CODE END RTOS_THREADS */ From 26aa038f381ac5ab14dffe34ea717f690bb98540 Mon Sep 17 00:00:00 2001 From: hasslesstech Date: Sat, 16 Aug 2025 21:26:16 +0300 Subject: [PATCH 07/13] Issue #15: [fix] make pulse function non-blocking and abortable --- KPI_Rover/Buzzer/driver.c | 135 ++++++++++++++++++++++++++++++++----- KPI_Rover/Buzzer/driver.h | 2 + KPI_Rover/Buzzer/manager.c | 4 ++ 3 files changed, 123 insertions(+), 18 deletions(-) diff --git a/KPI_Rover/Buzzer/driver.c b/KPI_Rover/Buzzer/driver.c index c576be4..0eb2330 100644 --- a/KPI_Rover/Buzzer/driver.c +++ b/KPI_Rover/Buzzer/driver.c @@ -2,9 +2,12 @@ #include "FreeRTOS.h" #include "task.h" +#include "timers.h" #include "driver.h" +#define BUZZER_BLOCKING_TIME_LIMIT 1000 + #define CHECK_ERROR(condition, err_value) do { \ if (condition) { \ errors = (err_value); \ @@ -12,10 +15,29 @@ } \ } while (0) +enum BuzzerState { + BUZZER_ON, + BUZZER_OFF, + BUZZER_NOT_ACTIVE, + IMPOSSIBLE_STATE +}; + +struct BuzzerStateMemory { + TickType_t on_duration; + TickType_t off_duration; + TickType_t total_active_time; + TickType_t active_time_limit; + enum BuzzerState current_state; +}; + static GPIO_TypeDef *GPIO_buzzer_port; static uint16_t GPIO_buzzer_pin; static int buzzer_initialized; +static TimerHandle_t timer_handle; +static StaticTimer_t timer; +static struct BuzzerStateMemory bsm; + static unsigned int count_bits_16bit(uint16_t value) { unsigned int mask = 0x8000, @@ -32,8 +54,18 @@ static unsigned int count_bits_16bit(uint16_t value) return result; } +static void Buzzer_ResetTimer(void) +{ + if (timer_handle == NULL) + return; + + (void) xTimerStop(timer_handle, BUZZER_BLOCKING_TIME_LIMIT); +} + unsigned int Buzzer_ConfigurePort(const GPIO_TypeDef * const gpio_port, const uint16_t gpio_pin) { + Buzzer_ResetTimer(); + unsigned int errors = 0; CHECK_ERROR(count_bits_16bit(gpio_pin) != 1, BUZZER_PIN_ERROR); @@ -50,7 +82,7 @@ unsigned int Buzzer_ConfigurePort(const GPIO_TypeDef * const gpio_port, const ui return errors; } -unsigned int Buzzer_Enable(void) +static unsigned int Buzzer_SetON(void) { unsigned int errors = 0; @@ -62,7 +94,7 @@ unsigned int Buzzer_Enable(void) return errors; } -unsigned int Buzzer_Disable(void) +static unsigned int Buzzer_SetOFF(void) { unsigned int errors = 0; @@ -74,8 +106,67 @@ unsigned int Buzzer_Disable(void) return errors; } +unsigned int Buzzer_Enable(void) +{ + Buzzer_ResetTimer(); + return Buzzer_SetON(); +} + +unsigned int Buzzer_Disable(void) +{ + Buzzer_ResetTimer(); + return Buzzer_SetOFF(); +} + +static void Buzzer_TimerCallback(TimerHandle_t t) +{ + TickType_t new_period; + + switch (bsm.current_state) { + case BUZZER_ON: + Buzzer_SetOFF(); // disable first, determine action course next + bsm.current_state = BUZZER_OFF; + bsm.total_active_time += bsm.on_duration; + + new_period = bsm.total_active_time + bsm.off_duration <= bsm.active_time_limit + ? bsm.off_duration + : bsm.active_time_limit - bsm.total_active_time; + + if (!new_period) + break; + + (void) xTimerChangePeriod(timer_handle, new_period, 0); + (void) xTimerStart(timer_handle, 0); + break; + + case BUZZER_OFF: + bsm.current_state = BUZZER_ON; + bsm.total_active_time += bsm.off_duration; + + new_period = bsm.total_active_time + bsm.on_duration <= bsm.active_time_limit + ? bsm.on_duration + : bsm.active_time_limit - bsm.total_active_time; + + if (!new_period) + break; + + (void) xTimerChangePeriod(timer_handle, new_period, 0); + (void) xTimerStart(timer_handle, 0); + Buzzer_SetON(); + break; + + case BUZZER_NOT_ACTIVE: + case IMPOSSIBLE_STATE: + default: + // why are we here then? + break; + } +} + unsigned int Buzzer_Pulse(const unsigned int on_time_ms, const unsigned int period_time_ms, const unsigned int total_active_time_ms) { + Buzzer_ResetTimer(); + unsigned int errors = 0; CHECK_ERROR(!buzzer_initialized, BUZZER_NOT_INITIALIZED_ERROR); @@ -86,26 +177,34 @@ unsigned int Buzzer_Pulse(const unsigned int on_time_ms, const unsigned int peri const TickType_t off_time_ticks = pdMS_TO_TICKS(period_time_ms) - on_time_ticks; CHECK_ERROR(!off_time_ticks, BUZZER_ZERO_OFFTIME_ERROR); - const TickType_t last_on_time_ticks = pdMS_TO_TICKS(total_active_time_ms % period_time_ms); + const TickType_t active_time_limit = pdMS_TO_TICKS(total_active_time_ms); + CHECK_ERROR(!active_time_limit, BUZZER_ZERO_ACTIVE_TIME_ERROR); + + if (timer_handle == NULL) { + timer_handle = xTimerCreateStatic( + "", + on_time_ticks, + pdFALSE, + 0, + Buzzer_TimerCallback, + &timer); + } else { + CHECK_ERROR(xTimerChangePeriod(timer_handle, on_time_ticks, BUZZER_BLOCKING_TIME_LIMIT) == pdFAIL, BUZZER_TIMER_BUSY); + } - const unsigned int total_beep_amount = total_active_time_ms / period_time_ms; + CHECK_ERROR(xTimerStart(timer_handle, BUZZER_BLOCKING_TIME_LIMIT) == pdFAIL, BUZZER_TIMER_BUSY); + Buzzer_SetON(); - for (unsigned int i = 0; i < total_beep_amount; i++) - { - Buzzer_Enable(); - vTaskDelay(on_time_ticks); - Buzzer_Disable(); - vTaskDelay(off_time_ticks); - } + bsm.on_duration = on_time_ticks; + bsm.off_duration = off_time_ticks; + bsm.total_active_time = 0; + bsm.active_time_limit = active_time_limit; + bsm.current_state = BUZZER_ON; - if (last_on_time_ticks) - { - Buzzer_Enable(); - vTaskDelay(last_on_time_ticks); - Buzzer_Disable(); - } + return 0; fail: - Buzzer_Disable(); + Buzzer_ResetTimer(); + Buzzer_SetOFF(); return errors; } diff --git a/KPI_Rover/Buzzer/driver.h b/KPI_Rover/Buzzer/driver.h index c4a49e0..4b0d15d 100644 --- a/KPI_Rover/Buzzer/driver.h +++ b/KPI_Rover/Buzzer/driver.h @@ -9,6 +9,8 @@ #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 unsigned int Buzzer_ConfigurePort(const GPIO_TypeDef * const gpio_port, const uint16_t gpio_pin); unsigned int Buzzer_Enable(void); diff --git a/KPI_Rover/Buzzer/manager.c b/KPI_Rover/Buzzer/manager.c index d26fb04..077b9da 100644 --- a/KPI_Rover/Buzzer/manager.c +++ b/KPI_Rover/Buzzer/manager.c @@ -20,8 +20,12 @@ void buzzer_manager_task(void *d) Buzzer_Disable(); vTaskDelay(pdMS_TO_TICKS(3000)); Buzzer_Pulse(500, 1000, 5000); + vTaskDelay(pdMS_TO_TICKS(5000)); Buzzer_Pulse(200, 1000, 5000); + vTaskDelay(pdMS_TO_TICKS(5000)); Buzzer_Pulse(100, 300, 5000); + vTaskDelay(pdMS_TO_TICKS(5000)); Buzzer_Pulse(250, 300, 5000); + vTaskDelay(pdMS_TO_TICKS(1000)); // intentionally shorter delay; next command must abort this one } } From ee5f7aabb08268521473c0316a68d0245d90df00 Mon Sep 17 00:00:00 2001 From: hasslesstech Date: Sat, 16 Aug 2025 21:27:35 +0300 Subject: [PATCH 08/13] Issue #15: simplify count_bits_16bit function --- KPI_Rover/Buzzer/driver.c | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/KPI_Rover/Buzzer/driver.c b/KPI_Rover/Buzzer/driver.c index 0eb2330..545d921 100644 --- a/KPI_Rover/Buzzer/driver.c +++ b/KPI_Rover/Buzzer/driver.c @@ -40,17 +40,12 @@ static struct BuzzerStateMemory bsm; static unsigned int count_bits_16bit(uint16_t value) { - unsigned int mask = 0x8000, - result = 0; + unsigned int result = 0; - while (mask) - { - if (value & mask) + for ( ; value; value >>= 1) + if (value & 1) result++; - mask >>= 1; - } - return result; } From 133cf061dc47c53555e0af20f4e0688dc4763c7d Mon Sep 17 00:00:00 2001 From: hasslesstech Date: Sun, 14 Sep 2025 21:06:17 +0300 Subject: [PATCH 09/13] Issue #15: Extract memory from driver to manager --- KPI_Rover/Buzzer/driver.c | 165 +++++++++++++------------------------ KPI_Rover/Buzzer/driver.h | 31 ++++++- KPI_Rover/Buzzer/manager.c | 49 +++++++++-- 3 files changed, 125 insertions(+), 120 deletions(-) diff --git a/KPI_Rover/Buzzer/driver.c b/KPI_Rover/Buzzer/driver.c index 545d921..d89fef2 100644 --- a/KPI_Rover/Buzzer/driver.c +++ b/KPI_Rover/Buzzer/driver.c @@ -1,8 +1,6 @@ -#include "stm32f4xx_hal.h" +#include -#include "FreeRTOS.h" -#include "task.h" -#include "timers.h" +#include "stm32f4xx_hal.h" #include "driver.h" @@ -15,29 +13,6 @@ } \ } while (0) -enum BuzzerState { - BUZZER_ON, - BUZZER_OFF, - BUZZER_NOT_ACTIVE, - IMPOSSIBLE_STATE -}; - -struct BuzzerStateMemory { - TickType_t on_duration; - TickType_t off_duration; - TickType_t total_active_time; - TickType_t active_time_limit; - enum BuzzerState current_state; -}; - -static GPIO_TypeDef *GPIO_buzzer_port; -static uint16_t GPIO_buzzer_pin; -static int buzzer_initialized; - -static TimerHandle_t timer_handle; -static StaticTimer_t timer; -static struct BuzzerStateMemory bsm; - static unsigned int count_bits_16bit(uint16_t value) { unsigned int result = 0; @@ -49,157 +24,129 @@ static unsigned int count_bits_16bit(uint16_t value) return result; } -static void Buzzer_ResetTimer(void) -{ - if (timer_handle == NULL) - return; - - (void) xTimerStop(timer_handle, BUZZER_BLOCKING_TIME_LIMIT); -} - -unsigned int Buzzer_ConfigurePort(const GPIO_TypeDef * const gpio_port, const uint16_t gpio_pin) +unsigned int Buzzer_ConfigurePort(struct BuzzerObject * const self, const GPIO_TypeDef * const gpio_port, const uint16_t gpio_pin) { - Buzzer_ResetTimer(); + self->bsm.current_state = BUZZER_NOT_TIMED; unsigned int errors = 0; CHECK_ERROR(count_bits_16bit(gpio_pin) != 1, BUZZER_PIN_ERROR); - GPIO_buzzer_port = (GPIO_TypeDef *) gpio_port; - GPIO_buzzer_pin = (uint16_t) gpio_pin; + self->GPIO_buzzer_port = (GPIO_TypeDef *) gpio_port; + self->GPIO_buzzer_pin = (uint16_t) gpio_pin; - buzzer_initialized = 1; + self->buzzer_initialized = 1; return errors; fail: - buzzer_initialized = 0; + self->buzzer_initialized = 0; return errors; } -static unsigned int Buzzer_SetON(void) +static unsigned int Buzzer_SetON(struct BuzzerObject * const self) { unsigned int errors = 0; - CHECK_ERROR(!buzzer_initialized, BUZZER_NOT_INITIALIZED_ERROR); + CHECK_ERROR(!self->buzzer_initialized, BUZZER_NOT_INITIALIZED_ERROR); - HAL_GPIO_WritePin(GPIO_buzzer_port, GPIO_buzzer_pin, GPIO_PIN_SET); + HAL_GPIO_WritePin(self->GPIO_buzzer_port, self->GPIO_buzzer_pin, GPIO_PIN_SET); fail: return errors; } -static unsigned int Buzzer_SetOFF(void) +static unsigned int Buzzer_SetOFF(struct BuzzerObject * const self) { unsigned int errors = 0; - CHECK_ERROR(!buzzer_initialized, BUZZER_NOT_INITIALIZED_ERROR); + CHECK_ERROR(!self->buzzer_initialized, BUZZER_NOT_INITIALIZED_ERROR); - HAL_GPIO_WritePin(GPIO_buzzer_port, GPIO_buzzer_pin, GPIO_PIN_RESET); + HAL_GPIO_WritePin(self->GPIO_buzzer_port, self->GPIO_buzzer_pin, GPIO_PIN_RESET); fail: return errors; } -unsigned int Buzzer_Enable(void) +unsigned int Buzzer_Enable(struct BuzzerObject * const self) { - Buzzer_ResetTimer(); - return Buzzer_SetON(); + self->bsm.current_state = BUZZER_NOT_TIMED; + return Buzzer_SetON(self); } -unsigned int Buzzer_Disable(void) +unsigned int Buzzer_Disable(struct BuzzerObject * const self) { - Buzzer_ResetTimer(); - return Buzzer_SetOFF(); + self->bsm.current_state = BUZZER_NOT_TIMED; + return Buzzer_SetOFF(self); } -static void Buzzer_TimerCallback(TimerHandle_t t) +void Buzzer_TimerTask(struct BuzzerObject * const self) { - TickType_t new_period; + if (self->bsm.current_state == BUZZER_NOT_TIMED) + return; - switch (bsm.current_state) { - case BUZZER_ON: - Buzzer_SetOFF(); // disable first, determine action course next - bsm.current_state = BUZZER_OFF; - bsm.total_active_time += bsm.on_duration; + self->bsm.total_active_time_left--; + self->bsm.current_state_valid_for--; - new_period = bsm.total_active_time + bsm.off_duration <= bsm.active_time_limit - ? bsm.off_duration - : bsm.active_time_limit - bsm.total_active_time; + if (!self->bsm.total_active_time_left) { + Buzzer_SetOFF(self); + self->bsm.current_state = BUZZER_NOT_TIMED; + return; + } - if (!new_period) - break; + if (self->bsm.current_state_valid_for) + return; - (void) xTimerChangePeriod(timer_handle, new_period, 0); - (void) xTimerStart(timer_handle, 0); + switch (self->bsm.current_state) { + case BUZZER_ON: + Buzzer_SetOFF(self); // disable first, determine action course next + self->bsm.current_state = BUZZER_OFF; + self->bsm.current_state_valid_for = self->bsm.off_duration; break; case BUZZER_OFF: - bsm.current_state = BUZZER_ON; - bsm.total_active_time += bsm.off_duration; - - new_period = bsm.total_active_time + bsm.on_duration <= bsm.active_time_limit - ? bsm.on_duration - : bsm.active_time_limit - bsm.total_active_time; - - if (!new_period) - break; - - (void) xTimerChangePeriod(timer_handle, new_period, 0); - (void) xTimerStart(timer_handle, 0); - Buzzer_SetON(); + self->bsm.current_state = BUZZER_ON; + self->bsm.current_state_valid_for = self->bsm.on_duration; + Buzzer_SetON(self); break; - case BUZZER_NOT_ACTIVE: + case BUZZER_NOT_TIMED: case IMPOSSIBLE_STATE: default: - // why are we here then? + // how did we get here? break; } } -unsigned int Buzzer_Pulse(const unsigned int on_time_ms, const unsigned int period_time_ms, const unsigned int total_active_time_ms) +unsigned int Buzzer_Pulse(struct BuzzerObject * const self, const unsigned int on_time_ms, const unsigned int period_time_ms, const unsigned int total_active_time_ms) { - Buzzer_ResetTimer(); + self->bsm.current_state = BUZZER_NOT_TIMED; unsigned int errors = 0; - CHECK_ERROR(!buzzer_initialized, BUZZER_NOT_INITIALIZED_ERROR); + CHECK_ERROR(!self->buzzer_initialized, BUZZER_NOT_INITIALIZED_ERROR); - const TickType_t on_time_ticks = pdMS_TO_TICKS(on_time_ms); + const int on_time_ticks = on_time_ms / 10; CHECK_ERROR(!on_time_ticks, BUZZER_ZERO_ONTIME_ERROR); - const TickType_t off_time_ticks = pdMS_TO_TICKS(period_time_ms) - on_time_ticks; + const int off_time_ticks = (period_time_ms / 10) - on_time_ticks; CHECK_ERROR(!off_time_ticks, BUZZER_ZERO_OFFTIME_ERROR); - const TickType_t active_time_limit = pdMS_TO_TICKS(total_active_time_ms); + const int active_time_limit = total_active_time_ms / 10; CHECK_ERROR(!active_time_limit, BUZZER_ZERO_ACTIVE_TIME_ERROR); - if (timer_handle == NULL) { - timer_handle = xTimerCreateStatic( - "", - on_time_ticks, - pdFALSE, - 0, - Buzzer_TimerCallback, - &timer); - } else { - CHECK_ERROR(xTimerChangePeriod(timer_handle, on_time_ticks, BUZZER_BLOCKING_TIME_LIMIT) == pdFAIL, BUZZER_TIMER_BUSY); - } - - CHECK_ERROR(xTimerStart(timer_handle, BUZZER_BLOCKING_TIME_LIMIT) == pdFAIL, BUZZER_TIMER_BUSY); - Buzzer_SetON(); + Buzzer_SetON(self); - bsm.on_duration = on_time_ticks; - bsm.off_duration = off_time_ticks; - bsm.total_active_time = 0; - bsm.active_time_limit = active_time_limit; - bsm.current_state = BUZZER_ON; + self->bsm.on_duration = on_time_ticks; + self->bsm.off_duration = off_time_ticks; + self->bsm.total_active_time_left = active_time_limit; + self->bsm.current_state_valid_for = on_time_ticks; + self->bsm.current_state = BUZZER_ON; return 0; fail: - Buzzer_ResetTimer(); - Buzzer_SetOFF(); + self->bsm.current_state = BUZZER_NOT_TIMED; + Buzzer_SetOFF(self); return errors; } diff --git a/KPI_Rover/Buzzer/driver.h b/KPI_Rover/Buzzer/driver.h index 4b0d15d..e4b9e73 100644 --- a/KPI_Rover/Buzzer/driver.h +++ b/KPI_Rover/Buzzer/driver.h @@ -12,9 +12,32 @@ #define BUZZER_ZERO_ACTIVE_TIME_ERROR 0x7U #define BUZZER_TIMER_BUSY 0x8U -unsigned int Buzzer_ConfigurePort(const GPIO_TypeDef * const gpio_port, const uint16_t gpio_pin); -unsigned int Buzzer_Enable(void); -unsigned int Buzzer_Disable(void); -unsigned int Buzzer_Pulse(const unsigned int on_time_ms, const unsigned int period_time_ms, const unsigned int total_active_time_ms); +enum BuzzerState { + BUZZER_NOT_TIMED, + BUZZER_ON, + BUZZER_OFF, + IMPOSSIBLE_STATE +}; + +struct BuzzerStateMemory { + int on_duration; + int off_duration; + int total_active_time_left; + int current_state_valid_for; + enum BuzzerState current_state; +}; + +struct BuzzerObject { + GPIO_TypeDef *GPIO_buzzer_port; + uint16_t GPIO_buzzer_pin; + int buzzer_initialized; + struct BuzzerStateMemory bsm; +}; + +unsigned int Buzzer_ConfigurePort(struct BuzzerObject * const self, const GPIO_TypeDef * const gpio_port, const uint16_t gpio_pin); +unsigned int Buzzer_Enable(struct BuzzerObject * const self); +unsigned int Buzzer_Disable(struct BuzzerObject * const self); +unsigned int Buzzer_Pulse(struct BuzzerObject * const self, const unsigned int on_time_ms, const unsigned int period_time_ms, const unsigned int total_active_time_ms); +void Buzzer_TimerTask(struct BuzzerObject * const self); #endif /* __BUZZER_DRIVER */ diff --git a/KPI_Rover/Buzzer/manager.c b/KPI_Rover/Buzzer/manager.c index 077b9da..3b8c035 100644 --- a/KPI_Rover/Buzzer/manager.c +++ b/KPI_Rover/Buzzer/manager.c @@ -1,31 +1,66 @@ #include "FreeRTOS.h" #include "task.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(GPIOD, GPIO_PIN_15)) + if (Buzzer_ConfigurePort(&(bo[0]), GPIOD, GPIO_PIN_15)) { ULOG_ERROR("Failed to configure buzzer driver port"); vTaskDelete(NULL); } + { + 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"); + vTaskDelete(NULL); + } + + if (osTimerStart(timer_handle, 10) != osOK) { + ULOG_ERROR("Failed to start a timer"); + vTaskDelete(NULL); + } + } + for ( ; ; ) { - Buzzer_Enable(); + Buzzer_Enable(&(bo[0])); vTaskDelay(pdMS_TO_TICKS(3000)); - Buzzer_Disable(); + Buzzer_Disable(&(bo[0])); vTaskDelay(pdMS_TO_TICKS(3000)); - Buzzer_Pulse(500, 1000, 5000); + Buzzer_Pulse(&(bo[0]), 500, 1000, 5000); vTaskDelay(pdMS_TO_TICKS(5000)); - Buzzer_Pulse(200, 1000, 5000); + Buzzer_Pulse(&(bo[0]), 200, 1000, 5000); vTaskDelay(pdMS_TO_TICKS(5000)); - Buzzer_Pulse(100, 300, 5000); + Buzzer_Pulse(&(bo[0]), 100, 300, 5000); vTaskDelay(pdMS_TO_TICKS(5000)); - Buzzer_Pulse(250, 300, 5000); + Buzzer_Pulse(&(bo[0]), 250, 300, 5000); vTaskDelay(pdMS_TO_TICKS(1000)); // intentionally shorter delay; next command must abort this one } } From 244f5c6601210b444a40af683c2effa5c28279b4 Mon Sep 17 00:00:00 2001 From: hasslesstech Date: Sun, 14 Sep 2025 21:27:05 +0300 Subject: [PATCH 10/13] Issue #15: switch to CMSISv2 functions in manager to improve OS independance --- KPI_Rover/Buzzer/manager.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/KPI_Rover/Buzzer/manager.c b/KPI_Rover/Buzzer/manager.c index 3b8c035..c36a715 100644 --- a/KPI_Rover/Buzzer/manager.c +++ b/KPI_Rover/Buzzer/manager.c @@ -1,5 +1,5 @@ #include "FreeRTOS.h" -#include "task.h" +#include "timers.h" #include "cmsis_os2.h" @@ -24,7 +24,7 @@ void buzzer_manager_task(void *d) if (Buzzer_ConfigurePort(&(bo[0]), GPIOD, GPIO_PIN_15)) { ULOG_ERROR("Failed to configure buzzer driver port"); - vTaskDelete(NULL); + osThreadExit(); } { @@ -39,28 +39,28 @@ void buzzer_manager_task(void *d) if (timer_handle != (&timer)) { ULOG_ERROR("Failed to create a timer"); - vTaskDelete(NULL); + osThreadExit(); } if (osTimerStart(timer_handle, 10) != osOK) { ULOG_ERROR("Failed to start a timer"); - vTaskDelete(NULL); + osThreadExit(); } } for ( ; ; ) { Buzzer_Enable(&(bo[0])); - vTaskDelay(pdMS_TO_TICKS(3000)); + osDelay(3000); Buzzer_Disable(&(bo[0])); - vTaskDelay(pdMS_TO_TICKS(3000)); + osDelay(3000); Buzzer_Pulse(&(bo[0]), 500, 1000, 5000); - vTaskDelay(pdMS_TO_TICKS(5000)); + osDelay(5000); Buzzer_Pulse(&(bo[0]), 200, 1000, 5000); - vTaskDelay(pdMS_TO_TICKS(5000)); + osDelay(5000); Buzzer_Pulse(&(bo[0]), 100, 300, 5000); - vTaskDelay(pdMS_TO_TICKS(5000)); + osDelay(5000); Buzzer_Pulse(&(bo[0]), 250, 300, 5000); - vTaskDelay(pdMS_TO_TICKS(1000)); // intentionally shorter delay; next command must abort this one + osDelay(1000); // intentionally shorter delay; any next command must abort any previous one } } From d84815584a7a5cde3d2a57fbdcef72fe0c0b0870 Mon Sep 17 00:00:00 2001 From: hasslesstech Date: Sun, 14 Sep 2025 21:42:07 +0300 Subject: [PATCH 11/13] Issue #15: Change all types to platform-independant alternatives --- KPI_Rover/Buzzer/driver.c | 30 +++++++++++++++--------------- KPI_Rover/Buzzer/driver.h | 18 +++++++++--------- 2 files changed, 24 insertions(+), 24 deletions(-) diff --git a/KPI_Rover/Buzzer/driver.c b/KPI_Rover/Buzzer/driver.c index d89fef2..7e81176 100644 --- a/KPI_Rover/Buzzer/driver.c +++ b/KPI_Rover/Buzzer/driver.c @@ -13,9 +13,9 @@ } \ } while (0) -static unsigned int count_bits_16bit(uint16_t value) +static uint8_t count_bits_16bit(uint16_t value) { - unsigned int result = 0; + uint8_t result = 0; for ( ; value; value >>= 1) if (value & 1) @@ -24,11 +24,11 @@ static unsigned int count_bits_16bit(uint16_t value) return result; } -unsigned int Buzzer_ConfigurePort(struct BuzzerObject * const self, const GPIO_TypeDef * const gpio_port, const uint16_t gpio_pin) +uint32_t Buzzer_ConfigurePort(struct BuzzerObject * const self, const GPIO_TypeDef * const gpio_port, const uint16_t gpio_pin) { self->bsm.current_state = BUZZER_NOT_TIMED; - unsigned int errors = 0; + uint32_t errors = 0; CHECK_ERROR(count_bits_16bit(gpio_pin) != 1, BUZZER_PIN_ERROR); @@ -44,9 +44,9 @@ unsigned int Buzzer_ConfigurePort(struct BuzzerObject * const self, const GPIO_T return errors; } -static unsigned int Buzzer_SetON(struct BuzzerObject * const self) +static uint32_t Buzzer_SetON(struct BuzzerObject * const self) { - unsigned int errors = 0; + uint32_t errors = 0; CHECK_ERROR(!self->buzzer_initialized, BUZZER_NOT_INITIALIZED_ERROR); @@ -56,9 +56,9 @@ static unsigned int Buzzer_SetON(struct BuzzerObject * const self) return errors; } -static unsigned int Buzzer_SetOFF(struct BuzzerObject * const self) +static uint32_t Buzzer_SetOFF(struct BuzzerObject * const self) { - unsigned int errors = 0; + uint32_t errors = 0; CHECK_ERROR(!self->buzzer_initialized, BUZZER_NOT_INITIALIZED_ERROR); @@ -68,13 +68,13 @@ static unsigned int Buzzer_SetOFF(struct BuzzerObject * const self) return errors; } -unsigned int Buzzer_Enable(struct BuzzerObject * const self) +uint32_t Buzzer_Enable(struct BuzzerObject * const self) { self->bsm.current_state = BUZZER_NOT_TIMED; return Buzzer_SetON(self); } -unsigned int Buzzer_Disable(struct BuzzerObject * const self) +uint32_t Buzzer_Disable(struct BuzzerObject * const self) { self->bsm.current_state = BUZZER_NOT_TIMED; return Buzzer_SetOFF(self); @@ -118,21 +118,21 @@ void Buzzer_TimerTask(struct BuzzerObject * const self) } } -unsigned int Buzzer_Pulse(struct BuzzerObject * const self, const unsigned int on_time_ms, const unsigned int period_time_ms, const unsigned int total_active_time_ms) +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) { self->bsm.current_state = BUZZER_NOT_TIMED; - unsigned int errors = 0; + uint32_t errors = 0; CHECK_ERROR(!self->buzzer_initialized, BUZZER_NOT_INITIALIZED_ERROR); - const int on_time_ticks = on_time_ms / 10; + const uint32_t on_time_ticks = on_time_ms / 10; CHECK_ERROR(!on_time_ticks, BUZZER_ZERO_ONTIME_ERROR); - const int off_time_ticks = (period_time_ms / 10) - on_time_ticks; + const uint32_t off_time_ticks = (period_time_ms / 10) - on_time_ticks; CHECK_ERROR(!off_time_ticks, BUZZER_ZERO_OFFTIME_ERROR); - const int active_time_limit = total_active_time_ms / 10; + const uint32_t active_time_limit = total_active_time_ms / 10; CHECK_ERROR(!active_time_limit, BUZZER_ZERO_ACTIVE_TIME_ERROR); Buzzer_SetON(self); diff --git a/KPI_Rover/Buzzer/driver.h b/KPI_Rover/Buzzer/driver.h index e4b9e73..73325ab 100644 --- a/KPI_Rover/Buzzer/driver.h +++ b/KPI_Rover/Buzzer/driver.h @@ -20,24 +20,24 @@ enum BuzzerState { }; struct BuzzerStateMemory { - int on_duration; - int off_duration; - int total_active_time_left; - int current_state_valid_for; + uint32_t on_duration; + uint32_t off_duration; + uint32_t total_active_time_left; + uint32_t current_state_valid_for; enum BuzzerState current_state; }; struct BuzzerObject { GPIO_TypeDef *GPIO_buzzer_port; uint16_t GPIO_buzzer_pin; - int buzzer_initialized; + int8_t buzzer_initialized; struct BuzzerStateMemory bsm; }; -unsigned int Buzzer_ConfigurePort(struct BuzzerObject * const self, const GPIO_TypeDef * const gpio_port, const uint16_t gpio_pin); -unsigned int Buzzer_Enable(struct BuzzerObject * const self); -unsigned int Buzzer_Disable(struct BuzzerObject * const self); -unsigned int Buzzer_Pulse(struct BuzzerObject * const self, const unsigned int on_time_ms, const unsigned int period_time_ms, const unsigned int total_active_time_ms); +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 */ From 508440304773ed9a3586ae65ab0ad5d7ff046388 Mon Sep 17 00:00:00 2001 From: hasslesstech Date: Sun, 28 Sep 2025 13:07:52 +0300 Subject: [PATCH 12/13] Issue #15: increase maximum stack size to prevent accidental task crashes --- Core/Src/main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Core/Src/main.c b/Core/Src/main.c index 07dd08f..5b46c23 100644 --- a/Core/Src/main.c +++ b/Core/Src/main.c @@ -160,7 +160,7 @@ int main(void) static const osThreadAttr_t buzzer_task_attrs = { .name = "buzzer", - .stack_size = 16 * 4, + .stack_size = 64 * 4, .priority = (osPriority_t) osPriorityHigh, }; (void) osThreadNew(buzzer_manager_task, NULL, &buzzer_task_attrs); From 981b69f557b325d27e46bf41ccc376b76bab17a3 Mon Sep 17 00:00:00 2001 From: hasslesstech Date: Sun, 28 Sep 2025 18:19:45 +0300 Subject: [PATCH 13/13] Issue #15: refactor code into a state machine --- KPI_Rover/Buzzer/driver.c | 262 ++++++++++++++++++++++++++++--------- KPI_Rover/Buzzer/driver.h | 71 ++++++++-- KPI_Rover/Buzzer/generic.c | 14 ++ KPI_Rover/Buzzer/generic.h | 9 ++ 4 files changed, 277 insertions(+), 79 deletions(-) create mode 100644 KPI_Rover/Buzzer/generic.c create mode 100644 KPI_Rover/Buzzer/generic.h diff --git a/KPI_Rover/Buzzer/driver.c b/KPI_Rover/Buzzer/driver.c index 7e81176..71a5be5 100644 --- a/KPI_Rover/Buzzer/driver.c +++ b/KPI_Rover/Buzzer/driver.c @@ -2,6 +2,7 @@ #include "stm32f4xx_hal.h" +#include "generic.h" #include "driver.h" #define BUZZER_BLOCKING_TIME_LIMIT 1000 @@ -13,140 +14,271 @@ } \ } while (0) + static uint8_t count_bits_16bit(uint16_t value) { uint8_t result = 0; for ( ; value; value >>= 1) - if (value & 1) - result++; + result += value & 1; return result; } -uint32_t Buzzer_ConfigurePort(struct BuzzerObject * const self, const GPIO_TypeDef * const gpio_port, const uint16_t gpio_pin) +static uint32_t Buzzer_SetON(struct BuzzerObject * const self) { - self->bsm.current_state = BUZZER_NOT_TIMED; - uint32_t errors = 0; - CHECK_ERROR(count_bits_16bit(gpio_pin) != 1, BUZZER_PIN_ERROR); - - self->GPIO_buzzer_port = (GPIO_TypeDef *) gpio_port; - self->GPIO_buzzer_pin = (uint16_t) gpio_pin; + CHECK_ERROR(!self->c.initialized, BUZZER_NOT_INITIALIZED_ERROR); - self->buzzer_initialized = 1; - - return errors; + HAL_GPIO_WritePin(self->c.GPIO_port, self->c.GPIO_pin, GPIO_PIN_SET); fail: - self->buzzer_initialized = 0; return errors; } -static uint32_t Buzzer_SetON(struct BuzzerObject * const self) +static uint32_t Buzzer_SetOFF(struct BuzzerObject * const self) { uint32_t errors = 0; - CHECK_ERROR(!self->buzzer_initialized, BUZZER_NOT_INITIALIZED_ERROR); + CHECK_ERROR(!self->c.initialized, BUZZER_NOT_INITIALIZED_ERROR); - HAL_GPIO_WritePin(self->GPIO_buzzer_port, self->GPIO_buzzer_pin, GPIO_PIN_SET); + HAL_GPIO_WritePin(self->c.GPIO_port, self->c.GPIO_pin, GPIO_PIN_RESET); fail: return errors; } -static uint32_t Buzzer_SetOFF(struct BuzzerObject * const self) + +static void Buzzer_OFF_Enter(struct BuzzerObject * const self, const struct BuzzerEvent * const ev) { - uint32_t errors = 0; + Buzzer_SetOFF(self); +} - CHECK_ERROR(!self->buzzer_initialized, BUZZER_NOT_INITIALIZED_ERROR); +static void Buzzer_OFF_Handle(struct BuzzerObject * const self) +{ - HAL_GPIO_WritePin(self->GPIO_buzzer_port, self->GPIO_buzzer_pin, GPIO_PIN_RESET); +} -fail: - return errors; +static void Buzzer_OFF_Leave(struct BuzzerObject * const self) +{ + Buzzer_SetOFF(self); } -uint32_t Buzzer_Enable(struct BuzzerObject * const self) + +static void Buzzer_ON_Enter(struct BuzzerObject * const self, const struct BuzzerEvent * const ev) { - self->bsm.current_state = BUZZER_NOT_TIMED; - return Buzzer_SetON(self); + Buzzer_SetON(self); } -uint32_t Buzzer_Disable(struct BuzzerObject * const self) +static void Buzzer_ON_Handle(struct BuzzerObject * const self) { - self->bsm.current_state = BUZZER_NOT_TIMED; - return Buzzer_SetOFF(self); + } -void Buzzer_TimerTask(struct BuzzerObject * const self) +static void Buzzer_ON_Leave(struct BuzzerObject * const self) { - if (self->bsm.current_state == BUZZER_NOT_TIMED) - return; + Buzzer_SetON(self); +} - self->bsm.total_active_time_left--; - self->bsm.current_state_valid_for--; - if (!self->bsm.total_active_time_left) { +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->bsm.current_state = BUZZER_NOT_TIMED; - return; + 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); +} - if (self->bsm.current_state_valid_for) - return; - switch (self->bsm.current_state) { +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_SetOFF(self); // disable first, determine action course next - self->bsm.current_state = BUZZER_OFF; - self->bsm.current_state_valid_for = self->bsm.off_duration; + 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: - self->bsm.current_state = BUZZER_ON; - self->bsm.current_state_valid_for = self->bsm.on_duration; - Buzzer_SetON(self); + Buzzer_OFF_Leave(self); + break; + case BUZZER_PULSE: + Buzzer_PULSE_Leave(self); + break; + default: break; + } - case BUZZER_NOT_TIMED: - case IMPOSSIBLE_STATE: + 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: - // how did we get here? + self->s.current_state = IMPOSSIBLE_STATE; break; } + + self->s.current_state_since = HAL_GetTick(); + self->e.ev = NO_EVENT; } -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 Buzzer_ConfigurePort(struct BuzzerObject * const self, const GPIO_TypeDef * const gpio_port, const uint16_t gpio_pin) { - self->bsm.current_state = BUZZER_NOT_TIMED; + Buzzer_Reset(self); uint32_t errors = 0; - CHECK_ERROR(!self->buzzer_initialized, BUZZER_NOT_INITIALIZED_ERROR); + CHECK_ERROR(count_bits_16bit(gpio_pin) != 1, BUZZER_PIN_ERROR); - const uint32_t on_time_ticks = on_time_ms / 10; - CHECK_ERROR(!on_time_ticks, BUZZER_ZERO_ONTIME_ERROR); + self->c.GPIO_port = (GPIO_TypeDef *) gpio_port; + self->c.GPIO_pin = (uint16_t) gpio_pin; - const uint32_t off_time_ticks = (period_time_ms / 10) - on_time_ticks; - CHECK_ERROR(!off_time_ticks, BUZZER_ZERO_OFFTIME_ERROR); + self->c.initialized = 1; - const uint32_t active_time_limit = total_active_time_ms / 10; - CHECK_ERROR(!active_time_limit, BUZZER_ZERO_ACTIVE_TIME_ERROR); + return errors; - Buzzer_SetON(self); +fail: + self->c.initialized = 0; + return errors; +} - self->bsm.on_duration = on_time_ticks; - self->bsm.off_duration = off_time_ticks; - self->bsm.total_active_time_left = active_time_limit; - self->bsm.current_state_valid_for = on_time_ticks; - self->bsm.current_state = BUZZER_ON; +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: - self->bsm.current_state = BUZZER_NOT_TIMED; - Buzzer_SetOFF(self); 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 index 73325ab..6e8a7a3 100644 --- a/KPI_Rover/Buzzer/driver.h +++ b/KPI_Rover/Buzzer/driver.h @@ -12,26 +12,69 @@ #define BUZZER_ZERO_ACTIVE_TIME_ERROR 0x7U #define BUZZER_TIMER_BUSY 0x8U -enum BuzzerState { - BUZZER_NOT_TIMED, - BUZZER_ON, + +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, - IMPOSSIBLE_STATE + BUZZER_ON, + BUZZER_PULSE +}; + +struct BuzzerGlobalState { + enum BuzzerGlobalStateType current_state; + uint32_t current_state_since; }; -struct BuzzerStateMemory { - uint32_t on_duration; - uint32_t off_duration; - uint32_t total_active_time_left; - uint32_t current_state_valid_for; - enum BuzzerState current_state; + +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 { - GPIO_TypeDef *GPIO_buzzer_port; - uint16_t GPIO_buzzer_pin; - int8_t buzzer_initialized; - struct BuzzerStateMemory bsm; + 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); 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 */