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>
pull/3001/head^2
Jonathan Bennett 2023-12-12 20:27:31 -06:00 zatwierdzone przez GitHub
rodzic d14d2c89c3
commit 2ebaea317a
Nie znaleziono w bazie danych klucza dla tego podpisu
ID klucza GPG: 4AEE18F83AFDEB23
21 zmienionych plików z 682 dodań i 131 usunięć

Wyświetl plik

@ -1,6 +1,6 @@
; The Portduino based sim environment on top of any host OS, all hardware will be simulated
[portduino_base]
platform = https://github.com/meshtastic/platform-native.git#05255283879a0c65a7d3eba6c468b9186438bb14
platform = https://github.com/meshtastic/platform-native.git#ff5da1d203b5c1163cfcda858d5f84920187f030
framework = arduino
build_src_filter =
@ -28,5 +28,4 @@ build_flags =
${arduino_base.build_flags}
-fPIC
-Isrc/platform/portduino
-DRADIOLIB_EEPROM_UNSUPPORTED
-DRADIOLIB_EEPROM_UNSUPPORTED

Wyświetl plik

@ -1,5 +1,5 @@
# Define your devices here using Broadcom pin numbering
# Uncomment the block that corresponds to your hardware
### Define your devices here using Broadcom pin numbering
### Uncomment the block that corresponds to your hardware
---
Lora:
# Module: sx1262 # Waveshare SX126X XXXM
@ -25,16 +25,40 @@ Lora:
# CS: 7
# IRQ: 25
# Set gpio chip to use in /dev/. Defaults to 0.
# Notably the Raspberry Pi 5 puts the GPIO header on gpiochip4
### Set gpio chip to use in /dev/. Defaults to 0.
### Notably the Raspberry Pi 5 puts the GPIO header on gpiochip4
# gpiochip: 4
# Define GPIO buttons here:
### Define GPIO buttons here:
GPIO:
# User: 6
# Define GPS
### Define GPS
GPS:
# 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

Wyświetl plik

@ -1,9 +1,12 @@
[unit]
description=Meshtastic Native Daemon
[Unit]
Description=Meshtastic Native Daemon
After=network-online.target
[Service]
User=root
Group=root
Type=simple
ExecStart=/usr/sbin/meshtasticd
[Install]
WantedBy=multi-user.target
WantedBy=multi-user.target

Wyświetl plik

