Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(hepa-uv): Add external IRQ handling and HEPA fan task to drive the HEPA fan. #742

Merged
merged 12 commits into from
Jan 18, 2024
51 changes: 51 additions & 0 deletions hepa-uv/core/tasks.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,26 +3,77 @@
#include "common/core/freertos_task.hpp"
#include "common/core/freertos_timer.hpp"
#include "hepa-uv/core/can_task.hpp"
#include "hepa-uv/firmware/gpio_drive_hardware.hpp"
#include "hepa-uv/firmware/utility_gpio.h"


#pragma GCC diagnostic push
// NOLINTNEXTLINE(clang-diagnostic-unknown-warning-option)
#pragma GCC diagnostic ignored "-Wvolatile"
#include "platform_specific_hal_conf.h"
#pragma GCC diagnostic pop

static auto tasks = hepauv_tasks::AllTask{};
static auto queues = hepauv_tasks::QueueClient{can::ids::NodeId::hepa_uv};

static auto gpio_drive_pins = gpio_drive_hardware::GpioDrivePins {
.door_open = gpio::PinConfig{
.port = DOOR_OPEN_MCU_PORT,
.pin = DOOR_OPEN_MCU_PIN,
.active_setting = DOOR_OPEN_MCU_AS
},
.reed_switch = gpio::PinConfig{
.port = REED_SW_MCU_PORT,
.pin = REED_SW_MCU_PIN,
.active_setting = REED_SW_MCU_AS
},
.hepa_push_button = gpio::PinConfig{
.port = HEPA_NO_MCU_PORT,
.pin = HEPA_NO_MCU_PIN,
},
.uv_push_button = gpio::PinConfig{
.port = UV_NO_MCU_PORT,
.pin = UV_NO_MCU_PIN,
},
.hepa_on_off = gpio::PinConfig{
.port = HEPA_ON_OFF_PORT,
.pin = HEPA_ON_OFF_PIN,
.active_setting = HEPA_ON_OFF_AS
},
.uv_on_off = gpio::PinConfig{
.port = UV_ON_OFF_MCU_PORT,
.pin = UV_ON_OFF_MCU_PIN,
.active_setting = UV_ON_OFF_AS
}
};

static auto hepa_task_builder =
freertos_task::TaskStarter<512, hepa_task::HepaTask>{};

/**
* Start hepa_uv tasks.
*/
void hepauv_tasks::start_tasks(can::bus::CanBus& can_bus) {
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);

tasks.hepa_task_handler = &hepa_task;
tasks.can_writer = &can_writer;

queues.set_queue(&can_writer.get_queue());
queues.hepa_queue = &hepa_task.get_queue();
}

hepauv_tasks::QueueClient::QueueClient(can::ids::NodeId this_fw)
: can::message_writer::MessageWriter{this_fw} {}

void hepauv_tasks::QueueClient::send_interrupt_message(
const hepa_task::TaskMessage& m) {
hepa_queue->try_write(m);
}

/**
* Access to the tasks singleton
* @return
Expand Down
20 changes: 20 additions & 0 deletions hepa-uv/firmware/main_rev1.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
#include "common/firmware/utility_gpio.h"
#include "hepa-uv/core/tasks.hpp"
#include "hepa-uv/firmware/utility_gpio.h"
#include "hepa-uv/core/messages.hpp"

static auto iWatchdog = iwdg::IndependentWatchDog{};

Expand Down Expand Up @@ -53,6 +54,25 @@ static constexpr auto can_bit_timings =
can::bit_timings::BitTimings<170 * can::bit_timings::MHZ, 100,
500 * can::bit_timings::KHZ, 800>{};

static auto& hepa_queue_client = hepauv_tasks::get_main_queues();

extern "C" void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin) {
switch (GPIO_Pin) {
case DOOR_OPEN_MCU_PIN:
case REED_SW_MCU_PIN:
case HEPA_NO_MCU_PIN:
case UV_NO_MCU_PIN:
if (hepa_queue_client.hepa_queue != nullptr) {
static_cast<void>(hepa_queue_client.hepa_queue->try_write_isr(
interrupt_task_messages::GPIOInterruptChanged{.pin = GPIO_Pin }));
}
// send to uv queue here
break;
default:
break;
}
}

auto main() -> int {
HardwareInit();
RCC_Peripheral_Clock_Select();
Expand Down
28 changes: 20 additions & 8 deletions hepa-uv/firmware/stm32g4xx_it.c
Original file line number Diff line number Diff line change
Expand Up @@ -115,14 +115,26 @@ void DebugMon_Handler(void) {}
/* file (startup_stm32g4xxxx.s). */
/******************************************************************************/

