Skip to content

Commit

Permalink
Merge pull request #22 from stevenewald/callbacks
Browse files Browse the repository at this point in the history
Centralize async callback storage in preparation for IPC/error handling
  • Loading branch information
stevenewald authored Nov 13, 2024
2 parents b5c0b4f + 0b5802c commit 6d6d0b1
Show file tree
Hide file tree
Showing 13 changed files with 211 additions and 144 deletions.
1 change: 1 addition & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ ETL_INCLUDES += ./external/etl/include/etl/optional.h
ETL_INCLUDES += ./external/etl/include/etl/string.h
ETL_INCLUDES += ./external/etl/include/etl/string_stream.h
ETL_INCLUDES += ./external/etl/include/etl/to_string.h
ETL_INCLUDES += ./external/etl/include/etl/delegate.h

# Source and header files
APP_HEADER_PATHS += ./include
Expand Down
41 changes: 41 additions & 0 deletions include/drivers/button_driver.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
#pragma once

#include "config.hpp"
#include "driver_enums.hpp"
#include "drivers/gpio_pin.hpp"
#include "drivers/gpio_pin_event.hpp"
#include "microbit_v2.h"

namespace edge::drivers {
class ButtonController {
GPIOPin button_a{BTN_A, GPIOConfiguration::IN_PUR};
GPIOPin button_b{BTN_B, GPIOConfiguration::IN_PUR};

void handle_button_press(ButtonType type, ButtonState state);
void handle_gpio_interrupt(nrf_gpio_pin_sense_t sense, int pin);

GPIOPinEvent event_a;
GPIOPinEvent event_b;

using SubscriptionArray = etl::array<SubscribeCallbackPtr, MAX_PROCESSES>;
SubscriptionArray a_subscriptions;
SubscriptionArray b_subscriptions;

ButtonController();
~ButtonController() = default;

public:
ButtonController(const ButtonController&) = delete;
ButtonController(ButtonController&&) = delete;
ButtonController& operator=(const ButtonController&) = delete;
ButtonController& operator=(ButtonController&&) = delete;

static ButtonController& get();

bool get_button_pressed(ButtonType button_type);

void subscribe_button_press(
ButtonType type, SubscribeCallbackPtr callback, uint8_t process_id
);
};
} // namespace edge::drivers
58 changes: 0 additions & 58 deletions include/drivers/buttons.hpp

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

