mirror of
https://github.com/meshtastic/firmware.git
synced 2025-06-08 14:12:05 +00:00
Adding support for Chatter keypad (#4022)
* Adding support for Chatter keypad * Remove user button mapping since full keypad is now useable * Adding TAB key and RIGHT to allow selecting a destination * Fix shift bug (there's only three levels, not four) * reformat file * Fix bug with fast repeated keypresses --------- Co-authored-by: Ben Meadors <benmmeadors@gmail.com>
This commit is contained in:
parent
103ab0c242
commit
106a50bce2
187
src/input/SerialKeyboard.cpp
Normal file
187
src/input/SerialKeyboard.cpp
Normal file
@ -0,0 +1,187 @@
|
|||||||
|
#include "SerialKeyboard.h"
|
||||||
|
#include "configuration.h"
|
||||||
|
|
||||||
|
#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
|
||||||
|
unsigned char KeyMap[3][4][10]= {{{'.','a','d','g','j','m','p','t','w',' '},
|
||||||
|
{',','b','e','h','k','n','q','u','x',' '},
|
||||||
|
{'?','c','f','i','l','o','r','v','y',' '},
|
||||||
|
{'1','2','3','4','5','6','s','8','z',' '}}, // low case
|
||||||
|
{{'!','A','D','G','J','M','P','T','W',' '},
|
||||||
|
{'+','B','E','H','K','N','Q','U','X',' '},
|
||||||
|
{'-','C','F','I','L','O','R','V','Y',' '},
|
||||||
|
{'1','2','3','4','5','6','S','8','Z',' '}}, // upper case
|
||||||
|
{{'1','2','3','4','5','6','7','8','9','0'},
|
||||||
|
{'1','2','3','4','5','6','7','8','9','0'},
|
||||||
|
{'1','2','3','4','5','6','7','8','9','0'},
|
||||||
|
{'1','2','3','4','5','6','7','8','9','0'}}}; // numbers
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
SerialKeyboard::SerialKeyboard(const char *name) : concurrency::OSThread(name)
|
||||||
|
{
|
||||||
|
this->_originName = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void SerialKeyboard::erase(){
|
||||||
|
InputEvent e;
|
||||||
|
e.inputEvent = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_BACK;
|
||||||
|
e.kbchar = 0x08;
|
||||||
|
e.source = this->_originName;
|
||||||
|
this->notifyObservers(&e);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int32_t SerialKeyboard::runOnce()
|
||||||
|
{
|
||||||
|
if (!INPUTBROKER_SERIAL_TYPE) {
|
||||||
|
// Input device is not requested.
|
||||||
|
return disable();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (firstTime) {
|
||||||
|
// This is the first time the OSThread library has called this function, so do port setup
|
||||||
|
firstTime = 0;
|
||||||
|
pinMode(KB_LOAD, OUTPUT);
|
||||||
|
pinMode(KB_CLK, OUTPUT);
|
||||||
|
pinMode(KB_DATA, INPUT);
|
||||||
|
digitalWrite(KB_LOAD, HIGH);
|
||||||
|
digitalWrite(KB_CLK, LOW);
|
||||||
|
prevKeys = 0b1111111111111111;
|
||||||
|
LOG_DEBUG("Serial Keyboard setup\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (INPUTBROKER_SERIAL_TYPE == 1) { //Chatter V1.0 & V2.0 keypads
|
||||||
|
// scan for keypresses
|
||||||
|
// Write pulse to load pin
|
||||||
|
digitalWrite(KB_LOAD, LOW);
|
||||||
|
delayMicroseconds(5);
|
||||||
|
digitalWrite(KB_LOAD, HIGH);
|
||||||
|
delayMicroseconds(5);
|
||||||
|
|
||||||
|
// Get data from 74HC165
|
||||||
|
byte shiftRegister1 = shiftIn(KB_DATA, KB_CLK, LSBFIRST);
|
||||||
|
byte shiftRegister2 = shiftIn(KB_DATA, KB_CLK, LSBFIRST);
|
||||||
|
|
||||||
|
keys = (shiftRegister1 << 8) + shiftRegister2;
|
||||||
|
|
||||||
|
// Print to serial monitor
|
||||||
|
//Serial.print (shiftRegister1, BIN);
|
||||||
|
//Serial.print ("X");
|
||||||
|
//Serial.println (shiftRegister2, BIN);
|
||||||
|
|
||||||
|
if (millis()-lastPressTime > 500){
|
||||||
|
quickPress = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (keys < prevKeys) { // a new key has been pressed (and not released), doesn't works for multiple presses at once but shouldn't be a limitation
|
||||||
|
InputEvent e;
|
||||||
|
e.inputEvent = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_NONE;
|
||||||
|
e.source = this->_originName;
|
||||||
|
// SELECT OR SEND OR CANCEL EVENT
|
||||||
|
if (!(shiftRegister2 & (1 << 3))) {
|
||||||
|
e.inputEvent = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_UP;
|
||||||
|
}
|
||||||
|
else if (!(shiftRegister2 & (1 << 2))) {
|
||||||
|
e.inputEvent = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_RIGHT;
|
||||||
|
e.kbchar = 0xb7;
|
||||||
|
}
|
||||||
|
else if (!(shiftRegister2 & (1 << 1))) {
|
||||||
|
e.inputEvent = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_SELECT;
|
||||||
|
}
|
||||||
|
else if (!(shiftRegister2 & (1 << 0))) {
|
||||||
|
e.inputEvent = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_CANCEL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TEXT INPUT EVENT
|
||||||
|
else if (!(shiftRegister1 & (1 << 4))) {
|
||||||
|
keyPressed = 0;
|
||||||
|
}
|
||||||
|
else if (!(shiftRegister1 & (1 << 3))) {
|
||||||
|
keyPressed = 1;
|
||||||
|
}
|
||||||
|
else if (!(shiftRegister2 & (1 << 4))) {
|
||||||
|
keyPressed = 2;
|
||||||
|
}
|
||||||
|
else if (!(shiftRegister1 & (1 << 5))) {
|
||||||
|
keyPressed = 3;
|
||||||
|
}
|
||||||
|
else if (!(shiftRegister1 & (1 << 2))) {
|
||||||
|
keyPressed = 4;
|
||||||
|
}
|
||||||
|
else if (!(shiftRegister2 & (1 << 5))) {
|
||||||
|
keyPressed = 5;
|
||||||
|
}
|
||||||
|
else if (!(shiftRegister1 & (1 << 6))) {
|
||||||
|
keyPressed = 6;
|
||||||
|
}
|
||||||
|
else if (!(shiftRegister1 & (1 << 1))) {
|
||||||
|
keyPressed = 7;
|
||||||
|
}
|
||||||
|
else if (!(shiftRegister2 & (1 << 6))) {
|
||||||
|
keyPressed = 8;
|
||||||
|
}
|
||||||
|
else if (!(shiftRegister1 & (1 << 0))) {
|
||||||
|
keyPressed = 9;
|
||||||
|
}
|
||||||
|
// BACKSPACE or TAB
|
||||||
|
else if (!(shiftRegister1 & (1 << 7))) {
|
||||||
|
if (shift == 0 || shift ==2){ // BACKSPACE
|
||||||
|
e.inputEvent = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_BACK;
|
||||||
|
e.kbchar = 0x08;
|
||||||
|
} else { // shift = 1 => TAB
|
||||||
|
e.inputEvent = ANYKEY;
|
||||||
|
e.kbchar = 0x09;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// SHIFT
|
||||||
|
else if (!(shiftRegister2 & (1 << 7))) {
|
||||||
|
keyPressed = 10;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (keyPressed < 11){
|
||||||
|
if (keyPressed == lastKeyPressed && millis()-lastPressTime < 500){
|
||||||
|
quickPress += 1;
|
||||||
|
if (quickPress > 3){
|
||||||
|
quickPress = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (keyPressed != lastKeyPressed){
|
||||||
|
quickPress = 0;
|
||||||
|
}
|
||||||
|
if (keyPressed < 10){ // if it's a letter
|
||||||
|
if (keyPressed == lastKeyPressed && millis()-lastPressTime < 500){
|
||||||
|
erase();
|
||||||
|
}
|
||||||
|
e.inputEvent = ANYKEY;
|
||||||
|
e.kbchar = char(KeyMap[shift][quickPress][keyPressed]);
|
||||||
|
}
|
||||||
|
else { //then it's shift
|
||||||
|
shift += 1;
|
||||||
|
if (shift > 2){
|
||||||
|
shift = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
lastPressTime = millis();
|
||||||
|
lastKeyPressed = keyPressed;
|
||||||
|
keyPressed = 13;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (e.inputEvent != meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_NONE) {
|
||||||
|
this->notifyObservers(&e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
prevKeys = keys;
|
||||||
|
|
||||||
|
}
|
||||||
|
return 50;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#endif // INPUTBROKER_SERIAL_TYPE
|
25
src/input/SerialKeyboard.h
Normal file
25
src/input/SerialKeyboard.h
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "InputBroker.h"
|
||||||
|
#include "concurrency/OSThread.h"
|
||||||
|
|
||||||
|
class SerialKeyboard : public Observable<const InputEvent *>, public concurrency::OSThread
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit SerialKeyboard(const char *name);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
virtual int32_t runOnce() override;
|
||||||
|
void erase();
|
||||||
|
|
||||||
|
private:
|
||||||
|
const char *_originName;
|
||||||
|
bool firstTime = 1;
|
||||||
|
int prevKeys = 0;
|
||||||
|
int keys = 0;
|
||||||
|
int shift = 0;
|
||||||
|
int keyPressed = 13;
|
||||||
|
int lastKeyPressed = 13;
|
||||||
|
int quickPress = 0;
|
||||||
|
unsigned long lastPressTime = 0;
|
||||||
|
};
|
21
src/input/SerialKeyboardImpl.cpp
Normal file
21
src/input/SerialKeyboardImpl.cpp
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
#include "configuration.h"
|
||||||
|
#include "InputBroker.h"
|
||||||
|
#include "SerialKeyboardImpl.h"
|
||||||
|
|
||||||
|
#ifdef INPUTBROKER_SERIAL_TYPE
|
||||||
|
|
||||||
|
SerialKeyboardImpl *aSerialKeyboardImpl;
|
||||||
|
|
||||||
|
SerialKeyboardImpl::SerialKeyboardImpl() : SerialKeyboard("serialKB") {}
|
||||||
|
|
||||||
|
void SerialKeyboardImpl::init()
|
||||||
|
{
|
||||||
|
if (!INPUTBROKER_SERIAL_TYPE) {
|
||||||
|
disable();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
inputBroker->registerSource(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // INPUTBROKER_SERIAL_TYPE
|
19
src/input/SerialKeyboardImpl.h
Normal file
19
src/input/SerialKeyboardImpl.h
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
#pragma once
|
||||||
|
#include "SerialKeyboard.h"
|
||||||
|
#include "main.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief The idea behind this class to have static methods for the event handlers.
|
||||||
|
* Check attachInterrupt() at RotaryEncoderInteruptBase.cpp
|
||||||
|
* Technically you can have as many rotary encoders hardver attached
|
||||||
|
* to your device as you wish, but you always need to have separate event
|
||||||
|
* handlers, thus you need to have a RotaryEncoderInterrupt implementation.
|
||||||
|
*/
|
||||||
|
class SerialKeyboardImpl : public SerialKeyboard
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
SerialKeyboardImpl();
|
||||||
|
void init();
|
||||||
|
};
|
||||||
|
|
||||||
|
extern SerialKeyboardImpl *aSerialKeyboardImpl;
|
@ -6,6 +6,7 @@
|
|||||||
#include "input/UpDownInterruptImpl1.h"
|
#include "input/UpDownInterruptImpl1.h"
|
||||||
#include "input/cardKbI2cImpl.h"
|
#include "input/cardKbI2cImpl.h"
|
||||||
#include "input/kbMatrixImpl.h"
|
#include "input/kbMatrixImpl.h"
|
||||||
|
#include "input/SerialKeyboardImpl.h"
|
||||||
#endif
|
#endif
|
||||||
#if !MESHTASTIC_EXCLUDE_ADMIN
|
#if !MESHTASTIC_EXCLUDE_ADMIN
|
||||||
#include "modules/AdminModule.h"
|
#include "modules/AdminModule.h"
|
||||||
@ -149,6 +150,10 @@ void setupModules()
|
|||||||
kbMatrixImpl = new KbMatrixImpl();
|
kbMatrixImpl = new KbMatrixImpl();
|
||||||
kbMatrixImpl->init();
|
kbMatrixImpl->init();
|
||||||
#endif // INPUTBROKER_MATRIX_TYPE
|
#endif // INPUTBROKER_MATRIX_TYPE
|
||||||
|
#ifdef INPUTBROKER_SERIAL_TYPE
|
||||||
|
aSerialKeyboardImpl = new SerialKeyboardImpl();
|
||||||
|
aSerialKeyboardImpl->init();
|
||||||
|
#endif // INPUTBROKER_MATRIX_TYPE
|
||||||
#endif // HAS_BUTTON
|
#endif // HAS_BUTTON
|
||||||
#if ARCH_PORTDUINO
|
#if ARCH_PORTDUINO
|
||||||
aLinuxInputImpl = new LinuxInputImpl();
|
aLinuxInputImpl = new LinuxInputImpl();
|
||||||
|
@ -34,7 +34,7 @@
|
|||||||
// Buzzer
|
// Buzzer
|
||||||
#define PIN_BUZZER 19
|
#define PIN_BUZZER 19
|
||||||
// Buttons
|
// Buttons
|
||||||
#define BUTTON_PIN 36 // Use the WAKE button as the user button
|
//#define BUTTON_PIN 36 // Use the WAKE button as the user button
|
||||||
// I2C
|
// I2C
|
||||||
// #define I2C_SCL 27
|
// #define I2C_SCL 27
|
||||||
// #define I2C_SDA 26
|
// #define I2C_SDA 26
|
||||||
@ -91,6 +91,13 @@
|
|||||||
#define GPS_TX_PIN 13
|
#define GPS_TX_PIN 13
|
||||||
#define GPS_RX_PIN 2
|
#define GPS_RX_PIN 2
|
||||||
|
|
||||||
|
// keyboard
|
||||||
|
#define INPUTBROKER_SERIAL_TYPE 1
|
||||||
|
#define KB_LOAD 21 // load values from the switch and store in shift register
|
||||||
|
#define KB_CLK 22 // clock pin for serial data out
|
||||||
|
#define KB_DATA 23 // data pin
|
||||||
|
#define CANNED_MESSAGE_MODULE_ENABLE 1
|
||||||
|
|
||||||
/////////////////////////////////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////////////////////////////////
|
||||||
// //
|
// //
|
||||||
// You should have no need to modify the code below, nor in pins_arduino.h //
|
// You should have no need to modify the code below, nor in pins_arduino.h //
|
||||||
|
Loading…
Reference in New Issue
Block a user