mirror of
https://github.com/alexhopeoconnor/firmware.git
synced 2026-10-19 09:51:30 +10:00
Merge branch 'develop' into pioarduino
This commit is contained in:
@@ -276,7 +276,8 @@ int32_t ButtonThread::runOnce()
|
||||
case BUTTON_EVENT_LONG_RELEASED: {
|
||||
|
||||
LOG_INFO("LONG PRESS RELEASE AFTER %u MILLIS", millis() - buttonPressStartTime);
|
||||
if (millis() > 30000 && _longLongPress != INPUT_BROKER_NONE &&
|
||||
// Require press started after boot holdoff to avoid phantom shutdown from floating pins
|
||||
if (millis() > 30000 && buttonPressStartTime > 30000 && _longLongPress != INPUT_BROKER_NONE &&
|
||||
(millis() - buttonPressStartTime) >= _longLongPressTime && leadUpPlayed) {
|
||||
evt.inputEvent = _longLongPress;
|
||||
this->notifyObservers(&evt);
|
||||
|
||||
@@ -20,20 +20,20 @@ constexpr uint8_t modifierLeftShift = 0b0001;
|
||||
|
||||
// Num chars per key, Modulus for rotating through characters
|
||||
static uint8_t HackadayCommunicatorTapMod[_TCA8418_NUM_KEYS] = {
|
||||
0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2,
|
||||
0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2,
|
||||
0, 0, 0, 1, 1, 0, 1, 1, 1, 0, 0, 0, 1, 2, 2, 2, 2, 2, 2, 0, 0, 0, 1, 2, 2, 2, 1, 2, 2, 0, 0, 0, 2, 1, 2, 2, 0, 1, 1, 0,
|
||||
};
|
||||
|
||||
static unsigned char HackadayCommunicatorTapMap[_TCA8418_NUM_KEYS][2] = {{},
|
||||
{},
|
||||
{Key::FUNCTION_F1},
|
||||
{'+'},
|
||||
{'9'},
|
||||
{'8'},
|
||||
{'7'},
|
||||
{'2'},
|
||||
{'3'},
|
||||
{'4'},
|
||||
{'5'},
|
||||
{Key::FUNCTION_F2},
|
||||
{Key::FUNCTION_F3},
|
||||
{Key::FUNCTION_F4},
|
||||
{Key::FUNCTION_F5},
|
||||
{Key::ESC},
|
||||
{'q', 'Q'},
|
||||
{'w', 'W'},
|
||||
@@ -106,8 +106,8 @@ static unsigned char HackadayCommunicatorTapMap[_TCA8418_NUM_KEYS][2] = {{},
|
||||
{}};
|
||||
|
||||
HackadayCommunicatorKeyboard::HackadayCommunicatorKeyboard()
|
||||
: TCA8418KeyboardBase(_TCA8418_ROWS, _TCA8418_COLS), modifierFlag(0), last_modifier_time(0), last_key(-1), next_key(-1),
|
||||
last_tap(0L), char_idx(0), tap_interval(0)
|
||||
: TCA8418KeyboardBase(_TCA8418_ROWS, _TCA8418_COLS), modifierFlag(0), last_modifier_time(0), last_key(UINT8_MAX),
|
||||
next_key(UINT8_MAX), last_tap(0L), char_idx(0), tap_interval(0)
|
||||
{
|
||||
reset();
|
||||
}
|
||||
@@ -141,12 +141,12 @@ void HackadayCommunicatorKeyboard::pressed(uint8_t key)
|
||||
if (state == Init || state == Busy) {
|
||||
return;
|
||||
}
|
||||
LOG_DEBUG("Key pressed: %u", key);
|
||||
|
||||
if (modifierFlag && (millis() - last_modifier_time > _TCA8418_MULTI_TAP_THRESHOLD)) {
|
||||
modifierFlag = 0;
|
||||
}
|
||||
|
||||
uint8_t next_key = 0;
|
||||
int row = (key - 1) / 10;
|
||||
int col = (key - 1) % 10;
|
||||
if (row >= _TCA8418_ROWS || col >= _TCA8418_COLS) {
|
||||
@@ -186,8 +186,8 @@ void HackadayCommunicatorKeyboard::released()
|
||||
return;
|
||||
}
|
||||
|
||||
if (last_key < 0 || last_key >= _TCA8418_NUM_KEYS) {
|
||||
last_key = -1;
|
||||
if (last_key >= _TCA8418_NUM_KEYS) {
|
||||
last_key = UINT8_MAX;
|
||||
state = Idle;
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -18,8 +18,8 @@ class HackadayCommunicatorKeyboard : public TCA8418KeyboardBase
|
||||
private:
|
||||
uint8_t modifierFlag; // Flag to indicate if a modifier key is pressed
|
||||
uint32_t last_modifier_time; // Timestamp of the last modifier key press
|
||||
int8_t last_key;
|
||||
int8_t next_key;
|
||||
uint8_t last_key;
|
||||
uint8_t next_key;
|
||||
uint32_t last_tap;
|
||||
uint8_t char_idx;
|
||||
int32_t tap_interval;
|
||||
|
||||
+326
-1
@@ -1,8 +1,59 @@
|
||||
#include "InputBroker.h"
|
||||
#include "PowerFSM.h" // needed for event trigger
|
||||
#include "configuration.h"
|
||||
#include "graphics/Screen.h"
|
||||
#include "modules/ExternalNotificationModule.h"
|
||||
|
||||
#if ARCH_PORTDUINO
|
||||
#include "input/LinuxInputImpl.h"
|
||||
#include "input/SeesawRotary.h"
|
||||
#include "platform/portduino/PortduinoGlue.h"
|
||||
#endif
|
||||
|
||||
#if !MESHTASTIC_EXCLUDE_INPUTBROKER
|
||||
#include "input/ExpressLRSFiveWay.h"
|
||||
#include "input/RotaryEncoderImpl.h"
|
||||
#include "input/RotaryEncoderInterruptImpl1.h"
|
||||
#include "input/SerialKeyboardImpl.h"
|
||||
#include "input/UpDownInterruptImpl1.h"
|
||||
#include "input/i2cButton.h"
|
||||
#if HAS_TRACKBALL
|
||||
#include "input/TrackballInterruptImpl1.h"
|
||||
#endif
|
||||
|
||||
#include "modules/StatusLEDModule.h"
|
||||
|
||||
#if !MESHTASTIC_EXCLUDE_I2C
|
||||
#include "input/cardKbI2cImpl.h"
|
||||
#endif
|
||||
#include "input/kbMatrixImpl.h"
|
||||
#endif
|
||||
|
||||
#if HAS_BUTTON || defined(ARCH_PORTDUINO)
|
||||
#include "input/ButtonThread.h"
|
||||
|
||||
#if defined(BUTTON_PIN_TOUCH)
|
||||
ButtonThread *TouchButtonThread = nullptr;
|
||||
#if defined(TTGO_T_ECHO_PLUS) && defined(PIN_EINK_EN)
|
||||
static bool touchBacklightWasOn = false;
|
||||
static bool touchBacklightActive = false;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(BUTTON_PIN) || defined(ARCH_PORTDUINO)
|
||||
ButtonThread *UserButtonThread = nullptr;
|
||||
#endif
|
||||
|
||||
#if defined(ALT_BUTTON_PIN)
|
||||
ButtonThread *BackButtonThread = nullptr;
|
||||
#endif
|
||||
|
||||
#if defined(CANCEL_BUTTON_PIN)
|
||||
ButtonThread *CancelButtonThread = nullptr;
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
InputBroker *inputBroker = nullptr;
|
||||
|
||||
InputBroker::InputBroker()
|
||||
@@ -49,13 +100,28 @@ void InputBroker::processInputEventQueue()
|
||||
|
||||
int InputBroker::handleInputEvent(const InputEvent *event)
|
||||
{
|
||||
powerFSM.trigger(EVENT_INPUT); // todo: not every input should wake, like long hold release
|
||||
#if HAS_SCREEN
|
||||
bool screenWasOff = false;
|
||||
if (screen) {
|
||||
screenWasOff = !screen->isScreenOn();
|
||||
}
|
||||
#endif
|
||||
powerFSM.trigger(EVENT_INPUT);
|
||||
|
||||
if (event && event->inputEvent != INPUT_BROKER_NONE && externalNotificationModule &&
|
||||
moduleConfig.external_notification.enabled && externalNotificationModule->nagging()) {
|
||||
externalNotificationModule->stopNow();
|
||||
// If this turns off a notification, don't further process the event
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if HAS_SCREEN
|
||||
if (screen && screenWasOff) {
|
||||
// If the screen was off, it is in the process of turning on, and we just drop the event
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
this->notifyObservers(event);
|
||||
return 0;
|
||||
}
|
||||
@@ -74,3 +140,262 @@ void InputBroker::pollSoonWorker(void *p)
|
||||
vTaskDelete(NULL);
|
||||
}
|
||||
#endif
|
||||
|
||||
void InputBroker::Init()
|
||||
{
|
||||
|
||||
#ifdef BUTTON_PIN
|
||||
#ifdef ARCH_ESP32
|
||||
|
||||
#if ESP_ARDUINO_VERSION_MAJOR >= 3
|
||||
#ifdef BUTTON_NEED_PULLUP
|
||||
pinMode(config.device.button_gpio ? config.device.button_gpio : BUTTON_PIN, INPUT_PULLUP);
|
||||
#else
|
||||
pinMode(config.device.button_gpio ? config.device.button_gpio : BUTTON_PIN, INPUT); // default to BUTTON_PIN
|
||||
#endif
|
||||
#else
|
||||
pinMode(config.device.button_gpio ? config.device.button_gpio : BUTTON_PIN, INPUT); // default to BUTTON_PIN
|
||||
#ifdef BUTTON_NEED_PULLUP
|
||||
gpio_pullup_en((gpio_num_t)(config.device.button_gpio ? config.device.button_gpio : BUTTON_PIN));
|
||||
delay(10);
|
||||
#endif
|
||||
#ifdef BUTTON_NEED_PULLUP2
|
||||
gpio_pullup_en((gpio_num_t)BUTTON_NEED_PULLUP2);
|
||||
delay(10);
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// buttons are now inputBroker, so have to come after setupModules
|
||||
#if HAS_BUTTON
|
||||
int pullup_sense = 0;
|
||||
#ifdef INPUT_PULLUP_SENSE
|
||||
// Some platforms (nrf52) have a SENSE variant which allows wake from sleep - override what OneButton did
|
||||
#ifdef BUTTON_SENSE_TYPE
|
||||
pullup_sense = BUTTON_SENSE_TYPE;
|
||||
#else
|
||||
pullup_sense = INPUT_PULLUP_SENSE;
|
||||
#endif
|
||||
#endif
|
||||
#if defined(ARCH_PORTDUINO)
|
||||
|
||||
if (portduino_config.userButtonPin.enabled) {
|
||||
|
||||
LOG_DEBUG("Use GPIO%02d for button", portduino_config.userButtonPin.pin);
|
||||
UserButtonThread = new ButtonThread("UserButton");
|
||||
if (screen) {
|
||||
ButtonConfig config;
|
||||
config.pinNumber = (uint8_t)portduino_config.userButtonPin.pin;
|
||||
config.activeLow = true;
|
||||
config.activePullup = true;
|
||||
config.pullupSense = INPUT_PULLUP;
|
||||
config.intRoutine = []() {
|
||||
UserButtonThread->userButton.tick();
|
||||
UserButtonThread->setIntervalFromNow(0);
|
||||
runASAP = true;
|
||||
BaseType_t higherWake = 0;
|
||||
concurrency::mainDelay.interruptFromISR(&higherWake);
|
||||
};
|
||||
config.singlePress = INPUT_BROKER_USER_PRESS;
|
||||
config.longPress = INPUT_BROKER_SELECT;
|
||||
UserButtonThread->initButton(config);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef BUTTON_PIN_TOUCH
|
||||
TouchButtonThread = new ButtonThread("BackButton");
|
||||
ButtonConfig touchConfig;
|
||||
touchConfig.pinNumber = BUTTON_PIN_TOUCH;
|
||||
touchConfig.activeLow = true;
|
||||
touchConfig.activePullup = true;
|
||||
touchConfig.pullupSense = pullup_sense;
|
||||
touchConfig.intRoutine = []() {
|
||||
TouchButtonThread->userButton.tick();
|
||||
TouchButtonThread->setIntervalFromNow(0);
|
||||
runASAP = true;
|
||||
BaseType_t higherWake = 0;
|
||||
concurrency::mainDelay.interruptFromISR(&higherWake);
|
||||
};
|
||||
touchConfig.singlePress = INPUT_BROKER_NONE;
|
||||
touchConfig.longPress = INPUT_BROKER_BACK;
|
||||
#if defined(TTGO_T_ECHO_PLUS) && defined(PIN_EINK_EN)
|
||||
// On T-Echo Plus the touch pad should only drive the backlight, not UI navigation/sounds
|
||||
touchConfig.longPress = INPUT_BROKER_NONE;
|
||||
touchConfig.suppressLeadUpSound = true;
|
||||
touchConfig.onPress = []() {
|
||||
touchBacklightWasOn = uiconfig.screen_brightness == 1;
|
||||
if (!touchBacklightWasOn) {
|
||||
digitalWrite(PIN_EINK_EN, HIGH);
|
||||
}
|
||||
touchBacklightActive = true;
|
||||
};
|
||||
touchConfig.onRelease = []() {
|
||||
if (touchBacklightActive && !touchBacklightWasOn) {
|
||||
digitalWrite(PIN_EINK_EN, LOW);
|
||||
}
|
||||
touchBacklightActive = false;
|
||||
};
|
||||
#endif
|
||||
TouchButtonThread->initButton(touchConfig);
|
||||
#endif
|
||||
|
||||
#if defined(CANCEL_BUTTON_PIN)
|
||||
// Buttons. Moved here cause we need NodeDB to be initialized
|
||||
CancelButtonThread = new ButtonThread("CancelButton");
|
||||
ButtonConfig cancelConfig;
|
||||
cancelConfig.pinNumber = CANCEL_BUTTON_PIN;
|
||||
cancelConfig.activeLow = CANCEL_BUTTON_ACTIVE_LOW;
|
||||
cancelConfig.activePullup = CANCEL_BUTTON_ACTIVE_PULLUP;
|
||||
cancelConfig.pullupSense = pullup_sense;
|
||||
cancelConfig.intRoutine = []() {
|
||||
CancelButtonThread->userButton.tick();
|
||||
CancelButtonThread->setIntervalFromNow(0);
|
||||
runASAP = true;
|
||||
BaseType_t higherWake = 0;
|
||||
concurrency::mainDelay.interruptFromISR(&higherWake);
|
||||
};
|
||||
cancelConfig.singlePress = INPUT_BROKER_CANCEL;
|
||||
cancelConfig.longPress = INPUT_BROKER_SHUTDOWN;
|
||||
cancelConfig.longPressTime = 4000;
|
||||
CancelButtonThread->initButton(cancelConfig);
|
||||
#endif
|
||||
|
||||
#if defined(ALT_BUTTON_PIN)
|
||||
// Buttons. Moved here cause we need NodeDB to be initialized
|
||||
BackButtonThread = new ButtonThread("BackButton");
|
||||
ButtonConfig backConfig;
|
||||
backConfig.pinNumber = ALT_BUTTON_PIN;
|
||||
backConfig.activeLow = ALT_BUTTON_ACTIVE_LOW;
|
||||
backConfig.activePullup = ALT_BUTTON_ACTIVE_PULLUP;
|
||||
backConfig.pullupSense = pullup_sense;
|
||||
backConfig.intRoutine = []() {
|
||||
BackButtonThread->userButton.tick();
|
||||
BackButtonThread->setIntervalFromNow(0);
|
||||
runASAP = true;
|
||||
BaseType_t higherWake = 0;
|
||||
concurrency::mainDelay.interruptFromISR(&higherWake);
|
||||
};
|
||||
backConfig.singlePress = INPUT_BROKER_ALT_PRESS;
|
||||
backConfig.longPress = INPUT_BROKER_ALT_LONG;
|
||||
backConfig.longPressTime = 500;
|
||||
BackButtonThread->initButton(backConfig);
|
||||
#endif
|
||||
|
||||
#if defined(BUTTON_PIN)
|
||||
#if defined(USERPREFS_BUTTON_PIN)
|
||||
int _pinNum = config.device.button_gpio ? config.device.button_gpio : USERPREFS_BUTTON_PIN;
|
||||
#else
|
||||
int _pinNum = config.device.button_gpio ? config.device.button_gpio : BUTTON_PIN;
|
||||
#endif
|
||||
#ifndef BUTTON_ACTIVE_LOW
|
||||
#define BUTTON_ACTIVE_LOW true
|
||||
#endif
|
||||
#ifndef BUTTON_ACTIVE_PULLUP
|
||||
#define BUTTON_ACTIVE_PULLUP true
|
||||
#endif
|
||||
|
||||
// Buttons. Moved here cause we need NodeDB to be initialized
|
||||
// If your variant.h has a BUTTON_PIN defined, go ahead and define BUTTON_ACTIVE_LOW and BUTTON_ACTIVE_PULLUP
|
||||
UserButtonThread = new ButtonThread("UserButton");
|
||||
if (screen) {
|
||||
ButtonConfig userConfig;
|
||||
userConfig.pinNumber = (uint8_t)_pinNum;
|
||||
userConfig.activeLow = BUTTON_ACTIVE_LOW;
|
||||
userConfig.activePullup = BUTTON_ACTIVE_PULLUP;
|
||||
userConfig.pullupSense = pullup_sense;
|
||||
userConfig.intRoutine = []() {
|
||||
UserButtonThread->userButton.tick();
|
||||
UserButtonThread->setIntervalFromNow(0);
|
||||
runASAP = true;
|
||||
BaseType_t higherWake = 0;
|
||||
concurrency::mainDelay.interruptFromISR(&higherWake);
|
||||
};
|
||||
userConfig.singlePress = INPUT_BROKER_USER_PRESS;
|
||||
userConfig.longPress = INPUT_BROKER_SELECT;
|
||||
userConfig.longPressTime = 500;
|
||||
userConfig.longLongPress = INPUT_BROKER_SHUTDOWN;
|
||||
UserButtonThread->initButton(userConfig);
|
||||
} else {
|
||||
ButtonConfig userConfigNoScreen;
|
||||
userConfigNoScreen.pinNumber = (uint8_t)_pinNum;
|
||||
userConfigNoScreen.activeLow = BUTTON_ACTIVE_LOW;
|
||||
userConfigNoScreen.activePullup = BUTTON_ACTIVE_PULLUP;
|
||||
userConfigNoScreen.pullupSense = pullup_sense;
|
||||
userConfigNoScreen.intRoutine = []() {
|
||||
UserButtonThread->userButton.tick();
|
||||
UserButtonThread->setIntervalFromNow(0);
|
||||
runASAP = true;
|
||||
BaseType_t higherWake = 0;
|
||||
concurrency::mainDelay.interruptFromISR(&higherWake);
|
||||
};
|
||||
userConfigNoScreen.singlePress = INPUT_BROKER_USER_PRESS;
|
||||
userConfigNoScreen.longPress = INPUT_BROKER_NONE;
|
||||
userConfigNoScreen.longPressTime = 500;
|
||||
userConfigNoScreen.longLongPress = INPUT_BROKER_SHUTDOWN;
|
||||
userConfigNoScreen.doublePress = INPUT_BROKER_SEND_PING;
|
||||
userConfigNoScreen.triplePress = INPUT_BROKER_GPS_TOGGLE;
|
||||
UserButtonThread->initButton(userConfigNoScreen);
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if (HAS_BUTTON || ARCH_PORTDUINO) && !MESHTASTIC_EXCLUDE_INPUTBROKER
|
||||
if (config.display.displaymode != meshtastic_Config_DisplayConfig_DisplayMode_COLOR) {
|
||||
#if defined(T_LORA_PAGER)
|
||||
// use a special FSM based rotary encoder version for T-LoRa Pager
|
||||
rotaryEncoderImpl = new RotaryEncoderImpl();
|
||||
if (!rotaryEncoderImpl->init()) {
|
||||
delete rotaryEncoderImpl;
|
||||
rotaryEncoderImpl = nullptr;
|
||||
}
|
||||
#elif defined(INPUTDRIVER_ENCODER_TYPE) && (INPUTDRIVER_ENCODER_TYPE == 2)
|
||||
upDownInterruptImpl1 = new UpDownInterruptImpl1();
|
||||
if (!upDownInterruptImpl1->init()) {
|
||||
delete upDownInterruptImpl1;
|
||||
upDownInterruptImpl1 = nullptr;
|
||||
}
|
||||
#else
|
||||
rotaryEncoderInterruptImpl1 = new RotaryEncoderInterruptImpl1();
|
||||
if (!rotaryEncoderInterruptImpl1->init()) {
|
||||
delete rotaryEncoderInterruptImpl1;
|
||||
rotaryEncoderInterruptImpl1 = nullptr;
|
||||
}
|
||||
#endif
|
||||
cardKbI2cImpl = new CardKbI2cImpl();
|
||||
cardKbI2cImpl->init();
|
||||
#if defined(M5STACK_UNITC6L)
|
||||
i2cButton = new i2cButtonThread("i2cButtonThread");
|
||||
#endif
|
||||
#ifdef INPUTBROKER_MATRIX_TYPE
|
||||
kbMatrixImpl = new KbMatrixImpl();
|
||||
kbMatrixImpl->init();
|
||||
#endif // INPUTBROKER_MATRIX_TYPE
|
||||
#ifdef INPUTBROKER_SERIAL_TYPE
|
||||
aSerialKeyboardImpl = new SerialKeyboardImpl();
|
||||
aSerialKeyboardImpl->init();
|
||||
#endif // INPUTBROKER_MATRIX_TYPE
|
||||
}
|
||||
#endif // HAS_BUTTON
|
||||
#if ARCH_PORTDUINO
|
||||
if (config.display.displaymode != meshtastic_Config_DisplayConfig_DisplayMode_COLOR && portduino_config.i2cdev != "") {
|
||||
seesawRotary = new SeesawRotary("SeesawRotary");
|
||||
if (!seesawRotary->init()) {
|
||||
delete seesawRotary;
|
||||
seesawRotary = nullptr;
|
||||
}
|
||||
aLinuxInputImpl = new LinuxInputImpl();
|
||||
aLinuxInputImpl->init();
|
||||
}
|
||||
#endif
|
||||
#if !MESHTASTIC_EXCLUDE_INPUTBROKER && HAS_TRACKBALL
|
||||
if (config.display.displaymode != meshtastic_Config_DisplayConfig_DisplayMode_COLOR) {
|
||||
trackballInterruptImpl1 = new TrackballInterruptImpl1();
|
||||
trackballInterruptImpl1->init(TB_DOWN, TB_UP, TB_LEFT, TB_RIGHT, TB_PRESS);
|
||||
}
|
||||
#endif
|
||||
#ifdef INPUTBROKER_EXPRESSLRSFIVEWAY_TYPE
|
||||
expressLRSFiveWayInput = new ExpressLRSFiveWay();
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "Observer.h"
|
||||
#include "concurrency/OSThread.h"
|
||||
#include "freertosinc.h"
|
||||
|
||||
#ifdef InputBrokerDebug
|
||||
@@ -27,6 +28,11 @@ enum input_broker_event {
|
||||
INPUT_BROKER_SHUTDOWN = 0x9b,
|
||||
INPUT_BROKER_GPS_TOGGLE = 0x9e,
|
||||
INPUT_BROKER_SEND_PING = 0xaf,
|
||||
INPUT_BROKER_FN_F1 = 0xf1,
|
||||
INPUT_BROKER_FN_F2 = 0xf2,
|
||||
INPUT_BROKER_FN_F3 = 0xf3,
|
||||
INPUT_BROKER_FN_F4 = 0xf4,
|
||||
INPUT_BROKER_FN_F5 = 0xf5,
|
||||
INPUT_BROKER_MATRIXKEY = 0xFE,
|
||||
INPUT_BROKER_ANYKEY = 0xff
|
||||
|
||||
@@ -71,6 +77,7 @@ class InputBroker : public Observable<const InputEvent *>
|
||||
void queueInputEvent(const InputEvent *event);
|
||||
void processInputEventQueue();
|
||||
#endif
|
||||
void Init();
|
||||
|
||||
protected:
|
||||
int handleInputEvent(const InputEvent *event);
|
||||
@@ -84,4 +91,5 @@ class InputBroker : public Observable<const InputEvent *>
|
||||
#endif
|
||||
};
|
||||
|
||||
extern InputBroker *inputBroker;
|
||||
extern InputBroker *inputBroker;
|
||||
extern bool runASAP;
|
||||
@@ -91,7 +91,7 @@ MPR121Keyboard::MPR121Keyboard() : m_wire(nullptr), m_addr(0), readCallback(null
|
||||
{
|
||||
// LOG_DEBUG("MPR121 @ %02x", m_addr);
|
||||
state = Init;
|
||||
last_key = -1;
|
||||
last_key = UINT8_MAX;
|
||||
last_tap = 0L;
|
||||
char_idx = 0;
|
||||
queue = "";
|
||||
@@ -359,8 +359,8 @@ void MPR121Keyboard::released()
|
||||
return;
|
||||
}
|
||||
// would clear longpress callback... later.
|
||||
if (last_key < 0 || last_key > _NUM_KEYS) { // reset to idle if last_key out of bounds
|
||||
last_key = -1;
|
||||
if (last_key >= _NUM_KEYS) { // reset to idle if last_key out of bounds
|
||||
last_key = UINT8_MAX;
|
||||
state = Idle;
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@ class MPR121Keyboard
|
||||
|
||||
MPR121States state;
|
||||
|
||||
int8_t last_key;
|
||||
uint8_t last_key;
|
||||
uint32_t last_tap;
|
||||
uint8_t char_idx;
|
||||
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
SerialKeyboard *globalSerialKeyboard = nullptr;
|
||||
|
||||
#ifdef INPUTBROKER_SERIAL_TYPE
|
||||
#define CANNED_MESSAGE_MODULE_ENABLE 1 // in case it's not set in the variant file
|
||||
|
||||
#if INPUTBROKER_SERIAL_TYPE == 1 // It's a Chatter
|
||||
// 3 SHIFT level (lower case, upper case, numbers), up to 4 repeated presses, button number
|
||||
|
||||
@@ -43,8 +43,8 @@ static unsigned char TCA8418LongPressMap[_TCA8418_NUM_KEYS] = {
|
||||
};
|
||||
|
||||
TCA8418Keyboard::TCA8418Keyboard()
|
||||
: TCA8418KeyboardBase(_TCA8418_ROWS, _TCA8418_COLS), last_key(-1), next_key(-1), last_tap(0L), char_idx(0), tap_interval(0),
|
||||
should_backspace(false)
|
||||
: TCA8418KeyboardBase(_TCA8418_ROWS, _TCA8418_COLS), last_key(UINT8_MAX), next_key(UINT8_MAX), last_tap(0L), char_idx(0),
|
||||
tap_interval(0), should_backspace(false)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -63,7 +63,6 @@ void TCA8418Keyboard::pressed(uint8_t key)
|
||||
if (state == Init || state == Busy) {
|
||||
return;
|
||||
}
|
||||
uint8_t next_key = 0;
|
||||
int row = (key - 1) / 10;
|
||||
int col = (key - 1) % 10;
|
||||
|
||||
@@ -72,7 +71,7 @@ void TCA8418Keyboard::pressed(uint8_t key)
|
||||
}
|
||||
|
||||
// Compute key index based on dynamic row/column
|
||||
next_key = row * _TCA8418_COLS + col;
|
||||
next_key = (uint8_t)(row * _TCA8418_COLS + col);
|
||||
|
||||
// LOG_DEBUG("TCA8418: Key %u -> Next Key %u", key, next_key);
|
||||
|
||||
@@ -106,8 +105,8 @@ void TCA8418Keyboard::released()
|
||||
return;
|
||||
}
|
||||
|
||||
if (last_key < 0 || last_key > _TCA8418_NUM_KEYS) { // reset to idle if last_key out of bounds
|
||||
last_key = -1;
|
||||
if (last_key >= _TCA8418_NUM_KEYS) { // reset to idle if last_key out of bounds
|
||||
last_key = UINT8_MAX;
|
||||
state = Idle;
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -14,8 +14,8 @@ class TCA8418Keyboard : public TCA8418KeyboardBase
|
||||
void pressed(uint8_t key) override;
|
||||
void released(void) override;
|
||||
|
||||
int8_t last_key;
|
||||
int8_t next_key;
|
||||
uint8_t last_key;
|
||||
uint8_t next_key;
|
||||
uint32_t last_tap;
|
||||
uint8_t char_idx;
|
||||
int32_t tap_interval;
|
||||
|
||||
@@ -26,7 +26,12 @@ class TCA8418KeyboardBase
|
||||
GPS_TOGGLE = 0x9E,
|
||||
MUTE_TOGGLE = 0xAC,
|
||||
SEND_PING = 0xAF,
|
||||
BL_TOGGLE = 0xAB
|
||||
BL_TOGGLE = 0xAB,
|
||||
FUNCTION_F1 = 0xF1,
|
||||
FUNCTION_F2 = 0xF2,
|
||||
FUNCTION_F3 = 0xF3,
|
||||
FUNCTION_F4 = 0xF4,
|
||||
FUNCTION_F5 = 0xF5
|
||||
};
|
||||
|
||||
typedef uint8_t (*i2c_com_fptr_t)(uint8_t dev_addr, uint8_t reg_addr, uint8_t *data, uint8_t len);
|
||||
|
||||
@@ -62,8 +62,8 @@ static unsigned char TDeckProTapMap[_TCA8418_NUM_KEYS][5] = {
|
||||
};
|
||||
|
||||
TDeckProKeyboard::TDeckProKeyboard()
|
||||
: TCA8418KeyboardBase(_TCA8418_ROWS, _TCA8418_COLS), modifierFlag(0), last_modifier_time(0), last_key(-1), next_key(-1),
|
||||
last_tap(0L), char_idx(0), tap_interval(0)
|
||||
: TCA8418KeyboardBase(_TCA8418_ROWS, _TCA8418_COLS), modifierFlag(0), last_modifier_time(0), last_key(UINT8_MAX),
|
||||
next_key(UINT8_MAX), last_tap(0L), char_idx(0), tap_interval(0)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -101,7 +101,6 @@ void TDeckProKeyboard::pressed(uint8_t key)
|
||||
modifierFlag = 0;
|
||||
}
|
||||
|
||||
uint8_t next_key = 0;
|
||||
int row = (key - 1) / 10;
|
||||
int col = (key - 1) % 10;
|
||||
|
||||
@@ -142,8 +141,8 @@ void TDeckProKeyboard::released()
|
||||
return;
|
||||
}
|
||||
|
||||
if (last_key < 0 || last_key >= _TCA8418_NUM_KEYS) {
|
||||
last_key = -1;
|
||||
if (last_key >= _TCA8418_NUM_KEYS) {
|
||||
last_key = UINT8_MAX;
|
||||
state = Idle;
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -19,8 +19,8 @@ class TDeckProKeyboard : public TCA8418KeyboardBase
|
||||
private:
|
||||
uint8_t modifierFlag; // Flag to indicate if a modifier key is pressed
|
||||
uint32_t last_modifier_time; // Timestamp of the last modifier key press
|
||||
int8_t last_key;
|
||||
int8_t next_key;
|
||||
uint8_t last_key;
|
||||
uint8_t next_key;
|
||||
uint32_t last_tap;
|
||||
uint8_t char_idx;
|
||||
int32_t tap_interval;
|
||||
|
||||
@@ -65,8 +65,8 @@ static unsigned char TLoraPagerTapMap[_TCA8418_NUM_KEYS][3] = {{'q', 'Q', '1'},
|
||||
{' ', 0x00, Key::BL_TOGGLE}};
|
||||
|
||||
TLoraPagerKeyboard::TLoraPagerKeyboard()
|
||||
: TCA8418KeyboardBase(_TCA8418_ROWS, _TCA8418_COLS), modifierFlag(0), last_modifier_time(0), last_key(-1), next_key(-1),
|
||||
last_tap(0L), char_idx(0), tap_interval(0)
|
||||
: TCA8418KeyboardBase(_TCA8418_ROWS, _TCA8418_COLS), modifierFlag(0), last_modifier_time(0), last_key(UINT8_MAX),
|
||||
next_key(UINT8_MAX), last_tap(0L), char_idx(0), tap_interval(0)
|
||||
{
|
||||
#if ESP_ARDUINO_VERSION >= ESP_ARDUINO_VERSION_VAL(3, 0, 0)
|
||||
ledcAttach(KB_BL_PIN, LEDC_BACKLIGHT_FREQ, LEDC_BACKLIGHT_BIT_WIDTH);
|
||||
@@ -129,7 +129,6 @@ void TLoraPagerKeyboard::pressed(uint8_t key)
|
||||
modifierFlag = 0;
|
||||
}
|
||||
|
||||
uint8_t next_key = 0;
|
||||
int row = (key - 1) / 10;
|
||||
int col = (key - 1) % 10;
|
||||
|
||||
@@ -170,8 +169,8 @@ void TLoraPagerKeyboard::released()
|
||||
return;
|
||||
}
|
||||
|
||||
if (last_key < 0 || last_key >= _TCA8418_NUM_KEYS) {
|
||||
last_key = -1;
|
||||
if (last_key >= _TCA8418_NUM_KEYS) {
|
||||
last_key = UINT8_MAX;
|
||||
state = Idle;
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -21,8 +21,8 @@ class TLoraPagerKeyboard : public TCA8418KeyboardBase
|
||||
private:
|
||||
uint8_t modifierFlag; // Flag to indicate if a modifier key is pressed
|
||||
uint32_t last_modifier_time; // Timestamp of the last modifier key press
|
||||
int8_t last_key;
|
||||
int8_t next_key;
|
||||
uint8_t last_key;
|
||||
uint8_t next_key;
|
||||
uint32_t last_tap;
|
||||
uint8_t char_idx;
|
||||
int32_t tap_interval;
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
#include "TrackballInterruptBase.h"
|
||||
#include "Throttle.h"
|
||||
#include "configuration.h"
|
||||
|
||||
extern bool osk_found;
|
||||
|
||||
TrackballInterruptBase::TrackballInterruptBase(const char *name) : concurrency::OSThread(name), _originName(name) {}
|
||||
@@ -55,17 +57,27 @@ int32_t TrackballInterruptBase::runOnce()
|
||||
{
|
||||
InputEvent e = {};
|
||||
e.inputEvent = INPUT_BROKER_NONE;
|
||||
#if TB_THRESHOLD
|
||||
if (lastInterruptTime && !Throttle::isWithinTimespanMs(lastInterruptTime, 1000)) {
|
||||
left_counter = 0;
|
||||
right_counter = 0;
|
||||
up_counter = 0;
|
||||
down_counter = 0;
|
||||
lastInterruptTime = 0;
|
||||
}
|
||||
#ifdef INPUT_DEBUG
|
||||
if (left_counter > 0 || right_counter > 0 || up_counter > 0 || down_counter > 0) {
|
||||
LOG_DEBUG("L %u R %u U %u D %u, time %u", left_counter, right_counter, up_counter, down_counter, millis());
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// Handle long press detection for press button
|
||||
if (pressDetected && pressStartTime > 0) {
|
||||
uint32_t pressDuration = millis() - pressStartTime;
|
||||
bool buttonStillPressed = false;
|
||||
|
||||
#if defined(T_DECK)
|
||||
buttonStillPressed = (this->action == TB_ACTION_PRESSED);
|
||||
#else
|
||||
buttonStillPressed = !digitalRead(_pinPress);
|
||||
#endif
|
||||
|
||||
if (!buttonStillPressed) {
|
||||
// Button released
|
||||
@@ -134,23 +146,31 @@ int32_t TrackballInterruptBase::runOnce()
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(T_DECK) // T-deck gets a super-simple debounce on trackball
|
||||
if (this->action == TB_ACTION_PRESSED && !pressDetected) {
|
||||
#if TB_THRESHOLD
|
||||
if (this->action == TB_ACTION_PRESSED && (!pressDetected || pressStartTime == 0)) {
|
||||
// Start long press detection
|
||||
pressDetected = true;
|
||||
pressStartTime = millis();
|
||||
// Don't send event yet, wait to see if it's a long press
|
||||
} else if (this->action == TB_ACTION_UP && lastEvent == TB_ACTION_UP) {
|
||||
// LOG_DEBUG("Trackball event UP");
|
||||
} else if (up_counter >= TB_THRESHOLD) {
|
||||
#ifdef INPUT_DEBUG
|
||||
LOG_DEBUG("Trackball event UP %u", millis());
|
||||
#endif
|
||||
e.inputEvent = this->_eventUp;
|
||||
} else if (this->action == TB_ACTION_DOWN && lastEvent == TB_ACTION_DOWN) {
|
||||
// LOG_DEBUG("Trackball event DOWN");
|
||||
} else if (down_counter >= TB_THRESHOLD) {
|
||||
#ifdef INPUT_DEBUG
|
||||
LOG_DEBUG("Trackball event DOWN %u", millis());
|
||||
#endif
|
||||
e.inputEvent = this->_eventDown;
|
||||
} else if (this->action == TB_ACTION_LEFT && lastEvent == TB_ACTION_LEFT) {
|
||||
// LOG_DEBUG("Trackball event LEFT");
|
||||
} else if (left_counter >= TB_THRESHOLD) {
|
||||
#ifdef INPUT_DEBUG
|
||||
LOG_DEBUG("Trackball event LEFT %u", millis());
|
||||
#endif
|
||||
e.inputEvent = this->_eventLeft;
|
||||
} else if (this->action == TB_ACTION_RIGHT && lastEvent == TB_ACTION_RIGHT) {
|
||||
// LOG_DEBUG("Trackball event RIGHT");
|
||||
} else if (right_counter >= TB_THRESHOLD) {
|
||||
#ifdef INPUT_DEBUG
|
||||
LOG_DEBUG("Trackball event RIGHT %u", millis());
|
||||
#endif
|
||||
e.inputEvent = this->_eventRight;
|
||||
}
|
||||
#else
|
||||
@@ -183,6 +203,12 @@ int32_t TrackballInterruptBase::runOnce()
|
||||
e.source = this->_originName;
|
||||
e.kbchar = 0x00;
|
||||
this->notifyObservers(&e);
|
||||
#if TB_THRESHOLD
|
||||
left_counter = 0;
|
||||
right_counter = 0;
|
||||
up_counter = 0;
|
||||
down_counter = 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
// Only update lastEvent for non-press actions or completed press actions
|
||||
@@ -198,25 +224,49 @@ int32_t TrackballInterruptBase::runOnce()
|
||||
|
||||
void TrackballInterruptBase::intPressHandler()
|
||||
{
|
||||
this->action = TB_ACTION_PRESSED;
|
||||
if (!Throttle::isWithinTimespanMs(lastInterruptTime, 10))
|
||||
this->action = TB_ACTION_PRESSED;
|
||||
lastInterruptTime = millis();
|
||||
}
|
||||
|
||||
void TrackballInterruptBase::intDownHandler()
|
||||
{
|
||||
this->action = TB_ACTION_DOWN;
|
||||
if (TB_THRESHOLD || !Throttle::isWithinTimespanMs(lastInterruptTime, 10))
|
||||
this->action = TB_ACTION_DOWN;
|
||||
lastInterruptTime = millis();
|
||||
|
||||
#if TB_THRESHOLD
|
||||
down_counter++;
|
||||
#endif
|
||||
}
|
||||
|
||||
void TrackballInterruptBase::intUpHandler()
|
||||
{
|
||||
this->action = TB_ACTION_UP;
|
||||
if (TB_THRESHOLD || !Throttle::isWithinTimespanMs(lastInterruptTime, 10))
|
||||
this->action = TB_ACTION_UP;
|
||||
lastInterruptTime = millis();
|
||||
|
||||
#if TB_THRESHOLD
|
||||
up_counter++;
|
||||
#endif
|
||||
}
|
||||
|
||||
void TrackballInterruptBase::intLeftHandler()
|
||||
{
|
||||
this->action = TB_ACTION_LEFT;
|
||||
if (TB_THRESHOLD || !Throttle::isWithinTimespanMs(lastInterruptTime, 10))
|
||||
this->action = TB_ACTION_LEFT;
|
||||
lastInterruptTime = millis();
|
||||
#if TB_THRESHOLD
|
||||
left_counter++;
|
||||
#endif
|
||||
}
|
||||
|
||||
void TrackballInterruptBase::intRightHandler()
|
||||
{
|
||||
this->action = TB_ACTION_RIGHT;
|
||||
if (TB_THRESHOLD || !Throttle::isWithinTimespanMs(lastInterruptTime, 10))
|
||||
this->action = TB_ACTION_RIGHT;
|
||||
lastInterruptTime = millis();
|
||||
#if TB_THRESHOLD
|
||||
right_counter++;
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -12,6 +12,10 @@
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef TB_THRESHOLD
|
||||
#define TB_THRESHOLD 0
|
||||
#endif
|
||||
|
||||
class TrackballInterruptBase : public Observable<const InputEvent *>, public concurrency::OSThread
|
||||
{
|
||||
public:
|
||||
@@ -25,8 +29,6 @@ class TrackballInterruptBase : public Observable<const InputEvent *>, public con
|
||||
void intUpHandler();
|
||||
void intLeftHandler();
|
||||
void intRightHandler();
|
||||
uint32_t lastTime = 0;
|
||||
|
||||
virtual int32_t runOnce() override;
|
||||
|
||||
protected:
|
||||
@@ -67,4 +69,12 @@ class TrackballInterruptBase : public Observable<const InputEvent *>, public con
|
||||
input_broker_event _eventPressedLong = INPUT_BROKER_NONE;
|
||||
const char *_originName;
|
||||
TrackballInterruptBaseActionType lastEvent = TB_ACTION_NONE;
|
||||
volatile uint32_t lastInterruptTime = 0;
|
||||
|
||||
#if TB_THRESHOLD
|
||||
volatile uint8_t left_counter = 0;
|
||||
volatile uint8_t right_counter = 0;
|
||||
volatile uint8_t up_counter = 0;
|
||||
volatile uint8_t down_counter = 0;
|
||||
#endif
|
||||
};
|
||||
|
||||
@@ -24,41 +24,26 @@ void TrackballInterruptImpl1::init(uint8_t pinDown, uint8_t pinUp, uint8_t pinLe
|
||||
|
||||
void TrackballInterruptImpl1::handleIntDown()
|
||||
{
|
||||
if (TB_DIRECTION == RISING || millis() > trackballInterruptImpl1->lastTime + 10) {
|
||||
trackballInterruptImpl1->lastTime = millis();
|
||||
trackballInterruptImpl1->intDownHandler();
|
||||
trackballInterruptImpl1->setIntervalFromNow(20);
|
||||
}
|
||||
trackballInterruptImpl1->intDownHandler();
|
||||
trackballInterruptImpl1->setIntervalFromNow(20);
|
||||
}
|
||||
void TrackballInterruptImpl1::handleIntUp()
|
||||
{
|
||||
if (TB_DIRECTION == RISING || millis() > trackballInterruptImpl1->lastTime + 10) {
|
||||
trackballInterruptImpl1->lastTime = millis();
|
||||
trackballInterruptImpl1->intUpHandler();
|
||||
trackballInterruptImpl1->setIntervalFromNow(20);
|
||||
}
|
||||
trackballInterruptImpl1->intUpHandler();
|
||||
trackballInterruptImpl1->setIntervalFromNow(20);
|
||||
}
|
||||
void TrackballInterruptImpl1::handleIntLeft()
|
||||
{
|
||||
if (TB_DIRECTION == RISING || millis() > trackballInterruptImpl1->lastTime + 10) {
|
||||
trackballInterruptImpl1->lastTime = millis();
|
||||
trackballInterruptImpl1->intLeftHandler();
|
||||
trackballInterruptImpl1->setIntervalFromNow(20);
|
||||
}
|
||||
trackballInterruptImpl1->intLeftHandler();
|
||||
trackballInterruptImpl1->setIntervalFromNow(20);
|
||||
}
|
||||
void TrackballInterruptImpl1::handleIntRight()
|
||||
{
|
||||
if (TB_DIRECTION == RISING || millis() > trackballInterruptImpl1->lastTime + 10) {
|
||||
trackballInterruptImpl1->lastTime = millis();
|
||||
trackballInterruptImpl1->intRightHandler();
|
||||
trackballInterruptImpl1->setIntervalFromNow(20);
|
||||
}
|
||||
trackballInterruptImpl1->intRightHandler();
|
||||
trackballInterruptImpl1->setIntervalFromNow(20);
|
||||
}
|
||||
void TrackballInterruptImpl1::handleIntPressed()
|
||||
{
|
||||
if (TB_DIRECTION == RISING || millis() > trackballInterruptImpl1->lastTime + 10) {
|
||||
trackballInterruptImpl1->lastTime = millis();
|
||||
trackballInterruptImpl1->intPressHandler();
|
||||
trackballInterruptImpl1->setIntervalFromNow(20);
|
||||
}
|
||||
trackballInterruptImpl1->intPressHandler();
|
||||
trackballInterruptImpl1->setIntervalFromNow(20);
|
||||
}
|
||||
|
||||
@@ -321,6 +321,26 @@ int32_t KbI2cBase::runOnce()
|
||||
e.inputEvent = INPUT_BROKER_ANYKEY;
|
||||
e.kbchar = INPUT_BROKER_MSG_TAB;
|
||||
break;
|
||||
case TCA8418KeyboardBase::FUNCTION_F1:
|
||||
e.inputEvent = INPUT_BROKER_FN_F1;
|
||||
e.kbchar = 0x00;
|
||||
break;
|
||||
case TCA8418KeyboardBase::FUNCTION_F2:
|
||||
e.inputEvent = INPUT_BROKER_FN_F2;
|
||||
e.kbchar = 0x00;
|
||||
break;
|
||||
case TCA8418KeyboardBase::FUNCTION_F3:
|
||||
e.inputEvent = INPUT_BROKER_FN_F3;
|
||||
e.kbchar = 0x00;
|
||||
break;
|
||||
case TCA8418KeyboardBase::FUNCTION_F4:
|
||||
e.inputEvent = INPUT_BROKER_FN_F4;
|
||||
e.kbchar = 0x00;
|
||||
break;
|
||||
case TCA8418KeyboardBase::FUNCTION_F5:
|
||||
e.inputEvent = INPUT_BROKER_FN_F5;
|
||||
e.kbchar = 0x00;
|
||||
break;
|
||||
default:
|
||||
if (nextEvent > 127) {
|
||||
e.inputEvent = INPUT_BROKER_NONE;
|
||||
|
||||
Reference in New Issue
Block a user