kopia lustrzana https://github.com/meshtastic/firmware
T-Lora Pager (#7613)
* initial commit * preset rotary1 encoder * define TAB+ESC * haptic feedback * allow switch off haptic feedback * enable audio amplifier * include PR4684 * fix for tft target * add ES8311 audio codec * fix KB scan duplicate * display workaround to avoid debris * fix debris on display * keyboard backlight * enable screen options * fsm based bounce-free rotary encoder implementation * use fsm RotaryEncoder only for T-Lora Pager * change inputbroker default config to allow using rotary wheel for screens AND menues --------- Co-authored-by: Thomas Göttgens <tgoettgens@gmail.com> Co-authored-by: Ben Meadors <benmmeadors@gmail.com>pull/7756/head
rodzic
1a279c6053
commit
3f5c30e3b3
|
@ -79,7 +79,8 @@ class ScanI2C
|
|||
BQ27220,
|
||||
LTR553ALS,
|
||||
BHI260AP,
|
||||
BMM150
|
||||
BMM150,
|
||||
DRV2605
|
||||
} DeviceType;
|
||||
|
||||
// typedef uint8_t DeviceAddress;
|
||||
|
|
|
@ -483,8 +483,14 @@ void ScanI2CTwoWire::scanPort(I2CPort port, uint8_t *address, uint8_t asize)
|
|||
type = MLX90614;
|
||||
logFoundDevice("MLX90614", (uint8_t)addr.address);
|
||||
} else {
|
||||
type = MPR121KB;
|
||||
logFoundDevice("MPR121KB", (uint8_t)addr.address);
|
||||
registerValue = getRegisterValue(ScanI2CTwoWire::RegisterLocation(addr, 0x00), 1); // DRV2605_REG_STATUS
|
||||
if (registerValue == 0xe0) {
|
||||
type = DRV2605;
|
||||
logFoundDevice("DRV2605", (uint8_t)addr.address);
|
||||
} else {
|
||||
type = MPR121KB;
|
||||
logFoundDevice("MPR121KB", (uint8_t)addr.address);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
|
|
|
@ -318,7 +318,7 @@ Screen::Screen(ScanI2C::DeviceAddress address, meshtastic_Config_DisplayConfig_O
|
|||
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(ILI9342_DRIVER) || defined(ST7701_CS) || defined(ST7789_CS) || \
|
||||
defined(RAK14014) || defined(HX8357_CS) || defined(ILI9488_CS)
|
||||
defined(RAK14014) || defined(HX8357_CS) || defined(ILI9488_CS) || defined(ST7796_CS)
|
||||
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) && !defined(USE_EINK_DYNAMICDISPLAY)
|
||||
|
@ -550,7 +550,7 @@ void Screen::setup()
|
|||
#else
|
||||
if (!config.display.flip_screen) {
|
||||
#if defined(ST7701_CS) || defined(ST7735_CS) || defined(ILI9341_DRIVER) || defined(ILI9342_DRIVER) || defined(ST7789_CS) || \
|
||||
defined(RAK14014) || defined(HX8357_CS) || defined(ILI9488_CS)
|
||||
defined(RAK14014) || defined(HX8357_CS) || defined(ILI9488_CS) || defined(ST7796_CS)
|
||||
static_cast<TFTDisplay *>(dispdev)->flipScreenVertically();
|
||||
#elif defined(USE_ST7789)
|
||||
static_cast<ST7789Spi *>(dispdev)->flipScreenVertically();
|
||||
|
|
|
@ -73,7 +73,7 @@
|
|||
#endif
|
||||
|
||||
#if (defined(USE_EINK) || defined(ILI9341_DRIVER) || defined(ILI9342_DRIVER) || defined(ST7701_CS) || defined(ST7735_CS) || \
|
||||
defined(ST7789_CS) || defined(USE_ST7789) || defined(HX8357_CS) || defined(ILI9488_CS)) && \
|
||||
defined(ST7789_CS) || defined(USE_ST7789) || defined(HX8357_CS) || defined(ILI9488_CS) || defined(ST7796_CS)) && \
|
||||
!defined(DISPLAY_FORCE_SMALL_FONTS)
|
||||
// The screen is bigger so use bigger fonts
|
||||
#define FONT_SMALL FONT_MEDIUM_LOCAL // Height: 19
|
||||
|
|
|
@ -562,6 +562,91 @@ class LGFX : public lgfx::LGFX_Device
|
|||
|
||||
static LGFX *tft = nullptr;
|
||||
|
||||
#elif defined(ST7796_CS)
|
||||
#include <LovyanGFX.hpp> // Graphics and font library for ST7796 driver chip
|
||||
|
||||
class LGFX : public lgfx::LGFX_Device
|
||||
{
|
||||
lgfx::Panel_ST7796 _panel_instance;
|
||||
lgfx::Bus_SPI _bus_instance;
|
||||
lgfx::Light_PWM _light_instance;
|
||||
|
||||
public:
|
||||
LGFX(void)
|
||||
{
|
||||
{
|
||||
auto cfg = _bus_instance.config();
|
||||
|
||||
// SPI
|
||||
cfg.spi_host = ST7796_SPI_HOST;
|
||||
cfg.spi_mode = 0;
|
||||
cfg.freq_write = SPI_FREQUENCY; // SPI clock for transmission (up to 80MHz, rounded to the value obtained by dividing
|
||||
// 80MHz by an integer)
|
||||
cfg.freq_read = SPI_READ_FREQUENCY; // SPI clock when receiving
|
||||
cfg.spi_3wire = false;
|
||||
cfg.use_lock = true; // Set to true to use transaction locking
|
||||
cfg.dma_channel = SPI_DMA_CH_AUTO; // SPI_DMA_CH_AUTO; // Set DMA channel to use (0=not use DMA / 1=1ch / 2=ch /
|
||||
// SPI_DMA_CH_AUTO=auto setting)
|
||||
cfg.pin_sclk = ST7796_SCK; // Set SPI SCLK pin number
|
||||
cfg.pin_mosi = ST7796_SDA; // Set SPI MOSI pin number
|
||||
cfg.pin_miso = ST7796_MISO; // Set SPI MISO pin number (-1 = disable)
|
||||
cfg.pin_dc = ST7796_RS; // Set SPI DC pin number (-1 = disable)
|
||||
|
||||
_bus_instance.config(cfg); // applies the set value to the bus.
|
||||
_panel_instance.setBus(&_bus_instance); // set the bus on the panel.
|
||||
}
|
||||
|
||||
{ // Set the display panel control.
|
||||
auto cfg = _panel_instance.config(); // Gets a structure for display panel settings.
|
||||
|
||||
cfg.pin_cs = ST7796_CS; // Pin number where CS is connected (-1 = disable)
|
||||
cfg.pin_rst = ST7796_RESET; // Pin number where RST is connected (-1 = disable)
|
||||
cfg.pin_busy = ST7796_BUSY; // Pin number where BUSY is connected (-1 = disable)
|
||||
|
||||
// cfg.memory_width = TFT_WIDTH; // Maximum width supported by the driver IC
|
||||
// cfg.memory_height = TFT_HEIGHT; // Maximum height supported by the driver IC
|
||||
cfg.panel_width = TFT_WIDTH; // actual displayable width
|
||||
cfg.panel_height = TFT_HEIGHT; // actual displayable height
|
||||
cfg.offset_x = TFT_OFFSET_X; // Panel offset amount in X direction
|
||||
cfg.offset_y = TFT_OFFSET_Y; // Panel offset amount in Y direction
|
||||
cfg.offset_rotation = TFT_OFFSET_ROTATION; // Rotation direction value offset 0~7 (4~7 is mirrored)
|
||||
#ifdef TFT_DUMMY_READ_PIXELS
|
||||
cfg.dummy_read_pixel = TFT_DUMMY_READ_PIXELS; // Number of bits for dummy read before pixel readout
|
||||
#else
|
||||
cfg.dummy_read_pixel = 8; // Number of bits for dummy read before pixel readout
|
||||
#endif
|
||||
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);
|
||||
}
|
||||
|
||||
#ifdef ST7796_BL
|
||||
// Set the backlight control. (delete if not necessary)
|
||||
{
|
||||
auto cfg = _light_instance.config(); // Gets a structure for backlight settings.
|
||||
|
||||
cfg.pin_bl = ST7796_BL; // Pin number to which the backlight is connected
|
||||
cfg.invert = false; // true to invert the brightness of the backlight
|
||||
cfg.freq = 44100;
|
||||
cfg.pwm_channel = 7;
|
||||
|
||||
_light_instance.config(cfg);
|
||||
_panel_instance.setLight(&_light_instance); // Set the backlight on the panel.
|
||||
}
|
||||
#endif
|
||||
|
||||
setPanel(&_panel_instance); // Sets the panel to use.
|
||||
}
|
||||
};
|
||||
|
||||
static LGFX *tft = nullptr;
|
||||
|
||||
#elif defined(ILI9341_DRIVER) || defined(ILI9342_DRIVER)
|
||||
|
||||
#include <LovyanGFX.hpp> // Graphics and font library for ILI9341/ILI9342 driver chip
|
||||
|
@ -997,8 +1082,9 @@ static LGFX *tft = nullptr;
|
|||
|
||||
#endif
|
||||
|
||||
#if defined(ST7701_CS) || defined(ST7735_CS) || defined(ST7789_CS) || defined(ILI9341_DRIVER) || defined(ILI9342_DRIVER) || \
|
||||
defined(RAK14014) || defined(HX8357_CS) || defined(ILI9488_CS) || defined(ST72xx_DE) || (ARCH_PORTDUINO && HAS_SCREEN != 0)
|
||||
#if defined(ST7701_CS) || defined(ST7735_CS) || defined(ST7789_CS) || defined(ST7796_CS) || defined(ILI9341_DRIVER) || \
|
||||
defined(ILI9342_DRIVER) || defined(RAK14014) || defined(HX8357_CS) || defined(ILI9488_CS) || defined(ST72xx_DE) || \
|
||||
(ARCH_PORTDUINO && HAS_SCREEN != 0)
|
||||
#include "SPILock.h"
|
||||
#include "TFTDisplay.h"
|
||||
#include <SPI.h>
|
||||
|
@ -1047,32 +1133,97 @@ void TFTDisplay::display(bool fromBlank)
|
|||
{
|
||||
if (fromBlank)
|
||||
tft->fillScreen(TFT_BLACK);
|
||||
// tft->clear();
|
||||
|
||||
concurrency::LockGuard g(spiLock);
|
||||
|
||||
uint16_t x, y;
|
||||
uint32_t x, y;
|
||||
uint32_t y_byteIndex;
|
||||
uint8_t y_byteMask;
|
||||
uint32_t x_FirstPixelUpdate;
|
||||
uint32_t x_LastPixelUpdate;
|
||||
bool isset, dblbuf_isset;
|
||||
uint16_t colorTftMesh, colorTftBlack;
|
||||
bool somethingChanged = false;
|
||||
|
||||
for (y = 0; y < displayHeight; y++) {
|
||||
for (x = 0; x < displayWidth; x++) {
|
||||
auto isset = buffer[x + (y / 8) * displayWidth] & (1 << (y & 7));
|
||||
// Store colors byte-reversed so that TFT_eSPI doesn't have to swap bytes in a separate step
|
||||
colorTftMesh = (TFT_MESH >> 8) | ((TFT_MESH & 0xFF) << 8);
|
||||
colorTftBlack = (TFT_BLACK >> 8) | ((TFT_BLACK & 0xFF) << 8);
|
||||
|
||||
y = 0;
|
||||
while (y < displayHeight) {
|
||||
y_byteIndex = (y / 8) * displayWidth;
|
||||
y_byteMask = (1 << (y & 7));
|
||||
|
||||
// Step 1: Do a quick scan of 8 rows together. This allows fast-forwarding over unchanged screen areas.
|
||||
if (y_byteMask == 1) {
|
||||
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);
|
||||
for (x = 0; x < displayWidth; x++) {
|
||||
if (buffer[x + y_byteIndex] != buffer_back[x + y_byteIndex])
|
||||
break;
|
||||
}
|
||||
} else if (isset) {
|
||||
tft->drawPixel(x, y, TFT_MESH);
|
||||
} else {
|
||||
for (x = 0; x < displayWidth; x++) {
|
||||
if (buffer[x + y_byteIndex] != 0)
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (x >= displayWidth) {
|
||||
// No changed pixels found in these 8 rows, fast-forward to the next 8
|
||||
y = y + 8;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// Step 2: Scan each of the 8 rows individually. Find the first pixel in each row that needs updating
|
||||
for (x_FirstPixelUpdate = 0; x_FirstPixelUpdate < displayWidth; x_FirstPixelUpdate++) {
|
||||
isset = buffer[x_FirstPixelUpdate + y_byteIndex] & y_byteMask;
|
||||
|
||||
if (!fromBlank) {
|
||||
// get src pixel in the page based ordering the OLED lib uses
|
||||
dblbuf_isset = buffer_back[x_FirstPixelUpdate + y_byteIndex] & y_byteMask;
|
||||
if (isset != dblbuf_isset) {
|
||||
break;
|
||||
}
|
||||
} else if (isset) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Did we find a pixel that needs updating on this row?
|
||||
if (x_FirstPixelUpdate < displayWidth) {
|
||||
|
||||
// Quickly write out the first changed pixel (saves another array lookup)
|
||||
linePixelBuffer[x_FirstPixelUpdate] = isset ? colorTftMesh : colorTftBlack;
|
||||
x_LastPixelUpdate = x_FirstPixelUpdate;
|
||||
|
||||
// Step 3: copy all remaining pixels in this row into the pixel line buffer,
|
||||
// while also recording the last pixel in the row that needs updating
|
||||
for (x = x_FirstPixelUpdate + 1; x < displayWidth; x++) {
|
||||
isset = buffer[x + y_byteIndex] & y_byteMask;
|
||||
linePixelBuffer[x] = isset ? colorTftMesh : colorTftBlack;
|
||||
|
||||
if (!fromBlank) {
|
||||
dblbuf_isset = buffer_back[x + y_byteIndex] & y_byteMask;
|
||||
if (isset != dblbuf_isset) {
|
||||
x_LastPixelUpdate = x;
|
||||
}
|
||||
} else if (isset) {
|
||||
x_LastPixelUpdate = x;
|
||||
}
|
||||
}
|
||||
|
||||
// Step 4: Send the changed pixels on this line to the screen as a single block transfer.
|
||||
// This function accepts pixel data MSB first so it can dump the memory straight out the SPI port.
|
||||
tft->pushRect(x_FirstPixelUpdate, y, (x_LastPixelUpdate - x_FirstPixelUpdate + 1), 1,
|
||||
&linePixelBuffer[x_FirstPixelUpdate]);
|
||||
|
||||
somethingChanged = true;
|
||||
}
|
||||
y++;
|
||||
}
|
||||
// Copy the Buffer to the Back Buffer
|
||||
for (y = 0; y < (displayHeight / 8); y++) {
|
||||
for (x = 0; x < displayWidth; x++) {
|
||||
uint16_t pos = x + y * displayWidth;
|
||||
buffer_back[pos] = buffer[pos];
|
||||
}
|
||||
}
|
||||
if (somethingChanged)
|
||||
memcpy(buffer_back, buffer, displayBufferSize);
|
||||
}
|
||||
|
||||
void TFTDisplay::sdlLoop()
|
||||
|
@ -1264,13 +1415,21 @@ bool TFTDisplay::connect()
|
|||
tft->setRotation(1); // T-Deck has the TFT in landscape
|
||||
#elif defined(T_WATCH_S3)
|
||||
tft->setRotation(2); // T-Watch S3 left-handed orientation
|
||||
#elif ARCH_PORTDUINO || defined(SENSECAP_INDICATOR)
|
||||
#elif ARCH_PORTDUINO || defined(SENSECAP_INDICATOR) || defined(T_LORA_PAGER)
|
||||
tft->setRotation(0); // use config.yaml to set rotation
|
||||
#else
|
||||
tft->setRotation(3); // Orient horizontal and wide underneath the silkscreen name label
|
||||
#endif
|
||||
tft->fillScreen(TFT_BLACK);
|
||||
|
||||
if (this->linePixelBuffer == NULL) {
|
||||
this->linePixelBuffer = (uint16_t *)malloc(sizeof(uint16_t) * displayWidth);
|
||||
|
||||
if (!this->linePixelBuffer) {
|
||||
LOG_ERROR("Not enough memory to create TFT line buffer\n");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -58,4 +58,6 @@ class TFTDisplay : public OLEDDisplay
|
|||
|
||||
// Connect to the display
|
||||
virtual bool connect() override;
|
||||
|
||||
uint16_t *linePixelBuffer = nullptr;
|
||||
};
|
|
@ -94,7 +94,8 @@ void drawFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16
|
|||
if (!Throttle::isWithinTimespanMs(storeForwardModule->lastHeartbeat,
|
||||
(storeForwardModule->heartbeatInterval * 1200))) { // no heartbeat, overlap a bit
|
||||
#if (defined(USE_EINK) || defined(ILI9341_DRIVER) || defined(ILI9342_DRIVER) || defined(ST7701_CS) || defined(ST7735_CS) || \
|
||||
defined(ST7789_CS) || defined(USE_ST7789) || defined(ILI9488_CS) || defined(HX8357_CS) || ARCH_PORTDUINO) && \
|
||||
defined(ST7789_CS) || defined(USE_ST7789) || defined(ILI9488_CS) || defined(HX8357_CS) || defined(ST7796_CS) || \
|
||||
ARCH_PORTDUINO) && \
|
||||
!defined(DISPLAY_FORCE_SMALL_FONTS)
|
||||
display->drawFastImage(x + SCREEN_WIDTH - 14 - display->getStringWidth(screen->ourId), y + 3 + FONT_HEIGHT_SMALL, 12,
|
||||
8, imgQuestionL1);
|
||||
|
@ -106,7 +107,7 @@ void drawFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16
|
|||
#endif
|
||||
} else {
|
||||
#if (defined(USE_EINK) || defined(ILI9341_DRIVER) || defined(ILI9342_DRIVER) || defined(ST7701_CS) || defined(ST7735_CS) || \
|
||||
defined(ST7789_CS) || defined(USE_ST7789) || defined(ILI9488_CS) || defined(HX8357_CS)) && \
|
||||
defined(ST7789_CS) || defined(USE_ST7789) || defined(ILI9488_CS) || defined(HX8357_CS) || defined(ST7796_CS)) && \
|
||||
!defined(DISPLAY_FORCE_SMALL_FONTS)
|
||||
display->drawFastImage(x + SCREEN_WIDTH - 18 - display->getStringWidth(screen->ourId), y + 3 + FONT_HEIGHT_SMALL, 16,
|
||||
8, imgSFL1);
|
||||
|
@ -121,7 +122,8 @@ void drawFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16
|
|||
} else {
|
||||
// TODO: Raspberry Pi supports more than just the one screen size
|
||||
#if (defined(USE_EINK) || defined(ILI9341_DRIVER) || defined(ILI9342_DRIVER) || defined(ST7701_CS) || defined(ST7735_CS) || \
|
||||
defined(ST7789_CS) || defined(USE_ST7789) || defined(ILI9488_CS) || defined(HX8357_CS) || ARCH_PORTDUINO) && \
|
||||
defined(ST7789_CS) || defined(USE_ST7789) || defined(ILI9488_CS) || defined(HX8357_CS) || defined(ST7796_CS) || \
|
||||
ARCH_PORTDUINO) && \
|
||||
!defined(DISPLAY_FORCE_SMALL_FONTS)
|
||||
display->drawFastImage(x + SCREEN_WIDTH - 14 - display->getStringWidth(screen->ourId), y + 3 + FONT_HEIGHT_SMALL, 12, 8,
|
||||
imgInfoL1);
|
||||
|
|
|
@ -434,8 +434,8 @@ void menuHandler::systemBaseMenu()
|
|||
|
||||
optionsArray[options] = "Notifications";
|
||||
optionsEnumArray[options++] = Notifications;
|
||||
#if defined(ST7789_CS) || defined(USE_OLED) || defined(USE_SSD1306) || defined(USE_SH1106) || defined(USE_SH1107) || \
|
||||
defined(HELTEC_MESH_NODE_T114) || defined(HELTEC_VISION_MASTER_T190) || HAS_TFT
|
||||
#if defined(ST7789_CS) || defined(ST7796_CS) || defined(USE_OLED) || defined(USE_SSD1306) || defined(USE_SH1106) || \
|
||||
defined(USE_SH1107) || defined(HELTEC_MESH_NODE_T114) || defined(HELTEC_VISION_MASTER_T190) || HAS_TFT
|
||||
optionsArray[options] = "Screen Options";
|
||||
optionsEnumArray[options++] = ScreenOptions;
|
||||
#endif
|
||||
|
@ -725,7 +725,7 @@ void menuHandler::BrightnessPickerMenu()
|
|||
#if defined(HELTEC_MESH_NODE_T114) || defined(HELTEC_VISION_MASTER_T190)
|
||||
// For HELTEC devices, use analogWrite to control backlight
|
||||
analogWrite(VTFT_LEDA, uiconfig.screen_brightness);
|
||||
#elif defined(ST7789_CS)
|
||||
#elif defined(ST7789_CS) || defined(ST7796_CS)
|
||||
static_cast<TFTDisplay *>(screen->getDisplayDevice())->setDisplayBrightness(uiconfig.screen_brightness);
|
||||
#elif defined(USE_OLED) || defined(USE_SSD1306) || defined(USE_SH1106) || defined(USE_SH1107)
|
||||
screen->getDisplayDevice()->setBrightness(uiconfig.screen_brightness);
|
||||
|
@ -768,7 +768,7 @@ void menuHandler::TFTColorPickerMenu(OLEDDisplay *display)
|
|||
bannerOptions.optionsArrayPtr = optionsArray;
|
||||
bannerOptions.optionsCount = 10;
|
||||
bannerOptions.bannerCallback = [display](int selected) -> void {
|
||||
#if defined(HELTEC_MESH_NODE_T114) || defined(HELTEC_VISION_MASTER_T190) || defined(T_DECK) || HAS_TFT
|
||||
#if defined(HELTEC_MESH_NODE_T114) || defined(HELTEC_VISION_MASTER_T190) || defined(T_DECK) || defined(T_LORA_PAGER) || HAS_TFT
|
||||
uint8_t TFT_MESH_r = 0;
|
||||
uint8_t TFT_MESH_g = 0;
|
||||
uint8_t TFT_MESH_b = 0;
|
||||
|
@ -1045,7 +1045,7 @@ void menuHandler::screenOptionsMenu()
|
|||
}
|
||||
|
||||
// Only show screen color for TFT displays
|
||||
#if defined(HELTEC_MESH_NODE_T114) || defined(HELTEC_VISION_MASTER_T190) || defined(T_DECK) || HAS_TFT
|
||||
#if defined(HELTEC_MESH_NODE_T114) || defined(HELTEC_VISION_MASTER_T190) || defined(T_DECK) || defined(T_LORA_PAGER) || HAS_TFT
|
||||
optionsArray[options] = "Screen Color";
|
||||
optionsEnumArray[options++] = ScreenColor;
|
||||
#endif
|
||||
|
|
|
@ -194,7 +194,7 @@ void UIRenderer::drawNodes(OLEDDisplay *display, int16_t x, int16_t y, const mes
|
|||
}
|
||||
|
||||
#if (defined(USE_EINK) || defined(ILI9341_DRIVER) || defined(ILI9342_DRIVER) || defined(ST7701_CS) || defined(ST7735_CS) || \
|
||||
defined(ST7789_CS) || defined(USE_ST7789) || defined(ILI9488_CS) || defined(HX8357_CS)) && \
|
||||
defined(ST7789_CS) || defined(USE_ST7789) || defined(ILI9488_CS) || defined(HX8357_CS) || defined(ST7796_CS)) && \
|
||||
!defined(DISPLAY_FORCE_SMALL_FONTS)
|
||||
|
||||
if (isHighResolution) {
|
||||
|
|
|
@ -27,7 +27,8 @@ const uint8_t bluetoothConnectedIcon[36] PROGMEM = {0xfe, 0x01, 0xff, 0x03, 0x03
|
|||
0xfe, 0x31, 0x00, 0x30, 0x30, 0x30, 0x30, 0x30, 0xf0, 0x3f, 0xe0, 0x1f};
|
||||
|
||||
#if (defined(USE_EINK) || defined(ILI9341_DRIVER) || defined(ILI9342_DRIVER) || defined(ST7701_CS) || defined(ST7735_CS) || \
|
||||
defined(ST7789_CS) || defined(USE_ST7789) || defined(HX8357_CS) || defined(ILI9488_CS) || ARCH_PORTDUINO) && \
|
||||
defined(ST7789_CS) || defined(USE_ST7789) || defined(HX8357_CS) || defined(ILI9488_CS) || defined(ST7796_CS) || \
|
||||
ARCH_PORTDUINO) && \
|
||||
!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};
|
||||
|
|
|
@ -0,0 +1,73 @@
|
|||
#ifdef T_LORA_PAGER
|
||||
|
||||
#include "RotaryEncoderImpl.h"
|
||||
#include "InputBroker.h"
|
||||
#include "RotaryEncoder.h"
|
||||
|
||||
#define ORIGIN_NAME "RotaryEncoder"
|
||||
|
||||
RotaryEncoderImpl *rotaryEncoderImpl;
|
||||
|
||||
RotaryEncoderImpl::RotaryEncoderImpl() : concurrency::OSThread(ORIGIN_NAME), originName(ORIGIN_NAME) {}
|
||||
|
||||
bool RotaryEncoderImpl::init()
|
||||
{
|
||||
if (!moduleConfig.canned_message.updown1_enabled || moduleConfig.canned_message.inputbroker_pin_a == 0 ||
|
||||
moduleConfig.canned_message.inputbroker_pin_b == 0) {
|
||||
// Input device is disabled.
|
||||
disable();
|
||||
return false;
|
||||
}
|
||||
|
||||
eventCw = static_cast<input_broker_event>(moduleConfig.canned_message.inputbroker_event_cw);
|
||||
eventCcw = static_cast<input_broker_event>(moduleConfig.canned_message.inputbroker_event_ccw);
|
||||
eventPressed = static_cast<input_broker_event>(moduleConfig.canned_message.inputbroker_event_press);
|
||||
|
||||
rotary = new RotaryEncoder(moduleConfig.canned_message.inputbroker_pin_a, moduleConfig.canned_message.inputbroker_pin_b,
|
||||
moduleConfig.canned_message.inputbroker_pin_press);
|
||||
rotary->resetButton();
|
||||
|
||||
inputBroker->registerSource(this);
|
||||
|
||||
LOG_INFO("RotaryEncoder initialized pins(%d, %d, %d), events(%d, %d, %d)", moduleConfig.canned_message.inputbroker_pin_a,
|
||||
moduleConfig.canned_message.inputbroker_pin_b, moduleConfig.canned_message.inputbroker_pin_press, eventCw, eventCcw,
|
||||
eventPressed);
|
||||
return true;
|
||||
}
|
||||
|
||||
int32_t RotaryEncoderImpl::runOnce()
|
||||
{
|
||||
InputEvent e;
|
||||
e.inputEvent = INPUT_BROKER_NONE;
|
||||
e.source = this->originName;
|
||||
|
||||
static uint32_t lastPressed = millis();
|
||||
if (rotary->readButton() == RotaryEncoder::ButtonState::BUTTON_PRESSED) {
|
||||
if (lastPressed + 200 < millis()) {
|
||||
LOG_DEBUG("Rotary event Press");
|
||||
lastPressed = millis();
|
||||
e.inputEvent = this->eventPressed;
|
||||
}
|
||||
} else {
|
||||
switch (rotary->process()) {
|
||||
case RotaryEncoder::DIRECTION_CW:
|
||||
LOG_DEBUG("Rotary event CW");
|
||||
e.inputEvent = this->eventCw;
|
||||
break;
|
||||
case RotaryEncoder::DIRECTION_CCW:
|
||||
LOG_DEBUG("Rotary event CCW");
|
||||
e.inputEvent = this->eventCcw;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (e.inputEvent != INPUT_BROKER_NONE) {
|
||||
this->notifyObservers(&e);
|
||||
}
|
||||
|
||||
return 20;
|
||||
}
|
||||
|
||||
#endif
|
|
@ -0,0 +1,28 @@
|
|||
#pragma once
|
||||
|
||||
// This is a non-interrupt version of RotaryEncoder which is based on a debounce inherent FSM table (see RotaryEncoder library)
|
||||
|
||||
#include "InputBroker.h"
|
||||
#include "concurrency/OSThread.h"
|
||||
#include "mesh/NodeDB.h"
|
||||
|
||||
class RotaryEncoder;
|
||||
|
||||
class RotaryEncoderImpl : public Observable<const InputEvent *>, public concurrency::OSThread
|
||||
{
|
||||
public:
|
||||
RotaryEncoderImpl();
|
||||
bool init(void);
|
||||
|
||||
protected:
|
||||
virtual int32_t runOnce() override;
|
||||
|
||||
input_broker_event eventCw = INPUT_BROKER_NONE;
|
||||
input_broker_event eventCcw = INPUT_BROKER_NONE;
|
||||
input_broker_event eventPressed = INPUT_BROKER_NONE;
|
||||
|
||||
RotaryEncoder *rotary;
|
||||
const char *originName;
|
||||
};
|
||||
|
||||
extern RotaryEncoderImpl *rotaryEncoderImpl;
|
|
@ -0,0 +1,230 @@
|
|||
#if defined(T_LORA_PAGER)
|
||||
|
||||
#include "TLoraPagerKeyboard.h"
|
||||
#include "main.h"
|
||||
|
||||
#ifndef LEDC_BACKLIGHT_CHANNEL
|
||||
#define LEDC_BACKLIGHT_CHANNEL 4
|
||||
#endif
|
||||
|
||||
#ifndef LEDC_BACKLIGHT_BIT_WIDTH
|
||||
#define LEDC_BACKLIGHT_BIT_WIDTH 8
|
||||
#endif
|
||||
|
||||
#ifndef LEDC_BACKLIGHT_FREQ
|
||||
#define LEDC_BACKLIGHT_FREQ 1000 // Hz
|
||||
#endif
|
||||
|
||||
#define _TCA8418_COLS 10
|
||||
#define _TCA8418_ROWS 4
|
||||
#define _TCA8418_NUM_KEYS 31
|
||||
|
||||
#define _TCA8418_MULTI_TAP_THRESHOLD 1500
|
||||
|
||||
using Key = TCA8418KeyboardBase::TCA8418Key;
|
||||
|
||||
constexpr uint8_t modifierRightShiftKey = 29 - 1; // keynum -1
|
||||
constexpr uint8_t modifierRightShift = 0b0001;
|
||||
constexpr uint8_t modifierSymKey = 21 - 1;
|
||||
constexpr uint8_t modifierSym = 0b0010;
|
||||
|
||||
// Num chars per key, Modulus for rotating through characters
|
||||
static uint8_t TLoraPagerTapMod[_TCA8418_NUM_KEYS] = {3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
|
||||
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3};
|
||||
|
||||
static unsigned char TLoraPagerTapMap[_TCA8418_NUM_KEYS][3] = {{'q', 'Q', '1'},
|
||||
{'w', 'W', '2'},
|
||||
{'e', 'E', '3'},
|
||||
{'r', 'R', '4'},
|
||||
{'t', 'T', '5'},
|
||||
{'y', 'Y', '6'},
|
||||
{'u', 'U', '7'},
|
||||
{'i', 'I', '8'},
|
||||
{'o', 'O', '9'},
|
||||
{'p', 'P', '0'},
|
||||
{'a', 'A', '*'},
|
||||
{'s', 'S', '/'},
|
||||
{'d', 'D', '+'},
|
||||
{'f', 'F', '-'},
|
||||
{'g', 'G', '='},
|
||||
{'h', 'H', ':'},
|
||||
{'j', 'J', '\''},
|
||||
{'k', 'K', '"'},
|
||||
{'l', 'L', '@'},
|
||||
{Key::SELECT, 0x00, Key::TAB},
|
||||
{0x00, 0x00, 0x00},
|
||||
{'z', 'Z', '_'},
|
||||
{'x', 'X', '$'},
|
||||
{'c', 'C', ';'},
|
||||
{'v', 'V', '?'},
|
||||
{'b', 'B', '!'},
|
||||
{'n', 'N', ','},
|
||||
{'m', 'M', '.'},
|
||||
{0x00, 0x00, 0x00},
|
||||
{Key::BSP, 0x00, Key::ESC},
|
||||
{' ', 0x00, Key::BL_TOGGLE}};
|
||||
|
||||
TLoraPagerKeyboard::TLoraPagerKeyboard()
|
||||
: TCA8418KeyboardBase(_TCA8418_ROWS, _TCA8418_COLS), modifierFlag(0), last_modifier_time(0), last_key(-1), next_key(-1),
|
||||
last_tap(0L), char_idx(0), tap_interval(0)
|
||||
{
|
||||
#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 0, 0)
|
||||
ledcAttach(KB_BL_PIN, LEDC_BACKLIGHT_FREQ, LEDC_BACKLIGHT_BIT_WIDTH);
|
||||
#else
|
||||
ledcSetup(LEDC_BACKLIGHT_CHANNEL, LEDC_BACKLIGHT_FREQ, LEDC_BACKLIGHT_BIT_WIDTH);
|
||||
ledcAttachPin(KB_BL_PIN, LEDC_BACKLIGHT_CHANNEL);
|
||||
#endif
|
||||
reset();
|
||||
}
|
||||
|
||||
void TLoraPagerKeyboard::reset(void)
|
||||
{
|
||||
TCA8418KeyboardBase::reset();
|
||||
pinMode(KB_BL_PIN, OUTPUT);
|
||||
digitalWrite(KB_BL_PIN, LOW);
|
||||
setBacklight(false);
|
||||
}
|
||||
|
||||
// handle multi-key presses (shift and alt)
|
||||
void TLoraPagerKeyboard::trigger()
|
||||
{
|
||||
uint8_t count = keyCount();
|
||||
if (count == 0)
|
||||
return;
|
||||
for (uint8_t i = 0; i < count; ++i) {
|
||||
uint8_t k = readRegister(TCA8418_REG_KEY_EVENT_A + i);
|
||||
uint8_t key = k & 0x7F;
|
||||
if (k & 0x80) {
|
||||
pressed(key);
|
||||
} else {
|
||||
released();
|
||||
state = Idle;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void TLoraPagerKeyboard::setBacklight(bool on)
|
||||
{
|
||||
toggleBacklight(!on);
|
||||
}
|
||||
|
||||
void TLoraPagerKeyboard::pressed(uint8_t key)
|
||||
{
|
||||
if (state == Init || state == Busy) {
|
||||
return;
|
||||
}
|
||||
if (config.device.buzzer_mode == meshtastic_Config_DeviceConfig_BuzzerMode_ALL_ENABLED ||
|
||||
config.device.buzzer_mode == meshtastic_Config_DeviceConfig_BuzzerMode_SYSTEM_ONLY) {
|
||||
hapticFeedback();
|
||||
}
|
||||
|
||||
if (modifierFlag && (millis() - last_modifier_time > _TCA8418_MULTI_TAP_THRESHOLD)) {
|
||||
modifierFlag = 0;
|
||||
}
|
||||
|
||||
uint8_t next_key = 0;
|
||||
int row = (key - 1) / 10;
|
||||
int col = (key - 1) % 10;
|
||||
|
||||
if (row >= _TCA8418_ROWS || col >= _TCA8418_COLS) {
|
||||
return; // Invalid key
|
||||
}
|
||||
|
||||
next_key = row * _TCA8418_COLS + col;
|
||||
state = Held;
|
||||
|
||||
uint32_t now = millis();
|
||||
tap_interval = now - last_tap;
|
||||
|
||||
updateModifierFlag(next_key);
|
||||
if (isModifierKey(next_key)) {
|
||||
last_modifier_time = now;
|
||||
}
|
||||
|
||||
if (tap_interval < 0) {
|
||||
last_tap = 0;
|
||||
state = Busy;
|
||||
return;
|
||||
}
|
||||
|
||||
if (next_key != last_key || tap_interval > _TCA8418_MULTI_TAP_THRESHOLD) {
|
||||
char_idx = 0;
|
||||
} else {
|
||||
char_idx += 1;
|
||||
}
|
||||
|
||||
last_key = next_key;
|
||||
last_tap = now;
|
||||
}
|
||||
|
||||
void TLoraPagerKeyboard::released()
|
||||
{
|
||||
if (state != Held) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (last_key < 0 || last_key >= _TCA8418_NUM_KEYS) {
|
||||
last_key = -1;
|
||||
state = Idle;
|
||||
return;
|
||||
}
|
||||
|
||||
uint32_t now = millis();
|
||||
last_tap = now;
|
||||
|
||||
if (TLoraPagerTapMap[last_key][modifierFlag % TLoraPagerTapMod[last_key]] == Key::BL_TOGGLE) {
|
||||
toggleBacklight();
|
||||
return;
|
||||
}
|
||||
|
||||
queueEvent(TLoraPagerTapMap[last_key][modifierFlag % TLoraPagerTapMod[last_key]]);
|
||||
if (isModifierKey(last_key) == false)
|
||||
modifierFlag = 0;
|
||||
}
|
||||
|
||||
void TLoraPagerKeyboard::hapticFeedback()
|
||||
{
|
||||
drv.setWaveform(0, 14); // strong buzz 100%
|
||||
drv.setWaveform(1, 0); // end waveform
|
||||
drv.go();
|
||||
}
|
||||
|
||||
// toggle brightness of the backlight in three steps
|
||||
void TLoraPagerKeyboard::toggleBacklight(bool off)
|
||||
{
|
||||
static uint32_t brightness = 0;
|
||||
if (off) {
|
||||
brightness = 0;
|
||||
} else {
|
||||
if (brightness == 0) {
|
||||
brightness = 40;
|
||||
} else if (brightness == 40) {
|
||||
brightness = 127;
|
||||
} else if (brightness >= 127) {
|
||||
brightness = 0;
|
||||
}
|
||||
}
|
||||
LOG_DEBUG("Toggle backlight: %d", brightness);
|
||||
|
||||
#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 0, 0)
|
||||
ledcWrite(KB_BL_PIN, brightness);
|
||||
#else
|
||||
ledcWrite(LEDC_BACKLIGHT_CHANNEL, brightness);
|
||||
#endif
|
||||
}
|
||||
|
||||
void TLoraPagerKeyboard::updateModifierFlag(uint8_t key)
|
||||
{
|
||||
if (key == modifierRightShiftKey) {
|
||||
modifierFlag ^= modifierRightShift;
|
||||
} else if (key == modifierSymKey) {
|
||||
modifierFlag ^= modifierSym;
|
||||
}
|
||||
}
|
||||
|
||||
bool TLoraPagerKeyboard::isModifierKey(uint8_t key)
|
||||
{
|
||||
return (key == modifierRightShiftKey || key == modifierSymKey);
|
||||
}
|
||||
|
||||
#endif
|
|
@ -4,9 +4,26 @@ class TLoraPagerKeyboard : public TCA8418KeyboardBase
|
|||
{
|
||||
public:
|
||||
TLoraPagerKeyboard();
|
||||
void setBacklight(bool on) override{};
|
||||
void reset(void);
|
||||
void trigger(void) override;
|
||||
void setBacklight(bool on) override;
|
||||
virtual ~TLoraPagerKeyboard() {}
|
||||
|
||||
protected:
|
||||
void pressed(uint8_t key) override{};
|
||||
void released(void) override{};
|
||||
void pressed(uint8_t key) override;
|
||||
void released(void) override;
|
||||
void hapticFeedback(void);
|
||||
|
||||
void updateModifierFlag(uint8_t key);
|
||||
bool isModifierKey(uint8_t key);
|
||||
void toggleBacklight(bool off = false);
|
||||
|
||||
private:
|
||||
uint8_t modifierFlag; // Flag to indicate if a modifier key is pressed
|
||||
uint32_t last_modifier_time; // Timestamp of the last modifier key press
|
||||
int8_t last_key;
|
||||
int8_t next_key;
|
||||
uint32_t last_tap;
|
||||
uint8_t char_idx;
|
||||
int32_t tap_interval;
|
||||
};
|
||||
|
|
|
@ -12,8 +12,8 @@ void CardKbI2cImpl::init()
|
|||
#if !MESHTASTIC_EXCLUDE_I2C && !defined(ARCH_PORTDUINO) && !defined(I2C_NO_RESCAN)
|
||||
if (cardkb_found.address == 0x00) {
|
||||
LOG_DEBUG("Rescan for I2C keyboard");
|
||||
uint8_t i2caddr_scan[] = {CARDKB_ADDR, TDECK_KB_ADDR, BBQ10_KB_ADDR, MPR121_KB_ADDR, XPOWERS_AXP192_AXP2101_ADDRESS};
|
||||
uint8_t i2caddr_asize = 5;
|
||||
uint8_t i2caddr_scan[] = {CARDKB_ADDR, TDECK_KB_ADDR, BBQ10_KB_ADDR, MPR121_KB_ADDR, TCA8418_KB_ADDR};
|
||||
uint8_t i2caddr_asize = sizeof(i2caddr_scan) / sizeof(i2caddr_scan[0]);
|
||||
auto i2cScanner = std::unique_ptr<ScanI2CTwoWire>(new ScanI2CTwoWire());
|
||||
|
||||
#if WIRE_INTERFACES_COUNT == 2
|
||||
|
|
37
src/main.cpp
37
src/main.cpp
|
@ -135,8 +135,9 @@ AccelerometerThread *accelerometerThread = nullptr;
|
|||
AudioThread *audioThread = nullptr;
|
||||
#endif
|
||||
|
||||
#ifdef USE_PCA9557
|
||||
PCA9557 IOEXP;
|
||||
#ifdef USE_XL9555
|
||||
#include "ExtensionIOXL9555.hpp"
|
||||
ExtensionIOXL9555 io;
|
||||
#endif
|
||||
|
||||
#if HAS_TFT
|
||||
|
@ -201,7 +202,7 @@ ScanI2C::FoundDevice rgb_found = ScanI2C::FoundDevice(ScanI2C::DeviceType::NONE,
|
|||
/// The I2C address of our Air Quality Indicator (if found)
|
||||
ScanI2C::DeviceAddress aqi_found = ScanI2C::ADDRESS_NONE;
|
||||
|
||||
#ifdef T_WATCH_S3
|
||||
#if defined(T_WATCH_S3) || defined(T_LORA_PAGER)
|
||||
Adafruit_DRV2605 drv;
|
||||
#endif
|
||||
|
||||
|
@ -359,6 +360,30 @@ void setup()
|
|||
digitalWrite(SDCARD_CS, HIGH);
|
||||
pinMode(PIN_EINK_CS, OUTPUT);
|
||||
digitalWrite(PIN_EINK_CS, HIGH);
|
||||
#elif defined(T_LORA_PAGER)
|
||||
pinMode(LORA_CS, OUTPUT);
|
||||
digitalWrite(LORA_CS, HIGH);
|
||||
pinMode(SDCARD_CS, OUTPUT);
|
||||
digitalWrite(SDCARD_CS, HIGH);
|
||||
pinMode(TFT_CS, OUTPUT);
|
||||
digitalWrite(TFT_CS, HIGH);
|
||||
// io expander
|
||||
io.begin(Wire, XL9555_SLAVE_ADDRESS0, SDA, SCL);
|
||||
io.pinMode(EXPANDS_DRV_EN, OUTPUT);
|
||||
io.digitalWrite(EXPANDS_DRV_EN, HIGH);
|
||||
io.pinMode(EXPANDS_AMP_EN, OUTPUT);
|
||||
io.digitalWrite(EXPANDS_AMP_EN, HIGH);
|
||||
io.pinMode(EXPANDS_LORA_EN, OUTPUT);
|
||||
io.digitalWrite(EXPANDS_LORA_EN, HIGH);
|
||||
io.pinMode(EXPANDS_GPS_EN, OUTPUT);
|
||||
io.digitalWrite(EXPANDS_GPS_EN, HIGH);
|
||||
io.pinMode(EXPANDS_KB_EN, OUTPUT);
|
||||
io.digitalWrite(EXPANDS_KB_EN, HIGH);
|
||||
io.pinMode(EXPANDS_SD_EN, OUTPUT);
|
||||
io.digitalWrite(EXPANDS_SD_EN, HIGH);
|
||||
io.pinMode(EXPANDS_GPIO_EN, OUTPUT);
|
||||
io.digitalWrite(EXPANDS_GPIO_EN, HIGH);
|
||||
io.pinMode(EXPANDS_SD_PULLEN, INPUT);
|
||||
#endif
|
||||
|
||||
concurrency::hasBeenSetup = true;
|
||||
|
@ -805,7 +830,7 @@ void setup()
|
|||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef T_WATCH_S3
|
||||
#if defined(T_WATCH_S3) || defined(T_LORA_PAGER)
|
||||
drv.begin();
|
||||
drv.selectLibrary(1);
|
||||
// I2C trigger by sending 'go' command
|
||||
|
@ -851,7 +876,7 @@ void setup()
|
|||
if (config.display.displaymode != meshtastic_Config_DisplayConfig_DisplayMode_COLOR) {
|
||||
|
||||
#if defined(ST7701_CS) || defined(ST7735_CS) || defined(USE_EINK) || defined(ILI9341_DRIVER) || defined(ILI9342_DRIVER) || \
|
||||
defined(ST7789_CS) || defined(HX8357_CS) || defined(USE_ST7789) || defined(ILI9488_CS)
|
||||
defined(ST7789_CS) || defined(HX8357_CS) || defined(USE_ST7789) || defined(ILI9488_CS) || defined(ST7796_CS)
|
||||
screen = new graphics::Screen(screen_found, screen_model, screen_geometry);
|
||||
#elif defined(ARCH_PORTDUINO)
|
||||
if ((screen_found.port != ScanI2C::I2CPort::NO_I2C || settingsMap[displayPanel]) &&
|
||||
|
@ -1114,7 +1139,7 @@ void setup()
|
|||
// Don't call screen setup until after nodedb is setup (because we need
|
||||
// the current region name)
|
||||
#if defined(ST7701_CS) || defined(ST7735_CS) || defined(USE_EINK) || defined(ILI9341_DRIVER) || defined(ILI9342_DRIVER) || \
|
||||
defined(ST7789_CS) || defined(HX8357_CS) || defined(USE_ST7789) || defined(ILI9488_CS)
|
||||
defined(ST7789_CS) || defined(HX8357_CS) || defined(USE_ST7789) || defined(ILI9488_CS) || defined(ST7796_CS)
|
||||
if (screen)
|
||||
screen->setup();
|
||||
#elif defined(ARCH_PORTDUINO)
|
||||
|
|
|
@ -41,7 +41,7 @@ extern bool eink_found;
|
|||
extern bool pmu_found;
|
||||
extern bool isUSBPowered;
|
||||
|
||||
#ifdef T_WATCH_S3
|
||||
#if defined(T_WATCH_S3) || defined(T_LORA_PAGER)
|
||||
#include <Adafruit_DRV2605.h>
|
||||
extern Adafruit_DRV2605 drv;
|
||||
#endif
|
||||
|
|
|
@ -663,7 +663,7 @@ void NodeDB::installDefaultConfig(bool preserveKey = false)
|
|||
config.bluetooth.fixed_pin = defaultBLEPin;
|
||||
|
||||
#if defined(ST7735_CS) || defined(USE_EINK) || defined(ILI9341_DRIVER) || defined(ILI9342_DRIVER) || defined(ST7789_CS) || \
|
||||
defined(HX8357_CS) || defined(USE_ST7789) || defined(ILI9488_CS)
|
||||
defined(HX8357_CS) || defined(USE_ST7789) || defined(ILI9488_CS) || defined(ST7796_CS)
|
||||
bool hasScreen = true;
|
||||
#ifdef HELTEC_MESH_NODE_T114
|
||||
uint32_t st7789_id = get_st7789_id(ST7789_NSS, ST7789_SCK, ST7789_SDA, ST7789_RS, ST7789_RESET);
|
||||
|
@ -830,6 +830,15 @@ void NodeDB::installDefaultModuleConfig()
|
|||
moduleConfig.external_notification.alert_message = true;
|
||||
moduleConfig.external_notification.output_ms = 1000;
|
||||
moduleConfig.external_notification.nag_timeout = 60;
|
||||
#endif
|
||||
#ifdef T_LORA_PAGER
|
||||
moduleConfig.canned_message.updown1_enabled = true;
|
||||
moduleConfig.canned_message.inputbroker_pin_a = ROTARY_A;
|
||||
moduleConfig.canned_message.inputbroker_pin_b = ROTARY_B;
|
||||
moduleConfig.canned_message.inputbroker_pin_press = ROTARY_PRESS;
|
||||
moduleConfig.canned_message.inputbroker_event_cw = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar(28);
|
||||
moduleConfig.canned_message.inputbroker_event_ccw = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar(29);
|
||||
moduleConfig.canned_message.inputbroker_event_press = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_SELECT;
|
||||
#endif
|
||||
moduleConfig.has_canned_message = true;
|
||||
#if USERPREFS_MQTT_ENABLED && !MESHTASTIC_EXCLUDE_MQTT
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
#include "buzz/BuzzerFeedbackThread.h"
|
||||
#include "input/ExpressLRSFiveWay.h"
|
||||
#include "input/InputBroker.h"
|
||||
#include "input/RotaryEncoderImpl.h"
|
||||
#include "input/RotaryEncoderInterruptImpl1.h"
|
||||
#include "input/SerialKeyboardImpl.h"
|
||||
#include "input/TrackballInterruptImpl1.h"
|
||||
|
@ -170,11 +171,20 @@ void setupModules()
|
|||
delete rotaryEncoderInterruptImpl1;
|
||||
rotaryEncoderInterruptImpl1 = nullptr;
|
||||
}
|
||||
#ifdef T_LORA_PAGER
|
||||
// use a special FSM based rotary encoder version for T-LoRa Pager
|
||||
rotaryEncoderImpl = new RotaryEncoderImpl();
|
||||
if (!rotaryEncoderImpl->init()) {
|
||||
delete rotaryEncoderImpl;
|
||||
rotaryEncoderImpl = nullptr;
|
||||
}
|
||||
#else
|
||||
upDownInterruptImpl1 = new UpDownInterruptImpl1();
|
||||
if (!upDownInterruptImpl1->init()) {
|
||||
delete upDownInterruptImpl1;
|
||||
upDownInterruptImpl1 = nullptr;
|
||||
}
|
||||
#endif
|
||||
cardKbI2cImpl = new CardKbI2cImpl();
|
||||
cardKbI2cImpl->init();
|
||||
#ifdef INPUTBROKER_MATRIX_TYPE
|
||||
|
|
|
@ -192,6 +192,8 @@
|
|||
#define HW_VENDOR meshtastic_HardwareModel_LINK_32
|
||||
#elif defined(T_DECK_PRO)
|
||||
#define HW_VENDOR meshtastic_HardwareModel_T_DECK_PRO
|
||||
#elif defined(T_LORA_PAGER)
|
||||
#define HW_VENDOR meshtastic_HardwareModel_T_LORA_PAGER
|
||||
#endif
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
|
|
@ -0,0 +1,27 @@
|
|||
#include "configuration.h"
|
||||
|
||||
#ifdef T_LORA_PAGER
|
||||
|
||||
#include "AudioBoard.h"
|
||||
|
||||
DriverPins PinsAudioBoardES8311;
|
||||
AudioBoard board(AudioDriverES8311, PinsAudioBoardES8311);
|
||||
|
||||
// TLora Pager specific init
|
||||
void lateInitVariant()
|
||||
{
|
||||
// AudioDriverLogger.begin(Serial, AudioDriverLogLevel::Debug);
|
||||
// I2C: function, scl, sda
|
||||
PinsAudioBoardES8311.addI2C(PinFunction::CODEC, Wire);
|
||||
// I2S: function, mclk, bck, ws, data_out, data_in
|
||||
PinsAudioBoardES8311.addI2S(PinFunction::CODEC, DAC_I2S_MCLK, DAC_I2S_BCK, DAC_I2S_WS, DAC_I2S_DOUT, DAC_I2S_DIN);
|
||||
|
||||
// configure codec
|
||||
CodecConfig cfg;
|
||||
cfg.input_device = ADC_INPUT_LINE1;
|
||||
cfg.output_device = DAC_OUTPUT_ALL;
|
||||
cfg.i2s.bits = BIT_LENGTH_16BITS;
|
||||
cfg.i2s.rate = RATE_44K;
|
||||
board.begin(cfg);
|
||||
}
|
||||
#endif
|
|
@ -0,0 +1,19 @@
|
|||
#ifndef Pins_Arduino_h
|
||||
#define Pins_Arduino_h
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#define USB_VID 0x303a
|
||||
#define USB_PID 0x1001
|
||||
|
||||
// used for keyboard, battery gauge, charger and haptic driver
|
||||
static const uint8_t SDA = 3;
|
||||
static const uint8_t SCL = 2;
|
||||
|
||||
// Default SPI will be mapped to Radio
|
||||
static const uint8_t SS = 36;
|
||||
static const uint8_t MOSI = 34;
|
||||
static const uint8_t MISO = 33;
|
||||
static const uint8_t SCK = 35;
|
||||
|
||||
#endif /* Pins_Arduino_h */
|
|
@ -0,0 +1,70 @@
|
|||
; LilyGo T-Lora-Pager
|
||||
[env:tlora-pager]
|
||||
extends = esp32s3_base
|
||||
board = t-deck-pro ; same as T-Deck Pro
|
||||
board_check = true
|
||||
board_build.partitions = default_16MB.csv
|
||||
upload_protocol = esptool
|
||||
|
||||
build_flags = ${esp32s3_base.build_flags}
|
||||
-I variants/esp32s3/tlora-pager
|
||||
-D T_LORA_PAGER
|
||||
-D BOARD_HAS_PSRAM
|
||||
-D GPS_POWER_TOGGLE
|
||||
-D HAS_SDCARD
|
||||
-D SDCARD_USE_SPI1
|
||||
-D ENABLE_ROTARY_PULLUP
|
||||
-D ENABLE_BUTTON_PULLUP
|
||||
-D HALF_STEP
|
||||
|
||||
lib_deps = ${esp32s3_base.lib_deps}
|
||||
lovyan03/LovyanGFX@1.2.7
|
||||
earlephilhower/ESP8266Audio@1.9.9
|
||||
earlephilhower/ESP8266SAM@1.0.1
|
||||
adafruit/Adafruit DRV2605 Library@1.2.4
|
||||
lewisxhe/PCF8563_Library@1.0.1
|
||||
lewisxhe/SensorLib@0.3.1
|
||||
https://github.com/pschatzmann/arduino-audio-driver/archive/refs/tags/v0.1.3.zip
|
||||
https://github.com/mverch67/BQ27220/archive/07d92be846abd8a0258a50c23198dac0858b22ed.zip
|
||||
https://github.com/mverch67/RotaryEncoder
|
||||
|
||||
[env:tlora-pager-tft]
|
||||
extends = env:tlora-pager
|
||||
build_flags =
|
||||
${env:tlora-pager.build_flags}
|
||||
-D CONFIG_DISABLE_HAL_LOCKS=1
|
||||
-D INPUTDRIVER_ROTARY_TYPE=1
|
||||
-D INPUTDRIVER_ROTARY_UP=40
|
||||
-D INPUTDRIVER_ROTARY_DOWN=41
|
||||
-D INPUTDRIVER_ROTARY_BTN=7
|
||||
-D INPUTDRIVER_BUTTON_TYPE=0
|
||||
-D HAS_SCREEN=1
|
||||
-D HAS_TFT=1
|
||||
-D USE_I2S_BUZZER
|
||||
-D RAM_SIZE=5120
|
||||
-D LV_LVGL_H_INCLUDE_SIMPLE
|
||||
-D LV_CONF_INCLUDE_SIMPLE
|
||||
-D LV_COMP_CONF_INCLUDE_SIMPLE
|
||||
-D LV_USE_SYSMON=0
|
||||
-D LV_USE_PROFILER=0
|
||||
-D LV_USE_PERF_MONITOR=0
|
||||
-D LV_USE_MEM_MONITOR=0
|
||||
-D LV_USE_LOG=0
|
||||
-D USE_LOG_DEBUG
|
||||
-D LOG_DEBUG_INC=\"DebugConfiguration.h\"
|
||||
-D RADIOLIB_SPI_PARANOID=0
|
||||
-D LGFX_SCREEN_WIDTH=222
|
||||
-D LGFX_SCREEN_HEIGHT=480
|
||||
-D DISPLAY_SIZE=480x222 ; landscape mode
|
||||
-D DISPLAY_SET_RESOLUTION
|
||||
-D LGFX_DRIVER=LGFX_TLORA_PAGER
|
||||
-D GFX_DRIVER_INC=\"graphics/LGFX/LGFX_T_LORA_PAGER.h\"
|
||||
; -D LVGL_DRIVER=LVGL_T_LORA_PAGER
|
||||
; -D LV_USE_ST7796=1
|
||||
-D VIEW_480x222
|
||||
-D USE_PACKET_API
|
||||
-D MAP_FULL_REDRAW
|
||||
|
||||
lib_deps =
|
||||
${env:tlora-pager.lib_deps}
|
||||
${device-ui_base.lib_deps}
|
|
@ -0,0 +1,125 @@
|
|||
// ST7796 TFT LCD
|
||||
#define TFT_CS 38
|
||||
#define ST7796_CS TFT_CS
|
||||
#define ST7796_RS 37 // DC
|
||||
#define ST7796_SDA MOSI // MOSI
|
||||
#define ST7796_SCK SCK
|
||||
#define ST7796_RESET -1
|
||||
#define ST7796_MISO MISO
|
||||
#define ST7796_BUSY -1
|
||||
#define ST7796_BL 42
|
||||
#define ST7796_SPI_HOST SPI2_HOST
|
||||
#define TFT_BL 42
|
||||
#define SPI_FREQUENCY 75000000
|
||||
#define SPI_READ_FREQUENCY 16000000
|
||||
#define TFT_HEIGHT 480
|
||||
#define TFT_WIDTH 222
|
||||
#define TFT_OFFSET_X 49
|
||||
#define TFT_OFFSET_Y 0
|
||||
#define TFT_OFFSET_ROTATION 3
|
||||
#define SCREEN_ROTATE
|
||||
#define SCREEN_TRANSITION_FRAMERATE 5
|
||||
#define BRIGHTNESS_DEFAULT 130 // Medium Low Brightness
|
||||
|
||||
#define I2C_SDA SDA
|
||||
#define I2C_SCL SCL
|
||||
|
||||
#define USE_POWERSAVE
|
||||
#define SLEEP_TIME 120
|
||||
|
||||
// GNNS
|
||||
#define HAS_GPS 1
|
||||
#define GPS_BAUDRATE 38400
|
||||
#define GPS_RX_PIN 4
|
||||
#define GPS_TX_PIN 12
|
||||
#define PIN_GPS_PPS 13
|
||||
|
||||
// PCF8563 RTC Module
|
||||
#if __has_include("pcf8563.h")
|
||||
#include "pcf8563.h"
|
||||
#endif
|
||||
#define PCF8563_RTC 0x51
|
||||
#define HAS_RTC 1
|
||||
|
||||
// Rotary
|
||||
#define ROTARY_A (40)
|
||||
#define ROTARY_B (41)
|
||||
#define ROTARY_PRESS (7)
|
||||
|
||||
#define BUTTON_PIN 0
|
||||
|
||||
// SPI interface SD card slot
|
||||
#define SPI_MOSI MOSI
|
||||
#define SPI_SCK SCK
|
||||
#define SPI_MISO MISO
|
||||
#define SPI_CS 21
|
||||
#define SDCARD_CS SPI_CS
|
||||
#define SD_SPI_FREQUENCY 75000000U
|
||||
|
||||
// TCA8418 keyboard
|
||||
#define I2C_NO_RESCAN
|
||||
#define KB_BL_PIN 46
|
||||
#define KB_INT 6
|
||||
#define CANNED_MESSAGE_MODULE_ENABLE 1
|
||||
|
||||
// audio codec ES8311
|
||||
#define HAS_I2S
|
||||
#define DAC_I2S_BCK 11
|
||||
#define DAC_I2S_WS 18
|
||||
#define DAC_I2S_DOUT 45
|
||||
#define DAC_I2S_DIN 17
|
||||
#define DAC_I2S_MCLK 10
|
||||
|
||||
// gyroscope BHI260AP
|
||||
#define HAS_BHI260AP
|
||||
|
||||
// battery charger BQ25896
|
||||
#define HAS_PPM 1
|
||||
#define XPOWERS_CHIP_BQ25896
|
||||
|
||||
// battery quality management BQ27220
|
||||
#define HAS_BQ27220 1
|
||||
#define BQ27220_I2C_SDA SDA
|
||||
#define BQ27220_I2C_SCL SCL
|
||||
#define BQ27220_DESIGN_CAPACITY 1500
|
||||
|
||||
// NFC ST25R3916
|
||||
#define NFC_INT 5
|
||||
#define NFC_CS 39
|
||||
|
||||
// External expansion chip XL9555
|
||||
#define USE_XL9555
|
||||
#define EXPANDS_DRV_EN (0)
|
||||
#define EXPANDS_AMP_EN (1)
|
||||
#define EXPANDS_KB_RST (2)
|
||||
#define EXPANDS_LORA_EN (3)
|
||||
#define EXPANDS_GPS_EN (4)
|
||||
#define EXPANDS_NFC_EN (5)
|
||||
#define EXPANDS_GPS_RST (7)
|
||||
#define EXPANDS_KB_EN (8)
|
||||
#define EXPANDS_GPIO_EN (9)
|
||||
#define EXPANDS_SD_DET (10)
|
||||
#define EXPANDS_SD_PULLEN (11)
|
||||
#define EXPANDS_SD_EN (12)
|
||||
|
||||
// LoRa
|
||||
#define USE_SX1262
|
||||
#define USE_SX1268
|
||||
|
||||
#define LORA_SCK 35
|
||||
#define LORA_MISO 33
|
||||
#define LORA_MOSI 34
|
||||
#define LORA_CS 36
|
||||
|
||||
#define LORA_DIO0 -1 // a No connect on the SX1262 module
|
||||
#define LORA_RESET 47
|
||||
#define LORA_DIO1 14 // SX1262 IRQ
|
||||
#define LORA_DIO2 48 // SX1262 BUSY
|
||||
#define LORA_DIO3 // Not connected on PCB, but internally on the TTGO SX1262, if DIO3 is high the TXCO is enabled
|
||||
|
||||
#define SX126X_CS LORA_CS
|
||||
#define SX126X_DIO1 LORA_DIO1
|
||||
#define SX126X_BUSY LORA_DIO2
|
||||
#define SX126X_RESET LORA_RESET
|
||||
#define SX126X_DIO2_AS_RF_SWITCH
|
||||
#define SX126X_DIO3_TCXO_VOLTAGE 3.0
|
Ładowanie…
Reference in New Issue