fully implement Key press handeling in HAL for esp32 hardware and switch hardware to use the refactored UI

make UI add widgets on button presses as a demo
This commit is contained in:
MatthewColvin 2023-10-05 09:53:07 -05:00
parent 7434f0b4da
commit 4a5c83c8b9
8 changed files with 113 additions and 29 deletions

View file

@ -35,17 +35,19 @@ public:
Aux1, Aux1,
Aux2, Aux2,
Aux3, Aux3,
Aux4 Aux4,
INVALID
}; };
class KeyEvent { class KeyEvent {
public: public:
enum class Type { Press, Release }; enum class Type { Press, Release, INVALID };
KeyEvent() = default;
KeyEvent(const KeyId aId, const Type aType) : mId(aId), mType(aType) {} KeyEvent(const KeyId aId, const Type aType) : mId(aId), mType(aType) {}
const KeyId mId; KeyId mId = KeyId::INVALID;
const Type mType; Type mType = Type::INVALID;
}; };
KeyPressAbstract(); KeyPressAbstract();

View file

@ -1,25 +1,61 @@
#include "keys.hpp" #include "keys.hpp"
Keys::Keys() {} Keys::Keys() {
void Keys::HandleKeyPresses(){ static constexpr auto MaxQueueableKeyPresses = 5;
mKeyPressQueueHandle = xQueueCreate(MaxQueueableKeyPresses, sizeof(KeyEvent));
xTaskCreate(KeyGrabberTask, "KeyGrabber", 1024, this, 1, &mKeyGrabbingTask);
xTaskCreate(KeyProccessor, "KeyProccessor", 4096, this, 1, &mKeyHandlingTask);
}
void Keys::KeyGrabberTask(void *aSelf) {
auto self = reinterpret_cast<Keys *>(aSelf);
while (true) {
self->GrabKeys();
vTaskDelay(5 / portTICK_PERIOD_MS); // 5 ms between key grabs
}
}
void Keys::KeyProccessor(void *aSelf) {
auto self = reinterpret_cast<Keys *>(aSelf);
while (true) {
self->HandleKeyPresses();
vTaskDelay(50 / portTICK_PERIOD_MS);
}
}
void Keys::HandleKeyPresses() {
KeyPressAbstract::KeyEvent eventToHandle;
while (xQueueReceive(mKeyPressQueueHandle, &eventToHandle, 0) == pdTRUE) {
if (mKeyEventHandler) {
mKeyEventHandler(eventToHandle);
}
}
}; };
void Keys::QueueKeyEvent(KeyEvent aJustOccuredKeyEvent){
void Keys::QueueKeyEvent(KeyEvent aJustOccuredKeyEvent) {
BaseType_t higherPriorityTaskAwoke;
xQueueSendFromISR(mKeyPressQueueHandle, &aJustOccuredKeyEvent,
&higherPriorityTaskAwoke);
}; };
void Keys::GrabKeys() { void Keys::GrabKeys() {
customKeypad.getKey(); // Populate key list if (!customKeypad.getKeys()) {
for (int i = 0; i < LIST_MAX; return; // no activity return early.
i++) { // Handle multiple keys (Not really necessary in this case) }
for (int i = 0; i < LIST_MAX; i++) {
if (customKeypad.key[i].kstate == PRESSED || if (customKeypad.key[i].kstate == PRESSED ||
customKeypad.key[i].kstate == HOLD) { customKeypad.key[i].kstate == RELEASED) {
// May need to think about resetting sleep timer in key handler.... // May need to think about resetting sleep timer in key handler....
// standbyTimer = // standbyTimer =
// sleepTimeout; // Reset the sleep timer when a button is pressed // sleepTimeout; // Reset the sleep timer when a button is
int keyCode = customKeypad.key[i].kcode; // pressed
// Queue Keys here!! auto eventType = customKeypad.key[i].kstate == PRESSED
Serial.println(customKeypad.key[i].kchar); ? KeyEvent::Type::Press
: KeyEvent::Type::Release;
const auto keyChar = customKeypad.key[i].kchar;
auto stateChange = customKeypad.key[i].stateChanged;
if (charKeyToKeyIds.count(keyChar) > 0 && stateChange) {
QueueKeyEvent(KeyEvent(charKeyToKeyIds.at(keyChar), eventType));
}
} }
} }
} }

View file

