mirror of
https://github.com/alexhopeoconnor/firmware.git
synced 2026-10-13 15:11:20 +10:00
Compare commits
23
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0f761d930b | ||
|
|
4d4906772f | ||
|
|
711abb56f3 | ||
|
|
82aefd1af1 | ||
|
|
0f9eb86830 | ||
|
|
e2aa44ec54 | ||
|
|
0832330327 | ||
|
|
af3739fd63 | ||
|
|
0148a89ddb | ||
|
|
6199faacf1 | ||
|
|
fc5556b8e6 | ||
|
|
502c5af524 | ||
|
|
05707079bd | ||
|
|
1c05633fcd | ||
|
|
fce419b335 | ||
|
|
1ae4a538f5 | ||
|
|
c756bbe2c1 | ||
|
|
4c3ba612bb | ||
|
|
59025e4820 | ||
|
|
0a7b3c723e | ||
|
|
cd5d608e8d | ||
|
|
7f5184281d | ||
|
|
4446b0f1a2 |
@@ -8,17 +8,21 @@
|
|||||||
"features": {
|
"features": {
|
||||||
"ghcr.io/devcontainers/features/python:1": {
|
"ghcr.io/devcontainers/features/python:1": {
|
||||||
"installTools": true,
|
"installTools": true,
|
||||||
"version": "3.14"
|
"version": "3.13"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"customizations": {
|
"customizations": {
|
||||||
"vscode": {
|
"vscode": {
|
||||||
"extensions": [
|
"extensions": [
|
||||||
"ms-vscode.cpptools",
|
"ms-vscode.cpptools",
|
||||||
"platformio.platformio-ide",
|
"Jason2866.esp-decoder",
|
||||||
|
"pioarduino.pioarduino-ide",
|
||||||
"Trunk.io"
|
"Trunk.io"
|
||||||
],
|
],
|
||||||
"unwantedRecommendations": ["ms-azuretools.vscode-docker"],
|
"unwantedRecommendations": [
|
||||||
|
"ms-azuretools.vscode-docker",
|
||||||
|
"platformio.platformio-ide"
|
||||||
|
],
|
||||||
"settings": {
|
"settings": {
|
||||||
"extensions.ignoreRecommendations": true
|
"extensions.ignoreRecommendations": true
|
||||||
}
|
}
|
||||||
|
|||||||
+5
-5
@@ -4,19 +4,19 @@ cli:
|
|||||||
plugins:
|
plugins:
|
||||||
sources:
|
sources:
|
||||||
- id: trunk
|
- id: trunk
|
||||||
ref: v1.9.0
|
ref: v1.10.0
|
||||||
uri: https://github.com/trunk-io/plugins
|
uri: https://github.com/trunk-io/plugins
|
||||||
lint:
|
lint:
|
||||||
enabled:
|
enabled:
|
||||||
- checkov@3.2.528
|
- checkov@3.2.529
|
||||||
- renovate@43.150.0
|
- renovate@43.150.0
|
||||||
- prettier@3.8.3
|
- prettier@3.8.3
|
||||||
- trufflehog@3.95.2
|
- trufflehog@3.95.3
|
||||||
- yamllint@1.38.0
|
- yamllint@1.38.0
|
||||||
- bandit@1.9.4
|
- bandit@1.9.4
|
||||||
- trivy@0.70.0
|
- trivy@0.70.0
|
||||||
- taplo@0.10.0
|
- taplo@0.10.0
|
||||||
- ruff@0.15.12
|
- ruff@0.15.13
|
||||||
- isort@8.0.1
|
- isort@8.0.1
|
||||||
- markdownlint@0.48.0
|
- markdownlint@0.48.0
|
||||||
- oxipng@10.1.1
|
- oxipng@10.1.1
|
||||||
@@ -26,7 +26,7 @@ lint:
|
|||||||
- hadolint@2.14.0
|
- hadolint@2.14.0
|
||||||
- shfmt@3.6.0
|
- shfmt@3.6.0
|
||||||
- shellcheck@0.11.0
|
- shellcheck@0.11.0
|
||||||
- black@26.3.1
|
- black@26.5.1
|
||||||
- git-diff-check
|
- git-diff-check
|
||||||
- gitleaks@8.30.1
|
- gitleaks@8.30.1
|
||||||
- clang-format@16.0.3
|
- clang-format@16.0.3
|
||||||
|
|||||||
Vendored
+4
-4
@@ -1,10 +1,10 @@
|
|||||||
{
|
{
|
||||||
// See http://go.microsoft.com/fwlink/?LinkId=827846
|
|
||||||
// for the documentation about the extensions.json format
|
|
||||||
"recommendations": [
|
"recommendations": [
|
||||||
"platformio.platformio-ide"
|
"Jason2866.esp-decoder",
|
||||||
|
"pioarduino.pioarduino-ide"
|
||||||
],
|
],
|
||||||
"unwantedRecommendations": [
|
"unwantedRecommendations": [
|
||||||
"ms-vscode.cpptools-extension-pack"
|
"ms-vscode.cpptools-extension-pack",
|
||||||
|
"platformio.platformio-ide"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,18 @@
|
|||||||
|
# Station G3 motherboard with a Raspberry Pi Zero 2W as the MCU daughterboard.
|
||||||
|
# Verify spidev / I2C device paths for your OS — they may differ.
|
||||||
|
Meta:
|
||||||
|
name: Station G3
|
||||||
|
support: community
|
||||||
|
compatible:
|
||||||
|
- raspberry-pi
|
||||||
|
|
||||||
|
Lora:
|
||||||
|
Module: sx1262
|
||||||
|
IRQ: 22 # BCM pin — wiki spec
|
||||||
|
Reset: 16 # BCM pin — wiki spec
|
||||||
|
Busy: 24 # BCM pin — wiki spec
|
||||||
|
# CS: 8 # BCM 8 = SPI0 CE0 (default); uncomment only to override
|
||||||
|
DIO2_AS_RF_SWITCH: true
|
||||||
|
DIO3_TCXO_VOLTAGE: true
|
||||||
|
spidev: spidev0.0
|
||||||
|
# SX126X_MAX_POWER: 19 # matches Station G2 firmware cap; raise carefully per PA jumper mode
|
||||||
@@ -0,0 +1,41 @@
|
|||||||
|
{
|
||||||
|
"build": {
|
||||||
|
"arduino": {
|
||||||
|
"ldscript": "esp32s3_out.ld",
|
||||||
|
"memory_type": "qio_opi"
|
||||||
|
},
|
||||||
|
"core": "esp32",
|
||||||
|
"extra_flags": [
|
||||||
|
"-DBOARD_HAS_PSRAM",
|
||||||
|
"-DARDUINO_USB_CDC_ON_BOOT=1",
|
||||||
|
"-DARDUINO_USB_MODE=1",
|
||||||
|
"-DARDUINO_RUNNING_CORE=1",
|
||||||
|
"-DARDUINO_EVENT_RUNNING_CORE=0"
|
||||||
|
],
|
||||||
|
"f_cpu": "240000000L",
|
||||||
|
"f_flash": "80000000L",
|
||||||
|
"flash_mode": "qio",
|
||||||
|
"hwids": [["0x303A", "0x1001"]],
|
||||||
|
"mcu": "esp32s3",
|
||||||
|
"variant": "station-g3"
|
||||||
|
},
|
||||||
|
"connectivity": ["wifi", "bluetooth", "lora"],
|
||||||
|
"debug": {
|
||||||
|
"default_tool": "esp-builtin",
|
||||||
|
"onboard_tools": ["esp-builtin"],
|
||||||
|
"openocd_target": "esp32s3.cfg"
|
||||||
|
},
|
||||||
|
"frameworks": ["arduino", "espidf"],
|
||||||
|
"name": "BQ Station G3",
|
||||||
|
"upload": {
|
||||||
|
"flash_size": "16MB",
|
||||||
|
"maximum_ram_size": 327680,
|
||||||
|
"maximum_size": 16777216,
|
||||||
|
"use_1200bps_touch": true,
|
||||||
|
"wait_for_upload_port": true,
|
||||||
|
"require_upload_port": true,
|
||||||
|
"speed": 921600
|
||||||
|
},
|
||||||
|
"url": "",
|
||||||
|
"vendor": "BQ Consulting"
|
||||||
|
}
|
||||||
+1
-1
@@ -138,7 +138,7 @@ lib_deps =
|
|||||||
# renovate: datasource=github-tags depName=Adafruit GFX packageName=adafruit/Adafruit-GFX-Library
|
# renovate: datasource=github-tags depName=Adafruit GFX packageName=adafruit/Adafruit-GFX-Library
|
||||||
https://github.com/adafruit/Adafruit-GFX-Library/archive/refs/tags/1.12.6.zip
|
https://github.com/adafruit/Adafruit-GFX-Library/archive/refs/tags/1.12.6.zip
|
||||||
# renovate: datasource=github-tags depName=NeoPixel packageName=adafruit/Adafruit_NeoPixel
|
# renovate: datasource=github-tags depName=NeoPixel packageName=adafruit/Adafruit_NeoPixel
|
||||||
https://github.com/adafruit/Adafruit_NeoPixel/archive/refs/tags/1.15.4.zip
|
https://github.com/adafruit/Adafruit_NeoPixel/archive/1.15.5.zip
|
||||||
# renovate: datasource=github-tags depName=Adafruit SSD1306 packageName=adafruit/Adafruit_SSD1306
|
# renovate: datasource=github-tags depName=Adafruit SSD1306 packageName=adafruit/Adafruit_SSD1306
|
||||||
https://github.com/adafruit/Adafruit_SSD1306/archive/refs/tags/2.5.16.zip
|
https://github.com/adafruit/Adafruit_SSD1306/archive/refs/tags/2.5.16.zip
|
||||||
# renovate: datasource=github-tags depName=Adafruit BMP280 packageName=adafruit/Adafruit_BMP280_Library
|
# renovate: datasource=github-tags depName=Adafruit BMP280 packageName=adafruit/Adafruit_BMP280_Library
|
||||||
|
|||||||
+1
-1
Submodule protobufs updated: b302d92332...59cb394dcf
@@ -353,6 +353,11 @@ Screen::Screen(ScanI2C::DeviceAddress address, meshtastic_Config_DisplayConfig_O
|
|||||||
#elif defined(USE_SSD1306)
|
#elif defined(USE_SSD1306)
|
||||||
dispdev = new SSD1306Wire(address.address, -1, -1, geometry,
|
dispdev = new SSD1306Wire(address.address, -1, -1, geometry,
|
||||||
(address.port == ScanI2C::I2CPort::WIRE1) ? HW_I2C::I2C_TWO : HW_I2C::I2C_ONE);
|
(address.port == ScanI2C::I2CPort::WIRE1) ? HW_I2C::I2C_TWO : HW_I2C::I2C_ONE);
|
||||||
|
#if defined(OLED_Y_OFFSET_PAGES)
|
||||||
|
// Panels whose active window does not start at GDDRAM row 0 (e.g. 72x40
|
||||||
|
// modules on pages 3..7) need a fixed vertical page shift on every write.
|
||||||
|
static_cast<SSD1306Wire *>(dispdev)->setYOffset(OLED_Y_OFFSET_PAGES);
|
||||||
|
#endif
|
||||||
#elif defined(USE_SPISSD1306)
|
#elif defined(USE_SPISSD1306)
|
||||||
dispdev = new SSD1306Spi(SSD1306_RESET, SSD1306_RS, SSD1306_NSS, GEOMETRY_64_48);
|
dispdev = new SSD1306Spi(SSD1306_RESET, SSD1306_RS, SSD1306_NSS, GEOMETRY_64_48);
|
||||||
if (!dispdev->init()) {
|
if (!dispdev->init()) {
|
||||||
@@ -834,7 +839,7 @@ int32_t Screen::runOnce()
|
|||||||
|
|
||||||
#ifndef DISABLE_WELCOME_UNSET
|
#ifndef DISABLE_WELCOME_UNSET
|
||||||
if (!NotificationRenderer::isOverlayBannerShowing() && config.lora.region == meshtastic_Config_LoRaConfig_RegionCode_UNSET) {
|
if (!NotificationRenderer::isOverlayBannerShowing() && config.lora.region == meshtastic_Config_LoRaConfig_RegionCode_UNSET) {
|
||||||
#if defined(M5STACK_UNITC6L)
|
#if defined(OLED_TINY)
|
||||||
menuHandler::LoraRegionPicker();
|
menuHandler::LoraRegionPicker();
|
||||||
#else
|
#else
|
||||||
menuHandler::OnboardMessage();
|
menuHandler::OnboardMessage();
|
||||||
@@ -1058,7 +1063,7 @@ void Screen::setFrames(FrameFocus focus)
|
|||||||
#if defined(DISPLAY_CLOCK_FRAME)
|
#if defined(DISPLAY_CLOCK_FRAME)
|
||||||
if (!hiddenFrames.clock) {
|
if (!hiddenFrames.clock) {
|
||||||
fsi.positions.clock = numframes;
|
fsi.positions.clock = numframes;
|
||||||
#if defined(M5STACK_UNITC6L)
|
#if defined(OLED_TINY)
|
||||||
normalFrames[numframes++] = graphics::ClockRenderer::drawAnalogClockFrame;
|
normalFrames[numframes++] = graphics::ClockRenderer::drawAnalogClockFrame;
|
||||||
#else
|
#else
|
||||||
normalFrames[numframes++] = uiconfig.is_clockface_analog ? graphics::ClockRenderer::drawAnalogClockFrame
|
normalFrames[numframes++] = uiconfig.is_clockface_analog ? graphics::ClockRenderer::drawAnalogClockFrame
|
||||||
@@ -1511,7 +1516,7 @@ void Screen::showFrame(FrameDirection direction)
|
|||||||
|
|
||||||
void Screen::setFastFramerate()
|
void Screen::setFastFramerate()
|
||||||
{
|
{
|
||||||
#if defined(M5STACK_UNITC6L)
|
#if defined(OLED_TINY)
|
||||||
dispdev->clear();
|
dispdev->clear();
|
||||||
dispdev->display();
|
dispdev->display();
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -96,7 +96,7 @@
|
|||||||
#define FONT_SMALL FONT_MEDIUM_LOCAL // Height: 19
|
#define FONT_SMALL FONT_MEDIUM_LOCAL // Height: 19
|
||||||
#define FONT_MEDIUM FONT_LARGE_LOCAL // Height: 28
|
#define FONT_MEDIUM FONT_LARGE_LOCAL // Height: 28
|
||||||
#define FONT_LARGE FONT_LARGE_LOCAL // Height: 28
|
#define FONT_LARGE FONT_LARGE_LOCAL // Height: 28
|
||||||
#elif defined(M5STACK_UNITC6L)
|
#elif defined(OLED_TINY)
|
||||||
#define FONT_SMALL FONT_SMALL_LOCAL // Height: 13
|
#define FONT_SMALL FONT_SMALL_LOCAL // Height: 13
|
||||||
#define FONT_MEDIUM FONT_SMALL_LOCAL // Height: 13
|
#define FONT_MEDIUM FONT_SMALL_LOCAL // Height: 13
|
||||||
#define FONT_LARGE FONT_SMALL_LOCAL // Height: 13
|
#define FONT_LARGE FONT_SMALL_LOCAL // Height: 13
|
||||||
|
|||||||
@@ -27,6 +27,12 @@ ScreenResolution determineScreenResolution(int16_t screenheight, int16_t screenw
|
|||||||
return ScreenResolution::UltraLow;
|
return ScreenResolution::UltraLow;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef DISPLAY_FORCE_SMALL_FONTS
|
||||||
|
if (screenwidth <= 160 && screenheight <= 80) {
|
||||||
|
return ScreenResolution::Low;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
// Standard OLED screens
|
// Standard OLED screens
|
||||||
if (screenwidth > 128 && screenheight <= 64) {
|
if (screenwidth > 128 && screenheight <= 64) {
|
||||||
return ScreenResolution::Low;
|
return ScreenResolution::Low;
|
||||||
@@ -155,7 +161,7 @@ void drawCommonHeader(OLEDDisplay *display, int16_t x, int16_t y, const char *ti
|
|||||||
|
|
||||||
int batteryX = 1;
|
int batteryX = 1;
|
||||||
int batteryY = HEADER_OFFSET_Y + 1;
|
int batteryY = HEADER_OFFSET_Y + 1;
|
||||||
#if !defined(M5STACK_UNITC6L)
|
#if !defined(OLED_TINY)
|
||||||
// === Battery Icons ===
|
// === Battery Icons ===
|
||||||
if (usbPowered && !isCharging) { // This is a basic check to determine USB Powered is flagged but not charging
|
if (usbPowered && !isCharging) { // This is a basic check to determine USB Powered is flagged but not charging
|
||||||
batteryX += 1;
|
batteryX += 1;
|
||||||
|
|||||||
@@ -183,9 +183,13 @@ void drawDigitalClockFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int1
|
|||||||
static float segmentHeight = SEGMENT_HEIGHT * 0.75f;
|
static float segmentHeight = SEGMENT_HEIGHT * 0.75f;
|
||||||
|
|
||||||
if (!scaleInitialized) {
|
if (!scaleInitialized) {
|
||||||
|
#ifdef DISPLAY_FORCE_SMALL_FONTS
|
||||||
|
float screenwidth_target_ratio = 0.70f; // Target 70% of display width (adjustable)
|
||||||
|
#else
|
||||||
float screenwidth_target_ratio = 0.80f; // Target 80% of display width (adjustable)
|
float screenwidth_target_ratio = 0.80f; // Target 80% of display width (adjustable)
|
||||||
float max_scale = 3.5f; // Safety limit to avoid runaway scaling
|
#endif
|
||||||
float step = 0.05f; // Step increment per iteration
|
float max_scale = 3.5f; // Safety limit to avoid runaway scaling
|
||||||
|
float step = 0.05f; // Step increment per iteration
|
||||||
|
|
||||||
float target_width = display->getWidth() * screenwidth_target_ratio;
|
float target_width = display->getWidth() * screenwidth_target_ratio;
|
||||||
float target_height =
|
float target_height =
|
||||||
|
|||||||
@@ -449,7 +449,7 @@ void drawLoRaFocused(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x,
|
|||||||
nameX = (SCREEN_WIDTH - textWidth) / 2;
|
nameX = (SCREEN_WIDTH - textWidth) / 2;
|
||||||
display->drawString(nameX, getTextPositions(display)[line++], frequencyslot);
|
display->drawString(nameX, getTextPositions(display)[line++], frequencyslot);
|
||||||
|
|
||||||
#if !defined(M5STACK_UNITC6L)
|
#if !defined(OLED_TINY)
|
||||||
// === Fifth Row: Channel Utilization ===
|
// === Fifth Row: Channel Utilization ===
|
||||||
const char *chUtil = "ChUtil:";
|
const char *chUtil = "ChUtil:";
|
||||||
char chUtilPercentage[10];
|
char chUtilPercentage[10];
|
||||||
@@ -569,7 +569,7 @@ void drawSystemScreen(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x
|
|||||||
// Label
|
// Label
|
||||||
display->setTextAlignment(TEXT_ALIGN_LEFT);
|
display->setTextAlignment(TEXT_ALIGN_LEFT);
|
||||||
display->drawString(labelX, getTextPositions(display)[line], label);
|
display->drawString(labelX, getTextPositions(display)[line], label);
|
||||||
#if !defined(M5STACK_UNITC6L)
|
#if !defined(OLED_TINY)
|
||||||
// Bar
|
// Bar
|
||||||
int barY = getTextPositions(display)[line] + (FONT_HEIGHT_SMALL - barHeight) / 2;
|
int barY = getTextPositions(display)[line] + (FONT_HEIGHT_SMALL - barHeight) / 2;
|
||||||
display->setColor(WHITE);
|
display->setColor(WHITE);
|
||||||
|
|||||||
@@ -491,7 +491,7 @@ void menuHandler::TZPicker()
|
|||||||
|
|
||||||
void menuHandler::clockMenu()
|
void menuHandler::clockMenu()
|
||||||
{
|
{
|
||||||
#if defined(M5STACK_UNITC6L)
|
#if defined(OLED_TINY)
|
||||||
static const char *optionsArray[] = {"Back", "Time Format", "Timezone"};
|
static const char *optionsArray[] = {"Back", "Time Format", "Timezone"};
|
||||||
#else
|
#else
|
||||||
static const char *optionsArray[] = {"Back", "Clock Face", "Time Format", "Timezone"};
|
static const char *optionsArray[] = {"Back", "Clock Face", "Time Format", "Timezone"};
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ extern bool haveGlyphs(const char *str);
|
|||||||
// Global screen instance
|
// Global screen instance
|
||||||
extern graphics::Screen *screen;
|
extern graphics::Screen *screen;
|
||||||
|
|
||||||
#if defined(M5STACK_UNITC6L)
|
#if defined(OLED_TINY)
|
||||||
static uint32_t lastSwitchTime = 0;
|
static uint32_t lastSwitchTime = 0;
|
||||||
#endif
|
#endif
|
||||||
namespace graphics
|
namespace graphics
|
||||||
@@ -670,7 +670,7 @@ void drawDynamicListScreen_Nodes(OLEDDisplay *display, OLEDDisplayUiState *state
|
|||||||
|
|
||||||
unsigned long now = millis();
|
unsigned long now = millis();
|
||||||
|
|
||||||
#if defined(M5STACK_UNITC6L)
|
#if defined(OLED_TINY)
|
||||||
display->clear();
|
display->clear();
|
||||||
if (now - lastSwitchTime >= 3000) {
|
if (now - lastSwitchTime >= 3000) {
|
||||||
display->display();
|
display->display();
|
||||||
@@ -706,7 +706,7 @@ void drawDynamicListScreen_Location(OLEDDisplay *display, OLEDDisplayUiState *st
|
|||||||
|
|
||||||
unsigned long now = millis();
|
unsigned long now = millis();
|
||||||
|
|
||||||
#if defined(M5STACK_UNITC6L)
|
#if defined(OLED_TINY)
|
||||||
display->clear();
|
display->clear();
|
||||||
if (now - lastSwitchTime >= 3000) {
|
if (now - lastSwitchTime >= 3000) {
|
||||||
display->display();
|
display->display();
|
||||||
@@ -771,7 +771,7 @@ void drawNodeListWithCompasses(OLEDDisplay *display, OLEDDisplayUiState *state,
|
|||||||
double lat = DegD(ourNode->position.latitude_i);
|
double lat = DegD(ourNode->position.latitude_i);
|
||||||
double lon = DegD(ourNode->position.longitude_i);
|
double lon = DegD(ourNode->position.longitude_i);
|
||||||
|
|
||||||
#if defined(M5STACK_UNITC6L)
|
#if defined(OLED_TINY)
|
||||||
display->clear();
|
display->clear();
|
||||||
uint32_t now = millis();
|
uint32_t now = millis();
|
||||||
if (now - lastSwitchTime >= 2000) {
|
if (now - lastSwitchTime >= 2000) {
|
||||||
|
|||||||
@@ -580,7 +580,7 @@ void NotificationRenderer::drawNotificationBox(OLEDDisplay *display, OLEDDisplay
|
|||||||
}
|
}
|
||||||
int16_t boxTop = (display->height() / 2) - (boxHeight / 2);
|
int16_t boxTop = (display->height() / 2) - (boxHeight / 2);
|
||||||
boxHeight += (currentResolution == ScreenResolution::High) ? 2 : 1;
|
boxHeight += (currentResolution == ScreenResolution::High) ? 2 : 1;
|
||||||
#if defined(M5STACK_UNITC6L)
|
#if defined(OLED_TINY)
|
||||||
if (visibleTotalLines == 1) {
|
if (visibleTotalLines == 1) {
|
||||||
boxTop += 25;
|
boxTop += 25;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,7 +20,7 @@
|
|||||||
|
|
||||||
// External variables
|
// External variables
|
||||||
extern graphics::Screen *screen;
|
extern graphics::Screen *screen;
|
||||||
#if defined(M5STACK_UNITC6L)
|
#if defined(OLED_TINY)
|
||||||
static uint32_t lastSwitchTime = 0;
|
static uint32_t lastSwitchTime = 0;
|
||||||
#endif
|
#endif
|
||||||
namespace graphics
|
namespace graphics
|
||||||
@@ -304,7 +304,7 @@ void UIRenderer::drawNodeInfo(OLEDDisplay *display, OLEDDisplayUiState *state, i
|
|||||||
if (!node || node->num == nodeDB->getNodeNum() || !node->is_favorite)
|
if (!node || node->num == nodeDB->getNodeNum() || !node->is_favorite)
|
||||||
return;
|
return;
|
||||||
display->clear();
|
display->clear();
|
||||||
#if defined(M5STACK_UNITC6L)
|
#if defined(OLED_TINY)
|
||||||
uint32_t now = millis();
|
uint32_t now = millis();
|
||||||
if (now - lastSwitchTime >= 10000) // 10000 ms = 10 秒
|
if (now - lastSwitchTime >= 10000) // 10000 ms = 10 秒
|
||||||
{
|
{
|
||||||
@@ -518,7 +518,7 @@ void UIRenderer::drawNodeInfo(OLEDDisplay *display, OLEDDisplayUiState *state, i
|
|||||||
if (seenStr[0]) {
|
if (seenStr[0]) {
|
||||||
display->drawString(x, getTextPositions(display)[line++], seenStr);
|
display->drawString(x, getTextPositions(display)[line++], seenStr);
|
||||||
}
|
}
|
||||||
#if !defined(M5STACK_UNITC6L)
|
#if !defined(OLED_TINY)
|
||||||
// === 4. Uptime (only show if metric is present) ===
|
// === 4. Uptime (only show if metric is present) ===
|
||||||
char uptimeStr[32] = "";
|
char uptimeStr[32] = "";
|
||||||
if (node->has_device_metrics && node->device_metrics.has_uptime_seconds) {
|
if (node->has_device_metrics && node->device_metrics.has_uptime_seconds) {
|
||||||
@@ -795,7 +795,7 @@ void UIRenderer::drawDeviceFocused(OLEDDisplay *display, OLEDDisplayUiState *sta
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(M5STACK_UNITC6L)
|
#if defined(OLED_TINY)
|
||||||
line += 1;
|
line += 1;
|
||||||
|
|
||||||
// === Node Identity ===
|
// === Node Identity ===
|
||||||
@@ -1092,7 +1092,7 @@ void UIRenderer::drawIconScreen(const char *upperMsg, OLEDDisplay *display, OLED
|
|||||||
// needs to be drawn relative to x and y
|
// needs to be drawn relative to x and y
|
||||||
|
|
||||||
// draw centered icon left to right and centered above the one line of app text
|
// draw centered icon left to right and centered above the one line of app text
|
||||||
#if defined(M5STACK_UNITC6L)
|
#if defined(OLED_TINY)
|
||||||
display->drawXbm(x + (SCREEN_WIDTH - 50) / 2, y + (SCREEN_HEIGHT - 28) / 2, icon_width, icon_height, icon_bits);
|
display->drawXbm(x + (SCREEN_WIDTH - 50) / 2, y + (SCREEN_HEIGHT - 28) / 2, icon_width, icon_height, icon_bits);
|
||||||
display->setFont(FONT_MEDIUM);
|
display->setFont(FONT_MEDIUM);
|
||||||
display->setTextAlignment(TEXT_ALIGN_LEFT);
|
display->setTextAlignment(TEXT_ALIGN_LEFT);
|
||||||
@@ -1243,7 +1243,7 @@ void UIRenderer::drawCompassAndLocationScreen(OLEDDisplay *display, OLEDDisplayU
|
|||||||
}
|
}
|
||||||
display->drawString(x, getTextPositions(display)[line++], altitudeLine);
|
display->drawString(x, getTextPositions(display)[line++], altitudeLine);
|
||||||
}
|
}
|
||||||
#if !defined(M5STACK_UNITC6L)
|
#if !defined(OLED_TINY)
|
||||||
// === Draw Compass if heading is valid ===
|
// === Draw Compass if heading is valid ===
|
||||||
if (validHeading) {
|
if (validHeading) {
|
||||||
// --- Compass Rendering: landscape (wide) screens use original side-aligned logic ---
|
// --- Compass Rendering: landscape (wide) screens use original side-aligned logic ---
|
||||||
|
|||||||
@@ -318,7 +318,7 @@ const uint8_t chirpy_small[] = {0x7f, 0x41, 0x55, 0x55, 0x55, 0x55, 0x41, 0x7f};
|
|||||||
#define connection_icon_height 5
|
#define connection_icon_height 5
|
||||||
const uint8_t connection_icon[] = {0x36, 0x41, 0x5D, 0x41, 0x36};
|
const uint8_t connection_icon[] = {0x36, 0x41, 0x5D, 0x41, 0x36};
|
||||||
|
|
||||||
#ifdef M5STACK_UNITC6L
|
#ifdef OLED_TINY
|
||||||
#include "img/icon_small.xbm"
|
#include "img/icon_small.xbm"
|
||||||
#else
|
#else
|
||||||
#include "img/icon.xbm"
|
#include "img/icon.xbm"
|
||||||
|
|||||||
@@ -741,6 +741,11 @@ void setup()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef OLED_GEOMETRY_OVERRIDE
|
||||||
|
// Per-variant geometry (e.g. 72x40 micro-OLEDs). Takes precedence over the
|
||||||
|
// default GEOMETRY_128_64 set at the top of setup().
|
||||||
|
screen_geometry = OLED_GEOMETRY_OVERRIDE;
|
||||||
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if !MESHTASTIC_EXCLUDE_I2C
|
#if !MESHTASTIC_EXCLUDE_I2C
|
||||||
|
|||||||
+13
-2
@@ -80,6 +80,14 @@ static unsigned char userprefs_admin_key_1[] = USERPREFS_USE_ADMIN_KEY_1;
|
|||||||
static unsigned char userprefs_admin_key_2[] = USERPREFS_USE_ADMIN_KEY_2;
|
static unsigned char userprefs_admin_key_2[] = USERPREFS_USE_ADMIN_KEY_2;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
// Weak empty variant initialization function.
|
||||||
|
// May be redefined by variant files.
|
||||||
|
void variantDefaultConfig() __attribute__((weak));
|
||||||
|
void variantDefaultConfig() {}
|
||||||
|
|
||||||
|
void variantDefaultModuleConfig() __attribute__((weak));
|
||||||
|
void variantDefaultModuleConfig() {}
|
||||||
|
|
||||||
#ifdef HELTEC_MESH_NODE_T114
|
#ifdef HELTEC_MESH_NODE_T114
|
||||||
|
|
||||||
uint32_t read8(uint8_t bits, uint8_t dummy, uint8_t cs, uint8_t sck, uint8_t mosi, uint8_t dc, uint8_t rst)
|
uint32_t read8(uint8_t bits, uint8_t dummy, uint8_t cs, uint8_t sck, uint8_t mosi, uint8_t dc, uint8_t rst)
|
||||||
@@ -785,6 +793,8 @@ void NodeDB::installDefaultConfig(bool preserveKey = false)
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
initConfigIntervals();
|
initConfigIntervals();
|
||||||
|
variantDefaultConfig();
|
||||||
|
variantDefaultModuleConfig();
|
||||||
}
|
}
|
||||||
|
|
||||||
void NodeDB::initConfigIntervals()
|
void NodeDB::initConfigIntervals()
|
||||||
@@ -826,7 +836,8 @@ void NodeDB::installDefaultModuleConfig()
|
|||||||
moduleConfig.has_store_forward = true;
|
moduleConfig.has_store_forward = true;
|
||||||
moduleConfig.has_telemetry = true;
|
moduleConfig.has_telemetry = true;
|
||||||
moduleConfig.has_external_notification = true;
|
moduleConfig.has_external_notification = true;
|
||||||
#if defined(PIN_BUZZER) || defined(PIN_VIBRATION) || defined(LED_NOTIFICATION) || defined(PCA_LED_NOTIFICATION)
|
#if defined(PIN_BUZZER) || defined(PIN_VIBRATION) || defined(LED_NOTIFICATION) || defined(PCA_LED_NOTIFICATION) || \
|
||||||
|
defined(NEOPIXEL_STATUS_NOTIFICATION_PIN)
|
||||||
moduleConfig.external_notification.enabled = true;
|
moduleConfig.external_notification.enabled = true;
|
||||||
#endif
|
#endif
|
||||||
#if defined(PIN_BUZZER)
|
#if defined(PIN_BUZZER)
|
||||||
@@ -847,7 +858,7 @@ void NodeDB::installDefaultModuleConfig()
|
|||||||
#endif
|
#endif
|
||||||
#if defined(PIN_VIBRATION)
|
#if defined(PIN_VIBRATION)
|
||||||
moduleConfig.external_notification.nag_timeout = 2;
|
moduleConfig.external_notification.nag_timeout = 2;
|
||||||
#elif defined(PIN_BUZZER) || defined(LED_NOTIFICATION)
|
#elif defined(PIN_BUZZER) || defined(LED_NOTIFICATION) || defined(NEOPIXEL_STATUS_NOTIFICATION_PIN)
|
||||||
moduleConfig.external_notification.nag_timeout = default_ringtone_nag_secs;
|
moduleConfig.external_notification.nag_timeout = default_ringtone_nag_secs;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,75 @@
|
|||||||
|
#include "PositionPrecision.h"
|
||||||
|
#include "Channels.h"
|
||||||
|
#include "mesh-pb-constants.h"
|
||||||
|
|
||||||
|
#include <Arduino.h>
|
||||||
|
|
||||||
|
uint32_t getPositionPrecisionForChannel(uint8_t channelIndex)
|
||||||
|
{
|
||||||
|
const meshtastic_Channel &channel = channels.getByIndex(channelIndex);
|
||||||
|
|
||||||
|
if (channel.settings.has_module_settings) {
|
||||||
|
return channel.settings.module_settings.position_precision;
|
||||||
|
} else if (channel.role == meshtastic_Channel_Role_PRIMARY) {
|
||||||
|
return 32;
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int32_t truncateCoordinate(int32_t coordinate, uint32_t precision)
|
||||||
|
{
|
||||||
|
uint32_t coordinateBits = static_cast<uint32_t>(coordinate);
|
||||||
|
uint32_t truncated = coordinateBits & (UINT32_MAX << (32 - precision));
|
||||||
|
|
||||||
|
// Use the middle of the possible location, not the low edge of the bucket.
|
||||||
|
truncated += (1UL << (31 - precision));
|
||||||
|
|
||||||
|
return static_cast<int32_t>(truncated);
|
||||||
|
}
|
||||||
|
|
||||||
|
void applyPositionPrecision(meshtastic_Position &position, uint32_t precision)
|
||||||
|
{
|
||||||
|
if (precision == 0) {
|
||||||
|
uint32_t time = position.time;
|
||||||
|
position = meshtastic_Position_init_default;
|
||||||
|
position.time = time;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t effectivePrecision = precision > 32 ? 32 : precision;
|
||||||
|
position.precision_bits = effectivePrecision;
|
||||||
|
|
||||||
|
if (effectivePrecision < 32) {
|
||||||
|
position.latitude_i = truncateCoordinate(position.latitude_i, effectivePrecision);
|
||||||
|
position.longitude_i = truncateCoordinate(position.longitude_i, effectivePrecision);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool applyPositionPrecision(meshtastic_MeshPacket &packet, uint32_t precision)
|
||||||
|
{
|
||||||
|
if (packet.which_payload_variant != meshtastic_MeshPacket_decoded_tag ||
|
||||||
|
packet.decoded.portnum != meshtastic_PortNum_POSITION_APP) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
meshtastic_Position position = meshtastic_Position_init_default;
|
||||||
|
if (!pb_decode_from_bytes(packet.decoded.payload.bytes, packet.decoded.payload.size, &meshtastic_Position_msg, &position)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
applyPositionPrecision(position, precision);
|
||||||
|
packet.decoded.payload.size = pb_encode_to_bytes(packet.decoded.payload.bytes, sizeof(packet.decoded.payload.bytes),
|
||||||
|
&meshtastic_Position_msg, &position);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool applyPositionPrecisionForChannel(meshtastic_MeshPacket &packet, uint8_t channelIndex)
|
||||||
|
{
|
||||||
|
if (packet.which_payload_variant != meshtastic_MeshPacket_decoded_tag ||
|
||||||
|
packet.decoded.portnum != meshtastic_PortNum_POSITION_APP) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return applyPositionPrecision(packet, getPositionPrecisionForChannel(channelIndex));
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "meshtastic/mesh.pb.h"
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
uint32_t getPositionPrecisionForChannel(uint8_t channelIndex);
|
||||||
|
void applyPositionPrecision(meshtastic_Position &position, uint32_t precision);
|
||||||
|
bool applyPositionPrecision(meshtastic_MeshPacket &packet, uint32_t precision);
|
||||||
|
bool applyPositionPrecisionForChannel(meshtastic_MeshPacket &packet, uint8_t channelIndex);
|
||||||
@@ -4,6 +4,7 @@
|
|||||||
#include "MeshRadio.h"
|
#include "MeshRadio.h"
|
||||||
#include "MeshService.h"
|
#include "MeshService.h"
|
||||||
#include "NodeDB.h"
|
#include "NodeDB.h"
|
||||||
|
#include "PositionPrecision.h"
|
||||||
#include "RTC.h"
|
#include "RTC.h"
|
||||||
|
|
||||||
#include "configuration.h"
|
#include "configuration.h"
|
||||||
@@ -350,6 +351,11 @@ ErrorCode Router::send(meshtastic_MeshPacket *p)
|
|||||||
}
|
}
|
||||||
|
|
||||||
fixPriority(p); // Before encryption, fix the priority if it's unset
|
fixPriority(p); // Before encryption, fix the priority if it's unset
|
||||||
|
if (!applyPositionPrecisionForChannel(*p, p->channel)) {
|
||||||
|
LOG_ERROR("Dropping malformed position packet before send");
|
||||||
|
packetPool.release(p);
|
||||||
|
return meshtastic_Routing_Error_BAD_REQUEST;
|
||||||
|
}
|
||||||
|
|
||||||
// If the packet is not yet encrypted, do so now
|
// If the packet is not yet encrypted, do so now
|
||||||
if (p->which_payload_variant == meshtastic_MeshPacket_decoded_tag) {
|
if (p->which_payload_variant == meshtastic_MeshPacket_decoded_tag) {
|
||||||
|
|||||||
@@ -15,6 +15,9 @@ PB_BIND(meshtastic_AdminMessage_InputEvent, meshtastic_AdminMessage_InputEvent,
|
|||||||
PB_BIND(meshtastic_AdminMessage_OTAEvent, meshtastic_AdminMessage_OTAEvent, AUTO)
|
PB_BIND(meshtastic_AdminMessage_OTAEvent, meshtastic_AdminMessage_OTAEvent, AUTO)
|
||||||
|
|
||||||
|
|
||||||
|
PB_BIND(meshtastic_LockdownAuth, meshtastic_LockdownAuth, AUTO)
|
||||||
|
|
||||||
|
|
||||||
PB_BIND(meshtastic_HamParameters, meshtastic_HamParameters, AUTO)
|
PB_BIND(meshtastic_HamParameters, meshtastic_HamParameters, AUTO)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -130,6 +130,41 @@ typedef struct _meshtastic_AdminMessage_OTAEvent {
|
|||||||
meshtastic_AdminMessage_OTAEvent_ota_hash_t ota_hash;
|
meshtastic_AdminMessage_OTAEvent_ota_hash_t ota_hash;
|
||||||
} meshtastic_AdminMessage_OTAEvent;
|
} meshtastic_AdminMessage_OTAEvent;
|
||||||
|
|
||||||
|
typedef PB_BYTES_ARRAY_T(32) meshtastic_LockdownAuth_passphrase_t;
|
||||||
|
/* Lockdown passphrase delivery payload.
|
||||||
|
|
||||||
|
One message handles three operations distinguished by content:
|
||||||
|
- Provision (first-time): passphrase set, lock_now=false. Firmware
|
||||||
|
generates DEK, wraps with passphrase-derived KEK, persists.
|
||||||
|
- Unlock: passphrase set, lock_now=false. Firmware verifies
|
||||||
|
passphrase against stored DEK, unlocks storage, authorizes the
|
||||||
|
connection that delivered this packet.
|
||||||
|
- Lock now: lock_now=true, passphrase ignored. Firmware revokes
|
||||||
|
all client auth and reboots into the locked state.
|
||||||
|
|
||||||
|
Firmware decides between provision and unlock based on its own state
|
||||||
|
(whether a DEK file already exists). Clients do not need to track
|
||||||
|
which case applies. */
|
||||||
|
typedef struct _meshtastic_LockdownAuth {
|
||||||
|
/* Passphrase bytes (1-32). Empty when lock_now is true.
|
||||||
|
Capped to 32 to match the proto cap on related security fields. */
|
||||||
|
meshtastic_LockdownAuth_passphrase_t passphrase;
|
||||||
|
/* Optional override of the boot-count token TTL granted on success.
|
||||||
|
0 = use firmware default (TOKEN_DEFAULT_BOOTS).
|
||||||
|
On reboot the firmware decrements this; when it reaches 0 the
|
||||||
|
device boots fully locked and requires a fresh passphrase. */
|
||||||
|
uint32_t boots_remaining;
|
||||||
|
/* Optional wall-clock expiry for the unlock token, as absolute
|
||||||
|
Unix-epoch seconds. 0 = no time limit (only the boot-count TTL
|
||||||
|
applies). On boot, if the device RTC is set and now > this value,
|
||||||
|
the token is treated as expired. */
|
||||||
|
uint32_t valid_until_epoch;
|
||||||
|
/* If true, ignore passphrase fields, immediately revoke all
|
||||||
|
connection-level admin authorization, and reboot the device into
|
||||||
|
the locked state. Always honoured regardless of current lock state. */
|
||||||
|
bool lock_now;
|
||||||
|
} meshtastic_LockdownAuth;
|
||||||
|
|
||||||
/* Parameters for setting up Meshtastic for ameteur radio usage */
|
/* Parameters for setting up Meshtastic for ameteur radio usage */
|
||||||
typedef struct _meshtastic_HamParameters {
|
typedef struct _meshtastic_HamParameters {
|
||||||
/* Amateur radio call sign, eg. KD2ABC */
|
/* Amateur radio call sign, eg. KD2ABC */
|
||||||
@@ -384,6 +419,15 @@ typedef struct _meshtastic_AdminMessage {
|
|||||||
meshtastic_AdminMessage_OTAEvent ota_request;
|
meshtastic_AdminMessage_OTAEvent ota_request;
|
||||||
/* Parameters and sensor configuration */
|
/* Parameters and sensor configuration */
|
||||||
meshtastic_SensorConfig sensor_config;
|
meshtastic_SensorConfig sensor_config;
|
||||||
|
/* Lockdown passphrase delivery / unlock / lock-now command for hardened
|
||||||
|
firmware builds (see MESHTASTIC_LOCKDOWN). Used to provision the
|
||||||
|
passphrase on first boot, unlock encrypted storage on subsequent
|
||||||
|
reboots, re-verify on already-unlocked devices to authorize a new
|
||||||
|
client connection, or immediately re-lock the device.
|
||||||
|
|
||||||
|
Replaces the earlier scheme that repurposed SecurityConfig.private_key
|
||||||
|
to carry passphrase bytes; that hack is retired. */
|
||||||
|
meshtastic_LockdownAuth lockdown_auth;
|
||||||
};
|
};
|
||||||
/* The node generates this key and sends it with any get_x_response packets.
|
/* The node generates this key and sends it with any get_x_response packets.
|
||||||
The client MUST include the same key with any set_x commands. Key expires after 300 seconds.
|
The client MUST include the same key with any set_x commands. Key expires after 300 seconds.
|
||||||
@@ -429,6 +473,7 @@ extern "C" {
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#define meshtastic_KeyVerificationAdmin_message_type_ENUMTYPE meshtastic_KeyVerificationAdmin_MessageType
|
#define meshtastic_KeyVerificationAdmin_message_type_ENUMTYPE meshtastic_KeyVerificationAdmin_MessageType
|
||||||
|
|
||||||
|
|
||||||
@@ -441,6 +486,7 @@ extern "C" {
|
|||||||
#define meshtastic_AdminMessage_init_default {0, {0}, {0, {0}}}
|
#define meshtastic_AdminMessage_init_default {0, {0}, {0, {0}}}
|
||||||
#define meshtastic_AdminMessage_InputEvent_init_default {0, 0, 0, 0}
|
#define meshtastic_AdminMessage_InputEvent_init_default {0, 0, 0, 0}
|
||||||
#define meshtastic_AdminMessage_OTAEvent_init_default {_meshtastic_OTAMode_MIN, {0, {0}}}
|
#define meshtastic_AdminMessage_OTAEvent_init_default {_meshtastic_OTAMode_MIN, {0, {0}}}
|
||||||
|
#define meshtastic_LockdownAuth_init_default {{0, {0}}, 0, 0, 0}
|
||||||
#define meshtastic_HamParameters_init_default {"", 0, 0, ""}
|
#define meshtastic_HamParameters_init_default {"", 0, 0, ""}
|
||||||
#define meshtastic_NodeRemoteHardwarePinsResponse_init_default {0, {meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default}}
|
#define meshtastic_NodeRemoteHardwarePinsResponse_init_default {0, {meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default}}
|
||||||
#define meshtastic_SharedContact_init_default {0, false, meshtastic_User_init_default, 0, 0}
|
#define meshtastic_SharedContact_init_default {0, false, meshtastic_User_init_default, 0, 0}
|
||||||
@@ -453,6 +499,7 @@ extern "C" {
|
|||||||
#define meshtastic_AdminMessage_init_zero {0, {0}, {0, {0}}}
|
#define meshtastic_AdminMessage_init_zero {0, {0}, {0, {0}}}
|
||||||
#define meshtastic_AdminMessage_InputEvent_init_zero {0, 0, 0, 0}
|
#define meshtastic_AdminMessage_InputEvent_init_zero {0, 0, 0, 0}
|
||||||
#define meshtastic_AdminMessage_OTAEvent_init_zero {_meshtastic_OTAMode_MIN, {0, {0}}}
|
#define meshtastic_AdminMessage_OTAEvent_init_zero {_meshtastic_OTAMode_MIN, {0, {0}}}
|
||||||
|
#define meshtastic_LockdownAuth_init_zero {{0, {0}}, 0, 0, 0}
|
||||||
#define meshtastic_HamParameters_init_zero {"", 0, 0, ""}
|
#define meshtastic_HamParameters_init_zero {"", 0, 0, ""}
|
||||||
#define meshtastic_NodeRemoteHardwarePinsResponse_init_zero {0, {meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero}}
|
#define meshtastic_NodeRemoteHardwarePinsResponse_init_zero {0, {meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero}}
|
||||||
#define meshtastic_SharedContact_init_zero {0, false, meshtastic_User_init_zero, 0, 0}
|
#define meshtastic_SharedContact_init_zero {0, false, meshtastic_User_init_zero, 0, 0}
|
||||||
@@ -470,6 +517,10 @@ extern "C" {
|
|||||||
#define meshtastic_AdminMessage_InputEvent_touch_y_tag 4
|
#define meshtastic_AdminMessage_InputEvent_touch_y_tag 4
|
||||||
#define meshtastic_AdminMessage_OTAEvent_reboot_ota_mode_tag 1
|
#define meshtastic_AdminMessage_OTAEvent_reboot_ota_mode_tag 1
|
||||||
#define meshtastic_AdminMessage_OTAEvent_ota_hash_tag 2
|
#define meshtastic_AdminMessage_OTAEvent_ota_hash_tag 2
|
||||||
|
#define meshtastic_LockdownAuth_passphrase_tag 1
|
||||||
|
#define meshtastic_LockdownAuth_boots_remaining_tag 2
|
||||||
|
#define meshtastic_LockdownAuth_valid_until_epoch_tag 3
|
||||||
|
#define meshtastic_LockdownAuth_lock_now_tag 4
|
||||||
#define meshtastic_HamParameters_call_sign_tag 1
|
#define meshtastic_HamParameters_call_sign_tag 1
|
||||||
#define meshtastic_HamParameters_tx_power_tag 2
|
#define meshtastic_HamParameters_tx_power_tag 2
|
||||||
#define meshtastic_HamParameters_frequency_tag 3
|
#define meshtastic_HamParameters_frequency_tag 3
|
||||||
@@ -560,6 +611,7 @@ extern "C" {
|
|||||||
#define meshtastic_AdminMessage_nodedb_reset_tag 100
|
#define meshtastic_AdminMessage_nodedb_reset_tag 100
|
||||||
#define meshtastic_AdminMessage_ota_request_tag 102
|
#define meshtastic_AdminMessage_ota_request_tag 102
|
||||||
#define meshtastic_AdminMessage_sensor_config_tag 103
|
#define meshtastic_AdminMessage_sensor_config_tag 103
|
||||||
|
#define meshtastic_AdminMessage_lockdown_auth_tag 104
|
||||||
#define meshtastic_AdminMessage_session_passkey_tag 101
|
#define meshtastic_AdminMessage_session_passkey_tag 101
|
||||||
|
|
||||||
/* Struct field encoding specification for nanopb */
|
/* Struct field encoding specification for nanopb */
|
||||||
@@ -621,7 +673,8 @@ X(a, STATIC, ONEOF, INT32, (payload_variant,factory_reset_config,factory
|
|||||||
X(a, STATIC, ONEOF, BOOL, (payload_variant,nodedb_reset,nodedb_reset), 100) \
|
X(a, STATIC, ONEOF, BOOL, (payload_variant,nodedb_reset,nodedb_reset), 100) \
|
||||||
X(a, STATIC, SINGULAR, BYTES, session_passkey, 101) \
|
X(a, STATIC, SINGULAR, BYTES, session_passkey, 101) \
|
||||||
X(a, STATIC, ONEOF, MESSAGE, (payload_variant,ota_request,ota_request), 102) \
|
X(a, STATIC, ONEOF, MESSAGE, (payload_variant,ota_request,ota_request), 102) \
|
||||||
X(a, STATIC, ONEOF, MESSAGE, (payload_variant,sensor_config,sensor_config), 103)
|
X(a, STATIC, ONEOF, MESSAGE, (payload_variant,sensor_config,sensor_config), 103) \
|
||||||
|
X(a, STATIC, ONEOF, MESSAGE, (payload_variant,lockdown_auth,lockdown_auth), 104)
|
||||||
#define meshtastic_AdminMessage_CALLBACK NULL
|
#define meshtastic_AdminMessage_CALLBACK NULL
|
||||||
#define meshtastic_AdminMessage_DEFAULT NULL
|
#define meshtastic_AdminMessage_DEFAULT NULL
|
||||||
#define meshtastic_AdminMessage_payload_variant_get_channel_response_MSGTYPE meshtastic_Channel
|
#define meshtastic_AdminMessage_payload_variant_get_channel_response_MSGTYPE meshtastic_Channel
|
||||||
@@ -644,6 +697,7 @@ X(a, STATIC, ONEOF, MESSAGE, (payload_variant,sensor_config,sensor_config)
|
|||||||
#define meshtastic_AdminMessage_payload_variant_key_verification_MSGTYPE meshtastic_KeyVerificationAdmin
|
#define meshtastic_AdminMessage_payload_variant_key_verification_MSGTYPE meshtastic_KeyVerificationAdmin
|
||||||
#define meshtastic_AdminMessage_payload_variant_ota_request_MSGTYPE meshtastic_AdminMessage_OTAEvent
|
#define meshtastic_AdminMessage_payload_variant_ota_request_MSGTYPE meshtastic_AdminMessage_OTAEvent
|
||||||
#define meshtastic_AdminMessage_payload_variant_sensor_config_MSGTYPE meshtastic_SensorConfig
|
#define meshtastic_AdminMessage_payload_variant_sensor_config_MSGTYPE meshtastic_SensorConfig
|
||||||
|
#define meshtastic_AdminMessage_payload_variant_lockdown_auth_MSGTYPE meshtastic_LockdownAuth
|
||||||
|
|
||||||
#define meshtastic_AdminMessage_InputEvent_FIELDLIST(X, a) \
|
#define meshtastic_AdminMessage_InputEvent_FIELDLIST(X, a) \
|
||||||
X(a, STATIC, SINGULAR, UINT32, event_code, 1) \
|
X(a, STATIC, SINGULAR, UINT32, event_code, 1) \
|
||||||
@@ -659,6 +713,14 @@ X(a, STATIC, SINGULAR, BYTES, ota_hash, 2)
|
|||||||
#define meshtastic_AdminMessage_OTAEvent_CALLBACK NULL
|
#define meshtastic_AdminMessage_OTAEvent_CALLBACK NULL
|
||||||
#define meshtastic_AdminMessage_OTAEvent_DEFAULT NULL
|
#define meshtastic_AdminMessage_OTAEvent_DEFAULT NULL
|
||||||
|
|
||||||
|
#define meshtastic_LockdownAuth_FIELDLIST(X, a) \
|
||||||
|
X(a, STATIC, SINGULAR, BYTES, passphrase, 1) \
|
||||||
|
X(a, STATIC, SINGULAR, UINT32, boots_remaining, 2) \
|
||||||
|
X(a, STATIC, SINGULAR, UINT32, valid_until_epoch, 3) \
|
||||||
|
X(a, STATIC, SINGULAR, BOOL, lock_now, 4)
|
||||||
|
#define meshtastic_LockdownAuth_CALLBACK NULL
|
||||||
|
#define meshtastic_LockdownAuth_DEFAULT NULL
|
||||||
|
|
||||||
#define meshtastic_HamParameters_FIELDLIST(X, a) \
|
#define meshtastic_HamParameters_FIELDLIST(X, a) \
|
||||||
X(a, STATIC, SINGULAR, STRING, call_sign, 1) \
|
X(a, STATIC, SINGULAR, STRING, call_sign, 1) \
|
||||||
X(a, STATIC, SINGULAR, INT32, tx_power, 2) \
|
X(a, STATIC, SINGULAR, INT32, tx_power, 2) \
|
||||||
@@ -737,6 +799,7 @@ X(a, STATIC, OPTIONAL, UINT32, set_accuracy, 1)
|
|||||||
extern const pb_msgdesc_t meshtastic_AdminMessage_msg;
|
extern const pb_msgdesc_t meshtastic_AdminMessage_msg;
|
||||||
extern const pb_msgdesc_t meshtastic_AdminMessage_InputEvent_msg;
|
extern const pb_msgdesc_t meshtastic_AdminMessage_InputEvent_msg;
|
||||||
extern const pb_msgdesc_t meshtastic_AdminMessage_OTAEvent_msg;
|
extern const pb_msgdesc_t meshtastic_AdminMessage_OTAEvent_msg;
|
||||||
|
extern const pb_msgdesc_t meshtastic_LockdownAuth_msg;
|
||||||
extern const pb_msgdesc_t meshtastic_HamParameters_msg;
|
extern const pb_msgdesc_t meshtastic_HamParameters_msg;
|
||||||
extern const pb_msgdesc_t meshtastic_NodeRemoteHardwarePinsResponse_msg;
|
extern const pb_msgdesc_t meshtastic_NodeRemoteHardwarePinsResponse_msg;
|
||||||
extern const pb_msgdesc_t meshtastic_SharedContact_msg;
|
extern const pb_msgdesc_t meshtastic_SharedContact_msg;
|
||||||
@@ -751,6 +814,7 @@ extern const pb_msgdesc_t meshtastic_SHTXX_config_msg;
|
|||||||
#define meshtastic_AdminMessage_fields &meshtastic_AdminMessage_msg
|
#define meshtastic_AdminMessage_fields &meshtastic_AdminMessage_msg
|
||||||
#define meshtastic_AdminMessage_InputEvent_fields &meshtastic_AdminMessage_InputEvent_msg
|
#define meshtastic_AdminMessage_InputEvent_fields &meshtastic_AdminMessage_InputEvent_msg
|
||||||
#define meshtastic_AdminMessage_OTAEvent_fields &meshtastic_AdminMessage_OTAEvent_msg
|
#define meshtastic_AdminMessage_OTAEvent_fields &meshtastic_AdminMessage_OTAEvent_msg
|
||||||
|
#define meshtastic_LockdownAuth_fields &meshtastic_LockdownAuth_msg
|
||||||
#define meshtastic_HamParameters_fields &meshtastic_HamParameters_msg
|
#define meshtastic_HamParameters_fields &meshtastic_HamParameters_msg
|
||||||
#define meshtastic_NodeRemoteHardwarePinsResponse_fields &meshtastic_NodeRemoteHardwarePinsResponse_msg
|
#define meshtastic_NodeRemoteHardwarePinsResponse_fields &meshtastic_NodeRemoteHardwarePinsResponse_msg
|
||||||
#define meshtastic_SharedContact_fields &meshtastic_SharedContact_msg
|
#define meshtastic_SharedContact_fields &meshtastic_SharedContact_msg
|
||||||
@@ -768,6 +832,7 @@ extern const pb_msgdesc_t meshtastic_SHTXX_config_msg;
|
|||||||
#define meshtastic_AdminMessage_size 511
|
#define meshtastic_AdminMessage_size 511
|
||||||
#define meshtastic_HamParameters_size 31
|
#define meshtastic_HamParameters_size 31
|
||||||
#define meshtastic_KeyVerificationAdmin_size 25
|
#define meshtastic_KeyVerificationAdmin_size 25
|
||||||
|
#define meshtastic_LockdownAuth_size 48
|
||||||
#define meshtastic_NodeRemoteHardwarePinsResponse_size 496
|
#define meshtastic_NodeRemoteHardwarePinsResponse_size 496
|
||||||
#define meshtastic_SCD30_config_size 27
|
#define meshtastic_SCD30_config_size 27
|
||||||
#define meshtastic_SCD4X_config_size 29
|
#define meshtastic_SCD4X_config_size 29
|
||||||
|
|||||||
@@ -198,7 +198,9 @@ typedef enum _meshtastic_Config_DisplayConfig_OledType {
|
|||||||
/* Can not be auto detected but set by proto. Used for 128x64 screens */
|
/* Can not be auto detected but set by proto. Used for 128x64 screens */
|
||||||
meshtastic_Config_DisplayConfig_OledType_OLED_SH1107 = 3,
|
meshtastic_Config_DisplayConfig_OledType_OLED_SH1107 = 3,
|
||||||
/* Can not be auto detected but set by proto. Used for 128x128 screens */
|
/* Can not be auto detected but set by proto. Used for 128x128 screens */
|
||||||
meshtastic_Config_DisplayConfig_OledType_OLED_SH1107_128_128 = 4
|
meshtastic_Config_DisplayConfig_OledType_OLED_SH1107_128_128 = 4,
|
||||||
|
/* Can not be auto detected but set by proto. Used for 64x128 rotated screens */
|
||||||
|
meshtastic_Config_DisplayConfig_OledType_OLED_SH1107_ROTATED = 5
|
||||||
} meshtastic_Config_DisplayConfig_OledType;
|
} meshtastic_Config_DisplayConfig_OledType;
|
||||||
|
|
||||||
typedef enum _meshtastic_Config_DisplayConfig_DisplayMode {
|
typedef enum _meshtastic_Config_DisplayConfig_DisplayMode {
|
||||||
@@ -720,8 +722,8 @@ extern "C" {
|
|||||||
#define _meshtastic_Config_DisplayConfig_DisplayUnits_ARRAYSIZE ((meshtastic_Config_DisplayConfig_DisplayUnits)(meshtastic_Config_DisplayConfig_DisplayUnits_IMPERIAL+1))
|
#define _meshtastic_Config_DisplayConfig_DisplayUnits_ARRAYSIZE ((meshtastic_Config_DisplayConfig_DisplayUnits)(meshtastic_Config_DisplayConfig_DisplayUnits_IMPERIAL+1))
|
||||||
|
|
||||||
#define _meshtastic_Config_DisplayConfig_OledType_MIN meshtastic_Config_DisplayConfig_OledType_OLED_AUTO
|
#define _meshtastic_Config_DisplayConfig_OledType_MIN meshtastic_Config_DisplayConfig_OledType_OLED_AUTO
|
||||||
#define _meshtastic_Config_DisplayConfig_OledType_MAX meshtastic_Config_DisplayConfig_OledType_OLED_SH1107_128_128
|
#define _meshtastic_Config_DisplayConfig_OledType_MAX meshtastic_Config_DisplayConfig_OledType_OLED_SH1107_ROTATED
|
||||||
#define _meshtastic_Config_DisplayConfig_OledType_ARRAYSIZE ((meshtastic_Config_DisplayConfig_OledType)(meshtastic_Config_DisplayConfig_OledType_OLED_SH1107_128_128+1))
|
#define _meshtastic_Config_DisplayConfig_OledType_ARRAYSIZE ((meshtastic_Config_DisplayConfig_OledType)(meshtastic_Config_DisplayConfig_OledType_OLED_SH1107_ROTATED+1))
|
||||||
|
|
||||||
#define _meshtastic_Config_DisplayConfig_DisplayMode_MIN meshtastic_Config_DisplayConfig_DisplayMode_DEFAULT
|
#define _meshtastic_Config_DisplayConfig_DisplayMode_MIN meshtastic_Config_DisplayConfig_DisplayMode_DEFAULT
|
||||||
#define _meshtastic_Config_DisplayConfig_DisplayMode_MAX meshtastic_Config_DisplayConfig_DisplayMode_COLOR
|
#define _meshtastic_Config_DisplayConfig_DisplayMode_MAX meshtastic_Config_DisplayConfig_DisplayMode_COLOR
|
||||||
|
|||||||
@@ -57,6 +57,9 @@ PB_BIND(meshtastic_QueueStatus, meshtastic_QueueStatus, AUTO)
|
|||||||
PB_BIND(meshtastic_FromRadio, meshtastic_FromRadio, 2)
|
PB_BIND(meshtastic_FromRadio, meshtastic_FromRadio, 2)
|
||||||
|
|
||||||
|
|
||||||
|
PB_BIND(meshtastic_LockdownStatus, meshtastic_LockdownStatus, AUTO)
|
||||||
|
|
||||||
|
|
||||||
PB_BIND(meshtastic_ClientNotification, meshtastic_ClientNotification, 2)
|
PB_BIND(meshtastic_ClientNotification, meshtastic_ClientNotification, 2)
|
||||||
|
|
||||||
|
|
||||||
@@ -134,6 +137,8 @@ PB_BIND(meshtastic_ChunkedPayloadResponse, meshtastic_ChunkedPayloadResponse, AU
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -321,6 +321,10 @@ typedef enum _meshtastic_HardwareModel {
|
|||||||
meshtastic_HardwareModel_HELTEC_MESH_NODE_T1 = 133,
|
meshtastic_HardwareModel_HELTEC_MESH_NODE_T1 = 133,
|
||||||
/* B&Q Consulting Station G3: TBD */
|
/* B&Q Consulting Station G3: TBD */
|
||||||
meshtastic_HardwareModel_STATION_G3 = 134,
|
meshtastic_HardwareModel_STATION_G3 = 134,
|
||||||
|
/* Lilygo T-Impulse-Plus */
|
||||||
|
meshtastic_HardwareModel_T_IMPULSE_PLUS = 135,
|
||||||
|
/* Lilygo T-Echo Card */
|
||||||
|
meshtastic_HardwareModel_T_ECHO_CARD = 136,
|
||||||
/* ------------------------------------------------------------------------------------------------------------------------------------------
|
/* ------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
Reserved ID For developing private Ports. These will show up in live traffic sparsely, so we can use a high number. Keep it within 8 bits.
|
Reserved ID For developing private Ports. These will show up in live traffic sparsely, so we can use a high number. Keep it within 8 bits.
|
||||||
------------------------------------------------------------------------------------------------------------------------------------------ */
|
------------------------------------------------------------------------------------------------------------------------------------------ */
|
||||||
@@ -638,6 +642,25 @@ typedef enum _meshtastic_LogRecord_Level {
|
|||||||
meshtastic_LogRecord_Level_TRACE = 5
|
meshtastic_LogRecord_Level_TRACE = 5
|
||||||
} meshtastic_LogRecord_Level;
|
} meshtastic_LogRecord_Level;
|
||||||
|
|
||||||
|
typedef enum _meshtastic_LockdownStatus_State {
|
||||||
|
/* Default; should not be sent. */
|
||||||
|
meshtastic_LockdownStatus_State_STATE_UNSPECIFIED = 0,
|
||||||
|
/* No passphrase has ever been provisioned on this device.
|
||||||
|
Client should prompt the operator to set one. */
|
||||||
|
meshtastic_LockdownStatus_State_NEEDS_PROVISION = 1,
|
||||||
|
/* Storage is locked or this client has not authenticated yet.
|
||||||
|
lock_reason carries a machine-readable detail string.
|
||||||
|
Client should present (or auto-replay) a passphrase via
|
||||||
|
AdminMessage.lockdown_auth. */
|
||||||
|
meshtastic_LockdownStatus_State_LOCKED = 2,
|
||||||
|
/* Passphrase accepted; client is now authorized for this connection.
|
||||||
|
boots_remaining and valid_until_epoch describe the active session
|
||||||
|
token's TTL. */
|
||||||
|
meshtastic_LockdownStatus_State_UNLOCKED = 3,
|
||||||
|
/* Passphrase rejected. backoff_seconds is non-zero when rate-limited. */
|
||||||
|
meshtastic_LockdownStatus_State_UNLOCK_FAILED = 4
|
||||||
|
} meshtastic_LockdownStatus_State;
|
||||||
|
|
||||||
/* Struct definitions */
|
/* Struct definitions */
|
||||||
/* A GPS Position */
|
/* A GPS Position */
|
||||||
typedef struct _meshtastic_Position {
|
typedef struct _meshtastic_Position {
|
||||||
@@ -1148,6 +1171,38 @@ typedef struct _meshtastic_QueueStatus {
|
|||||||
uint32_t mesh_packet_id;
|
uint32_t mesh_packet_id;
|
||||||
} meshtastic_QueueStatus;
|
} meshtastic_QueueStatus;
|
||||||
|
|
||||||
|
/* Lockdown state report from firmware to client (for hardened builds
|
||||||
|
with MESHTASTIC_LOCKDOWN). Sent immediately after config_complete_id
|
||||||
|
to inform a freshly-connected unauthorized client what it must do,
|
||||||
|
and again in response to each LockdownAuth admin command. */
|
||||||
|
typedef struct _meshtastic_LockdownStatus {
|
||||||
|
/* Current lockdown state being reported. */
|
||||||
|
meshtastic_LockdownStatus_State state;
|
||||||
|
/* For LOCKED: machine-readable reason. Known values:
|
||||||
|
"needs_auth" — storage already unlocked, client must auth
|
||||||
|
"token_missing" — no boot token on flash
|
||||||
|
"token_expired" — boot token wall-clock TTL elapsed
|
||||||
|
"token_boots_zero" — boot token boot-count TTL exhausted
|
||||||
|
"token_hmac_fail" — token tampered or wrong device
|
||||||
|
"token_dek_fail" — token DEK decrypt failed
|
||||||
|
"token_wrong_size" — token file corrupted
|
||||||
|
"token_bad_magic" — token file corrupted
|
||||||
|
"not_provisioned" — should generally use NEEDS_PROVISION state instead
|
||||||
|
Other values may be added; clients should treat unknown values as
|
||||||
|
"locked, ask for passphrase". */
|
||||||
|
char lock_reason[32];
|
||||||
|
/* For UNLOCKED: remaining boots on the issued session token.
|
||||||
|
Decrements by 1 on each subsequent boot. */
|
||||||
|
uint32_t boots_remaining;
|
||||||
|
/* For UNLOCKED: wall-clock expiry of the issued session token,
|
||||||
|
absolute Unix-epoch seconds. 0 = no time limit. */
|
||||||
|
uint32_t valid_until_epoch;
|
||||||
|
/* For UNLOCK_FAILED: seconds the client must wait before another
|
||||||
|
passphrase attempt will be accepted. 0 = wrong passphrase, no
|
||||||
|
backoff (immediate retry allowed but advisable to prompt user). */
|
||||||
|
uint32_t backoff_seconds;
|
||||||
|
} meshtastic_LockdownStatus;
|
||||||
|
|
||||||
typedef struct _meshtastic_KeyVerificationNumberInform {
|
typedef struct _meshtastic_KeyVerificationNumberInform {
|
||||||
uint64_t nonce;
|
uint64_t nonce;
|
||||||
char remote_longname[40];
|
char remote_longname[40];
|
||||||
@@ -1321,6 +1376,12 @@ typedef struct _meshtastic_FromRadio {
|
|||||||
meshtastic_ClientNotification clientNotification;
|
meshtastic_ClientNotification clientNotification;
|
||||||
/* Persistent data for device-ui */
|
/* Persistent data for device-ui */
|
||||||
meshtastic_DeviceUIConfig deviceuiConfig;
|
meshtastic_DeviceUIConfig deviceuiConfig;
|
||||||
|
/* Lockdown state notification for hardened firmware builds.
|
||||||
|
Sent post-config (so unauthorized clients learn they must
|
||||||
|
provision/unlock) and after each LockdownAuth admin command
|
||||||
|
to report success or failure. Replaces the earlier scheme of
|
||||||
|
encoding state as magic-string prefixes inside ClientNotification. */
|
||||||
|
meshtastic_LockdownStatus lockdown_status;
|
||||||
};
|
};
|
||||||
} meshtastic_FromRadio;
|
} meshtastic_FromRadio;
|
||||||
|
|
||||||
@@ -1462,6 +1523,10 @@ extern "C" {
|
|||||||
#define _meshtastic_LogRecord_Level_MAX meshtastic_LogRecord_Level_CRITICAL
|
#define _meshtastic_LogRecord_Level_MAX meshtastic_LogRecord_Level_CRITICAL
|
||||||
#define _meshtastic_LogRecord_Level_ARRAYSIZE ((meshtastic_LogRecord_Level)(meshtastic_LogRecord_Level_CRITICAL+1))
|
#define _meshtastic_LogRecord_Level_ARRAYSIZE ((meshtastic_LogRecord_Level)(meshtastic_LogRecord_Level_CRITICAL+1))
|
||||||
|
|
||||||
|
#define _meshtastic_LockdownStatus_State_MIN meshtastic_LockdownStatus_State_STATE_UNSPECIFIED
|
||||||
|
#define _meshtastic_LockdownStatus_State_MAX meshtastic_LockdownStatus_State_UNLOCK_FAILED
|
||||||
|
#define _meshtastic_LockdownStatus_State_ARRAYSIZE ((meshtastic_LockdownStatus_State)(meshtastic_LockdownStatus_State_UNLOCK_FAILED+1))
|
||||||
|
|
||||||
#define meshtastic_Position_location_source_ENUMTYPE meshtastic_Position_LocSource
|
#define meshtastic_Position_location_source_ENUMTYPE meshtastic_Position_LocSource
|
||||||
#define meshtastic_Position_altitude_source_ENUMTYPE meshtastic_Position_AltSource
|
#define meshtastic_Position_altitude_source_ENUMTYPE meshtastic_Position_AltSource
|
||||||
|
|
||||||
@@ -1492,6 +1557,8 @@ extern "C" {
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#define meshtastic_LockdownStatus_state_ENUMTYPE meshtastic_LockdownStatus_State
|
||||||
|
|
||||||
#define meshtastic_ClientNotification_level_ENUMTYPE meshtastic_LogRecord_Level
|
#define meshtastic_ClientNotification_level_ENUMTYPE meshtastic_LogRecord_Level
|
||||||
|
|
||||||
|
|
||||||
@@ -1532,6 +1599,7 @@ extern "C" {
|
|||||||
#define meshtastic_LogRecord_init_default {"", 0, "", _meshtastic_LogRecord_Level_MIN}
|
#define meshtastic_LogRecord_init_default {"", 0, "", _meshtastic_LogRecord_Level_MIN}
|
||||||
#define meshtastic_QueueStatus_init_default {0, 0, 0, 0}
|
#define meshtastic_QueueStatus_init_default {0, 0, 0, 0}
|
||||||
#define meshtastic_FromRadio_init_default {0, 0, {meshtastic_MeshPacket_init_default}}
|
#define meshtastic_FromRadio_init_default {0, 0, {meshtastic_MeshPacket_init_default}}
|
||||||
|
#define meshtastic_LockdownStatus_init_default {_meshtastic_LockdownStatus_State_MIN, "", 0, 0, 0}
|
||||||
#define meshtastic_ClientNotification_init_default {false, 0, 0, _meshtastic_LogRecord_Level_MIN, "", 0, {meshtastic_KeyVerificationNumberInform_init_default}}
|
#define meshtastic_ClientNotification_init_default {false, 0, 0, _meshtastic_LogRecord_Level_MIN, "", 0, {meshtastic_KeyVerificationNumberInform_init_default}}
|
||||||
#define meshtastic_KeyVerificationNumberInform_init_default {0, "", 0}
|
#define meshtastic_KeyVerificationNumberInform_init_default {0, "", 0}
|
||||||
#define meshtastic_KeyVerificationNumberRequest_init_default {0, ""}
|
#define meshtastic_KeyVerificationNumberRequest_init_default {0, ""}
|
||||||
@@ -1566,6 +1634,7 @@ extern "C" {
|
|||||||
#define meshtastic_LogRecord_init_zero {"", 0, "", _meshtastic_LogRecord_Level_MIN}
|
#define meshtastic_LogRecord_init_zero {"", 0, "", _meshtastic_LogRecord_Level_MIN}
|
||||||
#define meshtastic_QueueStatus_init_zero {0, 0, 0, 0}
|
#define meshtastic_QueueStatus_init_zero {0, 0, 0, 0}
|
||||||
#define meshtastic_FromRadio_init_zero {0, 0, {meshtastic_MeshPacket_init_zero}}
|
#define meshtastic_FromRadio_init_zero {0, 0, {meshtastic_MeshPacket_init_zero}}
|
||||||
|
#define meshtastic_LockdownStatus_init_zero {_meshtastic_LockdownStatus_State_MIN, "", 0, 0, 0}
|
||||||
#define meshtastic_ClientNotification_init_zero {false, 0, 0, _meshtastic_LogRecord_Level_MIN, "", 0, {meshtastic_KeyVerificationNumberInform_init_zero}}
|
#define meshtastic_ClientNotification_init_zero {false, 0, 0, _meshtastic_LogRecord_Level_MIN, "", 0, {meshtastic_KeyVerificationNumberInform_init_zero}}
|
||||||
#define meshtastic_KeyVerificationNumberInform_init_zero {0, "", 0}
|
#define meshtastic_KeyVerificationNumberInform_init_zero {0, "", 0}
|
||||||
#define meshtastic_KeyVerificationNumberRequest_init_zero {0, ""}
|
#define meshtastic_KeyVerificationNumberRequest_init_zero {0, ""}
|
||||||
@@ -1718,6 +1787,11 @@ extern "C" {
|
|||||||
#define meshtastic_QueueStatus_free_tag 2
|
#define meshtastic_QueueStatus_free_tag 2
|
||||||
#define meshtastic_QueueStatus_maxlen_tag 3
|
#define meshtastic_QueueStatus_maxlen_tag 3
|
||||||
#define meshtastic_QueueStatus_mesh_packet_id_tag 4
|
#define meshtastic_QueueStatus_mesh_packet_id_tag 4
|
||||||
|
#define meshtastic_LockdownStatus_state_tag 1
|
||||||
|
#define meshtastic_LockdownStatus_lock_reason_tag 2
|
||||||
|
#define meshtastic_LockdownStatus_boots_remaining_tag 3
|
||||||
|
#define meshtastic_LockdownStatus_valid_until_epoch_tag 4
|
||||||
|
#define meshtastic_LockdownStatus_backoff_seconds_tag 5
|
||||||
#define meshtastic_KeyVerificationNumberInform_nonce_tag 1
|
#define meshtastic_KeyVerificationNumberInform_nonce_tag 1
|
||||||
#define meshtastic_KeyVerificationNumberInform_remote_longname_tag 2
|
#define meshtastic_KeyVerificationNumberInform_remote_longname_tag 2
|
||||||
#define meshtastic_KeyVerificationNumberInform_security_number_tag 3
|
#define meshtastic_KeyVerificationNumberInform_security_number_tag 3
|
||||||
@@ -1777,6 +1851,7 @@ extern "C" {
|
|||||||
#define meshtastic_FromRadio_fileInfo_tag 15
|
#define meshtastic_FromRadio_fileInfo_tag 15
|
||||||
#define meshtastic_FromRadio_clientNotification_tag 16
|
#define meshtastic_FromRadio_clientNotification_tag 16
|
||||||
#define meshtastic_FromRadio_deviceuiConfig_tag 17
|
#define meshtastic_FromRadio_deviceuiConfig_tag 17
|
||||||
|
#define meshtastic_FromRadio_lockdown_status_tag 18
|
||||||
#define meshtastic_Heartbeat_nonce_tag 1
|
#define meshtastic_Heartbeat_nonce_tag 1
|
||||||
#define meshtastic_ToRadio_packet_tag 1
|
#define meshtastic_ToRadio_packet_tag 1
|
||||||
#define meshtastic_ToRadio_want_config_id_tag 3
|
#define meshtastic_ToRadio_want_config_id_tag 3
|
||||||
@@ -2017,7 +2092,8 @@ X(a, STATIC, ONEOF, MESSAGE, (payload_variant,metadata,metadata), 13) \
|
|||||||
X(a, STATIC, ONEOF, MESSAGE, (payload_variant,mqttClientProxyMessage,mqttClientProxyMessage), 14) \
|
X(a, STATIC, ONEOF, MESSAGE, (payload_variant,mqttClientProxyMessage,mqttClientProxyMessage), 14) \
|
||||||
X(a, STATIC, ONEOF, MESSAGE, (payload_variant,fileInfo,fileInfo), 15) \
|
X(a, STATIC, ONEOF, MESSAGE, (payload_variant,fileInfo,fileInfo), 15) \
|
||||||
X(a, STATIC, ONEOF, MESSAGE, (payload_variant,clientNotification,clientNotification), 16) \
|
X(a, STATIC, ONEOF, MESSAGE, (payload_variant,clientNotification,clientNotification), 16) \
|
||||||
X(a, STATIC, ONEOF, MESSAGE, (payload_variant,deviceuiConfig,deviceuiConfig), 17)
|
X(a, STATIC, ONEOF, MESSAGE, (payload_variant,deviceuiConfig,deviceuiConfig), 17) \
|
||||||
|
X(a, STATIC, ONEOF, MESSAGE, (payload_variant,lockdown_status,lockdown_status), 18)
|
||||||
#define meshtastic_FromRadio_CALLBACK NULL
|
#define meshtastic_FromRadio_CALLBACK NULL
|
||||||
#define meshtastic_FromRadio_DEFAULT NULL
|
#define meshtastic_FromRadio_DEFAULT NULL
|
||||||
#define meshtastic_FromRadio_payload_variant_packet_MSGTYPE meshtastic_MeshPacket
|
#define meshtastic_FromRadio_payload_variant_packet_MSGTYPE meshtastic_MeshPacket
|
||||||
@@ -2034,6 +2110,16 @@ X(a, STATIC, ONEOF, MESSAGE, (payload_variant,deviceuiConfig,deviceuiConfi
|
|||||||
#define meshtastic_FromRadio_payload_variant_fileInfo_MSGTYPE meshtastic_FileInfo
|
#define meshtastic_FromRadio_payload_variant_fileInfo_MSGTYPE meshtastic_FileInfo
|
||||||
#define meshtastic_FromRadio_payload_variant_clientNotification_MSGTYPE meshtastic_ClientNotification
|
#define meshtastic_FromRadio_payload_variant_clientNotification_MSGTYPE meshtastic_ClientNotification
|
||||||
#define meshtastic_FromRadio_payload_variant_deviceuiConfig_MSGTYPE meshtastic_DeviceUIConfig
|
#define meshtastic_FromRadio_payload_variant_deviceuiConfig_MSGTYPE meshtastic_DeviceUIConfig
|
||||||
|
#define meshtastic_FromRadio_payload_variant_lockdown_status_MSGTYPE meshtastic_LockdownStatus
|
||||||
|
|
||||||
|
#define meshtastic_LockdownStatus_FIELDLIST(X, a) \
|
||||||
|
X(a, STATIC, SINGULAR, UENUM, state, 1) \
|
||||||
|
X(a, STATIC, SINGULAR, STRING, lock_reason, 2) \
|
||||||
|
X(a, STATIC, SINGULAR, UINT32, boots_remaining, 3) \
|
||||||
|
X(a, STATIC, SINGULAR, UINT32, valid_until_epoch, 4) \
|
||||||
|
X(a, STATIC, SINGULAR, UINT32, backoff_seconds, 5)
|
||||||
|
#define meshtastic_LockdownStatus_CALLBACK NULL
|
||||||
|
#define meshtastic_LockdownStatus_DEFAULT NULL
|
||||||
|
|
||||||
#define meshtastic_ClientNotification_FIELDLIST(X, a) \
|
#define meshtastic_ClientNotification_FIELDLIST(X, a) \
|
||||||
X(a, STATIC, OPTIONAL, UINT32, reply_id, 1) \
|
X(a, STATIC, OPTIONAL, UINT32, reply_id, 1) \
|
||||||
@@ -2194,6 +2280,7 @@ extern const pb_msgdesc_t meshtastic_MyNodeInfo_msg;
|
|||||||
extern const pb_msgdesc_t meshtastic_LogRecord_msg;
|
extern const pb_msgdesc_t meshtastic_LogRecord_msg;
|
||||||
extern const pb_msgdesc_t meshtastic_QueueStatus_msg;
|
extern const pb_msgdesc_t meshtastic_QueueStatus_msg;
|
||||||
extern const pb_msgdesc_t meshtastic_FromRadio_msg;
|
extern const pb_msgdesc_t meshtastic_FromRadio_msg;
|
||||||
|
extern const pb_msgdesc_t meshtastic_LockdownStatus_msg;
|
||||||
extern const pb_msgdesc_t meshtastic_ClientNotification_msg;
|
extern const pb_msgdesc_t meshtastic_ClientNotification_msg;
|
||||||
extern const pb_msgdesc_t meshtastic_KeyVerificationNumberInform_msg;
|
extern const pb_msgdesc_t meshtastic_KeyVerificationNumberInform_msg;
|
||||||
extern const pb_msgdesc_t meshtastic_KeyVerificationNumberRequest_msg;
|
extern const pb_msgdesc_t meshtastic_KeyVerificationNumberRequest_msg;
|
||||||
@@ -2230,6 +2317,7 @@ extern const pb_msgdesc_t meshtastic_ChunkedPayloadResponse_msg;
|
|||||||
#define meshtastic_LogRecord_fields &meshtastic_LogRecord_msg
|
#define meshtastic_LogRecord_fields &meshtastic_LogRecord_msg
|
||||||
#define meshtastic_QueueStatus_fields &meshtastic_QueueStatus_msg
|
#define meshtastic_QueueStatus_fields &meshtastic_QueueStatus_msg
|
||||||
#define meshtastic_FromRadio_fields &meshtastic_FromRadio_msg
|
#define meshtastic_FromRadio_fields &meshtastic_FromRadio_msg
|
||||||
|
#define meshtastic_LockdownStatus_fields &meshtastic_LockdownStatus_msg
|
||||||
#define meshtastic_ClientNotification_fields &meshtastic_ClientNotification_msg
|
#define meshtastic_ClientNotification_fields &meshtastic_ClientNotification_msg
|
||||||
#define meshtastic_KeyVerificationNumberInform_fields &meshtastic_KeyVerificationNumberInform_msg
|
#define meshtastic_KeyVerificationNumberInform_fields &meshtastic_KeyVerificationNumberInform_msg
|
||||||
#define meshtastic_KeyVerificationNumberRequest_fields &meshtastic_KeyVerificationNumberRequest_msg
|
#define meshtastic_KeyVerificationNumberRequest_fields &meshtastic_KeyVerificationNumberRequest_msg
|
||||||
@@ -2265,6 +2353,7 @@ extern const pb_msgdesc_t meshtastic_ChunkedPayloadResponse_msg;
|
|||||||
#define meshtastic_KeyVerificationNumberInform_size 58
|
#define meshtastic_KeyVerificationNumberInform_size 58
|
||||||
#define meshtastic_KeyVerificationNumberRequest_size 52
|
#define meshtastic_KeyVerificationNumberRequest_size 52
|
||||||
#define meshtastic_KeyVerification_size 79
|
#define meshtastic_KeyVerification_size 79
|
||||||
|
#define meshtastic_LockdownStatus_size 53
|
||||||
#define meshtastic_LogRecord_size 426
|
#define meshtastic_LogRecord_size 426
|
||||||
#define meshtastic_LowEntropyKey_size 0
|
#define meshtastic_LowEntropyKey_size 0
|
||||||
#define meshtastic_MeshPacket_size 381
|
#define meshtastic_MeshPacket_size 381
|
||||||
|
|||||||
@@ -144,7 +144,7 @@ typedef struct _meshtastic_ModuleConfig_MQTTConfig {
|
|||||||
(the default official mqtt.meshtastic.org server can handle encrypted packets)
|
(the default official mqtt.meshtastic.org server can handle encrypted packets)
|
||||||
Decrypted packets may be useful for external systems that want to consume meshtastic packets */
|
Decrypted packets may be useful for external systems that want to consume meshtastic packets */
|
||||||
bool encryption_enabled;
|
bool encryption_enabled;
|
||||||
/* Whether to send / consume json packets on MQTT */
|
/* Deprecated: JSON packet support on MQTT was removed, and this field is ignored. */
|
||||||
bool json_enabled;
|
bool json_enabled;
|
||||||
/* If true, we attempt to establish a secure connection using TLS */
|
/* If true, we attempt to establish a secure connection using TLS */
|
||||||
bool tls_enabled;
|
bool tls_enabled;
|
||||||
|
|||||||
@@ -291,10 +291,8 @@ static int32_t reconnectWiFi()
|
|||||||
#endif
|
#endif
|
||||||
return 1000; // check once per second
|
return 1000; // check once per second
|
||||||
} else {
|
} else {
|
||||||
#ifdef ARCH_RP2040
|
onNetworkConnected(); // will only do anything once (guarded by APStartupComplete)
|
||||||
onNetworkConnected(); // will only do anything once
|
return 300000; // every 5 minutes
|
||||||
#endif
|
|
||||||
return 300000; // every 5 minutes
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -343,9 +341,6 @@ bool initWifi()
|
|||||||
const char *wifiPsw = config.network.wifi_psk;
|
const char *wifiPsw = config.network.wifi_psk;
|
||||||
|
|
||||||
#ifndef ARCH_RP2040
|
#ifndef ARCH_RP2040
|
||||||
#if !MESHTASTIC_EXCLUDE_WEBSERVER
|
|
||||||
createSSLCert(); // For WebServer
|
|
||||||
#endif
|
|
||||||
WiFi.persistent(false); // Disable flash storage for WiFi credentials
|
WiFi.persistent(false); // Disable flash storage for WiFi credentials
|
||||||
#endif
|
#endif
|
||||||
if (!*wifiPsw) // Treat empty password as no password
|
if (!*wifiPsw) // Treat empty password as no password
|
||||||
@@ -370,6 +365,9 @@ bool initWifi()
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
#ifdef ARCH_ESP32
|
#ifdef ARCH_ESP32
|
||||||
|
// Register WiFi event handler BEFORE createSSLCert() to prevent race condition:
|
||||||
|
// Without this, WiFi can auto-reconnect during cert generation and fire GOT_IP
|
||||||
|
// before the handler is registered, causing onNetworkConnected() to never run.
|
||||||
WiFi.onEvent(WiFiEvent);
|
WiFi.onEvent(WiFiEvent);
|
||||||
WiFi.setAutoReconnect(true);
|
WiFi.setAutoReconnect(true);
|
||||||
WiFi.setSleep(false);
|
WiFi.setSleep(false);
|
||||||
@@ -391,6 +389,12 @@ bool initWifi()
|
|||||||
wifiDisconnectReason = info.wifi_sta_disconnected.reason;
|
wifiDisconnectReason = info.wifi_sta_disconnected.reason;
|
||||||
},
|
},
|
||||||
WiFiEvent_t::ARDUINO_EVENT_WIFI_STA_DISCONNECTED);
|
WiFiEvent_t::ARDUINO_EVENT_WIFI_STA_DISCONNECTED);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef ARCH_RP2040
|
||||||
|
#if !MESHTASTIC_EXCLUDE_WEBSERVER
|
||||||
|
createSSLCert(); // For WebServer - called after WiFi.onEvent() to avoid race condition
|
||||||
|
#endif
|
||||||
#endif
|
#endif
|
||||||
LOG_DEBUG("JOINING WIFI soon: ssid=%s", wifiName);
|
LOG_DEBUG("JOINING WIFI soon: ssid=%s", wifiName);
|
||||||
wifiReconnect = new Periodic("WifiConnect", reconnectWiFi);
|
wifiReconnect = new Periodic("WifiConnect", reconnectWiFi);
|
||||||
|
|||||||
@@ -206,6 +206,10 @@ void ExternalNotificationModule::setExternalState(uint8_t index, bool on)
|
|||||||
#ifdef PCA_LED_NOTIFICATION
|
#ifdef PCA_LED_NOTIFICATION
|
||||||
io.digitalWrite(PCA_LED_NOTIFICATION, on);
|
io.digitalWrite(PCA_LED_NOTIFICATION, on);
|
||||||
|
|
||||||
|
#endif
|
||||||
|
#ifdef NEOPIXEL_STATUS_NOTIFICATION_PIN
|
||||||
|
notificationPixel.setPixelColor(0, on ? NEOPIXEL_STATUS_NOTIFICATION_COLOR : 0);
|
||||||
|
notificationPixel.show();
|
||||||
#endif
|
#endif
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -324,6 +328,12 @@ ExternalNotificationModule::ExternalNotificationModule()
|
|||||||
LOG_INFO("Use Pin %i in digital mode", output);
|
LOG_INFO("Use Pin %i in digital mode", output);
|
||||||
pinMode(output, OUTPUT);
|
pinMode(output, OUTPUT);
|
||||||
}
|
}
|
||||||
|
#ifdef NEOPIXEL_STATUS_NOTIFICATION_PIN
|
||||||
|
LOG_INFO("Use WS2812 on GPIO %d as notification LED", NEOPIXEL_STATUS_NOTIFICATION_PIN);
|
||||||
|
notificationPixel.begin();
|
||||||
|
notificationPixel.clear();
|
||||||
|
notificationPixel.show();
|
||||||
|
#endif
|
||||||
setExternalState(0, false);
|
setExternalState(0, false);
|
||||||
externalTurnedOn[0] = 0;
|
externalTurnedOn[0] = 0;
|
||||||
if (moduleConfig.external_notification.output_vibra) {
|
if (moduleConfig.external_notification.output_vibra) {
|
||||||
|
|||||||
@@ -10,6 +10,19 @@
|
|||||||
extern AmbientLightingThread *ambientLightingThread;
|
extern AmbientLightingThread *ambientLightingThread;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
// Drive a single WS2812 as the notification LED (M1/M2-style LED_NOTIFICATION
|
||||||
|
// but addressable). A variant defines NEOPIXEL_STATUS_NOTIFICATION_PIN to
|
||||||
|
// enable. Colour defaults to green but can be overridden.
|
||||||
|
#ifdef NEOPIXEL_STATUS_NOTIFICATION_PIN
|
||||||
|
#include <Adafruit_NeoPixel.h>
|
||||||
|
#ifndef NEOPIXEL_STATUS_TYPE
|
||||||
|
#define NEOPIXEL_STATUS_TYPE (NEO_GRB + NEO_KHZ800)
|
||||||
|
#endif
|
||||||
|
#ifndef NEOPIXEL_STATUS_NOTIFICATION_COLOR
|
||||||
|
#define NEOPIXEL_STATUS_NOTIFICATION_COLOR 0x00FF00 // green
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
#if !defined(ARCH_PORTDUINO) && !defined(ARCH_STM32WL) && !defined(CONFIG_IDF_TARGET_ESP32C6)
|
#if !defined(ARCH_PORTDUINO) && !defined(ARCH_STM32WL) && !defined(CONFIG_IDF_TARGET_ESP32C6)
|
||||||
#include <NonBlockingRtttl.h>
|
#include <NonBlockingRtttl.h>
|
||||||
#else
|
#else
|
||||||
@@ -38,6 +51,10 @@ class ExternalNotificationModule : public SinglePortModule, private concurrency:
|
|||||||
CallbackObserver<ExternalNotificationModule, const InputEvent *>(this, &ExternalNotificationModule::handleInputEvent);
|
CallbackObserver<ExternalNotificationModule, const InputEvent *>(this, &ExternalNotificationModule::handleInputEvent);
|
||||||
uint32_t output = 0;
|
uint32_t output = 0;
|
||||||
|
|
||||||
|
#ifdef NEOPIXEL_STATUS_NOTIFICATION_PIN
|
||||||
|
Adafruit_NeoPixel notificationPixel = Adafruit_NeoPixel(1, NEOPIXEL_STATUS_NOTIFICATION_PIN, NEOPIXEL_STATUS_TYPE);
|
||||||
|
#endif
|
||||||
|
|
||||||
public:
|
public:
|
||||||
ExternalNotificationModule();
|
ExternalNotificationModule();
|
||||||
|
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
#include "GPS.h"
|
#include "GPS.h"
|
||||||
#include "MeshService.h"
|
#include "MeshService.h"
|
||||||
#include "NodeDB.h"
|
#include "NodeDB.h"
|
||||||
|
#include "PositionPrecision.h"
|
||||||
#include "RTC.h"
|
#include "RTC.h"
|
||||||
#include "Router.h"
|
#include "Router.h"
|
||||||
#include "TransmitHistory.h"
|
#include "TransmitHistory.h"
|
||||||
@@ -107,13 +108,7 @@ bool PositionModule::handleReceivedProtobuf(const meshtastic_MeshPacket &mp, mes
|
|||||||
}
|
}
|
||||||
|
|
||||||
nodeDB->updatePosition(getFrom(&mp), p);
|
nodeDB->updatePosition(getFrom(&mp), p);
|
||||||
if (channels.getByIndex(mp.channel).settings.has_module_settings) {
|
precision = getPositionPrecisionForChannel(mp.channel);
|
||||||
precision = channels.getByIndex(mp.channel).settings.module_settings.position_precision;
|
|
||||||
} else if (channels.getByIndex(mp.channel).role == meshtastic_Channel_Role_PRIMARY) {
|
|
||||||
precision = 32;
|
|
||||||
} else {
|
|
||||||
precision = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false; // Let others look at this message also if they want
|
return false; // Let others look at this message also if they want
|
||||||
}
|
}
|
||||||
@@ -121,15 +116,12 @@ bool PositionModule::handleReceivedProtobuf(const meshtastic_MeshPacket &mp, mes
|
|||||||
void PositionModule::alterReceivedProtobuf(meshtastic_MeshPacket &mp, meshtastic_Position *p)
|
void PositionModule::alterReceivedProtobuf(meshtastic_MeshPacket &mp, meshtastic_Position *p)
|
||||||
{
|
{
|
||||||
// Phone position packets need to be truncated to the channel precision
|
// Phone position packets need to be truncated to the channel precision
|
||||||
if (isFromUs(&mp) && (precision < 32 && precision > 0)) {
|
if (isFromUs(&mp)) {
|
||||||
LOG_DEBUG("Truncate phone position to channel precision %i", precision);
|
if (precision == 0)
|
||||||
p->latitude_i = p->latitude_i & (UINT32_MAX << (32 - precision));
|
LOG_DEBUG("Strip phone position due to channel precision 0");
|
||||||
p->longitude_i = p->longitude_i & (UINT32_MAX << (32 - precision));
|
else if (precision < 32)
|
||||||
|
LOG_DEBUG("Truncate phone position to channel precision %i", precision);
|
||||||
// We want the imprecise position to be the middle of the possible location, not
|
applyPositionPrecision(*p, precision);
|
||||||
p->latitude_i += (1 << (31 - precision));
|
|
||||||
p->longitude_i += (1 << (31 - precision));
|
|
||||||
|
|
||||||
mp.decoded.payload.size =
|
mp.decoded.payload.size =
|
||||||
pb_encode_to_bytes(mp.decoded.payload.bytes, sizeof(mp.decoded.payload.bytes), &meshtastic_Position_msg, p);
|
pb_encode_to_bytes(mp.decoded.payload.bytes, sizeof(mp.decoded.payload.bytes), &meshtastic_Position_msg, p);
|
||||||
}
|
}
|
||||||
@@ -205,20 +197,11 @@ meshtastic_MeshPacket *PositionModule::allocPositionPacket()
|
|||||||
|
|
||||||
// lat/lon are unconditionally included - IF AVAILABLE!
|
// lat/lon are unconditionally included - IF AVAILABLE!
|
||||||
LOG_DEBUG("Send location with precision %i", precision);
|
LOG_DEBUG("Send location with precision %i", precision);
|
||||||
if (precision < 32 && precision > 0) {
|
p.latitude_i = localPosition.latitude_i;
|
||||||
p.latitude_i = localPosition.latitude_i & (UINT32_MAX << (32 - precision));
|
p.longitude_i = localPosition.longitude_i;
|
||||||
p.longitude_i = localPosition.longitude_i & (UINT32_MAX << (32 - precision));
|
|
||||||
|
|
||||||
// We want the imprecise position to be the middle of the possible location, not
|
|
||||||
p.latitude_i += (1 << (31 - precision));
|
|
||||||
p.longitude_i += (1 << (31 - precision));
|
|
||||||
} else {
|
|
||||||
p.latitude_i = localPosition.latitude_i;
|
|
||||||
p.longitude_i = localPosition.longitude_i;
|
|
||||||
}
|
|
||||||
p.precision_bits = precision;
|
|
||||||
p.has_latitude_i = true;
|
p.has_latitude_i = true;
|
||||||
p.has_longitude_i = true;
|
p.has_longitude_i = true;
|
||||||
|
applyPositionPrecision(p, precision);
|
||||||
// Always use NTP / GPS time if available
|
// Always use NTP / GPS time if available
|
||||||
if (getValidTime(RTCQualityNTP) > 0) {
|
if (getValidTime(RTCQualityNTP) > 0) {
|
||||||
p.time = getValidTime(RTCQualityNTP);
|
p.time = getValidTime(RTCQualityNTP);
|
||||||
@@ -349,8 +332,7 @@ void PositionModule::sendOurPosition()
|
|||||||
// If we changed channels, ask everyone else for their latest info
|
// If we changed channels, ask everyone else for their latest info
|
||||||
LOG_INFO("Send pos@%x:6 to mesh (wantReplies=%d)", localPosition.timestamp, requestReplies);
|
LOG_INFO("Send pos@%x:6 to mesh (wantReplies=%d)", localPosition.timestamp, requestReplies);
|
||||||
for (uint8_t channelNum = 0; channelNum < 8; channelNum++) {
|
for (uint8_t channelNum = 0; channelNum < 8; channelNum++) {
|
||||||
if (channels.getByIndex(channelNum).settings.has_module_settings &&
|
if (getPositionPrecisionForChannel(channelNum) != 0) {
|
||||||
channels.getByIndex(channelNum).settings.module_settings.position_precision != 0) {
|
|
||||||
sendOurPosition(NODENUM_BROADCAST, requestReplies, channelNum);
|
sendOurPosition(NODENUM_BROADCAST, requestReplies, channelNum);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -368,10 +350,8 @@ void PositionModule::sendOurPosition(NodeNum dest, bool wantReplies, uint8_t cha
|
|||||||
if (prevPacketId) // if we wrap around to zero, we'll simply fail to cancel in that rare case (no big deal)
|
if (prevPacketId) // if we wrap around to zero, we'll simply fail to cancel in that rare case (no big deal)
|
||||||
service->cancelSending(prevPacketId);
|
service->cancelSending(prevPacketId);
|
||||||
|
|
||||||
// Set's the class precision value for this particular packet
|
// Set the class precision value for this particular packet.
|
||||||
if (channels.getByIndex(channel).settings.has_module_settings) {
|
precision = getPositionPrecisionForChannel(channel);
|
||||||
precision = channels.getByIndex(channel).settings.module_settings.position_precision;
|
|
||||||
}
|
|
||||||
|
|
||||||
meshtastic_MeshPacket *p = allocPositionPacket();
|
meshtastic_MeshPacket *p = allocPositionPacket();
|
||||||
if (p == nullptr) {
|
if (p == nullptr) {
|
||||||
|
|||||||
@@ -17,8 +17,29 @@ StatusLEDModule::StatusLEDModule() : concurrency::OSThread("StatusLEDModule")
|
|||||||
if (inputBroker)
|
if (inputBroker)
|
||||||
inputObserver.observe(inputBroker);
|
inputObserver.observe(inputBroker);
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef NEOPIXEL_STATUS_POWER_PIN
|
||||||
|
powerPixel.begin();
|
||||||
|
powerPixel.clear();
|
||||||
|
powerPixel.show();
|
||||||
|
#endif
|
||||||
|
#ifdef NEOPIXEL_STATUS_PAIRING_PIN
|
||||||
|
pairingPixel.begin();
|
||||||
|
pairingPixel.clear();
|
||||||
|
pairingPixel.show();
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Helper: write a 1-pixel NeoPixel strand to `color` when stateOn, else clear.
|
||||||
|
// Kept as a static inline here (rather than a member) so it compiles out
|
||||||
|
// completely when no NeoPixel status pins are defined.
|
||||||
|
#if defined(NEOPIXEL_STATUS_POWER_PIN) || defined(NEOPIXEL_STATUS_PAIRING_PIN)
|
||||||
|
static inline void writeStatusPixel(Adafruit_NeoPixel &pixel, uint32_t color, bool stateOn)
|
||||||
|
{
|
||||||
|
pixel.setPixelColor(0, stateOn ? color : 0);
|
||||||
|
pixel.show();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
int StatusLEDModule::handleStatusUpdate(const meshtastic::Status *arg)
|
int StatusLEDModule::handleStatusUpdate(const meshtastic::Status *arg)
|
||||||
{
|
{
|
||||||
switch (arg->getStatusType()) {
|
switch (arg->getStatusType()) {
|
||||||
@@ -176,6 +197,12 @@ int32_t StatusLEDModule::runOnce()
|
|||||||
#ifdef LED_PAIRING
|
#ifdef LED_PAIRING
|
||||||
digitalWrite(LED_PAIRING, PAIRING_LED_state);
|
digitalWrite(LED_PAIRING, PAIRING_LED_state);
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef NEOPIXEL_STATUS_POWER_PIN
|
||||||
|
writeStatusPixel(powerPixel, NEOPIXEL_STATUS_POWER_COLOR, CHARGE_LED_state == LED_STATE_ON);
|
||||||
|
#endif
|
||||||
|
#ifdef NEOPIXEL_STATUS_PAIRING_PIN
|
||||||
|
writeStatusPixel(pairingPixel, NEOPIXEL_STATUS_PAIRING_COLOR, PAIRING_LED_state == LED_STATE_ON);
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef RGB_LED_POWER
|
#ifdef RGB_LED_POWER
|
||||||
if (!config.device.led_heartbeat_disabled) {
|
if (!config.device.led_heartbeat_disabled) {
|
||||||
@@ -225,6 +252,12 @@ void StatusLEDModule::setPowerLED(bool LEDon)
|
|||||||
#ifdef LED_PAIRING
|
#ifdef LED_PAIRING
|
||||||
digitalWrite(LED_PAIRING, ledState);
|
digitalWrite(LED_PAIRING, ledState);
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef NEOPIXEL_STATUS_POWER_PIN
|
||||||
|
writeStatusPixel(powerPixel, NEOPIXEL_STATUS_POWER_COLOR, LEDon);
|
||||||
|
#endif
|
||||||
|
#ifdef NEOPIXEL_STATUS_PAIRING_PIN
|
||||||
|
writeStatusPixel(pairingPixel, NEOPIXEL_STATUS_PAIRING_COLOR, LEDon);
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef Battery_LED_1
|
#ifdef Battery_LED_1
|
||||||
digitalWrite(Battery_LED_1, ledState);
|
digitalWrite(Battery_LED_1, ledState);
|
||||||
|
|||||||
@@ -13,6 +13,25 @@
|
|||||||
#include "input/InputBroker.h"
|
#include "input/InputBroker.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
// WS2812/NeoPixel status-LED support. A variant may define
|
||||||
|
// NEOPIXEL_STATUS_POWER_PIN (required to enable the power/charge pixel)
|
||||||
|
// NEOPIXEL_STATUS_POWER_COLOR (optional, default red 0xFF0000)
|
||||||
|
// NEOPIXEL_STATUS_PAIRING_PIN / _COLOR (default blue 0x0000FF)
|
||||||
|
// Each pixel is a standalone 1-LED strand on its own GPIO — this mirrors how
|
||||||
|
// boards like the LilyGo T-Echo-Card expose three independent WS2812s.
|
||||||
|
#if defined(NEOPIXEL_STATUS_POWER_PIN) || defined(NEOPIXEL_STATUS_PAIRING_PIN)
|
||||||
|
#include <Adafruit_NeoPixel.h>
|
||||||
|
#ifndef NEOPIXEL_STATUS_TYPE
|
||||||
|
#define NEOPIXEL_STATUS_TYPE (NEO_GRB + NEO_KHZ800)
|
||||||
|
#endif
|
||||||
|
#ifndef NEOPIXEL_STATUS_POWER_COLOR
|
||||||
|
#define NEOPIXEL_STATUS_POWER_COLOR 0xFF0000 // red
|
||||||
|
#endif
|
||||||
|
#ifndef NEOPIXEL_STATUS_PAIRING_COLOR
|
||||||
|
#define NEOPIXEL_STATUS_PAIRING_COLOR 0x0000FF // blue
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
class StatusLEDModule : private concurrency::OSThread
|
class StatusLEDModule : private concurrency::OSThread
|
||||||
{
|
{
|
||||||
bool slowTrack = false;
|
bool slowTrack = false;
|
||||||
@@ -27,6 +46,13 @@ class StatusLEDModule : private concurrency::OSThread
|
|||||||
|
|
||||||
void setPowerLED(bool);
|
void setPowerLED(bool);
|
||||||
|
|
||||||
|
#ifdef NEOPIXEL_STATUS_POWER_PIN
|
||||||
|
Adafruit_NeoPixel powerPixel = Adafruit_NeoPixel(1, NEOPIXEL_STATUS_POWER_PIN, NEOPIXEL_STATUS_TYPE);
|
||||||
|
#endif
|
||||||
|
#ifdef NEOPIXEL_STATUS_PAIRING_PIN
|
||||||
|
Adafruit_NeoPixel pairingPixel = Adafruit_NeoPixel(1, NEOPIXEL_STATUS_PAIRING_PIN, NEOPIXEL_STATUS_TYPE);
|
||||||
|
#endif
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
unsigned int my_interval = 1000; // interval in millisconds
|
unsigned int my_interval = 1000; // interval in millisconds
|
||||||
virtual int32_t runOnce() override;
|
virtual int32_t runOnce() override;
|
||||||
|
|||||||
@@ -610,7 +610,7 @@ class NimbleBluetoothServerCallback : public NimBLEServerCallbacks
|
|||||||
display->setTextAlignment(TEXT_ALIGN_CENTER);
|
display->setTextAlignment(TEXT_ALIGN_CENTER);
|
||||||
display->setFont(FONT_MEDIUM);
|
display->setFont(FONT_MEDIUM);
|
||||||
display->drawString(x_offset + x, y_offset + y, "Bluetooth");
|
display->drawString(x_offset + x, y_offset + y, "Bluetooth");
|
||||||
#if !defined(M5STACK_UNITC6L)
|
#if !defined(OLED_TINY)
|
||||||
display->setFont(FONT_SMALL);
|
display->setFont(FONT_SMALL);
|
||||||
y_offset = display->height() == 64 ? y_offset + FONT_HEIGHT_MEDIUM - 4 : y_offset + FONT_HEIGHT_MEDIUM + 5;
|
y_offset = display->height() == 64 ? y_offset + FONT_HEIGHT_MEDIUM - 4 : y_offset + FONT_HEIGHT_MEDIUM + 5;
|
||||||
display->drawString(x_offset + x, y_offset + y, "Enter this code");
|
display->drawString(x_offset + x, y_offset + y, "Enter this code");
|
||||||
|
|||||||
@@ -158,6 +158,8 @@
|
|||||||
#define HW_VENDOR meshtastic_HardwareModel_CHATTER_2
|
#define HW_VENDOR meshtastic_HardwareModel_CHATTER_2
|
||||||
#elif defined(STATION_G2)
|
#elif defined(STATION_G2)
|
||||||
#define HW_VENDOR meshtastic_HardwareModel_STATION_G2
|
#define HW_VENDOR meshtastic_HardwareModel_STATION_G2
|
||||||
|
#elif defined(STATION_G3)
|
||||||
|
#define HW_VENDOR meshtastic_HardwareModel_STATION_G3
|
||||||
#elif defined(UNPHONE)
|
#elif defined(UNPHONE)
|
||||||
#define HW_VENDOR meshtastic_HardwareModel_UNPHONE
|
#define HW_VENDOR meshtastic_HardwareModel_UNPHONE
|
||||||
#elif defined(WIPHONE)
|
#elif defined(WIPHONE)
|
||||||
|
|||||||
+55
-1
@@ -1,13 +1,65 @@
|
|||||||
#include "AudioBoard.h"
|
|
||||||
#include "configuration.h"
|
#include "configuration.h"
|
||||||
|
|
||||||
|
#ifdef M5STACK_CARDPUTER_ADV
|
||||||
|
|
||||||
|
#include "AudioBoard.h"
|
||||||
|
#include <Wire.h>
|
||||||
|
|
||||||
DriverPins PinsAudioBoardES8311;
|
DriverPins PinsAudioBoardES8311;
|
||||||
AudioBoard board(AudioDriverES8311, PinsAudioBoardES8311);
|
AudioBoard board(AudioDriverES8311, PinsAudioBoardES8311);
|
||||||
|
|
||||||
|
// PI4IOE5V6408 on the optional Cap LoRa-1262 (and Cap LoRa868).
|
||||||
|
#define PI4IO_ADDR 0x43
|
||||||
|
#define PI4IO_REG_IO_DIR 0x03
|
||||||
|
#define PI4IO_REG_OUT_SET 0x05
|
||||||
|
#define PI4IO_REG_OUT_H_IM 0x07
|
||||||
|
|
||||||
|
static TwoWire *findLoraCapBus()
|
||||||
|
{
|
||||||
|
TwoWire *candidates[] = {&Wire1, &Wire};
|
||||||
|
for (size_t i = 0; i < sizeof(candidates) / sizeof(candidates[0]); ++i) {
|
||||||
|
candidates[i]->beginTransmission(PI4IO_ADDR);
|
||||||
|
if (candidates[i]->endTransmission() == 0) {
|
||||||
|
return candidates[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool pi4ioWrite(TwoWire *bus, uint8_t reg, uint8_t val)
|
||||||
|
{
|
||||||
|
bus->beginTransmission(PI4IO_ADDR);
|
||||||
|
bus->write(reg);
|
||||||
|
bus->write(val);
|
||||||
|
uint8_t status = bus->endTransmission();
|
||||||
|
if (status != 0) {
|
||||||
|
LOG_DEBUG("PI4IO write reg=0x%02x val=0x%02x failed, I2C status=%u", reg, val, status);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void initLoraCap()
|
||||||
|
{
|
||||||
|
TwoWire *bus = findLoraCapBus();
|
||||||
|
if (!bus) {
|
||||||
|
LOG_ERROR("Cap LoRa-1262 not found");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
bool ok = pi4ioWrite(bus, PI4IO_REG_IO_DIR, 0b00000001);
|
||||||
|
ok = ok && pi4ioWrite(bus, PI4IO_REG_OUT_H_IM, 0b00000000);
|
||||||
|
ok = ok && pi4ioWrite(bus, PI4IO_REG_OUT_SET, 0b00000001);
|
||||||
|
if (!ok) {
|
||||||
|
LOG_ERROR("Antenna switch init failed");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// M5stack Cardputer ADV specific init
|
// M5stack Cardputer ADV specific init
|
||||||
|
|
||||||
void lateInitVariant()
|
void lateInitVariant()
|
||||||
{
|
{
|
||||||
|
initLoraCap();
|
||||||
|
|
||||||
// AudioDriverLogger.begin(Serial, AudioDriverLogLevel::Debug);
|
// AudioDriverLogger.begin(Serial, AudioDriverLogLevel::Debug);
|
||||||
// I2C: function, scl, sda
|
// I2C: function, scl, sda
|
||||||
PinsAudioBoardES8311.addI2C(PinFunction::CODEC, Wire);
|
PinsAudioBoardES8311.addI2C(PinFunction::CODEC, Wire);
|
||||||
@@ -38,3 +90,5 @@ void lateInitVariant()
|
|||||||
es8311_write_reg(0x32, 0xBF); // DAC volume (0dB)
|
es8311_write_reg(0x32, 0xBF); // DAC volume (0dB)
|
||||||
es8311_write_reg(0x37, 0x08); // EQ bypass
|
es8311_write_reg(0x37, 0x08); // EQ bypass
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -85,6 +85,8 @@
|
|||||||
#define HW_VENDOR meshtastic_HardwareModel_T_ECHO
|
#define HW_VENDOR meshtastic_HardwareModel_T_ECHO
|
||||||
#elif defined(T_ECHO_LITE)
|
#elif defined(T_ECHO_LITE)
|
||||||
#define HW_VENDOR meshtastic_HardwareModel_T_ECHO_LITE
|
#define HW_VENDOR meshtastic_HardwareModel_T_ECHO_LITE
|
||||||
|
#elif defined(T_ECHO_CARD)
|
||||||
|
#define HW_VENDOR meshtastic_HardwareModel_T_ECHO_CARD
|
||||||
#elif defined(TTGO_T_ECHO_PLUS)
|
#elif defined(TTGO_T_ECHO_PLUS)
|
||||||
#define HW_VENDOR meshtastic_HardwareModel_T_ECHO_PLUS
|
#define HW_VENDOR meshtastic_HardwareModel_T_ECHO_PLUS
|
||||||
#elif defined(ELECROW_ThinkNode_M1)
|
#elif defined(ELECROW_ThinkNode_M1)
|
||||||
|
|||||||
@@ -0,0 +1,100 @@
|
|||||||
|
#include "PositionPrecision.h"
|
||||||
|
#include "TestUtil.h"
|
||||||
|
#include "mesh-pb-constants.h"
|
||||||
|
#include <unity.h>
|
||||||
|
|
||||||
|
static meshtastic_Position makePosition()
|
||||||
|
{
|
||||||
|
meshtastic_Position position = meshtastic_Position_init_default;
|
||||||
|
position.has_latitude_i = true;
|
||||||
|
position.latitude_i = static_cast<int32_t>(0x12345678);
|
||||||
|
position.has_longitude_i = true;
|
||||||
|
position.longitude_i = static_cast<int32_t>(0x22345678);
|
||||||
|
position.has_altitude = true;
|
||||||
|
position.altitude = 123;
|
||||||
|
position.time = 42;
|
||||||
|
position.location_source = meshtastic_Position_LocSource_LOC_EXTERNAL;
|
||||||
|
position.timestamp = 43;
|
||||||
|
position.sats_in_view = 10;
|
||||||
|
return position;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void test_applyPositionPrecision_clampsLatLonAndSetsPrecisionBits()
|
||||||
|
{
|
||||||
|
meshtastic_Position position = makePosition();
|
||||||
|
|
||||||
|
applyPositionPrecision(position, 16);
|
||||||
|
|
||||||
|
TEST_ASSERT_EQUAL_INT32(static_cast<int32_t>(0x12348000), position.latitude_i);
|
||||||
|
TEST_ASSERT_EQUAL_INT32(static_cast<int32_t>(0x22348000), position.longitude_i);
|
||||||
|
TEST_ASSERT_EQUAL_UINT32(16, position.precision_bits);
|
||||||
|
TEST_ASSERT_TRUE(position.has_latitude_i);
|
||||||
|
TEST_ASSERT_TRUE(position.has_longitude_i);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void test_applyPositionPrecision_fullPrecisionKeepsLatLon()
|
||||||
|
{
|
||||||
|
meshtastic_Position position = makePosition();
|
||||||
|
|
||||||
|
applyPositionPrecision(position, 32);
|
||||||
|
|
||||||
|
TEST_ASSERT_EQUAL_INT32(static_cast<int32_t>(0x12345678), position.latitude_i);
|
||||||
|
TEST_ASSERT_EQUAL_INT32(static_cast<int32_t>(0x22345678), position.longitude_i);
|
||||||
|
TEST_ASSERT_EQUAL_UINT32(32, position.precision_bits);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void test_applyPositionPrecision_zeroScrubsLocationButKeepsTime()
|
||||||
|
{
|
||||||
|
meshtastic_Position position = makePosition();
|
||||||
|
|
||||||
|
applyPositionPrecision(position, 0);
|
||||||
|
|
||||||
|
TEST_ASSERT_FALSE(position.has_latitude_i);
|
||||||
|
TEST_ASSERT_EQUAL_INT32(0, position.latitude_i);
|
||||||
|
TEST_ASSERT_FALSE(position.has_longitude_i);
|
||||||
|
TEST_ASSERT_EQUAL_INT32(0, position.longitude_i);
|
||||||
|
TEST_ASSERT_FALSE(position.has_altitude);
|
||||||
|
TEST_ASSERT_EQUAL_INT32(0, position.altitude);
|
||||||
|
TEST_ASSERT_EQUAL_UINT32(42, position.time);
|
||||||
|
TEST_ASSERT_EQUAL_UINT32(0, position.timestamp);
|
||||||
|
TEST_ASSERT_EQUAL_UINT32(0, position.sats_in_view);
|
||||||
|
TEST_ASSERT_EQUAL_UINT32(0, position.precision_bits);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void test_applyPositionPrecision_reencodesPositionPacket()
|
||||||
|
{
|
||||||
|
meshtastic_Position position = makePosition();
|
||||||
|
meshtastic_MeshPacket packet = meshtastic_MeshPacket_init_default;
|
||||||
|
packet.which_payload_variant = meshtastic_MeshPacket_decoded_tag;
|
||||||
|
packet.decoded.portnum = meshtastic_PortNum_POSITION_APP;
|
||||||
|
packet.decoded.payload.size = pb_encode_to_bytes(packet.decoded.payload.bytes, sizeof(packet.decoded.payload.bytes),
|
||||||
|
&meshtastic_Position_msg, &position);
|
||||||
|
|
||||||
|
TEST_ASSERT_TRUE(applyPositionPrecision(packet, 16));
|
||||||
|
|
||||||
|
meshtastic_Position decoded = meshtastic_Position_init_default;
|
||||||
|
TEST_ASSERT_TRUE(
|
||||||
|
pb_decode_from_bytes(packet.decoded.payload.bytes, packet.decoded.payload.size, &meshtastic_Position_msg, &decoded));
|
||||||
|
TEST_ASSERT_EQUAL_INT32(static_cast<int32_t>(0x12348000), decoded.latitude_i);
|
||||||
|
TEST_ASSERT_EQUAL_INT32(static_cast<int32_t>(0x22348000), decoded.longitude_i);
|
||||||
|
TEST_ASSERT_EQUAL_UINT32(16, decoded.precision_bits);
|
||||||
|
}
|
||||||
|
|
||||||
|
void setUp(void) {}
|
||||||
|
|
||||||
|
void tearDown(void) {}
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
void setup()
|
||||||
|
{
|
||||||
|
initializeTestEnvironment();
|
||||||
|
UNITY_BEGIN();
|
||||||
|
RUN_TEST(test_applyPositionPrecision_clampsLatLonAndSetsPrecisionBits);
|
||||||
|
RUN_TEST(test_applyPositionPrecision_fullPrecisionKeepsLatLon);
|
||||||
|
RUN_TEST(test_applyPositionPrecision_zeroScrubsLocationButKeepsTime);
|
||||||
|
RUN_TEST(test_applyPositionPrecision_reencodesPositionPacket);
|
||||||
|
exit(UNITY_END());
|
||||||
|
}
|
||||||
|
|
||||||
|
void loop() {}
|
||||||
|
}
|
||||||
@@ -52,23 +52,25 @@ void c6l_init()
|
|||||||
vTaskDelay(10 / portTICK_PERIOD_MS);
|
vTaskDelay(10 / portTICK_PERIOD_MS);
|
||||||
i2c_read_byte(PI4IO_M_ADDR, PI4IO_REG_CHIP_RESET, &in_data);
|
i2c_read_byte(PI4IO_M_ADDR, PI4IO_REG_CHIP_RESET, &in_data);
|
||||||
vTaskDelay(10 / portTICK_PERIOD_MS);
|
vTaskDelay(10 / portTICK_PERIOD_MS);
|
||||||
i2c_write_byte(PI4IO_M_ADDR, PI4IO_REG_IO_DIR, 0b11000000); // 0: input 1: output
|
i2c_write_byte(PI4IO_M_ADDR, PI4IO_REG_IO_DIR, 0b11100000); // P5,P6,P7 as outputs
|
||||||
vTaskDelay(10 / portTICK_PERIOD_MS);
|
vTaskDelay(10 / portTICK_PERIOD_MS);
|
||||||
i2c_write_byte(PI4IO_M_ADDR, PI4IO_REG_OUT_H_IM, 0b00111100); // 使用到的引脚关闭High-Impedance
|
i2c_write_byte(PI4IO_M_ADDR, PI4IO_REG_OUT_H_IM, 0b00011100); // High-Impedance
|
||||||
vTaskDelay(10 / portTICK_PERIOD_MS);
|
vTaskDelay(10 / portTICK_PERIOD_MS);
|
||||||
i2c_write_byte(PI4IO_M_ADDR, PI4IO_REG_PULL_SEL, 0b11000011); // pull up/down select, 0 down, 1 up
|
i2c_write_byte(PI4IO_M_ADDR, PI4IO_REG_PULL_SEL, 0b11100011); // pull up/down select, 0 down, 1 up
|
||||||
vTaskDelay(10 / portTICK_PERIOD_MS);
|
vTaskDelay(10 / portTICK_PERIOD_MS);
|
||||||
i2c_write_byte(PI4IO_M_ADDR, PI4IO_REG_PULL_EN, 0b11000011); // pull up/down enable, 0 disable, 1 enable
|
i2c_write_byte(PI4IO_M_ADDR, PI4IO_REG_PULL_EN, 0b11100011); // pull up/down enable, 0 disable, 1 enable
|
||||||
vTaskDelay(10 / portTICK_PERIOD_MS);
|
vTaskDelay(10 / portTICK_PERIOD_MS);
|
||||||
i2c_write_byte(PI4IO_M_ADDR, PI4IO_REG_IN_DEF_STA, 0b00000011); // P0 P1 默认高电平, 按键按下触发中断
|
i2c_write_byte(PI4IO_M_ADDR, PI4IO_REG_IN_DEF_STA, 0b00000011); // P0 P1 default to high level; button press triggers the interrupt
|
||||||
vTaskDelay(10 / portTICK_PERIOD_MS);
|
vTaskDelay(10 / portTICK_PERIOD_MS);
|
||||||
i2c_write_byte(PI4IO_M_ADDR, PI4IO_REG_INT_MASK, 0b11111100); // P0 P1 中断使能 0 enable, 1 disable
|
i2c_write_byte(PI4IO_M_ADDR, PI4IO_REG_INT_MASK, 0b11111100); // P0 P1 interrupts enabled (0 = enable, 1 = disable)
|
||||||
vTaskDelay(10 / portTICK_PERIOD_MS);
|
vTaskDelay(10 / portTICK_PERIOD_MS);
|
||||||
i2c_write_byte(PI4IO_M_ADDR, PI4IO_REG_OUT_SET, 0b10000000); // 默认输出为0
|
i2c_write_byte(PI4IO_M_ADDR, PI4IO_REG_OUT_SET, 0b10000000); // default output is 0
|
||||||
|
vTaskDelay(10 / portTICK_PERIOD_MS);
|
||||||
|
i2c_read_byte(PI4IO_M_ADDR, PI4IO_REG_IRQ_STA, &in_data); // read IRQ_STA to clear the flag
|
||||||
vTaskDelay(10 / portTICK_PERIOD_MS);
|
vTaskDelay(10 / portTICK_PERIOD_MS);
|
||||||
i2c_read_byte(PI4IO_M_ADDR, PI4IO_REG_IRQ_STA, &in_data); // 读取IRQ_STA清除标志
|
|
||||||
|
|
||||||
i2c_read_byte(PI4IO_M_ADDR, PI4IO_REG_OUT_SET, &in_data);
|
i2c_read_byte(PI4IO_M_ADDR, PI4IO_REG_OUT_SET, &in_data);
|
||||||
setbit(in_data, 6); // HIGH
|
setbit(in_data, 6); // enable SX_ANT_SW
|
||||||
|
setbit(in_data, 5); // enable SX_LNA_EN
|
||||||
i2c_write_byte(PI4IO_M_ADDR, PI4IO_REG_OUT_SET, in_data);
|
i2c_write_byte(PI4IO_M_ADDR, PI4IO_REG_OUT_SET, in_data);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -48,6 +48,9 @@ void c6l_init();
|
|||||||
#define SSD1306_RESET 15
|
#define SSD1306_RESET 15
|
||||||
// #define OLED_DG 1
|
// #define OLED_DG 1
|
||||||
#endif
|
#endif
|
||||||
|
// Tiny OLED panel — opts into compile-time layout/font/feature substitutions
|
||||||
|
// gated on OLED_TINY across the graphics stack.
|
||||||
|
#define OLED_TINY
|
||||||
#define SCREEN_TRANSITION_FRAMERATE 10
|
#define SCREEN_TRANSITION_FRAMERATE 10
|
||||||
#define BRIGHTNESS_DEFAULT 130 // Medium Low Brightness
|
#define BRIGHTNESS_DEFAULT 130 // Medium Low Brightness
|
||||||
|
|
||||||
|
|||||||
@@ -12,7 +12,11 @@ build_flags =
|
|||||||
-mfix-esp32-psram-cache-issue
|
-mfix-esp32-psram-cache-issue
|
||||||
|
|
||||||
lib_ignore =
|
lib_ignore =
|
||||||
Ethernet
|
Ethernet
|
||||||
|
|
||||||
|
build_src_filter =
|
||||||
|
${esp32s3_base.build_src_filter}
|
||||||
|
+<../variants/esp32s3/ELECROW-ThinkNode-G3/*>
|
||||||
|
|
||||||
lib_deps =
|
lib_deps =
|
||||||
${esp32s3_base.lib_deps}
|
${esp32s3_base.lib_deps}
|
||||||
|
|||||||
@@ -0,0 +1,6 @@
|
|||||||
|
#include "mesh/NodeDB.h"
|
||||||
|
|
||||||
|
void variantDefaultConfig()
|
||||||
|
{
|
||||||
|
config.network.eth_enabled = true;
|
||||||
|
}
|
||||||
@@ -11,7 +11,11 @@ build_flags =
|
|||||||
-mfix-esp32-psram-cache-issue
|
-mfix-esp32-psram-cache-issue
|
||||||
|
|
||||||
lib_ignore =
|
lib_ignore =
|
||||||
Ethernet
|
Ethernet
|
||||||
|
|
||||||
|
build_src_filter =
|
||||||
|
${esp32s3_base.build_src_filter}
|
||||||
|
+<../variants/esp32s3/ELECROW-ThinkNode-M7/*>
|
||||||
|
|
||||||
lib_deps =
|
lib_deps =
|
||||||
${esp32s3_base.lib_deps}
|
${esp32s3_base.lib_deps}
|
||||||
|
|||||||
@@ -0,0 +1,6 @@
|
|||||||
|
#include "mesh/NodeDB.h"
|
||||||
|
|
||||||
|
void variantDefaultConfig()
|
||||||
|
{
|
||||||
|
config.network.eth_enabled = true;
|
||||||
|
}
|
||||||
@@ -10,9 +10,6 @@ build_flags =
|
|||||||
-D M5STACK_CARDPUTER_ADV
|
-D M5STACK_CARDPUTER_ADV
|
||||||
-D ARDUINO_USB_CDC_ON_BOOT=1
|
-D ARDUINO_USB_CDC_ON_BOOT=1
|
||||||
-I variants/esp32s3/m5stack_cardputer_adv
|
-I variants/esp32s3/m5stack_cardputer_adv
|
||||||
build_src_filter =
|
|
||||||
${esp32s3_base.build_src_filter}
|
|
||||||
+<../variants/esp32s3/m5stack_cardputer_adv>
|
|
||||||
lib_deps =
|
lib_deps =
|
||||||
${esp32s3_base.lib_deps}
|
${esp32s3_base.lib_deps}
|
||||||
# renovate: datasource=git-refs depName=meshtastic-st7789 packageName=https://github.com/meshtastic/st7789 gitBranch=main
|
# renovate: datasource=git-refs depName=meshtastic-st7789 packageName=https://github.com/meshtastic/st7789 gitBranch=main
|
||||||
|
|||||||
@@ -9,6 +9,7 @@
|
|||||||
#define ST7789_BUSY -1
|
#define ST7789_BUSY -1
|
||||||
// #define VTFT_CTRL 38
|
// #define VTFT_CTRL 38
|
||||||
#define VTFT_LEDA 38
|
#define VTFT_LEDA 38
|
||||||
|
#define TFT_BACKLIGHT_ON HIGH
|
||||||
// #define ST7789_BL (32+6)
|
// #define ST7789_BL (32+6)
|
||||||
#define ST7789_SPI_HOST SPI2_HOST
|
#define ST7789_SPI_HOST SPI2_HOST
|
||||||
// #define TFT_BL (32+6)
|
// #define TFT_BL (32+6)
|
||||||
|
|||||||
@@ -0,0 +1,38 @@
|
|||||||
|
// Shared pin/feature defines for BQ Station G2 and G3.
|
||||||
|
// Boards differ only in PA output power (SX126X_MAX_POWER) and the wiki URL.
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
// Station G2/G3 may not have GPS installed, but have a GROVE GPS Socket for an optional GPS module
|
||||||
|
#define GPS_RX_PIN 7
|
||||||
|
#define GPS_TX_PIN 15
|
||||||
|
|
||||||
|
// 1.3 inch OLED Screen
|
||||||
|
#define USE_SH1107_128_64
|
||||||
|
|
||||||
|
#define I2C_SDA 5
|
||||||
|
#define I2C_SCL 6
|
||||||
|
|
||||||
|
#define BUTTON_PIN 38 // Program button
|
||||||
|
#define BUTTON_NEED_PULLUP
|
||||||
|
|
||||||
|
#define USE_SX1262
|
||||||
|
|
||||||
|
#define LORA_MISO 14
|
||||||
|
#define LORA_SCK 12
|
||||||
|
#define LORA_MOSI 13
|
||||||
|
#define LORA_CS 11
|
||||||
|
|
||||||
|
#define LORA_RESET 21
|
||||||
|
#define LORA_DIO1 48
|
||||||
|
|
||||||
|
#ifdef USE_SX1262
|
||||||
|
#define SX126X_CS LORA_CS // Compatibility alias; prefer LORA_CS in board definitions.
|
||||||
|
#define SX126X_DIO1 LORA_DIO1
|
||||||
|
#define SX126X_BUSY 47
|
||||||
|
#define SX126X_RESET LORA_RESET
|
||||||
|
|
||||||
|
// DIO2 controls an antenna switch and the TCXO voltage is controlled by DIO3
|
||||||
|
#define SX126X_DIO2_AS_RF_SWITCH
|
||||||
|
#define SX126X_DIO3_TCXO_VOLTAGE 1.8
|
||||||
|
// NOTE: SX126X_MAX_POWER is intentionally NOT defined here — each board sets it.
|
||||||
|
#endif
|
||||||
@@ -22,10 +22,11 @@ upload_speed = 921600
|
|||||||
build_unflags =
|
build_unflags =
|
||||||
${esp32s3_base.build_unflags}
|
${esp32s3_base.build_unflags}
|
||||||
-DARDUINO_USB_MODE=0
|
-DARDUINO_USB_MODE=0
|
||||||
build_flags =
|
build_flags =
|
||||||
${esp32s3_base.build_flags}
|
${esp32s3_base.build_flags}
|
||||||
-D STATION_G2
|
-D STATION_G2
|
||||||
-I variants/esp32s3/station-g2
|
-I variants/esp32s3/station-g2
|
||||||
|
-I variants/esp32s3/station-common
|
||||||
-DBOARD_HAS_PSRAM
|
-DBOARD_HAS_PSRAM
|
||||||
-DSTATION_G2
|
-DSTATION_G2
|
||||||
-DARDUINO_USB_MODE=1
|
-DARDUINO_USB_MODE=1
|
||||||
|
|||||||
@@ -2,39 +2,9 @@
|
|||||||
Board Information: https://wiki.uniteng.com/en/meshtastic/station-g2
|
Board Information: https://wiki.uniteng.com/en/meshtastic/station-g2
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// Station G2 may not have GPS installed, but it has a GROVE GPS Socket for Optional GPS Module
|
#include "station_common.h"
|
||||||
#define GPS_RX_PIN 7
|
|
||||||
#define GPS_TX_PIN 15
|
|
||||||
|
|
||||||
// Station G2 has 1.3 inch OLED Screen
|
|
||||||
#define USE_SH1107_128_64
|
|
||||||
|
|
||||||
#define I2C_SDA 5 // I2C pins for this board
|
|
||||||
#define I2C_SCL 6
|
|
||||||
|
|
||||||
#define BUTTON_PIN 38 // This is the Program Button
|
|
||||||
#define BUTTON_NEED_PULLUP
|
|
||||||
|
|
||||||
#define USE_SX1262
|
|
||||||
|
|
||||||
#define LORA_MISO 14
|
|
||||||
#define LORA_SCK 12
|
|
||||||
#define LORA_MOSI 13
|
|
||||||
#define LORA_CS 11
|
|
||||||
|
|
||||||
#define LORA_RESET 21
|
|
||||||
#define LORA_DIO1 48
|
|
||||||
|
|
||||||
#ifdef USE_SX1262
|
#ifdef USE_SX1262
|
||||||
#define SX126X_CS LORA_CS // FIXME - we really should define LORA_CS instead
|
|
||||||
#define SX126X_DIO1 LORA_DIO1
|
|
||||||
#define SX126X_BUSY 47
|
|
||||||
#define SX126X_RESET LORA_RESET
|
|
||||||
|
|
||||||
// DIO2 controlls an antenna switch and the TCXO voltage is controlled by DIO3
|
|
||||||
#define SX126X_DIO2_AS_RF_SWITCH
|
|
||||||
#define SX126X_DIO3_TCXO_VOLTAGE 1.8
|
|
||||||
|
|
||||||
// Ensure the PA does not exceed the saturation output power. More
|
// Ensure the PA does not exceed the saturation output power. More
|
||||||
// Info:https://wiki.uniteng.com/en/meshtastic/station-g2#summary-for-lora-power-amplifier-conduction-test
|
// Info:https://wiki.uniteng.com/en/meshtastic/station-g2#summary-for-lora-power-amplifier-conduction-test
|
||||||
#define SX126X_MAX_POWER 19
|
#define SX126X_MAX_POWER 19
|
||||||
|
|||||||
@@ -0,0 +1,21 @@
|
|||||||
|
#ifndef Pins_Arduino_h
|
||||||
|
#define Pins_Arduino_h
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#define USB_VID 0x303a
|
||||||
|
#define USB_PID 0x1001
|
||||||
|
|
||||||
|
// GPIO48 Reference: https://github.com/espressif/arduino-esp32/pull/8600
|
||||||
|
|
||||||
|
// The default Wire will be mapped to Screen and Sensors
|
||||||
|
static const uint8_t SDA = 5;
|
||||||
|
static const uint8_t SCL = 6;
|
||||||
|
|
||||||
|
// Default SPI will be mapped to Radio
|
||||||
|
static const uint8_t MISO = 14;
|
||||||
|
static const uint8_t SCK = 12;
|
||||||
|
static const uint8_t MOSI = 13;
|
||||||
|
static const uint8_t SS = 11;
|
||||||
|
|
||||||
|
#endif /* Pins_Arduino_h */
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
[env:station-g3]
|
||||||
|
custom_meshtastic_hw_model = 134
|
||||||
|
custom_meshtastic_hw_model_slug = STATION_G3
|
||||||
|
custom_meshtastic_architecture = esp32-s3
|
||||||
|
custom_meshtastic_actively_supported = true
|
||||||
|
custom_meshtastic_support_level = 2
|
||||||
|
custom_meshtastic_display_name = Station G3
|
||||||
|
custom_meshtastic_images = station-g3.svg
|
||||||
|
custom_meshtastic_tags = B&Q
|
||||||
|
custom_meshtastic_requires_dfu = true
|
||||||
|
custom_meshtastic_partition_scheme = 16MB
|
||||||
|
|
||||||
|
extends = esp32s3_base
|
||||||
|
board = station-g3
|
||||||
|
board_level = pr
|
||||||
|
board_check = true
|
||||||
|
board_build.partitions = default_16MB.csv
|
||||||
|
board_build.mcu = esp32s3
|
||||||
|
upload_protocol = esptool
|
||||||
|
;upload_port = /dev/ttyACM0
|
||||||
|
upload_speed = 921600
|
||||||
|
build_unflags =
|
||||||
|
${esp32s3_base.build_unflags}
|
||||||
|
-DARDUINO_USB_MODE=0
|
||||||
|
build_flags =
|
||||||
|
${esp32s3_base.build_flags}
|
||||||
|
-D STATION_G3
|
||||||
|
-I variants/esp32s3/station-g3
|
||||||
|
-I variants/esp32s3/station-common
|
||||||
|
-DBOARD_HAS_PSRAM
|
||||||
|
-DSTATION_G3
|
||||||
|
-DARDUINO_USB_MODE=1
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
#include "station_common.h"
|
||||||
|
|
||||||
|
#ifdef USE_SX1262
|
||||||
|
// Station G3 reuses the same Fast-Transient DC-DC PA design as G2 (BQ35LORA900V1M).
|
||||||
|
// PA Operating Mode is set in hardware via the PA-PL1 / PA-PL2 jumpers.
|
||||||
|
// 19 matches the G2 cap (SX1262 19 dBm in → ~31 dBm PA out at Power Level 1, ISM compliant).
|
||||||
|
// Raise (max 22) only if running a higher PA Power Level and you can stay within local band limits.
|
||||||
|
#define SX126X_MAX_POWER 19
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
#define BATTERY_PIN 4 // A battery voltage measurement pin, voltage divider connected here to measure battery voltage
|
||||||
|
#define ADC_CHANNEL ADC1_GPIO4_CHANNEL
|
||||||
|
#define ADC_MULTIPLIER 4
|
||||||
|
#define BATTERY_SENSE_SAMPLES 15 // Set the number of samples, It has an effect of increasing sensitivity.
|
||||||
|
#define BAT_FULLVOLT 8400
|
||||||
|
#define BAT_EMPTYVOLT 5000
|
||||||
|
#define BAT_CHARGINGVOLT 8400
|
||||||
|
#define BAT_NOBATVOLT 4460
|
||||||
|
#define CELL_TYPE_LION // same curve for liion/lipo
|
||||||
|
#define NUM_CELLS 2
|
||||||
|
*/
|
||||||
@@ -29,7 +29,7 @@ lib_deps =
|
|||||||
# renovate: datasource=custom.pio depName=LovyanGFX packageName=lovyan03/library/LovyanGFX
|
# renovate: datasource=custom.pio depName=LovyanGFX packageName=lovyan03/library/LovyanGFX
|
||||||
lovyan03/LovyanGFX@1.2.21
|
lovyan03/LovyanGFX@1.2.21
|
||||||
; # renovate: datasource=git-refs depName=libch341-spi-userspace packageName=https://github.com/pine64/libch341-spi-userspace gitBranch=main
|
; # renovate: datasource=git-refs depName=libch341-spi-userspace packageName=https://github.com/pine64/libch341-spi-userspace gitBranch=main
|
||||||
https://github.com/pine64/libch341-spi-userspace/archive/23c42319a69cffcb65868e3c72e6bed83974a393.zip
|
https://github.com/pine64/libch341-spi-userspace/archive/2e5ff751d0c39667993df672cb683740ed5c9394.zip
|
||||||
# renovate: datasource=custom.pio depName=adafruit/Adafruit seesaw Library packageName=adafruit/library/Adafruit seesaw Library
|
# renovate: datasource=custom.pio depName=adafruit/Adafruit seesaw Library packageName=adafruit/library/Adafruit seesaw Library
|
||||||
adafruit/Adafruit seesaw Library@1.7.9
|
adafruit/Adafruit seesaw Library@1.7.9
|
||||||
# renovate: datasource=git-refs depName=RAK12034-BMX160 packageName=https://github.com/RAKWireless/RAK12034-BMX160 gitBranch=main
|
# renovate: datasource=git-refs depName=RAK12034-BMX160 packageName=https://github.com/RAKWireless/RAK12034-BMX160 gitBranch=main
|
||||||
|
|||||||
@@ -0,0 +1,11 @@
|
|||||||
|
[env:t-echo-card]
|
||||||
|
extends = nrf52840_base
|
||||||
|
board = t-echo
|
||||||
|
board_level = extra
|
||||||
|
debug_tool = jlink
|
||||||
|
|
||||||
|
build_flags = ${nrf52840_base.build_flags}
|
||||||
|
-I variants/nrf52840/t-echo-card
|
||||||
|
-D T_ECHO_CARD
|
||||||
|
|
||||||
|
build_src_filter = ${nrf52_base.build_src_filter} +<../variants/nrf52840/t-echo-card>
|
||||||
@@ -0,0 +1,66 @@
|
|||||||
|
/*
|
||||||
|
Copyright (c) 2014-2015 Arduino LLC. All right reserved.
|
||||||
|
Copyright (c) 2016 Sandeep Mistry All right reserved.
|
||||||
|
Copyright (c) 2018, Adafruit Industries (adafruit.com)
|
||||||
|
|
||||||
|
This library is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU Lesser General Public
|
||||||
|
License as published by the Free Software Foundation; either
|
||||||
|
version 2.1 of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
This library is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
See the GNU Lesser General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General Public
|
||||||
|
License along with this library; if not, write to the Free Software
|
||||||
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "variant.h"
|
||||||
|
#include "Arduino.h"
|
||||||
|
#include "nrf.h"
|
||||||
|
#include "wiring_constants.h"
|
||||||
|
#include "wiring_digital.h"
|
||||||
|
|
||||||
|
const uint32_t g_ADigitalPinMap[] = {
|
||||||
|
// P0 - pins 0 and 1 are hardwired for xtal and should never be enabled
|
||||||
|
0xff, 0xff, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
|
||||||
|
|
||||||
|
// P1
|
||||||
|
32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47};
|
||||||
|
|
||||||
|
void initVariant()
|
||||||
|
{
|
||||||
|
// No plain GPIO LEDs on this board (only WS2812 addressable LEDs, not driven here).
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reproduces the vendor firmware's boot sequence from
|
||||||
|
// examples/original_test/original_test.ino. Runs before Meshtastic touches
|
||||||
|
// PIN_POWER_EN, so the RT9080 LDO gets a clean reset pulse and peripherals
|
||||||
|
// whose EN pins must be LOW at boot (GPS_EN, GPS_RF_EN, BUZZER) aren't left
|
||||||
|
// floating while the 3V3 rail is ramping.
|
||||||
|
void earlyInitVariant()
|
||||||
|
{
|
||||||
|
// 3.3V rail: toggle RT9080_EN HIGH → LOW → HIGH with 100 ms dwell so the
|
||||||
|
// LDO enters enable from a known state. The single-shot HIGH in main.cpp
|
||||||
|
// is not enough on this hardware — if the chip was in a half-enabled
|
||||||
|
// state from a previous reset, the rail brown-outs once LoRa TX fires.
|
||||||
|
pinMode(PIN_POWER_EN, OUTPUT);
|
||||||
|
digitalWrite(PIN_POWER_EN, HIGH);
|
||||||
|
delay(100);
|
||||||
|
digitalWrite(PIN_POWER_EN, LOW);
|
||||||
|
delay(100);
|
||||||
|
digitalWrite(PIN_POWER_EN, HIGH);
|
||||||
|
delay(100);
|
||||||
|
|
||||||
|
// Park peripherals with active-high enables LOW so they don't sink
|
||||||
|
// current while the rest of setup() runs.
|
||||||
|
pinMode(PIN_GPS_STANDBY, OUTPUT);
|
||||||
|
digitalWrite(PIN_GPS_STANDBY, LOW);
|
||||||
|
pinMode(PIN_GPS_RESET, OUTPUT);
|
||||||
|
digitalWrite(PIN_GPS_RESET, LOW);
|
||||||
|
pinMode(PIN_BUZZER, OUTPUT);
|
||||||
|
digitalWrite(PIN_BUZZER, LOW);
|
||||||
|
}
|
||||||
@@ -0,0 +1,202 @@
|
|||||||
|
// Variant definition for LilyGo T-Echo-Card (nRF52840)
|
||||||
|
|
||||||
|
#ifndef _VARIANT_T_ECHO_CARD_
|
||||||
|
#define _VARIANT_T_ECHO_CARD_
|
||||||
|
|
||||||
|
/** Master clock frequency */
|
||||||
|
#define VARIANT_MCK (64000000ul)
|
||||||
|
|
||||||
|
#define USE_LFXO // Board uses 32kHz crystal for LF
|
||||||
|
|
||||||
|
/*----------------------------------------------------------------------------
|
||||||
|
* Headers
|
||||||
|
*----------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
#include "WVariant.h"
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif // __cplusplus
|
||||||
|
|
||||||
|
// Number of pins defined in PinDescription array
|
||||||
|
#define PINS_COUNT (48)
|
||||||
|
#define NUM_DIGITAL_PINS (48)
|
||||||
|
#define NUM_ANALOG_INPUTS (1)
|
||||||
|
#define NUM_ANALOG_OUTPUTS (0)
|
||||||
|
|
||||||
|
// LEDs - board only exposes 3x WS2812 addressable LEDs. No plain GPIO LEDs.
|
||||||
|
// Intentionally do not define PIN_LED1 on this variant, so nRF52 platform
|
||||||
|
// code does not auto-enable a nonexistent GPIO power/status LED.
|
||||||
|
#define LED_STATE_ON 1
|
||||||
|
|
||||||
|
// Three independent WS2812 data lines (one LED per line, not a daisy chain).
|
||||||
|
// Each is driven as a 1-pixel NeoPixel by StatusLEDModule / ExternalNotification,
|
||||||
|
// assigns LED_POWER (red) and LED_NOTIFICATION (green).
|
||||||
|
#define WS2812_DATA_1 (32 + 7) // P1.7 - charge/heartbeat (red)
|
||||||
|
#define WS2812_DATA_2 (32 + 12) // P1.12 - external notification (green)
|
||||||
|
#define WS2812_DATA_3 (0 + 28) // P0.28 - BLE pairing (blue)
|
||||||
|
|
||||||
|
// Wire each WS2812 to a status role. Colour defaults are scaled to 25%
|
||||||
|
// brightness (0x40) — the bare-die WS2812s on this board are very bright at
|
||||||
|
// full intensity in a close-range enclosure.
|
||||||
|
#define NEOPIXEL_STATUS_POWER_PIN WS2812_DATA_1
|
||||||
|
#define NEOPIXEL_STATUS_NOTIFICATION_PIN WS2812_DATA_2
|
||||||
|
#define NEOPIXEL_STATUS_PAIRING_PIN WS2812_DATA_3
|
||||||
|
#define NEOPIXEL_STATUS_POWER_COLOR 0x400000 // red @ 25%
|
||||||
|
#define NEOPIXEL_STATUS_NOTIFICATION_COLOR 0x004000 // green @ 25%
|
||||||
|
#define NEOPIXEL_STATUS_PAIRING_COLOR 0x000040 // blue @ 25%
|
||||||
|
|
||||||
|
// The charger IC does not blink on its own; let StatusLEDModule do the
|
||||||
|
// software blink while charging
|
||||||
|
// If left defined: hardware would be expected to handle the charging pulse.
|
||||||
|
// #define POWER_LED_HARDWARE_BLINKS_WHILE_CHARGING
|
||||||
|
|
||||||
|
// Buttons
|
||||||
|
#define PIN_BUTTON1 (32 + 10) // KEY_1: P1.10
|
||||||
|
|
||||||
|
#define BUTTON_CLICK_MS 400
|
||||||
|
|
||||||
|
// Analog pins
|
||||||
|
#define PIN_A0 (0 + 2) // Battery ADC (BATTERY_ADC_DATA)
|
||||||
|
|
||||||
|
#define BATTERY_PIN PIN_A0
|
||||||
|
|
||||||
|
static const uint8_t A0 = PIN_A0;
|
||||||
|
|
||||||
|
#define ADC_RESOLUTION 14
|
||||||
|
|
||||||
|
// BATTERY_MEASUREMENT_CONTROL - enable divider for battery reading
|
||||||
|
#define ADC_CTRL (0 + 31)
|
||||||
|
#define ADC_CTRL_ENABLED HIGH
|
||||||
|
|
||||||
|
// NFC placeholders, not used
|
||||||
|
#define PIN_NFC1 (9)
|
||||||
|
#define PIN_NFC2 (10)
|
||||||
|
|
||||||
|
// Wire Interfaces (IIC_1 on the vendor header)
|
||||||
|
#define WIRE_INTERFACES_COUNT 1
|
||||||
|
|
||||||
|
#define PIN_WIRE_SDA (32 + 4) // IIC_1_SDA: P1.4
|
||||||
|
#define PIN_WIRE_SCL (32 + 2) // IIC_1_SCL: P1.2
|
||||||
|
|
||||||
|
// External serial flash ZD25WQ32CEIGR
|
||||||
|
// QSPI Pins
|
||||||
|
#define PIN_QSPI_SCK (0 + 4)
|
||||||
|
#define PIN_QSPI_CS (0 + 12)
|
||||||
|
#define PIN_QSPI_IO0 (0 + 6) // MOSI if using two bit interface
|
||||||
|
#define PIN_QSPI_IO1 (0 + 8) // MISO if using two bit interface
|
||||||
|
#define PIN_QSPI_IO2 (32 + 9) // WP
|
||||||
|
#define PIN_QSPI_IO3 (0 + 26) // HOLD
|
||||||
|
|
||||||
|
// On-board QSPI Flash
|
||||||
|
#define EXTERNAL_FLASH_DEVICES ZD25WQ32CEIGR
|
||||||
|
#define EXTERNAL_FLASH_USE_QSPI
|
||||||
|
|
||||||
|
// Lora S62F (SX1262)
|
||||||
|
#define USE_SX1262
|
||||||
|
#define SX126X_CS (0 + 11)
|
||||||
|
#define SX126X_DIO1 (32 + 8)
|
||||||
|
#define SX126X_DIO2 (0 + 5)
|
||||||
|
#define SX126X_BUSY (0 + 14)
|
||||||
|
#define SX126X_RESET (0 + 7)
|
||||||
|
#define SX126X_RXEN (32 + 1) // SX1262_RF_VC2
|
||||||
|
#define SX126X_TXEN (0 + 27) // SX1262_RF_VC1
|
||||||
|
#define SX126X_DIO3_TCXO_VOLTAGE 1.8
|
||||||
|
|
||||||
|
// ───────────────────────────────────────────────────────────────────────────
|
||||||
|
// OLED display: SSD1315 on I2C @ 0x3C (IIC_1). SSD1315 is register-compatible
|
||||||
|
// with SSD1306, so USE_SSD1306 initializes the controller correctly.
|
||||||
|
//
|
||||||
|
// Viewport: the physical panel is 72×40, mapped into the SSD1315's 128×64
|
||||||
|
// GDDRAM at columns 28..99, pages 3..7 (rows 24..63). The firmware handles
|
||||||
|
// this by:
|
||||||
|
// * asking the library for GEOMETRY_72_40, which sets the framebuffer to
|
||||||
|
// 72×40 and emits the right SETMULTIPLEX (39) / SETCOMPINS at init;
|
||||||
|
// * relying on SSD1306Wire's built-in horizontal auto-centering
|
||||||
|
// ((128 - width) / 2 = 28), so no horizontal shim is needed;
|
||||||
|
// * calling SSD1306Wire::setYOffset(3) in Screen.cpp when
|
||||||
|
// OLED_Y_OFFSET_PAGES is defined — this shifts every PAGEADDR write by
|
||||||
|
// three pages (24 rows) so data lands on the visible rows.
|
||||||
|
// ───────────────────────────────────────────────────────────────────────────
|
||||||
|
#define HAS_SCREEN 1
|
||||||
|
#define USE_SSD1306
|
||||||
|
#define OLED_GEOMETRY_OVERRIDE GEOMETRY_72_40
|
||||||
|
#define OLED_Y_OFFSET_PAGES 3
|
||||||
|
#define OLED_TINY
|
||||||
|
|
||||||
|
// Controls power 3V3 for all peripherals (GPS + LoRa + Sensor)
|
||||||
|
#define PIN_POWER_EN (0 + 30) // RT9080_EN
|
||||||
|
|
||||||
|
// SPI1 is unused (no external SPI display). Keep declarations for the core.
|
||||||
|
#define PIN_SPI1_MISO (-1)
|
||||||
|
#define PIN_SPI1_MOSI (-1)
|
||||||
|
#define PIN_SPI1_SCK (-1)
|
||||||
|
|
||||||
|
// GPS pins
|
||||||
|
#define GPS_L76K
|
||||||
|
#define GPS_BAUDRATE 9600
|
||||||
|
#define HAS_GPS 1
|
||||||
|
|
||||||
|
#define PIN_GPS_EN (32 + 15) // GPS_EN: P1.15 - GPS power enable
|
||||||
|
#define GPS_EN_ACTIVE 1
|
||||||
|
#define PIN_GPS_STANDBY (0 + 25) // GPS_WAKE_UP: P0.25 - wakeup pin
|
||||||
|
#define PIN_GPS_PPS (0 + 23) // GPS_1PPS: P0.23
|
||||||
|
#define GPS_RX_PIN (0 + 19) // MCU RX ← GPS's TX (vendor GPS_UART_TX / P0.19)
|
||||||
|
#define GPS_TX_PIN (0 + 21) // MCU TX → GPS's RX (vendor GPS_UART_RX / P0.21)
|
||||||
|
#define PIN_GPS_RESET (0 + 29) // GPS_RF_EN: GPS RF enable / reset
|
||||||
|
|
||||||
|
#define GPS_THREAD_INTERVAL 50
|
||||||
|
|
||||||
|
#define PIN_SERIAL1_RX GPS_RX_PIN
|
||||||
|
#define PIN_SERIAL1_TX GPS_TX_PIN
|
||||||
|
|
||||||
|
// SPI Interfaces (LoRa on SPI0)
|
||||||
|
#define SPI_INTERFACES_COUNT 2
|
||||||
|
|
||||||
|
// For LORA, SPI 0
|
||||||
|
#define PIN_SPI_MISO (0 + 17)
|
||||||
|
#define PIN_SPI_MOSI (0 + 15)
|
||||||
|
#define PIN_SPI_SCK (0 + 13)
|
||||||
|
|
||||||
|
// Battery
|
||||||
|
// The battery sense is hooked to PIN_A0 (P0.2) via a divider controlled by ADC_CTRL.
|
||||||
|
#define BATTERY_SENSE_RESOLUTION_BITS 12
|
||||||
|
#define BATTERY_SENSE_RESOLUTION 4096.0
|
||||||
|
#undef AREF_VOLTAGE
|
||||||
|
#define AREF_VOLTAGE 3.0
|
||||||
|
#define VBAT_AR_INTERNAL AR_INTERNAL_3_0
|
||||||
|
#define ADC_MULTIPLIER (2.0F)
|
||||||
|
|
||||||
|
// Buzzer (PWM output, passive piezo)
|
||||||
|
#define PIN_BUZZER (32 + 6) // BUZZER_DATA: P1.6
|
||||||
|
|
||||||
|
// ───────────────────────────────────────────────────────────────────────────
|
||||||
|
// I²S speaker (MAX98357 Class-D amp). Stereo I²S data path.
|
||||||
|
// Not supported on nrf52. These defines exist for out-of-tree code only.
|
||||||
|
// ───────────────────────────────────────────────────────────────────────────
|
||||||
|
#define SPEAKER_EN (32 + 11) // P1.11 - amp main enable
|
||||||
|
#define SPEAKER_EN_2 (0 + 3) // P0.3 - secondary enable (vendor firmware toggles both)
|
||||||
|
#define SPEAKER_BCLK (0 + 16) // P0.16 - I2S bit clock
|
||||||
|
#define SPEAKER_DATA (0 + 20) // P0.20 - I2S data (SDOUT)
|
||||||
|
#define SPEAKER_WS_LRCK (0 + 22) // P0.22 - I2S word select / LRCK
|
||||||
|
|
||||||
|
// ───────────────────────────────────────────────────────────────────────────
|
||||||
|
// PDM microphone (ST MP34DT05).
|
||||||
|
// TODO to enable a mic path:
|
||||||
|
// Use Adafruit nRF52 core's built-in PDM.h wrapper (Arduino-compatible
|
||||||
|
// API exists on nRF52840). Clock on MIC_SCLK, data on MIC_DATA.
|
||||||
|
// ───────────────────────────────────────────────────────────────────────────
|
||||||
|
#define MIC_SCLK (32 + 3) // P1.3 - PDM clock (MIC_SCLK on vendor header)
|
||||||
|
#define MIC_DATA (32 + 5) // P1.5 - PDM data (MIC_DATA on vendor header)
|
||||||
|
|
||||||
|
#define SERIAL_PRINT_PORT 0
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*----------------------------------------------------------------------------
|
||||||
|
* Arduino objects - C++ only
|
||||||
|
*----------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
#endif
|
||||||
Reference in New Issue
Block a user