mirror of
https://github.com/meshtastic/firmware.git
synced 2026-01-20 00:37:36 +00:00
Compare commits
11 Commits
fix-bme
...
meshtastic
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e2b274bba8 | ||
|
|
d07db5a850 | ||
|
|
72acd8f58d | ||
|
|
fb4486c74b | ||
|
|
89be78ef0f | ||
|
|
f7a374600c | ||
|
|
6574af0551 | ||
|
|
16feccec2a | ||
|
|
59ca02aca0 | ||
|
|
7a5d4ad43c | ||
|
|
e93abf85c0 |
@@ -20,7 +20,7 @@ ENV PIP_ROOT_USER_ACTION=ignore
|
|||||||
RUN apt-get update && apt-get install --no-install-recommends -y \
|
RUN apt-get update && apt-get install --no-install-recommends -y \
|
||||||
cmake git zip libgpiod-dev libbluetooth-dev libi2c-dev \
|
cmake git zip libgpiod-dev libbluetooth-dev libi2c-dev \
|
||||||
libunistring-dev libmicrohttpd-dev libgnutls28-dev libgcrypt20-dev \
|
libunistring-dev libmicrohttpd-dev libgnutls28-dev libgcrypt20-dev \
|
||||||
libusb-1.0-0-dev libssl-dev pkg-config libsqlite3-dev && \
|
libusb-1.0-0-dev libssl-dev pkg-config && \
|
||||||
apt-get clean && rm -rf /var/lib/apt/lists/* && \
|
apt-get clean && rm -rf /var/lib/apt/lists/* && \
|
||||||
pip install --no-cache-dir -U \
|
pip install --no-cache-dir -U \
|
||||||
platformio==6.1.16 \
|
platformio==6.1.16 \
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ RUN apt-get update && apt-get install --no-install-recommends -y \
|
|||||||
curl wget g++ zip git ca-certificates pkg-config \
|
curl wget g++ zip git ca-certificates pkg-config \
|
||||||
libgpiod-dev libyaml-cpp-dev libbluetooth-dev libi2c-dev libuv1-dev \
|
libgpiod-dev libyaml-cpp-dev libbluetooth-dev libi2c-dev libuv1-dev \
|
||||||
libusb-1.0-0-dev libulfius-dev liborcania-dev libssl-dev \
|
libusb-1.0-0-dev libulfius-dev liborcania-dev libssl-dev \
|
||||||
libx11-dev libinput-dev libxkbcommon-x11-dev libsqlite3-dev \
|
libx11-dev libinput-dev libxkbcommon-x11-dev \
|
||||||
&& apt-get clean && rm -rf /var/lib/apt/lists/* \
|
&& apt-get clean && rm -rf /var/lib/apt/lists/* \
|
||||||
&& pip install --no-cache-dir -U platformio \
|
&& pip install --no-cache-dir -U platformio \
|
||||||
&& mkdir /tmp/firmware
|
&& mkdir /tmp/firmware
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ RUN apk --no-cache add \
|
|||||||
bash g++ libstdc++-dev linux-headers zip git ca-certificates libbsd-dev \
|
bash g++ libstdc++-dev linux-headers zip git ca-certificates libbsd-dev \
|
||||||
libgpiod-dev yaml-cpp-dev bluez-dev \
|
libgpiod-dev yaml-cpp-dev bluez-dev \
|
||||||
libusb-dev i2c-tools-dev libuv-dev openssl-dev pkgconf argp-standalone \
|
libusb-dev i2c-tools-dev libuv-dev openssl-dev pkgconf argp-standalone \
|
||||||
libx11-dev libinput-dev libxkbcommon-dev sqlite-dev \
|
libx11-dev libinput-dev libxkbcommon-dev \
|
||||||
&& rm -rf /var/cache/apk/* \
|
&& rm -rf /var/cache/apk/* \
|
||||||
&& pip install --no-cache-dir -U platformio \
|
&& pip install --no-cache-dir -U platformio \
|
||||||
&& mkdir /tmp/firmware
|
&& mkdir /tmp/firmware
|
||||||
|
|||||||
3
debian/control
vendored
3
debian/control
vendored
@@ -25,8 +25,7 @@ Build-Depends: debhelper-compat (= 13),
|
|||||||
liborcania-dev,
|
liborcania-dev,
|
||||||
libx11-dev,
|
libx11-dev,
|
||||||
libinput-dev,
|
libinput-dev,
|
||||||
libxkbcommon-x11-dev,
|
libxkbcommon-x11-dev
|
||||||
libsqlite3-dev
|
|
||||||
Standards-Version: 4.6.2
|
Standards-Version: 4.6.2
|
||||||
Homepage: https://github.com/meshtastic/firmware
|
Homepage: https://github.com/meshtastic/firmware
|
||||||
Rules-Requires-Root: no
|
Rules-Requires-Root: no
|
||||||
|
|||||||
@@ -39,7 +39,6 @@ BuildRequires: pkgconfig(bluez)
|
|||||||
BuildRequires: pkgconfig(libusb-1.0)
|
BuildRequires: pkgconfig(libusb-1.0)
|
||||||
BuildRequires: libi2c-devel
|
BuildRequires: libi2c-devel
|
||||||
BuildRequires: pkgconfig(libuv)
|
BuildRequires: pkgconfig(libuv)
|
||||||
BuildRequires: pkgconfig(sqlite3)
|
|
||||||
# Web components:
|
# Web components:
|
||||||
BuildRequires: pkgconfig(openssl)
|
BuildRequires: pkgconfig(openssl)
|
||||||
BuildRequires: pkgconfig(liborcania)
|
BuildRequires: pkgconfig(liborcania)
|
||||||
|
|||||||
@@ -445,6 +445,18 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
// BME680 BSEC2 support detection
|
||||||
|
#if !defined(MESHTASTIC_BME680_BSEC2_SUPPORTED)
|
||||||
|
#if defined(RAK_4631) || defined(TBEAM_V10)
|
||||||
|
|
||||||
|
#define MESHTASTIC_BME680_BSEC2_SUPPORTED 1
|
||||||
|
#define MESHTASTIC_BME680_HEADER <bsec2.h>
|
||||||
|
#else
|
||||||
|
#define MESHTASTIC_BME680_BSEC2_SUPPORTED 0
|
||||||
|
#define MESHTASTIC_BME680_HEADER <Adafruit_BME680.h>
|
||||||
|
#endif // defined(RAK_4631)
|
||||||
|
#endif // !defined(MESHTASTIC_BME680_BSEC2_SUPPORTED)
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
// Global switches to turn off features for a minimized build
|
// Global switches to turn off features for a minimized build
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
|
|||||||
@@ -438,7 +438,7 @@ void drawLoRaFocused(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x,
|
|||||||
if (currentResolution == ScreenResolution::UltraLow) {
|
if (currentResolution == ScreenResolution::UltraLow) {
|
||||||
snprintf(frequencyslot, sizeof(frequencyslot), "%sMHz (%d)", freqStr, config.lora.channel_num);
|
snprintf(frequencyslot, sizeof(frequencyslot), "%sMHz (%d)", freqStr, config.lora.channel_num);
|
||||||
} else {
|
} else {
|
||||||
snprintf(frequencyslot, sizeof(frequencyslot), "Freq: %sMHz (%d)", freqStr, config.lora.channel_num);
|
snprintf(frequencyslot, sizeof(frequencyslot), "Freq/Ch: %sMHz (%d)", freqStr, config.lora.channel_num);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
size_t len = strlen(frequencyslot);
|
size_t len = strlen(frequencyslot);
|
||||||
|
|||||||
@@ -65,12 +65,12 @@ uint8_t test_count = 0;
|
|||||||
|
|
||||||
void menuHandler::loraMenu()
|
void menuHandler::loraMenu()
|
||||||
{
|
{
|
||||||
static const char *optionsArray[] = {"Back", "Device Role", "Radio Preset", "Frequency Slot", "LoRa Region"};
|
static const char *optionsArray[] = {"Back", "Device Role", "Radio Preset", "LoRa Region"};
|
||||||
enum optionsNumbers { Back = 0, device_role_picker = 1, radio_preset_picker = 2, frequency_slot = 3, lora_picker = 4 };
|
enum optionsNumbers { Back = 0, device_role_picker = 1, radio_preset_picker = 2, lora_picker = 3 };
|
||||||
BannerOverlayOptions bannerOptions;
|
BannerOverlayOptions bannerOptions;
|
||||||
bannerOptions.message = "LoRa Actions";
|
bannerOptions.message = "LoRa Actions";
|
||||||
bannerOptions.optionsArrayPtr = optionsArray;
|
bannerOptions.optionsArrayPtr = optionsArray;
|
||||||
bannerOptions.optionsCount = 5;
|
bannerOptions.optionsCount = 4;
|
||||||
bannerOptions.bannerCallback = [](int selected) -> void {
|
bannerOptions.bannerCallback = [](int selected) -> void {
|
||||||
if (selected == Back) {
|
if (selected == Back) {
|
||||||
// No action
|
// No action
|
||||||
@@ -78,8 +78,6 @@ void menuHandler::loraMenu()
|
|||||||
menuHandler::menuQueue = menuHandler::device_role_picker;
|
menuHandler::menuQueue = menuHandler::device_role_picker;
|
||||||
} else if (selected == radio_preset_picker) {
|
} else if (selected == radio_preset_picker) {
|
||||||
menuHandler::menuQueue = menuHandler::radio_preset_picker;
|
menuHandler::menuQueue = menuHandler::radio_preset_picker;
|
||||||
} else if (selected == frequency_slot) {
|
|
||||||
menuHandler::menuQueue = menuHandler::frequency_slot;
|
|
||||||
} else if (selected == lora_picker) {
|
} else if (selected == lora_picker) {
|
||||||
menuHandler::menuQueue = menuHandler::lora_picker;
|
menuHandler::menuQueue = menuHandler::lora_picker;
|
||||||
}
|
}
|
||||||
@@ -250,113 +248,6 @@ void menuHandler::DeviceRolePicker()
|
|||||||
screen->showOverlayBanner(bannerOptions);
|
screen->showOverlayBanner(bannerOptions);
|
||||||
}
|
}
|
||||||
|
|
||||||
void menuHandler::FrequencySlotPicker()
|
|
||||||
{
|
|
||||||
|
|
||||||
enum ReplyOptions : int { Back = -1 };
|
|
||||||
constexpr int MAX_CHANNEL_OPTIONS = 202;
|
|
||||||
static const char *optionsArray[MAX_CHANNEL_OPTIONS];
|
|
||||||
static int optionsEnumArray[MAX_CHANNEL_OPTIONS];
|
|
||||||
static char channelText[MAX_CHANNEL_OPTIONS - 1][12];
|
|
||||||
int options = 0;
|
|
||||||
optionsArray[options] = "Back";
|
|
||||||
optionsEnumArray[options++] = Back;
|
|
||||||
optionsArray[options] = "Slot 0 (Auto)";
|
|
||||||
optionsEnumArray[options++] = 0;
|
|
||||||
|
|
||||||
// Calculate number of channels (copied from RadioInterface::applyModemConfig())
|
|
||||||
meshtastic_Config_LoRaConfig &loraConfig = config.lora;
|
|
||||||
double bw = loraConfig.bandwidth;
|
|
||||||
if (loraConfig.use_preset) {
|
|
||||||
switch (loraConfig.modem_preset) {
|
|
||||||
case meshtastic_Config_LoRaConfig_ModemPreset_SHORT_TURBO:
|
|
||||||
bw = (myRegion->wideLora) ? 1625.0 : 500;
|
|
||||||
break;
|
|
||||||
case meshtastic_Config_LoRaConfig_ModemPreset_SHORT_FAST:
|
|
||||||
bw = (myRegion->wideLora) ? 812.5 : 250;
|
|
||||||
break;
|
|
||||||
case meshtastic_Config_LoRaConfig_ModemPreset_SHORT_SLOW:
|
|
||||||
bw = (myRegion->wideLora) ? 812.5 : 250;
|
|
||||||
break;
|
|
||||||
case meshtastic_Config_LoRaConfig_ModemPreset_MEDIUM_FAST:
|
|
||||||
bw = (myRegion->wideLora) ? 812.5 : 250;
|
|
||||||
break;
|
|
||||||
case meshtastic_Config_LoRaConfig_ModemPreset_MEDIUM_SLOW:
|
|
||||||
bw = (myRegion->wideLora) ? 812.5 : 250;
|
|
||||||
break;
|
|
||||||
case meshtastic_Config_LoRaConfig_ModemPreset_LONG_TURBO:
|
|
||||||
bw = (myRegion->wideLora) ? 1625.0 : 500;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
bw = (myRegion->wideLora) ? 812.5 : 250;
|
|
||||||
break;
|
|
||||||
case meshtastic_Config_LoRaConfig_ModemPreset_LONG_MODERATE:
|
|
||||||
bw = (myRegion->wideLora) ? 406.25 : 125;
|
|
||||||
break;
|
|
||||||
case meshtastic_Config_LoRaConfig_ModemPreset_LONG_SLOW:
|
|
||||||
bw = (myRegion->wideLora) ? 406.25 : 125;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
bw = loraConfig.bandwidth;
|
|
||||||
if (bw == 31) // This parameter is not an integer
|
|
||||||
bw = 31.25;
|
|
||||||
if (bw == 62) // Fix for 62.5Khz bandwidth
|
|
||||||
bw = 62.5;
|
|
||||||
if (bw == 200)
|
|
||||||
bw = 203.125;
|
|
||||||
if (bw == 400)
|
|
||||||
bw = 406.25;
|
|
||||||
if (bw == 800)
|
|
||||||
bw = 812.5;
|
|
||||||
if (bw == 1600)
|
|
||||||
bw = 1625.0;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t numChannels = 0;
|
|
||||||
if (myRegion) {
|
|
||||||
numChannels = (uint32_t)floor((myRegion->freqEnd - myRegion->freqStart) / (myRegion->spacing + (bw / 1000.0)));
|
|
||||||
} else {
|
|
||||||
LOG_WARN("Region not set, cannot calculate number of channels");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (numChannels > (uint32_t)(MAX_CHANNEL_OPTIONS - 2))
|
|
||||||
numChannels = (uint32_t)(MAX_CHANNEL_OPTIONS - 2);
|
|
||||||
|
|
||||||
for (uint32_t ch = 1; ch <= numChannels; ch++) {
|
|
||||||
snprintf(channelText[ch - 1], sizeof(channelText[ch - 1]), "Slot %lu", (unsigned long)ch);
|
|
||||||
optionsArray[options] = channelText[ch - 1];
|
|
||||||
optionsEnumArray[options++] = (int)ch;
|
|
||||||
}
|
|
||||||
|
|
||||||
BannerOverlayOptions bannerOptions;
|
|
||||||
bannerOptions.message = "Frequency Slot";
|
|
||||||
bannerOptions.optionsArrayPtr = optionsArray;
|
|
||||||
bannerOptions.optionsEnumPtr = optionsEnumArray;
|
|
||||||
bannerOptions.optionsCount = options;
|
|
||||||
|
|
||||||
// Start highlight on current channel if possible, otherwise on "1"
|
|
||||||
int initial = (int)config.lora.channel_num + 1;
|
|
||||||
if (initial < 2 || initial > (int)numChannels + 1)
|
|
||||||
initial = 1;
|
|
||||||
bannerOptions.InitialSelected = initial;
|
|
||||||
|
|
||||||
bannerOptions.bannerCallback = [](int selected) -> void {
|
|
||||||
if (selected == Back) {
|
|
||||||
menuHandler::menuQueue = menuHandler::lora_Menu;
|
|
||||||
screen->runNow();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
config.lora.channel_num = selected;
|
|
||||||
service->reloadConfig(SEGMENT_CONFIG);
|
|
||||||
rebootAtMsec = (millis() + DEFAULT_REBOOT_SECONDS * 1000);
|
|
||||||
};
|
|
||||||
|
|
||||||
screen->showOverlayBanner(bannerOptions);
|
|
||||||
}
|
|
||||||
|
|
||||||
void menuHandler::RadioPresetPicker()
|
void menuHandler::RadioPresetPicker()
|
||||||
{
|
{
|
||||||
static const RadioPresetOption presetOptions[] = {
|
static const RadioPresetOption presetOptions[] = {
|
||||||
@@ -387,8 +278,6 @@ void menuHandler::RadioPresetPicker()
|
|||||||
}
|
}
|
||||||
|
|
||||||
config.lora.modem_preset = option.value;
|
config.lora.modem_preset = option.value;
|
||||||
config.lora.channel_num = 0; // Reset to default channel for the preset
|
|
||||||
config.lora.override_frequency = 0; // Clear any custom frequency
|
|
||||||
service->reloadConfig(SEGMENT_CONFIG);
|
service->reloadConfig(SEGMENT_CONFIG);
|
||||||
rebootAtMsec = (millis() + DEFAULT_REBOOT_SECONDS * 1000);
|
rebootAtMsec = (millis() + DEFAULT_REBOOT_SECONDS * 1000);
|
||||||
});
|
});
|
||||||
@@ -2662,9 +2551,6 @@ void menuHandler::handleMenuSwitch(OLEDDisplay *display)
|
|||||||
case radio_preset_picker:
|
case radio_preset_picker:
|
||||||
RadioPresetPicker();
|
RadioPresetPicker();
|
||||||
break;
|
break;
|
||||||
case frequency_slot:
|
|
||||||
FrequencySlotPicker();
|
|
||||||
break;
|
|
||||||
case no_timeout_lora_picker:
|
case no_timeout_lora_picker:
|
||||||
LoraRegionPicker(0);
|
LoraRegionPicker(0);
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -13,7 +13,6 @@ class menuHandler
|
|||||||
lora_picker,
|
lora_picker,
|
||||||
device_role_picker,
|
device_role_picker,
|
||||||
radio_preset_picker,
|
radio_preset_picker,
|
||||||
frequency_slot,
|
|
||||||
no_timeout_lora_picker,
|
no_timeout_lora_picker,
|
||||||
TZ_picker,
|
TZ_picker,
|
||||||
twelve_hour_picker,
|
twelve_hour_picker,
|
||||||
@@ -64,7 +63,6 @@ class menuHandler
|
|||||||
static void loraMenu();
|
static void loraMenu();
|
||||||
static void DeviceRolePicker();
|
static void DeviceRolePicker();
|
||||||
static void RadioPresetPicker();
|
static void RadioPresetPicker();
|
||||||
static void FrequencySlotPicker();
|
|
||||||
static void handleMenuSwitch(OLEDDisplay *display);
|
static void handleMenuSwitch(OLEDDisplay *display);
|
||||||
static void showConfirmationBanner(const char *message, std::function<void()> onConfirm);
|
static void showConfirmationBanner(const char *message, std::function<void()> onConfirm);
|
||||||
static void clockMenu();
|
static void clockMenu();
|
||||||
|
|||||||
43
src/main.cpp
43
src/main.cpp
@@ -105,6 +105,43 @@ NRF52Bluetooth *nrf52Bluetooth = nullptr;
|
|||||||
#include <string>
|
#include <string>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef ARCH_ESP32
|
||||||
|
#ifdef DEBUG_PARTITION_TABLE
|
||||||
|
#include "esp_partition.h"
|
||||||
|
|
||||||
|
void printPartitionTable()
|
||||||
|
{
|
||||||
|
printf("\n--- Partition Table ---\n");
|
||||||
|
// Print Column Headers
|
||||||
|
printf("| %-16s | %-4s | %-7s | %-10s | %-10s |\n", "Label", "Type", "Subtype", "Offset", "Size");
|
||||||
|
printf("|------------------|------|---------|------------|------------|\n");
|
||||||
|
|
||||||
|
// Create an iterator to find ALL partitions (Type ANY, Subtype ANY)
|
||||||
|
esp_partition_iterator_t it = esp_partition_find(ESP_PARTITION_TYPE_ANY, ESP_PARTITION_SUBTYPE_ANY, NULL);
|
||||||
|
|
||||||
|
// Loop through the iterator
|
||||||
|
if (it != NULL) {
|
||||||
|
do {
|
||||||
|
const esp_partition_t *part = esp_partition_get(it);
|
||||||
|
|
||||||
|
// Print details: Label, Type (Hex), Subtype (Hex), Offset (Hex), Size (Hex)
|
||||||
|
printf("| %-16s | 0x%02x | 0x%02x | 0x%08x | 0x%08x |\n", part->label, part->type, part->subtype, part->address,
|
||||||
|
part->size);
|
||||||
|
|
||||||
|
// Move to next partition
|
||||||
|
it = esp_partition_next(it);
|
||||||
|
} while (it != NULL);
|
||||||
|
|
||||||
|
// Release the iterator memory
|
||||||
|
esp_partition_iterator_release(it);
|
||||||
|
} else {
|
||||||
|
printf("No partitions found.\n");
|
||||||
|
}
|
||||||
|
printf("-----------------------\n");
|
||||||
|
}
|
||||||
|
#endif // DEBUG_PARTITION_TABLE
|
||||||
|
#endif // ARCH_ESP32
|
||||||
|
|
||||||
#if HAS_BUTTON || defined(ARCH_PORTDUINO)
|
#if HAS_BUTTON || defined(ARCH_PORTDUINO)
|
||||||
#include "input/ButtonThread.h"
|
#include "input/ButtonThread.h"
|
||||||
|
|
||||||
@@ -648,7 +685,11 @@ void setup()
|
|||||||
sensor_detected = true;
|
sensor_detected = true;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
#ifdef ARCH_ESP32
|
||||||
|
#ifdef DEBUG_PARTITION_TABLE
|
||||||
|
printPartitionTable();
|
||||||
|
#endif
|
||||||
|
#endif // ARCH_ESP32
|
||||||
#ifdef ARCH_ESP32
|
#ifdef ARCH_ESP32
|
||||||
// Don't init display if we don't have one or we are waking headless due to a timer event
|
// Don't init display if we don't have one or we are waking headless due to a timer event
|
||||||
if (wakeCause == ESP_SLEEP_WAKEUP_TIMER) {
|
if (wakeCause == ESP_SLEEP_WAKEUP_TIMER) {
|
||||||
|
|||||||
@@ -173,7 +173,7 @@ void handleAPIv1FromRadio(HTTPRequest *req, HTTPResponse *res)
|
|||||||
|
|
||||||
if (req->getMethod() == "OPTIONS") {
|
if (req->getMethod() == "OPTIONS") {
|
||||||
res->setStatusCode(204); // Success with no content
|
res->setStatusCode(204); // Success with no content
|
||||||
res->print("");
|
// res->print(""); @todo remove
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -223,7 +223,7 @@ void handleAPIv1ToRadio(HTTPRequest *req, HTTPResponse *res)
|
|||||||
|
|
||||||
if (req->getMethod() == "OPTIONS") {
|
if (req->getMethod() == "OPTIONS") {
|
||||||
res->setStatusCode(204); // Success with no content
|
res->setStatusCode(204); // Success with no content
|
||||||
res->print("");
|
// res->print(""); @todo remove
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -235,22 +235,46 @@ bool AdminModule::handleReceivedProtobuf(const meshtastic_MeshPacket &mp, meshta
|
|||||||
}
|
}
|
||||||
case meshtastic_AdminMessage_ota_request_tag: {
|
case meshtastic_AdminMessage_ota_request_tag: {
|
||||||
#if defined(ARCH_ESP32)
|
#if defined(ARCH_ESP32)
|
||||||
|
LOG_INFO("OTA Requested");
|
||||||
|
|
||||||
if (r->ota_request.ota_hash.size != 32) {
|
if (r->ota_request.ota_hash.size != 32) {
|
||||||
suppressRebootBanner = true;
|
suppressRebootBanner = true;
|
||||||
LOG_INFO("OTA Failed: Invalid `ota_hash` provided");
|
sendWarningAndLog("Cannot start OTA: Invalid `ota_hash` provided.");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
meshtastic_OTAMode mode = r->ota_request.reboot_ota_mode;
|
meshtastic_OTAMode mode = r->ota_request.reboot_ota_mode;
|
||||||
|
const char *mode_name = (mode == METHOD_OTA_BLE ? "BLE" : "WiFi");
|
||||||
|
|
||||||
|
// Check that we have an OTA partition
|
||||||
|
const esp_partition_t *part = MeshtasticOTA::getAppPartition();
|
||||||
|
if (part == NULL) {
|
||||||
|
suppressRebootBanner = true;
|
||||||
|
sendWarningAndLog("Cannot start OTA: Cannot find OTA Loader partition.");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
static esp_app_desc_t app_desc;
|
||||||
|
if (!MeshtasticOTA::getAppDesc(part, &app_desc)) {
|
||||||
|
suppressRebootBanner = true;
|
||||||
|
sendWarningAndLog("Cannot start OTA: Device does have a valid OTA Loader.");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!MeshtasticOTA::checkOTACapability(&app_desc, mode)) {
|
||||||
|
suppressRebootBanner = true;
|
||||||
|
sendWarningAndLog("OTA Loader does not support %s", mode_name);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
if (MeshtasticOTA::trySwitchToOTA()) {
|
if (MeshtasticOTA::trySwitchToOTA()) {
|
||||||
LOG_INFO("OTA Requested");
|
|
||||||
suppressRebootBanner = true;
|
suppressRebootBanner = true;
|
||||||
if (screen)
|
if (screen)
|
||||||
screen->startFirmwareUpdateScreen();
|
screen->startFirmwareUpdateScreen();
|
||||||
MeshtasticOTA::saveConfig(&config.network, mode, r->ota_request.ota_hash.bytes);
|
MeshtasticOTA::saveConfig(&config.network, mode, r->ota_request.ota_hash.bytes);
|
||||||
LOG_INFO("Rebooting to WiFi OTA");
|
sendWarningAndLog("Rebooting to %s OTA", mode_name);
|
||||||
} else {
|
} else {
|
||||||
LOG_INFO("WIFI OTA Failed");
|
sendWarningAndLog("Unable to switch to the OTA partition.");
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
int s = 1; // Reboot in 1 second, hard coded
|
int s = 1; // Reboot in 1 second, hard coded
|
||||||
@@ -1472,15 +1496,43 @@ void AdminModule::handleSendInputEvent(const meshtastic_AdminMessage_InputEvent
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void AdminModule::sendWarning(const char *message)
|
void AdminModule::sendWarning(const char *format, ...)
|
||||||
{
|
{
|
||||||
meshtastic_ClientNotification *cn = clientNotificationPool.allocZeroed();
|
meshtastic_ClientNotification *cn = clientNotificationPool.allocZeroed();
|
||||||
|
if (!cn)
|
||||||
|
return;
|
||||||
|
|
||||||
cn->level = meshtastic_LogRecord_Level_WARNING;
|
cn->level = meshtastic_LogRecord_Level_WARNING;
|
||||||
cn->time = getValidTime(RTCQualityFromNet);
|
cn->time = getValidTime(RTCQualityFromNet);
|
||||||
strncpy(cn->message, message, sizeof(cn->message));
|
|
||||||
|
va_list args;
|
||||||
|
va_start(args, format);
|
||||||
|
// Format the arguments directly into the notification object
|
||||||
|
vsnprintf(cn->message, sizeof(cn->message), format, args);
|
||||||
|
va_end(args);
|
||||||
|
|
||||||
service->sendClientNotification(cn);
|
service->sendClientNotification(cn);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void AdminModule::sendWarningAndLog(const char *format, ...)
|
||||||
|
{
|
||||||
|
// We need a temporary buffer to hold the formatted text so we can log it
|
||||||
|
// Using 250 bytes as a safe upper limit for typical text notifications
|
||||||
|
char buf[250];
|
||||||
|
|
||||||
|
va_list args;
|
||||||
|
va_start(args, format);
|
||||||
|
vsnprintf(buf, sizeof(buf), format, args);
|
||||||
|
va_end(args);
|
||||||
|
|
||||||
|
LOG_WARN(buf);
|
||||||
|
// 2. Call sendWarning
|
||||||
|
// SECURITY NOTE: We pass "%s", buf instead of just 'buf'.
|
||||||
|
// If 'buf' contained a % symbol (e.g. "Battery 50%"), passing it directly
|
||||||
|
// would crash sendWarning. "%s" treats it purely as text.
|
||||||
|
sendWarning("%s", buf);
|
||||||
|
}
|
||||||
|
|
||||||
void disableBluetooth()
|
void disableBluetooth()
|
||||||
{
|
{
|
||||||
#if HAS_BLUETOOTH
|
#if HAS_BLUETOOTH
|
||||||
|
|||||||
@@ -1,7 +1,9 @@
|
|||||||
#include <sys/types.h>
|
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
#ifdef ESP_PLATFORM
|
||||||
|
#include <esp_ota_ops.h>
|
||||||
|
#endif
|
||||||
#include "ProtobufModule.h"
|
#include "ProtobufModule.h"
|
||||||
|
#include <sys/types.h>
|
||||||
#if HAS_WIFI
|
#if HAS_WIFI
|
||||||
#include "mesh/wifi/WiFiAPClient.h"
|
#include "mesh/wifi/WiFiAPClient.h"
|
||||||
#endif
|
#endif
|
||||||
@@ -71,7 +73,8 @@ class AdminModule : public ProtobufModule<meshtastic_AdminMessage>, public Obser
|
|||||||
|
|
||||||
bool messageIsResponse(const meshtastic_AdminMessage *r);
|
bool messageIsResponse(const meshtastic_AdminMessage *r);
|
||||||
bool messageIsRequest(const meshtastic_AdminMessage *r);
|
bool messageIsRequest(const meshtastic_AdminMessage *r);
|
||||||
void sendWarning(const char *message);
|
void sendWarning(const char *format, ...) __attribute__((format(printf, 2, 3)));
|
||||||
|
void sendWarningAndLog(const char *format, ...) __attribute__((format(printf, 2, 3)));
|
||||||
};
|
};
|
||||||
|
|
||||||
static constexpr const char *licensedModeMessage =
|
static constexpr const char *licensedModeMessage =
|
||||||
|
|||||||
@@ -460,15 +460,12 @@ ProcessMessage ExternalNotificationModule::handleReceived(const meshtastic_MeshP
|
|||||||
}
|
}
|
||||||
|
|
||||||
meshtastic_NodeInfoLite *sender = nodeDB->getMeshNode(mp.from);
|
meshtastic_NodeInfoLite *sender = nodeDB->getMeshNode(mp.from);
|
||||||
|
bool mutedNode = false;
|
||||||
|
if (sender) {
|
||||||
|
mutedNode = (sender->bitfield & NODEINFO_BITFIELD_IS_MUTED_MASK);
|
||||||
|
}
|
||||||
meshtastic_Channel ch = channels.getByIndex(mp.channel ? mp.channel : channels.getPrimaryIndex());
|
meshtastic_Channel ch = channels.getByIndex(mp.channel ? mp.channel : channels.getPrimaryIndex());
|
||||||
|
|
||||||
// If we receive a broadcast message, apply channel mute setting
|
|
||||||
// If we receive a direct message and the receipent is us, apply DM mute setting
|
|
||||||
// Else we just handle it as not muted.
|
|
||||||
const bool directToUs = !isBroadcast(mp.to) && isToUs(&mp);
|
|
||||||
bool is_muted = directToUs ? (sender && ((sender->bitfield & NODEINFO_BITFIELD_IS_MUTED_MASK) != 0))
|
|
||||||
: (ch.settings.has_module_settings && ch.settings.module_settings.is_muted);
|
|
||||||
|
|
||||||
if (moduleConfig.external_notification.alert_bell) {
|
if (moduleConfig.external_notification.alert_bell) {
|
||||||
if (containsBell) {
|
if (containsBell) {
|
||||||
LOG_INFO("externalNotificationModule - Notification Bell");
|
LOG_INFO("externalNotificationModule - Notification Bell");
|
||||||
@@ -519,7 +516,8 @@ ProcessMessage ExternalNotificationModule::handleReceived(const meshtastic_MeshP
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (moduleConfig.external_notification.alert_message && !is_muted) {
|
if (moduleConfig.external_notification.alert_message && !mutedNode &&
|
||||||
|
(!ch.settings.has_module_settings || !ch.settings.module_settings.is_muted)) {
|
||||||
LOG_INFO("externalNotificationModule - Notification Module");
|
LOG_INFO("externalNotificationModule - Notification Module");
|
||||||
isNagging = true;
|
isNagging = true;
|
||||||
setExternalState(0, true);
|
setExternalState(0, true);
|
||||||
@@ -530,7 +528,8 @@ ProcessMessage ExternalNotificationModule::handleReceived(const meshtastic_MeshP
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (moduleConfig.external_notification.alert_message_vibra && !is_muted) {
|
if (moduleConfig.external_notification.alert_message_vibra && !mutedNode &&
|
||||||
|
(!ch.settings.has_module_settings || !ch.settings.module_settings.is_muted)) {
|
||||||
LOG_INFO("externalNotificationModule - Notification Module (Vibra)");
|
LOG_INFO("externalNotificationModule - Notification Module (Vibra)");
|
||||||
isNagging = true;
|
isNagging = true;
|
||||||
setExternalState(1, true);
|
setExternalState(1, true);
|
||||||
@@ -541,7 +540,8 @@ ProcessMessage ExternalNotificationModule::handleReceived(const meshtastic_MeshP
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (moduleConfig.external_notification.alert_message_buzzer && !is_muted) {
|
if (moduleConfig.external_notification.alert_message_buzzer && !mutedNode &&
|
||||||
|
(!ch.settings.has_module_settings || !ch.settings.module_settings.is_muted)) {
|
||||||
LOG_INFO("externalNotificationModule - Notification Module (Buzzer)");
|
LOG_INFO("externalNotificationModule - Notification Module (Buzzer)");
|
||||||
if (config.device.buzzer_mode != meshtastic_Config_DeviceConfig_BuzzerMode_DIRECT_MSG_ONLY ||
|
if (config.device.buzzer_mode != meshtastic_Config_DeviceConfig_BuzzerMode_DIRECT_MSG_ONLY ||
|
||||||
(!isBroadcast(mp.to) && isToUs(&mp))) {
|
(!isBroadcast(mp.to) && isToUs(&mp))) {
|
||||||
|
|||||||
@@ -53,7 +53,7 @@ extern void drawCommonHeader(OLEDDisplay *display, int16_t x, int16_t y, const c
|
|||||||
#include "Sensor/LTR390UVSensor.h"
|
#include "Sensor/LTR390UVSensor.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if __has_include(<bsec2.h>) || __has_include(<Adafruit_BME680.h>)
|
#if __has_include(MESHTASTIC_BME680_HEADER)
|
||||||
#include "Sensor/BME680Sensor.h"
|
#include "Sensor/BME680Sensor.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@@ -187,7 +187,7 @@ void EnvironmentTelemetryModule::i2cScanFinished(ScanI2C *i2cScanner)
|
|||||||
#if __has_include(<Adafruit_LTR390.h>)
|
#if __has_include(<Adafruit_LTR390.h>)
|
||||||
addSensor<LTR390UVSensor>(i2cScanner, ScanI2C::DeviceType::LTR390UV);
|
addSensor<LTR390UVSensor>(i2cScanner, ScanI2C::DeviceType::LTR390UV);
|
||||||
#endif
|
#endif
|
||||||
#if __has_include(<bsec2.h>) || __has_include(<Adafruit_BME680.h>)
|
#if __has_include(MESHTASTIC_BME680_HEADER)
|
||||||
addSensor<BME680Sensor>(i2cScanner, ScanI2C::DeviceType::BME_680);
|
addSensor<BME680Sensor>(i2cScanner, ScanI2C::DeviceType::BME_680);
|
||||||
#endif
|
#endif
|
||||||
#if __has_include(<Adafruit_BMP280.h>)
|
#if __has_include(<Adafruit_BMP280.h>)
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
#include "configuration.h"
|
#include "configuration.h"
|
||||||
|
|
||||||
#if !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR && (__has_include(<bsec2.h>) || __has_include(<Adafruit_BME680.h>))
|
#if !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR && __has_include(MESHTASTIC_BME680_HEADER)
|
||||||
|
|
||||||
#include "../mesh/generated/meshtastic/telemetry.pb.h"
|
#include "../mesh/generated/meshtastic/telemetry.pb.h"
|
||||||
#include "BME680Sensor.h"
|
#include "BME680Sensor.h"
|
||||||
@@ -10,7 +10,7 @@
|
|||||||
|
|
||||||
BME680Sensor::BME680Sensor() : TelemetrySensor(meshtastic_TelemetrySensorType_BME680, "BME680") {}
|
BME680Sensor::BME680Sensor() : TelemetrySensor(meshtastic_TelemetrySensorType_BME680, "BME680") {}
|
||||||
|
|
||||||
#if __has_include(<bsec2.h>)
|
#if MESHTASTIC_BME680_BSEC2_SUPPORTED == 1
|
||||||
int32_t BME680Sensor::runOnce()
|
int32_t BME680Sensor::runOnce()
|
||||||
{
|
{
|
||||||
if (!bme680.run()) {
|
if (!bme680.run()) {
|
||||||
@@ -18,13 +18,13 @@ int32_t BME680Sensor::runOnce()
|
|||||||
}
|
}
|
||||||
return 35;
|
return 35;
|
||||||
}
|
}
|
||||||
#endif
|
#endif // defined(MESHTASTIC_BME680_BSEC2_SUPPORTED)
|
||||||
|
|
||||||
bool BME680Sensor::initDevice(TwoWire *bus, ScanI2C::FoundDevice *dev)
|
bool BME680Sensor::initDevice(TwoWire *bus, ScanI2C::FoundDevice *dev)
|
||||||
{
|
{
|
||||||
status = 0;
|
status = 0;
|
||||||
|
|
||||||
#if __has_include(<bsec2.h>)
|
#if MESHTASTIC_BME680_BSEC2_SUPPORTED == 1
|
||||||
if (!bme680.begin(dev->address.address, *bus))
|
if (!bme680.begin(dev->address.address, *bus))
|
||||||
checkStatus("begin");
|
checkStatus("begin");
|
||||||
|
|
||||||
@@ -56,7 +56,7 @@ bool BME680Sensor::initDevice(TwoWire *bus, ScanI2C::FoundDevice *dev)
|
|||||||
|
|
||||||
status = 1;
|
status = 1;
|
||||||
|
|
||||||
#endif
|
#endif // MESHTASTIC_BME680_BSEC2_SUPPORTED
|
||||||
|
|
||||||
initI2CSensor();
|
initI2CSensor();
|
||||||
return status;
|
return status;
|
||||||
@@ -64,7 +64,7 @@ bool BME680Sensor::initDevice(TwoWire *bus, ScanI2C::FoundDevice *dev)
|
|||||||
|
|
||||||
bool BME680Sensor::getMetrics(meshtastic_Telemetry *measurement)
|
bool BME680Sensor::getMetrics(meshtastic_Telemetry *measurement)
|
||||||
{
|
{
|
||||||
#if __has_include(<bsec2.h>)
|
#if MESHTASTIC_BME680_BSEC2_SUPPORTED == 1
|
||||||
if (bme680.getData(BSEC_OUTPUT_RAW_PRESSURE).signal == 0)
|
if (bme680.getData(BSEC_OUTPUT_RAW_PRESSURE).signal == 0)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
@@ -98,11 +98,11 @@ bool BME680Sensor::getMetrics(meshtastic_Telemetry *measurement)
|
|||||||
measurement->variant.environment_metrics.barometric_pressure = bme680->readPressure() / 100.0F;
|
measurement->variant.environment_metrics.barometric_pressure = bme680->readPressure() / 100.0F;
|
||||||
measurement->variant.environment_metrics.gas_resistance = bme680->readGas() / 1000.0;
|
measurement->variant.environment_metrics.gas_resistance = bme680->readGas() / 1000.0;
|
||||||
|
|
||||||
#endif
|
#endif // MESHTASTIC_BME680_BSEC2_SUPPORTED
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if __has_include(<bsec2.h>)
|
#if MESHTASTIC_BME680_BSEC2_SUPPORTED == 1
|
||||||
void BME680Sensor::loadState()
|
void BME680Sensor::loadState()
|
||||||
{
|
{
|
||||||
#ifdef FSCom
|
#ifdef FSCom
|
||||||
@@ -179,6 +179,6 @@ void BME680Sensor::checkStatus(const char *functionName)
|
|||||||
else if (bme680.sensor.status > BME68X_OK)
|
else if (bme680.sensor.status > BME68X_OK)
|
||||||
LOG_WARN("%s BME68X code: %d", functionName, bme680.sensor.status);
|
LOG_WARN("%s BME68X code: %d", functionName, bme680.sensor.status);
|
||||||
}
|
}
|
||||||
#endif
|
#endif // MESHTASTIC_BME680_BSEC2_SUPPORTED
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -1,29 +1,29 @@
|
|||||||
#include "configuration.h"
|
#include "configuration.h"
|
||||||
|
|
||||||
#if !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR && (__has_include(<bsec2.h>) || __has_include(<Adafruit_BME680.h>))
|
#if !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR && __has_include(MESHTASTIC_BME680_HEADER)
|
||||||
|
|
||||||
#include "../mesh/generated/meshtastic/telemetry.pb.h"
|
#include "../mesh/generated/meshtastic/telemetry.pb.h"
|
||||||
#include "TelemetrySensor.h"
|
#include "TelemetrySensor.h"
|
||||||
|
|
||||||
#if __has_include(<bsec2.h>)
|
#if MESHTASTIC_BME680_BSEC2_SUPPORTED == 1
|
||||||
#include <bme68xLibrary.h>
|
#include <bme68xLibrary.h>
|
||||||
#include <bsec2.h>
|
#include <bsec2.h>
|
||||||
#else
|
#else
|
||||||
#include <Adafruit_BME680.h>
|
#include <Adafruit_BME680.h>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#endif
|
#endif // MESHTASTIC_BME680_BSEC2_SUPPORTED
|
||||||
|
|
||||||
#define STATE_SAVE_PERIOD UINT32_C(360 * 60 * 1000) // That's 6 hours worth of millis()
|
#define STATE_SAVE_PERIOD UINT32_C(360 * 60 * 1000) // That's 6 hours worth of millis()
|
||||||
|
|
||||||
#if __has_include(<bsec2.h>)
|
#if MESHTASTIC_BME680_BSEC2_SUPPORTED == 1
|
||||||
const uint8_t bsec_config[] = {
|
const uint8_t bsec_config[] = {
|
||||||
#include "config/bme680/bme680_iaq_33v_3s_4d/bsec_iaq.txt"
|
#include "config/bme680/bme680_iaq_33v_3s_4d/bsec_iaq.txt"
|
||||||
};
|
};
|
||||||
#endif
|
#endif // MESHTASTIC_BME680_BSEC2_SUPPORTED
|
||||||
class BME680Sensor : public TelemetrySensor
|
class BME680Sensor : public TelemetrySensor
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
#if __has_include(<bsec2.h>)
|
#if MESHTASTIC_BME680_BSEC2_SUPPORTED == 1
|
||||||
Bsec2 bme680;
|
Bsec2 bme680;
|
||||||
#else
|
#else
|
||||||
using BME680Ptr = std::unique_ptr<Adafruit_BME680>;
|
using BME680Ptr = std::unique_ptr<Adafruit_BME680>;
|
||||||
@@ -31,10 +31,10 @@ class BME680Sensor : public TelemetrySensor
|
|||||||
static BME680Ptr makeBME680(TwoWire *bus) { return std::make_unique<Adafruit_BME680>(bus); }
|
static BME680Ptr makeBME680(TwoWire *bus) { return std::make_unique<Adafruit_BME680>(bus); }
|
||||||
|
|
||||||
BME680Ptr bme680;
|
BME680Ptr bme680;
|
||||||
#endif
|
#endif // MESHTASTIC_BME680_BSEC2_SUPPORTED
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
#if __has_include(<bsec2.h>)
|
#if MESHTASTIC_BME680_BSEC2_SUPPORTED == 1
|
||||||
const char *bsecConfigFileName = "/prefs/bsec.dat";
|
const char *bsecConfigFileName = "/prefs/bsec.dat";
|
||||||
uint8_t bsecState[BSEC_MAX_STATE_BLOB_SIZE] = {0};
|
uint8_t bsecState[BSEC_MAX_STATE_BLOB_SIZE] = {0};
|
||||||
uint8_t accuracy = 0;
|
uint8_t accuracy = 0;
|
||||||
@@ -51,13 +51,13 @@ class BME680Sensor : public TelemetrySensor
|
|||||||
void loadState();
|
void loadState();
|
||||||
void updateState();
|
void updateState();
|
||||||
void checkStatus(const char *functionName);
|
void checkStatus(const char *functionName);
|
||||||
#endif
|
#endif // MESHTASTIC_BME680_BSEC2_SUPPORTED
|
||||||
|
|
||||||
public:
|
public:
|
||||||
BME680Sensor();
|
BME680Sensor();
|
||||||
#if __has_include(<bsec2.h>)
|
#if MESHTASTIC_BME680_BSEC2_SUPPORTED == 1
|
||||||
virtual int32_t runOnce() override;
|
virtual int32_t runOnce() override;
|
||||||
#endif
|
#endif // MESHTASTIC_BME680_BSEC2_SUPPORTED
|
||||||
virtual bool getMetrics(meshtastic_Telemetry *measurement) override;
|
virtual bool getMetrics(meshtastic_Telemetry *measurement) override;
|
||||||
virtual bool initDevice(TwoWire *bus, ScanI2C::FoundDevice *dev) override;
|
virtual bool initDevice(TwoWire *bus, ScanI2C::FoundDevice *dev) override;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,13 +1,17 @@
|
|||||||
#include "MeshtasticOTA.h"
|
#include "MeshtasticOTA.h"
|
||||||
#include "configuration.h"
|
#include "configuration.h"
|
||||||
|
#ifdef ESP_PLATFORM
|
||||||
#include <Preferences.h>
|
#include <Preferences.h>
|
||||||
#include <esp_ota_ops.h>
|
#include <esp_ota_ops.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
namespace MeshtasticOTA
|
namespace MeshtasticOTA
|
||||||
{
|
{
|
||||||
|
|
||||||
static const char *nvsNamespace = "MeshtasticOTA";
|
static const char *nvsNamespace = "MeshtasticOTA";
|
||||||
static const char *appProjectName = "MeshtasticOTA";
|
static const char *combinedAppProjectName = "MeshtasticOTA";
|
||||||
|
static const char *bleOnlyAppProjectName = "MeshtasticOTA-BLE";
|
||||||
|
static const char *wifiOnlyAppProjectName = "MeshtasticOTA-WiFi";
|
||||||
|
|
||||||
static bool updated = false;
|
static bool updated = false;
|
||||||
|
|
||||||
@@ -68,21 +72,44 @@ bool getAppDesc(const esp_partition_t *part, esp_app_desc_t *app_desc)
|
|||||||
LOG_INFO("esp_ota_get_partition_description failed");
|
LOG_INFO("esp_ota_get_partition_description failed");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (strcmp(app_desc->project_name, appProjectName) != 0) {
|
|
||||||
LOG_INFO("app_desc->project_name == 0");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool checkOTACapability(esp_app_desc_t *app_desc, uint8_t method)
|
||||||
|
{
|
||||||
|
// Combined loader supports all (both) transports, BLE and WiFi
|
||||||
|
if (strcmp(app_desc->project_name, combinedAppProjectName) == 0) {
|
||||||
|
LOG_INFO("OTA partition contains combined BLE/WiFi OTA Loader");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (method == METHOD_OTA_BLE && strcmp(app_desc->project_name, bleOnlyAppProjectName) == 0) {
|
||||||
|
LOG_INFO("OTA partition contains BLE-only OTA Loader");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (method == METHOD_OTA_WIFI && strcmp(app_desc->project_name, wifiOnlyAppProjectName) == 0) {
|
||||||
|
LOG_INFO("OTA partition contains WiFi-only OTA Loader");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
LOG_INFO("OTA partition does not contain a known OTA loader");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
bool trySwitchToOTA()
|
bool trySwitchToOTA()
|
||||||
{
|
{
|
||||||
const esp_partition_t *part = getAppPartition();
|
const esp_partition_t *part = getAppPartition();
|
||||||
esp_app_desc_t app_desc;
|
|
||||||
if (!getAppDesc(part, &app_desc))
|
if (part == NULL) {
|
||||||
|
LOG_WARN("Unable to get app partition in preparation of OTA reboot");
|
||||||
return false;
|
return false;
|
||||||
if (esp_ota_set_boot_partition(part) != ESP_OK)
|
}
|
||||||
|
|
||||||
|
uint8_t result = esp_ota_set_boot_partition(part);
|
||||||
|
// Partition and app checks should now be done in the AdminModule before this is called
|
||||||
|
if (result != ESP_OK) {
|
||||||
|
LOG_WARN("Unable to switch to OTA partiton. (Reason %d)", result);
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -3,12 +3,20 @@
|
|||||||
|
|
||||||
#include "mesh-pb-constants.h"
|
#include "mesh-pb-constants.h"
|
||||||
#include <Arduino.h>
|
#include <Arduino.h>
|
||||||
|
#ifdef ESP_PLATFORM
|
||||||
|
#include <esp_ota_ops.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define METHOD_OTA_BLE 1
|
||||||
|
#define METHOD_OTA_WIFI 2
|
||||||
|
|
||||||
namespace MeshtasticOTA
|
namespace MeshtasticOTA
|
||||||
{
|
{
|
||||||
void initialize();
|
void initialize();
|
||||||
bool isUpdated();
|
bool isUpdated();
|
||||||
|
const esp_partition_t *getAppPartition();
|
||||||
|
bool getAppDesc(const esp_partition_t *part, esp_app_desc_t *app_desc);
|
||||||
|
bool checkOTACapability(esp_app_desc_t *app_desc, uint8_t method);
|
||||||
void recoverConfig(meshtastic_Config_NetworkConfig *network);
|
void recoverConfig(meshtastic_Config_NetworkConfig *network);
|
||||||
void saveConfig(meshtastic_Config_NetworkConfig *network, meshtastic_OTAMode method, uint8_t *ota_hash);
|
void saveConfig(meshtastic_Config_NetworkConfig *network, meshtastic_OTAMode method, uint8_t *ota_hash);
|
||||||
bool trySwitchToOTA();
|
bool trySwitchToOTA();
|
||||||
|
|||||||
@@ -55,7 +55,6 @@ void cpuDeepSleep(uint32_t msecs)
|
|||||||
void updateBatteryLevel(uint8_t level) NOT_IMPLEMENTED("updateBatteryLevel");
|
void updateBatteryLevel(uint8_t level) NOT_IMPLEMENTED("updateBatteryLevel");
|
||||||
|
|
||||||
int TCPPort = SERVER_API_DEFAULT_PORT;
|
int TCPPort = SERVER_API_DEFAULT_PORT;
|
||||||
bool checkConfigPort = true;
|
|
||||||
|
|
||||||
static error_t parse_opt(int key, char *arg, struct argp_state *state)
|
static error_t parse_opt(int key, char *arg, struct argp_state *state)
|
||||||
{
|
{
|
||||||
@@ -64,7 +63,6 @@ static error_t parse_opt(int key, char *arg, struct argp_state *state)
|
|||||||
if (sscanf(arg, "%d", &TCPPort) < 1)
|
if (sscanf(arg, "%d", &TCPPort) < 1)
|
||||||
return ARGP_ERR_UNKNOWN;
|
return ARGP_ERR_UNKNOWN;
|
||||||
else
|
else
|
||||||
checkConfigPort = false;
|
|
||||||
printf("Using config file %d\n", TCPPort);
|
printf("Using config file %d\n", TCPPort);
|
||||||
break;
|
break;
|
||||||
case 'c':
|
case 'c':
|
||||||
@@ -872,14 +870,6 @@ bool loadConfig(const char *configPath)
|
|||||||
std::cout << "Cannot set both MACAddress and MACAddressSource!" << std::endl;
|
std::cout << "Cannot set both MACAddress and MACAddressSource!" << std::endl;
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
if (checkConfigPort) {
|
|
||||||
portduino_config.api_port = (yamlConfig["General"]["APIPort"]).as<int>(-1);
|
|
||||||
if (portduino_config.api_port != -1 &&
|
|
||||||
portduino_config.api_port > 1023 &&
|
|
||||||
portduino_config.api_port < 65536) {
|
|
||||||
TCPPort = (portduino_config.api_port);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
portduino_config.mac_address = (yamlConfig["General"]["MACAddress"]).as<std::string>("");
|
portduino_config.mac_address = (yamlConfig["General"]["MACAddress"]).as<std::string>("");
|
||||||
if (portduino_config.mac_address != "") {
|
if (portduino_config.mac_address != "") {
|
||||||
portduino_config.mac_address_explicit = true;
|
portduino_config.mac_address_explicit = true;
|
||||||
|
|||||||
@@ -175,7 +175,6 @@ extern struct portduino_config_struct {
|
|||||||
std::string mac_address = "";
|
std::string mac_address = "";
|
||||||
bool mac_address_explicit = false;
|
bool mac_address_explicit = false;
|
||||||
std::string mac_address_source = "";
|
std::string mac_address_source = "";
|
||||||
int api_port = -1;
|
|
||||||
std::string config_directory = "";
|
std::string config_directory = "";
|
||||||
std::string available_directory = "/etc/meshtasticd/available.d/";
|
std::string available_directory = "/etc/meshtasticd/available.d/";
|
||||||
int maxtophone = 100;
|
int maxtophone = 100;
|
||||||
@@ -509,8 +508,6 @@ extern struct portduino_config_struct {
|
|||||||
out << YAML::Key << "General" << YAML::Value << YAML::BeginMap;
|
out << YAML::Key << "General" << YAML::Value << YAML::BeginMap;
|
||||||
if (config_directory != "")
|
if (config_directory != "")
|
||||||
out << YAML::Key << "ConfigDirectory" << YAML::Value << config_directory;
|
out << YAML::Key << "ConfigDirectory" << YAML::Value << config_directory;
|
||||||
if (api_port != -1)
|
|
||||||
out << YAML::Key << "TCPPort" << YAML::Value << api_port;
|
|
||||||
if (mac_address_explicit)
|
if (mac_address_explicit)
|
||||||
out << YAML::Key << "MACAddress" << YAML::Value << mac_address;
|
out << YAML::Key << "MACAddress" << YAML::Value << mac_address;
|
||||||
if (mac_address_source != "")
|
if (mac_address_source != "")
|
||||||
@@ -522,4 +519,4 @@ extern struct portduino_config_struct {
|
|||||||
out << YAML::EndMap; // General
|
out << YAML::EndMap; // General
|
||||||
return out.c_str();
|
return out.c_str();
|
||||||
}
|
}
|
||||||
} portduino_config;
|
} portduino_config;
|
||||||
@@ -10,6 +10,8 @@ custom_meshtastic_tags = M5Stack
|
|||||||
|
|
||||||
extends = esp32c6_base
|
extends = esp32c6_base
|
||||||
board = esp32-c6-devkitc-1
|
board = esp32-c6-devkitc-1
|
||||||
|
board_upload.flash_size = 16MB
|
||||||
|
board_build.partitions = default_16MB.csv
|
||||||
;OpenOCD flash method
|
;OpenOCD flash method
|
||||||
;upload_protocol = esp-builtin
|
;upload_protocol = esp-builtin
|
||||||
;Normal method
|
;Normal method
|
||||||
|
|||||||
Reference in New Issue
Block a user