@ -2,6 +2,7 @@
#include "KeyPressAbstract.hpp" #include "KeyPressAbstract.hpp"
#include "omoteconfig.h" #include "omoteconfig.h"
#include <Keypad.h> // modified for inverted logic #include <Keypad.h> // modified for inverted logic
#include <map>
class Keys : public KeyPressAbstract { class Keys : public KeyPressAbstract {
public: public:
@ -13,6 +14,9 @@ protected:
void GrabKeys(); void GrabKeys();
private: private:
static void KeyGrabberTask(void *aSelf);
static void KeyProccessor(void *aSelf);
QueueHandle_t mKeyPressQueueHandle; QueueHandle_t mKeyPressQueueHandle;
TaskHandle_t mKeyGrabbingTask; TaskHandle_t mKeyGrabbingTask;
TaskHandle_t mKeyHandlingTask; TaskHandle_t mKeyHandlingTask;
@ -23,11 +27,46 @@ private:
// define the symbols on the buttons of the keypads // define the symbols on the buttons of the keypads
char hexaKeys[ROWS][COLS] = { char hexaKeys[ROWS][COLS] = {
{'s', '^', '-', 'm', 'r'}, // source, channel+, Volume-, mute, record {'s', '^', '-', 'm', 'r'}, // source, channel+, Volume-, mute, record
{'i', 'r', '+', 'k', 'd'}, // info, right, Volume+, OK, down {'i', 'R', '+', 'k', 'd'}, // info, right, Volume+, OK, down
{'4', 'v', '1', '3', '2'}, // blue, channel-, red, yellow, green {'4', 'v', '1', '3', '2'}, // blue, channel-, red, yellow, green
{'>', 'o', 'b', 'u', 'l'}, // forward, off, back, up, left {'>', 'o', 'b', 'u', 'L'}, // forward, off, back, up, left
{'?', 'p', 'c', '<', '='} // ?, play, config, rewind, stop {'?', 'p', 'c', '<', '='} // ?, play, config, rewind, stop
}; };
// TODO what is '?' lol
// TODO Should be able to optomize this out by reordering Ids at some point
// or even using interrupts to trigger key press queueing
static inline const std::map<char, KeyId> charKeyToKeyIds{
{'o', KeyId::Power},
// Top 4 Buttons left to right
{'=', KeyId::Stop},
{'<', KeyId::Rewind},
{'p', KeyId::Play},
{'>', KeyId::FastForward},
// Buttons around D Pad
{'c', KeyId::Menu},
{'i', KeyId::Info},
{'b', KeyId::Back},
{'s', KeyId::Source},
// D Pad
{'u', KeyId::Up},
{'d', KeyId::Down},
{'L', KeyId::Left},
{'R', KeyId::Right},
{'k', KeyId::Center},
// Volume Channel and 2 between
{'+', KeyId::VolUp},
{'-', KeyId::VolDown},
{'m', KeyId::Mute},
{'r', KeyId::Record},
{'^', KeyId::ChannelUp},
{'v', KeyId::ChannelDown},
// Bottom 4 buttons left to right
{'1', KeyId::Aux1},
{'2', KeyId::Aux2},
{'3', KeyId::Aux3},
{'4', KeyId::Aux4}};
byte rowPins[ROWS] = {SW_A, SW_B, SW_C, SW_D, byte rowPins[ROWS] = {SW_A, SW_B, SW_C, SW_D,
SW_E}; // connect to the row pinouts of the keypad SW_E}; // connect to the row pinouts of the keypad
byte colPins[COLS] = {SW_1, SW_2, SW_3, SW_4, byte colPins[COLS] = {SW_1, SW_2, SW_3, SW_4,

View file

@ -3,7 +3,8 @@
using namespace UI::Page; using namespace UI::Page;
SettingsPage::SettingsPage() : Base(ID::Pages::Settings) { SettingsPage::SettingsPage(std::shared_ptr<HardwareAbstract> aHardware)
: Base(ID::Pages::Settings), mHardware(aHardware) {
SetBgColor(lv_color_make(255, 0, 0)); SetBgColor(lv_color_make(255, 0, 0));
} }

View file

@ -1,9 +1,10 @@
#include "HardwareAbstract.hpp"
#include "PageBase.hpp" #include "PageBase.hpp"
namespace UI::Page { namespace UI::Page {
class SettingsPage : public Base { class SettingsPage : public Base {
public: public:
SettingsPage(); SettingsPage(std::shared_ptr<HardwareAbstract> aHardware = nullptr);
bool OnKeyEvent(KeyPressAbstract::KeyEvent aKeyEvent) override; bool OnKeyEvent(KeyPressAbstract::KeyEvent aKeyEvent) override;
@ -13,5 +14,6 @@ protected:
void OnShow() override; void OnShow() override;
std::vector<Widget::Base *> sliders; std::vector<Widget::Base *> sliders;
std::shared_ptr<HardwareAbstract> mHardware;
}; };
} // namespace UI::Page } // namespace UI::Page

View file

@ -3,16 +3,17 @@
using namespace UI::Screen; using namespace UI::Screen;
HomeScreen::HomeScreen() HomeScreen::HomeScreen(std::shared_ptr<HardwareAbstract> aHardware)
: Base(UI::ID::Screens::Home), mTabView(ID(ID::Pages::INVALID_PAGE_ID)) { : Base(UI::ID::Screens::Home), mHardware(aHardware),
mTabView(ID(ID::Pages::INVALID_PAGE_ID)) {
SetBgColor(lv_color_black()); SetBgColor(lv_color_black());
SetPushAnimation(LV_SCR_LOAD_ANIM_FADE_IN); SetPushAnimation(LV_SCR_LOAD_ANIM_FADE_IN);
AddElement(&mTabView); // Adds Tabview to Homescreen AddElement(&mTabView); // Adds Tabview to Homescreen
// Adds pages to the Tab view // Adds pages to the Tab view
mTabView.AddTab(std::make_unique<Page::SettingsPage>(), "Settings"); mTabView.AddTab(std::make_unique<Page::SettingsPage>(aHardware), "Settings");
mTabView.AddTab(std::make_unique<Page::SettingsPage>(), "Settings1"); mTabView.AddTab(std::make_unique<Page::SettingsPage>(aHardware), "Settings1");
} }
void HomeScreen::SetBgColor(lv_color_t value, lv_style_selector_t selector) { void HomeScreen::SetBgColor(lv_color_t value, lv_style_selector_t selector) {

View file

@ -1,4 +1,5 @@
#pragma once #pragma once
#include "HardwareAbstract.hpp"
#include "PageBase.hpp" #include "PageBase.hpp"
#include "ScreenBase.hpp" #include "ScreenBase.hpp"
#include "TabView.hpp" #include "TabView.hpp"
@ -7,7 +8,7 @@ namespace UI::Screen {
class HomeScreen : public Base { class HomeScreen : public Base {
public: public:
HomeScreen(); HomeScreen(std::shared_ptr<HardwareAbstract> aHardware = nullptr);
void SetBgColor(lv_color_t value, void SetBgColor(lv_color_t value,
lv_style_selector_t selector = LV_PART_MAIN) override; lv_style_selector_t selector = LV_PART_MAIN) override;
@ -19,6 +20,7 @@ protected:
private: private:
Page::TabView mTabView; Page::TabView mTabView;
std::shared_ptr<HardwareAbstract> mHardware = nullptr;
}; };
} // namespace UI::Screen } // namespace UI::Screen

View file

@ -1,24 +1,25 @@
// OMOTE firmware for ESP32 // OMOTE firmware for ESP32
// 2023 Maximilian Kern // 2023 Maximilian Kern
#include "BasicUI.hpp"
#include "HardwareRevX.hpp" #include "HardwareRevX.hpp"
#include "OmoteUI.hpp"
#include "omoteconfig.h" #include "omoteconfig.h"
#include <lvgl.h> #include <lvgl.h>
std::shared_ptr<HardwareRevX> hal = nullptr; std::shared_ptr<HardwareRevX> hal = nullptr;
std::shared_ptr<UI::UIBase> ui = nullptr;
void setup() { void setup() {
hal = HardwareRevX::getInstance(); hal = HardwareRevX::getInstance();
hal->init(); hal->init();
auto ui = UI::Basic::OmoteUI::getInstance(hal); auto ui = UI::BasicUI(hal);
ui->layout_UI(); // ui->layout_UI();
lv_timer_handler(); // Run the LVGL UI once before the loop takes over lv_timer_handler(); // Run the LVGL UI once before the loop takes over
} }
void loop() { void loop() {
HardwareRevX::getInstance()->loopHandler(); hal->loopHandler();
UI::Basic::OmoteUI::getInstance()->loopHandler(); ui->loopHandler();
} }