Skip to content

Commit a3bea08

Browse files
authored
feat(esp-box): Add interrupts for mute and boot buttons (#398)
* feat(esp-box): Add interrupts for mute and boot buttons * Update esp-box to have optional registration of interrupt callbacks for mute and boot buttons * Update esp-box to check sound initialized before dealing with sound functions * Update qtpy to only register button interrupt if not already registered Fleshes out more of the hardware functionality in esp-box; ensures the API cannot be misued and handles cases where mute button is initialized but sound is not. * add missing character
1 parent 10f450a commit a3bea08

File tree

4 files changed

+121
-3
lines changed

4 files changed

+121
-3
lines changed

components/esp-box/include/esp-box.hpp

+60-1
Original file line numberDiff line numberDiff line change
@@ -34,15 +34,19 @@ namespace espp {
3434
/// - Display
3535
/// - Audio
3636
/// - Interrupts
37+
/// - Buttons (boot and mute)
3738
/// - I2C
38-
/// - IMU (Inertial Measurement Unit)
39+
/// - IMU (Inertial Measurement Unit), 6-axis ICM42607
3940
///
4041
/// The class is a singleton and can be accessed using the get() method.
4142
///
4243
/// \section esp_box_example Example
4344
/// \snippet esp_box_example.cpp esp box example
4445
class EspBox : public BaseComponent {
4546
public:
47+
/// Alias for the button callback function
48+
using button_callback_t = espp::Interrupt::event_callback_fn;
49+
4650
/// Alias for the pixel type used by the ESP-Box display
4751
using Pixel = lv_color16_t;
4852

@@ -233,6 +237,28 @@ class EspBox : public BaseComponent {
233237
/// if there is an ongoing SPI transaction
234238
void write_lcd_lines(int xs, int ys, int xe, int ye, const uint8_t *data, uint32_t user_data);
235239

240+
/////////////////////////////////////////////////////////////////////////////
241+
// Button
242+
/////////////////////////////////////////////////////////////////////////////
243+
244+
/// Initialize the boot button (side of the box)
245+
/// \param callback The callback function to call when the button is pressed
246+
/// \return true if the button was successfully initialized, false otherwise
247+
bool initialize_boot_button(const button_callback_t &callback = nullptr);
248+
249+
/// Get the boot button state
250+
/// \return The button state (true = button pressed, false = button released)
251+
bool boot_button_state() const;
252+
253+
/// Initialize the mute button (top of the box)
254+
/// \param callback The callback function to call when the button is pressed
255+
/// \return true if the button was successfully initialized, false otherwise
256+
bool initialize_mute_button(const button_callback_t &callback = nullptr);
257+
258+
/// Get the mute button state
259+
/// \return The button state (true = button pressed, false = button released)
260+
bool mute_button_state() const;
261+
236262
/////////////////////////////////////////////////////////////////////////////
237263
// Audio
238264
/////////////////////////////////////////////////////////////////////////////
@@ -351,6 +377,9 @@ class EspBox : public BaseComponent {
351377
bool touch_interrupt_pullup_enabled;
352378

353379
// common:
380+
// button (boot button)
381+
static constexpr gpio_num_t boot_button_io = GPIO_NUM_0; // active low
382+
354383
// internal i2c (touchscreen, audio codec)
355384
static constexpr auto internal_i2c_port = I2C_NUM_0;
356385
static constexpr auto internal_i2c_clock_speed = 400 * 1000;
@@ -408,6 +437,29 @@ class EspBox : public BaseComponent {
408437
.sda_pullup_en = GPIO_PULLUP_ENABLE,
409438
.scl_pullup_en = GPIO_PULLUP_ENABLE}};
410439

440+
espp::Interrupt::PinConfig boot_button_interrupt_pin_{
441+
.gpio_num = boot_button_io,
442+
.callback =
443+
[this](const auto &event) {
444+
if (boot_button_callback_) {
445+
boot_button_callback_(event);
446+
}
447+
},
448+
.active_level = espp::Interrupt::ActiveLevel::LOW,
449+
.interrupt_type = espp::Interrupt::Type::ANY_EDGE,
450+
.pullup_enabled = true};
451+
espp::Interrupt::PinConfig mute_button_interrupt_pin_{
452+
.gpio_num = mute_pin,
453+
.callback =
454+
[this](const auto &event) {
455+
mute(event.active);
456+
if (mute_button_callback_) {
457+
mute_button_callback_(event);
458+
}
459+
},
460+
.active_level = espp::Interrupt::ActiveLevel::LOW,
461+
.interrupt_type = espp::Interrupt::Type::ANY_EDGE,
462+
.pullup_enabled = true};
411463
// NOTE: the active level, interrupt type, and pullup configuration is set by
412464
// detect(), since it depends on the box type
413465
espp::Interrupt::PinConfig touch_interrupt_pin_{
@@ -430,6 +482,12 @@ class EspBox : public BaseComponent {
430482
.task_config = {.name = "esp-box interrupts",
431483
.stack_size_bytes = CONFIG_ESP_BOX_INTERRUPT_STACK_SIZE}}};
432484

485+
// button
486+
std::atomic<bool> boot_button_initialized_{false};
487+
button_callback_t boot_button_callback_{nullptr};
488+
std::atomic<bool> mute_button_initialized_{false};
489+
button_callback_t mute_button_callback_{nullptr};
490+
433491
// touch
434492
std::shared_ptr<Gt911> gt911_; // only used on ESP32-S3-BOX-3
435493
std::shared_ptr<Tt21100> tt21100_; // only used on ESP32-S3-BOX
@@ -451,6 +509,7 @@ class EspBox : public BaseComponent {
451509
uint8_t *frame_buffer1_{nullptr};
452510

453511
// sound
512+
std::atomic<bool> sound_initialized_{false};
454513
std::atomic<float> volume_{50.0f};
455514
std::atomic<bool> mute_{false};
456515
std::unique_ptr<espp::Task> audio_task_{nullptr};

components/esp-box/src/audio.cpp

+9-1
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,10 @@ bool EspBox::initialize_i2s(uint32_t default_audio_rate) {
111111

112112
bool EspBox::initialize_sound(uint32_t default_audio_rate,
113113
const espp::Task::BaseConfig &task_config) {
114-
114+
if (sound_initialized_) {
115+
logger_.warn("Sound already initialized");
116+
return true;
117+
}
115118
if (!initialize_i2s(default_audio_rate)) {
116119
logger_.error("Could not initialize I2S driver");
117120
return false;
@@ -131,6 +134,8 @@ bool EspBox::initialize_sound(uint32_t default_audio_rate,
131134
.task_config = task_config,
132135
});
133136

137+
sound_initialized_ = true;
138+
134139
return audio_task_->start();
135140
}
136141

@@ -154,6 +159,9 @@ bool EspBox::audio_task_callback(std::mutex &m, std::condition_variable &cv, boo
154159
}
155160

156161
void EspBox::update_volume_output() {
162+
if (!sound_initialized_) {
163+
return;
164+
}
157165
if (mute_) {
158166
es8311_codec_set_voice_volume(0);
159167
} else {

components/esp-box/src/buttons.cpp

+49
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
#include "esp-box.hpp"
2+
3+
using namespace espp;
4+
5+
////////////////////////
6+
// Button Functions //
7+
////////////////////////
8+
9+
bool EspBox::initialize_boot_button(const EspBox::button_callback_t &callback) {
10+
logger_.info("Initializing boot button");
11+
12+
// save the callback
13+
boot_button_callback_ = callback;
14+
15+
// configure the button
16+
if (!boot_button_initialized_) {
17+
interrupts_.add_interrupt(boot_button_interrupt_pin_);
18+
}
19+
boot_button_initialized_ = true;
20+
return true;
21+
}
22+
23+
bool EspBox::boot_button_state() const {
24+
if (!boot_button_initialized_) {
25+
return false;
26+
}
27+
return interrupts_.is_active(boot_button_interrupt_pin_);
28+
}
29+
30+
bool EspBox::initialize_mute_button(const EspBox::button_callback_t &callback) {
31+
logger_.info("Initializing mute button");
32+
33+
// save the callback
34+
mute_button_callback_ = callback;
35+
36+
// configure the button
37+
if (!mute_button_initialized_) {
38+
interrupts_.add_interrupt(mute_button_interrupt_pin_);
39+
}
40+
mute_button_initialized_ = true;
41+
return true;
42+
}
43+
44+
bool EspBox::mute_button_state() const {
45+
if (!mute_button_initialized_) {
46+
return false;
47+
}
48+
return interrupts_.is_active(mute_button_interrupt_pin_);
49+
}

components/qtpy/src/qtpy.cpp

+3-1
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,9 @@ bool QtPy::initialize_button(const QtPy::button_callback_t &callback) {
2020
button_callback_ = callback;
2121

2222
// configure the button
23-
interrupts_.add_interrupt(button_interrupt_pin_);
23+
if (!button_initialized_) {
24+
interrupts_.add_interrupt(button_interrupt_pin_);
25+
}
2426
button_initialized_ = true;
2527
return true;
2628
}

0 commit comments

Comments
 (0)