@ -52,6 +52,10 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#include "modules/esp32/StoreForwardModule.h"
#endif
#if ARCH_RASPBERRY_PI
#include "platform/portduino/PortduinoGlue.h"
#endif
#ifdef OLED_RU
#include "fonts/OLEDDisplayFontsRU.h"
#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)
: 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)
: concurrency::OSThread("Screen"), address_found(address), model(screenType), geometry(geometry), cmdQueue(32)
{
#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);
}
@ -925,8 +959,8 @@ void Screen::doDeepSleep()
#ifdef USE_EINK
static FrameCallback sleepFrames[] = {drawSleepScreen};
static const int sleepFrameCount = sizeof(sleepFrames) / sizeof(sleepFrames[0]);
ui.setFrames(sleepFrames, sleepFrameCount);
ui.update();
ui->setFrames(sleepFrames, sleepFrameCount);
ui->update();
#endif
setOn(false);
}
@ -942,14 +976,16 @@ void Screen::handleSetOn(bool on)
#ifdef T_WATCH_S3
PMU->enablePowerOutput(XPOWERS_ALDO2);
#endif
dispdev.displayOn();
dispdev.displayOn();
#if !ARCH_RASPBERRY_PI
dispdev->displayOn();
#endif
dispdev->displayOn();
enabled = true;
setInterval(0); // Draw ASAP
runASAP = true;
} else {
LOG_INFO("Turning off screen\n");
dispdev.displayOff();
dispdev->displayOff();
#ifdef T_WATCH_S3
PMU->disablePowerOutput(XPOWERS_ALDO2);
#endif
@ -966,32 +1002,33 @@ void Screen::setup()
useDisplay = true;
#ifdef AutoOLEDWire_h
dispdev.setDetected(model);
if (isAUTOOled)
static_cast<AutoOLEDWire *>(dispdev)->setDetected(model);
#endif
#ifdef USE_SH1107_128_64
dispdev.setSubtype(7);
static_cast<SH1106Wire *>(dispdev)->setSubtype(7);
#endif
// Initialising the UI will init the display too.
ui.init();
ui->init();
displayWidth = dispdev.width();
displayHeight = dispdev.height();
displayWidth = dispdev->width();
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.
ui.setIndicatorDirection(LEFT_RIGHT);
ui.setFrameAnimation(SLIDE_LEFT);
ui->setIndicatorDirection(LEFT_RIGHT);
ui->setFrameAnimation(SLIDE_LEFT);
// 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.
ui.getUiState()->userData = this;
ui->getUiState()->userData = this;
// Set the utf8 conversion function
dispdev.setFontTableLookupFunction(customFontTableLookup);
dispdev->setFontTableLookupFunction(customFontTableLookup);
if (strlen(oemStore.oem_text) > 0)
logo_timeout *= 2;
@ -999,23 +1036,23 @@ void Screen::setup()
// Add frames.
static FrameCallback bootFrames[] = {drawBootScreen};
static const int bootFrameCount = sizeof(bootFrames) / sizeof(bootFrames[0]);
ui.setFrames(bootFrames, bootFrameCount);
ui->setFrames(bootFrames, bootFrameCount);
// No overlays.
ui.setOverlays(nullptr, 0);
ui->setOverlays(nullptr, 0);
// Require presses to switch between frames.
ui.disableAutoTransition();
ui->disableAutoTransition();
// Set up a log buffer with 3 lines, 32 chars each.
dispdev.setLogBuffer(3, 32);
dispdev->setLogBuffer(3, 32);
#ifdef SCREEN_MIRROR
dispdev.mirrorScreen();
dispdev->mirrorScreen();
#else
// 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.
if (!config.display.flip_screen) {
dispdev.flipScreenVertically();
dispdev->flipScreenVertically();
}
#endif
@ -1023,20 +1060,30 @@ void Screen::setup()
uint8_t dmac[6];
getMacAddr(dmac);
snprintf(ourId, sizeof(ourId), "%02x%02x", dmac[4], dmac[5]);
#if ARCH_RASPBERRY_PI
handleSetOn(false); // force clean init
#endif
// Turn on the display.
handleSetOn(true);
// 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
ui.update();
ui->update();
#ifndef USE_EINK
ui.update();
ui->update();
#endif
serialSinceMsec = millis();
#if HAS_TOUCHSCREEN
touchScreenImpl1 = new TouchScreenImpl1(dispdev.getWidth(), dispdev.getHeight(), dispdev.getTouch);
#if ARCH_RASPBERRY_PI
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();
#endif
@ -1057,7 +1104,7 @@ void Screen::forceDisplay()
{
// Nasty hack to force epaper updates for 'key' frames. FIXME, cleanup.
#ifdef USE_EINK
dispdev.forceDisplay();
static_cast<EInkDisplay *>(dispdev)->forceDisplay();
#endif
}
@ -1088,10 +1135,10 @@ int32_t Screen::runOnce()
// Change frames.
static FrameCallback bootOEMFrames[] = {drawOEMBootScreen};
static const int bootOEMFrameCount = sizeof(bootOEMFrames) / sizeof(bootOEMFrames[0]);
ui.setFrames(bootOEMFrames, bootOEMFrameCount);
ui.update();
ui->setFrames(bootOEMFrames, bootOEMFrameCount);
ui->update();
#ifndef USE_EINK
ui.update();
ui->update();
#endif
showingOEMBootScreen = false;
}
@ -1164,16 +1211,16 @@ int32_t Screen::runOnce()
// this must be before the frameState == FIXED check, because we always
// 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
// but we should only call setTargetFPS when framestate changes, because
// otherwise that breaks animations.
if (targetFramerate != IDLE_FRAMERATE && ui.getUiState()->frameState == FIXED) {
// oldFrameState = ui.getUiState()->frameState;
if (targetFramerate != IDLE_FRAMERATE && ui->getUiState()->frameState == FIXED) {
// oldFrameState = ui->getUiState()->frameState;
targetFramerate = IDLE_FRAMERATE;
ui.setTargetFPS(targetFramerate);
ui->setTargetFPS(targetFramerate);
forceDisplay();
}
@ -1189,7 +1236,7 @@ int32_t Screen::runOnce()
}
// 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
// as fast as we really need so that any rounding errors still result with
// the correct framerate
@ -1221,8 +1268,8 @@ void Screen::setSSLFrames()
if (address_found.address) {
// LOG_DEBUG("showing SSL frames\n");
static FrameCallback sslFrames[] = {drawSSLScreen};
ui.setFrames(sslFrames, 1);
ui.update();
ui->setFrames(sslFrames, 1);
ui->update();
}
}
@ -1306,8 +1353,8 @@ void Screen::setFrames()
LOG_DEBUG("Finished building frames. numframes: %d\n", numframes);
ui.setFrames(normalFrames, numframes);
ui.enableAllIndicators();
ui->setFrames(normalFrames, numframes);
ui->enableAllIndicators();
prevFrame = -1; // Force drawNodeInfo to pick a new node (because our list
// just changed)
@ -1327,8 +1374,8 @@ void Screen::handleStartBluetoothPinScreen(uint32_t pin)
void Screen::setFrameImmediateDraw(FrameCallback *drawFrames)
{
ui.disableAllIndicators();
ui.setFrames(drawFrames, 1);
ui->disableAllIndicators();
ui->setFrames(drawFrames, 1);
setFastFramerate();
}
@ -1370,17 +1417,17 @@ void Screen::blink()
{
setFastFramerate();
uint8_t count = 10;
dispdev.setBrightness(254);
dispdev->setBrightness(254);
while (count > 0) {
dispdev.fillRect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);
dispdev.display();
dispdev->fillRect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);
dispdev->display();
delay(50);
dispdev.clear();
dispdev.display();
dispdev->clear();
dispdev->display();
delay(50);
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)
@ -1408,15 +1455,15 @@ void Screen::handlePrint(const char *text)
if (!useDisplay || !showingNormalScreen)
return;
dispdev.print(text);
dispdev->print(text);
}
void Screen::handleOnPress()
{
// 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();
if (ui->getUiState()->frameState == FIXED) {
ui->nextFrame();
lastScreenTransition = millis();
setFastFramerate();
}
@ -1426,8 +1473,8 @@ 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();
if (ui->getUiState()->frameState == FIXED) {
ui->previousFrame();
lastScreenTransition = millis();
setFastFramerate();
}
@ -1437,8 +1484,8 @@ 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();
if (ui->getUiState()->frameState == FIXED) {
ui->nextFrame();
lastScreenTransition = millis();
setFastFramerate();
}
@ -1453,7 +1500,7 @@ void Screen::setFastFramerate()
// We are about to start a transition so speed up fps
targetFramerate = SCREEN_TRANSITION_FRAMERATE;
ui.setTargetFPS(targetFramerate);
ui->setTargetFPS(targetFramerate);
setInterval(0); // redraw ASAP
runASAP = true;
}
@ -1540,7 +1587,8 @@ void DebugInfo::drawFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16
}
#endif
} 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)
display->drawFastImage(x + SCREEN_WIDTH - 14 - display->getStringWidth(ourId), y + 3 + FONT_HEIGHT_SMALL, 12, 8,
imgInfoL1);
@ -1780,7 +1828,7 @@ int Screen::handleUIFrameEvent(const UIFrameEvent *event)
setFastFramerate();
// TODO: We might also want switch to corresponding frame,
// but we don't know the exact frame number.
// ui.switchToFrame(0);
// ui->switchToFrame(0);
}
}

