From 81cbbb64431d6cf362bc0a13a802351433d6b965 Mon Sep 17 00:00:00 2001 From: pschatzmann Date: Sat, 2 Nov 2024 14:57:51 +0100 Subject: [PATCH] Lyrat Mini Button Support --- .../lyrat-mini/buttons/buttons.ino | 51 +++++++++ .../lyrat-mini/mic/mic.ino | 29 +++++ .../output/{outout.ino => output.ino} | 1 + src/AudioTools/AudioLibs/AudioBoardStream.h | 101 ++++++++++++------ src/AudioTools/CoreAudio/AudioActions.h | 100 +++++++++++------ 5 files changed, 217 insertions(+), 65 deletions(-) create mode 100644 examples/examples-custom-boards/lyrat-mini/buttons/buttons.ino create mode 100644 examples/examples-custom-boards/lyrat-mini/mic/mic.ino rename examples/examples-custom-boards/lyrat-mini/output/{outout.ino => output.ino} (97%) diff --git a/examples/examples-custom-boards/lyrat-mini/buttons/buttons.ino b/examples/examples-custom-boards/lyrat-mini/buttons/buttons.ino new file mode 100644 index 000000000..ad3f20739 --- /dev/null +++ b/examples/examples-custom-boards/lyrat-mini/buttons/buttons.ino @@ -0,0 +1,51 @@ + +#include "AudioTools.h" +#include "AudioTools/AudioLibs/AudioBoardStream.h" + +AudioBoardStream lyrat(LyratMini); + +void rec(bool, int, void*) { + Serial.println("rec"); +} + +void mode(bool, int, void*) { + Serial.println("mode"); +} + +void play(bool, int, void*) { + Serial.println("play"); +} + +void set(bool, int, void*) { + Serial.println("set"); +} + +void volUp(bool, int, void*) { + Serial.println("vol+"); +} + +void volDown(bool, int, void*) { + Serial.println("vol-"); +} + + +// Arduino Setup +void setup(void) { + Serial.begin(115200); + AudioToolsLogger.begin(Serial, AudioToolsLogLevel::Warning); + + // start board + lyrat.begin(lyrat.defaultConfig(TX_MODE)); + + lyrat.addAction(KEY_REC, rec); + lyrat.addAction(KEY_MODE, mode); + lyrat.addAction(KEY_PLAY, play); + lyrat.addAction(KEY_SET, set); + lyrat.addAction(KEY_VOLUME_UP, volUp); + lyrat.addAction(KEY_VOLUME_DOWN, volDown); + +} + +void loop() { + lyrat.processActions(); +} diff --git a/examples/examples-custom-boards/lyrat-mini/mic/mic.ino b/examples/examples-custom-boards/lyrat-mini/mic/mic.ino new file mode 100644 index 000000000..d12b787af --- /dev/null +++ b/examples/examples-custom-boards/lyrat-mini/mic/mic.ino @@ -0,0 +1,29 @@ + + +#include "AudioTools.h" +#include "AudioTools/AudioLibs/AudioBoardStream.h" + +AudioInfo info(44100, 1, 16); +AudioBoardStream i2s(LyratMini); // Access I2S as stream +CsvOutput csvStream(Serial); +StreamCopy copier(csvStream, i2s); // copy i2s to csvStream + +// Arduino Setup +void setup(void) { + Serial.begin(115200); + AudioToolsLogger.begin(Serial, AudioToolsLogLevel::Warning); + + auto cfg = i2s.defaultConfig(RX_MODE); + cfg.copyFrom(info); + //cfg.input_device = ADC_INPUT_LINE2; + i2s.begin(cfg); + + // make sure that we have the correct number of channels set up + csvStream.begin(info); + +} + +// Arduino loop - copy data +void loop() { + copier.copy(); +} \ No newline at end of file diff --git a/examples/examples-custom-boards/lyrat-mini/output/outout.ino b/examples/examples-custom-boards/lyrat-mini/output/output.ino similarity index 97% rename from examples/examples-custom-boards/lyrat-mini/output/outout.ino rename to examples/examples-custom-boards/lyrat-mini/output/output.ino index d8feaa215..2eb7e9235 100644 --- a/examples/examples-custom-boards/lyrat-mini/output/outout.ino +++ b/examples/examples-custom-boards/lyrat-mini/output/output.ino @@ -20,6 +20,7 @@ void setup(void) { Serial.println("starting I2S..."); auto config = out.defaultConfig(TX_MODE); config.copyFrom(info); + out.begin(config); // additinal settings out.setVolume(0.5); diff --git a/src/AudioTools/AudioLibs/AudioBoardStream.h b/src/AudioTools/AudioLibs/AudioBoardStream.h index 73be23727..7629a5015 100644 --- a/src/AudioTools/AudioLibs/AudioBoardStream.h +++ b/src/AudioTools/AudioLibs/AudioBoardStream.h @@ -17,7 +17,18 @@ namespace audio_tools { * @copyright GPLv3 */ class AudioBoardStream : public I2SCodecStream { -public: + struct AudioBoardAction : public AudioActions::Action { + AudioBoardAction(AudioBoard &board, AudioDriverKey key) { + this->key = key; + this->p_board = &board; + } + AudioDriverKey key; + AudioBoard *p_board; + int id() override { return key | 0x400; } + bool readValue() override { return p_board->isKeyPressed(key); } + }; + + public: /** * @brief Default constructor: for available AudioBoard values check * the audioboard variables in @@ -44,6 +55,32 @@ class AudioBoardStream : public I2SCodecStream { yield(); } + + /** + * @brief Defines a new action that is executed when the Button is pressed + */ + void addAction(AudioDriverKey key, void (*action)(bool, int, void *), + void *ref = nullptr) { + AudioBoardAction *abo = new AudioBoardAction(board(), key); + abo->actionOn = action; + abo->ref = (ref == nullptr) ? this : ref; + actions.add(*abo); + } + + /** + * @brief Defines a new action that is executed when the Button is pressed and released + */ + void addAction(AudioDriverKey key, void (*actionOn)(bool, int, void *), + void (*actionOff)(bool, int, void *), + void *ref = nullptr) { + + AudioBoardAction *abo = new AudioBoardAction(board(), key); + abo->actionOn = actionOn; + abo->actionOn = actionOff; + abo->ref = (ref == nullptr) ? this : ref; + actions.add(*abo); + } + /** * @brief Defines a new action that is executed when the indicated pin is * active @@ -72,12 +109,12 @@ class AudioBoardStream : public I2SCodecStream { void addAction(int pin, void (*action)(bool, int, void *), AudioActions::ActiveLogic activeLogic, void *ref = nullptr) { TRACEI(); - actions.add(pin, action, activeLogic, ref == nullptr ? this : ref); + actions.add(pin, action, activeLogic, ref == nullptr ? this : ref); } /// Provides access to the AudioActions AudioActions &audioActions() { return actions; } - + AudioActions &getActions() { return actions; } /** @@ -98,7 +135,7 @@ class AudioBoardStream : public I2SCodecStream { */ static void actionVolumeUp(bool, int, void *ref) { TRACEI(); - AudioBoardStream *self = (AudioBoardStream*)ref; + AudioBoardStream *self = (AudioBoardStream *)ref; self->incrementVolume(+self->actionVolumeIncrementValue()); } @@ -108,18 +145,17 @@ class AudioBoardStream : public I2SCodecStream { */ static void actionVolumeDown(bool, int, void *ref) { TRACEI(); - AudioBoardStream *self = (AudioBoardStream*)ref; + AudioBoardStream *self = (AudioBoardStream *)ref; self->incrementVolume(-self->actionVolumeIncrementValue()); } - /** * @brief Toggle start stop * */ static void actionStartStop(bool, int, void *ref) { TRACEI(); - AudioBoardStream *self = (AudioBoardStream*)ref; + AudioBoardStream *self = (AudioBoardStream *)ref; self->active = !self->active; self->setActive(self->active); } @@ -130,7 +166,7 @@ class AudioBoardStream : public I2SCodecStream { */ static void actionStart(bool, int, void *ref) { TRACEI(); - AudioBoardStream *self = (AudioBoardStream*)ref; + AudioBoardStream *self = (AudioBoardStream *)ref; self->active = true; self->setActive(self->active); } @@ -140,7 +176,7 @@ class AudioBoardStream : public I2SCodecStream { */ static void actionStop(bool, int, void *ref) { TRACEI(); - AudioBoardStream *self = (AudioBoardStream*)ref; + AudioBoardStream *self = (AudioBoardStream *)ref; self->active = false; self->setActive(self->active); } @@ -151,9 +187,8 @@ class AudioBoardStream : public I2SCodecStream { * This method complies with the */ static void actionHeadphoneDetection(bool, int, void *ref) { - AudioBoardStream *self = (AudioBoardStream*)ref; + AudioBoardStream *self = (AudioBoardStream *)ref; if (self->pinHeadphoneDetect() >= 0) { - // detect changes bool isConnected = self->headphoneStatus(); if (self->headphoneIsConnected != isConnected) { @@ -289,7 +324,7 @@ class AudioBoardStream : public I2SCodecStream { addAction(input_mode, actionStartStop); } } - + /// add volume up and volume down action void addVolumeActions() { // pin conflicts with SD Lyrat SD CS GpioPin and buttons / Conflict on @@ -319,8 +354,9 @@ class AudioBoardStream : public I2SCodecStream { } /** - * @brief Setup the supported default actions (volume, start/stop, headphone detection) - */ + * @brief Setup the supported default actions (volume, start/stop, headphone + * detection) + */ void addDefaultActions() { TRACEI(); addHeadphoneDetectionAction(); @@ -329,15 +365,18 @@ class AudioBoardStream : public I2SCodecStream { } /// Defines the increment value used by actionVolumeDown/actionVolumeUp - void setActionVolumeIncrementValue(float value){ + void setActionVolumeIncrementValue(float value) { action_increment_value = value; } - float actionVolumeIncrementValue() { - return action_increment_value; + float actionVolumeIncrementValue() { return action_increment_value; } + + bool isKeyPressed(int key) { + if (!board()) return false; + return board().isKeyPressed(key); } -protected: + protected: AudioActions actions; bool headphoneIsConnected = false; bool active = true; @@ -346,8 +385,7 @@ class AudioBoardStream : public I2SCodecStream { int getSdCsPin() { static GpioPin sd_cs = -2; // execute only once - if (sd_cs != -2) - return sd_cs; + if (sd_cs != -2) return sd_cs; auto sd_opt = getPins().getSPIPins(PinFunction::SD); if (sd_opt) { @@ -365,20 +403,19 @@ class AudioBoardStream : public I2SCodecStream { AudioActions::ActiveLogic getActionLogic(int pin) { auto opt = board().getPins().getPin(pin); PinLogic logic = PinLogic::Input; - if (opt) - logic = opt.value().pin_logic; + if (opt) logic = opt.value().pin_logic; switch (logic) { - case PinLogic::Input: - case PinLogic::InputActiveLow: - return AudioActions::ActiveLow; - case PinLogic::InputActiveHigh: - return AudioActions::ActiveHigh; - case PinLogic::InputActiveTouch: - return AudioActions::ActiveTouch; - default: - return AudioActions::ActiveLow; + case PinLogic::Input: + case PinLogic::InputActiveLow: + return AudioActions::ActiveLow; + case PinLogic::InputActiveHigh: + return AudioActions::ActiveHigh; + case PinLogic::InputActiveTouch: + return AudioActions::ActiveTouch; + default: + return AudioActions::ActiveLow; } } }; -} // namespace audio_tools +} // namespace audio_tools diff --git a/src/AudioTools/CoreAudio/AudioActions.h b/src/AudioTools/CoreAudio/AudioActions.h index 19163685b..40a342697 100644 --- a/src/AudioTools/CoreAudio/AudioActions.h +++ b/src/AudioTools/CoreAudio/AudioActions.h @@ -41,7 +41,7 @@ class AudioActions { void (*actionOff)(bool pinStatus, int pin, void *ref) = nullptr; void *ref = nullptr; unsigned long debounceTimeout = 0; - ActiveLogic activeLogic; + ActiveLogic activeLogic = ActiveHigh; bool lastState = true; bool enabled = true; @@ -49,7 +49,11 @@ class AudioActions { int debounceDelayValue = DEBOUNCE_DELAY; int touchLimit = TOUCH_LIMIT; - bool readValue() { + virtual int id() { + return pin; + } + + virtual bool readValue() { #ifdef USE_TOUCH_READ bool result; if (this->activeLogic == ActiveTouch) { @@ -71,7 +75,7 @@ class AudioActions { #endif } - void process() { + virtual void process() { if (this->enabled) { bool value = readValue(); if (this->actionOn != nullptr && this->actionOff != nullptr) { @@ -118,6 +122,16 @@ class AudioActions { setUsePinInterrupt(useInterrupt); } + /// deletes all actions + ~AudioActions() { + clear(); + } + + /// Adds an Action + void add(Action &action){ + insertAction(action); + } + /// Adds an action void add(int pin, void (*actionOn)(bool pinStatus, int pin, void *ref), ActiveLogic activeLogic = ActiveLow, void *ref = nullptr) { @@ -133,27 +147,17 @@ class AudioActions { // setup pin mode setupPin(pin, activeLogicPar); - Action *p_action = findAction(pin); - if (p_action) { - // replace value - p_action->actionOn = actionOn; - p_action->actionOff = actionOff; - p_action->activeLogic = activeLogicPar; - p_action->ref = ref; - } else { - // add value - Action action; - action.pin = pin; - action.actionOn = actionOn; - action.actionOff = actionOff; - action.activeLogic = activeLogicPar; - action.ref = ref; - - action.debounceDelayValue = debounceDelayValue; - action.touchLimit = touchLimit; - - actions.push_back(action); - } + // add value + Action& action = *new Action(); + action.pin = pin; + action.actionOn = actionOn; + action.actionOff = actionOff; + action.activeLogic = activeLogicPar; + action.ref = ref; + action.debounceDelayValue = debounceDelayValue; + action.touchLimit = touchLimit; + + insertAction(action); } else { LOGW("pin %d -> Ignored", pin); } @@ -176,7 +180,7 @@ class AudioActions { if (actions.empty()) return; // execute action - actions[pos].process(); + actions[pos]->process(); pos++; if (pos >= actions.size()) { pos = 0; @@ -185,21 +189,33 @@ class AudioActions { /// Execute all actions void processAllActions() { - for (Action &action : actions) { - action.process(); + for (Action *action : actions) { + action->process(); } } - /// Determines the action for the pin - Action *findAction(int pin) { - for (Action &action : actions) { - if (action.pin == pin) { - return &action; + /// Determines the action for the pin/id + Action *findAction(int id) { + for (Action *action : actions) { + if (action->id() == id) { + return action; } } return nullptr; } + /// Determines the action for the pin/id + int findActionIdx(int id) { + int pos = 0; + for (Action *action : actions) { + if (action->id() == id) { + return pos; + } + pos++; + } + return -1; + } + /// Defines the debounce delay void setDebounceDelay(int value) { debounceDelayValue = value; } /// Defines the touch limit (Default 20) @@ -209,13 +225,31 @@ class AudioActions { /// setup pin mode when true void setPinMode(bool active) { use_pin_mode = active; } + void clear() { + for (Action *act : actions){ + delete(act); + } + actions.reset(); + } + protected: int debounceDelayValue = DEBOUNCE_DELAY; int touchLimit = TOUCH_LIMIT; bool use_pin_interrupt = false; bool use_pin_mode = true; + Vector actions{0}; - Vector actions{0}; + void insertAction(Action& action){ + int idx = findActionIdx(action.id()); + if (idx >= 0) { + // replace old action + delete(actions[idx]); + actions[idx] = &action; + } else { + // add new action + actions.push_back(&action); + } + } static void audioActionsISR() { selfAudioActions->processAllActions(); }