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 + } +}