Compare commits

...

10 Commits

Author SHA1 Message Date
TSAO
575178d4ac
Merge 4d9dbce55f into 8a8f60d129 2025-09-02 19:42:06 -05:00
github-actions[bot]
8a8f60d129
Update protobufs (#7831)
Some checks are pending
CI / build-rp2040 (push) Blocked by required conditions
CI / build-rp2350 (push) Blocked by required conditions
CI / build-stm32 (push) Blocked by required conditions
CI / build-debian-src (push) Waiting to run
CI / package-pio-deps-native-tft (push) Waiting to run
CI / test-native (push) Waiting to run
CI / docker-deb-amd64 (push) Waiting to run
CI / docker-deb-amd64-tft (push) Waiting to run
CI / docker-alp-amd64 (push) Waiting to run
CI / docker-alp-amd64-tft (push) Waiting to run
CI / docker-deb-arm64 (push) Waiting to run
CI / docker-deb-armv7 (push) Waiting to run
CI / gather-artifacts (esp32) (push) Blocked by required conditions
CI / gather-artifacts (esp32c3) (push) Blocked by required conditions
CI / gather-artifacts (esp32c6) (push) Blocked by required conditions
CI / gather-artifacts (esp32s3) (push) Blocked by required conditions
CI / gather-artifacts (nrf52840) (push) Blocked by required conditions
CI / gather-artifacts (rp2040) (push) Blocked by required conditions
CI / gather-artifacts (rp2350) (push) Blocked by required conditions
CI / gather-artifacts (stm32) (push) Blocked by required conditions
CI / release-artifacts (push) Blocked by required conditions
CI / release-firmware (esp32) (push) Blocked by required conditions
CI / release-firmware (esp32c3) (push) Blocked by required conditions
CI / release-firmware (esp32c6) (push) Blocked by required conditions
CI / release-firmware (esp32s3) (push) Blocked by required conditions
CI / release-firmware (nrf52840) (push) Blocked by required conditions
CI / release-firmware (rp2040) (push) Blocked by required conditions
CI / release-firmware (rp2350) (push) Blocked by required conditions
CI / release-firmware (stm32) (push) Blocked by required conditions
CI / publish-firmware (push) Blocked by required conditions
Co-authored-by: thebentern <9000580+thebentern@users.noreply.github.com>
2025-09-02 19:08:05 -05:00
renovate[bot]
b59409bec0
chore(deps): update caveman99-stm32-crypto digest to 1aa30eb (#7808)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-09-02 18:01:31 -05:00
renovate[bot]
c66125114f
chore(deps): update meshtastic/device-ui digest to 8019704 (#7830)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-09-02 16:17:00 -05:00
renovate[bot]
edb7ec58c6
chore(deps): update platform-native digest to c490bcd (#7814)
Some checks are pending
CI / build-rp2040 (push) Blocked by required conditions
CI / build-rp2350 (push) Blocked by required conditions
CI / build-stm32 (push) Blocked by required conditions
CI / build-debian-src (push) Waiting to run
CI / package-pio-deps-native-tft (push) Waiting to run
CI / test-native (push) Waiting to run
CI / docker-deb-amd64 (push) Waiting to run
CI / docker-deb-amd64-tft (push) Waiting to run
CI / docker-alp-amd64 (push) Waiting to run
CI / docker-alp-amd64-tft (push) Waiting to run
CI / docker-deb-arm64 (push) Waiting to run
CI / docker-deb-armv7 (push) Waiting to run
CI / gather-artifacts (esp32) (push) Blocked by required conditions
CI / gather-artifacts (esp32c3) (push) Blocked by required conditions
CI / gather-artifacts (esp32c6) (push) Blocked by required conditions
CI / gather-artifacts (esp32s3) (push) Blocked by required conditions
CI / gather-artifacts (nrf52840) (push) Blocked by required conditions
CI / gather-artifacts (rp2040) (push) Blocked by required conditions
CI / gather-artifacts (rp2350) (push) Blocked by required conditions
CI / gather-artifacts (stm32) (push) Blocked by required conditions
CI / release-artifacts (push) Blocked by required conditions
CI / release-firmware (esp32) (push) Blocked by required conditions
CI / release-firmware (esp32c3) (push) Blocked by required conditions
CI / release-firmware (esp32c6) (push) Blocked by required conditions
CI / release-firmware (esp32s3) (push) Blocked by required conditions
CI / release-firmware (nrf52840) (push) Blocked by required conditions
CI / release-firmware (rp2040) (push) Blocked by required conditions
CI / release-firmware (rp2350) (push) Blocked by required conditions
CI / release-firmware (stm32) (push) Blocked by required conditions
CI / publish-firmware (push) Blocked by required conditions
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-09-02 11:58:57 -05:00
Ben Meadors
655c6b51fe
Try-fix Cardkb detection (#7825)
* Try-fix: CardKB detection regression

* Correct macro
2025-09-02 09:50:15 -05:00
Chloe Bethel
0bd4cefad3 Make ExternalNotification show up in excluded_modules, more STM32 modules (#7797)
* Show ExternalNotification as excluded if it is

* Enable ExternalNotification, SerialModule and RangeTest on STM32WL

* Misc fixes for #7797 - ARCH_STM32 -> ARCH_STM32WL, use less flash by dropping weather station support for serialmodule, set tx/rx pins before begin

* Enable Serial1 on RAK3172, make SerialModule use it (console is on LPUART1)

* Fix SerialModule on RAK3172, fix board definition of RAK3172 to include the right pin mapping.
2025-09-02 07:09:15 -05:00
github-actions[bot]
9b1fb795d7
Upgrade trunk (#7822)
Co-authored-by: vidplace7 <1779290+vidplace7@users.noreply.github.com>
2025-09-02 06:41:48 -05:00
Tom Fifield
3040e5a7bb Fix GPS that hard code 2080 as the start time. (#7803)
* Fix GPS that hard code 2080 as the start time.

Some GPS chips, such as the AG3335 in T1000e and L96 have a hardcoded
time of 2080-01-05 when they start up.

To fix that in a way that seems permanent, let's ignore times that
are more than 40 years since the firmware was built. We should followup
in late 2039 to see if any changes are needed.

Reported-By: @b8b8

* Update src/gps/RTC.cpp

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Put FORTY_YEARS in header and use in both places.

* Restore Ben's nicer log lines.

---------

Co-authored-by: Ben Meadors <benmmeadors@gmail.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-09-02 06:41:26 -05:00
csrutil
4d9dbce55f feat: add virtual keyboard implementation for text input
- Implement VirtualKeyboard class with full keyboard functionality
- Support cursor navigation, text input, and special keys (DEL, SPACE, CAPS, OK)
- Compatible with both MESHCORE and MESHTASTIC display systems
- Include multi-language layout support (EN/CN keyboards)
- Add key press callback system for extensibility
- Handle caps lock toggle and text buffer management
2025-09-01 20:38:21 +08:00
21 changed files with 462 additions and 31 deletions

View File

@ -9,7 +9,7 @@ plugins:
lint:
enabled:
- checkov@3.2.467
- renovate@41.90.1
- renovate@41.91.3
- prettier@3.6.2
- trufflehog@3.90.5
- yamllint@1.37.1

View File

@ -2,7 +2,7 @@
[portduino_base]
platform =
# renovate: datasource=git-refs depName=platform-native packageName=https://github.com/meshtastic/platform-native gitBranch=develop
https://github.com/meshtastic/platform-native/archive/37d986499ce24511952d7146db72d667c6bdaff7.zip
https://github.com/meshtastic/platform-native/archive/c490bcd019e0658404088a61b96e653c9da22c45.zip
framework = arduino
build_src_filter =

View File

@ -50,7 +50,7 @@ lib_deps =
${radiolib_base.lib_deps}
# renovate: datasource=git-refs depName=caveman99-stm32-Crypto packageName=https://github.com/caveman99/Crypto gitBranch=main
https://github.com/caveman99/Crypto/archive/eae9c768054118a9399690f8af202853d1ae8516.zip
https://github.com/caveman99/Crypto/archive/1aa30eb536bd52a576fde6dfa393bf7349cf102d.zip
lib_ignore =
OneButton

View File

@ -5,7 +5,7 @@
},
"core": "stm32",
"cpu": "cortex-m4",
"extra_flags": "-DSTM32WLxx -DSTM32WLE5xx -DARDUINO_GENERIC_WLE5CCUX",
"extra_flags": "-DSTM32WLxx -DSTM32WLE5xx -DARDUINO_RAK3172_MODULE",
"f_cpu": "48000000L",
"mcu": "stm32wle5ccu",
"variant": "STM32WLxx/WL54CCU_WL55CCU_WLE4C(8-B-C)U_WLE5C(8-B-C)U",

View File

@ -118,7 +118,7 @@ lib_deps =
[device-ui_base]
lib_deps =
# renovate: datasource=git-refs depName=meshtastic/device-ui packageName=https://github.com/meshtastic/device-ui gitBranch=master
https://github.com/meshtastic/device-ui/archive/a3e0e1be372d069f47b4c19d718f5267251744d7.zip
https://github.com/meshtastic/device-ui/archive/8019704395b7539600d581330499208edcd80804.zip
; Common libs for environmental measurements in telemetry module
[environmental_base]

@ -1 +1 @@
Subproject commit 4c4427c4a73c86fed7dc8632188bb8be95349d81
Subproject commit 34f0c8115d95f9f4be6d600095428a03833ac98e

View File

@ -132,6 +132,10 @@ RTCSetResult perhapsSetRTC(RTCQuality q, const struct timeval *tv, bool forceUpd
if (tv->tv_sec < BUILD_EPOCH) {
LOG_WARN("Ignore time (%ld) before build epoch (%ld)!", printableEpoch, BUILD_EPOCH);
return RTCSetResultInvalidTime;
} else if (tv->tv_sec > (BUILD_EPOCH + FORTY_YEARS)) {
LOG_WARN("Ignore time (%ld) too far in the future (build epoch: %ld, max allowed: %ld)!", printableEpoch, BUILD_EPOCH,
BUILD_EPOCH + FORTY_YEARS);
return RTCSetResultInvalidTime;
}
#endif
@ -250,6 +254,10 @@ RTCSetResult perhapsSetRTC(RTCQuality q, struct tm &t)
if (tv.tv_sec < BUILD_EPOCH) {
LOG_WARN("Ignore time (%ld) before build epoch (%ld)!", printableEpoch, BUILD_EPOCH);
return RTCSetResultInvalidTime;
} else if (tv.tv_sec > (BUILD_EPOCH + FORTY_YEARS)) {
LOG_WARN("Ignore time (%ld) too far in the future (build epoch: %ld, max allowed: %ld)!", printableEpoch, BUILD_EPOCH,
BUILD_EPOCH + FORTY_YEARS);
return RTCSetResultInvalidTime;
}
#endif

View File

@ -55,3 +55,6 @@ time_t gm_mktime(struct tm *tm);
#define SEC_PER_DAY 86400
#define SEC_PER_HOUR 3600
#define SEC_PER_MIN 60
#ifdef BUILD_EPOCH
#define FORTY_YEARS (40UL * 365 * SEC_PER_DAY) // probably time to update your firmware
#endif

View File

@ -0,0 +1,285 @@
/*
* VirtualKeyboard.cpp
* Author TSAO (hey@tsao.dev) 2025
*/
#include "VirtualKeyboard.h"
#ifdef MESHCORE
#include "MeshCore.h"
#elif defined(MESHTASTIC)
#include "configuration.h"
#include "graphics/ScreenFonts.h"
#endif
#include <Arduino.h>
#include <string.h>
#ifdef MESHCORE
VirtualKeyboard::VirtualKeyboard(DisplayDriver *displayDriver, int startX, int startY, int keyboardWidth,
int keyboardHeight)
: display(displayDriver) {
#elif defined(MESHTASTIC)
VirtualKeyboard::VirtualKeyboard(OLEDDisplay *displayDriver, int startX, int startY, int keyboardWidth,
int keyboardHeight)
: display(displayDriver) {
#endif
memset(inputBuffer, 0, sizeof(inputBuffer));
bufferLength = 0;
this->startX = startX;
this->startY = startY;
this->keyboardWidth = keyboardWidth;
this->keyboardHeight = keyboardHeight;
}
void VirtualKeyboard::moveCursor(int deltaRow, int deltaColumn) {
cursorRow += deltaRow;
cursorColumn += deltaColumn;
// Handle column overflow/underflow with row wrapping
if (cursorColumn >= getCols()) {
cursorColumn = 0;
cursorRow++;
} else if (cursorColumn < 0) {
cursorColumn = getCols() - 1;
cursorRow--;
}
// Handle row overflow/underflow
if (cursorRow >= getRows()) {
cursorRow = 0;
} else if (cursorRow < 0) {
cursorRow = getRows() - 1;
}
}
void VirtualKeyboard::moveRight(int steps) {
moveCursor(0, steps);
}
void VirtualKeyboard::moveLeft(int steps) {
moveCursor(0, -steps);
}
void VirtualKeyboard::moveUp(int steps) {
moveCursor(-steps, 0);
}
void VirtualKeyboard::moveDown(int steps) {
moveCursor(steps, 0);
}
const char *VirtualKeyboard::getKeyText(int row, int column) {
const char *keyString = getKeyAt(row, column);
if (!keyString || strlen(keyString) == 0) {
return "";
}
// Handle caps lock for letters
if (capsLockEnabled && strlen(keyString) == 1 && keyString[0] >= 'a' && keyString[0] <= 'z') {
static char uppercaseKey[2];
uppercaseKey[0] = keyString[0] - 'a' + 'A';
uppercaseKey[1] = '\0';
return uppercaseKey;
}
return keyString;
}
const char *VirtualKeyboard::pressCurrentKey() {
const char *pressedKey = getKeyText(cursorRow, cursorColumn);
if (strcmp(pressedKey, "DEL") == 0) {
// Delete/Backspace
if (bufferLength > 0) {
bufferLength--;
inputBuffer[bufferLength] = '\0';
}
} else if (strcmp(pressedKey, "OK") == 0) {
// Enter - could trigger submission or new line
if (bufferLength < sizeof(inputBuffer) - 1) {
inputBuffer[bufferLength++] = '\n';
inputBuffer[bufferLength] = '\0';
}
} else if (strcmp(pressedKey, "SPACE") == 0) {
// Space
if (bufferLength < sizeof(inputBuffer) - 1) {
inputBuffer[bufferLength++] = ' ';
inputBuffer[bufferLength] = '\0';
}
} else if (strcmp(pressedKey, "CAPS") == 0) {
// Toggle caps lock
capsLockEnabled = !capsLockEnabled;
} else {
// Regular character
int keyLength = strlen(pressedKey);
if (bufferLength + keyLength < sizeof(inputBuffer) - 1) {
strcat(inputBuffer, pressedKey);
bufferLength += keyLength;
}
}
// Call user callback if one is set
if (keyPressCallback != nullptr) {
keyPressCallback(pressedKey, inputBuffer);
}
return pressedKey;
}
void VirtualKeyboard::clear() {
memset(inputBuffer, 0, sizeof(inputBuffer));
bufferLength = 0;
}
void VirtualKeyboard::reset() {
clear();
cursorRow = 0;
cursorColumn = 0;
}
void VirtualKeyboard::setKeyPressCallback(KeyPressCallback callback) {
keyPressCallback = callback;
}
void VirtualKeyboard::getTextBounds(const char *text, uint16_t *width, uint16_t *height) {
if (!display || !text) {
if (width) *width = 0;
if (height) *height = 0;
return;
}
#ifdef MESHCORE
Adafruit_SSD1306 *ssd1306Display = static_cast<Adafruit_SSD1306 *>(display->getDisplay());
if (ssd1306Display) {
int16_t x1, y1;
uint16_t w, h;
ssd1306Display->getTextBounds(text, 0, 0, &x1, &y1, &w, &h);
if (width) *width = w;
if (height) *height = h;
} else {
// Fallback if getDisplay() doesn't work
if (width) *width = display->getTextWidth(text);
if (height) *height = 8; // Default text height
}
#elif defined(MESHTASTIC)
if (width) *width = display->getStringWidth(text);
// FONT_SMALL is 7 by 🧐
if (height) *height = 7; // FONT_HEIGHT_SMALL;
#endif
}
void VirtualKeyboard::drawKeyboard() {
if (!display) return;
#ifdef MESHCORE
display->setTextSize(1);
#elif defined(MESHTASTIC)
display->setFont(FONT_SMALL);
// display->clear();
#endif
// Calculate max standard key width (kw)
uint16_t kw = 0;
for (int row = 0; row < getRows(); row++) {
for (int col = 0; col < getCols() - 1; col++) { // Exclude rightmost column (control keys)
uint16_t keyWidth = 0;
const char *keyText = getKeyText(row, col);
getTextBounds(keyText, &keyWidth, nullptr);
if (keyWidth > kw) {
kw = keyWidth;
}
}
}
// Calculate max control key width (cw)
uint16_t cw = 0;
for (int row = 0; row < getRows(); row++) {
int col = getCols() - 1; // Only check rightmost column
uint16_t keyWidth = 0;
const char *keyText = getKeyText(row, col);
getTextBounds(keyText, &keyWidth, nullptr);
if (keyWidth > cw) {
cw = keyWidth;
}
}
// Calculate horizontal spacing
uint16_t totalKeyWidth = (getCols() - 1) * kw + cw;
uint16_t spacingX = (keyboardWidth - totalKeyWidth) / (getCols() - 1);
uint16_t fraction = (keyboardWidth - totalKeyWidth) % (getCols() - 1);
// Calculate key height and vertical spacing
uint16_t keyH = 0;
getTextBounds(getKeyText(0, 0), nullptr, &keyH);
uint16_t spacingY = (keyboardHeight - getRows() * keyH) / (getRows() - 1);
#ifdef MESHTASTIC
spacingY = 2;
#endif
for (int row = 0; row < getRows(); row++) {
for (int col = 0; col < getCols(); col++) {
const char *label = getKeyText(row, col);
uint16_t currentKeyWidth = (col == getCols() - 1) ? cw : kw;
// Calculate x position dynamically
int currentX = startX + col * (kw + spacingX) + ((col == getCols() - 1) ? (cw - kw) : 0);
if (col == getCols() - 1) {
currentX = keyboardWidth - cw;
// currentX += fraction * (getCols() - 1);
}
// Calculate y position
int y = startY + row * keyH + row * spacingY;
// Check if this is the currently selected key
bool selected = (row == cursorRow && col == cursorColumn);
if (selected) {
// Highlight the selected key with inverted colors
#ifdef MESHCORE
display->setColor(DisplayDriver::LIGHT);
display->fillRect(currentX - 1, y - 1, currentKeyWidth + 2, keyH + 2);
display->setColor(DisplayDriver::DARK); // Dark text on light background
#elif defined(MESHTASTIC)
display->setColor(OLEDDISPLAY_COLOR::WHITE);
if (col == 0 && startX > 0) {
display->fillRect(currentX - 1, y + 2, currentKeyWidth + 1, keyH + 2);
} else {
display->fillRect(currentX - 2, y + 2, currentKeyWidth + 1, keyH + 2);
}
display->setColor(OLEDDISPLAY_COLOR::BLACK); // Dark text on light background
#endif
} else {
#ifdef MESHCORE
display->setColor(DisplayDriver::LIGHT); // Light text on dark background
#elif defined(MESHTASTIC)
display->setColor(OLEDDISPLAY_COLOR::WHITE); // Light text on dark background
#endif
}
// Draw the key text at the key position
#ifdef MESHCORE
display->setCursor(currentX, y);
display->print(label);
#elif defined(MESHTASTIC)
display->drawString(currentX, y, label);
#endif
}
}
// Reset text color to default
#ifdef MESHCORE
display->setColor(DisplayDriver::LIGHT);
#elif defined(MESHTASTIC)
display->setColor(OLEDDISPLAY_COLOR::WHITE);
#endif
}
void VirtualKeyboard::render() {
drawKeyboard();
}

View File

@ -0,0 +1,108 @@
/*
* VirtualKeyboard.h
* Author TSAO (hey@tsao.dev) 2025
*/
#pragma once
#ifdef MESHCORE
#include <Adafruit_SSD1306.h>
#include <helpers/ui/DisplayDriver.h>
#elif defined(MESHTASTIC)
#include "graphics/Screen.h"
#include <OLEDDisplay.h>
#endif
// Callback function type for key press events
typedef void (*KeyPressCallback)(const char *pressedKey, const char *currentText);
#ifdef VIRTUAL_KEYBOARD_EN
static const int VIRTUAL_KEYBOARD_ROWS = 4;
static const int VIRTUAL_KEYBOARD_COLS = 11;
static const char *keyboardLayout[VIRTUAL_KEYBOARD_ROWS][VIRTUAL_KEYBOARD_COLS] = {
{ "1", "2", "3", "4", "5", "6", "7", "8", "9", "0", "DEL" },
{ "q", "w", "e", "r", "t", "y", "u", "i", "o", "p", "OK" },
{ "a", "s", "d", "f", "g", "h", "j", "k", "l", ";", "SPACE" },
{ "z", "x", "c", "v", "b", "n", "m", ".", ",", "?", "CAPS" },
};
#endif
#ifdef VIRTUAL_KEYBOARD_CN
static const int VIRTUAL_KEYBOARD_ROWS = 4;
static const int VIRTUAL_KEYBOARD_COLS = 11;
static const char *keyboardLayout[VIRTUAL_KEYBOARD_ROWS][VIRTUAL_KEYBOARD_COLS] = {
{ "1", "2", "3", "4", "5", "6", "7", "8", "9", "0", "DEL" },
{ "q", "w", "e", "r", "t", "y", "u", "i", "o", "p", "OK" },
{ "a", "s", "d", "f", "g", "h", "j", "k", "l", ";", "SPACE" },
{ "z", "x", "c", "v", "b", "n", "m", ".", ",", "?", "EN/CN" },
};
#endif
class VirtualKeyboard {
private:
#ifdef MESHCORE
DisplayDriver *display;
#elif defined(MESHTASTIC)
OLEDDisplay *display;
#endif
int cursorRow = 0;
int cursorColumn = 0;
bool capsLockEnabled = false;
char inputBuffer[160];
int bufferLength = 0;
// Keyboard positioning and dimensions
int startX = 0;
int startY = 0;
int keyboardWidth = 0;
int keyboardHeight = 0;
// Callback function for key press events
KeyPressCallback keyPressCallback = nullptr;
void drawKeyboard();
const char *getKeyText(int row, int col);
public:
#ifdef MESHCORE
VirtualKeyboard(DisplayDriver *display, int startX = 0, int startY = 0, int keyboardWidth = 0,
int keyboardHeight = 0);
#elif defined(MESHTASTIC)
VirtualKeyboard(OLEDDisplay *display, int startX = 0, int startY = 0, int keyboardWidth = 0,
int keyboardHeight = 0);
#endif
void moveCursor(int deltaRow, int deltaColumn);
void moveRight(int steps = 1);
void moveLeft(int steps = 1);
void moveUp(int steps = 1);
void moveDown(int steps = 1);
const char *pressCurrentKey();
void clear();
void reset();
const char *getText() const { return inputBuffer; }
int getTextLength() const { return bufferLength; }
// Usage: kb.setKeyPressCallback([](const char* key, const char* text) { ... });
void setKeyPressCallback(KeyPressCallback callback);
void getTextBounds(const char *text, uint16_t *width, uint16_t *height);
void render();
int getRows() const { return VIRTUAL_KEYBOARD_ROWS; }
int getCols() const { return VIRTUAL_KEYBOARD_COLS; }
const char *getKeyAt(int row, int col) const {
if (row >= 0 && row < VIRTUAL_KEYBOARD_ROWS && col >= 0 && col < VIRTUAL_KEYBOARD_COLS) {
return keyboardLayout[row][col];
}
return "";
}
};

View File

@ -13,7 +13,11 @@ void CardKbI2cImpl::init()
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, TCA8418_KB_ADDR};
#if defined(T_LORA_PAGER)
uint8_t i2caddr_asize = sizeof(i2caddr_scan) / sizeof(i2caddr_scan[0]);
#else
uint8_t i2caddr_asize = 5;
#endif
auto i2cScanner = std::unique_ptr<ScanI2CTwoWire>(new ScanI2CTwoWire());
#if WIRE_INTERFACES_COUNT == 2

View File

@ -1525,7 +1525,7 @@ extern meshtastic_DeviceMetadata getDeviceMetadata()
#if ((!HAS_SCREEN || NO_EXT_GPIO) || MESHTASTIC_EXCLUDE_CANNEDMESSAGES) && !defined(MESHTASTIC_INCLUDE_NICHE_GRAPHICS)
deviceMetadata.excluded_modules |= meshtastic_ExcludedModules_CANNEDMSG_CONFIG;
#endif
#if NO_EXT_GPIO
#if NO_EXT_GPIO || MESHTASTIC_EXCLUDE_EXTERNALNOTIFICATION
deviceMetadata.excluded_modules |= meshtastic_ExcludedModules_EXTNOTIF_CONFIG;
#endif
// Only edge case here is if we apply this a device with built in Accelerometer and want to detect interrupts

View File

@ -360,7 +360,7 @@ extern const pb_msgdesc_t meshtastic_BackupPreferences_msg;
/* Maximum encoded size of messages (where known) */
/* meshtastic_NodeDatabase_size depends on runtime parameters */
#define MESHTASTIC_MESHTASTIC_DEVICEONLY_PB_H_MAX_SIZE meshtastic_BackupPreferences_size
#define meshtastic_BackupPreferences_size 2271
#define meshtastic_BackupPreferences_size 2273
#define meshtastic_ChannelFile_size 718
#define meshtastic_DeviceState_size 1737
#define meshtastic_NodeInfoLite_size 196

View File

@ -188,7 +188,7 @@ extern const pb_msgdesc_t meshtastic_LocalModuleConfig_msg;
/* Maximum encoded size of messages (where known) */
#define MESHTASTIC_MESHTASTIC_LOCALONLY_PB_H_MAX_SIZE meshtastic_LocalConfig_size
#define meshtastic_LocalConfig_size 747
#define meshtastic_LocalModuleConfig_size 669
#define meshtastic_LocalModuleConfig_size 671
#ifdef __cplusplus
} /* extern "C" */

View File

@ -317,6 +317,9 @@ typedef struct _meshtastic_ModuleConfig_RangeTestConfig {
/* Bool value indicating that this node should save a RangeTest.csv file.
ESP32 Only */
bool save;
/* Bool indicating that the node should cleanup / destroy it's RangeTest.csv file.
ESP32 Only */
bool clear_on_reboot;
} meshtastic_ModuleConfig_RangeTestConfig;
/* Configuration for both device and environment metrics */
@ -519,7 +522,7 @@ extern "C" {
#define meshtastic_ModuleConfig_SerialConfig_init_default {0, 0, 0, 0, _meshtastic_ModuleConfig_SerialConfig_Serial_Baud_MIN, 0, _meshtastic_ModuleConfig_SerialConfig_Serial_Mode_MIN, 0}
#define meshtastic_ModuleConfig_ExternalNotificationConfig_init_default {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
#define meshtastic_ModuleConfig_StoreForwardConfig_init_default {0, 0, 0, 0, 0, 0}
#define meshtastic_ModuleConfig_RangeTestConfig_init_default {0, 0, 0}
#define meshtastic_ModuleConfig_RangeTestConfig_init_default {0, 0, 0, 0}
#define meshtastic_ModuleConfig_TelemetryConfig_init_default {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
#define meshtastic_ModuleConfig_CannedMessageConfig_init_default {0, 0, 0, 0, _meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_MIN, _meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_MIN, _meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_MIN, 0, 0, "", 0}
#define meshtastic_ModuleConfig_AmbientLightingConfig_init_default {0, 0, 0, 0, 0}
@ -535,7 +538,7 @@ extern "C" {
#define meshtastic_ModuleConfig_SerialConfig_init_zero {0, 0, 0, 0, _meshtastic_ModuleConfig_SerialConfig_Serial_Baud_MIN, 0, _meshtastic_ModuleConfig_SerialConfig_Serial_Mode_MIN, 0}
#define meshtastic_ModuleConfig_ExternalNotificationConfig_init_zero {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
#define meshtastic_ModuleConfig_StoreForwardConfig_init_zero {0, 0, 0, 0, 0, 0}
#define meshtastic_ModuleConfig_RangeTestConfig_init_zero {0, 0, 0}
#define meshtastic_ModuleConfig_RangeTestConfig_init_zero {0, 0, 0, 0}
#define meshtastic_ModuleConfig_TelemetryConfig_init_zero {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
#define meshtastic_ModuleConfig_CannedMessageConfig_init_zero {0, 0, 0, 0, _meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_MIN, _meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_MIN, _meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_MIN, 0, 0, "", 0}
#define meshtastic_ModuleConfig_AmbientLightingConfig_init_zero {0, 0, 0, 0, 0}
@ -610,6 +613,7 @@ extern "C" {
#define meshtastic_ModuleConfig_RangeTestConfig_enabled_tag 1
#define meshtastic_ModuleConfig_RangeTestConfig_sender_tag 2
#define meshtastic_ModuleConfig_RangeTestConfig_save_tag 3
#define meshtastic_ModuleConfig_RangeTestConfig_clear_on_reboot_tag 4
#define meshtastic_ModuleConfig_TelemetryConfig_device_update_interval_tag 1
#define meshtastic_ModuleConfig_TelemetryConfig_environment_update_interval_tag 2
#define meshtastic_ModuleConfig_TelemetryConfig_environment_measurement_enabled_tag 3
@ -803,7 +807,8 @@ X(a, STATIC, SINGULAR, BOOL, is_server, 6)
#define meshtastic_ModuleConfig_RangeTestConfig_FIELDLIST(X, a) \
X(a, STATIC, SINGULAR, BOOL, enabled, 1) \
X(a, STATIC, SINGULAR, UINT32, sender, 2) \
X(a, STATIC, SINGULAR, BOOL, save, 3)
X(a, STATIC, SINGULAR, BOOL, save, 3) \
X(a, STATIC, SINGULAR, BOOL, clear_on_reboot, 4)
#define meshtastic_ModuleConfig_RangeTestConfig_CALLBACK NULL
#define meshtastic_ModuleConfig_RangeTestConfig_DEFAULT NULL
@ -901,7 +906,7 @@ extern const pb_msgdesc_t meshtastic_RemoteHardwarePin_msg;
#define meshtastic_ModuleConfig_MapReportSettings_size 14
#define meshtastic_ModuleConfig_NeighborInfoConfig_size 10
#define meshtastic_ModuleConfig_PaxcounterConfig_size 30
#define meshtastic_ModuleConfig_RangeTestConfig_size 10
#define meshtastic_ModuleConfig_RangeTestConfig_size 12
#define meshtastic_ModuleConfig_RemoteHardwareConfig_size 96
#define meshtastic_ModuleConfig_SerialConfig_size 28
#define meshtastic_ModuleConfig_StoreForwardConfig_size 24

View File

@ -364,9 +364,10 @@ ExternalNotificationModule::ExternalNotificationModule()
// moduleConfig.external_notification.alert_message_buzzer = true;
if (moduleConfig.external_notification.enabled) {
#if !defined(MESHTASTIC_EXCLUDE_INPUTBROKER)
if (inputBroker) // put our callback in the inputObserver list
inputObserver.observe(inputBroker);
#endif
if (nodeDB->loadProto(rtttlConfigFile, meshtastic_RTTTLConfig_size, sizeof(meshtastic_RTTTLConfig),
&meshtastic_RTTTLConfig_msg, &rtttlConfig) != LoadFileResult::LOAD_SUCCESS) {
memset(rtttlConfig.ringtone, 0, sizeof(rtttlConfig.ringtone));

View File

@ -88,7 +88,7 @@
#include "modules/StoreForwardModule.h"
#endif
#endif
#if defined(ARCH_ESP32) || defined(ARCH_NRF52) || defined(ARCH_RP2040) || defined(ARCH_PORTDUINO)
#if !MESHTASTIC_EXCLUDE_EXTERNALNOTIFICATION
#include "modules/ExternalNotificationModule.h"
#endif
@ -98,7 +98,6 @@
#if !defined(CONFIG_IDF_TARGET_ESP32S2) && !MESHTASTIC_EXCLUDE_SERIAL
#include "modules/SerialModule.h"
#endif
#endif
#if !MESHTASTIC_EXCLUDE_DROPZONE
#include "modules/DropzoneModule.h"
@ -246,8 +245,8 @@ void setupModules()
#if HAS_TELEMETRY && !MESHTASTIC_EXCLUDE_POWER_TELEMETRY && !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR
new PowerTelemetryModule();
#endif
#if (defined(ARCH_ESP32) || defined(ARCH_NRF52) || defined(ARCH_RP2040)) && !defined(CONFIG_IDF_TARGET_ESP32S2) && \
!defined(CONFIG_IDF_TARGET_ESP32C3)
#if (defined(ARCH_ESP32) || defined(ARCH_NRF52) || defined(ARCH_RP2040) || defined(ARCH_STM32WL)) && \
!defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32C3)
#if !MESHTASTIC_EXCLUDE_SERIAL
if (config.display.displaymode != meshtastic_Config_DisplayConfig_DisplayMode_COLOR) {
new SerialModule();
@ -268,13 +267,11 @@ void setupModules()
storeForwardModule = new StoreForwardModule();
#endif
#endif
#if defined(ARCH_ESP32) || defined(ARCH_NRF52) || defined(ARCH_RP2040) || defined(ARCH_PORTDUINO)
#if !MESHTASTIC_EXCLUDE_EXTERNALNOTIFICATION
externalNotificationModule = new ExternalNotificationModule();
#endif
#if !MESHTASTIC_EXCLUDE_RANGETEST && !MESHTASTIC_EXCLUDE_GPS
new RangeTestModule();
#endif
#endif
} else {
#if !MESHTASTIC_EXCLUDE_ADMIN

View File

@ -31,7 +31,7 @@ uint32_t packetSequence = 0;
int32_t RangeTestModule::runOnce()
{
#if defined(ARCH_ESP32) || defined(ARCH_NRF52) || defined(ARCH_PORTDUINO)
#if defined(ARCH_ESP32) || defined(ARCH_NRF52) || defined(ARCH_STM32WL) || defined(ARCH_PORTDUINO)
/*
Uncomment the preferences below if you want to use the module
@ -130,7 +130,7 @@ void RangeTestModuleRadio::sendPayload(NodeNum dest, bool wantReplies)
ProcessMessage RangeTestModuleRadio::handleReceived(const meshtastic_MeshPacket &mp)
{
#if defined(ARCH_ESP32) || defined(ARCH_NRF52) || defined(ARCH_PORTDUINO)
#if defined(ARCH_ESP32) || defined(ARCH_NRF52) || defined(ARCH_STM32WL) || defined(ARCH_PORTDUINO)
if (moduleConfig.range_test.enabled) {

View File

@ -49,8 +49,8 @@
#include "meshSolarApp.h"
#endif
#if (defined(ARCH_ESP32) || defined(ARCH_NRF52) || defined(ARCH_RP2040)) && !defined(CONFIG_IDF_TARGET_ESP32S2) && \
!defined(CONFIG_IDF_TARGET_ESP32C3)
#if (defined(ARCH_ESP32) || defined(ARCH_NRF52) || defined(ARCH_RP2040) || defined(ARCH_STM32WL)) && \
!defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32C3)
#define RX_BUFFER 256
#define TIMEOUT 250
@ -67,7 +67,7 @@ SerialModuleRadio *serialModuleRadio;
defined(ELECROW_ThinkNode_M5) || defined(HELTEC_MESH_SOLAR) || defined(T_ECHO_LITE)
SerialModule::SerialModule() : StreamAPI(&Serial), concurrency::OSThread("Serial") {}
static Print *serialPrint = &Serial;
#elif defined(CONFIG_IDF_TARGET_ESP32C6)
#elif defined(CONFIG_IDF_TARGET_ESP32C6) || defined(RAK3172)
SerialModule::SerialModule() : StreamAPI(&Serial1), concurrency::OSThread("Serial") {}
static Print *serialPrint = &Serial1;
#else
@ -173,7 +173,18 @@ int32_t SerialModule::runOnce()
Serial.begin(baud);
Serial.setTimeout(moduleConfig.serial.timeout > 0 ? moduleConfig.serial.timeout : TIMEOUT);
}
#elif defined(ARCH_STM32WL)
#ifndef RAK3172
HardwareSerial *serialInstance = &Serial2;
#else
HardwareSerial *serialInstance = &Serial1;
#endif
if (moduleConfig.serial.rxd && moduleConfig.serial.txd) {
serialInstance->setTx(moduleConfig.serial.txd);
serialInstance->setRx(moduleConfig.serial.rxd);
}
serialInstance->begin(baud);
serialInstance->setTimeout(moduleConfig.serial.timeout > 0 ? moduleConfig.serial.timeout : TIMEOUT);
#elif defined(ARCH_ESP32)
if (moduleConfig.serial.rxd && moduleConfig.serial.txd) {
@ -260,8 +271,13 @@ int32_t SerialModule::runOnce()
while (Serial1.available()) {
serialPayloadSize = Serial1.readBytes(serialBytes, meshtastic_Constants_DATA_PAYLOAD_LEN);
#else
while (Serial2.available()) {
serialPayloadSize = Serial2.readBytes(serialBytes, meshtastic_Constants_DATA_PAYLOAD_LEN);
#ifndef RAK3172
HardwareSerial *serialInstance = &Serial2;
#else
HardwareSerial *serialInstance = &Serial1;
#endif
while (serialInstance->available()) {
serialPayloadSize = serialInstance->readBytes(serialBytes, meshtastic_Constants_DATA_PAYLOAD_LEN);
#endif
serialModuleRadio->sendPayload();
}
@ -511,7 +527,7 @@ ParsedLine parseLine(const char *line)
void SerialModule::processWXSerial()
{
#if !defined(TTGO_T_ECHO) && !defined(T_ECHO_LITE) && !defined(CANARYONE) && !defined(CONFIG_IDF_TARGET_ESP32C6) && \
!defined(MESHLINK) && !defined(ELECROW_ThinkNode_M1) && !defined(ELECROW_ThinkNode_M5)
!defined(MESHLINK) && !defined(ELECROW_ThinkNode_M1) && !defined(ELECROW_ThinkNode_M5) && !defined(ARCH_STM32WL)
static unsigned int lastAveraged = 0;
static unsigned int averageIntervalMillis = 300000; // 5 minutes hard coded.
static double dir_sum_sin = 0;

View File

@ -8,8 +8,8 @@
#include <Arduino.h>
#include <functional>
#if (defined(ARCH_ESP32) || defined(ARCH_NRF52) || defined(ARCH_RP2040)) && !defined(CONFIG_IDF_TARGET_ESP32S2) && \
!defined(CONFIG_IDF_TARGET_ESP32C3)
#if (defined(ARCH_ESP32) || defined(ARCH_NRF52) || defined(ARCH_RP2040) || defined(ARCH_STM32WL)) && \
!defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32C3)
class SerialModule : public StreamAPI, private concurrency::OSThread
{

View File

@ -6,6 +6,10 @@ board_upload.maximum_size = 233472 ; reserve the last 28KB for filesystem
build_flags =
${stm32_base.build_flags}
-Ivariants/stm32/rak3172
-DRAK3172
-DENABLE_HWSERIAL1
-DPIN_SERIAL1_RX=PB7
-DPIN_SERIAL1_TX=PB6
-DPIN_WIRE_SDA=PA11
-DPIN_WIRE_SCL=PA12
-DMESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR=1