Wyświetl plik

@ -324,6 +324,8 @@ class Screen : public concurrency::OSThread
// Called periodically from the main loop.
int32_t runOnce() final;
bool isAUTOOled = false;
private:
struct ScreenCmd {
Cmd cmd;
@ -385,22 +387,10 @@ class Screen : public concurrency::OSThread
DebugInfo debugInfo;
/// 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
OLEDDisplayUi ui;
OLEDDisplayUi *ui;
};
} // namespace graphics

Wyświetl plik

@ -1,5 +1,8 @@
#include "configuration.h"
#include "main.h"
#if ARCH_RASPBERRY_PI
#include "platform/portduino/PortduinoGlue.h"
#endif
#ifndef TFT_BACKLIGHT_ON
#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)
#include <TFT_eSPI.h>
TFT_eSPI tft = TFT_eSPI();
TFT_eSPI *tft = nullptr;
#elif defined(ST7789_CS)
#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)
@ -322,23 +325,96 @@ class LGFX : public lgfx::LGFX_Device
}
};
static LGFX tft;
static LGFX *tft = nullptr;
#elif defined(ST7735_CS)
#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
#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 "TFTDisplay.h"
#include <SPI.h>
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);
#else
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
void TFTDisplay::display(void)
void TFTDisplay::display(bool fromBlank)
{
if (fromBlank)
tft->clear();
concurrency::LockGuard g(spiLock);
uint16_t x, y;
for (y = 0; y < displayHeight; y++) {
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 dblbuf_isset = buffer_back[x + (y / 8) * displayWidth] & (1 << (y & 7));
if (isset != dblbuf_isset) {
tft.drawPixel(x, y, isset ? TFT_MESH : TFT_BLACK);
if (!fromBlank) {
// get src pixel in the page based ordering the OLED lib uses FIXME, super inefficent
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
switch (com) {
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) {
digitalWrite(ST7735_BACKLIGHT_EN_V03, TFT_BACKLIGHT_ON);
} else {
@ -400,12 +486,16 @@ void TFTDisplay::sendCommand(uint8_t com)
#ifdef RAK14014
#elif !defined(M5STACK)
tft.setBrightness(128);
tft->setBrightness(128);
#endif
break;
}
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) {
digitalWrite(ST7735_BACKLIGHT_EN_V03, !TFT_BACKLIGHT_ON);
} else {
@ -427,7 +517,7 @@ void TFTDisplay::sendCommand(uint8_t com)
#endif
#ifdef RAK14014
#elif !defined(M5STACK)
tft.setBrightness(0);
tft->setBrightness(0);
#endif
break;
}
@ -442,7 +532,7 @@ void TFTDisplay::flipScreenVertically()
{
#if defined(T_WATCH_S3)
LOG_DEBUG("Flip TFT vertically\n"); // T-Watch S3 right-handed orientation
tft.setRotation(0);
tft->setRotation(0);
#endif
}
@ -450,7 +540,7 @@ bool TFTDisplay::hasTouch(void)
{
#ifdef RAK14014
#elif !defined(M5STACK)
return tft.touch() != nullptr;
return tft->touch() != nullptr;
#else
return false;
#endif
@ -460,7 +550,7 @@ bool TFTDisplay::getTouch(int16_t *x, int16_t *y)
{
#ifdef RAK14014
#elif !defined(M5STACK)
return tft.getTouch(x, y);
return tft->getTouch(x, y);
#else
return false;
#endif
@ -476,6 +566,11 @@ bool TFTDisplay::connect()
{
concurrency::LockGuard g(spiLock);
LOG_INFO("Doing TFT init\n");
#ifdef RAK14014
tft = new TFT_eSPI;
#else
tft = new LGFX;
#endif
#ifdef TFT_BL
pinMode(TFT_BL, OUTPUT);
@ -495,24 +590,24 @@ bool TFTDisplay::connect()
}
#endif
tft.init();
tft->init();
#if defined(M5STACK)
tft.setRotation(0);
tft->setRotation(0);
#elif defined(RAK14014)
tft.setRotation(1);
tft.setSwapBytes(true);
// tft.fillScreen(TFT_BLACK);
tft->setRotation(1);
tft->setSwapBytes(true);
// tft->fillScreen(TFT_BLACK);
#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)
tft.setRotation(2); // T-Watch S3 left-handed orientation
tft->setRotation(2); // T-Watch S3 left-handed orientation
#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
tft.fillScreen(TFT_BLACK);
tft->fillScreen(TFT_BLACK);
return true;
}
#endif
#endif

Wyświetl plik

@ -20,7 +20,8 @@ class TFTDisplay : public OLEDDisplay
TFTDisplay(uint8_t, int, int, OLEDDISPLAY_GEOMETRY, HW_I2C);
// 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
virtual void flipScreenVertically();

Wyświetl plik

@ -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 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)
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};
@ -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};
#endif
#include "img/icon.xbm"
#include "img/icon.xbm"

Wyświetl plik

@ -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

Wyświetl plik

@ -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

Wyświetl plik

@ -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

Wyświetl plik

@ -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

Wyświetl plik

@ -4,6 +4,10 @@
#include "configuration.h"
#include "modules/ExternalNotificationModule.h"
#ifdef ARCH_RASPBERRY_PI
#include "platform/portduino/PortduinoGlue.h"
#endif
TouchScreenImpl1 *touchScreenImpl1;
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()
{
#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);
return;
#else

Wyświetl plik

@ -697,6 +697,10 @@ void setup()
// the current region name)
#if defined(ST7735_CS) || defined(USE_EINK) || defined(ILI9341_DRIVER) || defined(ST7789_CS)
screen->setup();
#elif ARCH_RASPBERRY_PI
if (screen_found.port != ScanI2C::I2CPort::NO_I2C || settingsMap[displayPanel]) {
screen->setup();
}
#else
if (screen_found.port != ScanI2C::I2CPort::NO_I2C)
screen->setup();

Wyświetl plik

@ -27,6 +27,10 @@
#include <nvs_flash.h>
#endif
#ifdef ARCH_RASPBERRY_PI
#include "platform/portduino/PortduinoGlue.h"
#endif
#ifdef ARCH_NRF52
#include <bluefruit.h>
#include <utility/bonding.h>
@ -191,6 +195,12 @@ void NodeDB::installDefaultConfig()
config.bluetooth.fixed_pin = defaultBLEPin;
#if defined(ST7735_CS) || defined(USE_EINK) || defined(ILI9341_DRIVER) || defined(ST7789_CS)
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
bool hasScreen = screen_found.port != ScanI2C::I2CPort::NO_I2C;
#endif

Wyświetl plik

@ -1,4 +1,7 @@
#include "configuration.h"
#if ARCH_RASPBERRY_PI
#include "PortduinoGlue.h"
#endif
#if HAS_SCREEN
#include "CannedMessageModule.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)) {
LOG_DEBUG("Canned message event Cancel\n");
// emulate a timeout. Same result
this->lastTouchMillis = 0;
validEvent = true;
UIFrameEvent e = {false, true};
e.frameChanged = 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)) ||
(event->inputEvent == static_cast<char>(meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_LEFT)) ||
@ -212,7 +220,11 @@ int CannedMessageModule::handleInputEvent(const InputEvent *event)
if (validEvent) {
// 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;

Wyświetl plik

@ -17,6 +17,9 @@
#include "modules/TextMessageModule.h"
#include "modules/TraceRouteModule.h"
#include "modules/WaypointModule.h"
#if ARCH_RASPBERRY_PI
#include "input/LinuxInputImpl.h"
#endif
#if HAS_TELEMETRY
#include "modules/Telemetry/DeviceTelemetry.h"
#endif
@ -44,7 +47,7 @@
void setupModules()
{
if (config.device.role != meshtastic_Config_DeviceConfig_Role_REPEATER) {
#if HAS_BUTTON
#if HAS_BUTTON || ARCH_RASPBERRY_PI
inputBroker = new InputBroker();
#endif
adminModule = new AdminModule();
@ -61,7 +64,7 @@ void setupModules()
new RemoteHardwareModule();
new ReplyModule();
#if HAS_BUTTON
#if HAS_BUTTON || ARCH_RASPBERRY_PI
rotaryEncoderInterruptImpl1 = new RotaryEncoderInterruptImpl1();
if (!rotaryEncoderInterruptImpl1->init()) {
delete rotaryEncoderInterruptImpl1;
@ -79,6 +82,10 @@ void setupModules()
kbMatrixImpl->init();
#endif // INPUTBROKER_MATRIX_TYPE
#endif // HAS_BUTTON
#if ARCH_RASPBERRY_PI
aLinuxInputImpl = new LinuxInputImpl();
aLinuxInputImpl->init();
#endif
#if HAS_TRACKBALL
trackballInterruptImpl1 = new TrackballInterruptImpl1();
trackballInterruptImpl1->init();

Wyświetl plik

@ -17,7 +17,8 @@
#include <map>
#include <unistd.h>
std::map<int, int> settingsMap;
std::map<configNames, int> settingsMap;
std::map<configNames, std::string> settingsStrings;
#else
#include <linux/gpio/LinuxGPIOPin.h>
@ -154,6 +155,28 @@ void portduinoSetup()
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) {
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;
#endif
@ -250,8 +290,9 @@ int initGPIOPin(int pinNum, std::string gpioChipName)
csPin->setSilent();
gpioBind(csPin);
return ERRNO_OK;
} catch (std::invalid_argument &e) {
std::cout << "Warning, cannot claim pin" << gpio_name << std::endl;
} catch (...) {
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;
}
}

Wyświetl plik

@ -2,9 +2,35 @@
#ifdef ARCH_RASPBERRY_PI
#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);
#endif

Wyświetl plik

@ -19,4 +19,5 @@ extends = portduino_base
build_flags = ${portduino_base.build_flags} -O0 -lgpiod -I variants/portduino -DARCH_RASPBERRY_PI -lpigpio -lyaml-cpp
board = linux_arm
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}

Wyświetl plik

@ -1,6 +1,7 @@
#if defined(ARCH_RASPBERRY_PI)
#define HAS_WIRE 1
#define HAS_SCREEN 1
#define CANNED_MESSAGE_MODULE_ENABLE 1
#else // Pine64 mode.