Properly handle TCA8418 interrupts in sleep mode

This commit is contained in:
WillyJL 2025-09-24 03:06:36 +02:00
parent 696a391cb8
commit a37133214f
No known key found for this signature in database
3 changed files with 67 additions and 8 deletions

View File

@ -2,6 +2,7 @@
#include "TCA8418KeyboardBase.h"
#include "configuration.h"
#include "sleep.h"
#include <Arduino.h>
@ -44,14 +45,18 @@ void TCA8418KeyboardBase::begin(uint8_t addr, TwoWire *wire)
reset();
#ifdef KB_INT
interruptInstance = this;
auto interruptHandler = []() { interruptInstance->notifyObservers(interruptInstance); };
::pinMode(KB_INT, INPUT_PULLUP);
attachInterrupt(KB_INT, interruptHandler, FALLING);
attachInterruptHandler();
enableInterrupts();
#endif
#ifdef ARCH_ESP32
// Register callbacks for before and after lightsleep
// Used to detach and reattach interrupts
lsObserver.observe(&notifyLightSleep);
lsEndObserver.observe(&notifyLightSleepEnd);
#endif // ARCH_ESP32
#endif // KB_INT
}
void TCA8418KeyboardBase::begin(i2c_com_fptr_t r, i2c_com_fptr_t w, uint8_t addr)
@ -93,6 +98,41 @@ void TCA8418KeyboardBase::reset()
flush();
}
#ifdef KB_INT
void TCA8418KeyboardBase::attachInterruptHandler()
{
interruptInstance = this;
auto interruptHandler = []() { interruptInstance->notifyObservers(interruptInstance); };
attachInterrupt(KB_INT, interruptHandler, FALLING);
}
void TCA8418KeyboardBase::detachInterruptHandler()
{
detachInterrupt(KB_INT);
interruptInstance = nullptr;
}
#ifdef ARCH_ESP32
// Detach our class' interrupts before lightsleep
// Allows sleep.cpp to configure its own interrupts, which wake the device on user-button press
int TCA8418KeyboardBase::beforeLightSleep(void *unused)
{
detachInterruptHandler();
return 0; // Indicates success
}
// Reconfigure our interrupts
// Our class' interrupts were disconnected during sleep, to allow the user button to wake the device from sleep
int TCA8418KeyboardBase::afterLightSleep(esp_sleep_wakeup_cause_t cause)
{
attachInterruptHandler();
this->notifyObservers(this); // Trigger a one-off poll in case a keypress woke us
return 0; // Indicates success
}
#endif // ARCH_ESP32
#endif // KB_INT
bool TCA8418KeyboardBase::matrix(uint8_t rows, uint8_t columns)
{
if (rows < 1 || rows > 8 || columns < 1 || columns > 10)
@ -169,7 +209,7 @@ void TCA8418KeyboardBase::trigger()
#ifdef KB_INT
// Reset interrupt mask so we can receive future interrupts
writeRegister(TCA8418_REG_INT_STAT, 3);
clearInt();
#endif
}

View File

@ -163,9 +163,29 @@ class TCA8418KeyboardBase : public KbInterruptObservable
uint8_t columns;
String queue;
#ifdef KB_INT
void attachInterruptHandler();
void detachInterruptHandler();
#ifdef ARCH_ESP32
// Disconnect and reconnect interrupts for light sleep
int beforeLightSleep(void *unused);
int afterLightSleep(esp_sleep_wakeup_cause_t cause);
#endif // ARCH_ESP32
#endif // KB_INT
private:
TwoWire *m_wire;
uint8_t m_addr;
i2c_com_fptr_t readCallback;
i2c_com_fptr_t writeCallback;
#if defined(KB_INT) && defined(ARCH_ESP32)
// Get notified when lightsleep begins and ends
CallbackObserver<TCA8418KeyboardBase, void *> lsObserver =
CallbackObserver<TCA8418KeyboardBase, void *>(this, &TCA8418KeyboardBase::beforeLightSleep);
CallbackObserver<TCA8418KeyboardBase, esp_sleep_wakeup_cause_t> lsEndObserver =
CallbackObserver<TCA8418KeyboardBase, esp_sleep_wakeup_cause_t>(this, &TCA8418KeyboardBase::afterLightSleep);
#endif
};

View File

@ -441,7 +441,6 @@ int32_t KbI2cBase::runOnce()
this->notifyObservers(&e);
}
}
TCAKeyboard.clearInt();
#endif
break;
}