From e14239b2ec9d88bcc686a2ebbe003e3bec7fb664 Mon Sep 17 00:00:00 2001 From: Brayan Almonte Date: Tue, 23 Jan 2024 11:43:40 -0500 Subject: [PATCH] feat(hepa-uv): Configure Push button led timers and add led hardware to drive leds. (#745) * added led controls to the hepa and uv tasks --- hepa-uv/core/tasks.cpp | 22 +- hepa-uv/firmware/CMakeLists.txt | 2 + .../led_control_task/led_control_hardware.cpp | 17 + hepa-uv/firmware/led_hardware.c | 297 ++++++++++++++++++ hepa-uv/firmware/main_rev1.cpp | 7 +- include/hepa-uv/core/constants.h | 30 ++ include/hepa-uv/core/hepa_task.hpp | 24 +- include/hepa-uv/core/led_control_task.hpp | 94 ++++++ include/hepa-uv/core/messages.hpp | 15 + include/hepa-uv/core/tasks.hpp | 15 +- include/hepa-uv/core/uv_task.hpp | 43 ++- .../hepa-uv/firmware/led_control_hardware.hpp | 21 ++ include/hepa-uv/firmware/led_hardware.h | 24 ++ 13 files changed, 591 insertions(+), 20 deletions(-) create mode 100644 hepa-uv/firmware/led_control_task/led_control_hardware.cpp create mode 100644 hepa-uv/firmware/led_hardware.c create mode 100644 include/hepa-uv/core/constants.h create mode 100644 include/hepa-uv/core/led_control_task.hpp create mode 100644 include/hepa-uv/firmware/led_control_hardware.hpp create mode 100644 include/hepa-uv/firmware/led_hardware.h diff --git a/hepa-uv/core/tasks.cpp b/hepa-uv/core/tasks.cpp index 7286336b8..fe7b3b8f0 100644 --- a/hepa-uv/core/tasks.cpp +++ b/hepa-uv/core/tasks.cpp @@ -20,25 +20,36 @@ static auto hepa_task_builder = static auto uv_task_builder = freertos_task::TaskStarter<512, uv_task::UVTask>{}; +static auto led_control_task_builder = + freertos_task::TaskStarter<512, led_control_task::LEDControlTask>{}; + /** * Start hepa_uv tasks. */ void hepauv_tasks::start_tasks( can::bus::CanBus& can_bus, - gpio_drive_hardware::GpioDrivePins& gpio_drive_pins) { + gpio_drive_hardware::GpioDrivePins& gpio_drive_pins, + led_control_hardware::LEDControlHardware& led_hardware) { auto& can_writer = can_task::start_writer(can_bus); can_task::start_reader(can_bus); - auto& hepa_task = hepa_task_builder.start(5, "hepa_fan", gpio_drive_pins); - auto& uv_task = uv_task_builder.start(5, "uv_ballast", gpio_drive_pins); + // TODO: including led_hardware for testing, this should be a AssesorClient + auto& hepa_task = + hepa_task_builder.start(5, "hepa_fan", gpio_drive_pins, queues); + auto& uv_task = + uv_task_builder.start(5, "uv_ballast", gpio_drive_pins, queues); + auto& led_control_task = + led_control_task_builder.start(5, "push_button_leds", led_hardware); tasks.hepa_task_handler = &hepa_task; tasks.uv_task_handler = &uv_task; + tasks.led_control_task_handler = &led_control_task; tasks.can_writer = &can_writer; queues.set_queue(&can_writer.get_queue()); queues.hepa_queue = &hepa_task.get_queue(); queues.uv_queue = &uv_task.get_queue(); + queues.led_control_queue = &led_control_task.get_queue(); } hepauv_tasks::QueueClient::QueueClient(can::ids::NodeId this_fw) @@ -53,6 +64,11 @@ void hepauv_tasks::QueueClient::send_uv_message(const uv_task::TaskMessage& m) { uv_queue->try_write(m); } +void hepauv_tasks::QueueClient::send_led_control_message( + const led_control_task::TaskMessage& m) { + led_control_queue->try_write(m); +} + /** * Access to the tasks singleton * @return diff --git a/hepa-uv/firmware/CMakeLists.txt b/hepa-uv/firmware/CMakeLists.txt index d2056eb75..1e2f1f16f 100644 --- a/hepa-uv/firmware/CMakeLists.txt +++ b/hepa-uv/firmware/CMakeLists.txt @@ -12,6 +12,7 @@ set(REVISIONS hepa-rev1) # Add source files that should be checked by clang-tidy here set(HEPA_UV_FW_LINTABLE_SRCS ${CMAKE_CURRENT_SOURCE_DIR}/freertos_idle_timer_task.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/led_control_task/led_control_hardware.cpp ${COMMON_EXECUTABLE_DIR}/system/iwdg.cpp ${CAN_FW_DIR}/hal_can_bus.cpp ${CAN_FW_DIR}/utils.c @@ -23,6 +24,7 @@ set(HEPAUV_FW_NON_LINTABLE_SRCS ${CMAKE_CURRENT_SOURCE_DIR}/stm32g4xx_it.c ${CMAKE_CURRENT_SOURCE_DIR}/clocking.c ${CMAKE_CURRENT_SOURCE_DIR}/utility_gpio.c + ${CMAKE_CURRENT_SOURCE_DIR}/led_hardware.c ${CMAKE_CURRENT_SOURCE_DIR}/can.c ${CMAKE_CURRENT_SOURCE_DIR}/i2c_setup.c ${COMMON_EXECUTABLE_DIR}/errors/errors.c diff --git a/hepa-uv/firmware/led_control_task/led_control_hardware.cpp b/hepa-uv/firmware/led_control_task/led_control_hardware.cpp new file mode 100644 index 000000000..e14822e75 --- /dev/null +++ b/hepa-uv/firmware/led_control_task/led_control_hardware.cpp @@ -0,0 +1,17 @@ +#include "hepa-uv/firmware/led_control_hardware.hpp" + +#include "hepa-uv/core/led_control_task.hpp" +#include "hepa-uv/firmware/led_hardware.h" + +using namespace led_control_hardware; + +// NOLINTNEXTLINE(readability-convert-member-functions-to-static) +auto LEDControlHardware::initialize() -> void { + button_led_hw_initialize_leds(); +} + +void LEDControlHardware::set_button_led_power(uint8_t button, uint32_t r, + uint32_t g, uint32_t b, + uint32_t w) { + set_button_led_pwm(static_cast(button), r, g, b, w); +} \ No newline at end of file diff --git a/hepa-uv/firmware/led_hardware.c b/hepa-uv/firmware/led_hardware.c new file mode 100644 index 000000000..976bf5eb0 --- /dev/null +++ b/hepa-uv/firmware/led_hardware.c @@ -0,0 +1,297 @@ +#include "hepa-uv/firmware/led_hardware.h" +#include "hepa-uv/firmware/utility_gpio.h" +#include "common/firmware/errors.h" + +#include "platform_specific_hal_conf.h" +#include "system_stm32g4xx.h" + +TIM_HandleTypeDef htim1; +TIM_HandleTypeDef htim8; +TIM_HandleTypeDef htim16; +TIM_HandleTypeDef htim20; + +TIM_OC_InitTypeDef htim1_sConfigOC = {0}; +TIM_OC_InitTypeDef htim8_sConfigOC = {0}; +TIM_OC_InitTypeDef htim16_sConfigOC = {0}; +TIM_OC_InitTypeDef htim20_sConfigOC = {0}; + + +uint32_t round_closest(uint32_t dividend, uint32_t divisor) { + return (dividend + (divisor / 2)) / divisor; +} + +uint32_t calc_prescaler(uint32_t timer_clk_freq, uint32_t counter_clk_freq) { + return timer_clk_freq >= counter_clk_freq + ? round_closest(timer_clk_freq, counter_clk_freq) - 1U + : 0U; +} + +void HAL_TIM_Base_MspInit(TIM_HandleTypeDef* htim_pwm) { + if(htim_pwm->Instance == TIM1) { + __HAL_RCC_TIM1_CLK_ENABLE(); + } else if(htim_pwm->Instance == TIM8) { + __HAL_RCC_TIM8_CLK_ENABLE(); + } else if(htim_pwm->Instance == TIM16) { + __HAL_RCC_TIM16_CLK_ENABLE(); + } else if(htim_pwm->Instance == TIM20) { + __HAL_RCC_TIM20_CLK_ENABLE(); + } +} + +void HAL_TIM_MspPostInit(TIM_HandleTypeDef* htim) { + GPIO_InitTypeDef GPIO_InitStruct = {0}; + if (htim->Instance == TIM1) { + __HAL_RCC_GPIOA_CLK_ENABLE(); + __HAL_RCC_GPIOC_CLK_ENABLE(); + /**TIM1 GPIO Configuration + PA9 ------> TIM1_CH2 + PA10 ------> TIM1_CH3 + */ + GPIO_InitStruct.Pin = HEPA_R_CTRL_PIN | HEPA_W_CTRL_PIN; + GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; + GPIO_InitStruct.Pull = GPIO_NOPULL; + GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW; + GPIO_InitStruct.Alternate = GPIO_AF6_TIM1; + HAL_GPIO_Init(HEPA_R_CTRL_PORT, &GPIO_InitStruct); + + // PC5 ------> TIM1_CH4N + GPIO_InitStruct.Pin = UV_B_CTRL_PIN; + HAL_GPIO_Init(UV_B_CTRL_PORT, &GPIO_InitStruct); + } else if (htim->Instance == TIM8) { + __HAL_RCC_GPIOB_CLK_ENABLE(); + __HAL_RCC_GPIOC_CLK_ENABLE(); + /**TIM8 GPIO Configuration + PB0 ------> TIM8_CH2N + PB1 ------> TIM8_CH3N + */ + GPIO_InitStruct.Pin = UV_G_CTRL_PIN | UV_R_CTRL_PIN; + GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; + GPIO_InitStruct.Pull = GPIO_NOPULL; + GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW; + GPIO_InitStruct.Alternate = GPIO_AF4_TIM8; + HAL_GPIO_Init(UV_G_CTRL_PORT, &GPIO_InitStruct); + + /* + PC6 ------> TIM8_CH1 + */ + GPIO_InitStruct.Pin = HEPA_G_CTRL_PIN; + HAL_GPIO_Init(HEPA_G_CTRL_PORT, &GPIO_InitStruct); + } else if (htim->Instance == TIM16) { + __HAL_RCC_GPIOB_CLK_ENABLE(); + /**TIM16 GPIO Configuration + PB4 ------> TIM16_CH1 + */ + GPIO_InitStruct.Pin = HEPA_B_CTRL_PIN; + GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; + GPIO_InitStruct.Pull = GPIO_NOPULL; + GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW; + GPIO_InitStruct.Alternate = GPIO_AF1_TIM16; + HAL_GPIO_Init(HEPA_B_CTRL_PORT, &GPIO_InitStruct); + } else if (htim->Instance == TIM20) { + __HAL_RCC_GPIOB_CLK_ENABLE(); + /**TIM20 GPIO Configuration + PB2 ------> TIM20_CH1 + */ + GPIO_InitStruct.Pin = UV_W_CTRL_PIN; + GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; + GPIO_InitStruct.Pull = GPIO_NOPULL; + GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW; + GPIO_InitStruct.Alternate = GPIO_AF3_TIM20; + HAL_GPIO_Init(UV_W_CTRL_PORT, &GPIO_InitStruct); + } +} + +/** + * @brief TIM Initialization Function for the LED timers. + * @param tim Pointer to the timer we are configuring + * @retval None + */ +static void MX_TIM_Init(TIM_TypeDef* tim) { + TIM_ClockConfigTypeDef sClockSourceConfig = {0}; + TIM_MasterConfigTypeDef sMasterConfig = {0}; + TIM_BreakDeadTimeConfigTypeDef sBreakDeadTimeConfig = {0}; + + TIM_HandleTypeDef* htim; + TIM_OC_InitTypeDef* htim_sConfigOC; + unsigned int channels[3]; + int channels_size = 0; + if (tim == TIM1){ + htim = &htim1; + htim_sConfigOC = &htim1_sConfigOC; + /* Channels + HEPA_R_CTRL -> ch2 + HEPA_W_CTRL -> ch3 + UV_B_CTRL -> ch4 + */ + channels_size = 3; + channels[0] = TIM_CHANNEL_2; + channels[1] = TIM_CHANNEL_3; + channels[2] = TIM_CHANNEL_4; + } else if (tim == TIM8) { + htim = &htim8; + htim_sConfigOC = &htim8_sConfigOC; + /* Channels + HEPA_G_CTRL -> ch1 + UV_G_CTRL -> ch2 + UV_R_CTRL -> ch3 + */ + channels_size = 3; + channels[0] = TIM_CHANNEL_1; + channels[1] = TIM_CHANNEL_2; + channels[2] = TIM_CHANNEL_3; + } else if (tim == TIM16) { + htim = &htim16; + htim_sConfigOC = &htim16_sConfigOC; + /* Channels + HEPA_B_CTRL -> ch1 + */ + channels_size = 1; + channels[0] = TIM_CHANNEL_1; + } else if (tim == TIM20) { + htim = &htim20; + htim_sConfigOC = &htim20_sConfigOC; + /* Channels + UV_W_CTRL -> ch1 + */ + channels_size = 1; + channels[0] = TIM_CHANNEL_1; + } else { + Error_Handler(); + return; + } + + htim->State = HAL_TIM_STATE_RESET; + htim->Instance = tim; + /* + * Setting counter clock frequency to 2 kHz + */ + htim->Init.Prescaler = + calc_prescaler(SystemCoreClock, LED_TIMER_FREQ); + htim->Init.CounterMode = TIM_COUNTERMODE_UP; + htim->Init.Period = LED_PWM_WIDTH - 1; + htim->Init.ClockDivision = TIM_CLOCKDIVISION_DIV1; + htim->Init.RepetitionCounter = 0; + htim->Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE; + if (HAL_TIM_Base_Init(htim) != HAL_OK) { + Error_Handler(); + } + sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL; + if (HAL_TIM_ConfigClockSource(htim, &sClockSourceConfig) != HAL_OK) { + Error_Handler(); + } + if (HAL_TIM_PWM_Init(htim) != HAL_OK) { + Error_Handler(); + } + sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET; + sMasterConfig.MasterOutputTrigger2 = TIM_TRGO2_RESET; + sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE; + if (HAL_TIMEx_MasterConfigSynchronization(htim, &sMasterConfig) != + HAL_OK) { + Error_Handler(); + } + htim_sConfigOC->OCMode = TIM_OCMODE_PWM1; + /* Set duty cycle at 0% */ + htim_sConfigOC->Pulse = 0; + htim_sConfigOC->OCPolarity = TIM_OCPOLARITY_HIGH; + htim_sConfigOC->OCNPolarity = TIM_OCNPOLARITY_HIGH; + htim_sConfigOC->OCFastMode = TIM_OCFAST_DISABLE; + htim_sConfigOC->OCIdleState = TIM_OCIDLESTATE_RESET; + htim_sConfigOC->OCNIdleState = TIM_OCNIDLESTATE_RESET; + + // Enable the corresponding channels for this timer + for (int i = 0; i < channels_size; i++) { + if (HAL_TIM_PWM_ConfigChannel(htim, htim_sConfigOC, channels[i]) != + HAL_OK) { + Error_Handler(); + } + } + + sBreakDeadTimeConfig.OffStateRunMode = TIM_OSSR_DISABLE; + sBreakDeadTimeConfig.OffStateIDLEMode = TIM_OSSI_DISABLE; + sBreakDeadTimeConfig.LockLevel = TIM_LOCKLEVEL_OFF; + sBreakDeadTimeConfig.DeadTime = 0; + sBreakDeadTimeConfig.BreakState = TIM_BREAK_DISABLE; + sBreakDeadTimeConfig.BreakPolarity = TIM_BREAKPOLARITY_HIGH; + sBreakDeadTimeConfig.BreakFilter = 0; + sBreakDeadTimeConfig.BreakAFMode = TIM_BREAK_AFMODE_INPUT; + sBreakDeadTimeConfig.Break2State = TIM_BREAK2_DISABLE; + sBreakDeadTimeConfig.Break2Polarity = TIM_BREAK2POLARITY_HIGH; + sBreakDeadTimeConfig.Break2Filter = 0; + sBreakDeadTimeConfig.Break2AFMode = TIM_BREAK_AFMODE_INPUT; + sBreakDeadTimeConfig.AutomaticOutput = TIM_AUTOMATICOUTPUT_DISABLE; + if (HAL_TIMEx_ConfigBreakDeadTime(htim, &sBreakDeadTimeConfig) != + HAL_OK) { + Error_Handler(); + } + HAL_TIM_MspPostInit(htim); +} + +void button_led_hw_update_pwm(uint32_t duty_cycle, LED_TYPE led, PUSH_BUTTON_TYPE button) { + + // TODO: fix this + if (button == HEPA_BUTTON) { + switch(led) { + case RED_LED: + htim1.Instance->CCR2 = duty_cycle; + break; + case GREEN_LED: + htim8.Instance->CCR1 = duty_cycle; + break; + case BLUE_LED: + htim16.Instance->CCR1 = duty_cycle; + break; + case WHITE_LED: + htim1.Instance->CCR3 = duty_cycle; + break; + default: + break; + } + } else if (button == UV_BUTTON) { + switch(led) { + case RED_LED: + htim8.Instance->CCR3 = duty_cycle; + break; + case GREEN_LED: + htim8.Instance->CCR2 = duty_cycle; + break; + case BLUE_LED: + htim1.Instance->CCR4 = duty_cycle; + break; + case WHITE_LED: + htim20.Instance->CCR1=duty_cycle; + break; + default: + break; + } + } +} + +void set_button_led_pwm(PUSH_BUTTON_TYPE button, uint32_t red, uint32_t green, uint32_t blue, uint32_t white) { + button_led_hw_update_pwm(red, RED_LED, button); + button_led_hw_update_pwm(green, GREEN_LED, button); + button_led_hw_update_pwm(blue, BLUE_LED, button); + button_led_hw_update_pwm(white, WHITE_LED, button); +} + +void button_led_hw_initialize_leds() { + // Initialize the timers and channels + MX_TIM_Init(TIM1); + MX_TIM_Init(TIM8); + MX_TIM_Init(TIM16); + MX_TIM_Init(TIM20); + + // Set the the button LEDS to idle (white) + set_button_led_pwm(HEPA_BUTTON, 0, 0, 0, 50); + set_button_led_pwm(UV_BUTTON, 0, 0, 0, 50); + + // Activate the channels + HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_2); + HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_3); + HAL_TIM_PWM_Start(&htim8, TIM_CHANNEL_1); + HAL_TIM_PWM_Start(&htim16, TIM_CHANNEL_1); + HAL_TIM_PWM_Start(&htim20, TIM_CHANNEL_1); + // Activate the complementary output + HAL_TIMEx_PWMN_Start(&htim1, TIM_CHANNEL_4); + HAL_TIMEx_PWMN_Start(&htim8, TIM_CHANNEL_2); + HAL_TIMEx_PWMN_Start(&htim8, TIM_CHANNEL_3); +} diff --git a/hepa-uv/firmware/main_rev1.cpp b/hepa-uv/firmware/main_rev1.cpp index 4622ec289..f800b4996 100644 --- a/hepa-uv/firmware/main_rev1.cpp +++ b/hepa-uv/firmware/main_rev1.cpp @@ -22,6 +22,8 @@ #include "common/firmware/utility_gpio.h" #include "hepa-uv/core/messages.hpp" #include "hepa-uv/core/tasks.hpp" +#include "hepa-uv/firmware/led_control_hardware.hpp" +#include "hepa-uv/firmware/led_hardware.h" #include "hepa-uv/firmware/utility_gpio.h" static auto iWatchdog = iwdg::IndependentWatchDog{}; @@ -115,16 +117,19 @@ extern "C" void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin) { } } +static auto led_hardware = led_control_hardware::LEDControlHardware(); + auto main() -> int { HardwareInit(); RCC_Peripheral_Clock_Select(); utility_gpio_init(); + button_led_hw_initialize_leds(); app_update_clear_flags(); canbus.start(can_bit_timings); - hepauv_tasks::start_tasks(canbus, gpio_drive_pins); + hepauv_tasks::start_tasks(canbus, gpio_drive_pins, led_hardware); iWatchdog.start(6); diff --git a/include/hepa-uv/core/constants.h b/include/hepa-uv/core/constants.h new file mode 100644 index 000000000..8fc509aa9 --- /dev/null +++ b/include/hepa-uv/core/constants.h @@ -0,0 +1,30 @@ +#pragma once +#include + +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus + +// the number of selectable points in the PWM +#define LED_PWM_WIDTH (256UL) + +typedef enum LED_TYPE { + RED_LED, + GREEN_LED, + BLUE_LED, + WHITE_LED +} LED_TYPE; + +typedef enum PUSH_BUTTON_TYPE { + HEPA_BUTTON, + UV_BUTTON +} PUSH_BUTTON_TYPE; + +typedef struct LEDState { + LED_TYPE led; + uint32_t duty_cycle; +} LEDState; + +#ifdef __cplusplus +} // extern "C" +#endif // __cplusplus diff --git a/include/hepa-uv/core/hepa_task.hpp b/include/hepa-uv/core/hepa_task.hpp index bf9e5fb1a..d71958d7b 100644 --- a/include/hepa-uv/core/hepa_task.hpp +++ b/include/hepa-uv/core/hepa_task.hpp @@ -5,17 +5,21 @@ #include "common/core/logging.h" #include "common/core/message_queue.hpp" #include "common/firmware/gpio.hpp" +#include "hepa-uv/core/constants.h" +#include "hepa-uv/core/messages.hpp" #include "hepa-uv/firmware/gpio_drive_hardware.hpp" -#include "messages.hpp" +#include "hepa-uv/firmware/led_control_hardware.hpp" namespace hepa_task { using TaskMessage = interrupt_task_messages::TaskMessage; +template class HepaMessageHandler { public: - explicit HepaMessageHandler(gpio_drive_hardware::GpioDrivePins &drive_pins) - : drive_pins{drive_pins} { + explicit HepaMessageHandler(gpio_drive_hardware::GpioDrivePins &drive_pins, + LEDControlClient &led_control_client) + : drive_pins{drive_pins}, led_control_client{led_control_client} { // get current state hepa_push_button = gpio::is_set(drive_pins.hepa_push_button); // turn off the HEPA fan @@ -42,8 +46,14 @@ class HepaMessageHandler { // handle state changes here if (hepa_push_button) { gpio::set(drive_pins.hepa_on_off); + led_control_client.send_led_control_message( + led_control_task_messages::PushButtonLED{HEPA_BUTTON, 0, 50, + 0, 0}); } else { gpio::reset(drive_pins.hepa_on_off); + led_control_client.send_led_control_message( + led_control_task_messages::PushButtonLED{HEPA_BUTTON, 0, 0, + 0, 50}); } } @@ -55,6 +65,7 @@ class HepaMessageHandler { bool hepa_fan_on = false; gpio_drive_hardware::GpioDrivePins &drive_pins; + LEDControlClient &led_control_client; }; /** @@ -76,9 +87,10 @@ class HepaTask { /** * Task entry point. */ - [[noreturn]] void operator()( - gpio_drive_hardware::GpioDrivePins *drive_pins) { - auto handler = HepaMessageHandler{*drive_pins}; + template + [[noreturn]] void operator()(gpio_drive_hardware::GpioDrivePins *drive_pins, + LEDControlClient *led_control_client) { + auto handler = HepaMessageHandler{*drive_pins, *led_control_client}; TaskMessage message{}; for (;;) { if (queue.try_read(&message, queue.max_delay)) { diff --git a/include/hepa-uv/core/led_control_task.hpp b/include/hepa-uv/core/led_control_task.hpp new file mode 100644 index 000000000..74f3d752f --- /dev/null +++ b/include/hepa-uv/core/led_control_task.hpp @@ -0,0 +1,94 @@ +#pragma once + +#include + +#include "common/core/message_queue.hpp" +#include "hepa-uv/core/constants.h" +#include "hepa-uv/core/messages.hpp" + +namespace led_control_task { + +using TaskMessage = led_control_task_messages::TaskMessage; + +class LEDControlInterface { + public: + LEDControlInterface() = default; + LEDControlInterface(const LEDControlInterface&) = delete; + LEDControlInterface(LEDControlInterface&&) = delete; + auto operator=(LEDControlInterface&&) -> LEDControlInterface& = delete; + auto operator=(const LEDControlInterface&) -> LEDControlInterface& = delete; + virtual ~LEDControlInterface() = default; + + virtual auto set_button_led_power(uint8_t button, uint32_t r, uint32_t g, + uint32_t b, uint32_t w) -> void = 0; +}; + +class LEDControlMessageHandler { + public: + LEDControlMessageHandler(LEDControlInterface& hardware) + : _hardware(hardware) {} + + auto handle_message(const TaskMessage& message) -> void { + std::visit([this](auto m) { this->handle(m); }, message); + } + + private: + auto handle(std::monostate&) -> void {} + + auto handle(const led_control_task_messages::PushButtonLED& msg) -> void { + // Sets the Push button LED colors + _hardware.set_button_led_power(msg.button, static_cast(msg.r), + static_cast(msg.g), + static_cast(msg.b), + static_cast(msg.w)); + } + + LEDControlInterface& _hardware; +}; + +/** + * The task entry point. + */ +template