Merge branch 'master' into raspi-portduino

This commit is contained in:
Thomas Göttgens 2023-04-21 16:50:48 +02:00 committed by GitHub
commit 85818b8dfd
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
57 changed files with 541 additions and 139 deletions

View File

@ -42,6 +42,7 @@ jobs:
uses: ./.github/actions/setup-base
- name: Trunk Check
if: ${{ github.event_name != 'workflow_dispatch' }}
uses: trunk-io/trunk-action@v1
- name: Check ${{ matrix.board }}

View File

@ -35,7 +35,7 @@ lib_deps =
https://github.com/meshtastic/esp32_https_server.git#23665b3adc080a311dcbb586ed5941b5f94d6ea2
h2zero/NimBLE-Arduino@^1.4.0
https://github.com/lewisxhe/XPowersLib.git#84b7373faea3118b6c37954d52f98b8a337148d6
caveman99/ESP32 Codec2@^1.0.1
https://github.com/meshtastic/ESP32_Codec2.git#633326c78ac251c059ab3a8c430fcdf25b41672f
lib_ignore =
segger_rtt

View File

@ -34,8 +34,7 @@ lib_deps =
https://github.com/meshtastic/esp32_https_server.git#23665b3adc080a311dcbb586ed5941b5f94d6ea2
h2zero/NimBLE-Arduino@^1.4.0
https://github.com/lewisxhe/XPowersLib.git#84b7373faea3118b6c37954d52f98b8a337148d6
caveman99/ESP32 Codec2@^1.0.1
https://github.com/meshtastic/ESP32_Codec2.git#633326c78ac251c059ab3a8c430fcdf25b41672f
lib_ignore =
segger_rtt
ESP32 BLE Arduino

View File

@ -35,7 +35,7 @@ lib_deps =
${environmental_base.lib_deps}
https://github.com/meshtastic/esp32_https_server.git#23665b3adc080a311dcbb586ed5941b5f94d6ea2
https://github.com/lewisxhe/XPowersLib.git#84b7373faea3118b6c37954d52f98b8a337148d6
caveman99/ESP32 Codec2@^1.0.1
https://github.com/meshtastic/ESP32_Codec2.git#633326c78ac251c059ab3a8c430fcdf25b41672f
lib_ignore =
segger_rtt

View File

@ -35,7 +35,7 @@ lib_deps =
https://github.com/meshtastic/esp32_https_server.git#23665b3adc080a311dcbb586ed5941b5f94d6ea2
h2zero/NimBLE-Arduino@^1.4.0
https://github.com/lewisxhe/XPowersLib.git#84b7373faea3118b6c37954d52f98b8a337148d6
caveman99/ESP32 Codec2@^1.0.1
https://github.com/meshtastic/ESP32_Codec2.git#633326c78ac251c059ab3a8c430fcdf25b41672f
lib_ignore =
segger_rtt

38
bin/generate_ci_matrix.py Executable file
View File

@ -0,0 +1,38 @@
#!/usr/bin/env python
"""Generate the CI matrix"""
import configparser
import json
import os
import sys
rootdir = "variants/"
options = sys.argv[1:]
outlist = []
if len(options) < 1:
print(json.dumps(outlist))
exit()
for subdir, dirs, files in os.walk(rootdir):
for file in files:
if file == "platformio.ini":
config = configparser.ConfigParser()
config.read(subdir + "/" + file)
for c in config.sections():
if c.startswith("env:"):
section = config[c].name[4:]
if "extends" in config[config[c].name]:
if config[config[c].name]["extends"] == options[0] + "_base":
if "board_level" in config[config[c].name]:
if (
config[config[c].name]["board_level"] == "extra"
) & ("extra" in options):
outlist.append(section)
else:
outlist.append(section)
print(json.dumps(outlist))

View File

@ -1,5 +1 @@
cd protobufs && ..\nanopb-0.4.7\generator-bin\protoc.exe --nanopb_out=-v:..\src\mesh\generated -I=..\protobufs ..\protobufs\meshtastic\*.proto
@REM cd ../src/mesh/generated/meshtastic
@REM sed -i 's/#include "meshtastic/#include "./g' *
@REM sed -i 's/meshtastic_//g' *
cd protobufs && ..\nanopb-0.4.7\generator-bin\protoc.exe --experimental_allow_proto3_optional --nanopb_out=-v:..\src\mesh\generated -I=..\protobufs ..\protobufs\meshtastic\*.proto

View File

@ -85,7 +85,7 @@ lib_deps =
${env.lib_deps}
mprograms/QMC5883LCompass@^1.1.1
end2endzone/NonBlockingRTTTL@^1.3.0
https://github.com/meshtastic/SparkFun_ATECCX08a_Arduino_Library.git#52b5282639d08a8cbd4b748363089eed6102dc76
https://github.com/meshtastic/SparkFun_ATECCX08a_Arduino_Library.git#5cf62b36c6f30bc72a07bdb2c11fc9a22d1e31da
build_flags = ${env.build_flags} -Os -DRADIOLIB_SPI_PARANOID=0
build_src_filter = ${env.build_src_filter} -<platform/portduino/>
@ -105,7 +105,7 @@ lib_deps =
adafruit/Adafruit Unified Sensor@^1.1.9
adafruit/Adafruit BMP280 Library@^2.6.6
adafruit/Adafruit BME280 Library@^2.2.2
adafruit/Adafruit BME680 Library@^2.0.1
https://github.com/meshtastic/BSEC-Arduino-library.git#452f9a7ffa8b53e1debe2c454fe375dfad98b507
adafruit/Adafruit MCP9808 Library@^2.0.0
adafruit/Adafruit INA260 Library@^1.5.0
adafruit/Adafruit INA219@^1.2.0

@ -1 +1 @@
Subproject commit 641d7c3a460de9cc580bc2b8a0812e8b9d417b05
Subproject commit ef2bc66bba41e8ef98ea893e46eb36a2da40cb5e

View File

