TCA8418: Interrupt based notify of new key events

This commit is contained in:
WillyJL 2025-09-13 04:04:40 +02:00
parent 4816f45552
commit 63468df93f
No known key found for this signature in database
5 changed files with 54 additions and 4 deletions

View File

@ -43,6 +43,18 @@ void TCA8418KeyboardBase::begin(uint8_t addr, TwoWire *wire)
m_wire = wire; m_wire = wire;
m_wire->begin(); m_wire->begin();
reset(); reset();
#ifdef KB_INT
interruptInstance = this;
auto interruptHandler = []() {
interruptInstance->notifyObservers(interruptInstance);
};
::pinMode(KB_INT, INPUT_PULLUP);
attachInterrupt(KB_INT, interruptHandler, FALLING);
enableInterrupts();
#endif
} }
void TCA8418KeyboardBase::begin(i2c_com_fptr_t r, i2c_com_fptr_t w, uint8_t addr) void TCA8418KeyboardBase::begin(i2c_com_fptr_t r, i2c_com_fptr_t w, uint8_t addr)
@ -157,6 +169,11 @@ void TCA8418KeyboardBase::trigger()
released(key); released(key);
} }
} }
#ifdef KB_INT
// Reset interrupt mask so we can receive future interrupts
writeRegister(TCA8418_REG_INT_STAT, 3);
#endif
} }
void TCA8418KeyboardBase::pressed(uint8_t key) void TCA8418KeyboardBase::pressed(uint8_t key)
@ -292,6 +309,8 @@ void TCA8418KeyboardBase::disableInterrupts()
writeRegister(TCA8418_REG_CFG, value); writeRegister(TCA8418_REG_CFG, value);
}; };
TCA8418KeyboardBase* TCA8418KeyboardBase::interruptInstance;
void TCA8418KeyboardBase::enableMatrixOverflow() void TCA8418KeyboardBase::enableMatrixOverflow()
{ {
uint8_t value = readRegister(TCA8418_REG_CFG); uint8_t value = readRegister(TCA8418_REG_CFG);

View File

@ -1,6 +1,7 @@
// Based on the MPR121 Keyboard and Adafruit TCA8418 library // Based on the MPR121 Keyboard and Adafruit TCA8418 library
#include "configuration.h" #include "configuration.h"
#include <Wire.h> #include <Wire.h>
#include "kbInterrupt.h"
/** /**
* @brief TCA8418KeyboardBase is the base class for TCA8418 keyboard handling. * @brief TCA8418KeyboardBase is the base class for TCA8418 keyboard handling.
@ -8,7 +9,7 @@
* and handling key states. It is designed to be extended for specific keyboard implementations. * and handling key states. It is designed to be extended for specific keyboard implementations.
* It supports both I2C communication and function pointers for custom I2C operations. * It supports both I2C communication and function pointers for custom I2C operations.
*/ */
class TCA8418KeyboardBase class TCA8418KeyboardBase : public KbInterruptObservable
{ {
public: public:
enum TCA8418Key : uint8_t { enum TCA8418Key : uint8_t {
@ -142,6 +143,7 @@ class TCA8418KeyboardBase
// enable / disable interrupts for matrix and GPI pins // enable / disable interrupts for matrix and GPI pins
void enableInterrupts(); void enableInterrupts();
void disableInterrupts(); void disableInterrupts();
static TCA8418KeyboardBase* interruptInstance;
// ignore key events when FIFO buffer is full or not. // ignore key events when FIFO buffer is full or not.
void enableMatrixOverflow(); void enableMatrixOverflow();

View File

@ -46,6 +46,7 @@ uint8_t read_from_14004(TwoWire *i2cBus, uint8_t reg, uint8_t *data, uint8_t len
int32_t KbI2cBase::runOnce() int32_t KbI2cBase::runOnce()
{ {
int32_t interval = 300;
if (!i2cBus) { if (!i2cBus) {
switch (cardkb_found.port) { switch (cardkb_found.port) {
case ScanI2C::WIRE1: case ScanI2C::WIRE1:
@ -61,6 +62,7 @@ int32_t KbI2cBase::runOnce()
} }
if (cardkb_found.address == TCA8418_KB_ADDR) { if (cardkb_found.address == TCA8418_KB_ADDR) {
TCAKeyboard.begin(TCA8418_KB_ADDR, &Wire1); TCAKeyboard.begin(TCA8418_KB_ADDR, &Wire1);
observe(&TCAKeyboard);
} }
break; break;
#endif #endif
@ -76,6 +78,7 @@ int32_t KbI2cBase::runOnce()
} }
if (cardkb_found.address == TCA8418_KB_ADDR) { if (cardkb_found.address == TCA8418_KB_ADDR) {
TCAKeyboard.begin(TCA8418_KB_ADDR, &Wire); TCAKeyboard.begin(TCA8418_KB_ADDR, &Wire);
observe(&TCAKeyboard);
} }
break; break;
case ScanI2C::NO_I2C: case ScanI2C::NO_I2C:
@ -249,6 +252,7 @@ int32_t KbI2cBase::runOnce()
break; break;
} }
case 0x84: { // Adafruit TCA8418 case 0x84: { // Adafruit TCA8418
interval = 3000; // Less polling, we have interrupts with onNotify()
TCAKeyboard.trigger(); TCAKeyboard.trigger();
InputEvent e; InputEvent e;
while (TCAKeyboard.hasEvent()) { while (TCAKeyboard.hasEvent()) {
@ -331,7 +335,6 @@ int32_t KbI2cBase::runOnce()
LOG_DEBUG("TCA8418 Notifying: %i Char: %c", e.inputEvent, e.kbchar); LOG_DEBUG("TCA8418 Notifying: %i Char: %c", e.inputEvent, e.kbchar);
this->notifyObservers(&e); this->notifyObservers(&e);
} }
TCAKeyboard.trigger();
} }
break; break;
} }
@ -518,5 +521,17 @@ int32_t KbI2cBase::runOnce()
default: default:
LOG_WARN("Unknown kb_model 0x%02x", kb_model); LOG_WARN("Unknown kb_model 0x%02x", kb_model);
} }
return 300;
// If new interrupt triggered while we were processing the previous, reinvoke with 0 interval right away
if (pendingInterruptCount) pendingInterruptCount--;
if (pendingInterruptCount) return 0;
return interval;
}
int KbI2cBase::onNotify(KbInterruptObservable* src)
{
pendingInterruptCount++;
setInterval(0);
return 0;
} }

