AwesomeStudioPedal
A programmable, multi-profile foot controller for DAWs, score readers, and studio automation
Loading...
Searching...
No Matches
main.cpp
Go to the documentation of this file.
1#include <Arduino.h>
2#ifdef ESP32
3#include <Preferences.h>
4#endif
5#include <memory>
6// #include "freertos/FreeRTOS.h"
7// #include "freertos/task.h"
8// #include "FunctionalInterrupt.h"
9
10#include "ble_keyboard_adapter.h"
11#include "platform.h"
12
13#include "button.h"
14#include "button_constants.h"
15#include "config.h"
16#include "config_loader.h"
17#include "delayed_action.h"
18#include "event_dispatcher.h"
19#include "led_controller.h"
20#include "pedal_config.h"
21#include "profile_manager.h"
22#include "send_action.h"
23
33
34#ifdef ESP32
35static constexpr const char* NVS_NAMESPACE = "pedal";
36static constexpr const char* NVS_KEY_PROFILE = "profile";
37
38static void saveCurrentProfile(uint8_t index)
39{
40 Preferences prefs;
41 prefs.begin(NVS_NAMESPACE, false);
42 prefs.putUChar(NVS_KEY_PROFILE, index);
43 prefs.end();
44}
45
46static uint8_t loadSavedProfile()
47{
48 Preferences prefs;
49 prefs.begin(NVS_NAMESPACE, true);
50 uint8_t index = prefs.getUChar(NVS_KEY_PROFILE, 0);
51 prefs.end();
52 return index;
53}
54#else
55// Profile persistence not yet implemented for this platform
56static void saveCurrentProfile(uint8_t) {}
57static uint8_t loadSavedProfile() { return 0; }
58#endif
59
60bool connected = false;
61
64
65// Profile-select LEDs — one entry per hardwareConfig.numSelectLeds
67std::vector<ILEDController*> selectLeds;
68
69// Action buttons — one entry per hardwareConfig.numButtons
71
74
80{
81 Serial.println("CONFIG ERROR: falling back to factory default");
82 constexpr int BLINK_COUNT = 5;
83 constexpr int BLINK_DURATION = 100;
84 for (int i = 0; i < BLINK_COUNT; i++)
85 {
86 ledPower.setState(true);
88 for (auto* led : selectLeds)
89 led->setState(true);
90 delay(BLINK_DURATION);
91 ledPower.setState(false);
93 for (auto* led : selectLeds)
94 led->setState(false);
95 delay(BLINK_DURATION);
96 }
97 ledPower.setState(true);
99}
100
101void attachInterrupts();
102
103void IRAM_ATTR isr_buttons(uint8_t index)
104{
105 if (actionButtonObjects[index])
106 actionButtonObjects[index]->isr();
107}
108
110
111// Individual ISR stubs for up to 26 buttons — only used entries are attached
138
140
141using IsrFunc = void (*)();
142static const IsrFunc BTN_ISRS[Btn::MAX] = {
147};
148
153{
154 ledPower.setup(1);
156
157 for (uint8_t i = 0; i < hardwareConfig.numSelectLeds; i++)
158 {
160 selectLedObjects[i]->setup(i == 0 ? 1 : 0);
161 selectLeds.push_back(selectLedObjects[i]);
162 }
163
164 for (uint8_t i = 0; i < hardwareConfig.numButtons; i++)
165 {
168 }
169
171}
172
176void executeActionWithLogging(uint8_t buttonIndex)
177{
178 char btnLabel[2];
179 Btn::name(buttonIndex, btnLabel);
180
181 uint8_t profileIndex = profileManager->getCurrentProfile();
182 const char* profileName = profileManager->getProfileName(profileIndex).c_str();
183 Serial.printf("Button %s pressed (Profile: %s)\n", btnLabel, profileName);
184
185 if (auto action = profileManager->getAction(profileIndex, buttonIndex))
186 {
187 if (action->isInProgress())
188 {
189 Serial.println(" -> DelayedAction in progress, ignoring");
190 return;
191 }
192
193 const char* actionType = ProfileManager::getActionTypeString(action->getType());
194 if (action->hasName())
195 {
196 Serial.printf(" -> Executing %s action [%s]\n", actionType, action->getName().c_str());
197 }
198 else
199 {
200 Serial.printf(" -> Executing %s action\n", actionType);
201 }
202 action->execute();
203 }
204 else
205 {
206 Serial.println(" -> no action configured");
207 }
208}
209
214{
215 for (uint8_t i = 0; i < hardwareConfig.numButtons; i++)
216 {
217 uint8_t idx = i; // capture by value
219 }
220
221 // SELECT button is registered at index numButtons
222 uint8_t selectHandlerIdx = hardwareConfig.numButtons;
223 eventDispatcher.registerHandler(selectHandlerIdx,
224 []()
225 {
226 uint8_t profile = profileManager->switchProfile();
227 Serial.printf("Switched to Profile %d\n", profile + 1);
228 saveCurrentProfile(profile);
229 });
230}
231
235void setup()
236{
237 Serial.begin(115200);
238 delay(2000);
239 Serial.println("started");
240
242
245
247
249 {
251 }
252
253 // Restore last-used profile from NVS
254 uint8_t savedProfile = loadSavedProfile();
255 if (savedProfile != profileManager->getCurrentProfile() &&
256 profileManager->getProfile(savedProfile) != nullptr)
257 {
258 profileManager->setCurrentProfile(savedProfile);
259 Serial.printf("Restored profile %d from NVS\n", savedProfile + 1);
260 }
261
263}
264
269{
270 for (uint8_t i = 0; i < hardwareConfig.numButtons; i++)
271 {
273 attachInterrupt(hardwareConfig.buttonPins[i], BTN_ISRS[i], CHANGE);
274 }
276 attachInterrupt(hardwareConfig.buttonSelect, isr_select, CHANGE);
277}
278
283{
284 for (uint8_t i = 0; i < hardwareConfig.numButtons; i++)
285 {
287 detachInterrupt(hardwareConfig.buttonPins[i]);
288 }
290 detachInterrupt(hardwareConfig.buttonSelect);
291}
292
297{
298 for (uint8_t i = 0; i < hardwareConfig.numButtons; i++)
299 {
300 if (actionButtonObjects[i] && actionButtonObjects[i]->event())
301 {
303 }
304 }
305
306 if (BUTTON_SELECT.event())
307 {
309 }
310}
311
315void loop()
316{
318 {
319 if (! connected)
320 {
321 Serial.println("connected");
324 connected = true;
325 }
326 }
327 else
328 {
329 if (connected)
330 {
331 Serial.println("disconnected");
332 connected = false;
335 }
336 }
338
339 uint32_t now = millis();
340 ledPower.update(now);
341 ledBluetooth.update(now);
342 for (auto* led : selectLeds)
343 led->update(now);
344
346
348 {
349 if (! ledPower.isBlinking())
350 {
351 ledPower.startBlink(500);
352 }
353 }
354 else
355 {
356 if (ledPower.isBlinking())
357 {
359 ledPower.setState(true);
360 }
361 }
362
363 delay(10);
364}
Adapter that implements IBleKeyboard interface using BleKeyboard.
void begin() override
Initializes the BLE keyboard.
bool isConnected() override
Checks if BLE keyboard is connected.
ESP32 interrupt-driven button with debouncing.
void setup() override
Configures the GPIO pin as input with pull-up.
void isr()
ISR entry point — call from an IRAM_ATTR interrupt handler.
void reset() override
Clears the pressed flag.
bool event() override
Checks for a press event and clears the flag.
Manages event callbacks for button presses.
void dispatch(uint8_t button)
Executes the callback for the specified button.
void registerHandler(uint8_t button, EventCallback callback)
Registers a callback function for a button.
ESP32-specific implementation of ILEDController.
bool isBlinking() const override
Returns true if a blink sequence is currently running.
void setup(uint32_t initialState=0) override
void update(uint32_t now) override
Drive timed behaviour — must be called every loop iteration.
void setState(bool state) override
void startBlink(uint32_t intervalMs, int16_t count=-1) override
Start a blink sequence.
void stopBlink() override
Stop any running blink and restore the pre-blink state.
Manages up to MAX_PROFILES profiles with LED feedback.
bool hasActiveDelayedAction() const
Returns true if any DelayedAction across all profiles is currently running.
const std::string & getProfileName(uint8_t profileIndex) const
const Profile * getProfile(uint8_t profileIndex) const
Action * getAction(uint8_t profileIndex, uint8_t button) const
uint8_t getCurrentProfile() const
static const char * getActionTypeString(Action::Type actionType)
static constexpr uint8_t MAX_SELECT_LEDS
void setCurrentProfile(uint8_t profileIndex)
Directly set the current profile without triggering blink feedback.
void update(uint32_t now)
Drive timed LED behaviour — call every loop iteration.
uint8_t switchProfile()
Advance to the next populated profile slot and trigger blink feedback.
const HardwareConfig hardwareConfig
Global hardware configuration instance.
BleKeyboardAdapter * createBleKeyboardAdapter()
Creates the platform-specific BleKeyboardAdapter instance.
void IRAM_ATTR isr_btn16()
Definition main.cpp:128
void IRAM_ATTR isr_btn6()
Definition main.cpp:118
void IRAM_ATTR isr_btn7()
Definition main.cpp:119
void IRAM_ATTR isr_btn13()
Definition main.cpp:125
void IRAM_ATTR isr_btn10()
Definition main.cpp:122
void process_events()
Processes button events and dispatches them to handlers.
Definition main.cpp:296
void IRAM_ATTR isr_btn4()
Definition main.cpp:116
std::vector< ILEDController * > selectLeds
Definition main.cpp:67
void IRAM_ATTR isr_btn17()
Definition main.cpp:129
void signalLoadError()
Signal a configuration load error by blinking all LEDs, then fall back to the hardcoded factory defau...
Definition main.cpp:79
void IRAM_ATTR isr_btn24()
Definition main.cpp:136
void IRAM_ATTR isr_buttons(uint8_t index)
Definition main.cpp:103
void IRAM_ATTR isr_btn1()
Definition main.cpp:113
void IRAM_ATTR isr_btn11()
Definition main.cpp:123
void IRAM_ATTR isr_btn25()
Definition main.cpp:137
void IRAM_ATTR isr_btn3()
Definition main.cpp:115
void setup()
Arduino setup function - runs once at startup.
Definition main.cpp:235
void IRAM_ATTR isr_btn9()
Definition main.cpp:121
LEDController ledPower(hardwareConfig.ledPower)
void detachInterrupts()
Detaches interrupt handlers from all buttons.
Definition main.cpp:282
void(*)() IsrFunc
Definition main.cpp:141
Button * actionButtonObjects[Btn::MAX]
Definition main.cpp:70
BleKeyboardAdapter * bleKeyboardAdapter
Definition main.cpp:32
void IRAM_ATTR isr_btn23()
Definition main.cpp:135
void executeActionWithLogging(uint8_t buttonIndex)
Executes an action with proper logging.
Definition main.cpp:176
Button BUTTON_SELECT(hardwareConfig.buttonSelect)
LEDController ledBluetooth(hardwareConfig.ledBluetooth)
EventDispatcher eventDispatcher
Definition main.cpp:73
void IRAM_ATTR isr_btn12()
Definition main.cpp:124
void IRAM_ATTR isr_btn14()
Definition main.cpp:126
void IRAM_ATTR isr_btn18()
Definition main.cpp:130
void IRAM_ATTR isr_btn22()
Definition main.cpp:134
ProfileManager * profileManager
Definition main.cpp:72
bool connected
Definition main.cpp:60
void setup_hardware()
Initializes all hardware components.
Definition main.cpp:152
void setup_event_handlers()
Configures event handlers for all buttons.
Definition main.cpp:213
void IRAM_ATTR isr_btn0()
Definition main.cpp:112
void IRAM_ATTR isr_btn15()
Definition main.cpp:127
void IRAM_ATTR isr_btn8()
Definition main.cpp:120
void attachInterrupts()
Attaches interrupt handlers to all buttons.
Definition main.cpp:268
void IRAM_ATTR isr_btn19()
Definition main.cpp:131
void IRAM_ATTR isr_btn5()
Definition main.cpp:117
LEDController * selectLedObjects[ProfileManager::MAX_SELECT_LEDS]
Definition main.cpp:66
void IRAM_ATTR isr_select()
Definition main.cpp:139
void IRAM_ATTR isr_btn21()
Definition main.cpp:133
void IRAM_ATTR isr_btn20()
Definition main.cpp:132
void loop()
Arduino main loop - runs repeatedly.
Definition main.cpp:315
void IRAM_ATTR isr_btn2()
Definition main.cpp:114
void name(uint8_t index, char *buf)
Write the letter name for a button index into buf.
bool configureProfiles(ProfileManager &profileManager, IBleKeyboard *keyboard)
Loads pedal profiles from file, falling back to DEFAULT_CONFIG on failure.
Portability shims for platform-specific compiler attributes.
#define IRAM_ATTR
IRAM_ATTR places a function in IRAM on the ESP32, enabling fast execution from interrupt context.
Definition platform.h:16
uint8_t numSelectLeds
Profile-select LEDs wired; caps profiles at 2^n − 1.
Definition config.h:20
uint8_t buttonPins[26]
Action button pins: index 0 = A, 1 = B, ..., 25 = Z.
Definition config.h:30
uint8_t ledSelect[6]
Profile-select LED pins (up to 6)
Definition config.h:26
uint8_t ledBluetooth
Bluetooth status LED pin.
Definition config.h:24
uint8_t ledPower
Power indicator LED pin.
Definition config.h:25
uint8_t numButtons
Action buttons wired (1..26, A–Z)
Definition config.h:21
uint8_t buttonSelect
Profile-cycle button pin.
Definition config.h:29