Skip to content

Commit

Permalink
Merge pull request #18 from aaronze/add-morse-code-input-on-single-bu…
Browse files Browse the repository at this point in the history
…tton

Added morse code input module and integrated it into the menu system
  • Loading branch information
coelacant1 authored May 4, 2024
2 parents 01d3b7e + de28a69 commit 9b7d1bc
Show file tree
Hide file tree
Showing 6 changed files with 269 additions and 22 deletions.
65 changes: 45 additions & 20 deletions lib/ProtoTracer/Examples/Protogen/ProtogenHUB75Project.h
Original file line number Diff line number Diff line change
Expand Up @@ -99,26 +99,11 @@ class ProtogenHUB75Project : public ProtogenProject {
controller.SetBrightness(Menu::GetBrightness());
controller.SetAccentBrightness(Menu::GetAccentBrightness());

if (IsBooped() && mode != 6){
Surprised();
}
else{
if (mode == 0) Default();
else if (mode == 1) Angry();
else if (mode == 2) Doubt();
else if (mode == 3) Frown();
else if (mode == 4) LookUp();
else if (mode == 5) Sad();
else if (mode == 6) {
AudioReactiveGradientFace();
}
else if (mode == 7){
OscilloscopeFace();
}
else {
SpectrumAnalyzerFace();
}
}
#ifdef MORSEBUTTON
SelectFaceFromMorse(mode);
#else
SelectFace(mode);
#endif

UpdateFace(ratio);

Expand All @@ -129,4 +114,44 @@ class ProtogenHUB75Project : public ProtogenProject {
pM.GetObject()->GetTransform()->SetPosition(GetWiggleOffset());
pM.GetObject()->UpdateTransform();
}

void SelectFace(uint8_t code) {
if (IsBooped() && code != 6) {
Surprised();
return;
}

switch(code) {
case 0: Default(); break;
case 1: Angry(); break;
case 2: Doubt(); break;
case 3: Frown(); break;
case 4: LookUp(); break;
case 5: Sad(); break;
case 6: AudioReactiveGradientFace(); break;
case 7: OscilloscopeFace(); break;
default: SpectrumAnalyzerFace(); break;
}
}

void SelectFaceFromMorse(uint8_t code) {
if (IsBooped() && code != 24) {
Surprised();
return;
}

switch(code) {
case 1: Angry(); break; // [A]ngry
case 2: Surprised(); break; // [B]lush
case 4: Doubt(); break; // [D]oubt
case 6: Frown(); break; // [F]rown
case 19: Sad(); break; // [S]ad
case 21: LookUp(); break; // Look [U]p
case 22: LookDown(); break; // Look [V] Down
case 24: AudioReactiveGradientFace(); break; // [X] X.X
case 25: OscilloscopeFace(); break; // [Y] Oscilloscope
case 26: SpectrumAnalyzerFace(); break; // [Z] Spectrum
default: Default(); break; // [H] Happy
}
}
};
3 changes: 2 additions & 1 deletion lib/ProtoTracer/Examples/UserConfiguration.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,5 @@
#define PRINTINFO //Prints live stats, FPS,etc
//#define DEBUG //Prints debug information
//#define TESTHARDWARE //Tests for default hardware on the protocontroller, apds9960, ssd1306, neotrellis
//#define NEOTRELLISMENU //Enables the NeoTrellis controller, otherwise uses the button controller
//#define NEOTRELLISMENU //Enables the NeoTrellis controller, otherwise uses the button controller
//#define MORSEBUTTON // Enables inputting morse code into the button, cannot be used at the same time as NEOTRELLISMENU
6 changes: 5 additions & 1 deletion lib/ProtoTracer/ExternalDevices/InputDevices/Menu/Menu.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,11 @@ Overflow Menu::overflow = Overflow(20);

