mirror of
https://github.com/meshtastic/firmware.git
synced 2025-10-16 18:26:26 +00:00
Refactor display handling add Raspbian TFT display (#2998)
* Refactor display handling add Raspbian TFT display * Add missed change * Add static casts * Add missed TFT refactor for RAK14014 * Add missed GPIO configuration * Adds Native keyboard input option * Get the ifdefs right * CannedMessage send via queue, not run immediately. * Fixup systemd service file * Add display blanking for Raspberry Pi * Add a couple missed key definitions --------- Co-authored-by: Ben Meadors <benmmeadors@gmail.com>
This commit is contained in:
parent
d14d2c89c3
commit
2ebaea317a
@ -1,6 +1,6 @@
|
|||||||
; The Portduino based sim environment on top of any host OS, all hardware will be simulated
|
; The Portduino based sim environment on top of any host OS, all hardware will be simulated
|
||||||
[portduino_base]
|
[portduino_base]
|
||||||
platform = https://github.com/meshtastic/platform-native.git#05255283879a0c65a7d3eba6c468b9186438bb14
|
platform = https://github.com/meshtastic/platform-native.git#ff5da1d203b5c1163cfcda858d5f84920187f030
|
||||||
framework = arduino
|
framework = arduino
|
||||||
|
|
||||||
build_src_filter =
|
build_src_filter =
|
||||||
@ -28,5 +28,4 @@ build_flags =
|
|||||||
${arduino_base.build_flags}
|
${arduino_base.build_flags}
|
||||||
-fPIC
|
-fPIC
|
||||||
-Isrc/platform/portduino
|
-Isrc/platform/portduino
|
||||||
-DRADIOLIB_EEPROM_UNSUPPORTED
|
-DRADIOLIB_EEPROM_UNSUPPORTED
|
||||||
|
|
@ -1,5 +1,5 @@
|
|||||||
# Define your devices here using Broadcom pin numbering
|
### Define your devices here using Broadcom pin numbering
|
||||||
# Uncomment the block that corresponds to your hardware
|
### Uncomment the block that corresponds to your hardware
|
||||||
---
|
---
|
||||||
Lora:
|
Lora:
|
||||||
# Module: sx1262 # Waveshare SX126X XXXM
|
# Module: sx1262 # Waveshare SX126X XXXM
|
||||||
@ -25,16 +25,40 @@ Lora:
|
|||||||
# CS: 7
|
# CS: 7
|
||||||
# IRQ: 25
|
# IRQ: 25
|
||||||
|
|
||||||
# Set gpio chip to use in /dev/. Defaults to 0.
|
### Set gpio chip to use in /dev/. Defaults to 0.
|
||||||
# Notably the Raspberry Pi 5 puts the GPIO header on gpiochip4
|
### Notably the Raspberry Pi 5 puts the GPIO header on gpiochip4
|
||||||
# gpiochip: 4
|
# gpiochip: 4
|
||||||
|
|
||||||
# Define GPIO buttons here:
|
### Define GPIO buttons here:
|
||||||
|
|
||||||
GPIO:
|
GPIO:
|
||||||
# User: 6
|
# User: 6
|
||||||
|
|
||||||
# Define GPS
|
### Define GPS
|
||||||
|
|
||||||
GPS:
|
GPS:
|
||||||
# SerialPath: /dev/ttyS0
|
# SerialPath: /dev/ttyS0
|
||||||
|
|
||||||
|
### Set up SPI displays here. Note that I2C displays are generally auto-detected.
|
||||||
|
|
||||||
|
Display:
|
||||||
|
|
||||||
|
### Waveshare 2.8inch RPi LCD
|
||||||
|
# Panel: ST7789
|
||||||
|
# CS: 8
|
||||||
|
# DC: 22 # Data/Command pin
|
||||||
|
# Backlight: 18
|
||||||
|
# Width: 240
|
||||||
|
# Height: 320
|
||||||
|
# Reset: 27
|
||||||
|
# Rotate: true
|
||||||
|
|
||||||
|
Touchscreen:
|
||||||
|
# Module: XPT2046
|
||||||
|
# CS: 7
|
||||||
|
# IRQ: 17
|
||||||
|
|
||||||
|
### Configure device for direct keyboard input
|
||||||
|
|
||||||
|
Input:
|
||||||
|
# KeyboardDevice: /dev/input/event0
|
||||||
|
@ -1,9 +1,12 @@
|
|||||||
[unit]
|
[Unit]
|
||||||
description=Meshtastic Native Daemon
|
Description=Meshtastic Native Daemon
|
||||||
|
After=network-online.target
|
||||||
|
|
||||||
[Service]
|
[Service]
|
||||||
|
User=root
|
||||||
|
Group=root
|
||||||
Type=simple
|
Type=simple
|
||||||
ExecStart=/usr/sbin/meshtasticd
|
ExecStart=/usr/sbin/meshtasticd
|
||||||
|
|
||||||
[Install]
|
[Install]
|
||||||
WantedBy=multi-user.target
|
WantedBy=multi-user.target
|
@ -52,6 +52,10 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|||||||
#include "modules/esp32/StoreForwardModule.h"
|
#include "modules/esp32/StoreForwardModule.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if ARCH_RASPBERRY_PI
|
||||||
|
#include "platform/portduino/PortduinoGlue.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef OLED_RU
|
#ifdef OLED_RU
|
||||||
#include "fonts/OLEDDisplayFontsRU.h"
|
#include "fonts/OLEDDisplayFontsRU.h"
|
||||||
#endif
|
#endif
|
||||||
@ -909,10 +913,40 @@ static void drawNodeInfo(OLEDDisplay *display, OLEDDisplayUiState *state, int16_
|
|||||||
}
|
}
|
||||||
|
|
||||||
Screen::Screen(ScanI2C::DeviceAddress address, meshtastic_Config_DisplayConfig_OledType screenType, OLEDDISPLAY_GEOMETRY geometry)
|
Screen::Screen(ScanI2C::DeviceAddress address, meshtastic_Config_DisplayConfig_OledType screenType, OLEDDISPLAY_GEOMETRY geometry)
|
||||||
: concurrency::OSThread("Screen"), address_found(address), model(screenType), geometry(geometry), cmdQueue(32),
|
: concurrency::OSThread("Screen"), address_found(address), model(screenType), geometry(geometry), cmdQueue(32)
|
||||||
dispdev(address.address, -1, -1, geometry, (address.port == ScanI2C::I2CPort::WIRE1) ? HW_I2C::I2C_TWO : HW_I2C::I2C_ONE),
|
|
||||||
ui(&dispdev)
|
|
||||||
{
|
{
|
||||||
|
#if defined(USE_SH1106) || defined(USE_SH1107) || defined(USE_SH1107_128_64)
|
||||||
|
dispdev = new SH1106Wire(address.address, -1, -1, geometry,
|
||||||
|
(address.port == ScanI2C::I2CPort::WIRE1) ? HW_I2C::I2C_TWO : HW_I2C::I2C_ONE);
|
||||||
|
#elif defined(USE_SSD1306)
|
||||||
|
dispdev = new SSD1306Wire(address.address, -1, -1, geometry,
|
||||||
|
(address.port == ScanI2C::I2CPort::WIRE1) ? HW_I2C::I2C_TWO : HW_I2C::I2C_ONE);
|
||||||
|
#elif defined(ST7735_CS) || defined(ILI9341_DRIVER) || defined(ST7789_CS) || defined(RAK14014)
|
||||||
|
dispdev = new TFTDisplay(address.address, -1, -1, geometry,
|
||||||
|
(address.port == ScanI2C::I2CPort::WIRE1) ? HW_I2C::I2C_TWO : HW_I2C::I2C_ONE);
|
||||||
|
#elif defined(USE_EINK)
|
||||||
|
dispdev = new EInkDisplay(address.address, -1, -1, geometry,
|
||||||
|
(address.port == ScanI2C::I2CPort::WIRE1) ? HW_I2C::I2C_TWO : HW_I2C::I2C_ONE);
|
||||||
|
#elif defined(USE_ST7567)
|
||||||
|
dispdev = new ST7567Wire(address.address, -1, -1, geometry,
|
||||||
|
(address.port == ScanI2C::I2CPort::WIRE1) ? HW_I2C::I2C_TWO : HW_I2C::I2C_ONE);
|
||||||
|
#elif ARCH_RASPBERRY_PI
|
||||||
|
if (settingsMap[displayPanel] == st7789) {
|
||||||
|
LOG_DEBUG("Making TFTDisplay!\n");
|
||||||
|
dispdev = new TFTDisplay(address.address, -1, -1, geometry,
|
||||||
|
(address.port == ScanI2C::I2CPort::WIRE1) ? HW_I2C::I2C_TWO : HW_I2C::I2C_ONE);
|
||||||
|
} else {
|
||||||
|
dispdev = new AutoOLEDWire(address.address, -1, -1, geometry,
|
||||||
|
(address.port == ScanI2C::I2CPort::WIRE1) ? HW_I2C::I2C_TWO : HW_I2C::I2C_ONE);
|
||||||
|
isAUTOOled = true;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
dispdev = new AutoOLEDWire(address.address, -1, -1, geometry,
|
||||||
|
(address.port == ScanI2C::I2CPort::WIRE1) ? HW_I2C::I2C_TWO : HW_I2C::I2C_ONE);
|
||||||
|
isAUTOOled = true;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
ui = new OLEDDisplayUi(dispdev);
|
||||||
cmdQueue.setReader(this);
|
cmdQueue.setReader(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -925,8 +959,8 @@ void Screen::doDeepSleep()
|
|||||||
#ifdef USE_EINK
|
#ifdef USE_EINK
|
||||||
static FrameCallback sleepFrames[] = {drawSleepScreen};
|
static FrameCallback sleepFrames[] = {drawSleepScreen};
|
||||||
static const int sleepFrameCount = sizeof(sleepFrames) / sizeof(sleepFrames[0]);
|
static const int sleepFrameCount = sizeof(sleepFrames) / sizeof(sleepFrames[0]);
|
||||||
ui.setFrames(sleepFrames, sleepFrameCount);
|
ui->setFrames(sleepFrames, sleepFrameCount);
|
||||||
ui.update();
|
ui->update();
|
||||||
#endif
|
#endif
|
||||||
setOn(false);
|
setOn(false);
|
||||||
}
|
}
|
||||||
@ -942,14 +976,16 @@ void Screen::handleSetOn(bool on)
|
|||||||
#ifdef T_WATCH_S3
|
#ifdef T_WATCH_S3
|
||||||
PMU->enablePowerOutput(XPOWERS_ALDO2);
|
PMU->enablePowerOutput(XPOWERS_ALDO2);
|
||||||
#endif
|
#endif
|
||||||
dispdev.displayOn();
|
#if !ARCH_RASPBERRY_PI
|
||||||
dispdev.displayOn();
|
dispdev->displayOn();
|
||||||
|
#endif
|
||||||
|
dispdev->displayOn();
|
||||||
enabled = true;
|
enabled = true;
|
||||||
setInterval(0); // Draw ASAP
|
setInterval(0); // Draw ASAP
|
||||||
runASAP = true;
|
runASAP = true;
|
||||||
} else {
|
} else {
|
||||||
LOG_INFO("Turning off screen\n");
|
LOG_INFO("Turning off screen\n");
|
||||||
dispdev.displayOff();
|
dispdev->displayOff();
|
||||||
#ifdef T_WATCH_S3
|
#ifdef T_WATCH_S3
|
||||||
PMU->disablePowerOutput(XPOWERS_ALDO2);
|
PMU->disablePowerOutput(XPOWERS_ALDO2);
|
||||||
#endif
|
#endif
|
||||||
@ -966,32 +1002,33 @@ void Screen::setup()
|
|||||||
useDisplay = true;
|
useDisplay = true;
|
||||||
|
|
||||||
#ifdef AutoOLEDWire_h
|
#ifdef AutoOLEDWire_h
|
||||||
dispdev.setDetected(model);
|
if (isAUTOOled)
|
||||||
|
static_cast<AutoOLEDWire *>(dispdev)->setDetected(model);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef USE_SH1107_128_64
|
#ifdef USE_SH1107_128_64
|
||||||
dispdev.setSubtype(7);
|
static_cast<SH1106Wire *>(dispdev)->setSubtype(7);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Initialising the UI will init the display too.
|
// Initialising the UI will init the display too.
|
||||||
ui.init();
|
ui->init();
|
||||||
|
|
||||||
displayWidth = dispdev.width();
|
displayWidth = dispdev->width();
|
||||||
displayHeight = dispdev.height();
|
displayHeight = dispdev->height();
|
||||||
|
|
||||||
ui.setTimePerTransition(0);
|
ui->setTimePerTransition(0);
|
||||||
|
|
||||||
ui.setIndicatorPosition(BOTTOM);
|
ui->setIndicatorPosition(BOTTOM);
|
||||||
// Defines where the first frame is located in the bar.
|
// Defines where the first frame is located in the bar.
|
||||||
ui.setIndicatorDirection(LEFT_RIGHT);
|
ui->setIndicatorDirection(LEFT_RIGHT);
|
||||||
ui.setFrameAnimation(SLIDE_LEFT);
|
ui->setFrameAnimation(SLIDE_LEFT);
|
||||||
// Don't show the page swipe dots while in boot screen.
|
// Don't show the page swipe dots while in boot screen.
|
||||||
ui.disableAllIndicators();
|
ui->disableAllIndicators();
|
||||||
// Store a pointer to Screen so we can get to it from static functions.
|
// Store a pointer to Screen so we can get to it from static functions.
|
||||||
ui.getUiState()->userData = this;
|
ui->getUiState()->userData = this;
|
||||||
|
|
||||||
// Set the utf8 conversion function
|
// Set the utf8 conversion function
|
||||||
dispdev.setFontTableLookupFunction(customFontTableLookup);
|
dispdev->setFontTableLookupFunction(customFontTableLookup);
|
||||||
|
|
||||||
if (strlen(oemStore.oem_text) > 0)
|
if (strlen(oemStore.oem_text) > 0)
|
||||||
logo_timeout *= 2;
|
logo_timeout *= 2;
|
||||||
@ -999,23 +1036,23 @@ void Screen::setup()
|
|||||||
// Add frames.
|
// Add frames.
|
||||||
static FrameCallback bootFrames[] = {drawBootScreen};
|
static FrameCallback bootFrames[] = {drawBootScreen};
|
||||||
static const int bootFrameCount = sizeof(bootFrames) / sizeof(bootFrames[0]);
|
static const int bootFrameCount = sizeof(bootFrames) / sizeof(bootFrames[0]);
|
||||||
ui.setFrames(bootFrames, bootFrameCount);
|
ui->setFrames(bootFrames, bootFrameCount);
|
||||||
// No overlays.
|
// No overlays.
|
||||||
ui.setOverlays(nullptr, 0);
|
ui->setOverlays(nullptr, 0);
|
||||||
|
|
||||||
// Require presses to switch between frames.
|
// Require presses to switch between frames.
|
||||||
ui.disableAutoTransition();
|
ui->disableAutoTransition();
|
||||||
|
|
||||||
// Set up a log buffer with 3 lines, 32 chars each.
|
// Set up a log buffer with 3 lines, 32 chars each.
|
||||||
dispdev.setLogBuffer(3, 32);
|
dispdev->setLogBuffer(3, 32);
|
||||||
|
|
||||||
#ifdef SCREEN_MIRROR
|
#ifdef SCREEN_MIRROR
|
||||||
dispdev.mirrorScreen();
|
dispdev->mirrorScreen();
|
||||||
#else
|
#else
|
||||||
// Standard behaviour is to FLIP the screen (needed on T-Beam). If this config item is set, unflip it, and thereby logically
|
// Standard behaviour is to FLIP the screen (needed on T-Beam). If this config item is set, unflip it, and thereby logically
|
||||||
// flip it. If you have a headache now, you're welcome.
|
// flip it. If you have a headache now, you're welcome.
|
||||||
if (!config.display.flip_screen) {
|
if (!config.display.flip_screen) {
|
||||||
dispdev.flipScreenVertically();
|
dispdev->flipScreenVertically();
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -1023,20 +1060,30 @@ void Screen::setup()
|
|||||||
uint8_t dmac[6];
|
uint8_t dmac[6];
|
||||||
getMacAddr(dmac);
|
getMacAddr(dmac);
|
||||||
snprintf(ourId, sizeof(ourId), "%02x%02x", dmac[4], dmac[5]);
|
snprintf(ourId, sizeof(ourId), "%02x%02x", dmac[4], dmac[5]);
|
||||||
|
#if ARCH_RASPBERRY_PI
|
||||||
|
handleSetOn(false); // force clean init
|
||||||
|
#endif
|
||||||
|
|
||||||
// Turn on the display.
|
// Turn on the display.
|
||||||
handleSetOn(true);
|
handleSetOn(true);
|
||||||
|
|
||||||
// On some ssd1306 clones, the first draw command is discarded, so draw it
|
// On some ssd1306 clones, the first draw command is discarded, so draw it
|
||||||
// twice initially. Skip this for EINK Displays to save a few seconds during boot
|
// twice initially. Skip this for EINK Displays to save a few seconds during boot
|
||||||
ui.update();
|
ui->update();
|
||||||
#ifndef USE_EINK
|
#ifndef USE_EINK
|
||||||
ui.update();
|
ui->update();
|
||||||
#endif
|
#endif
|
||||||
serialSinceMsec = millis();
|
serialSinceMsec = millis();
|
||||||
|
|
||||||
#if HAS_TOUCHSCREEN
|
#if ARCH_RASPBERRY_PI
|
||||||
touchScreenImpl1 = new TouchScreenImpl1(dispdev.getWidth(), dispdev.getHeight(), dispdev.getTouch);
|
if (settingsMap[touchscreenModule]) {
|
||||||
|
touchScreenImpl1 =
|
||||||
|
new TouchScreenImpl1(dispdev->getWidth(), dispdev->getHeight(), static_cast<TFTDisplay *>(dispdev)->getTouch);
|
||||||
|
touchScreenImpl1->init();
|
||||||
|
}
|
||||||
|
#elif HAS_TOUCHSCREEN
|
||||||
|
touchScreenImpl1 =
|
||||||
|
new TouchScreenImpl1(dispdev->getWidth(), dispdev->getHeight(), static_cast<TFTDisplay *>(dispdev)->getTouch);
|
||||||
touchScreenImpl1->init();
|
touchScreenImpl1->init();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -1057,7 +1104,7 @@ void Screen::forceDisplay()
|
|||||||
{
|
{
|
||||||
// Nasty hack to force epaper updates for 'key' frames. FIXME, cleanup.
|
// Nasty hack to force epaper updates for 'key' frames. FIXME, cleanup.
|
||||||
#ifdef USE_EINK
|
#ifdef USE_EINK
|
||||||
dispdev.forceDisplay();
|
static_cast<EInkDisplay *>(dispdev)->forceDisplay();
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1088,10 +1135,10 @@ int32_t Screen::runOnce()
|
|||||||
// Change frames.
|
// Change frames.
|
||||||
static FrameCallback bootOEMFrames[] = {drawOEMBootScreen};
|
static FrameCallback bootOEMFrames[] = {drawOEMBootScreen};
|
||||||
static const int bootOEMFrameCount = sizeof(bootOEMFrames) / sizeof(bootOEMFrames[0]);
|
static const int bootOEMFrameCount = sizeof(bootOEMFrames) / sizeof(bootOEMFrames[0]);
|
||||||
ui.setFrames(bootOEMFrames, bootOEMFrameCount);
|
ui->setFrames(bootOEMFrames, bootOEMFrameCount);
|
||||||
ui.update();
|
ui->update();
|
||||||
#ifndef USE_EINK
|
#ifndef USE_EINK
|
||||||
ui.update();
|
ui->update();
|
||||||
#endif
|
#endif
|
||||||
showingOEMBootScreen = false;
|
showingOEMBootScreen = false;
|
||||||
}
|
}
|
||||||
@ -1164,16 +1211,16 @@ int32_t Screen::runOnce()
|
|||||||
|
|
||||||
// this must be before the frameState == FIXED check, because we always
|
// this must be before the frameState == FIXED check, because we always
|
||||||
// want to draw at least one FIXED frame before doing forceDisplay
|
// want to draw at least one FIXED frame before doing forceDisplay
|
||||||
ui.update();
|
ui->update();
|
||||||
|
|
||||||
// Switch to a low framerate (to save CPU) when we are not in transition
|
// Switch to a low framerate (to save CPU) when we are not in transition
|
||||||
// but we should only call setTargetFPS when framestate changes, because
|
// but we should only call setTargetFPS when framestate changes, because
|
||||||
// otherwise that breaks animations.
|
// otherwise that breaks animations.
|
||||||
if (targetFramerate != IDLE_FRAMERATE && ui.getUiState()->frameState == FIXED) {
|
if (targetFramerate != IDLE_FRAMERATE && ui->getUiState()->frameState == FIXED) {
|
||||||
// oldFrameState = ui.getUiState()->frameState;
|
// oldFrameState = ui->getUiState()->frameState;
|
||||||
targetFramerate = IDLE_FRAMERATE;
|
targetFramerate = IDLE_FRAMERATE;
|
||||||
|
|
||||||
ui.setTargetFPS(targetFramerate);
|
ui->setTargetFPS(targetFramerate);
|
||||||
forceDisplay();
|
forceDisplay();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1189,7 +1236,7 @@ int32_t Screen::runOnce()
|
|||||||
}
|
}
|
||||||
|
|
||||||
// LOG_DEBUG("want fps %d, fixed=%d\n", targetFramerate,
|
// LOG_DEBUG("want fps %d, fixed=%d\n", targetFramerate,
|
||||||
// ui.getUiState()->frameState); If we are scrolling we need to be called
|
// ui->getUiState()->frameState); If we are scrolling we need to be called
|
||||||
// soon, otherwise just 1 fps (to save CPU) We also ask to be called twice
|
// soon, otherwise just 1 fps (to save CPU) We also ask to be called twice
|
||||||
// as fast as we really need so that any rounding errors still result with
|
// as fast as we really need so that any rounding errors still result with
|
||||||
// the correct framerate
|
// the correct framerate
|
||||||
@ -1221,8 +1268,8 @@ void Screen::setSSLFrames()
|
|||||||
if (address_found.address) {
|
if (address_found.address) {
|
||||||
// LOG_DEBUG("showing SSL frames\n");
|
// LOG_DEBUG("showing SSL frames\n");
|
||||||
static FrameCallback sslFrames[] = {drawSSLScreen};
|
static FrameCallback sslFrames[] = {drawSSLScreen};
|
||||||
ui.setFrames(sslFrames, 1);
|
ui->setFrames(sslFrames, 1);
|
||||||
ui.update();
|
ui->update();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1306,8 +1353,8 @@ void Screen::setFrames()
|
|||||||
|
|
||||||
LOG_DEBUG("Finished building frames. numframes: %d\n", numframes);
|
LOG_DEBUG("Finished building frames. numframes: %d\n", numframes);
|
||||||
|
|
||||||
ui.setFrames(normalFrames, numframes);
|
ui->setFrames(normalFrames, numframes);
|
||||||
ui.enableAllIndicators();
|
ui->enableAllIndicators();
|
||||||
|
|
||||||
prevFrame = -1; // Force drawNodeInfo to pick a new node (because our list
|
prevFrame = -1; // Force drawNodeInfo to pick a new node (because our list
|
||||||
// just changed)
|
// just changed)
|
||||||
@ -1327,8 +1374,8 @@ void Screen::handleStartBluetoothPinScreen(uint32_t pin)
|
|||||||
|
|
||||||
void Screen::setFrameImmediateDraw(FrameCallback *drawFrames)
|
void Screen::setFrameImmediateDraw(FrameCallback *drawFrames)
|
||||||
{
|
{
|
||||||
ui.disableAllIndicators();
|
ui->disableAllIndicators();
|
||||||
ui.setFrames(drawFrames, 1);
|
ui->setFrames(drawFrames, 1);
|
||||||
setFastFramerate();
|
setFastFramerate();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1370,17 +1417,17 @@ void Screen::blink()
|
|||||||
{
|
{
|
||||||
setFastFramerate();
|
setFastFramerate();
|
||||||
uint8_t count = 10;
|
uint8_t count = 10;
|
||||||
dispdev.setBrightness(254);
|
dispdev->setBrightness(254);
|
||||||
while (count > 0) {
|
while (count > 0) {
|
||||||
dispdev.fillRect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);
|
dispdev->fillRect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);
|
||||||
dispdev.display();
|
dispdev->display();
|
||||||
delay(50);
|
delay(50);
|
||||||
dispdev.clear();
|
dispdev->clear();
|
||||||
dispdev.display();
|
dispdev->display();
|
||||||
delay(50);
|
delay(50);
|
||||||
count = count - 1;
|
count = count - 1;
|
||||||
}
|
}
|
||||||
dispdev.setBrightness(brightness);
|
dispdev->setBrightness(brightness);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string Screen::drawTimeDelta(uint32_t days, uint32_t hours, uint32_t minutes, uint32_t seconds)
|
std::string Screen::drawTimeDelta(uint32_t days, uint32_t hours, uint32_t minutes, uint32_t seconds)
|
||||||
@ -1408,15 +1455,15 @@ void Screen::handlePrint(const char *text)
|
|||||||
if (!useDisplay || !showingNormalScreen)
|
if (!useDisplay || !showingNormalScreen)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
dispdev.print(text);
|
dispdev->print(text);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Screen::handleOnPress()
|
void Screen::handleOnPress()
|
||||||
{
|
{
|
||||||
// If screen was off, just wake it, otherwise advance to next frame
|
// 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 we are in a transition, the press must have bounced, drop it.
|
||||||
if (ui.getUiState()->frameState == FIXED) {
|
if (ui->getUiState()->frameState == FIXED) {
|
||||||
ui.nextFrame();
|
ui->nextFrame();
|
||||||
lastScreenTransition = millis();
|
lastScreenTransition = millis();
|
||||||
setFastFramerate();
|
setFastFramerate();
|
||||||
}
|
}
|
||||||
@ -1426,8 +1473,8 @@ void Screen::handleShowPrevFrame()
|
|||||||
{
|
{
|
||||||
// If screen was off, just wake it, otherwise go back to previous frame
|
// 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 we are in a transition, the press must have bounced, drop it.
|
||||||
if (ui.getUiState()->frameState == FIXED) {
|
if (ui->getUiState()->frameState == FIXED) {
|
||||||
ui.previousFrame();
|
ui->previousFrame();
|
||||||
lastScreenTransition = millis();
|
lastScreenTransition = millis();
|
||||||
setFastFramerate();
|
setFastFramerate();
|
||||||
}
|
}
|
||||||
@ -1437,8 +1484,8 @@ void Screen::handleShowNextFrame()
|
|||||||
{
|
{
|
||||||
// If screen was off, just wake it, otherwise advance to next frame
|
// 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 we are in a transition, the press must have bounced, drop it.
|
||||||
if (ui.getUiState()->frameState == FIXED) {
|
if (ui->getUiState()->frameState == FIXED) {
|
||||||
ui.nextFrame();
|
ui->nextFrame();
|
||||||
lastScreenTransition = millis();
|
lastScreenTransition = millis();
|
||||||
setFastFramerate();
|
setFastFramerate();
|
||||||
}
|
}
|
||||||
@ -1453,7 +1500,7 @@ void Screen::setFastFramerate()
|
|||||||
// We are about to start a transition so speed up fps
|
// We are about to start a transition so speed up fps
|
||||||
targetFramerate = SCREEN_TRANSITION_FRAMERATE;
|
targetFramerate = SCREEN_TRANSITION_FRAMERATE;
|
||||||
|
|
||||||
ui.setTargetFPS(targetFramerate);
|
ui->setTargetFPS(targetFramerate);
|
||||||
setInterval(0); // redraw ASAP
|
setInterval(0); // redraw ASAP
|
||||||
runASAP = true;
|
runASAP = true;
|
||||||
}
|
}
|
||||||
@ -1540,7 +1587,8 @@ void DebugInfo::drawFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
} else {
|
} else {
|
||||||
#if (defined(USE_EINK) || defined(ILI9341_DRIVER) || defined(ST7735_CS) || defined(ST7789_CS)) && \
|
// TODO: Raspberry Pi supports more than just the one screen size
|
||||||
|
#if (defined(USE_EINK) || defined(ILI9341_DRIVER) || defined(ST7735_CS) || defined(ST7789_CS) || ARCH_RASPBERRY_PI) && \
|
||||||
!defined(DISPLAY_FORCE_SMALL_FONTS)
|
!defined(DISPLAY_FORCE_SMALL_FONTS)
|
||||||
display->drawFastImage(x + SCREEN_WIDTH - 14 - display->getStringWidth(ourId), y + 3 + FONT_HEIGHT_SMALL, 12, 8,
|
display->drawFastImage(x + SCREEN_WIDTH - 14 - display->getStringWidth(ourId), y + 3 + FONT_HEIGHT_SMALL, 12, 8,
|
||||||
imgInfoL1);
|
imgInfoL1);
|
||||||
@ -1780,7 +1828,7 @@ int Screen::handleUIFrameEvent(const UIFrameEvent *event)
|
|||||||
setFastFramerate();
|
setFastFramerate();
|
||||||
// TODO: We might also want switch to corresponding frame,
|
// TODO: We might also want switch to corresponding frame,
|
||||||
// but we don't know the exact frame number.
|
// but we don't know the exact frame number.
|
||||||
// ui.switchToFrame(0);
|
// ui->switchToFrame(0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -324,6 +324,8 @@ class Screen : public concurrency::OSThread
|
|||||||
// Called periodically from the main loop.
|
// Called periodically from the main loop.
|
||||||
int32_t runOnce() final;
|
int32_t runOnce() final;
|
||||||
|
|
||||||
|
bool isAUTOOled = false;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
struct ScreenCmd {
|
struct ScreenCmd {
|
||||||
Cmd cmd;
|
Cmd cmd;
|
||||||
@ -385,22 +387,10 @@ class Screen : public concurrency::OSThread
|
|||||||
DebugInfo debugInfo;
|
DebugInfo debugInfo;
|
||||||
|
|
||||||
/// Display device
|
/// Display device
|
||||||
|
OLEDDisplay *dispdev;
|
||||||
|
|
||||||
#if defined(USE_SH1106) || defined(USE_SH1107) || defined(USE_SH1107_128_64)
|
|
||||||
SH1106Wire dispdev;
|
|
||||||
#elif defined(USE_SSD1306)
|
|
||||||
SSD1306Wire dispdev;
|
|
||||||
#elif defined(ST7735_CS) || defined(ILI9341_DRIVER) || defined(ST7789_CS) || defined(RAK14014)
|
|
||||||
TFTDisplay dispdev;
|
|
||||||
#elif defined(USE_EINK)
|
|
||||||
EInkDisplay dispdev;
|
|
||||||
#elif defined(USE_ST7567)
|
|
||||||
ST7567Wire dispdev;
|
|
||||||
#else
|
|
||||||
AutoOLEDWire dispdev;
|
|
||||||
#endif
|
|
||||||
/// UI helper for rendering to frames and switching between them
|
/// UI helper for rendering to frames and switching between them
|
||||||
OLEDDisplayUi ui;
|
OLEDDisplayUi *ui;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace graphics
|
} // namespace graphics
|
||||||
|
@ -1,5 +1,8 @@
|
|||||||
#include "configuration.h"
|
#include "configuration.h"
|
||||||
#include "main.h"
|
#include "main.h"
|
||||||
|
#if ARCH_RASPBERRY_PI
|
||||||
|
#include "platform/portduino/PortduinoGlue.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifndef TFT_BACKLIGHT_ON
|
#ifndef TFT_BACKLIGHT_ON
|
||||||
#define TFT_BACKLIGHT_ON HIGH
|
#define TFT_BACKLIGHT_ON HIGH
|
||||||
@ -103,11 +106,11 @@ class LGFX : public lgfx::LGFX_Device
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
static LGFX tft;
|
static LGFX *tft = nullptr;
|
||||||
|
|
||||||
#elif defined(RAK14014)
|
#elif defined(RAK14014)
|
||||||
#include <TFT_eSPI.h>
|
#include <TFT_eSPI.h>
|
||||||
TFT_eSPI tft = TFT_eSPI();
|
TFT_eSPI *tft = nullptr;
|
||||||
|
|
||||||
#elif defined(ST7789_CS)
|
#elif defined(ST7789_CS)
|
||||||
#include <LovyanGFX.hpp> // Graphics and font library for ST7735 driver chip
|
#include <LovyanGFX.hpp> // Graphics and font library for ST7735 driver chip
|
||||||
@ -233,7 +236,7 @@ class LGFX : public lgfx::LGFX_Device
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
static LGFX tft;
|
static LGFX *tft = nullptr;
|
||||||
|
|
||||||
#elif defined(ILI9341_DRIVER)
|
#elif defined(ILI9341_DRIVER)
|
||||||
|
|
||||||
@ -322,23 +325,96 @@ class LGFX : public lgfx::LGFX_Device
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
static LGFX tft;
|
static LGFX *tft = nullptr;
|
||||||
|
|
||||||
#elif defined(ST7735_CS)
|
#elif defined(ST7735_CS)
|
||||||
#include <TFT_eSPI.h> // Graphics and font library for ILI9341 driver chip
|
#include <TFT_eSPI.h> // Graphics and font library for ILI9341 driver chip
|
||||||
|
|
||||||
static TFT_eSPI tft = TFT_eSPI(); // Invoke library, pins defined in User_Setup.h
|
static TFT_eSPI *tft = nullptr; // Invoke library, pins defined in User_Setup.h
|
||||||
|
#elif ARCH_RASPBERRY_PI
|
||||||
|
#include <LovyanGFX.hpp> // Graphics and font library for ST7735 driver chip
|
||||||
|
|
||||||
|
class LGFX : public lgfx::LGFX_Device
|
||||||
|
{
|
||||||
|
lgfx::Panel_LCD *_panel_instance;
|
||||||
|
lgfx::Bus_SPI _bus_instance;
|
||||||
|
|
||||||
|
lgfx::ITouch *_touch_instance;
|
||||||
|
|
||||||
|
public:
|
||||||
|
LGFX(void)
|
||||||
|
{
|
||||||
|
|
||||||
|
_panel_instance = new lgfx::Panel_ST7789;
|
||||||
|
auto buscfg = _bus_instance.config();
|
||||||
|
buscfg.spi_mode = 0;
|
||||||
|
|
||||||
|
buscfg.pin_dc = settingsMap[displayDC]; // Set SPI DC pin number (-1 = disable)
|
||||||
|
|
||||||
|
_bus_instance.config(buscfg); // applies the set value to the bus.
|
||||||
|
_panel_instance->setBus(&_bus_instance); // set the bus on the panel.
|
||||||
|
|
||||||
|
auto cfg = _panel_instance->config(); // Gets a structure for display panel settings.
|
||||||
|
LOG_DEBUG("Height: %d, Width: %d \n", settingsMap[displayHeight], settingsMap[displayWidth]);
|
||||||
|
cfg.pin_cs = settingsMap[displayCS]; // Pin number where CS is connected (-1 = disable)
|
||||||
|
cfg.panel_width = settingsMap[displayWidth]; // actual displayable width
|
||||||
|
cfg.panel_height = settingsMap[displayHeight]; // actual displayable height
|
||||||
|
cfg.offset_x = 0; // Panel offset amount in X direction
|
||||||
|
cfg.offset_y = 0; // Panel offset amount in Y direction
|
||||||
|
cfg.offset_rotation = 0; // Rotation direction value offset 0~7 (4~7 is mirrored)
|
||||||
|
cfg.dummy_read_pixel = 9; // Number of bits for dummy read before pixel readout
|
||||||
|
cfg.dummy_read_bits = 1; // Number of bits for dummy read before non-pixel data read
|
||||||
|
cfg.readable = true; // Set to true if data can be read
|
||||||
|
cfg.invert = true; // Set to true if the light/darkness of the panel is reversed
|
||||||
|
cfg.rgb_order = false; // Set to true if the panel's red and blue are swapped
|
||||||
|
cfg.dlen_16bit = false; // Set to true for panels that transmit data length in 16-bit units with 16-bit parallel or SPI
|
||||||
|
cfg.bus_shared = true; // If the bus is shared with the SD card, set to true (bus control with drawJpgFile etc.)
|
||||||
|
|
||||||
|
_panel_instance->config(cfg);
|
||||||
|
|
||||||
|
// Configure settings for touch control.
|
||||||
|
if (settingsMap[touchscreenModule]) {
|
||||||
|
if (settingsMap[touchscreenModule] == xpt2046) {
|
||||||
|
_touch_instance = new lgfx::Touch_XPT2046;
|
||||||
|
}
|
||||||
|
auto touch_cfg = _touch_instance->config();
|
||||||
|
|
||||||
|
touch_cfg.pin_cs = settingsMap[touchscreenCS];
|
||||||
|
touch_cfg.x_min = 0;
|
||||||
|
touch_cfg.x_max = settingsMap[displayHeight] - 1;
|
||||||
|
touch_cfg.y_min = 0;
|
||||||
|
touch_cfg.y_max = settingsMap[displayWidth] - 1;
|
||||||
|
touch_cfg.pin_int = settingsMap[touchscreenIRQ];
|
||||||
|
touch_cfg.bus_shared = true;
|
||||||
|
touch_cfg.offset_rotation = 1;
|
||||||
|
|
||||||
|
_touch_instance->config(touch_cfg);
|
||||||
|
_panel_instance->setTouch(_touch_instance);
|
||||||
|
}
|
||||||
|
|
||||||
|
setPanel(_panel_instance); // Sets the panel to use.
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
static LGFX *tft = nullptr;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(ST7735_CS) || defined(ST7789_CS) || defined(ILI9341_DRIVER) || defined(RAK14014)
|
#if defined(ST7735_CS) || defined(ST7789_CS) || defined(ILI9341_DRIVER) || defined(RAK14014) || ARCH_RASPBERRY_PI
|
||||||
#include "SPILock.h"
|
#include "SPILock.h"
|
||||||
#include "TFTDisplay.h"
|
#include "TFTDisplay.h"
|
||||||
#include <SPI.h>
|
#include <SPI.h>
|
||||||
|
|
||||||
TFTDisplay::TFTDisplay(uint8_t address, int sda, int scl, OLEDDISPLAY_GEOMETRY geometry, HW_I2C i2cBus)
|
TFTDisplay::TFTDisplay(uint8_t address, int sda, int scl, OLEDDISPLAY_GEOMETRY geometry, HW_I2C i2cBus)
|
||||||
{
|
{
|
||||||
#ifdef SCREEN_ROTATE
|
LOG_DEBUG("TFTDisplay!\n");
|
||||||
|
#if ARCH_RASPBERRY_PI
|
||||||
|
if (settingsMap[displayRotate]) {
|
||||||
|
setGeometry(GEOMETRY_RAWMODE, settingsMap[configNames::displayHeight], settingsMap[configNames::displayWidth]);
|
||||||
|
} else {
|
||||||
|
setGeometry(GEOMETRY_RAWMODE, settingsMap[configNames::displayWidth], settingsMap[configNames::displayHeight]);
|
||||||
|
}
|
||||||
|
|
||||||
|
#elif defined(SCREEN_ROTATE)
|
||||||
setGeometry(GEOMETRY_RAWMODE, TFT_HEIGHT, TFT_WIDTH);
|
setGeometry(GEOMETRY_RAWMODE, TFT_HEIGHT, TFT_WIDTH);
|
||||||
#else
|
#else
|
||||||
setGeometry(GEOMETRY_RAWMODE, TFT_WIDTH, TFT_HEIGHT);
|
setGeometry(GEOMETRY_RAWMODE, TFT_WIDTH, TFT_HEIGHT);
|
||||||
@ -346,19 +422,25 @@ TFTDisplay::TFTDisplay(uint8_t address, int sda, int scl, OLEDDISPLAY_GEOMETRY g
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Write the buffer to the display memory
|
// Write the buffer to the display memory
|
||||||
void TFTDisplay::display(void)
|
void TFTDisplay::display(bool fromBlank)
|
||||||
{
|
{
|
||||||
|
if (fromBlank)
|
||||||
|
tft->clear();
|
||||||
concurrency::LockGuard g(spiLock);
|
concurrency::LockGuard g(spiLock);
|
||||||
|
|
||||||
uint16_t x, y;
|
uint16_t x, y;
|
||||||
|
|
||||||
for (y = 0; y < displayHeight; y++) {
|
for (y = 0; y < displayHeight; y++) {
|
||||||
for (x = 0; x < displayWidth; x++) {
|
for (x = 0; x < displayWidth; x++) {
|
||||||
// get src pixel in the page based ordering the OLED lib uses FIXME, super inefficent
|
|
||||||
auto isset = buffer[x + (y / 8) * displayWidth] & (1 << (y & 7));
|
auto isset = buffer[x + (y / 8) * displayWidth] & (1 << (y & 7));
|
||||||
auto dblbuf_isset = buffer_back[x + (y / 8) * displayWidth] & (1 << (y & 7));
|
if (!fromBlank) {
|
||||||
if (isset != dblbuf_isset) {
|
// get src pixel in the page based ordering the OLED lib uses FIXME, super inefficent
|
||||||
tft.drawPixel(x, y, isset ? TFT_MESH : TFT_BLACK);
|
auto dblbuf_isset = buffer_back[x + (y / 8) * displayWidth] & (1 << (y & 7));
|
||||||
|
if (isset != dblbuf_isset) {
|
||||||
|
tft->drawPixel(x, y, isset ? TFT_MESH : TFT_BLACK);
|
||||||
|
}
|
||||||
|
} else if (isset) {
|
||||||
|
tft->drawPixel(x, y, TFT_MESH);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -377,7 +459,11 @@ void TFTDisplay::sendCommand(uint8_t com)
|
|||||||
// handle display on/off directly
|
// handle display on/off directly
|
||||||
switch (com) {
|
switch (com) {
|
||||||
case DISPLAYON: {
|
case DISPLAYON: {
|
||||||
#if defined(ST7735_BACKLIGHT_EN_V03) && defined(TFT_BACKLIGHT_ON)
|
#if ARCH_RASPBERRY_PI
|
||||||
|
display(true);
|
||||||
|
if (settingsMap[displayBacklight] > 0)
|
||||||
|
digitalWrite(settingsMap[displayBacklight], TFT_BACKLIGHT_ON);
|
||||||
|
#elif defined(ST7735_BACKLIGHT_EN_V03) && defined(TFT_BACKLIGHT_ON)
|
||||||
if (heltec_version == 3) {
|
if (heltec_version == 3) {
|
||||||
digitalWrite(ST7735_BACKLIGHT_EN_V03, TFT_BACKLIGHT_ON);
|
digitalWrite(ST7735_BACKLIGHT_EN_V03, TFT_BACKLIGHT_ON);
|
||||||
} else {
|
} else {
|
||||||
@ -400,12 +486,16 @@ void TFTDisplay::sendCommand(uint8_t com)
|
|||||||
|
|
||||||
#ifdef RAK14014
|
#ifdef RAK14014
|
||||||
#elif !defined(M5STACK)
|
#elif !defined(M5STACK)
|
||||||
tft.setBrightness(128);
|
tft->setBrightness(128);
|
||||||
#endif
|
#endif
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case DISPLAYOFF: {
|
case DISPLAYOFF: {
|
||||||
#if defined(ST7735_BACKLIGHT_EN_V03) && defined(TFT_BACKLIGHT_ON)
|
#if ARCH_RASPBERRY_PI
|
||||||
|
tft->clear();
|
||||||
|
if (settingsMap[displayBacklight] > 0)
|
||||||
|
digitalWrite(settingsMap[displayBacklight], !TFT_BACKLIGHT_ON);
|
||||||
|
#elif defined(ST7735_BACKLIGHT_EN_V03) && defined(TFT_BACKLIGHT_ON)
|
||||||
if (heltec_version == 3) {
|
if (heltec_version == 3) {
|
||||||
digitalWrite(ST7735_BACKLIGHT_EN_V03, !TFT_BACKLIGHT_ON);
|
digitalWrite(ST7735_BACKLIGHT_EN_V03, !TFT_BACKLIGHT_ON);
|
||||||
} else {
|
} else {
|
||||||
@ -427,7 +517,7 @@ void TFTDisplay::sendCommand(uint8_t com)
|
|||||||
#endif
|
#endif
|
||||||
#ifdef RAK14014
|
#ifdef RAK14014
|
||||||
#elif !defined(M5STACK)
|
#elif !defined(M5STACK)
|
||||||
tft.setBrightness(0);
|
tft->setBrightness(0);
|
||||||
#endif
|
#endif
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -442,7 +532,7 @@ void TFTDisplay::flipScreenVertically()
|
|||||||
{
|
{
|
||||||
#if defined(T_WATCH_S3)
|
#if defined(T_WATCH_S3)
|
||||||
LOG_DEBUG("Flip TFT vertically\n"); // T-Watch S3 right-handed orientation
|
LOG_DEBUG("Flip TFT vertically\n"); // T-Watch S3 right-handed orientation
|
||||||
tft.setRotation(0);
|
tft->setRotation(0);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -450,7 +540,7 @@ bool TFTDisplay::hasTouch(void)
|
|||||||
{
|
{
|
||||||
#ifdef RAK14014
|
#ifdef RAK14014
|
||||||
#elif !defined(M5STACK)
|
#elif !defined(M5STACK)
|
||||||
return tft.touch() != nullptr;
|
return tft->touch() != nullptr;
|
||||||
#else
|
#else
|
||||||
return false;
|
return false;
|
||||||
#endif
|
#endif
|
||||||
@ -460,7 +550,7 @@ bool TFTDisplay::getTouch(int16_t *x, int16_t *y)
|
|||||||
{
|
{
|
||||||
#ifdef RAK14014
|
#ifdef RAK14014
|
||||||
#elif !defined(M5STACK)
|
#elif !defined(M5STACK)
|
||||||
return tft.getTouch(x, y);
|
return tft->getTouch(x, y);
|
||||||
#else
|
#else
|
||||||
return false;
|
return false;
|
||||||
#endif
|
#endif
|
||||||
@ -476,6 +566,11 @@ bool TFTDisplay::connect()
|
|||||||
{
|
{
|
||||||
concurrency::LockGuard g(spiLock);
|
concurrency::LockGuard g(spiLock);
|
||||||
LOG_INFO("Doing TFT init\n");
|
LOG_INFO("Doing TFT init\n");
|
||||||
|
#ifdef RAK14014
|
||||||
|
tft = new TFT_eSPI;
|
||||||
|
#else
|
||||||
|
tft = new LGFX;
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef TFT_BL
|
#ifdef TFT_BL
|
||||||
pinMode(TFT_BL, OUTPUT);
|
pinMode(TFT_BL, OUTPUT);
|
||||||
@ -495,24 +590,24 @@ bool TFTDisplay::connect()
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
tft.init();
|
tft->init();
|
||||||
|
|
||||||
#if defined(M5STACK)
|
#if defined(M5STACK)
|
||||||
tft.setRotation(0);
|
tft->setRotation(0);
|
||||||
#elif defined(RAK14014)
|
#elif defined(RAK14014)
|
||||||
tft.setRotation(1);
|
tft->setRotation(1);
|
||||||
tft.setSwapBytes(true);
|
tft->setSwapBytes(true);
|
||||||
// tft.fillScreen(TFT_BLACK);
|
// tft->fillScreen(TFT_BLACK);
|
||||||
#elif defined(T_DECK) || defined(PICOMPUTER_S3)
|
#elif defined(T_DECK) || defined(PICOMPUTER_S3)
|
||||||
tft.setRotation(1); // T-Deck has the TFT in landscape
|
tft->setRotation(1); // T-Deck has the TFT in landscape
|
||||||
#elif defined(T_WATCH_S3)
|
#elif defined(T_WATCH_S3)
|
||||||
tft.setRotation(2); // T-Watch S3 left-handed orientation
|
tft->setRotation(2); // T-Watch S3 left-handed orientation
|
||||||
#else
|
#else
|
||||||
tft.setRotation(3); // Orient horizontal and wide underneath the silkscreen name label
|
tft->setRotation(3); // Orient horizontal and wide underneath the silkscreen name label
|
||||||
#endif
|
#endif
|
||||||
tft.fillScreen(TFT_BLACK);
|
tft->fillScreen(TFT_BLACK);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
@ -20,7 +20,8 @@ class TFTDisplay : public OLEDDisplay
|
|||||||
TFTDisplay(uint8_t, int, int, OLEDDISPLAY_GEOMETRY, HW_I2C);
|
TFTDisplay(uint8_t, int, int, OLEDDISPLAY_GEOMETRY, HW_I2C);
|
||||||
|
|
||||||
// Write the buffer to the display memory
|
// Write the buffer to the display memory
|
||||||
virtual void display(void) override;
|
virtual void display() override { display(false); };
|
||||||
|
virtual void display(bool fromBlank);
|
||||||
|
|
||||||
// Turn the display upside down
|
// Turn the display upside down
|
||||||
virtual void flipScreenVertically();
|
virtual void flipScreenVertically();
|
||||||
|
@ -14,7 +14,7 @@ const uint8_t imgUser[] PROGMEM = {0x3C, 0x42, 0x99, 0xA5, 0xA5, 0x99, 0x42, 0x3
|
|||||||
const uint8_t imgPositionEmpty[] PROGMEM = {0x20, 0x30, 0x28, 0x24, 0x42, 0xFF};
|
const uint8_t imgPositionEmpty[] PROGMEM = {0x20, 0x30, 0x28, 0x24, 0x42, 0xFF};
|
||||||
const uint8_t imgPositionSolid[] PROGMEM = {0x20, 0x30, 0x38, 0x3C, 0x7E, 0xFF};
|
const uint8_t imgPositionSolid[] PROGMEM = {0x20, 0x30, 0x38, 0x3C, 0x7E, 0xFF};
|
||||||
|
|
||||||
#if (defined(USE_EINK) || defined(ILI9341_DRIVER) || defined(ST7735_CS) || defined(ST7789_CS)) && \
|
#if (defined(USE_EINK) || defined(ILI9341_DRIVER) || defined(ST7735_CS) || defined(ST7789_CS) || ARCH_RASPBERRY_PI) && \
|
||||||
!defined(DISPLAY_FORCE_SMALL_FONTS)
|
!defined(DISPLAY_FORCE_SMALL_FONTS)
|
||||||
const uint8_t imgQuestionL1[] PROGMEM = {0xff, 0x01, 0x01, 0x32, 0x7b, 0x49, 0x49, 0x6f, 0x26, 0x01, 0x01, 0xff};
|
const uint8_t imgQuestionL1[] PROGMEM = {0xff, 0x01, 0x01, 0x32, 0x7b, 0x49, 0x49, 0x6f, 0x26, 0x01, 0x01, 0xff};
|
||||||
const uint8_t imgQuestionL2[] PROGMEM = {0x0f, 0x08, 0x08, 0x08, 0x06, 0x0f, 0x0f, 0x06, 0x08, 0x08, 0x08, 0x0f};
|
const uint8_t imgQuestionL2[] PROGMEM = {0x0f, 0x08, 0x08, 0x08, 0x06, 0x0f, 0x0f, 0x06, 0x08, 0x08, 0x08, 0x0f};
|
||||||
@ -30,4 +30,4 @@ const uint8_t imgQuestion[] PROGMEM = {0xbf, 0x41, 0xc0, 0x8b, 0xdb, 0x70, 0xa1,
|
|||||||
const uint8_t imgSF[] PROGMEM = {0xd2, 0xb7, 0xad, 0xbb, 0x92, 0x01, 0xfd, 0xfd, 0x15, 0x85, 0xf5};
|
const uint8_t imgSF[] PROGMEM = {0xd2, 0xb7, 0xad, 0xbb, 0x92, 0x01, 0xfd, 0xfd, 0x15, 0x85, 0xf5};
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "img/icon.xbm"
|
#include "img/icon.xbm"
|
179
src/input/LinuxInput.cpp
Normal file
179
src/input/LinuxInput.cpp
Normal file
@ -0,0 +1,179 @@
|
|||||||
|
#if ARCH_RASPBERRY_PI
|
||||||
|
#include "LinuxInput.h"
|
||||||
|
#include "configuration.h"
|
||||||
|
|
||||||
|
#include "platform/portduino/PortduinoGlue.h"
|
||||||
|
#include <assert.h>
|
||||||
|
#include <ctype.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <linux/input.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string>
|
||||||
|
#include <sys/epoll.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
// Inspired by https://github.com/librerpi/rpi-tools/blob/master/keyboard-proxy/main.c which is GPL-v2
|
||||||
|
|
||||||
|
LinuxInput::LinuxInput(const char *name) : concurrency::OSThread(name)
|
||||||
|
{
|
||||||
|
this->_originName = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
int32_t LinuxInput::runOnce()
|
||||||
|
{
|
||||||
|
|
||||||
|
if (firstTime) {
|
||||||
|
if (settingsStrings[keyboardDevice] == "")
|
||||||
|
return disable();
|
||||||
|
fd = open(settingsStrings[keyboardDevice].c_str(), O_RDWR);
|
||||||
|
if (fd < 0)
|
||||||
|
return disable();
|
||||||
|
ret = ioctl(fd, EVIOCGRAB, (void *)1);
|
||||||
|
if (ret != 0)
|
||||||
|
return disable();
|
||||||
|
|
||||||
|
epollfd = epoll_create1(0);
|
||||||
|
assert(epollfd >= 0);
|
||||||
|
|
||||||
|
ev.events = EPOLLIN;
|
||||||
|
ev.data.fd = fd;
|
||||||
|
if (epoll_ctl(epollfd, EPOLL_CTL_ADD, fd, &ev)) {
|
||||||
|
perror("unable to epoll add");
|
||||||
|
return disable();
|
||||||
|
}
|
||||||
|
// This is the first time the OSThread library has called this function, so do port setup
|
||||||
|
firstTime = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int nfds = epoll_wait(epollfd, events, MAX_EVENTS, 1);
|
||||||
|
if (nfds < 0) {
|
||||||
|
printf("%d ", nfds);
|
||||||
|
perror("epoll_wait failed");
|
||||||
|
return disable();
|
||||||
|
} else if (nfds == 0) {
|
||||||
|
return 50;
|
||||||
|
}
|
||||||
|
|
||||||
|
int keys = 0;
|
||||||
|
memset(report, 0, 8);
|
||||||
|
for (int i = 0; i < nfds; i++) {
|
||||||
|
|
||||||
|
struct input_event ev[64];
|
||||||
|
int rd = read(events[i].data.fd, ev, sizeof(ev));
|
||||||
|
assert(rd > ((signed int)sizeof(struct input_event)));
|
||||||
|
for (int j = 0; j < rd / ((signed int)sizeof(struct input_event)); j++) {
|
||||||
|
InputEvent e;
|
||||||
|
e.inputEvent = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_NONE;
|
||||||
|
e.source = this->_originName;
|
||||||
|
e.kbchar = 0;
|
||||||
|
unsigned int type, code;
|
||||||
|
type = ev[j].type;
|
||||||
|
code = ev[j].code;
|
||||||
|
int value = ev[j].value;
|
||||||
|
// printf("Event: time %ld.%06ld, ", ev[j].time.tv_sec, ev[j].time.tv_usec);
|
||||||
|
|
||||||
|
if (type == EV_KEY) {
|
||||||
|
uint8_t mod = 0;
|
||||||
|
|
||||||
|
switch (code) {
|
||||||
|
case KEY_LEFTCTRL:
|
||||||
|
mod = 0x01;
|
||||||
|
break;
|
||||||
|
case KEY_RIGHTCTRL:
|
||||||
|
mod = 0x10;
|
||||||
|
break;
|
||||||
|
case KEY_LEFTSHIFT:
|
||||||
|
mod = 0x02;
|
||||||
|
break;
|
||||||
|
case KEY_RIGHTSHIFT:
|
||||||
|
mod = 0x20;
|
||||||
|
break;
|
||||||
|
case KEY_LEFTALT:
|
||||||
|
mod = 0x04;
|
||||||
|
break;
|
||||||
|
case KEY_RIGHTALT:
|
||||||
|
mod = 0x40;
|
||||||
|
break;
|
||||||
|
case KEY_LEFTMETA:
|
||||||
|
mod = 0x08;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (value == 1) {
|
||||||
|
switch (code) {
|
||||||
|
case KEY_LEFTCTRL:
|
||||||
|
mod = 0x01;
|
||||||
|
break;
|
||||||
|
case KEY_RIGHTCTRL:
|
||||||
|
mod = 0x10;
|
||||||
|
break;
|
||||||
|
case KEY_LEFTSHIFT:
|
||||||
|
mod = 0x02;
|
||||||
|
break;
|
||||||
|
case KEY_RIGHTSHIFT:
|
||||||
|
mod = 0x20;
|
||||||
|
break;
|
||||||
|
case KEY_LEFTALT:
|
||||||
|
mod = 0x04;
|
||||||
|
break;
|
||||||
|
case KEY_RIGHTALT:
|
||||||
|
mod = 0x40;
|
||||||
|
break;
|
||||||
|
case KEY_LEFTMETA:
|
||||||
|
mod = 0x08;
|
||||||
|
break;
|
||||||
|
case KEY_ESC: // ESC
|
||||||
|
e.inputEvent = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_CANCEL;
|
||||||
|
break;
|
||||||
|
case KEY_BACK: // Back
|
||||||
|
e.inputEvent = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_BACK;
|
||||||
|
// e.kbchar = key;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case KEY_UP: // Up
|
||||||
|
e.inputEvent = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_UP;
|
||||||
|
break;
|
||||||
|
case KEY_DOWN: // Down
|
||||||
|
e.inputEvent = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_DOWN;
|
||||||
|
break;
|
||||||
|
case KEY_LEFT: // Left
|
||||||
|
e.inputEvent = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_LEFT;
|
||||||
|
break;
|
||||||
|
e.kbchar = 0xb4;
|
||||||
|
case KEY_RIGHT: // Right
|
||||||
|
e.inputEvent = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_RIGHT;
|
||||||
|
break;
|
||||||
|
e.kbchar = 0xb7;
|
||||||
|
case KEY_ENTER: // Enter
|
||||||
|
e.inputEvent = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_SELECT;
|
||||||
|
break;
|
||||||
|
default: // all other keys
|
||||||
|
if (keymap[code]) {
|
||||||
|
e.inputEvent = ANYKEY;
|
||||||
|
e.kbchar = keymap[code];
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (ev[j].value) {
|
||||||
|
modifiers |= mod;
|
||||||
|
} else {
|
||||||
|
modifiers &= ~mod;
|
||||||
|
}
|
||||||
|
report[0] = modifiers;
|
||||||
|
}
|
||||||
|
if (e.inputEvent != meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_NONE) {
|
||||||
|
if (e.inputEvent == ANYKEY && (modifiers && 0x22))
|
||||||
|
e.kbchar = uppers[e.kbchar]; // doesn't get punctuation. Meh.
|
||||||
|
this->notifyObservers(&e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 50; // Keyscan every 50msec to avoid key bounce
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
64
src/input/LinuxInput.h
Normal file
64
src/input/LinuxInput.h
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
#pragma once
|
||||||
|
#if ARCH_RASPBERRY_PI
|
||||||
|
#include "InputBroker.h"
|
||||||
|
#include "concurrency/OSThread.h"
|
||||||
|
#include <assert.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <linux/input.h>
|
||||||
|
#include <map>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <sys/epoll.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#define MAX_EVENTS 10
|
||||||
|
|
||||||
|
class LinuxInput : public Observable<const InputEvent *>, public concurrency::OSThread
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit LinuxInput(const char *name);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
virtual int32_t runOnce() override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
const char *_originName;
|
||||||
|
bool firstTime = 1;
|
||||||
|
int shift = 0;
|
||||||
|
char key = 0;
|
||||||
|
char prevkey = 0;
|
||||||
|
|
||||||
|
InputEvent eventqueue[50]; // The Linux API will return multiple keypresses at a time. Queue them to not miss any.
|
||||||
|
int queue_length = 0;
|
||||||
|
int queue_progress = 0;
|
||||||
|
|
||||||
|
struct epoll_event events[MAX_EVENTS];
|
||||||
|
int fd;
|
||||||
|
int ret;
|
||||||
|
uint8_t report[8];
|
||||||
|
int epollfd;
|
||||||
|
struct epoll_event ev;
|
||||||
|
uint8_t modifiers = 0;
|
||||||
|
std::map<int, char> keymap{
|
||||||
|
{KEY_A, 'a'}, {KEY_B, 'b'}, {KEY_C, 'c'}, {KEY_D, 'd'}, {KEY_E, 'e'},
|
||||||
|
{KEY_F, 'f'}, {KEY_G, 'g'}, {KEY_H, 'h'}, {KEY_I, 'i'}, {KEY_J, 'j'},
|
||||||
|
{KEY_K, 'k'}, {KEY_L, 'l'}, {KEY_M, 'm'}, {KEY_N, 'n'}, {KEY_O, 'o'},
|
||||||
|
{KEY_P, 'p'}, {KEY_Q, 'q'}, {KEY_R, 'r'}, {KEY_S, 's'}, {KEY_T, 't'},
|
||||||
|
{KEY_U, 'u'}, {KEY_V, 'v'}, {KEY_W, 'w'}, {KEY_X, 'x'}, {KEY_Y, 'y'},
|
||||||
|
{KEY_Z, 'z'}, {KEY_BACKSPACE, 0x08}, {KEY_SPACE, ' '}, {KEY_1, '1'}, {KEY_2, '2'},
|
||||||
|
{KEY_3, '3'}, {KEY_4, '4'}, {KEY_5, '5'}, {KEY_6, '6'}, {KEY_7, '7'},
|
||||||
|
{KEY_8, '8'}, {KEY_9, '9'}, {KEY_0, '0'}, {KEY_DOT, '.'}, {KEY_COMMA, ','},
|
||||||
|
{KEY_MINUS, '-'}, {KEY_EQUAL, '='}, {KEY_LEFTBRACE, '['}, {KEY_RIGHTBRACE, ']'}, {KEY_BACKSLASH, '\\'},
|
||||||
|
{KEY_SEMICOLON, ';'}, {KEY_APOSTROPHE, '\''}, {KEY_SLASH, '/'}, {KEY_TAB, 0x09}};
|
||||||
|
std::map<char, char> uppers{{'a', 'A'}, {'b', 'B'}, {'c', 'C'}, {'d', 'D'}, {'e', 'E'}, {'f', 'F'}, {'g', 'G'}, {'h', 'H'},
|
||||||
|
{'i', 'I'}, {'j', 'J'}, {'k', 'K'}, {'l', 'L'}, {'m', 'M'}, {'n', 'N'}, {'o', 'O'}, {'p', 'P'},
|
||||||
|
{'q', 'Q'}, {'r', 'R'}, {'s', 'S'}, {'t', 'T'}, {'u', 'U'}, {'v', 'V'}, {'w', 'W'}, {'x', 'X'},
|
||||||
|
{'y', 'Y'}, {'z', 'Z'}, {'1', '!'}, {'2', '@'}, {'3', '#'}, {'4', '$'}, {'5', '%'}, {'6', '^'},
|
||||||
|
{'7', '&'}, {'8', '*'}, {'9', '('}, {'0', ')'}, {'.', '>'}, {',', '<'}, {'-', '_'}, {'=', '+'},
|
||||||
|
{'[', '{'}, {']', '}'}, {'\\', '|'}, {';', ':'}, {'\'', '"'}, {'/', '?'}};
|
||||||
|
};
|
||||||
|
#endif
|
14
src/input/LinuxInputImpl.cpp
Normal file
14
src/input/LinuxInputImpl.cpp
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
#if ARCH_RASPBERRY_PI
|
||||||
|
#include "LinuxInputImpl.h"
|
||||||
|
#include "InputBroker.h"
|
||||||
|
|
||||||
|
LinuxInputImpl *aLinuxInputImpl;
|
||||||
|
|
||||||
|
LinuxInputImpl::LinuxInputImpl() : LinuxInput("LinuxInput") {}
|
||||||
|
|
||||||
|
void LinuxInputImpl::init()
|
||||||
|
{
|
||||||
|
inputBroker->registerSource(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
21
src/input/LinuxInputImpl.h
Normal file
21
src/input/LinuxInputImpl.h
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
#ifdef ARCH_RASPBERRY_PI
|
||||||
|
#pragma once
|
||||||
|
#include "LinuxInput.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 LinuxInputImpl : public LinuxInput
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
LinuxInputImpl();
|
||||||
|
void init();
|
||||||
|
};
|
||||||
|
extern LinuxInputImpl *aLinuxInputImpl;
|
||||||
|
#endif
|
@ -4,6 +4,10 @@
|
|||||||
#include "configuration.h"
|
#include "configuration.h"
|
||||||
#include "modules/ExternalNotificationModule.h"
|
#include "modules/ExternalNotificationModule.h"
|
||||||
|
|
||||||
|
#ifdef ARCH_RASPBERRY_PI
|
||||||
|
#include "platform/portduino/PortduinoGlue.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
TouchScreenImpl1 *touchScreenImpl1;
|
TouchScreenImpl1 *touchScreenImpl1;
|
||||||
|
|
||||||
TouchScreenImpl1::TouchScreenImpl1(uint16_t width, uint16_t height, bool (*getTouch)(int16_t *, int16_t *))
|
TouchScreenImpl1::TouchScreenImpl1(uint16_t width, uint16_t height, bool (*getTouch)(int16_t *, int16_t *))
|
||||||
@ -13,7 +17,14 @@ TouchScreenImpl1::TouchScreenImpl1(uint16_t width, uint16_t height, bool (*getTo
|
|||||||
|
|
||||||
void TouchScreenImpl1::init()
|
void TouchScreenImpl1::init()
|
||||||
{
|
{
|
||||||
#if !HAS_TOUCHSCREEN
|
#if ARCH_RASPBERRY_PI
|
||||||
|
if (settingsMap[touchscreenModule]) {
|
||||||
|
TouchScreenBase::init(true);
|
||||||
|
inputBroker->registerSource(this);
|
||||||
|
} else {
|
||||||
|
TouchScreenBase::init(false);
|
||||||
|
}
|
||||||
|
#elif !HAS_TOUCHSCREEN
|
||||||
TouchScreenBase::init(false);
|
TouchScreenBase::init(false);
|
||||||
return;
|
return;
|
||||||
#else
|
#else
|
||||||
|
@ -697,6 +697,10 @@ void setup()
|
|||||||
// the current region name)
|
// the current region name)
|
||||||
#if defined(ST7735_CS) || defined(USE_EINK) || defined(ILI9341_DRIVER) || defined(ST7789_CS)
|
#if defined(ST7735_CS) || defined(USE_EINK) || defined(ILI9341_DRIVER) || defined(ST7789_CS)
|
||||||
screen->setup();
|
screen->setup();
|
||||||
|
#elif ARCH_RASPBERRY_PI
|
||||||
|
if (screen_found.port != ScanI2C::I2CPort::NO_I2C || settingsMap[displayPanel]) {
|
||||||
|
screen->setup();
|
||||||
|
}
|
||||||
#else
|
#else
|
||||||
if (screen_found.port != ScanI2C::I2CPort::NO_I2C)
|
if (screen_found.port != ScanI2C::I2CPort::NO_I2C)
|
||||||
screen->setup();
|
screen->setup();
|
||||||
|
@ -27,6 +27,10 @@
|
|||||||
#include <nvs_flash.h>
|
#include <nvs_flash.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef ARCH_RASPBERRY_PI
|
||||||
|
#include "platform/portduino/PortduinoGlue.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef ARCH_NRF52
|
#ifdef ARCH_NRF52
|
||||||
#include <bluefruit.h>
|
#include <bluefruit.h>
|
||||||
#include <utility/bonding.h>
|
#include <utility/bonding.h>
|
||||||
@ -191,6 +195,12 @@ void NodeDB::installDefaultConfig()
|
|||||||
config.bluetooth.fixed_pin = defaultBLEPin;
|
config.bluetooth.fixed_pin = defaultBLEPin;
|
||||||
#if defined(ST7735_CS) || defined(USE_EINK) || defined(ILI9341_DRIVER) || defined(ST7789_CS)
|
#if defined(ST7735_CS) || defined(USE_EINK) || defined(ILI9341_DRIVER) || defined(ST7789_CS)
|
||||||
bool hasScreen = true;
|
bool hasScreen = true;
|
||||||
|
#elif ARCH_RASPBERRY_PI
|
||||||
|
bool hasScreen = false;
|
||||||
|
if (settingsMap[displayPanel])
|
||||||
|
hasScreen = true;
|
||||||
|
else
|
||||||
|
hasScreen = screen_found.port != ScanI2C::I2CPort::NO_I2C;
|
||||||
#else
|
#else
|
||||||
bool hasScreen = screen_found.port != ScanI2C::I2CPort::NO_I2C;
|
bool hasScreen = screen_found.port != ScanI2C::I2CPort::NO_I2C;
|
||||||
#endif
|
#endif
|
||||||
|
@ -1,4 +1,7 @@
|
|||||||
#include "configuration.h"
|
#include "configuration.h"
|
||||||
|
#if ARCH_RASPBERRY_PI
|
||||||
|
#include "PortduinoGlue.h"
|
||||||
|
#endif
|
||||||
#if HAS_SCREEN
|
#if HAS_SCREEN
|
||||||
#include "CannedMessageModule.h"
|
#include "CannedMessageModule.h"
|
||||||
#include "FSCommon.h"
|
#include "FSCommon.h"
|
||||||
@ -163,9 +166,14 @@ int CannedMessageModule::handleInputEvent(const InputEvent *event)
|
|||||||
}
|
}
|
||||||
if (event->inputEvent == static_cast<char>(meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_CANCEL)) {
|
if (event->inputEvent == static_cast<char>(meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_CANCEL)) {
|
||||||
LOG_DEBUG("Canned message event Cancel\n");
|
LOG_DEBUG("Canned message event Cancel\n");
|
||||||
// emulate a timeout. Same result
|
UIFrameEvent e = {false, true};
|
||||||
this->lastTouchMillis = 0;
|
e.frameChanged = true;
|
||||||
validEvent = true;
|
this->currentMessageIndex = -1;
|
||||||
|
this->freetext = ""; // clear freetext
|
||||||
|
this->cursor = 0;
|
||||||
|
this->destSelect = false;
|
||||||
|
this->runState = CANNED_MESSAGE_RUN_STATE_INACTIVE;
|
||||||
|
this->notifyObservers(&e);
|
||||||
}
|
}
|
||||||
if ((event->inputEvent == static_cast<char>(meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_BACK)) ||
|
if ((event->inputEvent == static_cast<char>(meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_BACK)) ||
|
||||||
(event->inputEvent == static_cast<char>(meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_LEFT)) ||
|
(event->inputEvent == static_cast<char>(meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_LEFT)) ||
|
||||||
@ -212,7 +220,11 @@ int CannedMessageModule::handleInputEvent(const InputEvent *event)
|
|||||||
|
|
||||||
if (validEvent) {
|
if (validEvent) {
|
||||||
// Let runOnce to be called immediately.
|
// Let runOnce to be called immediately.
|
||||||
setIntervalFromNow(0);
|
if (this->runState == CANNED_MESSAGE_RUN_STATE_ACTION_SELECT) {
|
||||||
|
setIntervalFromNow(0); // on fast keypresses, this isn't fast enough.
|
||||||
|
} else {
|
||||||
|
runOnce();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -17,6 +17,9 @@
|
|||||||
#include "modules/TextMessageModule.h"
|
#include "modules/TextMessageModule.h"
|
||||||
#include "modules/TraceRouteModule.h"
|
#include "modules/TraceRouteModule.h"
|
||||||
#include "modules/WaypointModule.h"
|
#include "modules/WaypointModule.h"
|
||||||
|
#if ARCH_RASPBERRY_PI
|
||||||
|
#include "input/LinuxInputImpl.h"
|
||||||
|
#endif
|
||||||
#if HAS_TELEMETRY
|
#if HAS_TELEMETRY
|
||||||
#include "modules/Telemetry/DeviceTelemetry.h"
|
#include "modules/Telemetry/DeviceTelemetry.h"
|
||||||
#endif
|
#endif
|
||||||
@ -44,7 +47,7 @@
|
|||||||
void setupModules()
|
void setupModules()
|
||||||
{
|
{
|
||||||
if (config.device.role != meshtastic_Config_DeviceConfig_Role_REPEATER) {
|
if (config.device.role != meshtastic_Config_DeviceConfig_Role_REPEATER) {
|
||||||
#if HAS_BUTTON
|
#if HAS_BUTTON || ARCH_RASPBERRY_PI
|
||||||
inputBroker = new InputBroker();
|
inputBroker = new InputBroker();
|
||||||
#endif
|
#endif
|
||||||
adminModule = new AdminModule();
|
adminModule = new AdminModule();
|
||||||
@ -61,7 +64,7 @@ void setupModules()
|
|||||||
|
|
||||||
new RemoteHardwareModule();
|
new RemoteHardwareModule();
|
||||||
new ReplyModule();
|
new ReplyModule();
|
||||||
#if HAS_BUTTON
|
#if HAS_BUTTON || ARCH_RASPBERRY_PI
|
||||||
rotaryEncoderInterruptImpl1 = new RotaryEncoderInterruptImpl1();
|
rotaryEncoderInterruptImpl1 = new RotaryEncoderInterruptImpl1();
|
||||||
if (!rotaryEncoderInterruptImpl1->init()) {
|
if (!rotaryEncoderInterruptImpl1->init()) {
|
||||||
delete rotaryEncoderInterruptImpl1;
|
delete rotaryEncoderInterruptImpl1;
|
||||||
@ -79,6 +82,10 @@ void setupModules()
|
|||||||
kbMatrixImpl->init();
|
kbMatrixImpl->init();
|
||||||
#endif // INPUTBROKER_MATRIX_TYPE
|
#endif // INPUTBROKER_MATRIX_TYPE
|
||||||
#endif // HAS_BUTTON
|
#endif // HAS_BUTTON
|
||||||
|
#if ARCH_RASPBERRY_PI
|
||||||
|
aLinuxInputImpl = new LinuxInputImpl();
|
||||||
|
aLinuxInputImpl->init();
|
||||||
|
#endif
|
||||||
#if HAS_TRACKBALL
|
#if HAS_TRACKBALL
|
||||||
trackballInterruptImpl1 = new TrackballInterruptImpl1();
|
trackballInterruptImpl1 = new TrackballInterruptImpl1();
|
||||||
trackballInterruptImpl1->init();
|
trackballInterruptImpl1->init();
|
||||||
|
@ -17,7 +17,8 @@
|
|||||||
#include <map>
|
#include <map>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
std::map<int, int> settingsMap;
|
std::map<configNames, int> settingsMap;
|
||||||
|
std::map<configNames, std::string> settingsStrings;
|
||||||
|
|
||||||
#else
|
#else
|
||||||
#include <linux/gpio/LinuxGPIOPin.h>
|
#include <linux/gpio/LinuxGPIOPin.h>
|
||||||
@ -154,6 +155,28 @@ void portduinoSetup()
|
|||||||
settingsMap[has_gps] = 1;
|
settingsMap[has_gps] = 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
settingsMap[displayPanel] = no_screen;
|
||||||
|
if (yamlConfig["Display"]) {
|
||||||
|
if (yamlConfig["Display"]["Panel"].as<std::string>("") == "ST7789")
|
||||||
|
settingsMap[displayPanel] = st7789;
|
||||||
|
settingsMap[displayHeight] = yamlConfig["Display"]["Height"].as<int>(0);
|
||||||
|
settingsMap[displayWidth] = yamlConfig["Display"]["Width"].as<int>(0);
|
||||||
|
settingsMap[displayDC] = yamlConfig["Display"]["DC"].as<int>(-1);
|
||||||
|
settingsMap[displayCS] = yamlConfig["Display"]["CS"].as<int>(-1);
|
||||||
|
settingsMap[displayBacklight] = yamlConfig["Display"]["Backlight"].as<int>(-1);
|
||||||
|
settingsMap[displayReset] = yamlConfig["Display"]["Reset"].as<int>(-1);
|
||||||
|
settingsMap[displayRotate] = yamlConfig["Display"]["Rotate"].as<bool>(false);
|
||||||
|
}
|
||||||
|
settingsMap[touchscreenModule] = no_touchscreen;
|
||||||
|
if (yamlConfig["Touchscreen"]) {
|
||||||
|
if (yamlConfig["Touchscreen"]["Module"].as<std::string>("") == "XPT2046")
|
||||||
|
settingsMap[touchscreenModule] = xpt2046;
|
||||||
|
settingsMap[touchscreenCS] = yamlConfig["Touchscreen"]["CS"].as<int>(-1);
|
||||||
|
settingsMap[touchscreenIRQ] = yamlConfig["Touchscreen"]["IRQ"].as<int>(-1);
|
||||||
|
}
|
||||||
|
if (yamlConfig["Input"]) {
|
||||||
|
settingsStrings[keyboardDevice] = (yamlConfig["Input"]["KeyboardDevice"]).as<std::string>("");
|
||||||
|
}
|
||||||
|
|
||||||
} catch (YAML::Exception e) {
|
} catch (YAML::Exception e) {
|
||||||
std::cout << "*** Exception " << e.what() << std::endl;
|
std::cout << "*** Exception " << e.what() << std::endl;
|
||||||
@ -191,6 +214,23 @@ void portduinoSetup()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (settingsMap[displayPanel] != no_screen) {
|
||||||
|
if (settingsMap[displayCS] > 0)
|
||||||
|
initGPIOPin(settingsMap[displayCS], gpioChipName);
|
||||||
|
if (settingsMap[displayDC] > 0)
|
||||||
|
initGPIOPin(settingsMap[displayDC], gpioChipName);
|
||||||
|
if (settingsMap[displayBacklight] > 0)
|
||||||
|
initGPIOPin(settingsMap[displayBacklight], gpioChipName);
|
||||||
|
if (settingsMap[displayReset] > 0)
|
||||||
|
initGPIOPin(settingsMap[displayReset], gpioChipName);
|
||||||
|
}
|
||||||
|
if (settingsMap[touchscreenModule] != no_touchscreen) {
|
||||||
|
if (settingsMap[touchscreenCS] > 0)
|
||||||
|
initGPIOPin(settingsMap[touchscreenCS], gpioChipName);
|
||||||
|
if (settingsMap[touchscreenIRQ] > 0)
|
||||||
|
initGPIOPin(settingsMap[touchscreenIRQ], gpioChipName);
|
||||||
|
}
|
||||||
|
|
||||||
return;
|
return;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -250,8 +290,9 @@ int initGPIOPin(int pinNum, std::string gpioChipName)
|
|||||||
csPin->setSilent();
|
csPin->setSilent();
|
||||||
gpioBind(csPin);
|
gpioBind(csPin);
|
||||||
return ERRNO_OK;
|
return ERRNO_OK;
|
||||||
} catch (std::invalid_argument &e) {
|
} catch (...) {
|
||||||
std::cout << "Warning, cannot claim pin" << gpio_name << std::endl;
|
std::exception_ptr p = std::current_exception();
|
||||||
|
std::cout << "Warning, cannot claim pin " << gpio_name << (p ? p.__cxa_exception_type()->name() : "null") << std::endl;
|
||||||
return ERRNO_DISABLED;
|
return ERRNO_DISABLED;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,9 +2,35 @@
|
|||||||
#ifdef ARCH_RASPBERRY_PI
|
#ifdef ARCH_RASPBERRY_PI
|
||||||
#include <map>
|
#include <map>
|
||||||
|
|
||||||
extern std::map<int, int> settingsMap;
|
enum configNames {
|
||||||
|
use_sx1262,
|
||||||
|
cs,
|
||||||
|
irq,
|
||||||
|
busy,
|
||||||
|
reset,
|
||||||
|
dio2_as_rf_switch,
|
||||||
|
use_rf95,
|
||||||
|
user,
|
||||||
|
gpiochip,
|
||||||
|
has_gps,
|
||||||
|
touchscreenModule,
|
||||||
|
touchscreenCS,
|
||||||
|
touchscreenIRQ,
|
||||||
|
displayPanel,
|
||||||
|
displayWidth,
|
||||||
|
displayHeight,
|
||||||
|
displayCS,
|
||||||
|
displayDC,
|
||||||
|
displayBacklight,
|
||||||
|
displayReset,
|
||||||
|
displayRotate,
|
||||||
|
keyboardDevice
|
||||||
|
};
|
||||||
|
enum { no_screen, st7789 };
|
||||||
|
enum { no_touchscreen, xpt2046 };
|
||||||
|
|
||||||
enum { use_sx1262, cs, irq, busy, reset, dio2_as_rf_switch, use_rf95, user, gpiochip, has_gps };
|
extern std::map<configNames, int> settingsMap;
|
||||||
|
extern std::map<configNames, std::string> settingsStrings;
|
||||||
int initGPIOPin(int pinNum, std::string gpioChipname);
|
int initGPIOPin(int pinNum, std::string gpioChipname);
|
||||||
|
|
||||||
#endif
|
#endif
|
@ -19,4 +19,5 @@ extends = portduino_base
|
|||||||
build_flags = ${portduino_base.build_flags} -O0 -lgpiod -I variants/portduino -DARCH_RASPBERRY_PI -lpigpio -lyaml-cpp
|
build_flags = ${portduino_base.build_flags} -O0 -lgpiod -I variants/portduino -DARCH_RASPBERRY_PI -lpigpio -lyaml-cpp
|
||||||
board = linux_arm
|
board = linux_arm
|
||||||
lib_deps = ${portduino_base.lib_deps}
|
lib_deps = ${portduino_base.lib_deps}
|
||||||
|
https://github.com/jp-bennett/LovyanGFX.git#jp-bennett-patch-1 ; lovyan03/LovyanGFX@^1.1.9
|
||||||
build_src_filter = ${portduino_base.build_src_filter}
|
build_src_filter = ${portduino_base.build_src_filter}
|
@ -1,6 +1,7 @@
|
|||||||
#if defined(ARCH_RASPBERRY_PI)
|
#if defined(ARCH_RASPBERRY_PI)
|
||||||
#define HAS_WIRE 1
|
#define HAS_WIRE 1
|
||||||
#define HAS_SCREEN 1
|
#define HAS_SCREEN 1
|
||||||
|
#define CANNED_MESSAGE_MODULE_ENABLE 1
|
||||||
|
|
||||||
#else // Pine64 mode.
|
#else // Pine64 mode.
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user