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 a task to handle the UV Ballast state based on external input #744

Merged
merged 3 commits into from
Jan 18, 2024
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 11 additions & 1 deletion hepa-uv/core/tasks.cpp
Original file line number Diff line number Diff line change
@@ -17,6 +17,9 @@ static auto queues = hepauv_tasks::QueueClient{can::ids::NodeId::hepa_uv};
static auto hepa_task_builder =
freertos_task::TaskStarter<512, hepa_task::HepaTask>{};

static auto uv_task_builder =
freertos_task::TaskStarter<512, uv_task::UVTask>{};

/**
* Start hepa_uv tasks.
*/
@@ -27,22 +30,29 @@ void hepauv_tasks::start_tasks(
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);

tasks.hepa_task_handler = &hepa_task;
tasks.uv_task_handler = &uv_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();
}

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

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

void hepauv_tasks::QueueClient::send_uv_message(const uv_task::TaskMessage& m) {
uv_queue->try_write(m);
}

/**
* Access to the tasks singleton
* @return
12 changes: 8 additions & 4 deletions hepa-uv/firmware/main_rev1.cpp
Original file line number Diff line number Diff line change
@@ -91,20 +91,24 @@ static auto gpio_drive_pins = gpio_drive_hardware::GpioDrivePins{
.pin = UV_ON_OFF_MCU_PIN,
.active_setting = UV_ON_OFF_AS}};

static auto& hepa_queue_client = hepauv_tasks::get_main_queues();
static auto& hepauv_queues = 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(
if (hepauv_queues.hepa_queue != nullptr) {
static_cast<void>(hepauv_queues.hepa_queue->try_write_isr(
interrupt_task_messages::GPIOInterruptChanged{
.pin = GPIO_Pin}));
}
if (hepauv_queues.uv_queue != nullptr) {
static_cast<void>(hepauv_queues.uv_queue->try_write_isr(
interrupt_task_messages::GPIOInterruptChanged{
.pin = GPIO_Pin}));
}
// send to uv queue here
break;
default:
break;
7 changes: 6 additions & 1 deletion include/hepa-uv/core/hepa_task.hpp
Original file line number Diff line number Diff line change
@@ -15,7 +15,12 @@ using TaskMessage = interrupt_task_messages::TaskMessage;
class HepaMessageHandler {
public:
explicit HepaMessageHandler(gpio_drive_hardware::GpioDrivePins &drive_pins)
: drive_pins{drive_pins} {}
: drive_pins{drive_pins} {
// get current state
hepa_push_button = gpio::is_set(drive_pins.hepa_push_button);
// turn off the HEPA fan
gpio::reset(drive_pins.hepa_on_off);
}
HepaMessageHandler(const HepaMessageHandler &) = delete;
HepaMessageHandler(const HepaMessageHandler &&) = delete;
auto operator=(const HepaMessageHandler &) -> HepaMessageHandler & = delete;
10 changes: 9 additions & 1 deletion include/hepa-uv/core/tasks.hpp
Original file line number Diff line number Diff line change
@@ -2,6 +2,7 @@
#include "can/core/message_writer.hpp"
#include "common/core/freertos_timer.hpp"
#include "hepa-uv/core/hepa_task.hpp"
#include "hepa-uv/core/uv_task.hpp"
#include "hepa-uv/firmware/gpio_drive_hardware.hpp"

namespace hepauv_tasks {
@@ -18,10 +19,14 @@ void start_tasks(can::bus::CanBus& can_bus,
struct QueueClient : can::message_writer::MessageWriter {
QueueClient(can::ids::NodeId this_fw);

void send_interrupt_message(const hepa_task::TaskMessage& m);
void send_hepa_message(const hepa_task::TaskMessage& m);
void send_uv_message(const hepa_task::TaskMessage& m);

freertos_message_queue::FreeRTOSMessageQueue<hepa_task::TaskMessage>*
hepa_queue{nullptr};

freertos_message_queue::FreeRTOSMessageQueue<uv_task::TaskMessage>*
uv_queue{nullptr};
};

/**
@@ -33,6 +38,9 @@ struct AllTask {

hepa_task::HepaTask<freertos_message_queue::FreeRTOSMessageQueue>*
hepa_task_handler{nullptr};

uv_task::UVTask<freertos_message_queue::FreeRTOSMessageQueue>*
uv_task_handler{nullptr};
};

/**
133 changes: 133 additions & 0 deletions include/hepa-uv/core/uv_task.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
#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 "hepa-uv/firmware/gpio_drive_hardware.hpp"
#include "messages.hpp"
#include "ot_utils/freertos/freertos_timer.hpp"

namespace uv_task {

// How long to keep the UV light on in ms.
static constexpr uint32_t DELAY_MS = 1000 * 60 * 15; // 15 minutes

using TaskMessage = interrupt_task_messages::TaskMessage;

class UVMessageHandler {
public:
explicit UVMessageHandler(gpio_drive_hardware::GpioDrivePins &drive_pins)
: drive_pins{drive_pins},
_timer(
"UVTask", [ThisPtr = this] { ThisPtr->timer_callback(); },
DELAY_MS) {
// get current state
uv_push_button = gpio::is_set(drive_pins.uv_push_button);
door_closed = gpio::is_set(drive_pins.door_open);
reed_switch_set = gpio::is_set(drive_pins.reed_switch);
// turn off UV Ballast
gpio::reset(drive_pins.uv_on_off);
}
UVMessageHandler(const UVMessageHandler &) = delete;
UVMessageHandler(const UVMessageHandler &&) = delete;
auto operator=(const UVMessageHandler &) -> UVMessageHandler & = delete;
auto operator=(const UVMessageHandler &&) -> UVMessageHandler && = delete;
~UVMessageHandler() {}

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

private:
// call back to turn off the UV ballast
auto timer_callback() -> void {
gpio::reset(drive_pins.uv_on_off);
uv_push_button = false;
uv_fan_on = false;
}

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) {
// ignore hepa push button presses
return;
}

// update states
if (m.pin == drive_pins.uv_push_button.pin) {
uv_push_button = !uv_push_button;
} else if (m.pin == drive_pins.door_open.pin) {
door_closed = gpio::is_set(drive_pins.door_open);
} else if (m.pin == drive_pins.reed_switch.pin) {
reed_switch_set = gpio::is_set(drive_pins.reed_switch);
}

// reset push button state if the door is opened or the reed switch is
// not set
if (!door_closed || !reed_switch_set) uv_push_button = false;

// set the UV Ballast
if (door_closed && reed_switch_set && uv_push_button) {
gpio::set(drive_pins.uv_on_off);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what happens if i push the button twice?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We toggle the uv_push_button every time it's pressed on line 61.
Assuming the ballast is on and the timer is running, pressing the button again would turn it off and cancel the timer.

// start the turn off timer
if (_timer.is_running()) _timer.stop();
_timer.start();
uv_fan_on = true;
} else {
gpio::reset(drive_pins.uv_on_off);
if (_timer.is_running()) _timer.stop();
uv_fan_on = false;
}

// TODO: send CAN message to host
}

// state tracking variables
bool door_closed = false;
bool reed_switch_set = false;
bool uv_push_button = false;
bool uv_fan_on = false;

gpio_drive_hardware::GpioDrivePins &drive_pins;
ot_utils::freertos_timer::FreeRTOSTimer _timer;
};

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

/**
* Task entry point.
*/
[[noreturn]] void operator()(
gpio_drive_hardware::GpioDrivePins *drive_pins) {
auto handler = UVMessageHandler{*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 uv_task
Loading