void Menu::SetMaxEntries() {
// Define your max entries here
#ifdef MORSEBUTTON
MenuHandler<menuCount>::SetMenuMax(Faces, 27); // 1 unset + 26 letters
#else
MenuHandler<menuCount>::SetMenuMax(Faces, faceCount);
#endif
MenuHandler<menuCount>::SetMenuMax(Bright, 10);
MenuHandler<menuCount>::SetMenuMax(AccentBright, 10);
MenuHandler<menuCount>::SetMenuMax(Microphone, 2);
Expand Down Expand Up @@ -194,7 +198,7 @@ void Menu::SetCurrentMenu(uint8_t currentMenu) {
}

void Menu::Update(float ratio) {
#ifdef NEOTRELLISMENU
#if defined NEOTRELLISMENU || defined MORSEBUTTON
MenuHandler<menuCount>::Update();
#endif

Expand Down
2 changes: 2 additions & 0 deletions lib/ProtoTracer/ExternalDevices/InputDevices/Menu/Menu.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@

#ifdef NEOTRELLISMENU
#include "..\NeoTrellisMenuHandler.h"
#elif defined MORSEBUTTON
#include "..\SingleButtonMorseHandler.h"
#else
#include "..\SingleButtonMenuHandler.h"
#endif
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
#pragma once

#include <Arduino.h>
#include <EEPROM.h>

template <uint8_t menuCount>
class MenuHandler {
private:
static bool previousState;
static long previousMillis;
static uint8_t inputCount;
static uint16_t inputStream[4];
static uint8_t currentMenu;
static uint8_t currentValue[menuCount];
static uint8_t maxValue[menuCount];
static uint8_t pin;

static uint8_t ReadEEPROM(uint16_t index);
static void WriteEEPROM(uint16_t index, uint8_t value);

public:
static void Begin();
static bool Initialize(uint8_t pin, uint16_t holdingTime);
static void SetDefaultValue(uint16_t menu, uint8_t value);
static void SetInitialized();
static void SetMenuMax(uint8_t menu, uint8_t maxValue);
static void Update();
static uint8_t GetMenuValue(uint8_t menu);
static uint8_t GetCurrentMenu();
};

#include "SingleButtonMorseHandler.tpp"
Original file line number Diff line number Diff line change
@@ -0,0 +1,183 @@
#pragma once

template <uint8_t menuCount>
bool MenuHandler<menuCount>::previousState;

template <uint8_t menuCount>
long MenuHandler<menuCount>::previousMillis;

template <uint8_t menuCount>
uint8_t MenuHandler<menuCount>::inputCount;

template <uint8_t menuCount>
uint8_t MenuHandler<menuCount>::currentMenu;

template <uint8_t menuCount>
uint16_t MenuHandler<menuCount>::inputStream[4];

template <uint8_t menuCount>
uint8_t MenuHandler<menuCount>::currentValue[menuCount];

template <uint8_t menuCount>
uint8_t MenuHandler<menuCount>::maxValue[menuCount];

template <uint8_t menuCount>
uint8_t MenuHandler<menuCount>::pin;

template <uint8_t menuCount>
void MenuHandler<menuCount>::Begin() {
previousMillis = millis();
previousState = false;
}

template <uint8_t menuCount>
void MenuHandler<menuCount>::Update() {
bool pinState = !digitalRead(pin);
long timeOn = millis() - previousMillis;

if (timeOn < 40) return;

if (!pinState && inputCount > 0 && timeOn > 500) {
uint32_t mask = 0;
if (inputStream[0] > 0) mask |= (inputStream[0] < 150 ? 1 : 2) << 0; // 1 2
if (inputStream[1] > 0) mask |= (inputStream[1] < 150 ? 1 : 2) << 2; // 4 8
if (inputStream[2] > 0) mask |= (inputStream[2] < 150 ? 1 : 2) << 4; // 16 32
if (inputStream[3] > 0) mask |= (inputStream[3] < 150 ? 1 : 2) << 6; // 64 128

uint8_t val;
switch (mask) {
case 9: val = 1; break; // A: .-
case 86: val = 2; break; // B: -...
case 102: val = 3; break; // C: -.-.
case 22: val = 4; break; // D: -..
case 1: val = 5; break; // E: .
case 101: val = 6; break; // F: ..-.
case 26: val = 7; break; // G: --.
case 85: val = 8; break; // H: ....
case 5: val = 9; break; // I: ..
case 169: val = 10; break; // J: .---
case 38: val = 11; break; // K: -.-
case 89: val = 12; break; // L: .-..
case 10: val = 13; break; // M: --
case 6: val = 14; break; // N: -.
case 42: val = 15; break; // O: ---
case 105: val = 16; break; // P: .--.
case 154: val = 17; break; // Q: --.-
case 25: val = 18; break; // R: .-.
case 21: val = 19; break; // S: ...
case 2: val = 20; break; // T: -
case 37: val = 21; break; // U: ..-
case 149: val = 22; break; // V: ...-
case 41: val = 23; break; // W: .--
case 150: val = 24; break; // X: -..-
case 166: val = 25; break; // Y: -.--
case 90: val = 26; break; // Z: --..
default: val = 0; break;
}

if (val == 20) {
// T (long press) is used to advance menu, to keep it similar to default menu navigation
WriteEEPROM(currentMenu, currentValue[currentMenu]);
currentMenu = (currentMenu + 1) % menuCount;
} else if (currentMenu > 0) {
// When in the menu
switch (val) {
case 5:
// E (short press) is used to advance selection in non-face menu, to keep it similar to default menu navigation
val = currentValue[currentMenu] + 1;
if (maxValue[currentMenu] > 0) val = val % maxValue[currentMenu];
currentValue[currentMenu] = val;
break;
case 9:
// I (2 short presses) is used to go back a selection in non-face menu
val = currentValue[currentMenu] - 1;
if (maxValue[currentMenu] < 0) val += maxValue[currentMenu];
currentValue[currentMenu] = val;
break;
case 13:
// M (2 long presses) is used to go back a menu
WriteEEPROM(currentMenu, currentValue[currentMenu]);
currentMenu = (currentMenu - 1) % menuCount;
break;
case 15:
// O (3 long presses) is used to exit the menu
WriteEEPROM(currentMenu, currentValue[currentMenu]);
currentMenu = 0;
break;
}
} else {
if (maxValue[currentMenu] > 0) val = val % maxValue[currentMenu]; // If max is set, wrap value
currentValue[currentMenu] = val;
}

std::fill_n(inputStream, inputCount, 0);
inputCount = 0;
previousState = false;
return;
}

if (pinState == previousState) return;

if (!pinState) {
inputStream[inputCount] = timeOn;
inputCount += 1;
}

previousMillis = millis();
previousState = pinState;
}

template <uint8_t menuCount>
uint8_t MenuHandler<menuCount>::ReadEEPROM(uint16_t index) {
return EEPROM.read(index);
}

template <uint8_t menuCount>
void MenuHandler<menuCount>::WriteEEPROM(uint16_t index, uint8_t value) {
EEPROM.write(index, value);
}

template <uint8_t menuCount>
bool MenuHandler<menuCount>::Initialize(uint8_t pin, uint16_t _holdingTime) {
MenuHandler::pin = pin;
MenuHandler::previousState = false;

pinMode(pin, INPUT_PULLUP);

for (uint8_t i = 0; i < menuCount; i++) {
currentValue[i] = ReadEEPROM(i);
}

return ReadEEPROM(menuCount + 1) != 255;
}

template <uint8_t menuCount>
void MenuHandler<menuCount>::SetDefaultValue(uint16_t menu, uint8_t value) {
if (menu >= menuCount) return;

currentValue[menu] = value;

WriteEEPROM(menu, value);
}

template <uint8_t menuCount>
void MenuHandler<menuCount>::SetInitialized() {
WriteEEPROM(menuCount + 1, 0);
}

template <uint8_t menuCount>
void MenuHandler<menuCount>::SetMenuMax(uint8_t menu, uint8_t maxValue) {
if (menu >= menuCount) return;

MenuHandler::maxValue[menu] = maxValue;
}

template <uint8_t menuCount>
uint8_t MenuHandler<menuCount>::GetMenuValue(uint8_t menu) {
return currentValue[menu];
}

template <uint8_t menuCount>
uint8_t MenuHandler<menuCount>::GetCurrentMenu() {
return currentMenu;
}

0 comments on commit 9b7d1bc

Please sign in to comment.