@ -45,10 +45,10 @@ class ButtonThread : public concurrency::OSThread
ButtonThread() : OSThread("Button")
{
#ifdef BUTTON_PIN
userButton = OneButton(BUTTON_PIN, true, true);
userButton = OneButton(config.device.button_gpio ? config.device.button_gpio : BUTTON_PIN, true, true);
#ifdef INPUT_PULLUP_SENSE
// Some platforms (nrf52) have a SENSE variant which allows wake from sleep - override what OneButton did
pinMode(BUTTON_PIN, INPUT_PULLUP_SENSE);
pinMode(config.device.button_gpio ? config.device.button_gpio : BUTTON_PIN, INPUT_PULLUP_SENSE);
#endif
userButton.attachClick(userButtonPressed);
userButton.setClickTicks(300);
@ -57,7 +57,7 @@ class ButtonThread : public concurrency::OSThread
userButton.attachMultiClick(userButtonMultiPressed);
userButton.attachLongPressStart(userButtonPressedLongStart);
userButton.attachLongPressStop(userButtonPressedLongStop);
wakeOnIrq(BUTTON_PIN, FALLING);
wakeOnIrq(config.device.button_gpio ? config.device.button_gpio : BUTTON_PIN, FALLING);
#endif
#ifdef BUTTON_PIN_ALT
userButtonAlt = OneButton(BUTTON_PIN_ALT, true, true);
@ -115,7 +115,9 @@ class ButtonThread : public concurrency::OSThread
{
// LOG_DEBUG("press!\n");
#ifdef BUTTON_PIN
if ((BUTTON_PIN != moduleConfig.canned_message.inputbroker_pin_press) || !moduleConfig.canned_message.enabled) {
if (((config.device.button_gpio ? config.device.button_gpio : BUTTON_PIN) !=
moduleConfig.canned_message.inputbroker_pin_press) ||
!moduleConfig.canned_message.enabled) {
powerFSM.trigger(EVENT_PRESS);
}
#endif
@ -124,13 +126,8 @@ class ButtonThread : public concurrency::OSThread
{
// LOG_DEBUG("Long press!\n");
// If user button is held down for 5 seconds, shutdown the device.
if ((millis() - longPressTime > 5 * 1000) && (longPressTime > 0)) {
#ifdef HAS_PMU
if (pmu_found == true) {
setLed(false);
power->shutdown();
}
#elif defined(ARCH_NRF52) || defined(ARCH_ESP32)
if ((millis() - longPressTime > 5000) && (longPressTime > 0)) {
#if defined(ARCH_NRF52) || defined(ARCH_ESP32)
// Do actual shutdown when button released, otherwise the button release
// may wake the board immediatedly.
if ((!shutdown_on_long_stop) && (millis() > 30 * 1000)) {

View File

@ -34,6 +34,7 @@ bool copyFile(const char *from, const char *to)
f2.write(cbuffer, i);
}
f2.flush();
f2.close();
f1.close();
return true;

View File

@ -212,7 +212,7 @@ Power::Power() : OSThread("Power")
statusHandler = {};
low_voltage_counter = 0;
#ifdef DEBUG_HEAP
lastheap = ESP.getFreeHeap();
lastheap = memGet.getFreeHeap();
#endif
}
@ -277,12 +277,11 @@ void Power::shutdown()
LOG_INFO("Shutting down\n");
#ifdef HAS_PMU
if (PMU) {
if (pmu_found == true) {
PMU->setChargingLedMode(XPOWERS_CHG_LED_OFF);
PMU->shutdown();
}
#endif
#if defined(ARCH_NRF52) || defined(ARCH_ESP32)
#elif defined(ARCH_NRF52) || defined(ARCH_ESP32)
#ifdef PIN_LED1
ledOff(PIN_LED1);
#endif
@ -328,7 +327,7 @@ void Power::readPowerStatus()
powerStatus2.getIsCharging(), powerStatus2.getBatteryVoltageMv(), powerStatus2.getBatteryChargePercent());
newStatus.notifyObservers(&powerStatus2);
#ifdef DEBUG_HEAP
if (lastheap != ESP.getFreeHeap()) {
if (lastheap != memGet.getFreeHeap()) {
LOG_DEBUG("Threads running:");
int running = 0;
for (int i = 0; i < MAX_THREADS; i++) {
@ -339,9 +338,9 @@ void Power::readPowerStatus()
}
}
LOG_DEBUG("\n");
LOG_DEBUG("Heap status: %d/%d bytes free (%d), running %d/%d threads\n", ESP.getFreeHeap(), ESP.getHeapSize(),
ESP.getFreeHeap() - lastheap, running, concurrency::mainController.size(false));
lastheap = ESP.getFreeHeap();
LOG_DEBUG("Heap status: %d/%d bytes free (%d), running %d/%d threads\n", memGet.getFreeHeap(), memGet.getHeapSize(),
memGet.getFreeHeap() - lastheap, running, concurrency::mainController.size(false));
lastheap = memGet.getFreeHeap();
}
#ifdef DEBUG_HEAP_MQTT
if (mqtt) {
@ -350,15 +349,17 @@ void Power::readPowerStatus()
getMacAddr(dmac); // Get our hardware ID
char mac[18];
sprintf(mac, "!%02x%02x%02x%02x", dmac[2], dmac[3], dmac[4], dmac[5]);
auto newHeap = ESP.getFreeHeap();
std::string heapTopic = "msh/2/heap/" + std::string(mac);
auto newHeap = memGet.getFreeHeap();
std::string heapTopic =
(*moduleConfig.mqtt.root ? moduleConfig.mqtt.root : "msh") + std::string("/2/heap/") + std::string(mac);
std::string heapString = std::to_string(newHeap);
mqtt->pubSub.publish(heapTopic.c_str(), heapString.c_str(), false);
// auto fragHeap = ESP.getHeapFragmentation();
auto wifiRSSI = WiFi.RSSI();
heapTopic = "msh/2/wifi/" + std::string(mac);
std::string wifiTopic =
(*moduleConfig.mqtt.root ? moduleConfig.mqtt.root : "msh") + std::string("/2/wifi/") + std::string(mac);
std::string wifiString = std::to_string(wifiRSSI);
mqtt->pubSub.publish(heapTopic.c_str(), wifiString.c_str(), false);
mqtt->pubSub.publish(wifiTopic.c_str(), wifiString.c_str(), false);
}
#endif

View File

@ -93,18 +93,23 @@ static void lsIdle()
powerFSM.trigger(EVENT_SERIAL_CONNECTED);
break;
case ESP_SLEEP_WAKEUP_GPIO:
// GPIO of BUTTON_PIN (if available) triggered the wakeup
powerFSM.trigger(EVENT_PRESS);
break;
default:
// We woke for some other reason (device interrupt)
// We woke for some other reason (button press, device interrupt)
// uint64_t status = esp_sleep_get_ext1_wakeup_status();
LOG_INFO("wakeCause2 %d\n", wakeCause2);
// Let the NB state handle the IRQ (and that state will handle stuff like IRQs etc)
// we lie and say "wake timer" because the interrupt will be handled by the regular IRQ code
powerFSM.trigger(EVENT_WAKE_TIMER);
#ifdef BUTTON_PIN
bool pressed = !digitalRead(config.device.button_gpio ? config.device.button_gpio : BUTTON_PIN);
#else
bool pressed = false;
#endif
if (pressed) { // If we woke because of press, instead generate a PRESS event.
powerFSM.trigger(EVENT_PRESS);
} else {
// Otherwise let the NB state handle the IRQ (and that state will handle stuff like IRQs etc)
// we lie and say "wake timer" because the interrupt will be handled by the regular IRQ code
powerFSM.trigger(EVENT_WAKE_TIMER);
}
break;
}
} else {
@ -348,4 +353,4 @@ void PowerFSM_setup()
#endif
powerFSM.run_machine(); // run one interation of the state machine, so we run our on enter tasks for the initial DARK state
}
}

View File

@ -1,5 +1,6 @@
#include "OSThread.h"
#include "configuration.h"
#include "memGet.h"
#include <assert.h>
namespace concurrency
@ -75,12 +76,12 @@ bool OSThread::shouldRun(unsigned long time)
void OSThread::run()
{
#ifdef DEBUG_HEAP
auto heap = ESP.getFreeHeap();
auto heap = memGet.getFreeHeap();
#endif
currentThread = this;
auto newDelay = runOnce();
#ifdef DEBUG_HEAP
auto newHeap = ESP.getFreeHeap();
auto newHeap = memGet.getFreeHeap();
if (newHeap < heap)
LOG_DEBUG("------ Thread %s leaked heap %d -> %d (%d) ------\n", ThreadName.c_str(), heap, newHeap, newHeap - heap);
if (heap < newHeap)

View File

@ -142,17 +142,6 @@ static int32_t ledBlinker()
setLed(ledOn);
#ifdef ARCH_ESP32
auto newHeap = ESP.getFreeHeap();
if (newHeap < 11000) {
LOG_DEBUG("\n\n====== heap too low [11000] -> reboot in 1s ======\n\n");
#ifdef HAS_SCREEN
screen->startRebootScreen();
#endif
rebootAtMsec = millis() + 900;
}
#endif
// have a very sparse duty cycle of LED being on, unless charging, then blink 0.5Hz square wave rate to indicate that
return powerStatus->getIsCharging() ? 1000 : (ledOn ? 1 : 1000);
}
@ -229,10 +218,10 @@ void setup()
// If the button is connected to GPIO 12, don't enable the ability to use
// meshtasticAdmin on the device.
pinMode(BUTTON_PIN, INPUT);
pinMode(config.device.button_gpio ? config.device.button_gpio : BUTTON_PIN, INPUT);
#ifdef BUTTON_NEED_PULLUP
gpio_pullup_en((gpio_num_t)BUTTON_PIN);
gpio_pullup_en((gpio_num_t)(config.device.button_gpio ? config.device.button_gpio : BUTTON_PIN));
delay(10);
#endif
@ -400,10 +389,7 @@ void setup()
// scanEInkDevice();
#endif
#if HAS_BUTTON
// Buttons & LED
buttonThread = new ButtonThread();
#endif
// LED init
#ifdef LED_PIN
pinMode(LED_PIN, OUTPUT);
@ -428,6 +414,11 @@ void setup()
if (config.device.role == meshtastic_Config_DeviceConfig_Role_REPEATER)
router = new FloodingRouter();
#if HAS_BUTTON
// Buttons. Moved here cause we need NodeDB to be initialized
buttonThread = new ButtonThread();
#endif
playStartMelody();
// fixed screen override?

View File

@ -5,6 +5,7 @@
#include "PowerStatus.h"
#include "detect/ScanI2C.h"
#include "graphics/Screen.h"
#include "memGet.h"
#include "mesh/generated/meshtastic/config.pb.h"
#include "mesh/generated/meshtastic/telemetry.pb.h"
#include <map>

46
src/memGet.cpp Normal file
View File

@ -0,0 +1,46 @@
#include "memGet.h"
#include "configuration.h"
MemGet memGet;
uint32_t MemGet::getFreeHeap()
{
#ifdef ARCH_ESP32
return ESP.getFreeHeap();
#elif defined(ARCH_NRF52)
return dbgHeapFree();
#else
// this platform does not have heap management function implemented
return UINT32_MAX;
#endif
}
uint32_t MemGet::getHeapSize()
{
#ifdef ARCH_ESP32
return ESP.getHeapSize();
#elif defined(ARCH_NRF52)
return dbgHeapTotal();
#else
// this platform does not have heap management function implemented
return UINT32_MAX;
#endif
}
uint32_t MemGet::getFreePsram()
{
#ifdef ARCH_ESP32
return ESP.getFreePsram();
#else
return 0;
#endif
}
uint32_t MemGet::getPsramSize()
{
#ifdef ARCH_ESP32
return ESP.getPsramSize();
#else
return 0;
#endif
}

18
src/memGet.h Normal file
View File

@ -0,0 +1,18 @@
#pragma once
#ifndef _MT_MEMGET_H
#define _MT_MEMGET_H
#include <Arduino.h>
class MemGet
{
public:
uint32_t getFreeHeap();
uint32_t getHeapSize();
uint32_t getFreePsram();
uint32_t getPsramSize();
};
extern MemGet memGet;
#endif

View File

@ -1,6 +1,8 @@
#include "CryptoEngine.h"
#include "configuration.h"
concurrency::Lock *cryptLock;
void CryptoEngine::setKey(const CryptoKey &k)
{
LOG_DEBUG("Using AES%d key!\n", k.length * 8);

View File

@ -1,7 +1,10 @@
#pragma once
#include "concurrency/LockGuard.h"
#include <Arduino.h>
extern concurrency::Lock *cryptLock;
struct CryptoKey {
uint8_t bytes[32];

View File

@ -490,6 +490,7 @@ bool NodeDB::saveProto(const char *filename, size_t protoSize, const pb_msgdesc_
} else {
okay = true;
}
f.flush();
f.close();
// brief window of risk here ;-)
@ -689,11 +690,11 @@ void NodeDB::updateTelemetry(uint32_t nodeId, const meshtastic_Telemetry &t, RxS
/** Update user info for this node based on received user data
*/
void NodeDB::updateUser(uint32_t nodeId, const meshtastic_User &p)
bool NodeDB::updateUser(uint32_t nodeId, const meshtastic_User &p)
{
meshtastic_NodeInfo *info = getOrCreateNode(nodeId);
if (!info) {
return;
return false;
}
LOG_DEBUG("old user %s/%s/%s\n", info->user.id, info->user.long_name, info->user.short_name);
@ -713,6 +714,8 @@ void NodeDB::updateUser(uint32_t nodeId, const meshtastic_User &p)
// We just changed something important about the user, store our DB
saveToDisk(SEGMENT_DEVICESTATE);
}
return changed;
}
/// given a subpacket sniffed from the network, update our DB state
@ -765,7 +768,7 @@ meshtastic_NodeInfo *NodeDB::getOrCreateNode(NodeNum n)
meshtastic_NodeInfo *info = getNode(n);
if (!info) {
if (*numNodes >= MAX_NUM_NODES) {
if ((*numNodes >= MAX_NUM_NODES) || (memGet.getFreeHeap() < meshtastic_NodeInfo_size * 3)) {
screen->print("warning: node_db full! erasing oldest entry\n");
// look for oldest node and erase it
uint32_t oldest = UINT32_MAX;

View File

@ -86,7 +86,7 @@ class NodeDB
/** Update user info for this node based on received user data
*/
void updateUser(uint32_t nodeId, const meshtastic_User &p);
bool updateUser(uint32_t nodeId, const meshtastic_User &p);
/// @return our node number
NodeNum getNodeNum() { return myNodeInfo.my_node_num; }

View File

@ -55,6 +55,10 @@ Router::Router() : concurrency::OSThread("Router"), fromRadioQueue(MAX_RX_FROMRA
LOG_DEBUG("Size of MeshPacket %d\n", sizeof(MeshPacket)); */
fromRadioQueue.setReader(this);
// init Lockguard for crypt operations
assert(!cryptLock);
cryptLock = new concurrency::Lock();
}
/**
@ -305,6 +309,8 @@ void Router::sniffReceived(const meshtastic_MeshPacket *p, const meshtastic_Rout
bool perhapsDecode(meshtastic_MeshPacket *p)
{
concurrency::LockGuard g(cryptLock);
if (config.device.role == meshtastic_Config_DeviceConfig_Role_REPEATER &&
config.device.rebroadcast_mode == meshtastic_Config_DeviceConfig_RebroadcastMode_ALL_SKIP_DECODING)
return false;
@ -371,6 +377,8 @@ bool perhapsDecode(meshtastic_MeshPacket *p)
*/
meshtastic_Routing_Error perhapsEncode(meshtastic_MeshPacket *p)
{
concurrency::LockGuard g(cryptLock);
// If the packet is not yet encrypted, do so now
if (p->which_payload_variant == meshtastic_MeshPacket_decoded_tag) {
size_t numbytes = pb_encode_to_bytes(bytes, sizeof(bytes), &meshtastic_Data_msg, &p->decoded);

View File

@ -31,11 +31,9 @@ typedef enum _meshtastic_Channel_Role {
/* Struct definitions */
typedef PB_BYTES_ARRAY_T(32) meshtastic_ChannelSettings_psk_t;
/* Full settings (center freq, spread factor, pre-shared secret key etc...)
needed to configure a radio for speaking on a particular channel This
information can be encoded as a QRcode/url so that other users can configure
/* This information can be encoded as a QRcode/url so that other users can configure
their radio to join the same channel.
A note about how channel names are shown to users: channelname-Xy
A note about how channel names are shown to users: channelname-X
poundsymbol is a prefix used to indicate this is a channel name (idea from @professr).
Where X is a letter from A-Z (base 26) representing a hash of the PSK for this
channel - so that if the user changes anything about the channel (which does
@ -45,8 +43,6 @@ typedef PB_BYTES_ARRAY_T(32) meshtastic_ChannelSettings_psk_t;
The PSK is hashed into this letter by "0x41 + [xor all bytes of the psk ] modulo 26"
This also allows the option of someday if people have the PSK off (zero), the
users COULD type in a channel name and be able to talk.
Y is a lower case letter from a-z that represents the channel 'speed' settings
(for some future definition of speed)
FIXME: Add description of multi-channel support and how primary vs secondary channels are used.
FIXME: explain how apps use channels for security.
explain how remote settings and remote gpio are managed as an example */
@ -60,7 +56,7 @@ typedef struct _meshtastic_ChannelSettings {
because they are listed in this source code.
Those bytes are mapped using the following scheme:
`0` = No crypto
`1` = The special "default" channel key: {0xd4, 0xf1, 0xbb, 0x3a, 0x20, 0x29, 0x07, 0x59, 0xf0, 0xbc, 0xff, 0xab, 0xcf, 0x4e, 0x69, 0xbf}
`1` = The special "default" channel key: {0xd4, 0xf1, 0xbb, 0x3a, 0x20, 0x29, 0x07, 0x59, 0xf0, 0xbc, 0xff, 0xab, 0xcf, 0x4e, 0x69, 0x01}
`2` through 10 = The default channel key, except with 1 through 9 added to the last byte.
Shown to user as simple1 through 10 */
meshtastic_ChannelSettings_psk_t psk;

View File

@ -0,0 +1,12 @@
/* Automatically generated nanopb constant definitions */
/* Generated by nanopb-0.4.7 */
#include "meshtastic/clientonly.pb.h"
#if PB_PROTO_HEADER_VERSION != 40
#error Regenerate this file with the current version of nanopb generator.
#endif
PB_BIND(meshtastic_DeviceProfile, meshtastic_DeviceProfile, 2)

View File

@ -0,0 +1,73 @@
/* Automatically generated nanopb header */
/* Generated by nanopb-0.4.7 */
#ifndef PB_MESHTASTIC_MESHTASTIC_CLIENTONLY_PB_H_INCLUDED
#define PB_MESHTASTIC_MESHTASTIC_CLIENTONLY_PB_H_INCLUDED
#include <pb.h>
#include "meshtastic/localonly.pb.h"
#if PB_PROTO_HEADER_VERSION != 40
#error Regenerate this file with the current version of nanopb generator.
#endif
/* Struct definitions */
/* This abstraction is used to contain any configuration for provisioning a node on any client.
It is useful for importing and exporting configurations. */
typedef struct _meshtastic_DeviceProfile {
/* Long name for the node */
bool has_long_name;
char long_name[40];
/* Short name of the node */
bool has_short_name;
char short_name[5];
/* The url of the channels from our node */
pb_callback_t channel_url;
/* The Config of the node */
bool has_config;
meshtastic_LocalConfig config;
/* The ModuleConfig of the node */
bool has_module_config;
meshtastic_LocalModuleConfig module_config;
} meshtastic_DeviceProfile;
#ifdef __cplusplus
extern "C" {
#endif
/* Initializer values for message structs */
#define meshtastic_DeviceProfile_init_default {false, "", false, "", {{NULL}, NULL}, false, meshtastic_LocalConfig_init_default, false, meshtastic_LocalModuleConfig_init_default}
#define meshtastic_DeviceProfile_init_zero {false, "", false, "", {{NULL}, NULL}, false, meshtastic_LocalConfig_init_zero, false, meshtastic_LocalModuleConfig_init_zero}
/* Field tags (for use in manual encoding/decoding) */
#define meshtastic_DeviceProfile_long_name_tag 1
#define meshtastic_DeviceProfile_short_name_tag 2
#define meshtastic_DeviceProfile_channel_url_tag 3
#define meshtastic_DeviceProfile_config_tag 4
#define meshtastic_DeviceProfile_module_config_tag 5
/* Struct field encoding specification for nanopb */
#define meshtastic_DeviceProfile_FIELDLIST(X, a) \
X(a, STATIC, OPTIONAL, STRING, long_name, 1) \
X(a, STATIC, OPTIONAL, STRING, short_name, 2) \
X(a, CALLBACK, OPTIONAL, STRING, channel_url, 3) \
X(a, STATIC, OPTIONAL, MESSAGE, config, 4) \
X(a, STATIC, OPTIONAL, MESSAGE, module_config, 5)
#define meshtastic_DeviceProfile_CALLBACK pb_default_field_callback
#define meshtastic_DeviceProfile_DEFAULT NULL
#define meshtastic_DeviceProfile_config_MSGTYPE meshtastic_LocalConfig
#define meshtastic_DeviceProfile_module_config_MSGTYPE meshtastic_LocalModuleConfig
extern const pb_msgdesc_t meshtastic_DeviceProfile_msg;
/* Defines for backwards compatibility with code written before nanopb-0.4.0 */
#define meshtastic_DeviceProfile_fields &meshtastic_DeviceProfile_msg
/* Maximum encoded size of messages (where known) */
/* meshtastic_DeviceProfile_size depends on runtime parameters */
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif

View File

@ -188,7 +188,7 @@ extern const pb_msgdesc_t meshtastic_OEMStore_msg;
/* Maximum encoded size of messages (where known) */
#define meshtastic_ChannelFile_size 638
#define meshtastic_DeviceState_size 22040
#define meshtastic_OEMStore_size 3024
#define meshtastic_OEMStore_size 3041
#ifdef __cplusplus
} /* extern "C" */

View File

@ -157,7 +157,7 @@ extern const pb_msgdesc_t meshtastic_LocalModuleConfig_msg;
/* Maximum encoded size of messages (where known) */
#define meshtastic_LocalConfig_size 456
#define meshtastic_LocalModuleConfig_size 422
#define meshtastic_LocalModuleConfig_size 439
#ifdef __cplusplus
} /* extern "C" */

View File

@ -48,6 +48,12 @@ PB_BIND(meshtastic_ToRadio, meshtastic_ToRadio, 2)
PB_BIND(meshtastic_Compressed, meshtastic_Compressed, AUTO)
PB_BIND(meshtastic_NeighborInfo, meshtastic_NeighborInfo, AUTO)
PB_BIND(meshtastic_Neighbor, meshtastic_Neighbor, AUTO)
PB_BIND(meshtastic_DeviceMetadata, meshtastic_DeviceMetadata, AUTO)

View File

@ -680,6 +680,25 @@ typedef struct _meshtastic_Compressed {
meshtastic_Compressed_data_t data;
} meshtastic_Compressed;
/* A single edge in the mesh */
typedef struct _meshtastic_Neighbor {
/* Node ID of neighbor */
uint32_t node_id;
/* SNR of last heard message */
float snr;
} meshtastic_Neighbor;
/* Full info on edges for a single node */
typedef struct _meshtastic_NeighborInfo {
/* The node ID of the node sending info on its neighbors */
uint32_t node_id;
/* Field to pass neighbor info for the next sending cycle */
uint32_t last_sent_by_id;
/* The list of out edges from this node */
pb_size_t neighbors_count;
meshtastic_Neighbor neighbors[10];
} meshtastic_NeighborInfo;
/* Device metadata response */
typedef struct _meshtastic_DeviceMetadata {
/* Device firmware version string */
@ -813,6 +832,8 @@ extern "C" {
#define meshtastic_Compressed_portnum_ENUMTYPE meshtastic_PortNum
#define meshtastic_DeviceMetadata_role_ENUMTYPE meshtastic_Config_DeviceConfig_Role
#define meshtastic_DeviceMetadata_hw_model_ENUMTYPE meshtastic_HardwareModel
@ -832,6 +853,8 @@ extern "C" {
#define meshtastic_FromRadio_init_default {0, 0, {meshtastic_MeshPacket_init_default}}
#define meshtastic_ToRadio_init_default {0, {meshtastic_MeshPacket_init_default}}
#define meshtastic_Compressed_init_default {_meshtastic_PortNum_MIN, {0, {0}}}
#define meshtastic_NeighborInfo_init_default {0, 0, 0, {meshtastic_Neighbor_init_default, meshtastic_Neighbor_init_default, meshtastic_Neighbor_init_default, meshtastic_Neighbor_init_default, meshtastic_Neighbor_init_default, meshtastic_Neighbor_init_default, meshtastic_Neighbor_init_default, meshtastic_Neighbor_init_default, meshtastic_Neighbor_init_default, meshtastic_Neighbor_init_default}}
#define meshtastic_Neighbor_init_default {0, 0}
#define meshtastic_DeviceMetadata_init_default {"", 0, 0, 0, 0, 0, _meshtastic_Config_DeviceConfig_Role_MIN, 0, _meshtastic_HardwareModel_MIN}
#define meshtastic_Position_init_zero {0, 0, 0, 0, _meshtastic_Position_LocSource_MIN, _meshtastic_Position_AltSource_MIN, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
#define meshtastic_User_init_zero {"", "", "", {0}, _meshtastic_HardwareModel_MIN, 0}
@ -847,6 +870,8 @@ extern "C" {
#define meshtastic_FromRadio_init_zero {0, 0, {meshtastic_MeshPacket_init_zero}}
#define meshtastic_ToRadio_init_zero {0, {meshtastic_MeshPacket_init_zero}}
#define meshtastic_Compressed_init_zero {_meshtastic_PortNum_MIN, {0, {0}}}
#define meshtastic_NeighborInfo_init_zero {0, 0, 0, {meshtastic_Neighbor_init_zero, meshtastic_Neighbor_init_zero, meshtastic_Neighbor_init_zero, meshtastic_Neighbor_init_zero, meshtastic_Neighbor_init_zero, meshtastic_Neighbor_init_zero, meshtastic_Neighbor_init_zero, meshtastic_Neighbor_init_zero, meshtastic_Neighbor_init_zero, meshtastic_Neighbor_init_zero}}
#define meshtastic_Neighbor_init_zero {0, 0}
#define meshtastic_DeviceMetadata_init_zero {"", 0, 0, 0, 0, 0, _meshtastic_Config_DeviceConfig_Role_MIN, 0, _meshtastic_HardwareModel_MIN}
/* Field tags (for use in manual encoding/decoding) */
@ -948,6 +973,11 @@ extern "C" {
#define meshtastic_ToRadio_xmodemPacket_tag 5
#define meshtastic_Compressed_portnum_tag 1
#define meshtastic_Compressed_data_tag 2
#define meshtastic_Neighbor_node_id_tag 1
#define meshtastic_Neighbor_snr_tag 2
#define meshtastic_NeighborInfo_node_id_tag 1
#define meshtastic_NeighborInfo_last_sent_by_id_tag 2
#define meshtastic_NeighborInfo_neighbors_tag 3
#define meshtastic_DeviceMetadata_firmware_version_tag 1
#define meshtastic_DeviceMetadata_device_state_version_tag 2
#define meshtastic_DeviceMetadata_canShutdown_tag 3
@ -1157,6 +1187,20 @@ X(a, STATIC, SINGULAR, BYTES, data, 2)
#define meshtastic_Compressed_CALLBACK NULL
#define meshtastic_Compressed_DEFAULT NULL
#define meshtastic_NeighborInfo_FIELDLIST(X, a) \
X(a, STATIC, SINGULAR, UINT32, node_id, 1) \
X(a, STATIC, SINGULAR, UINT32, last_sent_by_id, 2) \
X(a, STATIC, REPEATED, MESSAGE, neighbors, 3)
#define meshtastic_NeighborInfo_CALLBACK NULL
#define meshtastic_NeighborInfo_DEFAULT NULL
#define meshtastic_NeighborInfo_neighbors_MSGTYPE meshtastic_Neighbor
#define meshtastic_Neighbor_FIELDLIST(X, a) \
X(a, STATIC, SINGULAR, UINT32, node_id, 1) \
X(a, STATIC, SINGULAR, FLOAT, snr, 2)
#define meshtastic_Neighbor_CALLBACK NULL
#define meshtastic_Neighbor_DEFAULT NULL
#define meshtastic_DeviceMetadata_FIELDLIST(X, a) \
X(a, STATIC, SINGULAR, STRING, firmware_version, 1) \
X(a, STATIC, SINGULAR, UINT32, device_state_version, 2) \
@ -1184,6 +1228,8 @@ extern const pb_msgdesc_t meshtastic_QueueStatus_msg;
extern const pb_msgdesc_t meshtastic_FromRadio_msg;
extern const pb_msgdesc_t meshtastic_ToRadio_msg;
extern const pb_msgdesc_t meshtastic_Compressed_msg;
extern const pb_msgdesc_t meshtastic_NeighborInfo_msg;
extern const pb_msgdesc_t meshtastic_Neighbor_msg;
extern const pb_msgdesc_t meshtastic_DeviceMetadata_msg;
/* Defines for backwards compatibility with code written before nanopb-0.4.0 */
@ -1201,6 +1247,8 @@ extern const pb_msgdesc_t meshtastic_DeviceMetadata_msg;
#define meshtastic_FromRadio_fields &meshtastic_FromRadio_msg
#define meshtastic_ToRadio_fields &meshtastic_ToRadio_msg
#define meshtastic_Compressed_fields &meshtastic_Compressed_msg
#define meshtastic_NeighborInfo_fields &meshtastic_NeighborInfo_msg
#define meshtastic_Neighbor_fields &meshtastic_Neighbor_msg
#define meshtastic_DeviceMetadata_fields &meshtastic_DeviceMetadata_msg
/* Maximum encoded size of messages (where known) */
@ -1211,6 +1259,8 @@ extern const pb_msgdesc_t meshtastic_DeviceMetadata_msg;
#define meshtastic_LogRecord_size 81
#define meshtastic_MeshPacket_size 321
#define meshtastic_MyNodeInfo_size 179
#define meshtastic_NeighborInfo_size 142
#define meshtastic_Neighbor_size 11
#define meshtastic_NodeInfo_size 261
#define meshtastic_Position_size 137
#define meshtastic_QueueStatus_size 23

View File

@ -98,6 +98,9 @@ typedef struct _meshtastic_ModuleConfig_MQTTConfig {
bool json_enabled;
/* If true, we attempt to establish a secure connection using TLS */
bool tls_enabled;
/* The root topic to use for MQTT messages. Default is "msh".
This is useful if you want to use a single MQTT server for multiple meshtastic networks and separate them via ACLs */
char root[16];
} meshtastic_ModuleConfig_MQTTConfig;
/* RemoteHardwareModule Config */
@ -325,7 +328,7 @@ extern "C" {
/* Initializer values for message structs */
#define meshtastic_ModuleConfig_init_default {0, {meshtastic_ModuleConfig_MQTTConfig_init_default}}
#define meshtastic_ModuleConfig_MQTTConfig_init_default {0, "", "", "", 0, 0, 0}
#define meshtastic_ModuleConfig_MQTTConfig_init_default {0, "", "", "", 0, 0, 0, ""}
#define meshtastic_ModuleConfig_RemoteHardwareConfig_init_default {0}
#define meshtastic_ModuleConfig_AudioConfig_init_default {0, 0, _meshtastic_ModuleConfig_AudioConfig_Audio_Baud_MIN, 0, 0, 0, 0}
#define meshtastic_ModuleConfig_SerialConfig_init_default {0, 0, 0, 0, _meshtastic_ModuleConfig_SerialConfig_Serial_Baud_MIN, 0, _meshtastic_ModuleConfig_SerialConfig_Serial_Mode_MIN}
@ -335,7 +338,7 @@ extern "C" {
#define meshtastic_ModuleConfig_TelemetryConfig_init_default {0, 0, 0, 0, 0, 0, 0}
#define meshtastic_ModuleConfig_CannedMessageConfig_init_default {0, 0, 0, 0, _meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_MIN, _meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_MIN, _meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_MIN, 0, 0, "", 0}
#define meshtastic_ModuleConfig_init_zero {0, {meshtastic_ModuleConfig_MQTTConfig_init_zero}}
#define meshtastic_ModuleConfig_MQTTConfig_init_zero {0, "", "", "", 0, 0, 0}
#define meshtastic_ModuleConfig_MQTTConfig_init_zero {0, "", "", "", 0, 0, 0, ""}
#define meshtastic_ModuleConfig_RemoteHardwareConfig_init_zero {0}
#define meshtastic_ModuleConfig_AudioConfig_init_zero {0, 0, _meshtastic_ModuleConfig_AudioConfig_Audio_Baud_MIN, 0, 0, 0, 0}
#define meshtastic_ModuleConfig_SerialConfig_init_zero {0, 0, 0, 0, _meshtastic_ModuleConfig_SerialConfig_Serial_Baud_MIN, 0, _meshtastic_ModuleConfig_SerialConfig_Serial_Mode_MIN}
@ -353,6 +356,7 @@ extern "C" {
#define meshtastic_ModuleConfig_MQTTConfig_encryption_enabled_tag 5
#define meshtastic_ModuleConfig_MQTTConfig_json_enabled_tag 6
#define meshtastic_ModuleConfig_MQTTConfig_tls_enabled_tag 7
#define meshtastic_ModuleConfig_MQTTConfig_root_tag 8
#define meshtastic_ModuleConfig_RemoteHardwareConfig_enabled_tag 1
#define meshtastic_ModuleConfig_AudioConfig_codec2_enabled_tag 1
#define meshtastic_ModuleConfig_AudioConfig_ptt_pin_tag 2
@ -448,7 +452,8 @@ X(a, STATIC, SINGULAR, STRING, username, 3) \
X(a, STATIC, SINGULAR, STRING, password, 4) \
X(a, STATIC, SINGULAR, BOOL, encryption_enabled, 5) \
X(a, STATIC, SINGULAR, BOOL, json_enabled, 6) \
X(a, STATIC, SINGULAR, BOOL, tls_enabled, 7)
X(a, STATIC, SINGULAR, BOOL, tls_enabled, 7) \
X(a, STATIC, SINGULAR, STRING, root, 8)
#define meshtastic_ModuleConfig_MQTTConfig_CALLBACK NULL
#define meshtastic_ModuleConfig_MQTTConfig_DEFAULT NULL
@ -566,13 +571,13 @@ extern const pb_msgdesc_t meshtastic_ModuleConfig_CannedMessageConfig_msg;
#define meshtastic_ModuleConfig_AudioConfig_size 19
#define meshtastic_ModuleConfig_CannedMessageConfig_size 49
#define meshtastic_ModuleConfig_ExternalNotificationConfig_size 40
#define meshtastic_ModuleConfig_MQTTConfig_size 203
#define meshtastic_ModuleConfig_MQTTConfig_size 220
#define meshtastic_ModuleConfig_RangeTestConfig_size 10
#define meshtastic_ModuleConfig_RemoteHardwareConfig_size 2
#define meshtastic_ModuleConfig_SerialConfig_size 26
#define meshtastic_ModuleConfig_StoreForwardConfig_size 22
#define meshtastic_ModuleConfig_TelemetryConfig_size 26
#define meshtastic_ModuleConfig_size 206
#define meshtastic_ModuleConfig_size 223
#ifdef __cplusplus
} /* extern "C" */

View File

@ -85,6 +85,8 @@ typedef enum _meshtastic_PortNum {
/* Provides a traceroute functionality to show the route a packet towards
a certain destination would take on the mesh. */
meshtastic_PortNum_TRACEROUTE_APP = 70,
/* Aggregates edge info for the network by sending out a list of each node's neighbors */
meshtastic_PortNum_NEIGHBORINFO_APP = 71,
/* Private applications should use portnums >= 256.
To simplify initial development and testing you can use "PRIVATE_APP"
in your code without needing to rebuild protobuf files (via [regen-protos.sh](https://github.com/meshtastic/firmware/blob/master/bin/regen-protos.sh)) */

View File

@ -234,15 +234,18 @@ void htmlDeleteDir(const char *dirname)
while (file) {
if (file.isDirectory() && !String(file.name()).endsWith(".")) {
htmlDeleteDir(file.name());
file.flush();
file.close();
} else {
String fileName = String(file.name());
file.flush();
file.close();
LOG_DEBUG(" %s\n", fileName.c_str());
FSCom.remove(fileName);
}
file = root.openNextFile();
}
root.flush();
root.close();
}
@ -521,7 +524,7 @@ void handleFormUpload(HTTPRequest *req, HTTPResponse *res)
std::string pathname = "/static/" + filename;
// Create a new file to stream the data into
File file = FSCom.open(pathname.c_str(), "w");
File file = FSCom.open(pathname.c_str(), FILE_O_WRITE);
size_t fileLength = 0;
didwrite = true;
@ -536,6 +539,7 @@ void handleFormUpload(HTTPRequest *req, HTTPResponse *res)
// Abort the transfer if there is less than 50k space left on the filesystem.
if (FSCom.totalBytes() - FSCom.usedBytes() < 51200) {
file.flush();
file.close();
res->println("<p>Write aborted! Reserving 50k on filesystem.</p>");
@ -553,6 +557,7 @@ void handleFormUpload(HTTPRequest *req, HTTPResponse *res)
}
// enableLoopWDT();
file.flush();
file.close();
res->printf("<p>Saved %d bytes to %s</p>", (int)fileLength, pathname.c_str());
}
@ -622,10 +627,10 @@ void handleReport(HTTPRequest *req, HTTPResponse *res)
// data->memory
JSONObject jsonObjMemory;
jsonObjMemory["heap_total"] = new JSONValue((int)ESP.getHeapSize());
jsonObjMemory["heap_free"] = new JSONValue((int)ESP.getFreeHeap());
jsonObjMemory["psram_total"] = new JSONValue((int)ESP.getPsramSize());
jsonObjMemory["psram_free"] = new JSONValue((int)ESP.getFreePsram());
jsonObjMemory["heap_total"] = new JSONValue((int)memGet.getHeapSize());
jsonObjMemory["heap_free"] = new JSONValue((int)memGet.getFreeHeap());
jsonObjMemory["psram_total"] = new JSONValue((int)memGet.getPsramSize());
jsonObjMemory["psram_free"] = new JSONValue((int)memGet.getFreePsram());
jsonObjMemory["fs_total"] = new JSONValue((int)FSCom.totalBytes());
jsonObjMemory["fs_used"] = new JSONValue((int)FSCom.usedBytes());
jsonObjMemory["fs_free"] = new JSONValue(int(FSCom.totalBytes() - FSCom.usedBytes()));

View File

@ -12,7 +12,7 @@ bool NodeInfoModule::handleReceivedProtobuf(const meshtastic_MeshPacket &mp, mes
{
auto p = *pptr;
nodeDB.updateUser(getFrom(&mp), p);
bool hasChanged = nodeDB.updateUser(getFrom(&mp), p);
bool wasBroadcast = mp.to == NODENUM_BROADCAST;
@ -23,6 +23,10 @@ bool NodeInfoModule::handleReceivedProtobuf(const meshtastic_MeshPacket &mp, mes
screen->print(lcd.c_str());
}
// if user has changed while packet was not for us, inform phone
if (hasChanged && !wasBroadcast && mp.to != nodeDB.getNodeNum())
service.sendToPhone(packetPool.allocCopy(mp));
// LOG_DEBUG("did handleReceived\n");
return false; // Let others look at this message also if they want
}

View File

@ -1,18 +1,26 @@
#include "BME680Sensor.h"
#include "../mesh/generated/meshtastic/telemetry.pb.h"
#include "FSCommon.h"
#include "TelemetrySensor.h"
#include "configuration.h"
#include <Adafruit_BME680.h>
BME680Sensor::BME680Sensor() : TelemetrySensor(meshtastic_TelemetrySensorType_BME680, "BME680") {}
int32_t BME680Sensor::runOnce()
{
LOG_INFO("Init sensor: %s\n", sensorName);
LOG_INFO("Init sensor: %s with the BSEC Library\n", sensorName);
if (!hasSensor()) {
return DEFAULT_SENSOR_MINIMUM_WAIT_TIME_BETWEEN_READS;
}
status = bme680.begin(nodeTelemetrySensorsMap[sensorType]);
bme680.begin(nodeTelemetrySensorsMap[sensorType], Wire);
if (bme680.bsecStatus == BSEC_OK) {
bme680.setConfig(bsec_config_iaq);
loadState();
bme680.updateSubscription(sensorList, 13, BSEC_SAMPLE_RATE_LP);
status = 1;
} else {
status = 0;
}
return initI2CSensor();
}
@ -21,11 +29,76 @@ void BME680Sensor::setup() {}
bool BME680Sensor::getMetrics(meshtastic_Telemetry *measurement)
{
bme680.performReading();
bme680.run();
measurement->variant.environment_metrics.temperature = bme680.temperature;
measurement->variant.environment_metrics.relative_humidity = bme680.humidity;
measurement->variant.environment_metrics.barometric_pressure = bme680.pressure / 100.0F;
measurement->variant.environment_metrics.gas_resistance = bme680.gas_resistance / 1000.0;
measurement->variant.environment_metrics.gas_resistance = bme680.gasResistance / 1000.0;
// Check if we need to save state to filesystem (every STATE_SAVE_PERIOD ms)
updateState();
return true;
}
void BME680Sensor::loadState()
{
#ifdef FSCom
auto file = FSCom.open(bsecConfigFileName, FILE_O_READ);
if (file) {
file.read((uint8_t *)&bsecState, BSEC_MAX_STATE_BLOB_SIZE);
file.close();
bme680.setState(bsecState);
LOG_INFO("%s state read from %s.\n", sensorName, bsecConfigFileName);
} else {
LOG_INFO("No %s state found (File: %s).\n", sensorName, bsecConfigFileName);
}
#else
LOG_ERROR("ERROR: Filesystem not implemented\n");
#endif
}
void BME680Sensor::updateState()
{
#ifdef FSCom
bool update = false;
if (stateUpdateCounter == 0) {
/* First state update when IAQ accuracy is >= 3 */
if (bme680.iaqAccuracy >= 3) {
LOG_DEBUG("%s state update IAQ accuracy %u >= 3\n", sensorName, bme680.iaqAccuracy);
update = true;
stateUpdateCounter++;
} else {
LOG_DEBUG("%s not updated, IAQ accuracy is %u >= 3\n", sensorName, bme680.iaqAccuracy);
}
} else {
/* Update every STATE_SAVE_PERIOD minutes */
if ((stateUpdateCounter * STATE_SAVE_PERIOD) < millis()) {
LOG_DEBUG("%s state update every %d minutes\n", sensorName, STATE_SAVE_PERIOD);
update = true;
stateUpdateCounter++;
}
}
if (update) {
bme680.getState(bsecState);
std::string filenameTmp = bsecConfigFileName;
filenameTmp += ".tmp";
auto file = FSCom.open(bsecConfigFileName, FILE_O_WRITE);
if (file) {
LOG_INFO("%s state write to %s.\n", sensorName, bsecConfigFileName);
file.write((uint8_t *)&bsecState, BSEC_MAX_STATE_BLOB_SIZE);
file.flush();
file.close();
// brief window of risk here ;-)
if (FSCom.exists(bsecConfigFileName) && !FSCom.remove(bsecConfigFileName))
LOG_WARN("Can't remove old state file\n");
if (!renameFile(filenameTmp.c_str(), bsecConfigFileName))
LOG_ERROR("Error: can't rename new state file\n");
} else {
LOG_INFO("Can't write %s state (File: %s).\n", sensorName, bsecConfigFileName);
}
}
#else
LOG_ERROR("ERROR: Filesystem not implemented\n");
#endif
}

View File

@ -1,14 +1,38 @@
#include "../mesh/generated/meshtastic/telemetry.pb.h"
#include "TelemetrySensor.h"
#include <Adafruit_BME680.h>
#include <bsec.h>
#define STATE_SAVE_PERIOD UINT32_C(360 * 60 * 1000) // That's 6 hours worth of millis()
const uint8_t bsec_config_iaq[] = {
#include <config/generic_33v_3s_4d/bsec_iaq.txt>
};
class BME680Sensor : virtual public TelemetrySensor
{
private:
Adafruit_BME680 bme680;
Bsec bme680;
protected:
virtual void setup() override;
const char *bsecConfigFileName = "/prefs/bsec.dat";
uint8_t bsecState[BSEC_MAX_STATE_BLOB_SIZE] = {0};
uint16_t stateUpdateCounter = 0;
bsec_virtual_sensor_t sensorList[13] = {BSEC_OUTPUT_IAQ,
BSEC_OUTPUT_STATIC_IAQ,
BSEC_OUTPUT_CO2_EQUIVALENT,
BSEC_OUTPUT_BREATH_VOC_EQUIVALENT,
BSEC_OUTPUT_RAW_TEMPERATURE,
BSEC_OUTPUT_RAW_PRESSURE,
BSEC_OUTPUT_RAW_HUMIDITY,
BSEC_OUTPUT_RAW_GAS,
BSEC_OUTPUT_STABILIZATION_STATUS,
BSEC_OUTPUT_RUN_IN_STATUS,
BSEC_OUTPUT_SENSOR_HEAT_COMPENSATED_TEMPERATURE,
BSEC_OUTPUT_SENSOR_HEAT_COMPENSATED_HUMIDITY,
BSEC_OUTPUT_GAS_PERCENTAGE};
void loadState();
void updateState();
public:
BME680Sensor();

View File

@ -226,7 +226,7 @@ bool RangeTestModuleRadio::appendFile(const meshtastic_MeshPacket &mp)
} else {
LOG_ERROR("File write failed\n");
}
fileToWrite.flush();
fileToWrite.close();
}
@ -275,6 +275,7 @@ bool RangeTestModuleRadio::appendFile(const meshtastic_MeshPacket &mp)
// TODO: If quotes are found in the payload, it has to be escaped.
fileToAppend.printf("\"%s\"\n", p.payload.bytes);
fileToAppend.flush();
fileToAppend.close();
return 1;

View File

@ -5,6 +5,7 @@
#include "Router.h"
#include "airtime.h"
#include "configuration.h"
#include "memGet.h"
#include "mesh-pb-constants.h"
#include "mesh/generated/meshtastic/storeforward.pb.h"
#include "modules/ModuleDev.h"
@ -63,8 +64,8 @@ void StoreForwardModule::populatePSRAM()
https://learn.upesy.com/en/programmation/psram.html#psram-tab
*/
LOG_DEBUG("*** Before PSRAM initilization: heap %d/%d PSRAM %d/%d\n", ESP.getFreeHeap(), ESP.getHeapSize(),
ESP.getFreePsram(), ESP.getPsramSize());
LOG_DEBUG("*** Before PSRAM initilization: heap %d/%d PSRAM %d/%d\n", memGet.getFreeHeap(), memGet.getHeapSize(),
memGet.getFreePsram(), memGet.getPsramSize());
this->packetHistoryTXQueue =
static_cast<PacketHistoryStruct *>(ps_calloc(this->historyReturnMax, sizeof(PacketHistoryStruct)));
@ -72,13 +73,14 @@ void StoreForwardModule::populatePSRAM()
/* Use a maximum of 2/3 the available PSRAM unless otherwise specified.
Note: This needs to be done after every thing that would use PSRAM
*/
uint32_t numberOfPackets = (this->records ? this->records : (((ESP.getFreePsram() / 3) * 2) / sizeof(PacketHistoryStruct)));
uint32_t numberOfPackets =
(this->records ? this->records : (((memGet.getFreePsram() / 3) * 2) / sizeof(PacketHistoryStruct)));
this->records = numberOfPackets;
this->packetHistory = static_cast<PacketHistoryStruct *>(ps_calloc(numberOfPackets, sizeof(PacketHistoryStruct)));
LOG_DEBUG("*** After PSRAM initilization: heap %d/%d PSRAM %d/%d\n", ESP.getFreeHeap(), ESP.getHeapSize(), ESP.getFreePsram(),
ESP.getPsramSize());
LOG_DEBUG("*** After PSRAM initilization: heap %d/%d PSRAM %d/%d\n", memGet.getFreeHeap(), memGet.getHeapSize(),
memGet.getFreePsram(), memGet.getPsramSize());
LOG_DEBUG("*** numberOfPackets for packetHistory - %u\n", numberOfPackets);
}
@ -445,8 +447,8 @@ StoreForwardModule::StoreForwardModule()
if ((config.device.role == meshtastic_Config_DeviceConfig_Role_ROUTER) ||
(config.device.role == meshtastic_Config_DeviceConfig_Role_ROUTER_CLIENT)) {
LOG_INFO("*** Initializing Store & Forward Module in Router mode\n");
if (ESP.getPsramSize() > 0) {
if (ESP.getFreePsram() >= 1024 * 1024) {
if (memGet.getPsramSize() > 0) {
if (memGet.getFreePsram() >= 1024 * 1024) {
// Do the startup here

View File

@ -19,10 +19,6 @@ const int reconnectMax = 5;
MQTT *mqtt;
std::string statusTopic = "msh/2/stat/";
std::string cryptTopic = "msh/2/c/"; // msh/2/c/CHANNELID/NODEID
std::string jsonTopic = "msh/2/json/"; // msh/2/json/CHANNELID/NODEID
static MemoryDynamic<meshtastic_ServiceEnvelope> staticMqttPool;
Allocator<meshtastic_ServiceEnvelope> &mqttPool = staticMqttPool;
@ -164,6 +160,16 @@ MQTT::MQTT() : concurrency::OSThread("mqtt"), pubSub(mqttClient), mqttQueue(MAX_
assert(!mqtt);
mqtt = this;
if (*moduleConfig.mqtt.root) {
statusTopic = moduleConfig.mqtt.root + statusTopic;
cryptTopic = moduleConfig.mqtt.root + cryptTopic;
jsonTopic = moduleConfig.mqtt.root + jsonTopic;
} else {
statusTopic = "msh" + statusTopic;
cryptTopic = "msh" + cryptTopic;
jsonTopic = "msh" + jsonTopic;
}
pubSub.setCallback(mqttCallback);
// preflightSleepObserver.observe(&preflightSleep);
@ -192,6 +198,26 @@ void MQTT::reconnect()
mqttPassword = moduleConfig.mqtt.password;
}
#if HAS_WIFI && !defined(ARCH_PORTDUINO)
if (moduleConfig.mqtt.tls_enabled) {
// change default for encrypted to 8883
try {
serverPort = 8883;
wifiSecureClient.setInsecure();
pubSub.setClient(wifiSecureClient);
LOG_INFO("Using TLS-encrypted session\n");
} catch (const std::exception &e) {
LOG_ERROR("MQTT ERROR: %s\n", e.what());
}
} else {
LOG_INFO("Using non-TLS-encrypted session\n");
pubSub.setClient(mqttClient);
}
#else
pubSub.setClient(mqttClient);
#endif
String server = String(serverAddr);
int delimIndex = server.indexOf(':');
if (delimIndex > 0) {
@ -528,4 +554,4 @@ std::string MQTT::downstreamPacketToJson(meshtastic_MeshPacket *mp)
delete value;
return jsonStr;
}
}

View File

@ -8,6 +8,9 @@
#include <PubSubClient.h>
#if HAS_WIFI
#include <WiFiClient.h>
#if !defined(ARCH_PORTDUINO)
#include <WiFiClientSecure.h>
#endif
#endif
#if HAS_ETHERNET
#include <EthernetClient.h>
@ -23,9 +26,11 @@ class MQTT : private concurrency::OSThread
{
// supposedly the current version is busted:
// http://www.iotsharing.com/2017/08/how-to-use-esp32-mqtts-with-mqtts-mosquitto-broker-tls-ssl.html
// WiFiClientSecure wifiClient;
#if HAS_WIFI
WiFiClient mqttClient;
#if !defined(ARCH_PORTDUINO)
WiFiClientSecure wifiSecureClient;
#endif
#endif
#if HAS_ETHERNET
EthernetClient mqttClient;
@ -64,6 +69,9 @@ class MQTT : private concurrency::OSThread
virtual int32_t runOnce() override;
private:
std::string statusTopic = "/2/stat/";
std::string cryptTopic = "/2/c/"; // msh/2/c/CHANNELID/NODEID
std::string jsonTopic = "/2/json/"; // msh/2/json/CHANNELID/NODEID
/** return true if we have a channel that wants uplink/downlink
*/
bool wantsLink() const;
@ -87,4 +95,4 @@ class MQTT : private concurrency::OSThread
void mqttInit();
extern MQTT *mqtt;
extern MQTT *mqtt;

View File

@ -162,7 +162,7 @@ void esp32Loop()
// radio.radioIf.canSleep();
}
void cpuDeepSleep(uint64_t msecToWake)
void cpuDeepSleep(uint32_t msecToWake)
{
/*
Some ESP32 IOs have internal pullups or pulldowns, which are enabled by default.
@ -202,7 +202,7 @@ void cpuDeepSleep(uint64_t msecToWake)
#ifdef BUTTON_PIN
// Only GPIOs which are have RTC functionality can be used in this bit map: 0,2,4,12-15,25-27,32-39.
#if SOC_RTCIO_HOLD_SUPPORTED
uint64_t gpioMask = (1ULL << BUTTON_PIN);
uint64_t gpioMask = (1ULL << config.device.button_gpio ? config.device.button_gpio : BUTTON_PIN);
#endif
#ifdef BUTTON_NEED_PULLUP

View File

@ -92,12 +92,12 @@ void startAdv(void)
Bluefruit.Advertising.addFlags(BLE_GAP_ADV_FLAGS_LE_ONLY_GENERAL_DISC_MODE);
// IncludeService UUID
Bluefruit.ScanResponse.addService(meshBleService);
// Bluefruit.ScanResponse.addService(meshBleService);
Bluefruit.ScanResponse.addTxPower();
Bluefruit.ScanResponse.addName();
// Include Name
Bluefruit.Advertising.addName();
// Bluefruit.Advertising.addName();
Bluefruit.Advertising.addService(meshBleService);
/* Start Advertising

View File

@ -90,7 +90,7 @@ extern "C" void HardFault_Handler(void)
asm volatile(" mrs r0,msp\n"
" b HardFault_Impl \n");
}
#else
#elif !defined(ARCH_NRF52)
/* The prototype shows it is a naked function - in effect this is just an
assembly function. */

View File

@ -155,7 +155,7 @@ void nrf52Setup()
nRFCrypto.end();
}
void cpuDeepSleep(uint64_t msecToWake)
void cpuDeepSleep(uint32_t msecToWake)
{
// FIXME, configure RTC or button press to wake us
// FIXME, power down SPI, I2C, RAMs

View File

@ -16,7 +16,7 @@ void setBluetoothEnable(bool on)
// not needed
}
void cpuDeepSleep(uint64_t msecs)
void cpuDeepSleep(uint32_t msecs)
{
notImplemented("cpuDeepSleep");
}

View File

@ -7,7 +7,7 @@ void setBluetoothEnable(bool on)
// not needed
}
void cpuDeepSleep(uint64_t msecs)
void cpuDeepSleep(uint32_t msecs)
{
// not needed
}

View File

@ -15,7 +15,7 @@ void getMacAddr(uint8_t *dmac)
dmac[i] = i;
}
void cpuDeepSleep(uint64_t msecToWake) {}
void cpuDeepSleep(uint32_t msecToWake) {}
/* pacify libc_nano */
extern "C" {

View File

@ -19,6 +19,10 @@
esp_sleep_source_t wakeCause; // the reason we booted this time
#endif
#ifndef INCLUDE_vTaskSuspend
#define INCLUDE_vTaskSuspend 0
#endif
#ifdef HAS_PMU
#include "XPowersLibInterface.hpp"
extern XPowersLibInterface *PMU;
@ -201,9 +205,13 @@ void doGPSpowersave(bool on)
#endif
}
void doDeepSleep(uint64_t msecToWake)
void doDeepSleep(uint32_t msecToWake)
{
LOG_INFO("Entering deep sleep for %lu seconds\n", msecToWake / 1000);
if (INCLUDE_vTaskSuspend && (msecToWake == portMAX_DELAY)) {
LOG_INFO("Entering deep sleep forever\n");
} else {
LOG_INFO("Entering deep sleep for %u seconds\n", msecToWake / 1000);
}
// not using wifi yet, but once we are this is needed to shutoff the radio hw
// esp_wifi_stop();
@ -301,7 +309,8 @@ esp_sleep_wakeup_cause_t doLightSleep(uint64_t sleepMsec) // FIXME, use a more r
// assert(esp_sleep_enable_uart_wakeup(0) == ESP_OK);
#endif
#ifdef BUTTON_PIN
esp_sleep_enable_ext0_wakeup((gpio_num_t)BUTTON_PIN, LOW); // when user presses, this button goes low
esp_sleep_enable_ext0_wakeup((gpio_num_t)(config.device.button_gpio ? config.device.button_gpio : BUTTON_PIN),
LOW); // when user presses, this button goes low
#endif
#if defined(LORA_DIO1) && (LORA_DIO1 != RADIOLIB_NC)
gpio_wakeup_enable((gpio_num_t)LORA_DIO1, GPIO_INTR_HIGH_LEVEL); // SX126x/SX128x interrupt, active high
@ -330,7 +339,8 @@ esp_sleep_wakeup_cause_t doLightSleep(uint64_t sleepMsec) // FIXME, use a more r
esp_sleep_wakeup_cause_t cause = esp_sleep_get_wakeup_cause();
#ifdef BUTTON_PIN
if (cause == ESP_SLEEP_WAKEUP_GPIO)
LOG_INFO("Exit light sleep gpio: btn=%d\n", !digitalRead(BUTTON_PIN));
LOG_INFO("Exit light sleep gpio: btn=%d\n",
!digitalRead(config.device.button_gpio ? config.device.button_gpio : BUTTON_PIN));
#endif
return cause;

View File

@ -4,7 +4,7 @@
#include "Observer.h"
#include "configuration.h"
void doDeepSleep(uint64_t msecToWake), cpuDeepSleep(uint64_t msecToWake);
void doDeepSleep(uint32_t msecToWake), cpuDeepSleep(uint32_t msecToWake);
#ifdef ARCH_ESP32
#include "esp_sleep.h"

View File

@ -142,12 +142,14 @@ void XModemAdapter::handlePacket(meshtastic_XModem xmodemPacket)
case meshtastic_XModem_Control_EOT:
// End of transmission
sendControl(meshtastic_XModem_Control_ACK);
file.flush();
file.close();
isReceiving = false;
break;
case meshtastic_XModem_Control_CAN:
// Cancel transmission and remove file
sendControl(meshtastic_XModem_Control_ACK);
file.flush();
file.close();
FSCom.remove(filename);
isReceiving = false;

View File

@ -7,7 +7,7 @@ build_flags = ${nrf52840_base.build_flags} -Ivariants/MakePython_nRF52840_eink -
build_src_filter = ${nrf52_base.build_src_filter} +<../variants/MakePython_nRF52840_eink>
lib_deps =
${nrf52840_base.lib_deps}
caveman99/ESP32 Codec2@^1.0.1
https://github.com/meshtastic/ESP32_Codec2.git#633326c78ac251c059ab3a8c430fcdf25b41672f
zinggjm/GxEPD2@^1.4.9
debug_tool = jlink
upload_port = /dev/ttyACM4

View File

@ -6,5 +6,5 @@ build_flags = ${nrf52840_base.build_flags} -Ivariants/MakePython_nRF52840_oled -
build_src_filter = ${nrf52_base.build_src_filter} +<../variants/MakePython_nRF52840_oled>
lib_deps =
${nrf52840_base.lib_deps}
caveman99/ESP32 Codec2@^1.0.1
https://github.com/meshtastic/ESP32_Codec2.git#633326c78ac251c059ab3a8c430fcdf25b41672f
debug_tool = jlink

View File

@ -12,7 +12,6 @@ platform_packages =
tool-esptoolpy@^1.40500.0
lib_deps =
${esp32_base.lib_deps}
caveman99/ESP32 Codec2@^1.0.1
zinggjm/GxEPD2@^1.5.1
adafruit/Adafruit NeoPixel@^1.10.7
build_unflags = -DARDUINO_USB_MODE=1

View File

@ -12,7 +12,6 @@ platform_packages =
tool-esptoolpy@^1.40500.0
lib_deps =
${esp32_base.lib_deps}
caveman99/ESP32 Codec2@^1.0.1
adafruit/Adafruit NeoPixel@^1.10.7
build_unflags = -DARDUINO_USB_MODE=1
build_flags =

View File

@ -2,9 +2,6 @@
extends = esp32s3_base
board = tlora-t3s3-v1
upload_protocol = esp-builtin
lib_deps =
${esp32_base.lib_deps}
caveman99/ESP32 Codec2@^1.0.1
build_flags =
${esp32_base.build_flags} -D TLORA_T3S3_V1 -I variants/tlora_t3s3_v1

View File

@ -1,9 +1,6 @@
[env:tlora-v2-1-1.8]
extends = esp32_base
board = ttgo-lora32-v21
lib_deps =
${esp32_base.lib_deps}
caveman99/ESP32 Codec2@^1.0.1
build_flags =
${esp32_base.build_flags} -D TLORA_V2_1_18 -I variants/tlora_v2_1_18

View File

@ -1,4 +1,4 @@
[VERSION]
major = 2
minor = 1
build = 7
build = 10