/**
* @brief This function handles PPP interrupt request.
* @param None
* @retval None
*/
/*void PPP_IRQHandler(void)
{
}*/
void EXTI2_IRQHandler(void) {
if (__HAL_GPIO_EXTI_GET_IT(GPIO_PIN_2)) {
HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_2);
}
}

void EXTI9_5_IRQHandler(void) {
if (__HAL_GPIO_EXTI_GET_IT(GPIO_PIN_7)) {
HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_7);
}
}

void EXTI15_10_IRQHandler(void) {
if (__HAL_GPIO_EXTI_GET_IT(GPIO_PIN_10)) {
HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_10);
} else if (__HAL_GPIO_EXTI_GET_IT(GPIO_PIN_11)) {
HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_11);
}
}

/**
* @brief This function handles DMA1 channel2 global interrupt.
*/
Expand Down
3 changes: 3 additions & 0 deletions hepa-uv/firmware/stm32g4xx_it.h
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,9 @@ void SysTick_Handler(void);
void DMA1_Channel2_IRQHandler(void);
void DMA1_Channel3_IRQHandler(void);
void FDCAN1_IT0_IRQHandler(void);
void EXTI2_IRQHandler(void);
void EXTI9_5_IRQHandler(void);
void EXTI15_10_IRQHandler(void);

