mirror of
https://github.com/meshtastic/firmware.git
synced 2025-06-07 21:52:05 +00:00
refactored TCA8418Keyboard
This commit is contained in:
parent
0ccce5e991
commit
70ec2c84ed
@ -114,11 +114,12 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|||||||
// Define if screen should be mirrored left to right
|
// Define if screen should be mirrored left to right
|
||||||
// #define SCREEN_MIRROR
|
// #define SCREEN_MIRROR
|
||||||
|
|
||||||
// I2C Keyboards (M5Stack, RAK14004, T-Deck)
|
// I2C Keyboards (M5Stack, RAK14004, T-Deck, T-Deck Pro, T-Lora Pager, CardKB, BBQ10, MPR121, TCA8418)
|
||||||
#define CARDKB_ADDR 0x5F
|
#define CARDKB_ADDR 0x5F
|
||||||
#define TDECK_KB_ADDR 0x55
|
#define TDECK_KB_ADDR 0x55
|
||||||
#define BBQ10_KB_ADDR 0x1F
|
#define BBQ10_KB_ADDR 0x1F
|
||||||
#define MPR121_KB_ADDR 0x5A
|
#define MPR121_KB_ADDR 0x5A
|
||||||
|
#define TCA8418_KB_ADDR 0x34
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
// SENSOR
|
// SENSOR
|
||||||
@ -156,7 +157,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|||||||
#define MLX90614_ADDR_DEF 0x5A
|
#define MLX90614_ADDR_DEF 0x5A
|
||||||
#define CGRADSENS_ADDR 0x66
|
#define CGRADSENS_ADDR 0x66
|
||||||
#define LTR390UV_ADDR 0x53
|
#define LTR390UV_ADDR 0x53
|
||||||
#define XPOWERS_AXP192_AXP2101_ADDRESS 0x34 // same adress as TCA8418
|
#define XPOWERS_AXP192_AXP2101_ADDRESS 0x34 // same adress as TCA8418_KB
|
||||||
#define PCT2075_ADDR 0x37
|
#define PCT2075_ADDR 0x37
|
||||||
#define BQ27220_ADDR 0x55 // same address as TDECK_KB
|
#define BQ27220_ADDR 0x55 // same address as TDECK_KB
|
||||||
#define BQ25896_ADDR 0x6B
|
#define BQ25896_ADDR 0x6B
|
||||||
|
@ -1,165 +1,5 @@
|
|||||||
// Based on the MPR121 Keyboard and Adafruit TCA8418 library
|
|
||||||
|
|
||||||
#include "TCA8418Keyboard.h"
|
#include "TCA8418Keyboard.h"
|
||||||
#include "configuration.h"
|
|
||||||
|
|
||||||
#include <Arduino.h>
|
|
||||||
|
|
||||||
// REGISTERS
|
|
||||||
// #define _TCA8418_REG_RESERVED 0x00
|
|
||||||
#define _TCA8418_REG_CFG 0x01 // Configuration register
|
|
||||||
#define _TCA8418_REG_INT_STAT 0x02 // Interrupt status
|
|
||||||
#define _TCA8418_REG_KEY_LCK_EC 0x03 // Key lock and event counter
|
|
||||||
#define _TCA8418_REG_KEY_EVENT_A 0x04 // Key event register A
|
|
||||||
#define _TCA8418_REG_KEY_EVENT_B 0x05 // Key event register B
|
|
||||||
#define _TCA8418_REG_KEY_EVENT_C 0x06 // Key event register C
|
|
||||||
#define _TCA8418_REG_KEY_EVENT_D 0x07 // Key event register D
|
|
||||||
#define _TCA8418_REG_KEY_EVENT_E 0x08 // Key event register E
|
|
||||||
#define _TCA8418_REG_KEY_EVENT_F 0x09 // Key event register F
|
|
||||||
#define _TCA8418_REG_KEY_EVENT_G 0x0A // Key event register G
|
|
||||||
#define _TCA8418_REG_KEY_EVENT_H 0x0B // Key event register H
|
|
||||||
#define _TCA8418_REG_KEY_EVENT_I 0x0C // Key event register I
|
|
||||||
#define _TCA8418_REG_KEY_EVENT_J 0x0D // Key event register J
|
|
||||||
#define _TCA8418_REG_KP_LCK_TIMER 0x0E // Keypad lock1 to lock2 timer
|
|
||||||
#define _TCA8418_REG_UNLOCK_1 0x0F // Unlock register 1
|
|
||||||
#define _TCA8418_REG_UNLOCK_2 0x10 // Unlock register 2
|
|
||||||
#define _TCA8418_REG_GPIO_INT_STAT_1 0x11 // GPIO interrupt status 1
|
|
||||||
#define _TCA8418_REG_GPIO_INT_STAT_2 0x12 // GPIO interrupt status 2
|
|
||||||
#define _TCA8418_REG_GPIO_INT_STAT_3 0x13 // GPIO interrupt status 3
|
|
||||||
#define _TCA8418_REG_GPIO_DAT_STAT_1 0x14 // GPIO data status 1
|
|
||||||
#define _TCA8418_REG_GPIO_DAT_STAT_2 0x15 // GPIO data status 2
|
|
||||||
#define _TCA8418_REG_GPIO_DAT_STAT_3 0x16 // GPIO data status 3
|
|
||||||
#define _TCA8418_REG_GPIO_DAT_OUT_1 0x17 // GPIO data out 1
|
|
||||||
#define _TCA8418_REG_GPIO_DAT_OUT_2 0x18 // GPIO data out 2
|
|
||||||
#define _TCA8418_REG_GPIO_DAT_OUT_3 0x19 // GPIO data out 3
|
|
||||||
#define _TCA8418_REG_GPIO_INT_EN_1 0x1A // GPIO interrupt enable 1
|
|
||||||
#define _TCA8418_REG_GPIO_INT_EN_2 0x1B // GPIO interrupt enable 2
|
|
||||||
#define _TCA8418_REG_GPIO_INT_EN_3 0x1C // GPIO interrupt enable 3
|
|
||||||
#define _TCA8418_REG_KP_GPIO_1 0x1D // Keypad/GPIO select 1
|
|
||||||
#define _TCA8418_REG_KP_GPIO_2 0x1E // Keypad/GPIO select 2
|
|
||||||
#define _TCA8418_REG_KP_GPIO_3 0x1F // Keypad/GPIO select 3
|
|
||||||
#define _TCA8418_REG_GPI_EM_1 0x20 // GPI event mode 1
|
|
||||||
#define _TCA8418_REG_GPI_EM_2 0x21 // GPI event mode 2
|
|
||||||
#define _TCA8418_REG_GPI_EM_3 0x22 // GPI event mode 3
|
|
||||||
#define _TCA8418_REG_GPIO_DIR_1 0x23 // GPIO data direction 1
|
|
||||||
#define _TCA8418_REG_GPIO_DIR_2 0x24 // GPIO data direction 2
|
|
||||||
#define _TCA8418_REG_GPIO_DIR_3 0x25 // GPIO data direction 3
|
|
||||||
#define _TCA8418_REG_GPIO_INT_LVL_1 0x26 // GPIO edge/level detect 1
|
|
||||||
#define _TCA8418_REG_GPIO_INT_LVL_2 0x27 // GPIO edge/level detect 2
|
|
||||||
#define _TCA8418_REG_GPIO_INT_LVL_3 0x28 // GPIO edge/level detect 3
|
|
||||||
#define _TCA8418_REG_DEBOUNCE_DIS_1 0x29 // Debounce disable 1
|
|
||||||
#define _TCA8418_REG_DEBOUNCE_DIS_2 0x2A // Debounce disable 2
|
|
||||||
#define _TCA8418_REG_DEBOUNCE_DIS_3 0x2B // Debounce disable 3
|
|
||||||
#define _TCA8418_REG_GPIO_PULL_1 0x2C // GPIO pull-up disable 1
|
|
||||||
#define _TCA8418_REG_GPIO_PULL_2 0x2D // GPIO pull-up disable 2
|
|
||||||
#define _TCA8418_REG_GPIO_PULL_3 0x2E // GPIO pull-up disable 3
|
|
||||||
// #define _TCA8418_REG_RESERVED 0x2F
|
|
||||||
|
|
||||||
// FIELDS CONFIG REGISTER 1
|
|
||||||
#define _TCA8418_REG_CFG_AI 0x80 // Auto-increment for read/write
|
|
||||||
#define _TCA8418_REG_CFG_GPI_E_CGF 0x40 // Event mode config
|
|
||||||
#define _TCA8418_REG_CFG_OVR_FLOW_M 0x20 // Overflow mode enable
|
|
||||||
#define _TCA8418_REG_CFG_INT_CFG 0x10 // Interrupt config
|
|
||||||
#define _TCA8418_REG_CFG_OVR_FLOW_IEN 0x08 // Overflow interrupt enable
|
|
||||||
#define _TCA8418_REG_CFG_K_LCK_IEN 0x04 // Keypad lock interrupt enable
|
|
||||||
#define _TCA8418_REG_CFG_GPI_IEN 0x02 // GPI interrupt enable
|
|
||||||
#define _TCA8418_REG_CFG_KE_IEN 0x01 // Key events interrupt enable
|
|
||||||
|
|
||||||
// FIELDS INT_STAT REGISTER 2
|
|
||||||
#define _TCA8418_REG_STAT_CAD_INT 0x10 // Ctrl-alt-del seq status
|
|
||||||
#define _TCA8418_REG_STAT_OVR_FLOW_INT 0x08 // Overflow interrupt status
|
|
||||||
#define _TCA8418_REG_STAT_K_LCK_INT 0x04 // Key lock interrupt status
|
|
||||||
#define _TCA8418_REG_STAT_GPI_INT 0x02 // GPI interrupt status
|
|
||||||
#define _TCA8418_REG_STAT_K_INT 0x01 // Key events interrupt status
|
|
||||||
|
|
||||||
// FIELDS KEY_LCK_EC REGISTER 3
|
|
||||||
#define _TCA8418_REG_LCK_EC_K_LCK_EN 0x40 // Key lock enable
|
|
||||||
#define _TCA8418_REG_LCK_EC_LCK_2 0x20 // Keypad lock status 2
|
|
||||||
#define _TCA8418_REG_LCK_EC_LCK_1 0x10 // Keypad lock status 1
|
|
||||||
#define _TCA8418_REG_LCK_EC_KLEC_3 0x08 // Key event count bit 3
|
|
||||||
#define _TCA8418_REG_LCK_EC_KLEC_2 0x04 // Key event count bit 2
|
|
||||||
#define _TCA8418_REG_LCK_EC_KLEC_1 0x02 // Key event count bit 1
|
|
||||||
#define _TCA8418_REG_LCK_EC_KLEC_0 0x01 // Key event count bit 0
|
|
||||||
|
|
||||||
// Pin IDs for matrix rows/columns
|
|
||||||
enum {
|
|
||||||
_TCA8418_ROW0, // Pin ID for row 0
|
|
||||||
_TCA8418_ROW1, // Pin ID for row 1
|
|
||||||
_TCA8418_ROW2, // Pin ID for row 2
|
|
||||||
_TCA8418_ROW3, // Pin ID for row 3
|
|
||||||
_TCA8418_ROW4, // Pin ID for row 4
|
|
||||||
_TCA8418_ROW5, // Pin ID for row 5
|
|
||||||
_TCA8418_ROW6, // Pin ID for row 6
|
|
||||||
_TCA8418_ROW7, // Pin ID for row 7
|
|
||||||
_TCA8418_COL0, // Pin ID for column 0
|
|
||||||
_TCA8418_COL1, // Pin ID for column 1
|
|
||||||
_TCA8418_COL2, // Pin ID for column 2
|
|
||||||
_TCA8418_COL3, // Pin ID for column 3
|
|
||||||
_TCA8418_COL4, // Pin ID for column 4
|
|
||||||
_TCA8418_COL5, // Pin ID for column 5
|
|
||||||
_TCA8418_COL6, // Pin ID for column 6
|
|
||||||
_TCA8418_COL7, // Pin ID for column 7
|
|
||||||
_TCA8418_COL8, // Pin ID for column 8
|
|
||||||
_TCA8418_COL9 // Pin ID for column 9
|
|
||||||
};
|
|
||||||
|
|
||||||
#if defined(T_DECK_PRO)
|
|
||||||
#define _TCA8418_COLS 10
|
|
||||||
#define _TCA8418_ROWS 4
|
|
||||||
#define _TCA8418_NUM_KEYS 35
|
|
||||||
|
|
||||||
#define _TCA8418_LONG_PRESS_THRESHOLD 2000
|
|
||||||
#define _TCA8418_MULTI_TAP_THRESHOLD 1500
|
|
||||||
|
|
||||||
// Num chars per key, Modulus for rotating through characters
|
|
||||||
uint8_t TCA8418TapMod[_TCA8418_NUM_KEYS] = {3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
|
|
||||||
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3};
|
|
||||||
|
|
||||||
// https://learn.microsoft.com/en-us/windows/win32/inputdev/virtual-key-codes
|
|
||||||
unsigned char TCA8418TapMap[_TCA8418_NUM_KEYS][3] = {{'p', 'P', '@'},
|
|
||||||
{'o', 'O', '+'},
|
|
||||||
{'i', 'I', '-'},
|
|
||||||
{'u', 'U', '_'},
|
|
||||||
{'y', 'Y', ')'},
|
|
||||||
{'t', 'T', '('},
|
|
||||||
{'r', 'R', '3'},
|
|
||||||
{'e', 'E', '2'},
|
|
||||||
{'w', 'W', '1'},
|
|
||||||
{'q', 'Q', '#'},
|
|
||||||
{_TCA8418_BSP, 0x00, 0x00},
|
|
||||||
{'l', 'L', '"'},
|
|
||||||
{'k', 'K', '\''},
|
|
||||||
{'j', 'J', ';'},
|
|
||||||
{'h', 'H', ':'},
|
|
||||||
{'g', 'G', '/'},
|
|
||||||
{'f', 'F', '6'},
|
|
||||||
{'d', 'D', '5'},
|
|
||||||
{'s', 'S', '4'},
|
|
||||||
{'a', 'A', '*'},
|
|
||||||
{0x0d, 0x00, 0x00},
|
|
||||||
{'$', 0x00, 0x00},
|
|
||||||
{'m', 'M', '.'},
|
|
||||||
{'n', 'N', ','},
|
|
||||||
{'b', 'B', '!'},
|
|
||||||
{'v', 'V', '?'},
|
|
||||||
{'c', 'C', '9'},
|
|
||||||
{'x', 'X', '8'},
|
|
||||||
{'z', 'Z', '7'},
|
|
||||||
{0xa4, 0x00, 0x00},
|
|
||||||
{0xa1, 0x00, 0x00},
|
|
||||||
{0x00, 0x00, 0x00},
|
|
||||||
{0x20, 0x00, 0x00},
|
|
||||||
{0x00, 0x00, '0'},
|
|
||||||
{0xa0, 0x00, 0x00}};
|
|
||||||
|
|
||||||
unsigned char TCA8418LongPressMap[_TCA8418_NUM_KEYS] = {
|
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, _TCA8418_ESC, // p,o,i,u,y,t,r,e,w,q
|
|
||||||
0x00, 0x00, 0x00, 0xb5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // bsp,l,k,j,h,g,f,d,s,a
|
|
||||||
0x00, 0x00, 0xb7, 0xb6, 0xb4, 0x00, 0x00, 0x00, 0x00, 0x00, // ent,$,m,n,b,v,c,x,z,alt
|
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00 // rShift,sym,space,mic,lShift
|
|
||||||
};
|
|
||||||
|
|
||||||
#else
|
|
||||||
#define _TCA8418_COLS 3
|
#define _TCA8418_COLS 3
|
||||||
#define _TCA8418_ROWS 4
|
#define _TCA8418_ROWS 4
|
||||||
#define _TCA8418_NUM_KEYS 12
|
#define _TCA8418_NUM_KEYS 12
|
||||||
@ -167,10 +7,12 @@ unsigned char TCA8418LongPressMap[_TCA8418_NUM_KEYS] = {
|
|||||||
#define _TCA8418_LONG_PRESS_THRESHOLD 2000
|
#define _TCA8418_LONG_PRESS_THRESHOLD 2000
|
||||||
#define _TCA8418_MULTI_TAP_THRESHOLD 750
|
#define _TCA8418_MULTI_TAP_THRESHOLD 750
|
||||||
|
|
||||||
uint8_t TCA8418TapMod[_TCA8418_NUM_KEYS] = {13, 7, 7, 7, 7, 7,
|
using Key = TCA8418KeyboardBase::TCA8418Key;
|
||||||
9, 7, 9, 2, 2, 2}; // Num chars per key, Modulus for rotating through characters
|
|
||||||
|
|
||||||
unsigned char TCA8418TapMap[_TCA8418_NUM_KEYS][13] = {
|
// Num chars per key, Modulus for rotating through characters
|
||||||
|
static uint8_t TCA8418TapMod[_TCA8418_NUM_KEYS] = {13, 7, 7, 7, 7, 7, 9, 7, 9, 2, 2, 2};
|
||||||
|
|
||||||
|
static unsigned char TCA8418TapMap[_TCA8418_NUM_KEYS][13] = {
|
||||||
{'1', '.', ',', '?', '!', ':', ';', '-', '_', '\\', '/', '(', ')'}, // 1
|
{'1', '.', ',', '?', '!', ':', ';', '-', '_', '\\', '/', '(', ')'}, // 1
|
||||||
{'2', 'a', 'b', 'c', 'A', 'B', 'C'}, // 2
|
{'2', 'a', 'b', 'c', 'A', 'B', 'C'}, // 2
|
||||||
{'3', 'd', 'e', 'f', 'D', 'E', 'F'}, // 3
|
{'3', 'd', 'e', 'f', 'D', 'E', 'F'}, // 3
|
||||||
@ -185,179 +27,35 @@ unsigned char TCA8418TapMap[_TCA8418_NUM_KEYS][13] = {
|
|||||||
{'#', '@'}, // #
|
{'#', '@'}, // #
|
||||||
};
|
};
|
||||||
|
|
||||||
unsigned char TCA8418LongPressMap[_TCA8418_NUM_KEYS] = {
|
static unsigned char TCA8418LongPressMap[_TCA8418_NUM_KEYS] = {
|
||||||
_TCA8418_ESC, // 1
|
Key::ESC, // 1
|
||||||
_TCA8418_UP, // 2
|
Key::UP, // 2
|
||||||
_TCA8418_NONE, // 3
|
Key::NONE, // 3
|
||||||
_TCA8418_LEFT, // 4
|
Key::LEFT, // 4
|
||||||
_TCA8418_NONE, // 5
|
Key::NONE, // 5
|
||||||
_TCA8418_RIGHT, // 6
|
Key::RIGHT, // 6
|
||||||
_TCA8418_NONE, // 7
|
Key::NONE, // 7
|
||||||
_TCA8418_DOWN, // 8
|
Key::DOWN, // 8
|
||||||
_TCA8418_NONE, // 9
|
Key::NONE, // 9
|
||||||
_TCA8418_BSP, // *
|
Key::BSP, // *
|
||||||
_TCA8418_NONE, // 0
|
Key::NONE, // 0
|
||||||
_TCA8418_NONE, // #
|
Key::NONE, // #
|
||||||
};
|
};
|
||||||
#endif
|
|
||||||
|
|
||||||
TCA8418Keyboard::TCA8418Keyboard() : m_wire(nullptr), m_addr(0), readCallback(nullptr), writeCallback(nullptr)
|
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)
|
||||||
{
|
{
|
||||||
state = Init;
|
|
||||||
last_key = -1;
|
|
||||||
next_key = -1;
|
|
||||||
should_backspace = false;
|
|
||||||
last_tap = 0L;
|
|
||||||
char_idx = 0;
|
|
||||||
tap_interval = 0;
|
|
||||||
backlight_on = true;
|
|
||||||
queue = "";
|
|
||||||
}
|
|
||||||
|
|
||||||
void TCA8418Keyboard::begin(uint8_t addr, TwoWire *wire)
|
|
||||||
{
|
|
||||||
m_addr = addr;
|
|
||||||
m_wire = wire;
|
|
||||||
|
|
||||||
m_wire->begin();
|
|
||||||
|
|
||||||
reset();
|
|
||||||
}
|
|
||||||
|
|
||||||
void TCA8418Keyboard::begin(i2c_com_fptr_t r, i2c_com_fptr_t w, uint8_t addr)
|
|
||||||
{
|
|
||||||
m_addr = addr;
|
|
||||||
m_wire = nullptr;
|
|
||||||
writeCallback = w;
|
|
||||||
readCallback = r;
|
|
||||||
reset();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void TCA8418Keyboard::reset()
|
void TCA8418Keyboard::reset()
|
||||||
{
|
{
|
||||||
LOG_DEBUG("TCA8418 Reset");
|
TCA8418KeyboardBase::reset();
|
||||||
// GPIO
|
|
||||||
// set default all GIO pins to INPUT
|
|
||||||
writeRegister(_TCA8418_REG_GPIO_DIR_1, 0x00);
|
|
||||||
writeRegister(_TCA8418_REG_GPIO_DIR_2, 0x00);
|
|
||||||
#ifndef T_DECK_PRO
|
|
||||||
// Set COL9 as GPIO output
|
// Set COL9 as GPIO output
|
||||||
writeRegister(_TCA8418_REG_GPIO_DIR_3, 0x02);
|
writeRegister(TCA8418_REG_GPIO_DIR_3, 0x02);
|
||||||
// Switch off keyboard backlight (COL9 = LOW)
|
// Switch off keyboard backlight (COL9 = LOW)
|
||||||
writeRegister(_TCA8418_REG_GPIO_DAT_OUT_3, 0x00);
|
writeRegister(TCA8418_REG_GPIO_DAT_OUT_3, 0x00);
|
||||||
#else
|
|
||||||
writeRegister(_TCA8418_REG_GPIO_DIR_3, 0x00);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// add all pins to key events
|
|
||||||
writeRegister(_TCA8418_REG_GPI_EM_1, 0xFF);
|
|
||||||
writeRegister(_TCA8418_REG_GPI_EM_2, 0xFF);
|
|
||||||
writeRegister(_TCA8418_REG_GPI_EM_3, 0xFF);
|
|
||||||
|
|
||||||
// set all pins to FALLING interrupts
|
|
||||||
writeRegister(_TCA8418_REG_GPIO_INT_LVL_1, 0x00);
|
|
||||||
writeRegister(_TCA8418_REG_GPIO_INT_LVL_2, 0x00);
|
|
||||||
writeRegister(_TCA8418_REG_GPIO_INT_LVL_3, 0x00);
|
|
||||||
|
|
||||||
// add all pins to interrupts
|
|
||||||
writeRegister(_TCA8418_REG_GPIO_INT_EN_1, 0xFF);
|
|
||||||
writeRegister(_TCA8418_REG_GPIO_INT_EN_2, 0xFF);
|
|
||||||
writeRegister(_TCA8418_REG_GPIO_INT_EN_3, 0xFF);
|
|
||||||
|
|
||||||
// Set keyboard matrix size
|
|
||||||
matrix(_TCA8418_ROWS, _TCA8418_COLS);
|
|
||||||
enableDebounce();
|
|
||||||
flush();
|
|
||||||
state = Idle;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool TCA8418Keyboard::matrix(uint8_t rows, uint8_t columns)
|
|
||||||
{
|
|
||||||
if ((rows > 8) || (columns > 10))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
// Skip zero size matrix
|
|
||||||
if ((rows != 0) && (columns != 0)) {
|
|
||||||
// Setup the keypad matrix.
|
|
||||||
uint8_t mask = 0x00;
|
|
||||||
for (int r = 0; r < rows; r++) {
|
|
||||||
mask <<= 1;
|
|
||||||
mask |= 1;
|
|
||||||
}
|
|
||||||
writeRegister(_TCA8418_REG_KP_GPIO_1, mask);
|
|
||||||
|
|
||||||
mask = 0x00;
|
|
||||||
for (int c = 0; c < columns && c < 8; c++) {
|
|
||||||
mask <<= 1;
|
|
||||||
mask |= 1;
|
|
||||||
}
|
|
||||||
writeRegister(_TCA8418_REG_KP_GPIO_2, mask);
|
|
||||||
|
|
||||||
if (columns > 8) {
|
|
||||||
if (columns == 9)
|
|
||||||
mask = 0x01;
|
|
||||||
else
|
|
||||||
mask = 0x03;
|
|
||||||
writeRegister(_TCA8418_REG_KP_GPIO_3, mask);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint8_t TCA8418Keyboard::keyCount() const
|
|
||||||
{
|
|
||||||
uint8_t eventCount = readRegister(_TCA8418_REG_KEY_LCK_EC);
|
|
||||||
eventCount &= 0x0F; // lower 4 bits only
|
|
||||||
return eventCount;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool TCA8418Keyboard::hasEvent()
|
|
||||||
{
|
|
||||||
return queue.length() > 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void TCA8418Keyboard::queueEvent(char next)
|
|
||||||
{
|
|
||||||
if (next == _TCA8418_NONE) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
queue.concat(next);
|
|
||||||
}
|
|
||||||
|
|
||||||
char TCA8418Keyboard::dequeueEvent()
|
|
||||||
{
|
|
||||||
if (queue.length() < 1) {
|
|
||||||
return _TCA8418_NONE;
|
|
||||||
}
|
|
||||||
char next = queue.charAt(0);
|
|
||||||
queue.remove(0, 1);
|
|
||||||
return next;
|
|
||||||
}
|
|
||||||
|
|
||||||
void TCA8418Keyboard::trigger()
|
|
||||||
{
|
|
||||||
if (keyCount() == 0) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (state != Init) {
|
|
||||||
// Read the key register
|
|
||||||
uint8_t k = readRegister(_TCA8418_REG_KEY_EVENT_A);
|
|
||||||
uint8_t key = k & 0x7F;
|
|
||||||
if (k & 0x80) {
|
|
||||||
if (state == Idle)
|
|
||||||
pressed(key);
|
|
||||||
return;
|
|
||||||
} else {
|
|
||||||
if (state == Held) {
|
|
||||||
released();
|
|
||||||
}
|
|
||||||
state = Idle;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
reset();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void TCA8418Keyboard::pressed(uint8_t key)
|
void TCA8418Keyboard::pressed(uint8_t key)
|
||||||
@ -417,7 +115,7 @@ void TCA8418Keyboard::released()
|
|||||||
int32_t held_interval = now - last_tap;
|
int32_t held_interval = now - last_tap;
|
||||||
last_tap = now;
|
last_tap = now;
|
||||||
if (tap_interval < _TCA8418_MULTI_TAP_THRESHOLD && should_backspace) {
|
if (tap_interval < _TCA8418_MULTI_TAP_THRESHOLD && should_backspace) {
|
||||||
queueEvent(_TCA8418_BSP);
|
queueEvent(BSP);
|
||||||
}
|
}
|
||||||
if (held_interval > _TCA8418_LONG_PRESS_THRESHOLD) {
|
if (held_interval > _TCA8418_LONG_PRESS_THRESHOLD) {
|
||||||
queueEvent(TCA8418LongPressMap[last_key]);
|
queueEvent(TCA8418LongPressMap[last_key]);
|
||||||
@ -429,203 +127,11 @@ void TCA8418Keyboard::released()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t TCA8418Keyboard::flush()
|
|
||||||
{
|
|
||||||
// Flush key events
|
|
||||||
uint8_t count = 0;
|
|
||||||
while (readRegister(_TCA8418_REG_KEY_EVENT_A) != 0)
|
|
||||||
count++;
|
|
||||||
// Flush gpio events
|
|
||||||
readRegister(_TCA8418_REG_GPIO_INT_STAT_1);
|
|
||||||
readRegister(_TCA8418_REG_GPIO_INT_STAT_2);
|
|
||||||
readRegister(_TCA8418_REG_GPIO_INT_STAT_3);
|
|
||||||
// Clear INT_STAT register
|
|
||||||
writeRegister(_TCA8418_REG_INT_STAT, 3);
|
|
||||||
return count;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint8_t TCA8418Keyboard::digitalRead(uint8_t pinnum) const
|
|
||||||
{
|
|
||||||
if (pinnum > _TCA8418_COL9)
|
|
||||||
return 0xFF;
|
|
||||||
|
|
||||||
uint8_t reg = _TCA8418_REG_GPIO_DAT_STAT_1 + pinnum / 8;
|
|
||||||
uint8_t mask = (1 << (pinnum % 8));
|
|
||||||
|
|
||||||
// Level 0 = low other = high
|
|
||||||
uint8_t value = readRegister(reg);
|
|
||||||
if (value & mask)
|
|
||||||
return HIGH;
|
|
||||||
return LOW;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool TCA8418Keyboard::digitalWrite(uint8_t pinnum, uint8_t level)
|
|
||||||
{
|
|
||||||
if (pinnum > _TCA8418_COL9)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
uint8_t reg = _TCA8418_REG_GPIO_DAT_OUT_1 + pinnum / 8;
|
|
||||||
uint8_t mask = (1 << (pinnum % 8));
|
|
||||||
|
|
||||||
// Level 0 = low other = high
|
|
||||||
uint8_t value = readRegister(reg);
|
|
||||||
if (level == LOW)
|
|
||||||
value &= ~mask;
|
|
||||||
else
|
|
||||||
value |= mask;
|
|
||||||
writeRegister(reg, value);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool TCA8418Keyboard::pinMode(uint8_t pinnum, uint8_t mode)
|
|
||||||
{
|
|
||||||
if (pinnum > _TCA8418_COL9)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
uint8_t idx = pinnum / 8;
|
|
||||||
uint8_t reg = _TCA8418_REG_GPIO_DIR_1 + idx;
|
|
||||||
uint8_t mask = (1 << (pinnum % 8));
|
|
||||||
|
|
||||||
// Mode 0 = input 1 = output
|
|
||||||
uint8_t value = readRegister(reg);
|
|
||||||
if (mode == OUTPUT)
|
|
||||||
value |= mask;
|
|
||||||
else
|
|
||||||
value &= ~mask;
|
|
||||||
writeRegister(reg, value);
|
|
||||||
|
|
||||||
// Pullup 0 = enabled 1 = disabled
|
|
||||||
reg = _TCA8418_REG_GPIO_PULL_1 + idx;
|
|
||||||
value = readRegister(reg);
|
|
||||||
if (mode == INPUT_PULLUP)
|
|
||||||
value &= ~mask;
|
|
||||||
else
|
|
||||||
value |= mask;
|
|
||||||
writeRegister(reg, value);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool TCA8418Keyboard::pinIRQMode(uint8_t pinnum, uint8_t mode)
|
|
||||||
{
|
|
||||||
if (pinnum > _TCA8418_COL9)
|
|
||||||
return false;
|
|
||||||
if ((mode != RISING) && (mode != FALLING))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
// Mode 0 = falling 1 = rising
|
|
||||||
uint8_t idx = pinnum / 8;
|
|
||||||
uint8_t reg = _TCA8418_REG_GPIO_INT_LVL_1 + idx;
|
|
||||||
uint8_t mask = (1 << (pinnum % 8));
|
|
||||||
|
|
||||||
uint8_t value = readRegister(reg);
|
|
||||||
if (mode == RISING)
|
|
||||||
value |= mask;
|
|
||||||
else
|
|
||||||
value &= ~mask;
|
|
||||||
writeRegister(reg, value);
|
|
||||||
|
|
||||||
// Enable interrupt
|
|
||||||
reg = _TCA8418_REG_GPIO_INT_EN_1 + idx;
|
|
||||||
value = readRegister(reg);
|
|
||||||
value |= mask;
|
|
||||||
writeRegister(reg, value);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void TCA8418Keyboard::enableInterrupts()
|
|
||||||
{
|
|
||||||
uint8_t value = readRegister(_TCA8418_REG_CFG);
|
|
||||||
value |= (_TCA8418_REG_CFG_GPI_IEN | _TCA8418_REG_CFG_KE_IEN);
|
|
||||||
writeRegister(_TCA8418_REG_CFG, value);
|
|
||||||
};
|
|
||||||
|
|
||||||
void TCA8418Keyboard::disableInterrupts()
|
|
||||||
{
|
|
||||||
uint8_t value = readRegister(_TCA8418_REG_CFG);
|
|
||||||
value &= ~(_TCA8418_REG_CFG_GPI_IEN | _TCA8418_REG_CFG_KE_IEN);
|
|
||||||
writeRegister(_TCA8418_REG_CFG, value);
|
|
||||||
};
|
|
||||||
|
|
||||||
void TCA8418Keyboard::enableMatrixOverflow()
|
|
||||||
{
|
|
||||||
uint8_t value = readRegister(_TCA8418_REG_CFG);
|
|
||||||
value |= _TCA8418_REG_CFG_OVR_FLOW_M;
|
|
||||||
writeRegister(_TCA8418_REG_CFG, value);
|
|
||||||
};
|
|
||||||
|
|
||||||
void TCA8418Keyboard::disableMatrixOverflow()
|
|
||||||
{
|
|
||||||
uint8_t value = readRegister(_TCA8418_REG_CFG);
|
|
||||||
value &= ~_TCA8418_REG_CFG_OVR_FLOW_M;
|
|
||||||
writeRegister(_TCA8418_REG_CFG, value);
|
|
||||||
};
|
|
||||||
|
|
||||||
void TCA8418Keyboard::enableDebounce()
|
|
||||||
{
|
|
||||||
writeRegister(_TCA8418_REG_DEBOUNCE_DIS_1, 0x00);
|
|
||||||
writeRegister(_TCA8418_REG_DEBOUNCE_DIS_2, 0x00);
|
|
||||||
writeRegister(_TCA8418_REG_DEBOUNCE_DIS_3, 0x00);
|
|
||||||
}
|
|
||||||
|
|
||||||
void TCA8418Keyboard::disableDebounce()
|
|
||||||
{
|
|
||||||
writeRegister(_TCA8418_REG_DEBOUNCE_DIS_1, 0xFF);
|
|
||||||
writeRegister(_TCA8418_REG_DEBOUNCE_DIS_2, 0xFF);
|
|
||||||
writeRegister(_TCA8418_REG_DEBOUNCE_DIS_3, 0xFF);
|
|
||||||
}
|
|
||||||
|
|
||||||
void TCA8418Keyboard::setBacklight(bool on)
|
void TCA8418Keyboard::setBacklight(bool on)
|
||||||
{
|
{
|
||||||
#ifdef T_DECK_PRO
|
|
||||||
if (on) {
|
if (on) {
|
||||||
digitalWrite(KB_BL_PIN, HIGH);
|
digitalWrite(TCA8418_COL9, HIGH);
|
||||||
} else {
|
} else {
|
||||||
digitalWrite(KB_BL_PIN, LOW);
|
digitalWrite(TCA8418_COL9, LOW);
|
||||||
}
|
|
||||||
#else
|
|
||||||
if (on) {
|
|
||||||
digitalWrite(_TCA8418_COL9, HIGH);
|
|
||||||
} else {
|
|
||||||
digitalWrite(_TCA8418_COL9, LOW);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
uint8_t TCA8418Keyboard::readRegister(uint8_t reg) const
|
|
||||||
{
|
|
||||||
if (m_wire) {
|
|
||||||
m_wire->beginTransmission(m_addr);
|
|
||||||
m_wire->write(reg);
|
|
||||||
m_wire->endTransmission();
|
|
||||||
|
|
||||||
m_wire->requestFrom(m_addr, (uint8_t)1);
|
|
||||||
if (m_wire->available() < 1)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
return m_wire->read();
|
|
||||||
}
|
|
||||||
if (readCallback) {
|
|
||||||
uint8_t data;
|
|
||||||
readCallback(m_addr, reg, &data, 1);
|
|
||||||
return data;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void TCA8418Keyboard::writeRegister(uint8_t reg, uint8_t value)
|
|
||||||
{
|
|
||||||
uint8_t data[2];
|
|
||||||
data[0] = reg;
|
|
||||||
data[1] = value;
|
|
||||||
|
|
||||||
if (m_wire) {
|
|
||||||
m_wire->beginTransmission(m_addr);
|
|
||||||
m_wire->write(data, sizeof(uint8_t) * 2);
|
|
||||||
m_wire->endTransmission();
|
|
||||||
}
|
|
||||||
if (writeCallback) {
|
|
||||||
writeCallback(m_addr, data[0], &(data[1]), 1);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,83 +1,23 @@
|
|||||||
// Based on the MPR121 Keyboard and Adafruit TCA8418 library
|
#include "TCA8418KeyboardBase.h"
|
||||||
#include "configuration.h"
|
|
||||||
#include <Wire.h>
|
|
||||||
|
|
||||||
#define _TCA8418_NONE 0x00
|
/**
|
||||||
#define _TCA8418_REBOOT 0x90
|
* @brief 3x4 keypad with 3 columns and 4 rows
|
||||||
#define _TCA8418_LEFT 0xb4
|
*/
|
||||||
#define _TCA8418_UP 0xb5
|
class TCA8418Keyboard : public TCA8418KeyboardBase
|
||||||
#define _TCA8418_DOWN 0xb6
|
|
||||||
#define _TCA8418_RIGHT 0xb7
|
|
||||||
#define _TCA8418_ESC 0x1b
|
|
||||||
#define _TCA8418_BSP 0x08
|
|
||||||
#define _TCA8418_SELECT 0x0d
|
|
||||||
|
|
||||||
class TCA8418Keyboard
|
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
typedef uint8_t (*i2c_com_fptr_t)(uint8_t dev_addr, uint8_t reg_addr, uint8_t *data, uint8_t len);
|
TCA8418Keyboard();
|
||||||
|
void reset(void) override;
|
||||||
|
void setBacklight(bool on) override;
|
||||||
|
|
||||||
enum KeyState { Init = 0, Idle, Held, Busy };
|
protected:
|
||||||
|
void pressed(uint8_t key) override;
|
||||||
|
void released(void) override;
|
||||||
|
|
||||||
KeyState state;
|
|
||||||
int8_t last_key;
|
int8_t last_key;
|
||||||
int8_t next_key;
|
int8_t next_key;
|
||||||
bool should_backspace;
|
|
||||||
uint32_t last_tap;
|
uint32_t last_tap;
|
||||||
uint8_t char_idx;
|
uint8_t char_idx;
|
||||||
int32_t tap_interval;
|
int32_t tap_interval;
|
||||||
bool backlight_on;
|
bool should_backspace;
|
||||||
|
|
||||||
String queue;
|
|
||||||
|
|
||||||
TCA8418Keyboard();
|
|
||||||
|
|
||||||
void begin(uint8_t addr = XPOWERS_AXP192_AXP2101_ADDRESS, TwoWire *wire = &Wire);
|
|
||||||
void begin(i2c_com_fptr_t r, i2c_com_fptr_t w, uint8_t addr = XPOWERS_AXP192_AXP2101_ADDRESS);
|
|
||||||
|
|
||||||
void reset(void);
|
|
||||||
// Configure the size of the keypad.
|
|
||||||
// All other rows and columns are set as inputs.
|
|
||||||
bool matrix(uint8_t rows, uint8_t columns);
|
|
||||||
|
|
||||||
// Flush all events in the FIFO buffer + GPIO events.
|
|
||||||
uint8_t flush(void);
|
|
||||||
|
|
||||||
// Key events available in the internal FIFO buffer.
|
|
||||||
uint8_t keyCount(void) const;
|
|
||||||
|
|
||||||
void trigger(void);
|
|
||||||
void pressed(uint8_t key);
|
|
||||||
void released(void);
|
|
||||||
bool hasEvent(void);
|
|
||||||
char dequeueEvent(void);
|
|
||||||
void queueEvent(char);
|
|
||||||
|
|
||||||
uint8_t digitalRead(uint8_t pinnum) const;
|
|
||||||
bool digitalWrite(uint8_t pinnum, uint8_t level);
|
|
||||||
bool pinMode(uint8_t pinnum, uint8_t mode);
|
|
||||||
bool pinIRQMode(uint8_t pinnum, uint8_t mode); // MODE FALLING or RISING
|
|
||||||
|
|
||||||
// enable / disable interrupts for matrix and GPI pins
|
|
||||||
void enableInterrupts();
|
|
||||||
void disableInterrupts();
|
|
||||||
|
|
||||||
// ignore key events when FIFO buffer is full or not.
|
|
||||||
void enableMatrixOverflow();
|
|
||||||
void disableMatrixOverflow();
|
|
||||||
|
|
||||||
// debounce keys.
|
|
||||||
void enableDebounce();
|
|
||||||
void disableDebounce();
|
|
||||||
|
|
||||||
void setBacklight(bool on);
|
|
||||||
|
|
||||||
uint8_t readRegister(uint8_t reg) const;
|
|
||||||
void writeRegister(uint8_t reg, uint8_t value);
|
|
||||||
|
|
||||||
private:
|
|
||||||
TwoWire *m_wire;
|
|
||||||
uint8_t m_addr;
|
|
||||||
i2c_com_fptr_t readCallback;
|
|
||||||
i2c_com_fptr_t writeCallback;
|
|
||||||
};
|
};
|
||||||
|
372
src/input/TCA8418KeyboardBase.cpp
Normal file
372
src/input/TCA8418KeyboardBase.cpp
Normal file
@ -0,0 +1,372 @@
|
|||||||
|
// Based on the MPR121 Keyboard and Adafruit TCA8418 library
|
||||||
|
|
||||||
|
#include "TCA8418KeyboardBase.h"
|
||||||
|
#include "configuration.h"
|
||||||
|
|
||||||
|
#include <Arduino.h>
|
||||||
|
|
||||||
|
// FIELDS CONFIG REGISTER 1
|
||||||
|
#define _TCA8418_REG_CFG_AI 0x80 // Auto-increment for read/write
|
||||||
|
#define _TCA8418_REG_CFG_GPI_E_CGF 0x40 // Event mode config
|
||||||
|
#define _TCA8418_REG_CFG_OVR_FLOW_M 0x20 // Overflow mode enable
|
||||||
|
#define _TCA8418_REG_CFG_INT_CFG 0x10 // Interrupt config
|
||||||
|
#define _TCA8418_REG_CFG_OVR_FLOW_IEN 0x08 // Overflow interrupt enable
|
||||||
|
#define _TCA8418_REG_CFG_K_LCK_IEN 0x04 // Keypad lock interrupt enable
|
||||||
|
#define _TCA8418_REG_CFG_GPI_IEN 0x02 // GPI interrupt enable
|
||||||
|
#define _TCA8418_REG_CFG_KE_IEN 0x01 // Key events interrupt enable
|
||||||
|
|
||||||
|
// FIELDS INT_STAT REGISTER 2
|
||||||
|
#define _TCA8418_REG_STAT_CAD_INT 0x10 // Ctrl-alt-del seq status
|
||||||
|
#define _TCA8418_REG_STAT_OVR_FLOW_INT 0x08 // Overflow interrupt status
|
||||||
|
#define _TCA8418_REG_STAT_K_LCK_INT 0x04 // Key lock interrupt status
|
||||||
|
#define _TCA8418_REG_STAT_GPI_INT 0x02 // GPI interrupt status
|
||||||
|
#define _TCA8418_REG_STAT_K_INT 0x01 // Key events interrupt status
|
||||||
|
|
||||||
|
// FIELDS KEY_LCK_EC REGISTER 3
|
||||||
|
#define _TCA8418_REG_LCK_EC_K_LCK_EN 0x40 // Key lock enable
|
||||||
|
#define _TCA8418_REG_LCK_EC_LCK_2 0x20 // Keypad lock status 2
|
||||||
|
#define _TCA8418_REG_LCK_EC_LCK_1 0x10 // Keypad lock status 1
|
||||||
|
#define _TCA8418_REG_LCK_EC_KLEC_3 0x08 // Key event count bit 3
|
||||||
|
#define _TCA8418_REG_LCK_EC_KLEC_2 0x04 // Key event count bit 2
|
||||||
|
#define _TCA8418_REG_LCK_EC_KLEC_1 0x02 // Key event count bit 1
|
||||||
|
#define _TCA8418_REG_LCK_EC_KLEC_0 0x01 // Key event count bit 0
|
||||||
|
|
||||||
|
TCA8418KeyboardBase::TCA8418KeyboardBase(uint8_t rows, uint8_t columns)
|
||||||
|
: rows(rows), columns(columns), state(Init), queue(""), m_wire(nullptr), m_addr(0), readCallback(nullptr),
|
||||||
|
writeCallback(nullptr)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void TCA8418KeyboardBase::begin(uint8_t addr, TwoWire *wire)
|
||||||
|
{
|
||||||
|
m_addr = addr;
|
||||||
|
m_wire = wire;
|
||||||
|
m_wire->begin();
|
||||||
|
reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
void TCA8418KeyboardBase::begin(i2c_com_fptr_t r, i2c_com_fptr_t w, uint8_t addr)
|
||||||
|
{
|
||||||
|
m_addr = addr;
|
||||||
|
m_wire = nullptr;
|
||||||
|
writeCallback = w;
|
||||||
|
readCallback = r;
|
||||||
|
reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
void TCA8418KeyboardBase::reset()
|
||||||
|
{
|
||||||
|
LOG_DEBUG("TCA8418 Reset");
|
||||||
|
// GPIO
|
||||||
|
// set default all GIO pins to INPUT
|
||||||
|
writeRegister(TCA8418_REG_GPIO_DIR_1, 0x00);
|
||||||
|
writeRegister(TCA8418_REG_GPIO_DIR_2, 0x00);
|
||||||
|
writeRegister(TCA8418_REG_GPIO_DIR_3, 0x00);
|
||||||
|
|
||||||
|
// add all pins to key events
|
||||||
|
writeRegister(TCA8418_REG_GPI_EM_1, 0xFF);
|
||||||
|
writeRegister(TCA8418_REG_GPI_EM_2, 0xFF);
|
||||||
|
writeRegister(TCA8418_REG_GPI_EM_3, 0xFF);
|
||||||
|
|
||||||
|
// set all pins to FALLING interrupts
|
||||||
|
writeRegister(TCA8418_REG_GPIO_INT_LVL_1, 0x00);
|
||||||
|
writeRegister(TCA8418_REG_GPIO_INT_LVL_2, 0x00);
|
||||||
|
writeRegister(TCA8418_REG_GPIO_INT_LVL_3, 0x00);
|
||||||
|
|
||||||
|
// add all pins to interrupts
|
||||||
|
writeRegister(TCA8418_REG_GPIO_INT_EN_1, 0xFF);
|
||||||
|
writeRegister(TCA8418_REG_GPIO_INT_EN_2, 0xFF);
|
||||||
|
writeRegister(TCA8418_REG_GPIO_INT_EN_3, 0xFF);
|
||||||
|
|
||||||
|
// Set keyboard matrix size
|
||||||
|
matrix(rows, columns);
|
||||||
|
enableDebounce();
|
||||||
|
flush();
|
||||||
|
state = Idle;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool TCA8418KeyboardBase::matrix(uint8_t rows, uint8_t columns)
|
||||||
|
{
|
||||||
|
if (rows < 1 || rows > 8 || columns < 1 || columns > 10)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// Setup the keypad matrix.
|
||||||
|
uint8_t mask = 0x00;
|
||||||
|
for (int r = 0; r < rows; r++) {
|
||||||
|
mask <<= 1;
|
||||||
|
mask |= 1;
|
||||||
|
}
|
||||||
|
writeRegister(TCA8418_REG_KP_GPIO_1, mask);
|
||||||
|
|
||||||
|
mask = 0x00;
|
||||||
|
for (int c = 0; c < columns && c < 8; c++) {
|
||||||
|
mask <<= 1;
|
||||||
|
mask |= 1;
|
||||||
|
}
|
||||||
|
writeRegister(TCA8418_REG_KP_GPIO_2, mask);
|
||||||
|
|
||||||
|
if (columns > 8) {
|
||||||
|
if (columns == 9)
|
||||||
|
mask = 0x01;
|
||||||
|
else
|
||||||
|
mask = 0x03;
|
||||||
|
writeRegister(TCA8418_REG_KP_GPIO_3, mask);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t TCA8418KeyboardBase::keyCount() const
|
||||||
|
{
|
||||||
|
uint8_t eventCount = readRegister(TCA8418_REG_KEY_LCK_EC);
|
||||||
|
eventCount &= 0x0F; // lower 4 bits only
|
||||||
|
return eventCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool TCA8418KeyboardBase::hasEvent() const
|
||||||
|
{
|
||||||
|
return queue.length() > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void TCA8418KeyboardBase::queueEvent(char next)
|
||||||
|
{
|
||||||
|
if (next == NONE) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
queue.concat(next);
|
||||||
|
}
|
||||||
|
|
||||||
|
char TCA8418KeyboardBase::dequeueEvent()
|
||||||
|
{
|
||||||
|
if (queue.length() < 1) {
|
||||||
|
return NONE;
|
||||||
|
}
|
||||||
|
char next = queue.charAt(0);
|
||||||
|
queue.remove(0, 1);
|
||||||
|
return next;
|
||||||
|
}
|
||||||
|
|
||||||
|
void TCA8418KeyboardBase::trigger()
|
||||||
|
{
|
||||||
|
if (keyCount() == 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (state != Init) {
|
||||||
|
// Read the key register
|
||||||
|
uint8_t k = readRegister(TCA8418_REG_KEY_EVENT_A);
|
||||||
|
uint8_t key = k & 0x7F;
|
||||||
|
if (k & 0x80) {
|
||||||
|
if (state == Idle)
|
||||||
|
pressed(key);
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
if (state == Held) {
|
||||||
|
released();
|
||||||
|
}
|
||||||
|
state = Idle;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
reset();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void TCA8418KeyboardBase::pressed(uint8_t key)
|
||||||
|
{
|
||||||
|
// must be defined in derived class
|
||||||
|
LOG_ERROR("pressed() not implemented in derived class");
|
||||||
|
}
|
||||||
|
|
||||||
|
void TCA8418KeyboardBase::released()
|
||||||
|
{
|
||||||
|
// must be defined in derived class
|
||||||
|
LOG_ERROR("released() not implemented in derived class");
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t TCA8418KeyboardBase::flush()
|
||||||
|
{
|
||||||
|
// Flush key events
|
||||||
|
uint8_t count = 0;
|
||||||
|
while (readRegister(TCA8418_REG_KEY_EVENT_A) != 0)
|
||||||
|
count++;
|
||||||
|
|
||||||
|
// Flush gpio events
|
||||||
|
readRegister(TCA8418_REG_GPIO_INT_STAT_1);
|
||||||
|
readRegister(TCA8418_REG_GPIO_INT_STAT_2);
|
||||||
|
readRegister(TCA8418_REG_GPIO_INT_STAT_3);
|
||||||
|
|
||||||
|
// Clear INT_STAT register
|
||||||
|
writeRegister(TCA8418_REG_INT_STAT, 3);
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t TCA8418KeyboardBase::digitalRead(uint8_t pinnum) const
|
||||||
|
{
|
||||||
|
if (pinnum > TCA8418_COL9)
|
||||||
|
return 0xFF;
|
||||||
|
|
||||||
|
uint8_t reg = TCA8418_REG_GPIO_DAT_STAT_1 + pinnum / 8;
|
||||||
|
uint8_t mask = (1 << (pinnum % 8));
|
||||||
|
|
||||||
|
// Level 0 = low other = high
|
||||||
|
uint8_t value = readRegister(reg);
|
||||||
|
if (value & mask)
|
||||||
|
return HIGH;
|
||||||
|
return LOW;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool TCA8418KeyboardBase::digitalWrite(uint8_t pinnum, uint8_t level)
|
||||||
|
{
|
||||||
|
if (pinnum > TCA8418_COL9)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
uint8_t reg = TCA8418_REG_GPIO_DAT_OUT_1 + pinnum / 8;
|
||||||
|
uint8_t mask = (1 << (pinnum % 8));
|
||||||
|
|
||||||
|
// Level 0 = low other = high
|
||||||
|
uint8_t value = readRegister(reg);
|
||||||
|
if (level == LOW)
|
||||||
|
value &= ~mask;
|
||||||
|
else
|
||||||
|
value |= mask;
|
||||||
|
writeRegister(reg, value);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool TCA8418KeyboardBase::pinMode(uint8_t pinnum, uint8_t mode)
|
||||||
|
{
|
||||||
|
if (pinnum > TCA8418_COL9)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
uint8_t idx = pinnum / 8;
|
||||||
|
uint8_t reg = TCA8418_REG_GPIO_DIR_1 + idx;
|
||||||
|
uint8_t mask = (1 << (pinnum % 8));
|
||||||
|
|
||||||
|
// Mode 0 = input 1 = output
|
||||||
|
uint8_t value = readRegister(reg);
|
||||||
|
if (mode == OUTPUT)
|
||||||
|
value |= mask;
|
||||||
|
else
|
||||||
|
value &= ~mask;
|
||||||
|
writeRegister(reg, value);
|
||||||
|
|
||||||
|
// Pullup 0 = enabled 1 = disabled
|
||||||
|
reg = TCA8418_REG_GPIO_PULL_1 + idx;
|
||||||
|
value = readRegister(reg);
|
||||||
|
if (mode == INPUT_PULLUP)
|
||||||
|
value &= ~mask;
|
||||||
|
else
|
||||||
|
value |= mask;
|
||||||
|
writeRegister(reg, value);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool TCA8418KeyboardBase::pinIRQMode(uint8_t pinnum, uint8_t mode)
|
||||||
|
{
|
||||||
|
if (pinnum > TCA8418_COL9)
|
||||||
|
return false;
|
||||||
|
if ((mode != RISING) && (mode != FALLING))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// Mode 0 = falling 1 = rising
|
||||||
|
uint8_t idx = pinnum / 8;
|
||||||
|
uint8_t reg = TCA8418_REG_GPIO_INT_LVL_1 + idx;
|
||||||
|
uint8_t mask = (1 << (pinnum % 8));
|
||||||
|
|
||||||
|
uint8_t value = readRegister(reg);
|
||||||
|
if (mode == RISING)
|
||||||
|
value |= mask;
|
||||||
|
else
|
||||||
|
value &= ~mask;
|
||||||
|
writeRegister(reg, value);
|
||||||
|
|
||||||
|
// Enable interrupt
|
||||||
|
reg = TCA8418_REG_GPIO_INT_EN_1 + idx;
|
||||||
|
value = readRegister(reg);
|
||||||
|
value |= mask;
|
||||||
|
writeRegister(reg, value);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void TCA8418KeyboardBase::enableInterrupts()
|
||||||
|
{
|
||||||
|
uint8_t value = readRegister(TCA8418_REG_CFG);
|
||||||
|
value |= (_TCA8418_REG_CFG_GPI_IEN | _TCA8418_REG_CFG_KE_IEN);
|
||||||
|
writeRegister(TCA8418_REG_CFG, value);
|
||||||
|
};
|
||||||
|
|
||||||
|
void TCA8418KeyboardBase::disableInterrupts()
|
||||||
|
{
|
||||||
|
uint8_t value = readRegister(TCA8418_REG_CFG);
|
||||||
|
value &= ~(_TCA8418_REG_CFG_GPI_IEN | _TCA8418_REG_CFG_KE_IEN);
|
||||||
|
writeRegister(TCA8418_REG_CFG, value);
|
||||||
|
};
|
||||||
|
|
||||||
|
void TCA8418KeyboardBase::enableMatrixOverflow()
|
||||||
|
{
|
||||||
|
uint8_t value = readRegister(TCA8418_REG_CFG);
|
||||||
|
value |= _TCA8418_REG_CFG_OVR_FLOW_M;
|
||||||
|
writeRegister(TCA8418_REG_CFG, value);
|
||||||
|
};
|
||||||
|
|
||||||
|
void TCA8418KeyboardBase::disableMatrixOverflow()
|
||||||
|
{
|
||||||
|
uint8_t value = readRegister(TCA8418_REG_CFG);
|
||||||
|
value &= ~_TCA8418_REG_CFG_OVR_FLOW_M;
|
||||||
|
writeRegister(TCA8418_REG_CFG, value);
|
||||||
|
};
|
||||||
|
|
||||||
|
void TCA8418KeyboardBase::enableDebounce()
|
||||||
|
{
|
||||||
|
writeRegister(TCA8418_REG_DEBOUNCE_DIS_1, 0x00);
|
||||||
|
writeRegister(TCA8418_REG_DEBOUNCE_DIS_2, 0x00);
|
||||||
|
writeRegister(TCA8418_REG_DEBOUNCE_DIS_3, 0x00);
|
||||||
|
}
|
||||||
|
|
||||||
|
void TCA8418KeyboardBase::disableDebounce()
|
||||||
|
{
|
||||||
|
writeRegister(TCA8418_REG_DEBOUNCE_DIS_1, 0xFF);
|
||||||
|
writeRegister(TCA8418_REG_DEBOUNCE_DIS_2, 0xFF);
|
||||||
|
writeRegister(TCA8418_REG_DEBOUNCE_DIS_3, 0xFF);
|
||||||
|
}
|
||||||
|
|
||||||
|
void TCA8418KeyboardBase::setBacklight(bool on) {}
|
||||||
|
|
||||||
|
uint8_t TCA8418KeyboardBase::readRegister(uint8_t reg) const
|
||||||
|
{
|
||||||
|
if (m_wire) {
|
||||||
|
m_wire->beginTransmission(m_addr);
|
||||||
|
m_wire->write(reg);
|
||||||
|
m_wire->endTransmission();
|
||||||
|
|
||||||
|
m_wire->requestFrom(m_addr, (uint8_t)1);
|
||||||
|
if (m_wire->available() < 1)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
return m_wire->read();
|
||||||
|
}
|
||||||
|
if (readCallback) {
|
||||||
|
uint8_t data;
|
||||||
|
readCallback(m_addr, reg, &data, 1);
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void TCA8418KeyboardBase::writeRegister(uint8_t reg, uint8_t value)
|
||||||
|
{
|
||||||
|
uint8_t data[2];
|
||||||
|
data[0] = reg;
|
||||||
|
data[1] = value;
|
||||||
|
|
||||||
|
if (m_wire) {
|
||||||
|
m_wire->beginTransmission(m_addr);
|
||||||
|
m_wire->write(data, sizeof(uint8_t) * 2);
|
||||||
|
m_wire->endTransmission();
|
||||||
|
}
|
||||||
|
if (writeCallback) {
|
||||||
|
writeCallback(m_addr, data[0], &(data[1]), 1);
|
||||||
|
}
|
||||||
|
}
|
170
src/input/TCA8418KeyboardBase.h
Normal file
170
src/input/TCA8418KeyboardBase.h
Normal file
@ -0,0 +1,170 @@
|
|||||||
|
// Based on the MPR121 Keyboard and Adafruit TCA8418 library
|
||||||
|
#include "configuration.h"
|
||||||
|
#include <Wire.h>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief TCA8418KeyboardBase is the base class for TCA8418 keyboard handling.
|
||||||
|
* It provides basic functionality for reading key events, managing the keyboard matrix,
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
class TCA8418KeyboardBase
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
enum TCA8418Key : uint8_t {
|
||||||
|
NONE = 0x00,
|
||||||
|
BSP = 0x08,
|
||||||
|
TAB = 0x09,
|
||||||
|
SELECT = 0x0d,
|
||||||
|
ESC = 0x1b,
|
||||||
|
REBOOT = 0x90,
|
||||||
|
LEFT = 0xb4,
|
||||||
|
UP = 0xb5,
|
||||||
|
DOWN = 0xb6,
|
||||||
|
RIGHT = 0xb7,
|
||||||
|
BT_TOGGLE = 0xAA,
|
||||||
|
GPS_TOGGLE = 0x9E,
|
||||||
|
MUTE_TOGGLE = 0xAC,
|
||||||
|
SEND_PING = 0xAF,
|
||||||
|
BL_TOGGLE = 0xAB
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef uint8_t (*i2c_com_fptr_t)(uint8_t dev_addr, uint8_t reg_addr, uint8_t *data, uint8_t len);
|
||||||
|
|
||||||
|
TCA8418KeyboardBase(uint8_t rows, uint8_t columns);
|
||||||
|
|
||||||
|
virtual void begin(uint8_t addr = TCA8418_KB_ADDR, TwoWire *wire = &Wire);
|
||||||
|
virtual void begin(i2c_com_fptr_t r, i2c_com_fptr_t w, uint8_t addr = TCA8418_KB_ADDR);
|
||||||
|
|
||||||
|
virtual void reset(void);
|
||||||
|
virtual void trigger(void);
|
||||||
|
|
||||||
|
virtual void setBacklight(bool on);
|
||||||
|
|
||||||
|
// Key events available
|
||||||
|
virtual bool hasEvent(void) const;
|
||||||
|
virtual char dequeueEvent(void);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
enum KeyState { Init, Idle, Held, Busy };
|
||||||
|
|
||||||
|
enum TCA8418Register : uint8_t {
|
||||||
|
TCA8418_REG_RESERVED = 0x00,
|
||||||
|
TCA8418_REG_CFG = 0x01,
|
||||||
|
TCA8418_REG_INT_STAT = 0x02,
|
||||||
|
TCA8418_REG_KEY_LCK_EC = 0x03,
|
||||||
|
TCA8418_REG_KEY_EVENT_A = 0x04,
|
||||||
|
TCA8418_REG_KEY_EVENT_B = 0x05,
|
||||||
|
TCA8418_REG_KEY_EVENT_C = 0x06,
|
||||||
|
TCA8418_REG_KEY_EVENT_D = 0x07,
|
||||||
|
TCA8418_REG_KEY_EVENT_E = 0x08,
|
||||||
|
TCA8418_REG_KEY_EVENT_F = 0x09,
|
||||||
|
TCA8418_REG_KEY_EVENT_G = 0x0A,
|
||||||
|
TCA8418_REG_KEY_EVENT_H = 0x0B,
|
||||||
|
TCA8418_REG_KEY_EVENT_I = 0x0C,
|
||||||
|
TCA8418_REG_KEY_EVENT_J = 0x0D,
|
||||||
|
TCA8418_REG_KP_LCK_TIMER = 0x0E,
|
||||||
|
TCA8418_REG_UNLOCK_1 = 0x0F,
|
||||||
|
TCA8418_REG_UNLOCK_2 = 0x10,
|
||||||
|
TCA8418_REG_GPIO_INT_STAT_1 = 0x11,
|
||||||
|
TCA8418_REG_GPIO_INT_STAT_2 = 0x12,
|
||||||
|
TCA8418_REG_GPIO_INT_STAT_3 = 0x13,
|
||||||
|
TCA8418_REG_GPIO_DAT_STAT_1 = 0x14,
|
||||||
|
TCA8418_REG_GPIO_DAT_STAT_2 = 0x15,
|
||||||
|
TCA8418_REG_GPIO_DAT_STAT_3 = 0x16,
|
||||||
|
TCA8418_REG_GPIO_DAT_OUT_1 = 0x17,
|
||||||
|
TCA8418_REG_GPIO_DAT_OUT_2 = 0x18,
|
||||||
|
TCA8418_REG_GPIO_DAT_OUT_3 = 0x19,
|
||||||
|
TCA8418_REG_GPIO_INT_EN_1 = 0x1A,
|
||||||
|
TCA8418_REG_GPIO_INT_EN_2 = 0x1B,
|
||||||
|
TCA8418_REG_GPIO_INT_EN_3 = 0x1C,
|
||||||
|
TCA8418_REG_KP_GPIO_1 = 0x1D,
|
||||||
|
TCA8418_REG_KP_GPIO_2 = 0x1E,
|
||||||
|
TCA8418_REG_KP_GPIO_3 = 0x1F,
|
||||||
|
TCA8418_REG_GPI_EM_1 = 0x20,
|
||||||
|
TCA8418_REG_GPI_EM_2 = 0x21,
|
||||||
|
TCA8418_REG_GPI_EM_3 = 0x22,
|
||||||
|
TCA8418_REG_GPIO_DIR_1 = 0x23,
|
||||||
|
TCA8418_REG_GPIO_DIR_2 = 0x24,
|
||||||
|
TCA8418_REG_GPIO_DIR_3 = 0x25,
|
||||||
|
TCA8418_REG_GPIO_INT_LVL_1 = 0x26,
|
||||||
|
TCA8418_REG_GPIO_INT_LVL_2 = 0x27,
|
||||||
|
TCA8418_REG_GPIO_INT_LVL_3 = 0x28,
|
||||||
|
TCA8418_REG_DEBOUNCE_DIS_1 = 0x29,
|
||||||
|
TCA8418_REG_DEBOUNCE_DIS_2 = 0x2A,
|
||||||
|
TCA8418_REG_DEBOUNCE_DIS_3 = 0x2B,
|
||||||
|
TCA8418_REG_GPIO_PULL_1 = 0x2C,
|
||||||
|
TCA8418_REG_GPIO_PULL_2 = 0x2D,
|
||||||
|
TCA8418_REG_GPIO_PULL_3 = 0x2E
|
||||||
|
};
|
||||||
|
|
||||||
|
// Pin IDs for matrix rows/columns
|
||||||
|
enum TCA8418PinId : uint8_t {
|
||||||
|
TCA8418_ROW0, // Pin ID for row 0
|
||||||
|
TCA8418_ROW1, // Pin ID for row 1
|
||||||
|
TCA8418_ROW2, // Pin ID for row 2
|
||||||
|
TCA8418_ROW3, // Pin ID for row 3
|
||||||
|
TCA8418_ROW4, // Pin ID for row 4
|
||||||
|
TCA8418_ROW5, // Pin ID for row 5
|
||||||
|
TCA8418_ROW6, // Pin ID for row 6
|
||||||
|
TCA8418_ROW7, // Pin ID for row 7
|
||||||
|
TCA8418_COL0, // Pin ID for column 0
|
||||||
|
TCA8418_COL1, // Pin ID for column 1
|
||||||
|
TCA8418_COL2, // Pin ID for column 2
|
||||||
|
TCA8418_COL3, // Pin ID for column 3
|
||||||
|
TCA8418_COL4, // Pin ID for column 4
|
||||||
|
TCA8418_COL5, // Pin ID for column 5
|
||||||
|
TCA8418_COL6, // Pin ID for column 6
|
||||||
|
TCA8418_COL7, // Pin ID for column 7
|
||||||
|
TCA8418_COL8, // Pin ID for column 8
|
||||||
|
TCA8418_COL9 // Pin ID for column 9
|
||||||
|
};
|
||||||
|
|
||||||
|
virtual void pressed(uint8_t key);
|
||||||
|
virtual void released(void);
|
||||||
|
|
||||||
|
virtual void queueEvent(char);
|
||||||
|
|
||||||
|
virtual ~TCA8418KeyboardBase() {}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
// Set the size of the keypad matrix
|
||||||
|
// All other rows and columns are set as inputs.
|
||||||
|
bool matrix(uint8_t rows, uint8_t columns);
|
||||||
|
|
||||||
|
uint8_t keyCount(void) const;
|
||||||
|
|
||||||
|
// Flush all events in the FIFO buffer + GPIO events.
|
||||||
|
uint8_t flush(void);
|
||||||
|
|
||||||
|
// debounce keys.
|
||||||
|
void enableDebounce();
|
||||||
|
void disableDebounce();
|
||||||
|
|
||||||
|
// enable / disable interrupts for matrix and GPI pins
|
||||||
|
void enableInterrupts();
|
||||||
|
void disableInterrupts();
|
||||||
|
|
||||||
|
// ignore key events when FIFO buffer is full or not.
|
||||||
|
void enableMatrixOverflow();
|
||||||
|
void disableMatrixOverflow();
|
||||||
|
|
||||||
|
uint8_t digitalRead(uint8_t pinnum) const;
|
||||||
|
bool digitalWrite(uint8_t pinnum, uint8_t level);
|
||||||
|
bool pinMode(uint8_t pinnum, uint8_t mode);
|
||||||
|
bool pinIRQMode(uint8_t pinnum, uint8_t mode); // MODE FALLING or RISING
|
||||||
|
uint8_t readRegister(uint8_t reg) const;
|
||||||
|
void writeRegister(uint8_t reg, uint8_t value);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
uint8_t rows;
|
||||||
|
uint8_t columns;
|
||||||
|
KeyState state;
|
||||||
|
String queue;
|
||||||
|
|
||||||
|
private:
|
||||||
|
TwoWire *m_wire;
|
||||||
|
uint8_t m_addr;
|
||||||
|
i2c_com_fptr_t readCallback;
|
||||||
|
i2c_com_fptr_t writeCallback;
|
||||||
|
};
|
196
src/input/TDeckProKeyboard.cpp
Normal file
196
src/input/TDeckProKeyboard.cpp
Normal file
@ -0,0 +1,196 @@
|
|||||||
|
#if defined(T_DECK_PRO)
|
||||||
|
|
||||||
|
#include "TDeckProKeyboard.h"
|
||||||
|
|
||||||
|
#define _TCA8418_COLS 10
|
||||||
|
#define _TCA8418_ROWS 4
|
||||||
|
#define _TCA8418_NUM_KEYS 35
|
||||||
|
|
||||||
|
#define _TCA8418_MULTI_TAP_THRESHOLD 1500
|
||||||
|
|
||||||
|
using Key = TCA8418KeyboardBase::TCA8418Key;
|
||||||
|
|
||||||
|
constexpr uint8_t modifierRightShiftKey = 31 - 1; // keynum -1
|
||||||
|
constexpr uint8_t modifierRightShift = 0b0001;
|
||||||
|
constexpr uint8_t modifierLeftShiftKey = 35 - 1;
|
||||||
|
constexpr uint8_t modifierLeftShift = 0b0001;
|
||||||
|
constexpr uint8_t modifierSymKey = 32 - 1;
|
||||||
|
constexpr uint8_t modifierSym = 0b0010;
|
||||||
|
constexpr uint8_t modifierAltKey = 30 - 1;
|
||||||
|
constexpr uint8_t modifierAlt = 0b0100;
|
||||||
|
|
||||||
|
// Num chars per key, Modulus for rotating through characters
|
||||||
|
static uint8_t TDeckProTapMod[_TCA8418_NUM_KEYS] = {5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
|
||||||
|
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5};
|
||||||
|
|
||||||
|
static unsigned char TDeckProTapMap[_TCA8418_NUM_KEYS][5] = {
|
||||||
|
{'p', 'P', '@', 0x00, Key::SEND_PING},
|
||||||
|
{'o', 'O', '+'},
|
||||||
|
{'i', 'I', '-'},
|
||||||
|
{'u', 'U', '_'},
|
||||||
|
{'y', 'Y', ')'},
|
||||||
|
{'t', 'T', '(', 0x00, Key::TAB},
|
||||||
|
{'r', 'R', '3'},
|
||||||
|
{'e', 'E', '2', 0x00, Key::UP},
|
||||||
|
{'w', 'W', '1'},
|
||||||
|
{'q', 'Q', '#', 0x00, Key::ESC}, // p, o, i, u, y, t, r, e, w, q
|
||||||
|
{Key::BSP, 0x00, 0x00},
|
||||||
|
{'l', 'L', '"'},
|
||||||
|
{'k', 'K', '\''},
|
||||||
|
{'j', 'J', ';'},
|
||||||
|
{'h', 'H', ':'},
|
||||||
|
{'g', 'G', '/', 0x00, Key::GPS_TOGGLE},
|
||||||
|
{'f', 'F', '6', 0x00, Key::RIGHT},
|
||||||
|
{'d', 'D', '5'},
|
||||||
|
{'s', 'S', '4', 0x00, Key::LEFT},
|
||||||
|
{'a', 'A', '*'}, // bsp, l, k, j, h, g, f, d, s, a
|
||||||
|
{0x0d, 0x00, 0x00},
|
||||||
|
{'$', 0x00, 0x00},
|
||||||
|
{'m', 'M', '.', 0x00, Key::MUTE_TOGGLE},
|
||||||
|
{'n', 'N', ','},
|
||||||
|
{'b', 'B', '!', 0x00, Key::BL_TOGGLE},
|
||||||
|
{'v', 'V', '?'},
|
||||||
|
{'c', 'C', '9'},
|
||||||
|
{'x', 'X', '8', 0x00, Key::DOWN},
|
||||||
|
{'z', 'Z', '7'},
|
||||||
|
{0x00, 0x00, 0x00}, // Ent, $, m, n, b, v, c, x, z, alt
|
||||||
|
{0x00, 0x00, 0x00},
|
||||||
|
{0x00, 0x00, 0x00},
|
||||||
|
{0x20, 0x00, 0x00},
|
||||||
|
{0x00, 0x00, 0x00},
|
||||||
|
{0x00, 0x00, 0x00} // R_Shift, sym, space, mic, L_Shift
|
||||||
|
};
|
||||||
|
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void TDeckProKeyboard::reset()
|
||||||
|
{
|
||||||
|
TCA8418KeyboardBase::reset();
|
||||||
|
pinMode(KB_BL_PIN, OUTPUT);
|
||||||
|
setBacklight(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
// handle multi-key presses (shift and alt)
|
||||||
|
void TDeckProKeyboard::trigger()
|
||||||
|
{
|
||||||
|
uint8_t count = keyCount();
|
||||||
|
if (count == 0)
|
||||||
|
return;
|
||||||
|
for (uint8_t i = 0; i < count; ++i) {
|
||||||
|
uint8_t k = readRegister(TCA8418_REG_KEY_EVENT_A + i);
|
||||||
|
uint8_t key = k & 0x7F;
|
||||||
|
if (k & 0x80) {
|
||||||
|
pressed(key);
|
||||||
|
} else {
|
||||||
|
released();
|
||||||
|
state = Idle;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void TDeckProKeyboard::pressed(uint8_t key)
|
||||||
|
{
|
||||||
|
if (state == Init || state == Busy) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
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) {
|
||||||
|
return; // Invalid key
|
||||||
|
}
|
||||||
|
|
||||||
|
next_key = row * _TCA8418_COLS + col;
|
||||||
|
state = Held;
|
||||||
|
|
||||||
|
uint32_t now = millis();
|
||||||
|
tap_interval = now - last_tap;
|
||||||
|
|
||||||
|
updateModifierFlag(next_key);
|
||||||
|
if (isModifierKey(next_key)) {
|
||||||
|
last_modifier_time = now;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tap_interval < 0) {
|
||||||
|
last_tap = 0;
|
||||||
|
state = Busy;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (next_key != last_key || tap_interval > _TCA8418_MULTI_TAP_THRESHOLD) {
|
||||||
|
char_idx = 0;
|
||||||
|
} else {
|
||||||
|
char_idx += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
last_key = next_key;
|
||||||
|
last_tap = now;
|
||||||
|
}
|
||||||
|
|
||||||
|
void TDeckProKeyboard::released()
|
||||||
|
{
|
||||||
|
if (state != Held) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (last_key < 0 || last_key >= _TCA8418_NUM_KEYS) {
|
||||||
|
last_key = -1;
|
||||||
|
state = Idle;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t now = millis();
|
||||||
|
last_tap = now;
|
||||||
|
|
||||||
|
if (TDeckProTapMap[last_key][modifierFlag % TDeckProTapMod[last_key]] == Key::BL_TOGGLE) {
|
||||||
|
toggleBacklight();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
queueEvent(TDeckProTapMap[last_key][modifierFlag % TDeckProTapMod[last_key]]);
|
||||||
|
if (isModifierKey(last_key) == false)
|
||||||
|
modifierFlag = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void TDeckProKeyboard::setBacklight(bool on)
|
||||||
|
{
|
||||||
|
if (on) {
|
||||||
|
digitalWrite(KB_BL_PIN, HIGH);
|
||||||
|
} else {
|
||||||
|
digitalWrite(KB_BL_PIN, LOW);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void TDeckProKeyboard::toggleBacklight(void)
|
||||||
|
{
|
||||||
|
digitalWrite(KB_BL_PIN, !digitalRead(KB_BL_PIN));
|
||||||
|
}
|
||||||
|
|
||||||
|
void TDeckProKeyboard::updateModifierFlag(uint8_t key)
|
||||||
|
{
|
||||||
|
if (key == modifierRightShiftKey) {
|
||||||
|
modifierFlag ^= modifierRightShift;
|
||||||
|
} else if (key == modifierLeftShiftKey) {
|
||||||
|
modifierFlag ^= modifierLeftShift;
|
||||||
|
} else if (key == modifierSymKey) {
|
||||||
|
modifierFlag ^= modifierSym;
|
||||||
|
} else if (key == modifierAltKey) {
|
||||||
|
modifierFlag ^= modifierAlt;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool TDeckProKeyboard::isModifierKey(uint8_t key)
|
||||||
|
{
|
||||||
|
return (key == modifierRightShiftKey || key == modifierLeftShiftKey || key == modifierAltKey || key == modifierSymKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // T_DECK_PRO
|
27
src/input/TDeckProKeyboard.h
Normal file
27
src/input/TDeckProKeyboard.h
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
#include "TCA8418KeyboardBase.h"
|
||||||
|
|
||||||
|
class TDeckProKeyboard : public TCA8418KeyboardBase
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
TDeckProKeyboard();
|
||||||
|
void reset(void) override;
|
||||||
|
void trigger(void) override;
|
||||||
|
void setBacklight(bool on) override;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void pressed(uint8_t key) override;
|
||||||
|
void released(void) override;
|
||||||
|
|
||||||
|
void updateModifierFlag(uint8_t key);
|
||||||
|
bool isModifierKey(uint8_t key);
|
||||||
|
void toggleBacklight(void);
|
||||||
|
|
||||||
|
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;
|
||||||
|
uint32_t last_tap;
|
||||||
|
uint8_t char_idx;
|
||||||
|
int32_t tap_interval;
|
||||||
|
};
|
12
src/input/TLoraPagerKeyboard.h
Normal file
12
src/input/TLoraPagerKeyboard.h
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
#include "TCA8418KeyboardBase.h"
|
||||||
|
|
||||||
|
class TLoraPagerKeyboard : public TCA8418KeyboardBase
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
TLoraPagerKeyboard();
|
||||||
|
void setBacklight(bool on) override{};
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void pressed(uint8_t key) override{};
|
||||||
|
void released(void) override{};
|
||||||
|
};
|
@ -3,10 +3,26 @@
|
|||||||
#include "detect/ScanI2C.h"
|
#include "detect/ScanI2C.h"
|
||||||
#include "detect/ScanI2CTwoWire.h"
|
#include "detect/ScanI2CTwoWire.h"
|
||||||
|
|
||||||
|
#if defined(T_DECK_PRO)
|
||||||
|
#include "TDeckProKeyboard.h"
|
||||||
|
#elif defined(T_LORA_PAGER)
|
||||||
|
#include "TLoraPagerKeyboard.h"
|
||||||
|
#else
|
||||||
|
#include "TCA8418Keyboard.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
extern ScanI2C::DeviceAddress cardkb_found;
|
extern ScanI2C::DeviceAddress cardkb_found;
|
||||||
extern uint8_t kb_model;
|
extern uint8_t kb_model;
|
||||||
|
|
||||||
KbI2cBase::KbI2cBase(const char *name) : concurrency::OSThread(name)
|
KbI2cBase::KbI2cBase(const char *name)
|
||||||
|
: concurrency::OSThread(name),
|
||||||
|
#if defined(T_DECK_PRO)
|
||||||
|
TCAKeyboard(*(new TDeckProKeyboard()))
|
||||||
|
#elif defined(T_LORA_PAGER)
|
||||||
|
TCAKeyboard(*(new TLoraPagerKeyboard()))
|
||||||
|
#else
|
||||||
|
TCAKeyboard(*(new TCA8418Keyboard()))
|
||||||
|
#endif
|
||||||
{
|
{
|
||||||
this->_originName = name;
|
this->_originName = name;
|
||||||
}
|
}
|
||||||
@ -43,8 +59,8 @@ int32_t KbI2cBase::runOnce()
|
|||||||
if (cardkb_found.address == MPR121_KB_ADDR) {
|
if (cardkb_found.address == MPR121_KB_ADDR) {
|
||||||
MPRkeyboard.begin(MPR121_KB_ADDR, &Wire1);
|
MPRkeyboard.begin(MPR121_KB_ADDR, &Wire1);
|
||||||
}
|
}
|
||||||
if (cardkb_found.address == XPOWERS_AXP192_AXP2101_ADDRESS) {
|
if (cardkb_found.address == TCA8418_KB_ADDR) {
|
||||||
TCAKeyboard.begin(XPOWERS_AXP192_AXP2101_ADDRESS, &Wire1);
|
TCAKeyboard.begin(TCA8418_KB_ADDR, &Wire1);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
#endif
|
#endif
|
||||||
@ -58,8 +74,8 @@ int32_t KbI2cBase::runOnce()
|
|||||||
if (cardkb_found.address == MPR121_KB_ADDR) {
|
if (cardkb_found.address == MPR121_KB_ADDR) {
|
||||||
MPRkeyboard.begin(MPR121_KB_ADDR, &Wire);
|
MPRkeyboard.begin(MPR121_KB_ADDR, &Wire);
|
||||||
}
|
}
|
||||||
if (cardkb_found.address == XPOWERS_AXP192_AXP2101_ADDRESS) {
|
if (cardkb_found.address == TCA8418_KB_ADDR) {
|
||||||
TCAKeyboard.begin(XPOWERS_AXP192_AXP2101_ADDRESS, &Wire);
|
TCAKeyboard.begin(TCA8418_KB_ADDR, &Wire);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case ScanI2C::NO_I2C:
|
case ScanI2C::NO_I2C:
|
||||||
@ -241,42 +257,66 @@ int32_t KbI2cBase::runOnce()
|
|||||||
e.kbchar = 0x00;
|
e.kbchar = 0x00;
|
||||||
e.source = this->_originName;
|
e.source = this->_originName;
|
||||||
switch (nextEvent) {
|
switch (nextEvent) {
|
||||||
case _TCA8418_NONE:
|
case TCA8418KeyboardBase::NONE:
|
||||||
e.inputEvent = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_NONE;
|
e.inputEvent = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_NONE;
|
||||||
e.kbchar = 0x00;
|
e.kbchar = 0x00;
|
||||||
break;
|
break;
|
||||||
case _TCA8418_REBOOT:
|
case TCA8418KeyboardBase::REBOOT:
|
||||||
e.inputEvent = ANYKEY;
|
e.inputEvent = ANYKEY;
|
||||||
e.kbchar = INPUT_BROKER_MSG_REBOOT;
|
e.kbchar = INPUT_BROKER_MSG_REBOOT;
|
||||||
break;
|
break;
|
||||||
case _TCA8418_LEFT:
|
case TCA8418KeyboardBase::LEFT:
|
||||||
e.inputEvent = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_LEFT;
|
e.inputEvent = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_LEFT;
|
||||||
e.kbchar = 0x00;
|
e.kbchar = 0x00;
|
||||||
break;
|
break;
|
||||||
case _TCA8418_UP:
|
case TCA8418KeyboardBase::UP:
|
||||||
e.inputEvent = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_UP;
|
e.inputEvent = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_UP;
|
||||||
e.kbchar = 0x00;
|
e.kbchar = 0x00;
|
||||||
break;
|
break;
|
||||||
case _TCA8418_DOWN:
|
case TCA8418KeyboardBase::DOWN:
|
||||||
e.inputEvent = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_DOWN;
|
e.inputEvent = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_DOWN;
|
||||||
e.kbchar = 0x00;
|
e.kbchar = 0x00;
|
||||||
break;
|
break;
|
||||||
case _TCA8418_RIGHT:
|
case TCA8418KeyboardBase::RIGHT:
|
||||||
e.inputEvent = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_RIGHT;
|
e.inputEvent = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_RIGHT;
|
||||||
e.kbchar = 0x00;
|
e.kbchar = 0x00;
|
||||||
break;
|
break;
|
||||||
case _TCA8418_BSP:
|
case TCA8418KeyboardBase::BSP:
|
||||||
e.inputEvent = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_BACK;
|
e.inputEvent = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_BACK;
|
||||||
e.kbchar = 0x08;
|
e.kbchar = 0x08;
|
||||||
break;
|
break;
|
||||||
case _TCA8418_SELECT:
|
case TCA8418KeyboardBase::SELECT:
|
||||||
e.inputEvent = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_SELECT;
|
e.inputEvent = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_SELECT;
|
||||||
e.kbchar = 0x0d;
|
e.kbchar = 0x0d;
|
||||||
break;
|
break;
|
||||||
case _TCA8418_ESC:
|
case TCA8418KeyboardBase::ESC:
|
||||||
e.inputEvent = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_CANCEL;
|
e.inputEvent = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_CANCEL;
|
||||||
e.kbchar = 0x1b;
|
e.kbchar = 0x1b;
|
||||||
break;
|
break;
|
||||||
|
case 0x9E:
|
||||||
|
e.inputEvent = ANYKEY;
|
||||||
|
e.kbchar = INPUT_BROKER_MSG_GPS_TOGGLE;
|
||||||
|
break;
|
||||||
|
case 0xAF:
|
||||||
|
e.inputEvent = ANYKEY;
|
||||||
|
e.kbchar = INPUT_BROKER_MSG_SEND_PING;
|
||||||
|
break;
|
||||||
|
case 0xAC:
|
||||||
|
e.inputEvent = ANYKEY;
|
||||||
|
e.kbchar = INPUT_BROKER_MSG_MUTE_TOGGLE;
|
||||||
|
break;
|
||||||
|
case 0xAA:
|
||||||
|
e.inputEvent = ANYKEY;
|
||||||
|
e.kbchar = INPUT_BROKER_MSG_BLUETOOTH_TOGGLE;
|
||||||
|
break;
|
||||||
|
case 0xAB:
|
||||||
|
e.inputEvent = ANYKEY;
|
||||||
|
e.kbchar = INPUT_BROKER_MSG_BLUETOOTH_TOGGLE;
|
||||||
|
break;
|
||||||
|
case 0x09:
|
||||||
|
e.inputEvent = ANYKEY;
|
||||||
|
e.kbchar = 0x09; // Tab
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
if (nextEvent > 127) {
|
if (nextEvent > 127) {
|
||||||
e.inputEvent = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_NONE;
|
e.inputEvent = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_NONE;
|
||||||
@ -291,6 +331,7 @@ 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;
|
||||||
}
|
}
|
||||||
|
@ -3,10 +3,11 @@
|
|||||||
#include "BBQ10Keyboard.h"
|
#include "BBQ10Keyboard.h"
|
||||||
#include "InputBroker.h"
|
#include "InputBroker.h"
|
||||||
#include "MPR121Keyboard.h"
|
#include "MPR121Keyboard.h"
|
||||||
#include "TCA8418Keyboard.h"
|
|
||||||
#include "Wire.h"
|
#include "Wire.h"
|
||||||
#include "concurrency/OSThread.h"
|
#include "concurrency/OSThread.h"
|
||||||
|
|
||||||
|
class TCA8418KeyboardBase;
|
||||||
|
|
||||||
class KbI2cBase : public Observable<const InputEvent *>, public concurrency::OSThread
|
class KbI2cBase : public Observable<const InputEvent *>, public concurrency::OSThread
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@ -22,6 +23,6 @@ class KbI2cBase : public Observable<const InputEvent *>, public concurrency::OST
|
|||||||
|
|
||||||
BBQ10Keyboard Q10keyboard;
|
BBQ10Keyboard Q10keyboard;
|
||||||
MPR121Keyboard MPRkeyboard;
|
MPR121Keyboard MPRkeyboard;
|
||||||
TCA8418Keyboard TCAKeyboard;
|
TCA8418KeyboardBase &TCAKeyboard;
|
||||||
bool is_sym = false;
|
bool is_sym = false;
|
||||||
};
|
};
|
Loading…
Reference in New Issue
Block a user