mirror of
https://github.com/meshtastic/firmware.git
synced 2025-04-27 10:21:40 +00:00
Merge branch 'master' into 2.2-working-changes
This commit is contained in:
commit
04cba45c60
@ -101,23 +101,8 @@ class ButtonThread : public concurrency::OSThread
|
||||
#endif
|
||||
// if (!canSleep) LOG_DEBUG("Suppressing sleep!\n");
|
||||
// else LOG_DEBUG("sleep ok\n");
|
||||
#if defined(ST7735_CS) || defined(ILI9341_DRIVER) || defined(ST7789_CS)
|
||||
int x, y = 0;
|
||||
screen->getTouch(&x, &y);
|
||||
if (x > 0 && y > 0) {
|
||||
#ifdef T_WATCH_S3
|
||||
drv.setWaveform(0, 75);
|
||||
drv.setWaveform(1, 0); // end waveform
|
||||
drv.go();
|
||||
#endif
|
||||
LOG_DEBUG("touch %d %d\n", x, y);
|
||||
powerFSM.trigger(EVENT_PRESS);
|
||||
return 150; // Check for next touch every in 150ms
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
return 5;
|
||||
return 50;
|
||||
}
|
||||
|
||||
private:
|
||||
|
@ -15,4 +15,6 @@ enum class Cmd {
|
||||
PRINT,
|
||||
START_SHUTDOWN_SCREEN,
|
||||
START_REBOOT_SCREEN,
|
||||
SHOW_PREV_FRAME,
|
||||
SHOW_NEXT_FRAME
|
||||
};
|
@ -98,8 +98,9 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
// Define if screen should be mirrored left to right
|
||||
// #define SCREEN_MIRROR
|
||||
|
||||
// The m5stack I2C Keyboard (also RAK14004)
|
||||
// I2C Keyboards (M5Stack, RAK14004, T-Deck)
|
||||
#define CARDKB_ADDR 0x5F
|
||||
#define TDECK_KB_ADDR 0x55
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// SENSOR
|
||||
@ -173,6 +174,12 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#ifndef HAS_BUTTON
|
||||
#define HAS_BUTTON 0
|
||||
#endif
|
||||
#ifndef HAS_TRACKBALL
|
||||
#define HAS_TRACKBALL 0
|
||||
#endif
|
||||
#ifndef HAS_TOUCHSCREEN
|
||||
#define HAS_TOUCHSCREEN 0
|
||||
#endif
|
||||
#ifndef HAS_TELEMETRY
|
||||
#define HAS_TELEMETRY 0
|
||||
#endif
|
||||
|
@ -30,8 +30,8 @@ ScanI2C::FoundDevice ScanI2C::firstRTC() const
|
||||
|
||||
ScanI2C::FoundDevice ScanI2C::firstKeyboard() const
|
||||
{
|
||||
ScanI2C::DeviceType types[] = {CARDKB, RAK14004};
|
||||
return firstOfOrNONE(2, types);
|
||||
ScanI2C::DeviceType types[] = {CARDKB, TDECKKB, RAK14004};
|
||||
return firstOfOrNONE(3, types);
|
||||
}
|
||||
|
||||
ScanI2C::FoundDevice ScanI2C::firstAccelerometer() const
|
||||
|
@ -16,6 +16,7 @@ class ScanI2C
|
||||
RTC_RV3028,
|
||||
RTC_PCF8563,
|
||||
CARDKB,
|
||||
TDECKKB,
|
||||
RAK14004,
|
||||
PMU_AXP192_AXP2101,
|
||||
BME_680,
|
||||
|
@ -212,6 +212,7 @@ void ScanI2CTwoWire::scanPort(I2CPort port)
|
||||
}
|
||||
break;
|
||||
|
||||
SCAN_SIMPLE_CASE(TDECK_KB_ADDR, TDECKKB, "T-Deck keyboard found\n");
|
||||
SCAN_SIMPLE_CASE(ST7567_ADDRESS, SCREEN_ST7567, "st7567 display found\n");
|
||||
#ifdef HAS_NCP5623
|
||||
SCAN_SIMPLE_CASE(NCP5623_ADDR, NCP5623, "NCP5623 RGB LED found\n");
|
||||
|
@ -31,6 +31,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#include "gps/GeoCoord.h"
|
||||
#include "gps/RTC.h"
|
||||
#include "graphics/images.h"
|
||||
#include "input/TouchScreenImpl1.h"
|
||||
#include "main.h"
|
||||
#include "mesh-pb-constants.h"
|
||||
#include "mesh/Channels.h"
|
||||
@ -1044,12 +1045,18 @@ void Screen::setup()
|
||||
#endif
|
||||
serialSinceMsec = millis();
|
||||
|
||||
#if HAS_TOUCHSCREEN
|
||||
touchScreenImpl1 = new TouchScreenImpl1(dispdev.getWidth(), dispdev.getHeight(), dispdev.getTouch);
|
||||
touchScreenImpl1->init();
|
||||
#endif
|
||||
|
||||
// Subscribe to status updates
|
||||
powerStatusObserver.observe(&powerStatus->onNewStatus);
|
||||
gpsStatusObserver.observe(&gpsStatus->onNewStatus);
|
||||
nodeStatusObserver.observe(&nodeStatus->onNewStatus);
|
||||
if (textMessageModule)
|
||||
textMessageObserver.observe(textMessageModule);
|
||||
inputObserver.observe(inputBroker);
|
||||
|
||||
// Modules can notify screen about refresh
|
||||
MeshModule::observeUIEvents(&uiFrameEventObserver);
|
||||
@ -1127,6 +1134,12 @@ int32_t Screen::runOnce()
|
||||
handleOnPress();
|
||||
}
|
||||
break;
|
||||
case Cmd::SHOW_PREV_FRAME:
|
||||
handleShowPrevFrame();
|
||||
break;
|
||||
case Cmd::SHOW_NEXT_FRAME:
|
||||
handleShowNextFrame();
|
||||
break;
|
||||
case Cmd::START_BLUETOOTH_PIN_SCREEN:
|
||||
handleStartBluetoothPinScreen(cmd.bluetooth_pin);
|
||||
break;
|
||||
@ -1420,6 +1433,28 @@ void Screen::handleOnPress()
|
||||
}
|
||||
}
|
||||
|
||||
void Screen::handleShowPrevFrame()
|
||||
{
|
||||
// If screen was off, just wake it, otherwise go back to previous frame
|
||||
// If we are in a transition, the press must have bounced, drop it.
|
||||
if (ui.getUiState()->frameState == FIXED) {
|
||||
ui.previousFrame();
|
||||
lastScreenTransition = millis();
|
||||
setFastFramerate();
|
||||
}
|
||||
}
|
||||
|
||||
void Screen::handleShowNextFrame()
|
||||
{
|
||||
// If screen was off, just wake it, otherwise advance to next frame
|
||||
// If we are in a transition, the press must have bounced, drop it.
|
||||
if (ui.getUiState()->frameState == FIXED) {
|
||||
ui.nextFrame();
|
||||
lastScreenTransition = millis();
|
||||
setFastFramerate();
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef SCREEN_TRANSITION_FRAMERATE
|
||||
#define SCREEN_TRANSITION_FRAMERATE 30 // fps
|
||||
#endif
|
||||
@ -1857,6 +1892,20 @@ int Screen::handleUIFrameEvent(const UIFrameEvent *event)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int Screen::handleInputEvent(const InputEvent *event)
|
||||
{
|
||||
if (showingNormalScreen && moduleFrames.size() == 0) {
|
||||
LOG_DEBUG("Screen::handleInputEvent from %s\n", event->source);
|
||||
if (event->inputEvent == static_cast<char>(meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_LEFT)) {
|
||||
showPrevFrame();
|
||||
} else if (event->inputEvent == static_cast<char>(meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_RIGHT)) {
|
||||
showNextFrame();
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
} // namespace graphics
|
||||
#else
|
||||
graphics::Screen::Screen(ScanI2C::DeviceAddress, meshtastic_Config_DisplayConfig_OledType, OLEDDISPLAY_GEOMETRY) {}
|
||||
|
@ -53,6 +53,7 @@ class Screen
|
||||
#include "commands.h"
|
||||
#include "concurrency/LockGuard.h"
|
||||
#include "concurrency/OSThread.h"
|
||||
#include "input/InputBroker.h"
|
||||
#include "mesh/MeshModule.h"
|
||||
#include "power.h"
|
||||
#include <string>
|
||||
@ -118,6 +119,8 @@ class Screen : public concurrency::OSThread
|
||||
CallbackObserver<Screen, const meshtastic_MeshPacket *>(this, &Screen::handleTextMessage);
|
||||
CallbackObserver<Screen, const UIFrameEvent *> uiFrameEventObserver =
|
||||
CallbackObserver<Screen, const UIFrameEvent *>(this, &Screen::handleUIFrameEvent);
|
||||
CallbackObserver<Screen, const InputEvent *> inputObserver =
|
||||
CallbackObserver<Screen, const InputEvent *>(this, &Screen::handleInputEvent);
|
||||
|
||||
public:
|
||||
explicit Screen(ScanI2C::DeviceAddress, meshtastic_Config_DisplayConfig_OledType, OLEDDISPLAY_GEOMETRY);
|
||||
@ -152,8 +155,10 @@ class Screen : public concurrency::OSThread
|
||||
|
||||
void blink();
|
||||
|
||||
/// Handles a button press.
|
||||
/// Handle button press, trackball or swipe action)
|
||||
void onPress() { enqueueCmd(ScreenCmd{.cmd = Cmd::ON_PRESS}); }
|
||||
void showPrevFrame() { enqueueCmd(ScreenCmd{.cmd = Cmd::SHOW_PREV_FRAME}); }
|
||||
void showNextFrame() { enqueueCmd(ScreenCmd{.cmd = Cmd::SHOW_NEXT_FRAME}); }
|
||||
|
||||
// Implementation to Adjust Brightness
|
||||
void adjustBrightness();
|
||||
@ -301,9 +306,11 @@ class Screen : public concurrency::OSThread
|
||||
// Use this handle to set things like battery status, user count, GPS status, etc.
|
||||
DebugInfo *debug_info() { return &debugInfo; }
|
||||
|
||||
// Handle observer events
|
||||
int handleStatusUpdate(const meshtastic::Status *arg);
|
||||
int handleTextMessage(const meshtastic_MeshPacket *arg);
|
||||
int handleUIFrameEvent(const UIFrameEvent *arg);
|
||||
int handleInputEvent(const InputEvent *arg);
|
||||
|
||||
/// Used to force (super slow) eink displays to draw critical frames
|
||||
void forceDisplay();
|
||||
@ -313,13 +320,6 @@ class Screen : public concurrency::OSThread
|
||||
|
||||
void setWelcomeFrames();
|
||||
|
||||
void getTouch(int *x, int *y)
|
||||
{
|
||||
#if defined(ST7735_CS) || defined(ILI9341_DRIVER) || defined(ST7789_CS)
|
||||
dispdev.getTouch(x, y);
|
||||
#endif
|
||||
};
|
||||
|
||||
protected:
|
||||
/// Updates the UI.
|
||||
//
|
||||
@ -350,6 +350,8 @@ class Screen : public concurrency::OSThread
|
||||
// Implementations of various commands, called from doTask().
|
||||
void handleSetOn(bool on);
|
||||
void handleOnPress();
|
||||
void handleShowNextFrame();
|
||||
void handleShowPrevFrame();
|
||||
void handleStartBluetoothPinScreen(uint32_t pin);
|
||||
void handlePrint(const char *text);
|
||||
void handleStartFirmwareUpdateScreen();
|
||||
|
@ -174,7 +174,7 @@ class LGFX : public lgfx::LGFX_Device
|
||||
auto cfg = _light_instance.config(); // Gets a structure for backlight settings.
|
||||
|
||||
cfg.pin_bl = ST7789_BL; // Pin number to which the backlight is connected
|
||||
cfg.invert = true; // true to invert the brightness of the backlight
|
||||
cfg.invert = false; // true to invert the brightness of the backlight
|
||||
// cfg.pwm_channel = 0;
|
||||
|
||||
_light_instance.config(cfg);
|
||||
@ -196,7 +196,7 @@ class LGFX : public lgfx::LGFX_Device
|
||||
// cfg.freq = 2500000;
|
||||
|
||||
// I2C
|
||||
cfg.i2c_port = 1;
|
||||
cfg.i2c_port = TOUCH_I2C_PORT;
|
||||
cfg.i2c_addr = TOUCH_SLAVE_ADDRESS;
|
||||
#ifdef SCREEN_TOUCH_USE_I2C1
|
||||
cfg.pin_sda = I2C_SDA1;
|
||||
@ -205,7 +205,7 @@ class LGFX : public lgfx::LGFX_Device
|
||||
cfg.pin_sda = I2C_SDA;
|
||||
cfg.pin_scl = I2C_SCL;
|
||||
#endif
|
||||
cfg.freq = 400000;
|
||||
// cfg.freq = 400000;
|
||||
|
||||
_touch_instance.config(cfg);
|
||||
_panel_instance.setTouch(&_touch_instance);
|
||||
@ -275,6 +275,9 @@ void TFTDisplay::sendCommand(uint8_t com)
|
||||
#endif
|
||||
#ifdef VTFT_CTRL
|
||||
digitalWrite(VTFT_CTRL, LOW);
|
||||
#endif
|
||||
#ifndef M5STACK
|
||||
tft.setBrightness(128);
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
@ -284,6 +287,9 @@ void TFTDisplay::sendCommand(uint8_t com)
|
||||
#endif
|
||||
#ifdef VTFT_CTRL
|
||||
digitalWrite(VTFT_CTRL, HIGH);
|
||||
#endif
|
||||
#ifndef M5STACK
|
||||
tft.setBrightness(0);
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
@ -294,6 +300,24 @@ void TFTDisplay::sendCommand(uint8_t com)
|
||||
// Drop all other commands to device (we just update the buffer)
|
||||
}
|
||||
|
||||
bool TFTDisplay::hasTouch(void)
|
||||
{
|
||||
#ifndef M5STACK
|
||||
return tft.touch() != nullptr;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
bool TFTDisplay::getTouch(int16_t *x, int16_t *y)
|
||||
{
|
||||
#ifndef M5STACK
|
||||
return tft.getTouch(x, y);
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
void TFTDisplay::setDetected(uint8_t detected)
|
||||
{
|
||||
(void)detected;
|
||||
@ -322,12 +346,4 @@ bool TFTDisplay::connect()
|
||||
return true;
|
||||
}
|
||||
|
||||
// Get touch coords from the display
|
||||
void TFTDisplay::getTouch(int *x, int *y)
|
||||
{
|
||||
#ifndef M5STACK
|
||||
tft.getTouch(x, y);
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif
|
@ -22,14 +22,16 @@ class TFTDisplay : public OLEDDisplay
|
||||
// Write the buffer to the display memory
|
||||
virtual void display(void) override;
|
||||
|
||||
// Touch screen (static handlers)
|
||||
static bool hasTouch(void);
|
||||
static bool getTouch(int16_t *x, int16_t *y);
|
||||
|
||||
/**
|
||||
* shim to make the abstraction happy
|
||||
*
|
||||
*/
|
||||
void setDetected(uint8_t detected);
|
||||
|
||||
void getTouch(int *x, int *y);
|
||||
|
||||
protected:
|
||||
// the header size of the buffer used, e.g. for the SPI command header
|
||||
virtual int getBufferOffset(void) override { return 0; }
|
||||
|
137
src/input/TouchScreenBase.cpp
Normal file
137
src/input/TouchScreenBase.cpp
Normal file
@ -0,0 +1,137 @@
|
||||
#include "TouchScreenBase.h"
|
||||
#include "main.h"
|
||||
|
||||
#ifndef TIME_LONG_PRESS
|
||||
#define TIME_LONG_PRESS 400
|
||||
#endif
|
||||
|
||||
// move a minimum distance over the screen to detect a "swipe"
|
||||
#ifndef TOUCH_THRESHOLD_X
|
||||
#define TOUCH_THRESHOLD_X 30
|
||||
#endif
|
||||
|
||||
#ifndef TOUCH_THRESHOLD_Y
|
||||
#define TOUCH_THRESHOLD_Y 20
|
||||
#endif
|
||||
|
||||
TouchScreenBase::TouchScreenBase(const char *name, uint16_t width, uint16_t height)
|
||||
: concurrency::OSThread(name), _display_width(width), _display_height(height), _first_x(0), _last_x(0), _first_y(0),
|
||||
_last_y(0), _start(0), _tapped(false), _originName(name)
|
||||
{
|
||||
}
|
||||
|
||||
void TouchScreenBase::init(bool hasTouch)
|
||||
{
|
||||
if (hasTouch) {
|
||||
LOG_INFO("TouchScreen initialized %d %d\n", TOUCH_THRESHOLD_X, TOUCH_THRESHOLD_Y);
|
||||
this->setInterval(100);
|
||||
} else {
|
||||
disable();
|
||||
this->setInterval(UINT_MAX);
|
||||
}
|
||||
}
|
||||
|
||||
int32_t TouchScreenBase::runOnce()
|
||||
{
|
||||
TouchEvent e;
|
||||
e.touchEvent = static_cast<char>(TOUCH_ACTION_NONE);
|
||||
|
||||
// process touch events
|
||||
int16_t x, y;
|
||||
bool touched = getTouch(x, y);
|
||||
if (touched) {
|
||||
hapticFeedback();
|
||||
this->setInterval(20);
|
||||
_last_x = x;
|
||||
_last_y = y;
|
||||
}
|
||||
if (touched != _touchedOld) {
|
||||
if (touched) {
|
||||
_state = TOUCH_EVENT_OCCURRED;
|
||||
_start = millis();
|
||||
_first_x = x;
|
||||
_first_y = y;
|
||||
} else {
|
||||
_state = TOUCH_EVENT_CLEARED;
|
||||
time_t duration = millis() - _start;
|
||||
x = _last_x;
|
||||
y = _last_y;
|
||||
this->setInterval(50);
|
||||
|
||||
// compute distance
|
||||
int16_t dx = x - _first_x;
|
||||
int16_t dy = y - _first_y;
|
||||
uint16_t adx = abs(dx);
|
||||
uint16_t ady = abs(dy);
|
||||
|
||||
// swipe horizontal
|
||||
if (adx > ady && adx > TOUCH_THRESHOLD_X) {
|
||||
if (0 > dx) { // swipe right to left
|
||||
e.touchEvent = static_cast<char>(TOUCH_ACTION_LEFT);
|
||||
LOG_DEBUG("action SWIPE: right to left\n");
|
||||
} else { // swipe left to right
|
||||
e.touchEvent = static_cast<char>(TOUCH_ACTION_RIGHT);
|
||||
LOG_DEBUG("action SWIPE: left to right\n");
|
||||
}
|
||||
}
|
||||
// swipe vertical
|
||||
else if (ady > adx && ady > TOUCH_THRESHOLD_Y) {
|
||||
if (0 > dy) { // swipe bottom to top
|
||||
e.touchEvent = static_cast<char>(TOUCH_ACTION_UP);
|
||||
LOG_DEBUG("action SWIPE: bottom to top\n");
|
||||
} else { // swipe top to bottom
|
||||
e.touchEvent = static_cast<char>(TOUCH_ACTION_DOWN);
|
||||
LOG_DEBUG("action SWIPE: top to bottom\n");
|
||||
}
|
||||
}
|
||||
// tap
|
||||
else {
|
||||
if (duration > 0 && duration < TIME_LONG_PRESS) {
|
||||
if (_tapped) {
|
||||
_tapped = false;
|
||||
e.touchEvent = static_cast<char>(TOUCH_ACTION_DOUBLE_TAP);
|
||||
LOG_DEBUG("action DOUBLE TAP(%d/%d)\n", x, y);
|
||||
} else {
|
||||
_tapped = true;
|
||||
}
|
||||
} else {
|
||||
_tapped = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
_touchedOld = touched;
|
||||
|
||||
// fire TAP event when no 2nd tap occured within time
|
||||
if (_tapped && (time_t(millis()) - _start) > TIME_LONG_PRESS - 50) {
|
||||
_tapped = false;
|
||||
e.touchEvent = static_cast<char>(TOUCH_ACTION_TAP);
|
||||
LOG_DEBUG("action TAP(%d/%d)\n", _last_x, _last_y);
|
||||
}
|
||||
|
||||
// fire LONG_PRESS event without the need for release
|
||||
if (touched && (time_t(millis()) - _start) > TIME_LONG_PRESS) {
|
||||
// tricky: prevent reoccurring events and another touch event when releasing
|
||||
_start = millis() + 30000;
|
||||
e.touchEvent = static_cast<char>(TOUCH_ACTION_LONG_PRESS);
|
||||
LOG_DEBUG("action LONG PRESS(%d/%d)\n", _last_x, _last_y);
|
||||
}
|
||||
|
||||
if (e.touchEvent != TOUCH_ACTION_NONE) {
|
||||
e.source = this->_originName;
|
||||
e.x = _last_x;
|
||||
e.y = _last_y;
|
||||
onEvent(e);
|
||||
}
|
||||
|
||||
return interval;
|
||||
}
|
||||
|
||||
void TouchScreenBase::hapticFeedback()
|
||||
{
|
||||
#ifdef T_WATCH_S3
|
||||
drv.setWaveform(0, 75);
|
||||
drv.setWaveform(1, 0); // end waveform
|
||||
drv.go();
|
||||
#endif
|
||||
}
|
55
src/input/TouchScreenBase.h
Normal file
55
src/input/TouchScreenBase.h
Normal file
@ -0,0 +1,55 @@
|
||||
#pragma once
|
||||
|
||||
#include "InputBroker.h"
|
||||
#include "concurrency/OSThread.h"
|
||||
#include "mesh/NodeDB.h"
|
||||
|
||||
typedef struct _TouchEvent {
|
||||
const char *source;
|
||||
char touchEvent;
|
||||
uint16_t x;
|
||||
uint16_t y;
|
||||
} TouchEvent;
|
||||
|
||||
class TouchScreenBase : public Observable<const InputEvent *>, public concurrency::OSThread
|
||||
{
|
||||
public:
|
||||
explicit TouchScreenBase(const char *name, uint16_t width, uint16_t height);
|
||||
void init(bool hasTouch);
|
||||
|
||||
protected:
|
||||
enum TouchScreenBaseStateType { TOUCH_EVENT_OCCURRED, TOUCH_EVENT_CLEARED };
|
||||
|
||||
enum TouchScreenBaseEventType {
|
||||
TOUCH_ACTION_NONE,
|
||||
TOUCH_ACTION_UP,
|
||||
TOUCH_ACTION_DOWN,
|
||||
TOUCH_ACTION_LEFT,
|
||||
TOUCH_ACTION_RIGHT,
|
||||
TOUCH_ACTION_TAP,
|
||||
TOUCH_ACTION_DOUBLE_TAP,
|
||||
TOUCH_ACTION_LONG_PRESS
|
||||
};
|
||||
|
||||
virtual int32_t runOnce() override;
|
||||
|
||||
virtual bool getTouch(int16_t &x, int16_t &y) = 0;
|
||||
virtual void onEvent(const TouchEvent &event) = 0;
|
||||
|
||||
volatile TouchScreenBaseStateType _state = TOUCH_EVENT_CLEARED;
|
||||
volatile TouchScreenBaseEventType _action = TOUCH_ACTION_NONE;
|
||||
void hapticFeedback();
|
||||
|
||||
protected:
|
||||
uint16_t _display_width;
|
||||
uint16_t _display_height;
|
||||
|
||||
private:
|
||||
bool _touchedOld = false; // previous touch state
|
||||
int16_t _first_x, _last_x; // horizontal swipe direction
|
||||
int16_t _first_y, _last_y; // vertical swipe direction
|
||||
time_t _start; // for LONG_PRESS
|
||||
bool _tapped; // for DOUBLE_TAP
|
||||
|
||||
const char *_originName;
|
||||
};
|
68
src/input/TouchScreenImpl1.cpp
Normal file
68
src/input/TouchScreenImpl1.cpp
Normal file
@ -0,0 +1,68 @@
|
||||
#include "TouchScreenImpl1.h"
|
||||
#include "InputBroker.h"
|
||||
#include "configuration.h"
|
||||
|
||||
TouchScreenImpl1 *touchScreenImpl1;
|
||||
|
||||
TouchScreenImpl1::TouchScreenImpl1(uint16_t width, uint16_t height, bool (*getTouch)(int16_t *, int16_t *))
|
||||
: TouchScreenBase("touchscreen1", width, height), _getTouch(getTouch)
|
||||
{
|
||||
}
|
||||
|
||||
void TouchScreenImpl1::init()
|
||||
{
|
||||
#if !HAS_TOUCHSCREEN
|
||||
TouchScreenBase::init(false);
|
||||
return;
|
||||
#else
|
||||
TouchScreenBase::init(true);
|
||||
inputBroker->registerSource(this);
|
||||
#endif
|
||||
}
|
||||
|
||||
bool TouchScreenImpl1::getTouch(int16_t &x, int16_t &y)
|
||||
{
|
||||
return _getTouch(&x, &y);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief forward touchscreen event
|
||||
*
|
||||
* @param event
|
||||
*
|
||||
* The touchscreen events are translated to input events and reversed
|
||||
*/
|
||||
void TouchScreenImpl1::onEvent(const TouchEvent &event)
|
||||
{
|
||||
InputEvent e;
|
||||
e.source = event.source;
|
||||
switch (event.touchEvent) {
|
||||
case TOUCH_ACTION_LEFT: {
|
||||
e.inputEvent = static_cast<char>(meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_RIGHT);
|
||||
break;
|
||||
}
|
||||
case TOUCH_ACTION_RIGHT: {
|
||||
e.inputEvent = static_cast<char>(meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_LEFT);
|
||||
break;
|
||||
}
|
||||
case TOUCH_ACTION_UP: {
|
||||
e.inputEvent = static_cast<char>(meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_UP);
|
||||
break;
|
||||
}
|
||||
case TOUCH_ACTION_DOWN: {
|
||||
e.inputEvent = static_cast<char>(meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_DOWN);
|
||||
break;
|
||||
}
|
||||
case TOUCH_ACTION_DOUBLE_TAP: {
|
||||
e.inputEvent = static_cast<char>(meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_SELECT);
|
||||
break;
|
||||
}
|
||||
case TOUCH_ACTION_LONG_PRESS: {
|
||||
e.inputEvent = static_cast<char>(meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_CANCEL);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
return;
|
||||
}
|
||||
this->notifyObservers(&e);
|
||||
}
|
17
src/input/TouchScreenImpl1.h
Normal file
17
src/input/TouchScreenImpl1.h
Normal file
@ -0,0 +1,17 @@
|
||||
#pragma once
|
||||
#include "TouchScreenBase.h"
|
||||
|
||||
class TouchScreenImpl1 : public TouchScreenBase
|
||||
{
|
||||
public:
|
||||
TouchScreenImpl1(uint16_t width, uint16_t height, bool (*getTouch)(int16_t *, int16_t *));
|
||||
void init(void);
|
||||
|
||||
protected:
|
||||
virtual bool getTouch(int16_t &x, int16_t &y);
|
||||
virtual void onEvent(const TouchEvent &event);
|
||||
|
||||
bool (*_getTouch)(int16_t *, int16_t *);
|
||||
};
|
||||
|
||||
extern TouchScreenImpl1 *touchScreenImpl1;
|
78
src/input/TrackballInterruptBase.cpp
Normal file
78
src/input/TrackballInterruptBase.cpp
Normal file
@ -0,0 +1,78 @@
|
||||
#include "TrackballInterruptBase.h"
|
||||
#include "configuration.h"
|
||||
|
||||
TrackballInterruptBase::TrackballInterruptBase(const char *name)
|
||||
{
|
||||
this->_originName = name;
|
||||
}
|
||||
|
||||
void TrackballInterruptBase::init(uint8_t pinDown, uint8_t pinUp, uint8_t pinLeft, uint8_t pinRight, uint8_t pinPress,
|
||||
char eventDown, char eventUp, char eventLeft, char eventRight, char eventPressed,
|
||||
void (*onIntDown)(), void (*onIntUp)(), void (*onIntLeft)(), void (*onIntRight)(),
|
||||
void (*onIntPress)())
|
||||
{
|
||||
this->_pinDown = pinDown;
|
||||
this->_pinUp = pinUp;
|
||||
this->_pinLeft = pinLeft;
|
||||
this->_pinRight = pinRight;
|
||||
this->_eventDown = eventDown;
|
||||
this->_eventUp = eventUp;
|
||||
this->_eventLeft = eventLeft;
|
||||
this->_eventRight = eventRight;
|
||||
this->_eventPressed = eventPressed;
|
||||
|
||||
pinMode(pinPress, INPUT_PULLUP);
|
||||
pinMode(this->_pinDown, INPUT_PULLUP);
|
||||
pinMode(this->_pinUp, INPUT_PULLUP);
|
||||
pinMode(this->_pinLeft, INPUT_PULLUP);
|
||||
pinMode(this->_pinRight, INPUT_PULLUP);
|
||||
|
||||
attachInterrupt(pinPress, onIntPress, RISING);
|
||||
attachInterrupt(this->_pinDown, onIntDown, RISING);
|
||||
attachInterrupt(this->_pinUp, onIntUp, RISING);
|
||||
attachInterrupt(this->_pinLeft, onIntLeft, RISING);
|
||||
attachInterrupt(this->_pinRight, onIntRight, RISING);
|
||||
|
||||
LOG_DEBUG("Trackball GPIO initialized (%d, %d, %d, %d, %d)\n", this->_pinUp, this->_pinDown, this->_pinLeft, this->_pinRight,
|
||||
pinPress);
|
||||
}
|
||||
|
||||
void TrackballInterruptBase::intPressHandler()
|
||||
{
|
||||
InputEvent e;
|
||||
e.source = this->_originName;
|
||||
e.inputEvent = this->_eventPressed;
|
||||
this->notifyObservers(&e);
|
||||
}
|
||||
|
||||
void TrackballInterruptBase::intDownHandler()
|
||||
{
|
||||
InputEvent e;
|
||||
e.source = this->_originName;
|
||||
e.inputEvent = this->_eventDown;
|
||||
this->notifyObservers(&e);
|
||||
}
|
||||
|
||||
void TrackballInterruptBase::intUpHandler()
|
||||
{
|
||||
InputEvent e;
|
||||
e.source = this->_originName;
|
||||
e.inputEvent = this->_eventUp;
|
||||
this->notifyObservers(&e);
|
||||
}
|
||||
|
||||
void TrackballInterruptBase::intLeftHandler()
|
||||
{
|
||||
InputEvent e;
|
||||
e.source = this->_originName;
|
||||
e.inputEvent = this->_eventLeft;
|
||||
this->notifyObservers(&e);
|
||||
}
|
||||
|
||||
void TrackballInterruptBase::intRightHandler()
|
||||
{
|
||||
InputEvent e;
|
||||
e.source = this->_originName;
|
||||
e.inputEvent = this->_eventRight;
|
||||
this->notifyObservers(&e);
|
||||
}
|
30
src/input/TrackballInterruptBase.h
Normal file
30
src/input/TrackballInterruptBase.h
Normal file
@ -0,0 +1,30 @@
|
||||
#pragma once
|
||||
|
||||
#include "InputBroker.h"
|
||||
#include "mesh/NodeDB.h"
|
||||
|
||||
class TrackballInterruptBase : public Observable<const InputEvent *>
|
||||
{
|
||||
public:
|
||||
explicit TrackballInterruptBase(const char *name);
|
||||
void init(uint8_t pinDown, uint8_t pinUp, uint8_t pinLeft, uint8_t pinRight, uint8_t pinPress, char eventDown, char eventUp,
|
||||
char eventLeft, char eventRight, char eventPressed, void (*onIntDown)(), void (*onIntUp)(), void (*onIntLeft)(),
|
||||
void (*onIntRight)(), void (*onIntPress)());
|
||||
void intPressHandler();
|
||||
void intDownHandler();
|
||||
void intUpHandler();
|
||||
void intLeftHandler();
|
||||
void intRightHandler();
|
||||
|
||||
private:
|
||||
uint8_t _pinDown = 0;
|
||||
uint8_t _pinUp = 0;
|
||||
uint8_t _pinLeft = 0;
|
||||
uint8_t _pinRight = 0;
|
||||
char _eventDown = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_NONE;
|
||||
char _eventUp = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_NONE;
|
||||
char _eventLeft = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_NONE;
|
||||
char _eventRight = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_NONE;
|
||||
char _eventPressed = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_NONE;
|
||||
const char *_originName;
|
||||
};
|
54
src/input/TrackballInterruptImpl1.cpp
Normal file
54
src/input/TrackballInterruptImpl1.cpp
Normal file
@ -0,0 +1,54 @@
|
||||
#include "TrackballInterruptImpl1.h"
|
||||
#include "InputBroker.h"
|
||||
#include "configuration.h"
|
||||
|
||||
TrackballInterruptImpl1 *trackballInterruptImpl1;
|
||||
|
||||
TrackballInterruptImpl1::TrackballInterruptImpl1() : TrackballInterruptBase("trackball1") {}
|
||||
|
||||
void TrackballInterruptImpl1::init()
|
||||
{
|
||||
#if !HAS_TRACKBALL
|
||||
// Input device is disabled.
|
||||
return;
|
||||
#else
|
||||
uint8_t pinUp = TB_UP;
|
||||
uint8_t pinDown = TB_DOWN;
|
||||
uint8_t pinLeft = TB_LEFT;
|
||||
uint8_t pinRight = TB_RIGHT;
|
||||
uint8_t pinPress = TB_PRESS;
|
||||
|
||||
char eventDown = static_cast<char>(meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_DOWN);
|
||||
char eventUp = static_cast<char>(meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_UP);
|
||||
char eventLeft = static_cast<char>(meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_LEFT);
|
||||
char eventRight = static_cast<char>(meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_RIGHT);
|
||||
char eventPressed = static_cast<char>(meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_SELECT);
|
||||
|
||||
TrackballInterruptBase::init(pinDown, pinUp, pinLeft, pinRight, pinPress, eventDown, eventUp, eventLeft, eventRight,
|
||||
eventPressed, TrackballInterruptImpl1::handleIntDown, TrackballInterruptImpl1::handleIntUp,
|
||||
TrackballInterruptImpl1::handleIntLeft, TrackballInterruptImpl1::handleIntRight,
|
||||
TrackballInterruptImpl1::handleIntPressed);
|
||||
inputBroker->registerSource(this);
|
||||
#endif
|
||||
}
|
||||
|
||||
void TrackballInterruptImpl1::handleIntDown()
|
||||
{
|
||||
trackballInterruptImpl1->intDownHandler();
|
||||
}
|
||||
void TrackballInterruptImpl1::handleIntUp()
|
||||
{
|
||||
trackballInterruptImpl1->intUpHandler();
|
||||
}
|
||||
void TrackballInterruptImpl1::handleIntLeft()
|
||||
{
|
||||
trackballInterruptImpl1->intLeftHandler();
|
||||
}
|
||||
void TrackballInterruptImpl1::handleIntRight()
|
||||
{
|
||||
trackballInterruptImpl1->intRightHandler();
|
||||
}
|
||||
void TrackballInterruptImpl1::handleIntPressed()
|
||||
{
|
||||
trackballInterruptImpl1->intPressHandler();
|
||||
}
|
16
src/input/TrackballInterruptImpl1.h
Normal file
16
src/input/TrackballInterruptImpl1.h
Normal file
@ -0,0 +1,16 @@
|
||||
#pragma once
|
||||
#include "TrackballInterruptBase.h"
|
||||
|
||||
class TrackballInterruptImpl1 : public TrackballInterruptBase
|
||||
{
|
||||
public:
|
||||
TrackballInterruptImpl1();
|
||||
void init();
|
||||
static void handleIntDown();
|
||||
static void handleIntUp();
|
||||
static void handleIntLeft();
|
||||
static void handleIntRight();
|
||||
static void handleIntPressed();
|
||||
};
|
||||
|
||||
extern TrackballInterruptImpl1 *trackballInterruptImpl1;
|
@ -23,7 +23,7 @@ void UpDownInterruptBase::init(uint8_t pinDown, uint8_t pinUp, uint8_t pinPress,
|
||||
attachInterrupt(this->_pinDown, onIntDown, RISING);
|
||||
attachInterrupt(this->_pinUp, onIntUp, RISING);
|
||||
|
||||
LOG_DEBUG("GPIO initialized (%d, %d, %d)\n", this->_pinDown, this->_pinUp, pinPress);
|
||||
LOG_DEBUG("Up/down/press GPIO initialized (%d, %d, %d)\n", this->_pinUp, this->_pinDown, pinPress);
|
||||
}
|
||||
|
||||
void UpDownInterruptBase::intPressHandler()
|
||||
|
@ -7,7 +7,7 @@ CardKbI2cImpl::CardKbI2cImpl() : KbI2cBase("cardKB") {}
|
||||
|
||||
void CardKbI2cImpl::init()
|
||||
{
|
||||
if (cardkb_found.address != CARDKB_ADDR) {
|
||||
if (cardkb_found.address != CARDKB_ADDR && cardkb_found.address != TDECK_KB_ADDR) {
|
||||
disable();
|
||||
return;
|
||||
}
|
||||
|
@ -41,7 +41,7 @@ void write_to_14004(const TwoWire * i2cBus, uint8_t reg, uint8_t data)
|
||||
|
||||
int32_t KbI2cBase::runOnce()
|
||||
{
|
||||
if (cardkb_found.address != CARDKB_ADDR) {
|
||||
if (cardkb_found.address != CARDKB_ADDR && cardkb_found.address != TDECK_KB_ADDR) {
|
||||
// Input device is not detected.
|
||||
return INT32_MAX;
|
||||
}
|
||||
@ -85,9 +85,9 @@ int32_t KbI2cBase::runOnce()
|
||||
e.kbchar = PrintDataBuf;
|
||||
this->notifyObservers(&e);
|
||||
}
|
||||
} else {
|
||||
// m5 cardkb
|
||||
i2cBus->requestFrom(CARDKB_ADDR, 1);
|
||||
} else if (kb_model == 0x00 || kb_model == 0x10) {
|
||||
// m5 cardkb and T-Deck
|
||||
i2cBus->requestFrom(kb_model == 0x00 ? CARDKB_ADDR : TDECK_KB_ADDR, 1);
|
||||
|
||||
while (i2cBus->available()) {
|
||||
char c = i2cBus->read();
|
||||
@ -132,6 +132,8 @@ int32_t KbI2cBase::runOnce()
|
||||
this->notifyObservers(&e);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
LOG_WARN("Unknown kb_model 0x%02x\n", kb_model);
|
||||
}
|
||||
return 500;
|
||||
return 300;
|
||||
}
|
||||
|
18
src/main.cpp
18
src/main.cpp
@ -96,7 +96,7 @@ ScanI2C::DeviceAddress screen_found = ScanI2C::ADDRESS_NONE;
|
||||
|
||||
// The I2C address of the cardkb or RAK14004 (if found)
|
||||
ScanI2C::DeviceAddress cardkb_found = ScanI2C::ADDRESS_NONE;
|
||||
// 0x02 for RAK14004 and 0x00 for cardkb
|
||||
// 0x02 for RAK14004, 0x00 for cardkb, 0x10 for T-Deck
|
||||
uint8_t kb_model;
|
||||
|
||||
// The I2C address of the RTC Module (if found)
|
||||
@ -300,6 +300,15 @@ void setup()
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef T_DECK
|
||||
// enable keyboard
|
||||
pinMode(KB_POWERON, OUTPUT);
|
||||
digitalWrite(KB_POWERON, HIGH);
|
||||
// There needs to be a delay after power on, give LILYGO-KEYBOARD some startup time
|
||||
// otherwise keyboard and touch screen will not work
|
||||
delay(800);
|
||||
#endif
|
||||
|
||||
// Currently only the tbeam has a PMU
|
||||
// PMU initialization needs to be placed before i2c scanning
|
||||
power = new Power();
|
||||
@ -372,8 +381,15 @@ void setup()
|
||||
kb_model = 0x02;
|
||||
break;
|
||||
case ScanI2C::DeviceType::CARDKB:
|
||||
kb_model = 0x00;
|
||||
break;
|
||||
case ScanI2C::DeviceType::TDECKKB:
|
||||
// assign an arbitrary value to distinguish from other models
|
||||
kb_model = 0x10;
|
||||
break;
|
||||
default:
|
||||
// use this as default since it's also just zero
|
||||
LOG_WARN("kb_info.type is unknown(0x%02x), setting kb_model=0x00\n", kb_info.type);
|
||||
kb_model = 0x00;
|
||||
}
|
||||
}
|
||||
|
@ -164,12 +164,21 @@ int CannedMessageModule::handleInputEvent(const InputEvent *event)
|
||||
(event->inputEvent == static_cast<char>(meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_LEFT)) ||
|
||||
(event->inputEvent == static_cast<char>(meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_RIGHT))) {
|
||||
LOG_DEBUG("Canned message event (%x)\n", event->kbchar);
|
||||
if (this->runState == CANNED_MESSAGE_RUN_STATE_FREETEXT) {
|
||||
// tweak for left/right events generated via trackball/touch with empty kbchar
|
||||
if (!event->kbchar) {
|
||||
if (event->inputEvent == static_cast<char>(meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_LEFT)) {
|
||||
this->payload = 0xb4;
|
||||
this->destSelect = true;
|
||||
} else if (event->inputEvent == static_cast<char>(meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_RIGHT)) {
|
||||
this->payload = 0xb7;
|
||||
this->destSelect = true;
|
||||
}
|
||||
} else {
|
||||
// pass the pressed key
|
||||
this->payload = event->kbchar;
|
||||
this->lastTouchMillis = millis();
|
||||
validEvent = true;
|
||||
}
|
||||
this->lastTouchMillis = millis();
|
||||
validEvent = true;
|
||||
}
|
||||
if (event->inputEvent == static_cast<char>(ANYKEY)) {
|
||||
LOG_DEBUG("Canned message event any key pressed\n");
|
||||
@ -225,7 +234,7 @@ int32_t CannedMessageModule::runOnce()
|
||||
(this->runState == CANNED_MESSAGE_RUN_STATE_INACTIVE)) {
|
||||
return INT32_MAX;
|
||||
}
|
||||
LOG_DEBUG("Check status\n");
|
||||
// LOG_DEBUG("Check status\n");
|
||||
UIFrameEvent e = {false, true};
|
||||
if (this->runState == CANNED_MESSAGE_RUN_STATE_SENDING_ACTIVE) {
|
||||
// TODO: might have some feedback of sendig state
|
||||
@ -300,8 +309,7 @@ int32_t CannedMessageModule::runOnce()
|
||||
this->runState = CANNED_MESSAGE_RUN_STATE_ACTIVE;
|
||||
LOG_DEBUG("MOVE DOWN (%d):%s\n", this->currentMessageIndex, this->getCurrentMessage());
|
||||
}
|
||||
} else if (this->runState == CANNED_MESSAGE_RUN_STATE_FREETEXT) {
|
||||
e.frameChanged = true;
|
||||
} else if (this->runState == CANNED_MESSAGE_RUN_STATE_FREETEXT || this->runState == CANNED_MESSAGE_RUN_STATE_ACTIVE) {
|
||||
switch (this->payload) {
|
||||
case 0xb4: // left
|
||||
if (this->destSelect) {
|
||||
@ -347,38 +355,49 @@ int32_t CannedMessageModule::runOnce()
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 0x08: // backspace
|
||||
if (this->freetext.length() > 0) {
|
||||
if (this->cursor == this->freetext.length()) {
|
||||
this->freetext = this->freetext.substring(0, this->freetext.length() - 1);
|
||||
} else {
|
||||
this->freetext = this->freetext.substring(0, this->cursor - 1) +
|
||||
this->freetext.substring(this->cursor, this->freetext.length());
|
||||
}
|
||||
this->cursor--;
|
||||
}
|
||||
break;
|
||||
case 0x09: // tab
|
||||
if (this->destSelect) {
|
||||
this->destSelect = false;
|
||||
} else {
|
||||
this->destSelect = true;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
if (this->cursor == this->freetext.length()) {
|
||||
this->freetext += this->payload;
|
||||
} else {
|
||||
this->freetext =
|
||||
this->freetext.substring(0, this->cursor) + this->payload + this->freetext.substring(this->cursor);
|
||||
}
|
||||
this->cursor += 1;
|
||||
if (this->freetext.length() > meshtastic_Constants_DATA_PAYLOAD_LEN) {
|
||||
this->cursor = meshtastic_Constants_DATA_PAYLOAD_LEN;
|
||||
this->freetext = this->freetext.substring(0, meshtastic_Constants_DATA_PAYLOAD_LEN);
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (this->runState == CANNED_MESSAGE_RUN_STATE_FREETEXT) {
|
||||
e.frameChanged = true;
|
||||
switch (this->payload) {
|
||||
case 0x08: // backspace
|
||||
if (this->freetext.length() > 0) {
|
||||
if (this->cursor == this->freetext.length()) {
|
||||
this->freetext = this->freetext.substring(0, this->freetext.length() - 1);
|
||||
} else {
|
||||
this->freetext = this->freetext.substring(0, this->cursor - 1) +
|
||||
this->freetext.substring(this->cursor, this->freetext.length());
|
||||
}
|
||||
this->cursor--;
|
||||
}
|
||||
break;
|
||||
case 0x09: // tab
|
||||
if (this->destSelect) {
|
||||
this->destSelect = false;
|
||||
} else {
|
||||
this->destSelect = true;
|
||||
}
|
||||
break;
|
||||
case 0xb4: // left
|
||||
case 0xb7: // right
|
||||
// already handled above
|
||||
break;
|
||||
default:
|
||||
if (this->cursor == this->freetext.length()) {
|
||||
this->freetext += this->payload;
|
||||
} else {
|
||||
this->freetext =
|
||||
this->freetext.substring(0, this->cursor) + this->payload + this->freetext.substring(this->cursor);
|
||||
}
|
||||
this->cursor += 1;
|
||||
if (this->freetext.length() > meshtastic_Constants_DATA_PAYLOAD_LEN) {
|
||||
this->cursor = meshtastic_Constants_DATA_PAYLOAD_LEN;
|
||||
this->freetext = this->freetext.substring(0, meshtastic_Constants_DATA_PAYLOAD_LEN);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
this->lastTouchMillis = millis();
|
||||
this->notifyObservers(&e);
|
||||
@ -406,6 +425,11 @@ const char *CannedMessageModule::getNextMessage()
|
||||
{
|
||||
return this->messages[this->getNextIndex()];
|
||||
}
|
||||
const char *CannedMessageModule::getMessageByIndex(int index)
|
||||
{
|
||||
return (index >= 0 && index < this->messagesCount) ? this->messages[index] : "";
|
||||
}
|
||||
|
||||
const char *CannedMessageModule::getNodeName(NodeNum node)
|
||||
{
|
||||
if (node == NODENUM_BROADCAST) {
|
||||
@ -482,12 +506,31 @@ void CannedMessageModule::drawFrame(OLEDDisplay *display, OLEDDisplayUiState *st
|
||||
display->setTextAlignment(TEXT_ALIGN_LEFT);
|
||||
display->setFont(FONT_SMALL);
|
||||
display->drawStringf(0 + x, 0 + y, buffer, "To: %s", cannedMessageModule->getNodeName(this->dest));
|
||||
display->drawString(0 + x, 0 + y + FONT_HEIGHT_SMALL, cannedMessageModule->getPrevMessage());
|
||||
display->fillRect(0 + x, 0 + y + FONT_HEIGHT_SMALL * 2, x + display->getWidth(), y + FONT_HEIGHT_SMALL);
|
||||
display->setColor(BLACK);
|
||||
display->drawString(0 + x, 0 + y + FONT_HEIGHT_SMALL * 2, cannedMessageModule->getCurrentMessage());
|
||||
display->setColor(WHITE);
|
||||
display->drawString(0 + x, 0 + y + FONT_HEIGHT_SMALL * 3, cannedMessageModule->getNextMessage());
|
||||
int lines = (display->getHeight() / FONT_HEIGHT_SMALL) - 1;
|
||||
if (lines == 3) {
|
||||
// static (old) behavior for small displays
|
||||
display->drawString(0 + x, 0 + y + FONT_HEIGHT_SMALL, cannedMessageModule->getPrevMessage());
|
||||
display->fillRect(0 + x, 0 + y + FONT_HEIGHT_SMALL * 2, x + display->getWidth(), y + FONT_HEIGHT_SMALL);
|
||||
display->setColor(BLACK);
|
||||
display->drawString(0 + x, 0 + y + FONT_HEIGHT_SMALL * 2, cannedMessageModule->getCurrentMessage());
|
||||
display->setColor(WHITE);
|
||||
display->drawString(0 + x, 0 + y + FONT_HEIGHT_SMALL * 3, cannedMessageModule->getNextMessage());
|
||||
} else {
|
||||
// use entire display height for larger displays
|
||||
int topMsg = (messagesCount > lines && currentMessageIndex >= lines - 1) ? currentMessageIndex - lines + 2 : 0;
|
||||
for (int i = 0; i < std::min(messagesCount, lines); i++) {
|
||||
if (i == currentMessageIndex - topMsg) {
|
||||
display->fillRect(0 + x, 0 + y + FONT_HEIGHT_SMALL * (i + 1), x + display->getWidth(),
|
||||
y + FONT_HEIGHT_SMALL);
|
||||
display->setColor(BLACK);
|
||||
display->drawString(0 + x, 0 + y + FONT_HEIGHT_SMALL * (i + 1), cannedMessageModule->getCurrentMessage());
|
||||
display->setColor(WHITE);
|
||||
} else {
|
||||
display->drawString(0 + x, 0 + y + FONT_HEIGHT_SMALL * (i + 1),
|
||||
cannedMessageModule->getMessageByIndex(topMsg + i));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -30,6 +30,7 @@ class CannedMessageModule : public SinglePortModule, public Observable<const UIF
|
||||
const char *getCurrentMessage();
|
||||
const char *getPrevMessage();
|
||||
const char *getNextMessage();
|
||||
const char *getMessageByIndex(int index);
|
||||
const char *getNodeName(NodeNum node);
|
||||
bool shouldDraw();
|
||||
void eventUp();
|
||||
|
@ -1,6 +1,7 @@
|
||||
#include "configuration.h"
|
||||
#include "input/InputBroker.h"
|
||||
#include "input/RotaryEncoderInterruptImpl1.h"
|
||||
#include "input/TrackballInterruptImpl1.h"
|
||||
#include "input/UpDownInterruptImpl1.h"
|
||||
#include "input/cardKbI2cImpl.h"
|
||||
#include "modules/AdminModule.h"
|
||||
@ -62,6 +63,10 @@ void setupModules()
|
||||
cardKbI2cImpl = new CardKbI2cImpl();
|
||||
cardKbI2cImpl->init();
|
||||
#endif
|
||||
#if HAS_TRACKBALL
|
||||
trackballInterruptImpl1 = new TrackballInterruptImpl1();
|
||||
trackballInterruptImpl1->init();
|
||||
#endif
|
||||
#if HAS_SCREEN
|
||||
cannedMessageModule = new CannedMessageModule();
|
||||
#endif
|
||||
|
@ -16,8 +16,11 @@
|
||||
#define TFT_OFFSET_X 0
|
||||
#define TFT_OFFSET_Y 0
|
||||
#define SCREEN_ROTATE
|
||||
#define SCREEN_TRANSITION_FRAMERATE 1 // fps
|
||||
#define SCREEN_TRANSITION_FRAMERATE 5
|
||||
|
||||
#define HAS_TOUCHSCREEN 1
|
||||
#define SCREEN_TOUCH_INT 16
|
||||
#define TOUCH_I2C_PORT 0
|
||||
#define TOUCH_SLAVE_ADDRESS 0x5D // GT911
|
||||
|
||||
#define BUTTON_PIN 0
|
||||
@ -43,14 +46,25 @@
|
||||
// keyboard
|
||||
#define I2C_SDA 18 // I2C pins for this board
|
||||
#define I2C_SCL 8
|
||||
#define BOARD_POWERON 10 // must be set to HIGH
|
||||
#define KB_SLAVE_ADDRESS 0x55
|
||||
#define KB_BL_PIN 46 // INT, set to INPUT
|
||||
#define KB_UP 2
|
||||
#define KB_DOWN 3
|
||||
#define KB_LEFT 1
|
||||
#define KB_RIGHT 15
|
||||
#define KB_POWERON 10 // must be set to HIGH
|
||||
#define KB_SLAVE_ADDRESS TDECK_KB_ADDR // 0x55
|
||||
#define KB_BL_PIN 46 // not used for now
|
||||
|
||||
// trackball
|
||||
#define HAS_TRACKBALL 1
|
||||
#define TB_UP 3
|
||||
#define TB_DOWN 15
|
||||
#define TB_LEFT 1
|
||||
#define TB_RIGHT 2
|
||||
#define TB_PRESS BUTTON_PIN
|
||||
|
||||
// microphone
|
||||
#define ES7210_SCK 47
|
||||
#define ES7210_DIN 14
|
||||
#define ES7210_LRCK 21
|
||||
#define ES7210_MCLK 48
|
||||
|
||||
// LoRa
|
||||
#define USE_SX1262
|
||||
#define USE_SX1268
|
||||
|
||||
|
@ -16,10 +16,13 @@
|
||||
#define TFT_OFFSET_X 0
|
||||
#define TFT_OFFSET_Y 0
|
||||
#define SCREEN_ROTATE
|
||||
#define SCREEN_TRANSITION_FRAMERATE 1 // fps
|
||||
#define SCREEN_TRANSITION_FRAMERATE 5 // fps
|
||||
|
||||
#define HAS_TOUCHSCREEN 1
|
||||
#define SCREEN_TOUCH_INT 16
|
||||
#define SCREEN_TOUCH_USE_I2C1 1
|
||||
#define TOUCH_SLAVE_ADDRESS 0x38 // GT911
|
||||
#define SCREEN_TOUCH_USE_I2C1
|
||||
#define TOUCH_I2C_PORT 1
|
||||
#define TOUCH_SLAVE_ADDRESS 0x38
|
||||
|
||||
#define I2C_SDA1 39 // Used for capacitive touch
|
||||
#define I2C_SCL1 40 // Used for capacitive touch
|
||||
|
Loading…
Reference in New Issue
Block a user