View File

@ -5,16 +5,18 @@
#include "MPR121Keyboard.h" #include "MPR121Keyboard.h"
#include "Wire.h" #include "Wire.h"
#include "concurrency/OSThread.h" #include "concurrency/OSThread.h"
#include "kbInterrupt.h"
class TCA8418KeyboardBase; class TCA8418KeyboardBase;
class KbI2cBase : public Observable<const InputEvent *>, public concurrency::OSThread class KbI2cBase : public Observable<const InputEvent *>, public KbInterruptObserver, public concurrency::OSThread
{ {
public: public:
explicit KbI2cBase(const char *name); explicit KbI2cBase(const char *name);
protected: protected:
virtual int32_t runOnce() override; virtual int32_t runOnce() override;
virtual int onNotify(KbInterruptObservable* src) override;
private: private:
const char *_originName; const char *_originName;
@ -24,5 +26,6 @@ class KbI2cBase : public Observable<const InputEvent *>, public concurrency::OST
BBQ10Keyboard Q10keyboard; BBQ10Keyboard Q10keyboard;
MPR121Keyboard MPRkeyboard; MPR121Keyboard MPRkeyboard;
TCA8418KeyboardBase &TCAKeyboard; TCA8418KeyboardBase &TCAKeyboard;
volatile uint8_t pendingInterruptCount = 0;
bool is_sym = false; bool is_sym = false;
}; };

11
src/input/kbInterrupt.h Normal file
View File

@ -0,0 +1,11 @@
#pragma once
#include "Observer.h"
class KbInterruptObservable : public Observable<KbInterruptObservable*>
{
};
class KbInterruptObserver : public Observer<KbInterruptObservable*>
{
};