Skip to content

Commit

Permalink
Merge pull request #17 from stevenewald/subscribe
Browse files Browse the repository at this point in the history
Add subscriptions for buttons
  • Loading branch information
stevenewald authored Nov 6, 2024
2 parents 42897ef + f5d0ecc commit 4c5766b
Show file tree
Hide file tree
Showing 26 changed files with 457 additions and 115 deletions.
1 change: 0 additions & 1 deletion external/microbit_v2/Board.mk
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,6 @@ BOARD_SOURCES += \
nrf_strerror.c\
nrf_twi_mngr.c\
nrfx_clock.c\
nrfx_gpiote.c\
nrfx_ppi.c\
nrfx_prs.c\
nrfx_pwm.c\
Expand Down
5 changes: 5 additions & 0 deletions include/config.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
#pragma once

namespace edge {
constexpr uint8_t MAX_PROCESSES = 10;
}
5 changes: 0 additions & 5 deletions include/drivers/button_type.hpp

This file was deleted.

52 changes: 40 additions & 12 deletions include/drivers/buttons.hpp
Original file line number Diff line number Diff line change
@@ -1,24 +1,52 @@
#pragma once

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

namespace edge::drivers {
// Without runtime std::function, we can't directly point the gpio callback to
// handle_callback instead, we need a function to call it instead. I'm sure there is a
// better way to do this, though
void handle_gpiote_callback(int channel);

class ButtonController {
GPIOPin button_a{BTN_A, IN_PUR};
GPIOPin button_b{BTN_B, IN_PUR};
public:
static constexpr uint8_t MAX_READY_CALLBACKS = 10;

private:
GPIOPin button_a{BTN_A, GPIOConfiguration::IN_PUR};
GPIOPin button_b{BTN_B, GPIOConfiguration::IN_PUR};

GPIOTEPin int_button_a{
0, BTN_A, aidan::GPIOTEEventPolarity::HI_TO_LO,
&edge::drivers::handle_gpiote_callback
};
GPIOTEPin int_button_b{
1, BTN_B, aidan::GPIOTEEventPolarity::HI_TO_LO,
&edge::drivers::handle_gpiote_callback
};

using SubscriptionArray = etl::array<ButtonCallbackPtr, MAX_PROCESSES>;
etl::array<SubscriptionArray, 2> subscriptions;
etl::array<
etl::vector<button_subscribe_callback, MAX_READY_CALLBACKS>, MAX_PROCESSES>
ready_callbacks;

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

void subscribe_button_press(
ButtonType type, ButtonCallbackPtr callback, uint8_t process_id
);

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

private:
void handle_callback(int button_type);
friend void handle_gpiote_callback(int channel);
};

extern ButtonController button_controller;
Expand Down
10 changes: 0 additions & 10 deletions include/drivers/driver_commands.hpp

This file was deleted.

11 changes: 9 additions & 2 deletions include/drivers/driver_controller.hpp
Original file line number Diff line number Diff line change
@@ -1,13 +1,20 @@
#pragma once

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

#include <stdio.h>

namespace edge::drivers {

void do_async_work();

etl::optional<int> handle_command(DriverType type, int arg1, int arg2, int arg3);
etl::optional<int> handle_command(DriverCommand type, int arg1, int arg2, int arg3);

void handle_subscribe(
DriverSubscribe type, ButtonCallbackPtr callback, int arg1, int arg2,
uint8_t process_id
);

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

} // namespace edge::drivers
24 changes: 24 additions & 0 deletions include/drivers/driver_enums.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
#pragma once

namespace edge::drivers {
enum class DriverCommand {
GET_TIME = 0,
LED_DISPLAY = 1,
BUTTONS = 2,
TERMINAL_OUTPUT = 3
};

enum class DriverSubscribe { NOTIFY_BUTTON_PRESS = 0 };

enum class GPIOConfiguration { OUT, IN_NORES, IN_PDR, IN_PUR };

enum class ButtonType { A = 0, B = 1 };

using ButtonCallbackPtr = void (*)(ButtonType);

struct button_subscribe_callback {
ButtonCallbackPtr callback;
ButtonType type;
};

} // namespace edge::drivers
10 changes: 5 additions & 5 deletions include/drivers/gpio_pin.hpp
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
#pragma once

#include "driver_enums.hpp"
#include "hil/gpio_wrapper.hpp"
#include "hil/hil_enums.hpp"
#include "stdint.h"

namespace edge {
namespace drivers {

enum GPIOConfiguration { OUT, IN_NORES, IN_PDR, IN_PUR };

class GPIOPin {
public:
GPIOPin(uint32_t const pin_number, GPIOConfiguration const pin_config) :
Expand All @@ -18,13 +18,13 @@ class GPIOPin {
aidan::set_gpio_pin_output(pin_number);
break;
case GPIOConfiguration::IN_NORES:
aidan::set_gpio_pin_input(pin_number, aidan::INPUT_RESISTOR::NONE);
aidan::set_gpio_pin_input(pin_number, aidan::InputResistor::NONE);
break;
case GPIOConfiguration::IN_PDR:
aidan::set_gpio_pin_input(pin_number, aidan::INPUT_RESISTOR::PDR);
aidan::set_gpio_pin_input(pin_number, aidan::InputResistor::PDR);
break;
case GPIOConfiguration::IN_PUR:
aidan::set_gpio_pin_input(pin_number, aidan::INPUT_RESISTOR::PUR);
aidan::set_gpio_pin_input(pin_number, aidan::InputResistor::PUR);
break;
}
}
Expand Down
28 changes: 28 additions & 0 deletions include/drivers/gpiote_pin.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
#pragma once

#include "hil/gpiote_wrapper.hpp"
#include "hil/hil_enums.hpp"

namespace edge::drivers {
class GPIOTEPin {
uint32_t channel;

public:
// TODO: use PORT event instead so we aren't limited to 8 of these
GPIOTEPin(
uint32_t channel, uint32_t pin_number, aidan::GPIOTEEventPolarity polarity,
void (*callback)(int)
) : channel(channel)
{
aidan::configure_gpiote_event(channel, pin_number, polarity);
aidan::set_gpiote_callback(channel, callback);
}

GPIOTEPin(const GPIOTEPin&) = delete;
GPIOTEPin(GPIOTEPin&&) = delete;
GPIOTEPin& operator=(const GPIOTEPin&) = delete;
GPIOTEPin& operator=(GPIOTEPin&&) = delete;

~GPIOTEPin() { aidan::clear_gpiote_event(channel); }
};
} // namespace edge::drivers
22 changes: 11 additions & 11 deletions include/drivers/led_display.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,19 +12,19 @@ class LedDisplay {
etl::array<etl::array<bool, WIDTH>, HEIGHT> led_enabled{};

etl::array<GPIOPin, HEIGHT> led_rows = {
GPIOPin{LED_ROW1, OUT},
GPIOPin{LED_ROW2, OUT},
GPIOPin{LED_ROW3, OUT},
GPIOPin{LED_ROW4, OUT},
GPIOPin{LED_ROW5, OUT}
GPIOPin{LED_ROW1, GPIOConfiguration::OUT},
GPIOPin{LED_ROW2, GPIOConfiguration::OUT},
GPIOPin{LED_ROW3, GPIOConfiguration::OUT},
GPIOPin{LED_ROW4, GPIOConfiguration::OUT},
GPIOPin{LED_ROW5, GPIOConfiguration::OUT}
};

etl::array<GPIOPin, WIDTH> led_cols = {
GPIOPin{LED_COL1, OUT},
GPIOPin{LED_COL2, OUT},
GPIOPin{LED_COL3, OUT},
GPIOPin{LED_COL4, OUT},
GPIOPin{LED_COL5, OUT}
GPIOPin{LED_COL1, GPIOConfiguration::OUT},
GPIOPin{LED_COL2, GPIOConfiguration::OUT},
GPIOPin{LED_COL3, GPIOConfiguration::OUT},
GPIOPin{LED_COL4, GPIOConfiguration::OUT},
GPIOPin{LED_COL5, GPIOConfiguration::OUT}
};

void set_output(uint8_t row, uint8_t col, bool enabled);
Expand All @@ -34,7 +34,7 @@ class LedDisplay {

void set_led(uint8_t row, uint8_t col, bool enabled);

void display_pixels_once();
void do_async_work();
};

extern LedDisplay led_display;
Expand Down
6 changes: 3 additions & 3 deletions include/hil/gpio_wrapper.hpp
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
#pragma once

namespace edge::aidan {
#include "hil/hil_enums.hpp"

enum INPUT_RESISTOR { PUR, PDR, NONE };
namespace edge::aidan {

bool read_gpio_pin(uint32_t pin_number);

Expand All @@ -16,6 +16,6 @@ void toggle_gpio_pin(uint32_t pin_number);

void set_gpio_pin_output(uint32_t pin_number);

void set_gpio_pin_input(uint32_t pin_number, INPUT_RESISTOR input_resistor);
void set_gpio_pin_input(uint32_t pin_number, InputResistor input_resistor);

} // namespace edge::aidan
16 changes: 16 additions & 0 deletions include/hil/gpiote_wrapper.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
#include "hil_enums.hpp"

#include <nrf_gpiote.h>

#include <cstdint>

namespace edge::aidan {

void set_gpiote_callback(uint32_t channel, void (*callback)(int));

void clear_gpiote_event(uint32_t channel);

void configure_gpiote_event(
uint32_t channel, uint32_t pin_number, GPIOTEEventPolarity polarity
);
} // namespace edge::aidan
15 changes: 15 additions & 0 deletions include/hil/hil_enums.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
#pragma once

#include <nrf_gpiote.h>

namespace edge::aidan {
enum class InputResistor { PUR, PDR, NONE };

enum class GPIOTEEventPolarity {
LO_TO_HI = NRF_GPIOTE_POLARITY_LOTOHI,
HI_TO_LO = NRF_GPIOTE_POLARITY_HITOLO,
TOGGLE = NRF_GPIOTE_POLARITY_TOGGLE,
};

enum class GPIOTETask { SET, CLEAR };
} // namespace edge::aidan
50 changes: 31 additions & 19 deletions include/scheduler.hpp
Original file line number Diff line number Diff line change
@@ -1,56 +1,67 @@
#pragma once

#include "config.hpp"

#include <stdio.h>

#include <cstdint>

static constexpr auto MAX_PROCESSES = 10;
static constexpr size_t STACK_SIZE_BYTES = 2048;
static constexpr size_t QUANTUM_MILLIS = 10;
static constexpr size_t QUANTUM_MILLIS = 5;

namespace edge {
extern "C" {
void PendSV_Handler();
void SVC_Handler();
void restore();
}

struct saved_registers {
unsigned R0{};
unsigned R1{};
unsigned R2{};
unsigned R3{};
unsigned R12{};
unsigned LR{};
unsigned RETURN_ADDR{};
unsigned FLAG{};

saved_registers(unsigned return_addr, unsigned flag = 0x01000000) :
RETURN_ADDR(return_addr), FLAG(flag)
{}
};

class Scheduler {
unsigned current_task_index = 0;
uint8_t slices_remaining = 1;

struct saved_registers {
const unsigned HARDWARE_REGS[5]{};
const unsigned RETURN_ADDR;
const unsigned FLAG;
const unsigned SOFTWARE_REGS[8]{};

saved_registers(unsigned return_addr, unsigned flag = 0x01000000) :
RETURN_ADDR(return_addr), FLAG(flag)
{}
};

struct task {
class Task {
static constexpr size_t STACK_SIZE_IN_UNSIGNED =
STACK_SIZE_BYTES / sizeof(unsigned);

// ===== DO NOT REARRANGE THESE =====
etl::array<unsigned, STACK_SIZE_IN_UNSIGNED> stack{};
saved_registers METADATA;
saved_registers first_stack_frame;
// ==================================

unsigned* stack_ptr_loc{&stack.back()};
public:
// needs to point to first_stack_frame
unsigned* stack_ptr_loc{&first_stack_frame.R0};

// This is useful if we want to adjust the ratio of driver to process runtime
uint8_t consecutive_quantums_to_run;

task(const saved_registers& metadata, uint8_t initial_priority) :
METADATA(metadata), consecutive_quantums_to_run(initial_priority)
Task(const saved_registers& initial_stack_frame, uint8_t initial_priority) :
first_stack_frame(initial_stack_frame),
consecutive_quantums_to_run(initial_priority)
{}
};

etl::vector<task, MAX_PROCESSES> task_stack{};
etl::vector<Task, MAX_PROCESSES> task_stack{};

public:
unsigned get_current_task() const { return current_task_index; }

void add_task(void (*function)(void), uint8_t priority = 1);

void start_scheduler();
Expand All @@ -63,6 +74,7 @@ class Scheduler {

friend void PendSV_Handler(void);
friend void SVC_Handler(void);
friend void restore(void);
};

extern Scheduler scheduler;
Expand Down
Loading

0 comments on commit 4c5766b

Please sign in to comment.