namespace edge::drivers {

// SHOULD BE DEPRECATED SOON
void do_async_work();

etl::optional<int> handle_command(DriverCommand type, int arg1, int arg2, int arg3);
Expand All @@ -15,6 +16,4 @@ void handle_subscribe(
uint8_t process_id
);

etl::optional<subscribe_callback> get_ready_callback(uint8_t process_id);

} // namespace edge::drivers
10 changes: 3 additions & 7 deletions include/hal/gpio_event_controller.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,22 +11,18 @@ static constexpr uint8_t GPIO_PINS = 32;
// TODO: Add a controller for other GPIOTE events (channels)?
class GPIOEventController {
public:
using GPIOEventCallback = void (*)(nrf_gpio_pin_sense_t sense, int pin);
using GPIOEventCallback = etl::delegate<void(nrf_gpio_pin_sense_t, int)>;

private:
etl::array<GPIOEventCallback, GPIO_PINS> callbacks{nullptr};
etl::array<etl::optional<GPIOEventCallback>, GPIO_PINS> callbacks{etl::nullopt};

void handle_gpiote_port_event() const;
GPIOEventController();

public:
~GPIOEventController();

static GPIOEventController& get()
{
static GPIOEventController controller;
return controller;
}
static GPIOEventController& get();

GPIOEventController& operator=(const GPIOEventController&) = delete;
GPIOEventController& operator=(GPIOEventController&&) = delete;
Expand Down
39 changes: 39 additions & 0 deletions include/process_callback_storage.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
#pragma once
#include "config.hpp"
#include "drivers/driver_enums.hpp"

namespace edge {
// One option is to make the drivers and other things non singletons and have the
// scheduler own everything. I'm actually okay with this, but not a big deal rn and this
// works fine
// This doesn't matter rn but would matter if we were worried about shutdown and wanted
// very predictable dtor calls
// TLDR: singleton vs everything owned by scheduler, food for thought
class ProcessCallbackStorage {
public:
static constexpr uint8_t MAX_READY_CALLBACKS = 10;

private:
etl::array<
etl::vector<drivers::subscribe_callback, MAX_READY_CALLBACKS>, MAX_PROCESSES>
ready_callbacks;

ProcessCallbackStorage() = default;
~ProcessCallbackStorage() = default;

public:
ProcessCallbackStorage(const ProcessCallbackStorage&) = delete;
ProcessCallbackStorage(ProcessCallbackStorage&&) = delete;
ProcessCallbackStorage& operator=(const ProcessCallbackStorage&) = delete;
ProcessCallbackStorage& operator=(ProcessCallbackStorage&&) = delete;

void add_ready_callback(
uint8_t process_id, drivers::SubscribeCallbackPtr callback, int arg1 = 0,
int arg2 = 0
);

etl::optional<drivers::subscribe_callback> get_ready_callback(uint8_t process_id);

static ProcessCallbackStorage& get();
};
} // namespace edge
70 changes: 70 additions & 0 deletions src/button_driver.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
#include "drivers/button_driver.hpp"

#include "drivers/driver_enums.hpp"
#include "process_callback_storage.hpp"

namespace edge::drivers {

ButtonController& ButtonController::get()
{
static ButtonController button_controller;
return button_controller;
}

ButtonController::ButtonController() :
event_a{
BTN_A, GPIOConfiguration::IN_PUR,
aidan::GPIOEventController::GPIOEventCallback::create<
ButtonController, &ButtonController::handle_gpio_interrupt>(*this)
},
event_b{
BTN_B, GPIOConfiguration::IN_PUR,
aidan::GPIOEventController::GPIOEventCallback::create<
ButtonController, &ButtonController::handle_gpio_interrupt>(*this)
}
{}

void ButtonController::subscribe_button_press(
ButtonType type, SubscribeCallbackPtr callback, uint8_t process_id
)
{
if (type == ButtonType::A) {
a_subscriptions[process_id] = callback;
}
else if (type == ButtonType::B) {
b_subscriptions[process_id] = callback;
}
}

bool ButtonController::get_button_pressed(ButtonType button_type)
{
if (button_type == ButtonType::A) {
return !button_a.read();
}
else {
return !button_b.read();
}
}

void ButtonController::handle_button_press(ButtonType type, ButtonState state)
{
SubscriptionArray& button_subscriptions =
type == ButtonType::A ? a_subscriptions : b_subscriptions;
for (int process_id = 0; process_id < MAX_PROCESSES; process_id++) {
if (button_subscriptions[process_id] != nullptr) {
ProcessCallbackStorage::get().add_ready_callback(
process_id, button_subscriptions[process_id], static_cast<int>(type),
static_cast<int>(state)
);
}
}
}

void ButtonController::handle_gpio_interrupt(nrf_gpio_pin_sense_t sense, int pin)
{
ButtonType type = pin == BTN_A ? ButtonType::A : ButtonType::B;
ButtonState state =
sense == NRF_GPIO_PIN_SENSE_LOW ? ButtonState::DOWN : ButtonState::UP;
handle_button_press(type, state);
}
} // namespace edge::drivers
62 changes: 0 additions & 62 deletions src/buttons.cpp

This file was deleted.

16 changes: 7 additions & 9 deletions src/driver_controller.cpp → src/driver_commands.cpp
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
#include "drivers/driver_controller.hpp"
#include "drivers/driver_commands.hpp"

#include "drivers/buttons.hpp"
#include "drivers/button_driver.hpp"
#include "drivers/driver_enums.hpp"
#include "drivers/led_display.hpp"
#include "drivers/timer.hpp"

#include <stdio.h>

namespace edge::drivers {

// Runs on context switch
void do_async_work()
{
Expand All @@ -26,7 +27,9 @@ etl::optional<int> handle_command(DriverCommand type, int arg1, int arg2, int ar
printf((char*)arg1);
break;
case DriverCommand::BUTTONS:
return button_controller.get_button_pressed(static_cast<ButtonType>(arg1));
return ButtonController::get().get_button_pressed(
static_cast<ButtonType>(arg1)
);
}
return etl::nullopt;
}
Expand All @@ -38,16 +41,11 @@ void handle_subscribe(
{
switch (type) {
case DriverSubscribe::NOTIFY_BUTTON_PRESS:
button_controller.subscribe_button_press(
ButtonController::get().subscribe_button_press(
static_cast<ButtonType>(arg1), callback, process_id
);
break;
}
}

etl::optional<subscribe_callback> get_ready_callback(uint8_t process_id)
{
return button_controller.get_ready_callback(process_id);
}

} // namespace edge::drivers
12 changes: 9 additions & 3 deletions src/gpio_event_controller.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,15 @@ void GPIOEventController::set_gpio_callback(
);
}

GPIOEventController& GPIOEventController::get()
{
static GPIOEventController controller;
return controller;
}

void GPIOEventController::clear_gpio_callback(uint32_t pin)
{
callbacks[pin] = nullptr;
callbacks[pin] = etl::nullopt;
nrf_gpio_cfg_sense_input(pin, NRF_GPIO_PIN_NOPULL, NRF_GPIO_PIN_NOSENSE);
}

Expand Down Expand Up @@ -59,8 +65,8 @@ void GPIOEventController::handle_gpiote_port_event() const
nrf_gpio_cfg_sense_input(pin, nrf_gpio_pin_pull_get(pin), opposite_state);

auto callback = GPIOEventController::get().callbacks[pin];
if (callback != nullptr) {
callback(state, pin);
if (callback) {
callback.value()(state, pin);
}
}
NRF_GPIO->LATCH = latch;
Expand Down
Loading

0 comments on commit 6d6d0b1

Please sign in to comment.