#ifdef __cplusplus
}
Expand Down
77 changes: 69 additions & 8 deletions hepa-uv/firmware/utility_gpio.c
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ void door_open_input_gpio_init() {
/*Configure GPIO pin DOOR_OPEN_MCU : PC7 */
GPIO_InitTypeDef GPIO_InitStruct = {0};
GPIO_InitStruct.Pin = DOOR_OPEN_MCU_PIN;
GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
GPIO_InitStruct.Mode = GPIO_MODE_IT_RISING_FALLING;
GPIO_InitStruct.Pull = GPIO_NOPULL;
HAL_GPIO_Init(DOOR_OPEN_MCU_PORT, &GPIO_InitStruct);
}
Expand All @@ -44,10 +44,10 @@ void door_open_input_gpio_init() {
void reed_switch_input_gpio_init() {
/* GPIO Ports Clock Enable */
__HAL_RCC_GPIOC_CLK_ENABLE();
/*Configure GPIO pin DOOR_OPEN_MCU : PC11 */
/*Configure GPIO pin REED_SW_MCU : PC11 */
GPIO_InitTypeDef GPIO_InitStruct = {0};
GPIO_InitStruct.Pin = REED_SW_MCU_PIN;
GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
GPIO_InitStruct.Mode = GPIO_MODE_IT_RISING_FALLING;
GPIO_InitStruct.Pull = GPIO_NOPULL;
HAL_GPIO_Init(REED_SW_MCU_PORT, &GPIO_InitStruct);
}
Expand All @@ -59,7 +59,7 @@ void reed_switch_input_gpio_init() {
*/
void aux_input_gpio_init(void) {
/* GPIO Ports Clock Enable */
__HAL_RCC_GPIOB_CLK_ENABLE();
__HAL_RCC_GPIOC_CLK_ENABLE();
/*Configure GPIO pin AUX_ID_MCU : PC12 */
GPIO_InitTypeDef GPIO_InitStruct = {0};
GPIO_InitStruct.Pin = AUX_ID_MCU_PIN;
Expand All @@ -79,7 +79,7 @@ void hepa_push_button_input_gpio_init(void) {
/*Configure GPIO pin HEPA_NO_MCU : PB10 */
GPIO_InitTypeDef GPIO_InitStruct = {0};
GPIO_InitStruct.Pin = HEPA_NO_MCU_PIN;
GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
GPIO_InitStruct.Mode = GPIO_MODE_IT_RISING;
GPIO_InitStruct.Pull = GPIO_NOPULL;
HAL_GPIO_Init(HEPA_NO_MCU_PORT, &GPIO_InitStruct);
}
Expand All @@ -89,9 +89,9 @@ void hepa_push_button_input_gpio_init(void) {
* @param None
* @retval None
*/
void uv_push_button_gpio_init(void) {
void uv_push_button_input_gpio_init(void) {
/*Configure Ports Clock Enable*/
__HAL_RCC_GPIOB_CLK_ENABLE();
__HAL_RCC_GPIOC_CLK_ENABLE();
/*Configure GPIO pin UV_NO_MCU : PC2 */
GPIO_InitTypeDef GPIO_InitStruct = {0};
GPIO_InitStruct.Pin = UV_NO_MCU_PIN;
Expand All @@ -100,11 +100,72 @@ void uv_push_button_gpio_init(void) {
HAL_GPIO_Init(UV_NO_MCU_PORT, &GPIO_InitStruct);
}

/**
* @brief HEPA ON/OFF GPIO Initialization Function
* @param None
* @retval None
*/
void hepa_on_off_output_init() {
/* GPIO Ports Clock Enable */
__HAL_RCC_GPIOA_CLK_ENABLE();
/*Configure GPIO pin LED_DRIVE : PA7 */
GPIO_InitTypeDef GPIO_InitStruct = {0};
GPIO_InitStruct.Pin = HEPA_ON_OFF_PIN;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_PULLDOWN;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(HEPA_ON_OFF_PORT, &GPIO_InitStruct);
}

/**
* @brief UV ON/OFF GPIO Initialization Function
* @param None
* @retval None
*/
void uv_on_off_output_init() {
/* GPIO Ports Clock Enable */
__HAL_RCC_GPIOA_CLK_ENABLE();
/*Configure GPIO pin LED_DRIVE : PA4 */
GPIO_InitTypeDef GPIO_InitStruct = {0};
GPIO_InitStruct.Pin = UV_ON_OFF_MCU_PIN;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_PULLDOWN;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(UV_ON_OFF_MCU_PORT, &GPIO_InitStruct);
}

/**
* @brief NVIC EXTI interrupt priority Initialization
* @param None
* @retval None
*/
static void nvic_priority_enable_init() {
/* EXTI interrupt init DOOR_OPEN_MCU : PC7*/
// PC7 -> GPIO_EXTI6 (EXTI9_5_IRQn)
HAL_NVIC_SetPriority(EXTI9_5_IRQn, 5, 0);
HAL_NVIC_EnableIRQ(EXTI9_5_IRQn);

/* EXTI interrupt init REED_SW_MCU : PC11*/
/* EXTI interrupt init HEPA_NO_MCU : PB10*/
// PC11 -> GPIO_EXTI11 (EXTI15_10_IRQn)
// PB11 -> GPIO_EXTI11 (EXTI15_10_IRQn)
HAL_NVIC_SetPriority(EXTI15_10_IRQn, 5, 0);
HAL_NVIC_EnableIRQ(EXTI15_10_IRQn);

/* EXTI interrupt init UV_NO_MCU : PC2*/
// PC2 -> GPIO_EXTI2 (EXTI2_IRQn)
HAL_NVIC_SetPriority(EXTI2_IRQn, 5, 0);
HAL_NVIC_EnableIRQ(EXTI2_IRQn);
}

void utility_gpio_init(void) {
LED_drive_gpio_init();
nvic_priority_enable_init();
door_open_input_gpio_init();
reed_switch_input_gpio_init();
aux_input_gpio_init();
hepa_push_button_input_gpio_init();
uv_push_button_gpio_init();
uv_push_button_input_gpio_init();
hepa_on_off_output_init();
uv_on_off_output_init();
}
92 changes: 92 additions & 0 deletions include/hepa-uv/core/hepa_task.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
#pragma once

#include "can/core/ids.hpp"
#include "common/core/bit_utils.hpp"
#include "common/core/logging.h"
#include "common/core/message_queue.hpp"
#include "messages.hpp"
#include "hepa-uv/firmware/gpio_drive_hardware.hpp"

namespace hepa_task {

using TaskMessage = interrupt_task_messages::TaskMessage;

class HepaMessageHandler {
public:
explicit HepaMessageHandler(
gpio_drive_hardware::GpioDrivePins& drive_pins)
: drive_pins{drive_pins} {}
HepaMessageHandler(const HepaMessageHandler &) = delete;
HepaMessageHandler(const HepaMessageHandler &&) = delete;
auto operator=(const HepaMessageHandler &)
-> HepaMessageHandler & = delete;
auto operator=(const HepaMessageHandler &&)
-> HepaMessageHandler && = delete;
~HepaMessageHandler() { }

void handle_message(const TaskMessage &m) {
std::visit([this](auto o) { this->visit(o); }, m);
}

private:
void visit(const std::monostate &) {}

// Handle GPIO EXTI Interrupts here
void visit(const interrupt_task_messages::GPIOInterruptChanged &m) {
if (m.pin == drive_pins.hepa_push_button.pin) {
hepa_push_button = !hepa_push_button;
// handle state changes here
if (hepa_push_button) {
gpio::set(drive_pins.hepa_on_off);
} else {
gpio::reset(drive_pins.hepa_on_off);
}
}

// TODO: send CAN message to host
}

// state tracking variables
bool hepa_push_button = false;
bool hepa_fan_on = false;

gpio_drive_hardware::GpioDrivePins& drive_pins;
};

/**
* The task type.
*/
template <template <class> class QueueImpl>
requires MessageQueue<QueueImpl<TaskMessage>, TaskMessage>
class HepaTask {
public:
using Messages = TaskMessage;
using QueueType = QueueImpl<TaskMessage>;
HepaTask(QueueType &queue)
: queue{queue} {}
HepaTask(const HepaTask &c) = delete;
HepaTask(const HepaTask &&c) = delete;
auto operator=(const HepaTask &c) = delete;
auto operator=(const HepaTask &&c) = delete;
~HepaTask() = default;

/**
* Task entry point.
*/
[[noreturn]] void operator()(
gpio_drive_hardware::GpioDrivePins* drive_pins) {
auto handler = HepaMessageHandler{*drive_pins};
TaskMessage message{};
for (;;) {
if (queue.try_read(&message, queue.max_delay)) {
handler.handle_message(message);
}
}
}

[[nodiscard]] auto get_queue() const -> QueueType & { return queue; }

private:
QueueType &queue;
};
}; // namespace hepa_task
19 changes: 19 additions & 0 deletions include/hepa-uv/core/messages.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
#pragma once

#include "can/core/messages.hpp"
#include "hepa-uv/firmware/gpio_drive_hardware.hpp"

namespace interrupt_task_messages {

/**
* A message sent when external interurpts are triguered
*/
struct GPIOInterruptChanged {
uint16_t pin;
uint8_t state;
};

using TaskMessage =
std::variant<std::monostate, GPIOInterruptChanged>;

} // namespace interrupt_task_messages
Loading
Loading