diff --git a/.github/workflows/package_raspbian.yml b/.github/workflows/package_raspbian.yml
index 2f9a99e58..377074e95 100644
--- a/.github/workflows/package_raspbian.yml
+++ b/.github/workflows/package_raspbian.yml
@@ -23,6 +23,14 @@ jobs:
ref: ${{github.event.pull_request.head.ref}}
repository: ${{github.event.pull_request.head.repo.full_name}}
+ - name: Pull web ui
+ uses: dsaltares/fetch-gh-release-asset@a40c8b4a0471f9ab81bdf73a010f74cc51476ad4
+ with:
+ repo: meshtastic/web
+ file: build.tar
+ target: build.tar
+ token: ${{ secrets.GITHUB_TOKEN }}
+
- name: Get release version string
run: echo "version=$(./bin/buildinfo.py long)" >> $GITHUB_OUTPUT
id: version
@@ -37,9 +45,12 @@ jobs:
- name: build .debpkg
run: |
+ mkdir -p .debpkg/usr/share/doc/meshtasticd/web
mkdir -p .debpkg/usr/sbin
mkdir -p .debpkg/etc/meshtasticd
mkdir -p .debpkg/usr/lib/systemd/system/
+ tar -xf build.tar -C .debpkg/usr/share/doc/meshtasticd/web
+ gunzip .debpkg/usr/share/doc/meshtasticd/web/*.gz
cp release/meshtasticd_linux_aarch64 .debpkg/usr/sbin/meshtasticd
cp bin/config-dist.yaml .debpkg/etc/meshtasticd/config.yaml
chmod +x .debpkg/usr/sbin/meshtasticd
@@ -52,7 +63,7 @@ jobs:
maintainer: Jonathan Bennett
version: ${{ steps.version.outputs.version }} # refs/tags/v*.*.*
arch: arm64
- depends: libyaml-cpp0.7
+ depends: libyaml-cpp0.7, openssl
desc: Native Linux Meshtastic binary.
- uses: actions/upload-artifact@v3
diff --git a/.gitignore b/.gitignore
index 89f8ee065..0f2202f8d 100644
--- a/.gitignore
+++ b/.gitignore
@@ -31,3 +31,5 @@ venv/
release/
.vscode/extensions.json
/compile_commands.json
+src/mesh/raspihttp/certificate.pem
+src/mesh/raspihttp/private_key.pem
\ No newline at end of file
diff --git a/.trunk/trunk.yaml b/.trunk/trunk.yaml
index af7d3d21d..0826b71d9 100644
--- a/.trunk/trunk.yaml
+++ b/.trunk/trunk.yaml
@@ -4,19 +4,19 @@ cli:
plugins:
sources:
- id: trunk
- ref: v1.4.3
+ ref: v1.4.4
uri: https://github.com/trunk-io/plugins
lint:
enabled:
- - trufflehog@3.68.2
+ - trufflehog@3.68.5
- yamllint@1.35.1
- bandit@1.7.7
- - checkov@3.2.26
- - terrascan@1.18.11
+ - checkov@3.2.32
+ - terrascan@1.19.1
- trivy@0.49.1
#- trufflehog@3.63.2-rc0
- taplo@0.8.1
- - ruff@0.2.2
+ - ruff@0.3.1
- isort@5.13.2
- markdownlint@0.39.0
- oxipng@9.0.0
diff --git a/.vscode/settings.json b/.vscode/settings.json
index 03922dc72..e86d31c7d 100644
--- a/.vscode/settings.json
+++ b/.vscode/settings.json
@@ -1,5 +1,7 @@
{
"editor.formatOnSave": true,
"editor.defaultFormatter": "trunk.io",
- "trunk.enableWindows": true
+ "trunk.enableWindows": true,
+ "files.insertFinalNewline": false,
+ "files.trimFinalNewlines": false
}
diff --git a/arch/esp32/esp32.ini b/arch/esp32/esp32.ini
index bf84dd939..39935b849 100644
--- a/arch/esp32/esp32.ini
+++ b/arch/esp32/esp32.ini
@@ -4,7 +4,7 @@ extends = arduino_base
platform = platformio/espressif32@6.3.2 # This is a temporary fix to the S3-based devices bluetooth issues until we can determine what within ESP-IDF changed and can develop a suitable patch.
build_src_filter =
- ${arduino_base.build_src_filter} - - - -
+ ${arduino_base.build_src_filter} - - - - -
upload_speed = 921600
debug_init_break = tbreak setup
diff --git a/arch/esp32/esp32s2.ini b/arch/esp32/esp32s2.ini
index 3bde3465a..5de0fa549 100644
--- a/arch/esp32/esp32s2.ini
+++ b/arch/esp32/esp32s2.ini
@@ -2,7 +2,7 @@
extends = esp32_base
build_src_filter =
- ${esp32_base.build_src_filter} -
+ ${esp32_base.build_src_filter} - -
monitor_speed = 115200
@@ -12,5 +12,4 @@ build_flags =
lib_ignore =
${esp32_base.lib_ignore}
- NimBLE-Arduino
-
+ NimBLE-Arduino
\ No newline at end of file
diff --git a/arch/nrf52/nrf52.ini b/arch/nrf52/nrf52.ini
index 04ca89a54..5155eaadc 100644
--- a/arch/nrf52/nrf52.ini
+++ b/arch/nrf52/nrf52.ini
@@ -11,7 +11,7 @@ build_flags =
-Isrc/platform/nrf52
build_src_filter =
- ${arduino_base.build_src_filter} - - - - - - - - -
+ ${arduino_base.build_src_filter} - - - - - - - - - -
lib_deps=
${arduino_base.lib_deps}
diff --git a/arch/portduino/portduino.ini b/arch/portduino/portduino.ini
index 0dcc9afc2..368fb5d0e 100644
--- a/arch/portduino/portduino.ini
+++ b/arch/portduino/portduino.ini
@@ -12,6 +12,7 @@ build_src_filter =
-
-
-
+ +
-
-
-
diff --git a/arch/rp2040/rp2040.ini b/arch/rp2040/rp2040.ini
index 48fe0dae6..edc4373ad 100644
--- a/arch/rp2040/rp2040.ini
+++ b/arch/rp2040/rp2040.ini
@@ -12,7 +12,7 @@ build_flags =
-D__PLAT_RP2040__
# -D _POSIX_THREADS
build_src_filter =
- ${arduino_base.build_src_filter} - - - - - - - -
+ ${arduino_base.build_src_filter} - - - - - - - - -
lib_ignore =
BluetoothOTA
diff --git a/arch/stm32/stm32wl5e.ini b/arch/stm32/stm32wl5e.ini
index 4483ff526..4d74ade8f 100644
--- a/arch/stm32/stm32wl5e.ini
+++ b/arch/stm32/stm32wl5e.ini
@@ -13,7 +13,7 @@ build_flags =
-DVECT_TAB_OFFSET=0x08000000
build_src_filter =
- ${arduino_base.build_src_filter} - - - - - - - - - - - - -
+ ${arduino_base.build_src_filter} - - - - - - - - - - - - - -
board_upload.offset_address = 0x08000000
upload_protocol = stlink
diff --git a/bin/config-dist.yaml b/bin/config-dist.yaml
index b5b105e4c..a241a929a 100644
--- a/bin/config-dist.yaml
+++ b/bin/config-dist.yaml
@@ -117,3 +117,7 @@ Input:
Logging:
LogLevel: info # debug, info, warn, error
+
+Webserver:
+# Port: 443 # Port for Webserver & Webservices
+# RootPath: /usr/share/doc/meshtasticd/web # Root Dir of WebServer
diff --git a/boards/canaryone.json b/boards/canaryone.json
index d8f966a47..f64a4a7c7 100644
--- a/boards/canaryone.json
+++ b/boards/canaryone.json
@@ -7,7 +7,10 @@
"cpu": "cortex-m4",
"extra_flags": "-DARDUINO_NRF52840_CANARY -DNRF52840_XXAA",
"f_cpu": "64000000L",
- "hwids": [["0x239A", "0x4405"]],
+ "hwids": [
+ ["0x239A", "0x4405"],
+ ["0x239A", "0x009F"]
+ ],
"usb_product": "CanaryOne",
"mcu": "nrf52840",
"variant": "canaryone",
diff --git a/platformio.ini b/platformio.ini
index 0033b6e46..b67ddc50a 100644
--- a/platformio.ini
+++ b/platformio.ini
@@ -116,6 +116,7 @@ lib_deps =
adafruit/Adafruit BusIO@^1.11.4
adafruit/Adafruit Unified Sensor@^1.1.11
adafruit/Adafruit BMP280 Library@^2.6.8
+ adafruit/Adafruit BMP085 Library@^1.2.4
adafruit/Adafruit BME280 Library@^2.2.2
https://github.com/boschsensortec/Bosch-BSEC2-Library#v1.5.2400
boschsensortec/BME68x Sensor Library@^1.1.40407
diff --git a/protobufs b/protobufs
index 62b7d8b88..5a97acb17 160000
--- a/protobufs
+++ b/protobufs
@@ -1 +1 @@
-Subproject commit 62b7d8b884d70aed5ff18c3b0e228095eeb48de2
+Subproject commit 5a97acb17543a10e114675a205e3274a83e721af
diff --git a/src/Power.cpp b/src/Power.cpp
index 8e44ddb98..3d1a1b9b2 100644
--- a/src/Power.cpp
+++ b/src/Power.cpp
@@ -473,11 +473,6 @@ bool Power::setup()
void Power::shutdown()
{
- screen->setOn(false);
-#if defined(USE_EINK) && defined(PIN_EINK_EN)
- digitalWrite(PIN_EINK_EN, LOW); // power off backlight first
-#endif
-
LOG_INFO("Shutting down\n");
#ifdef HAS_PMU
diff --git a/src/configuration.h b/src/configuration.h
index d8b0dba5f..03170c1c7 100644
--- a/src/configuration.h
+++ b/src/configuration.h
@@ -221,4 +221,22 @@ along with this program. If not, see .
#ifndef HW_VENDOR
#error HW_VENDOR must be defined
-#endif
\ No newline at end of file
+#endif
+
+// global switch to turn off all optional modules for a minimzed build
+#ifdef MESHTASTIC_EXCLUDE_MODULES
+#define MESHTASTIC_EXCLUDE_AUDIO 1
+#define MESHTASTIC_EXCLUDE_DETECTIONSENSOR 1
+#define MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR 1
+#define MESHTASTIC_EXCLUDE_EXTERNALNOTIFICATION 1
+#define MESHTASTIC_EXCLUDE_PAXCOUNTER 1
+#define MESHTASTIC_EXCLUDE_POWER_TELEMETRY 1
+#define MESHTASTIC_EXCLUDE_RANGETEST 1
+#define MESHTASTIC_EXCLUDE_REMOTEHARDWARE 1
+#define MESHTASTIC_EXCLUDE_STOREFORWARD 1
+#define MESHTASTIC_EXCLUDE_ATAK 1
+#define MESHTASTIC_EXCLUDE_CANNEDMESSAGES 1
+#define MESHTASTIC_EXCLUDE_NEIGHBORINFO 1
+#define MESHTASTIC_EXCLUDE_TRACEROUTE 1
+#define MESHTASTIC_EXCLUDE_WAYPOINT 1
+#endif
diff --git a/src/detect/ScanI2C.h b/src/detect/ScanI2C.h
index 2b4b8a735..66e683982 100644
--- a/src/detect/ScanI2C.h
+++ b/src/detect/ScanI2C.h
@@ -23,6 +23,7 @@ class ScanI2C
BME_680,
BME_280,
BMP_280,
+ BMP_085,
INA260,
INA219,
INA3221,
diff --git a/src/detect/ScanI2CTwoWire.cpp b/src/detect/ScanI2CTwoWire.cpp
index 990fb36ea..b6eca5fa4 100644
--- a/src/detect/ScanI2CTwoWire.cpp
+++ b/src/detect/ScanI2CTwoWire.cpp
@@ -242,6 +242,10 @@ void ScanI2CTwoWire::scanPort(I2CPort port)
LOG_INFO("BME-280 sensor found at address 0x%x\n", (uint8_t)addr.address);
type = BME_280;
break;
+ case 0x55:
+ LOG_INFO("BMP-085 or BMP-180 sensor found at address 0x%x\n", (uint8_t)addr.address);
+ type = BMP_085;
+ break;
default:
LOG_INFO("BMP-280 sensor found at address 0x%x\n", (uint8_t)addr.address);
type = BMP_280;
diff --git a/src/gps/GeoCoord.h b/src/gps/GeoCoord.h
index 9f911ed93..e811035db 100644
--- a/src/gps/GeoCoord.h
+++ b/src/gps/GeoCoord.h
@@ -11,7 +11,7 @@
#define PI 3.1415926535897932384626433832795
#define OLC_CODE_LEN 11
-#define DEG_CONVERT 180 / PI
+#define DEG_CONVERT (180 / PI)
// Helper functions
// Raises a number to an exponent, handling negative exponents.
diff --git a/src/graphics/EInkDisplay2.cpp b/src/graphics/EInkDisplay2.cpp
index aee30c7f8..6ee4245b3 100644
--- a/src/graphics/EInkDisplay2.cpp
+++ b/src/graphics/EInkDisplay2.cpp
@@ -122,11 +122,6 @@ bool EInkDisplay::connect()
{
LOG_INFO("Doing EInk init\n");
-#ifdef PIN_EINK_PWR_ON
- pinMode(PIN_EINK_PWR_ON, OUTPUT);
- digitalWrite(PIN_EINK_PWR_ON, HIGH); // If we need to assert a pin to power external peripherals
-#endif
-
#ifdef PIN_EINK_EN
// backlight power, HIGH is backlight on, LOW is off
pinMode(PIN_EINK_EN, OUTPUT);
diff --git a/src/graphics/Screen.cpp b/src/graphics/Screen.cpp
index 33df78462..3ffea4a60 100644
--- a/src/graphics/Screen.cpp
+++ b/src/graphics/Screen.cpp
@@ -938,6 +938,9 @@ void Screen::doDeepSleep()
static const int sleepFrameCount = sizeof(sleepFrames) / sizeof(sleepFrames[0]);
ui->setFrames(sleepFrames, sleepFrameCount);
ui->update();
+#ifdef PIN_EINK_EN
+ digitalWrite(PIN_EINK_EN, LOW); // power off backlight
+#endif
#endif
setOn(false);
}
diff --git a/src/main.cpp b/src/main.cpp
index fbfb983d2..ef1cd53c3 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -68,6 +68,7 @@ NRF52Bluetooth *nrf52Bluetooth;
#ifdef ARCH_PORTDUINO
#include "linux/LinuxHardwareI2C.h"
+#include "mesh/raspihttp/PiWebServer.h"
#include "platform/portduino/PortduinoGlue.h"
#include
#include
@@ -218,10 +219,11 @@ void setup()
initDeepSleep();
- // Testing this fix für erratic T-Echo boot behaviour
-#if defined(TTGO_T_ECHO) && defined(PIN_EINK_PWR_ON)
- pinMode(PIN_EINK_PWR_ON, OUTPUT);
- digitalWrite(PIN_EINK_PWR_ON, HIGH);
+ // power on peripherals
+#if defined(TTGO_T_ECHO) && defined(PIN_POWER_EN)
+ pinMode(PIN_POWER_EN, OUTPUT);
+ digitalWrite(PIN_POWER_EN, HIGH);
+ digitalWrite(PIN_POWER_EN1, INPUT);
#endif
#if defined(VEXT_ENABLE_V03)
@@ -499,6 +501,7 @@ void setup()
SCANNER_TO_SENSORS_MAP(ScanI2C::DeviceType::BME_680, meshtastic_TelemetrySensorType_BME680)
SCANNER_TO_SENSORS_MAP(ScanI2C::DeviceType::BME_280, meshtastic_TelemetrySensorType_BME280)
SCANNER_TO_SENSORS_MAP(ScanI2C::DeviceType::BMP_280, meshtastic_TelemetrySensorType_BMP280)
+ SCANNER_TO_SENSORS_MAP(ScanI2C::DeviceType::BMP_085, meshtastic_TelemetrySensorType_BMP085)
SCANNER_TO_SENSORS_MAP(ScanI2C::DeviceType::INA260, meshtastic_TelemetrySensorType_INA260)
SCANNER_TO_SENSORS_MAP(ScanI2C::DeviceType::INA219, meshtastic_TelemetrySensorType_INA219)
SCANNER_TO_SENSORS_MAP(ScanI2C::DeviceType::INA3221, meshtastic_TelemetrySensorType_INA3221)
@@ -679,6 +682,11 @@ void setup()
digitalWrite(SX126X_ANT_SW, 1);
#endif
+#ifdef PIN_PWR_DELAY_MS
+ // This may be required to give the peripherals time to power up.
+ delay(PIN_PWR_DELAY_MS);
+#endif
+
#ifdef ARCH_PORTDUINO
if (settingsMap[use_sx1262]) {
if (!rIf) {
@@ -857,6 +865,11 @@ void setup()
#endif
#ifdef ARCH_PORTDUINO
+#if __has_include()
+ if (settingsMap[webserverport] != -1) {
+ piwebServerThread = new PiWebServerThread();
+ }
+#endif
initApiServer(TCPPort);
#endif
diff --git a/src/mesh/MeshModule.cpp b/src/mesh/MeshModule.cpp
index 9c6ca78ee..ad0c78108 100644
--- a/src/mesh/MeshModule.cpp
+++ b/src/mesh/MeshModule.cpp
@@ -32,7 +32,8 @@ MeshModule::~MeshModule()
assert(0); // FIXME - remove from list of modules once someone needs this feature
}
-meshtastic_MeshPacket *MeshModule::allocAckNak(meshtastic_Routing_Error err, NodeNum to, PacketId idFrom, ChannelIndex chIndex)
+meshtastic_MeshPacket *MeshModule::allocAckNak(meshtastic_Routing_Error err, NodeNum to, PacketId idFrom, ChannelIndex chIndex,
+ uint8_t hopStart, uint8_t hopLimit)
{
meshtastic_Routing c = meshtastic_Routing_init_default;
@@ -49,7 +50,7 @@ meshtastic_MeshPacket *MeshModule::allocAckNak(meshtastic_Routing_Error err, Nod
p->priority = meshtastic_MeshPacket_Priority_ACK;
- p->hop_limit = config.lora.hop_limit; // Flood ACK back to original sender
+ p->hop_limit = routingModule->getHopLimitForResponse(hopStart, hopLimit); // Flood ACK back to original sender
p->to = to;
p->decoded.request_id = idFrom;
p->channel = chIndex;
@@ -176,7 +177,8 @@ void MeshModule::callPlugins(meshtastic_MeshPacket &mp, RxSource src)
// SECURITY NOTE! I considered sending back a different error code if we didn't find the psk (i.e. !isDecoded)
// but opted NOT TO. Because it is not a good idea to let remote nodes 'probe' to find out which PSKs were "good" vs
// bad.
- routingModule->sendAckNak(meshtastic_Routing_Error_NO_RESPONSE, getFrom(&mp), mp.id, mp.channel);
+ routingModule->sendAckNak(meshtastic_Routing_Error_NO_RESPONSE, getFrom(&mp), mp.id, mp.channel, mp.hop_start,
+ mp.hop_limit);
}
}
@@ -217,6 +219,7 @@ void setReplyTo(meshtastic_MeshPacket *p, const meshtastic_MeshPacket &to)
assert(p->which_payload_variant == meshtastic_MeshPacket_decoded_tag); // Should already be set by now
p->to = getFrom(&to); // Make sure that if we are sending to the local node, we use our local node addr, not 0
p->channel = to.channel; // Use the same channel that the request came in on
+ p->hop_limit = routingModule->getHopLimitForResponse(to.hop_start, to.hop_limit);
// No need for an ack if we are just delivering locally (it just generates an ignored ack)
p->want_ack = (to.from != 0) ? to.want_ack : false;
diff --git a/src/mesh/MeshModule.h b/src/mesh/MeshModule.h
index ebe3af1a0..6c431adb4 100644
--- a/src/mesh/MeshModule.h
+++ b/src/mesh/MeshModule.h
@@ -153,7 +153,8 @@ class MeshModule
virtual bool wantUIFrame() { return false; }
virtual Observable *getUIFrameObservable() { return NULL; }
- meshtastic_MeshPacket *allocAckNak(meshtastic_Routing_Error err, NodeNum to, PacketId idFrom, ChannelIndex chIndex);
+ meshtastic_MeshPacket *allocAckNak(meshtastic_Routing_Error err, NodeNum to, PacketId idFrom, ChannelIndex chIndex,
+ uint8_t hopStart = 0, uint8_t hopLimit = 0);
/// Send an error response for the specified packet.
meshtastic_MeshPacket *allocErrorResponse(meshtastic_Routing_Error err, const meshtastic_MeshPacket *p);
diff --git a/src/mesh/NodeDB.cpp b/src/mesh/NodeDB.cpp
index dc8d7540c..787c16a79 100644
--- a/src/mesh/NodeDB.cpp
+++ b/src/mesh/NodeDB.cpp
@@ -875,6 +875,12 @@ void NodeDB::updateFrom(const meshtastic_MeshPacket &mp)
if (mp.rx_snr)
info->snr = mp.rx_snr; // keep the most recent SNR we received for this node.
+
+ info->via_mqtt = mp.via_mqtt; // Store if we received this packet via MQTT
+
+ // If hopStart was set and there wasn't someone messing with the limit in the middle, add hopsAway
+ if (mp.hop_start != 0 && mp.hop_limit <= mp.hop_start)
+ info->hops_away = mp.hop_start - mp.hop_limit;
}
}
diff --git a/src/mesh/RadioInterface.cpp b/src/mesh/RadioInterface.cpp
index cea3968ce..c10eb26f6 100644
--- a/src/mesh/RadioInterface.cpp
+++ b/src/mesh/RadioInterface.cpp
@@ -302,6 +302,8 @@ void printPacket(const char *prefix, const meshtastic_MeshPacket *p)
out += DEBUG_PORT.mt_sprintf(" rxRSSI=%i", p->rx_rssi);
if (p->via_mqtt != 0)
out += DEBUG_PORT.mt_sprintf(" via MQTT");
+ if (p->hop_start != 0)
+ out += DEBUG_PORT.mt_sprintf(" hopStart=%d", p->hop_start);
if (p->priority != 0)
out += DEBUG_PORT.mt_sprintf(" priority=%d", p->priority);
@@ -561,6 +563,7 @@ size_t RadioInterface::beginSending(meshtastic_MeshPacket *p)
p->hop_limit = HOP_RELIABLE;
}
h->flags = p->hop_limit | (p->want_ack ? PACKET_FLAGS_WANT_ACK_MASK : 0) | (p->via_mqtt ? PACKET_FLAGS_VIA_MQTT_MASK : 0);
+ h->flags |= (p->hop_start << PACKET_FLAGS_HOP_START_SHIFT) & PACKET_FLAGS_HOP_START_MASK;
// if the sender nodenum is zero, that means uninitialized
assert(h->from);
@@ -569,4 +572,4 @@ size_t RadioInterface::beginSending(meshtastic_MeshPacket *p)
sendingPacket = p;
return p->encrypted.size + sizeof(PacketHeader);
-}
+}
\ No newline at end of file
diff --git a/src/mesh/RadioInterface.h b/src/mesh/RadioInterface.h
index 83c5dae64..f85b3bfa5 100644
--- a/src/mesh/RadioInterface.h
+++ b/src/mesh/RadioInterface.h
@@ -10,9 +10,11 @@
#define MAX_RHPACKETLEN 256
-#define PACKET_FLAGS_HOP_MASK 0x07
+#define PACKET_FLAGS_HOP_LIMIT_MASK 0x07
#define PACKET_FLAGS_WANT_ACK_MASK 0x08
#define PACKET_FLAGS_VIA_MQTT_MASK 0x10
+#define PACKET_FLAGS_HOP_START_MASK 0xE0
+#define PACKET_FLAGS_HOP_START_SHIFT 5
/**
* This structure has to exactly match the wire layout when sent over the radio link. Used to keep compatibility
@@ -224,4 +226,4 @@ class RadioInterface
};
/// Debug printing for packets
-void printPacket(const char *prefix, const meshtastic_MeshPacket *p);
+void printPacket(const char *prefix, const meshtastic_MeshPacket *p);
\ No newline at end of file
diff --git a/src/mesh/RadioLibInterface.cpp b/src/mesh/RadioLibInterface.cpp
index 8a2bc53e5..9f42afa6d 100644
--- a/src/mesh/RadioLibInterface.cpp
+++ b/src/mesh/RadioLibInterface.cpp
@@ -359,8 +359,9 @@ void RadioLibInterface::handleReceiveInterrupt()
mp->to = h->to;
mp->id = h->id;
mp->channel = h->channel;
- assert(HOP_MAX <= PACKET_FLAGS_HOP_MASK); // If hopmax changes, carefully check this code
- mp->hop_limit = h->flags & PACKET_FLAGS_HOP_MASK;
+ assert(HOP_MAX <= PACKET_FLAGS_HOP_LIMIT_MASK); // If hopmax changes, carefully check this code
+ mp->hop_limit = h->flags & PACKET_FLAGS_HOP_LIMIT_MASK;
+ mp->hop_start = (h->flags & PACKET_FLAGS_HOP_START_MASK) >> PACKET_FLAGS_HOP_START_SHIFT;
mp->want_ack = !!(h->flags & PACKET_FLAGS_WANT_ACK_MASK);
mp->via_mqtt = !!(h->flags & PACKET_FLAGS_VIA_MQTT_MASK);
@@ -407,4 +408,4 @@ void RadioLibInterface::startSend(meshtastic_MeshPacket *txp)
// bits
enableInterrupt(isrTxLevel0);
}
-}
+}
\ No newline at end of file
diff --git a/src/mesh/ReliableRouter.cpp b/src/mesh/ReliableRouter.cpp
index a1e9f281d..167a248ab 100644
--- a/src/mesh/ReliableRouter.cpp
+++ b/src/mesh/ReliableRouter.cpp
@@ -71,12 +71,12 @@ bool ReliableRouter::shouldFilterReceived(const meshtastic_MeshPacket *p)
i->second.nextTxMsec += iface->getPacketTime(p);
}
- /* Resend implicit ACKs for repeated packets (assuming the original packet was sent with HOP_RELIABLE)
+ /* Resend implicit ACKs for repeated packets (hopStart equals hopLimit);
* this way if an implicit ACK is dropped and a packet is resent we'll rebroadcast again.
* Resending real ACKs is omitted, as you might receive a packet multiple times due to flooding and
* flooding this ACK back to the original sender already adds redundancy. */
- if (wasSeenRecently(p, false) && p->hop_limit == HOP_RELIABLE && !MeshModule::currentReply && p->to != nodeDB.getNodeNum()) {
- // retransmission on broadcast has hop_limit still equal to HOP_RELIABLE
+ bool isRepeated = p->hop_start == 0 ? (p->hop_limit == HOP_RELIABLE) : (p->hop_start == p->hop_limit);
+ if (wasSeenRecently(p, false) && isRepeated && !MeshModule::currentReply && p->to != nodeDB.getNodeNum()) {
LOG_DEBUG("Resending implicit ack for a repeated floodmsg\n");
meshtastic_MeshPacket *tosend = packetPool.allocCopy(*p);
tosend->hop_limit--; // bump down the hop count
@@ -107,10 +107,11 @@ void ReliableRouter::sniffReceived(const meshtastic_MeshPacket *p, const meshtas
if (MeshModule::currentReply) {
LOG_DEBUG("Some other module has replied to this message, no need for a 2nd ack\n");
} else if (p->which_payload_variant == meshtastic_MeshPacket_decoded_tag) {
- sendAckNak(meshtastic_Routing_Error_NONE, getFrom(p), p->id, p->channel);
+ sendAckNak(meshtastic_Routing_Error_NONE, getFrom(p), p->id, p->channel, p->hop_start, p->hop_limit);
} else {
// Send a 'NO_CHANNEL' error on the primary channel if want_ack packet destined for us cannot be decoded
- sendAckNak(meshtastic_Routing_Error_NO_CHANNEL, getFrom(p), p->id, channels.getPrimaryIndex());
+ sendAckNak(meshtastic_Routing_Error_NO_CHANNEL, getFrom(p), p->id, channels.getPrimaryIndex(), p->hop_start,
+ p->hop_limit);
}
}
@@ -255,4 +256,4 @@ void ReliableRouter::setNextTx(PendingPacket *pending)
LOG_DEBUG("Setting next retransmission in %u msecs: ", d);
printPacket("", pending->packet);
setReceivedMessage(); // Run ASAP, so we can figure out our correct sleep time
-}
+}
\ No newline at end of file
diff --git a/src/mesh/Router.cpp b/src/mesh/Router.cpp
index 1d6a2d96b..7c739b8f2 100644
--- a/src/mesh/Router.cpp
+++ b/src/mesh/Router.cpp
@@ -132,9 +132,10 @@ meshtastic_MeshPacket *Router::allocForSending()
/**
* Send an ack or a nak packet back towards whoever sent idFrom
*/
-void Router::sendAckNak(meshtastic_Routing_Error err, NodeNum to, PacketId idFrom, ChannelIndex chIndex)
+void Router::sendAckNak(meshtastic_Routing_Error err, NodeNum to, PacketId idFrom, ChannelIndex chIndex, uint8_t hopStart,
+ uint8_t hopLimit)
{
- routingModule->sendAckNak(err, to, idFrom, chIndex);
+ routingModule->sendAckNak(err, to, idFrom, chIndex, hopStart, hopLimit);
}
void Router::abortSendAndNak(meshtastic_Routing_Error err, meshtastic_MeshPacket *p)
@@ -240,6 +241,10 @@ ErrorCode Router::send(meshtastic_MeshPacket *p)
// the lora we need to make sure we have replaced it with our local address
p->from = getFrom(p);
+ // If we are the original transmitter, set the hop limit with which we start
+ if (p->from == getNodeNum())
+ p->hop_start = p->hop_limit;
+
// If the packet hasn't yet been encrypted, do so now (it might already be encrypted if we are just forwarding it)
assert(p->which_payload_variant == meshtastic_MeshPacket_encrypted_tag ||
@@ -292,7 +297,7 @@ bool perhapsDecode(meshtastic_MeshPacket *p)
return false;
if (config.device.rebroadcast_mode == meshtastic_Config_DeviceConfig_RebroadcastMode_KNOWN_ONLY &&
- !nodeDB.getMeshNode(p->from)->has_user) {
+ (nodeDB.getMeshNode(p->from) == NULL || !nodeDB.getMeshNode(p->from)->has_user)) {
LOG_DEBUG("Node 0x%x not in NodeDB. Rebroadcast mode KNOWN_ONLY will ignore packet\n", p->from);
return false;
}
diff --git a/src/mesh/Router.h b/src/mesh/Router.h
index db810e42e..98486745b 100644
--- a/src/mesh/Router.h
+++ b/src/mesh/Router.h
@@ -104,7 +104,8 @@ class Router : protected concurrency::OSThread
/**
* Send an ack or a nak packet back towards whoever sent idFrom
*/
- void sendAckNak(meshtastic_Routing_Error err, NodeNum to, PacketId idFrom, ChannelIndex chIndex);
+ void sendAckNak(meshtastic_Routing_Error err, NodeNum to, PacketId idFrom, ChannelIndex chIndex, uint8_t hopStart = 0,
+ uint8_t hopLimit = 0);
private:
/**
diff --git a/src/mesh/generated/meshtastic/portnums.pb.h b/src/mesh/generated/meshtastic/portnums.pb.h
index 88342e5dc..3f3e9aaee 100644
--- a/src/mesh/generated/meshtastic/portnums.pb.h
+++ b/src/mesh/generated/meshtastic/portnums.pb.h
@@ -38,19 +38,19 @@ typedef enum _meshtastic_PortNum {
ENCODING: Protobuf */
meshtastic_PortNum_REMOTE_HARDWARE_APP = 2,
/* The built-in position messaging app.
- Payload is a [Position](/docs/developers/protobufs/api#position) message
+ Payload is a Position message.
ENCODING: Protobuf */
meshtastic_PortNum_POSITION_APP = 3,
/* The built-in user info app.
- Payload is a [User](/docs/developers/protobufs/api#user) message
+ Payload is a User message.
ENCODING: Protobuf */
meshtastic_PortNum_NODEINFO_APP = 4,
/* Protocol control packets for mesh protocol use.
- Payload is a [Routing](/docs/developers/protobufs/api#routing) message
+ Payload is a Routing message.
ENCODING: Protobuf */
meshtastic_PortNum_ROUTING_APP = 5,
/* Admin control packets.
- Payload is a [AdminMessage](/docs/developers/protobufs/api#adminmessage) message
+ Payload is a AdminMessage message.
ENCODING: Protobuf */
meshtastic_PortNum_ADMIN_APP = 6,
/* Compressed TEXT_MESSAGE payloads.
@@ -60,7 +60,7 @@ typedef enum _meshtastic_PortNum {
any incoming TEXT_MESSAGE_COMPRESSED_APP payload and convert to TEXT_MESSAGE_APP. */
meshtastic_PortNum_TEXT_MESSAGE_COMPRESSED_APP = 7,
/* Waypoint payloads.
- Payload is a [Waypoint](/docs/developers/protobufs/api#waypoint) message
+ Payload is a Waypoint message.
ENCODING: Protobuf */
meshtastic_PortNum_WAYPOINT_APP = 8,
/* Audio Payloads.
diff --git a/src/mesh/generated/meshtastic/telemetry.pb.h b/src/mesh/generated/meshtastic/telemetry.pb.h
index fc2780a96..d73c6baa1 100644
--- a/src/mesh/generated/meshtastic/telemetry.pb.h
+++ b/src/mesh/generated/meshtastic/telemetry.pb.h
@@ -41,7 +41,9 @@ typedef enum _meshtastic_TelemetrySensorType {
/* PM2.5 air quality sensor */
meshtastic_TelemetrySensorType_PMSA003I = 13,
/* INA3221 3 Channel Voltage / Current Sensor */
- meshtastic_TelemetrySensorType_INA3221 = 14
+ meshtastic_TelemetrySensorType_INA3221 = 14,
+ /* BMP085/BMP180 High accuracy temperature and pressure (older Version of BMP280) */
+ meshtastic_TelemetrySensorType_BMP085 = 15
} meshtastic_TelemetrySensorType;
/* Struct definitions */
@@ -141,8 +143,8 @@ extern "C" {
/* Helper constants for enums */
#define _meshtastic_TelemetrySensorType_MIN meshtastic_TelemetrySensorType_SENSOR_UNSET
-#define _meshtastic_TelemetrySensorType_MAX meshtastic_TelemetrySensorType_INA3221
-#define _meshtastic_TelemetrySensorType_ARRAYSIZE ((meshtastic_TelemetrySensorType)(meshtastic_TelemetrySensorType_INA3221+1))
+#define _meshtastic_TelemetrySensorType_MAX meshtastic_TelemetrySensorType_BMP085
+#define _meshtastic_TelemetrySensorType_ARRAYSIZE ((meshtastic_TelemetrySensorType)(meshtastic_TelemetrySensorType_BMP085+1))
diff --git a/src/mesh/raspihttp/PiWebServer.cpp b/src/mesh/raspihttp/PiWebServer.cpp
new file mode 100644
index 000000000..41f6727a4
--- /dev/null
+++ b/src/mesh/raspihttp/PiWebServer.cpp
@@ -0,0 +1,530 @@
+/*
+Adds a WebServer and WebService callbacks to meshtastic as Linux Version. The WebServer & Webservices
+runs in a real linux thread beside the portdunio threading emulation. It replaces the complete ESP32
+Webserver libs including generation of SSL certifcicates, because the use ESP specific details in
+the lib that can't be emulated.
+
+The WebServices adapt to the two major phoneapi functions "handleAPIv1FromRadio,handleAPIv1ToRadio"
+The WebServer just adds basaic support to deliver WebContent, so it can be used to
+deliver the WebGui definded by the WebClient Project.
+
+Steps to get it running:
+1.) Add these Linux Libs to the compile and target machine:
+
+ sudo apt update && \
+ apt -y install openssl libssl-dev libopenssl libsdl2-dev \
+ libulfius-dev liborcania-dev
+
+2.) Configure the root directory of the web Content in the config.yaml file.
+ The followinng tags should be included and set at your needs
+
+ Example entry in the config.yaml
+ Webserver:
+ Port: 9001 # Port for Webserver & Webservices
+ RootPath: /home/marc/web # Root Dir of WebServer
+
+3.) Checkout the web project
+ https://github.com/meshtastic/web.git
+
+ Build it and copy the content of the folder web/dist/* to the folder you did set as "RootPath"
+
+!!!The WebServer should not be used as production system or exposed to the Internet. Its a raw basic version!!!
+
+Author: Marc Philipp Hammermann
+mail: marchammermann@googlemail.com
+
+*/
+#ifdef PORTDUINO_LINUX_HARDWARE
+#if __has_include()
+#include "PiWebServer.h"
+#include "NodeDB.h"
+#include "PhoneAPI.h"
+#include "PowerFSM.h"
+#include "RadioLibInterface.h"
+#include "airtime.h"
+#include "graphics/Screen.h"
+#include "main.h"
+#include "mesh/wifi/WiFiAPClient.h"
+#include "sleep.h"
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include
+#include
+
+#include "PortduinoFS.h"
+#include "platform/portduino/PortduinoGlue.h"
+
+#define DEFAULT_REALM "default_realm"
+#define PREFIX ""
+
+struct _file_config configWeb;
+
+// We need to specify some content-type mapping, so the resources get delivered with the
+// right content type and are displayed correctly in the browser
+char contentTypes[][2][32] = {{".txt", "text/plain"}, {".html", "text/html"},
+ {".js", "text/javascript"}, {".png", "image/png"},
+ {".jpg", "image/jpg"}, {".gz", "application/gzip"},
+ {".gif", "image/gif"}, {".json", "application/json"},
+ {".css", "text/css"}, {".ico", "image/vnd.microsoft.icon"},
+ {".svg", "image/svg+xml"}, {".ts", "text/javascript"},
+ {".tsx", "text/javascript"}, {"", ""}};
+
+#undef str
+
+volatile bool isWebServerReady;
+volatile bool isCertReady;
+
+HttpAPI webAPI;
+
+PiWebServerThread *piwebServerThread;
+
+/**
+ * Return the filename extension
+ */
+const char *get_filename_ext(const char *path)
+{
+ const char *dot = strrchr(path, '.');
+ if (!dot || dot == path)
+ return "*";
+ if (strchr(dot, '?') != NULL) {
+ //*strchr(dot, '?') = '\0';
+ const char *empty = "\0";
+ return empty;
+ }
+ return dot;
+}
+
+/**
+ * Streaming callback function to ease sending large files
+ */
+static ssize_t callback_static_file_stream(void *cls, uint64_t pos, char *buf, size_t max)
+{
+ (void)(pos);
+ if (cls != NULL) {
+ return fread(buf, 1, max, (FILE *)cls);
+ } else {
+ return U_STREAM_END;
+ }
+}
+
+/**
+ * Cleanup FILE* structure when streaming is complete
+ */
+static void callback_static_file_stream_free(void *cls)
+{
+ if (cls != NULL) {
+ fclose((FILE *)cls);
+ }
+}
+
+/**
+ * static file callback endpoint that delivers the content for WebServer calls
+ */
+int callback_static_file(const struct _u_request *request, struct _u_response *response, void *user_data)
+{
+ size_t length;
+ FILE *f;
+ char *file_requested, *file_path, *url_dup_save, *real_path = NULL;
+ const char *content_type;
+
+ /*
+ * Comment this if statement if you don't access static files url from root dir, like /app
+ */
+ if (request->callback_position > 0) {
+ return U_CALLBACK_CONTINUE;
+ } else if (user_data != NULL && (configWeb.files_path != NULL)) {
+ file_requested = o_strdup(request->http_url);
+ url_dup_save = file_requested;
+
+ while (file_requested[0] == '/') {
+ file_requested++;
+ }
+ file_requested += o_strlen(configWeb.url_prefix);
+ while (file_requested[0] == '/') {
+ file_requested++;
+ }
+
+ if (strchr(file_requested, '#') != NULL) {
+ *strchr(file_requested, '#') = '\0';
+ }
+
+ if (strchr(file_requested, '?') != NULL) {
+ *strchr(file_requested, '?') = '\0';
+ }
+
+ if (file_requested == NULL || o_strlen(file_requested) == 0 || 0 == o_strcmp("/", file_requested)) {
+ o_free(url_dup_save);
+ url_dup_save = file_requested = o_strdup("index.html");
+ }
+
+ file_path = msprintf("%s/%s", configWeb.files_path, file_requested);
+ real_path = realpath(file_path, NULL);
+ if (0 == o_strncmp(configWeb.files_path, real_path, o_strlen(configWeb.files_path))) {
+ if (access(file_path, F_OK) != -1) {
+ f = fopen(file_path, "rb");
+ if (f) {
+ fseek(f, 0, SEEK_END);
+ length = ftell(f);
+ fseek(f, 0, SEEK_SET);
+
+ content_type = u_map_get_case(&configWeb.mime_types, get_filename_ext(file_requested));
+ if (content_type == NULL) {
+ content_type = u_map_get(&configWeb.mime_types, "*");
+ LOG_DEBUG("Static File Server - Unknown mime type for extension %s \n", get_filename_ext(file_requested));
+ }
+ u_map_put(response->map_header, "Content-Type", content_type);
+ u_map_copy_into(response->map_header, &configWeb.map_header);
+
+ if (ulfius_set_stream_response(response, 200, callback_static_file_stream, callback_static_file_stream_free,
+ length, STATIC_FILE_CHUNK, f) != U_OK) {
+ LOG_DEBUG("callback_static_file - Error ulfius_set_stream_response\n ");
+ }
+ }
+ } else {
+ if (configWeb.redirect_on_404 == NULL) {
+ ulfius_set_string_body_response(response, 404, "File not found");
+ } else {
+ ulfius_add_header_to_response(response, "Location", configWeb.redirect_on_404);
+ response->status = 302;
+ }
+ }
+ } else {
+ if (configWeb.redirect_on_404 == NULL) {
+ ulfius_set_string_body_response(response, 404, "File not found");
+ } else {
+ ulfius_add_header_to_response(response, "Location", configWeb.redirect_on_404);
+ response->status = 302;
+ }
+ }
+
+ o_free(file_path);
+ o_free(url_dup_save);
+ free(real_path); // realpath uses malloc
+ return U_CALLBACK_CONTINUE;
+ } else {
+ LOG_DEBUG("Static File Server - Error, user_data is NULL or inconsistent\n");
+ return U_CALLBACK_ERROR;
+ }
+}
+
+static void handleWebResponse() {}
+
+/*
+ * Adapt the radioapi to the Webservice handleAPIv1ToRadio
+ * Trigger : WebGui(SAVE)->WebServcice->phoneApi
+ */
+int handleAPIv1ToRadio(const struct _u_request *req, struct _u_response *res, void *user_data)
+{
+ LOG_DEBUG("handleAPIv1ToRadio web -> radio \n");
+
+ ulfius_add_header_to_response(res, "Content-Type", "application/x-protobuf");
+ ulfius_add_header_to_response(res, "Access-Control-Allow-Headers", "Content-Type");
+ ulfius_add_header_to_response(res, "Access-Control-Allow-Origin", "*");
+ ulfius_add_header_to_response(res, "Access-Control-Allow-Methods", "PUT, OPTIONS");
+ ulfius_add_header_to_response(res, "X-Protobuf-Schema",
+ "https://raw.githubusercontent.com/meshtastic/protobufs/master/mesh.proto");
+
+ if (req->http_verb == "OPTIONS") {
+ ulfius_set_response_properties(res, U_OPT_STATUS, 204);
+ return U_CALLBACK_CONTINUE;
+ }
+
+ byte buffer[MAX_TO_FROM_RADIO_SIZE];
+ size_t s = req->binary_body_length;
+
+ memcpy(buffer, req->binary_body, MAX_TO_FROM_RADIO_SIZE);
+
+ // FIXME* Problem with portdunio loosing mountpoint maybe because of running in a real sep. thread
+
+ portduinoVFS->mountpoint("/home/marc/.portduino/default");
+
+ LOG_DEBUG("Received %d bytes from PUT request\n", s);
+ webAPI.handleToRadio(buffer, s);
+ LOG_DEBUG("end web->radio \n");
+ return U_CALLBACK_COMPLETE;
+}
+
+/*
+ * Adapt the radioapi to the Webservice handleAPIv1FromRadio
+ * Trigger : WebGui(POLL)->handleAPIv1FromRadio->phoneapi->Meshtastic(Radio) events
+ */
+int handleAPIv1FromRadio(const struct _u_request *req, struct _u_response *res, void *user_data)
+{
+
+ // LOG_DEBUG("handleAPIv1FromRadio radio -> web\n");
+ std::string valueAll;
+
+ // Status code is 200 OK by default.
+ ulfius_add_header_to_response(res, "Content-Type", "application/x-protobuf");
+ ulfius_add_header_to_response(res, "Access-Control-Allow-Origin", "*");
+ ulfius_add_header_to_response(res, "Access-Control-Allow-Methods", "GET");
+ ulfius_add_header_to_response(res, "X-Protobuf-Schema",
+ "https://raw.githubusercontent.com/meshtastic/protobufs/master/mesh.proto");
+
+ uint8_t txBuf[MAX_STREAM_BUF_SIZE];
+ uint32_t len = 1;
+
+ if (valueAll == "true") {
+ while (len) {
+ len = webAPI.getFromRadio(txBuf);
+ ulfius_set_response_properties(res, U_OPT_STATUS, 200, U_OPT_BINARY_BODY, txBuf, len);
+ const char *tmpa = (const char *)txBuf;
+ ulfius_set_string_body_response(res, 200, tmpa);
+ // LOG_DEBUG("\n----webAPI response all:----\n");
+ LOG_DEBUG(tmpa);
+ LOG_DEBUG("\n");
+ }
+ // Otherwise, just return one protobuf
+ } else {
+ len = webAPI.getFromRadio(txBuf);
+ const char *tmpa = (const char *)txBuf;
+ ulfius_set_binary_body_response(res, 200, tmpa, len);
+ // LOG_DEBUG("\n----webAPI response:\n");
+ LOG_DEBUG(tmpa);
+ LOG_DEBUG("\n");
+ }
+
+ // LOG_DEBUG("end radio->web\n", len);
+ return U_CALLBACK_COMPLETE;
+}
+
+/*
+OpenSSL RSA Key Gen
+*/
+int generate_rsa_key(EVP_PKEY **pkey)
+{
+ EVP_PKEY_CTX *pkey_ctx = EVP_PKEY_CTX_new_id(EVP_PKEY_RSA, NULL);
+ if (!pkey_ctx)
+ return -1;
+ if (EVP_PKEY_keygen_init(pkey_ctx) <= 0)
+ return -1;
+ if (EVP_PKEY_CTX_set_rsa_keygen_bits(pkey_ctx, 2048) <= 0)
+ return -1;
+ if (EVP_PKEY_keygen(pkey_ctx, pkey) <= 0)
+ return -1;
+ EVP_PKEY_CTX_free(pkey_ctx);
+ return 0; // SUCCESS
+}
+
+int generate_self_signed_x509(EVP_PKEY *pkey, X509 **x509)
+{
+ *x509 = X509_new();
+ if (!*x509)
+ return -1;
+ if (X509_set_version(*x509, 2) != 1)
+ return -1;
+ ASN1_INTEGER_set(X509_get_serialNumber(*x509), 1);
+ X509_gmtime_adj(X509_get_notBefore(*x509), 0);
+ X509_gmtime_adj(X509_get_notAfter(*x509), 31536000L); // 1 YEAR ACCESS
+
+ X509_set_pubkey(*x509, pkey);
+
+ // SET Subject Name
+ X509_NAME *name = X509_get_subject_name(*x509);
+ X509_NAME_add_entry_by_txt(name, "C", MBSTRING_ASC, (unsigned char *)"DE", -1, -1, 0);
+ X509_NAME_add_entry_by_txt(name, "O", MBSTRING_ASC, (unsigned char *)"Meshtastic", -1, -1, 0);
+ X509_NAME_add_entry_by_txt(name, "CN", MBSTRING_ASC, (unsigned char *)"meshtastic.local", -1, -1, 0);
+ // Selfsigned, Issuer = Subject
+ X509_set_issuer_name(*x509, name);
+
+ // Certificate signed with our privte key
+ if (X509_sign(*x509, pkey, EVP_sha256()) <= 0)
+ return -1;
+
+ return 0;
+}
+
+char *read_file_into_string(const char *filename)
+{
+ FILE *file = fopen(filename, "rb");
+ if (file == NULL) {
+ LOG_ERROR("Error reading File : %s \n", filename);
+ return NULL;
+ }
+
+ // Size of file
+ fseek(file, 0, SEEK_END);
+ long filesize = ftell(file);
+ rewind(file);
+
+ // reserve mem for file + 1 byte
+ char *buffer = (char *)malloc(filesize + 1);
+ if (buffer == NULL) {
+ LOG_ERROR("Malloc of mem failed for file : %s \n", filename);
+ fclose(file);
+ return NULL;
+ }
+
+ // read content
+ size_t readSize = fread(buffer, 1, filesize, file);
+ if (readSize != filesize) {
+ LOG_ERROR("Error reading file into buffer\n");
+ free(buffer);
+ fclose(file);
+ return NULL;
+ }
+
+ // add terminator sign at the end
+ buffer[filesize] = '\0';
+ fclose(file);
+ return buffer; // return pointer
+}
+
+int PiWebServerThread::CheckSSLandLoad()
+{
+ // read certificate
+ cert_pem = read_file_into_string("certificate.pem");
+ if (cert_pem == NULL) {
+ LOG_ERROR("ERROR SSL Certificate File can't be loaded or is missing\n");
+ return 1;
+ }
+ // read private key
+ key_pem = read_file_into_string("private_key.pem");
+ if (key_pem == NULL) {
+ LOG_ERROR("ERROR file private_key can't be loaded or is missing\n");
+ return 2;
+ }
+
+ return 0;
+}
+
+int PiWebServerThread::CreateSSLCertificate()
+{
+
+ EVP_PKEY *pkey = NULL;
+ X509 *x509 = NULL;
+
+ if (generate_rsa_key(&pkey) != 0) {
+ LOG_ERROR("Error generating RSA-Key.\n");
+ return 1;
+ }
+
+ if (generate_self_signed_x509(pkey, &x509) != 0) {
+ LOG_ERROR("Error generating of X509-Certificat.\n");
+ return 2;
+ }
+
+ // Ope file to write private key file
+ FILE *pkey_file = fopen("private_key.pem", "wb");
+ if (!pkey_file) {
+ LOG_ERROR("Error opening private key file.\n");
+ return 3;
+ }
+ // write private key file
+ PEM_write_PrivateKey(pkey_file, pkey, NULL, NULL, 0, NULL, NULL);
+ fclose(pkey_file);
+
+ // open Certificate file
+ FILE *x509_file = fopen("certificate.pem", "wb");
+ if (!x509_file) {
+ LOG_ERROR("Error opening certificate.\n");
+ return 4;
+ }
+ // write cirtificate
+ PEM_write_X509(x509_file, x509);
+ fclose(x509_file);
+
+ EVP_PKEY_free(pkey);
+ X509_free(x509);
+ LOG_INFO("Create SSL Certifictate -certificate.pem- succesfull \n");
+ return 0;
+}
+
+void initWebServer() {}
+
+PiWebServerThread::PiWebServerThread()
+{
+ int ret, retssl, webservport;
+
+ if (CheckSSLandLoad() != 0) {
+ CreateSSLCertificate();
+ if (CheckSSLandLoad() != 0) {
+ LOG_ERROR("Major Error Gen & Read SSL Certificate\n");
+ }
+ }
+
+ if (settingsMap[webserverport] != 0) {
+ webservport = settingsMap[webserverport];
+ LOG_INFO("Using webserver port from yaml config. %i \n", webservport);
+ } else {
+ LOG_INFO("Webserver port in yaml config set to 0, so defaulting to port 443.\n");
+ webservport = 443;
+ }
+
+ // Web Content Service Instance
+ if (ulfius_init_instance(&instanceWeb, webservport, NULL, DEFAULT_REALM) != U_OK) {
+ LOG_ERROR("Webserver couldn't be started, abort execution\n");
+ } else {
+
+ LOG_INFO("Webserver started ....\n");
+ u_map_init(&configWeb.mime_types);
+ u_map_put(&configWeb.mime_types, "*", "application/octet-stream");
+ u_map_put(&configWeb.mime_types, ".html", "text/html");
+ u_map_put(&configWeb.mime_types, ".htm", "text/html");
+ u_map_put(&configWeb.mime_types, ".tsx", "application/javascript");
+ u_map_put(&configWeb.mime_types, ".ts", "application/javascript");
+ u_map_put(&configWeb.mime_types, ".css", "text/css");
+ u_map_put(&configWeb.mime_types, ".js", "application/javascript");
+ u_map_put(&configWeb.mime_types, ".json", "application/json");
+ u_map_put(&configWeb.mime_types, ".png", "image/png");
+ u_map_put(&configWeb.mime_types, ".gif", "image/gif");
+ u_map_put(&configWeb.mime_types, ".jpeg", "image/jpeg");
+ u_map_put(&configWeb.mime_types, ".jpg", "image/jpeg");
+ u_map_put(&configWeb.mime_types, ".ttf", "font/ttf");
+ u_map_put(&configWeb.mime_types, ".woff", "font/woff");
+ u_map_put(&configWeb.mime_types, ".ico", "image/x-icon");
+ u_map_put(&configWeb.mime_types, ".svg", "image/svg+xml");
+
+ webrootpath = settingsStrings[webserverrootpath];
+
+ configWeb.files_path = (char *)webrootpath.c_str();
+ configWeb.url_prefix = "";
+ configWeb.rootPath = strdup(portduinoVFS->mountpoint());
+
+ u_map_put(instanceWeb.default_headers, "Access-Control-Allow-Origin", "*");
+ // Maximum body size sent by the client is 1 Kb
+ instanceWeb.max_post_body_size = 1024;
+ ulfius_add_endpoint_by_val(&instanceWeb, "GET", PREFIX, "/api/v1/fromradio/*", 1, &handleAPIv1FromRadio, NULL);
+ ulfius_add_endpoint_by_val(&instanceWeb, "PUT", PREFIX, "/api/v1/toradio/*", 1, &handleAPIv1ToRadio, configWeb.rootPath);
+
+ // Add callback function to all endpoints for the Web Server
+ ulfius_add_endpoint_by_val(&instanceWeb, "GET", NULL, "/*", 2, &callback_static_file, &configWeb);
+
+ // thats for serving without SSL
+ // retssl = ulfius_start_framework(&instanceWeb);
+
+ // thats for serving with SSL
+ retssl = ulfius_start_secure_framework(&instanceWeb, key_pem, cert_pem);
+
+ if (retssl == U_OK) {
+ LOG_INFO("Web Server framework started on port: %i \n", webservport);
+ LOG_INFO("Web Server root %s\n", (char *)webrootpath.c_str());
+ } else {
+ LOG_ERROR("Error starting Web Server framework\n");
+ }
+ }
+}
+
+PiWebServerThread::~PiWebServerThread()
+{
+ u_map_clean(&configWeb.mime_types);
+
+ ulfius_stop_framework(&instanceWeb);
+ ulfius_stop_framework(&instanceWeb);
+ free(configWeb.rootPath);
+ ulfius_clean_instance(&instanceService);
+ ulfius_clean_instance(&instanceService);
+ free(cert_pem);
+ LOG_INFO("End framework");
+}
+
+#endif
+#endif
\ No newline at end of file
diff --git a/src/mesh/raspihttp/PiWebServer.h b/src/mesh/raspihttp/PiWebServer.h
new file mode 100644
index 000000000..c4c49e919
--- /dev/null
+++ b/src/mesh/raspihttp/PiWebServer.h
@@ -0,0 +1,61 @@
+#pragma once
+#ifdef PORTDUINO_LINUX_HARDWARE
+#if __has_include()
+#include "PhoneAPI.h"
+#include "ulfius-cfg.h"
+#include "ulfius.h"
+#include
+#include
+
+#define STATIC_FILE_CHUNK 256
+
+void initWebServer();
+void createSSLCert();
+int callback_static_file(const struct _u_request *request, struct _u_response *response, void *user_data);
+const char *get_filename_ext(const char *path);
+
+struct _file_config {
+ char *files_path;
+ char *url_prefix;
+ struct _u_map mime_types;
+ struct _u_map map_header;
+ char *redirect_on_404;
+ char *rootPath;
+};
+
+class PiWebServerThread
+{
+ private:
+ char *key_pem = NULL;
+ char *cert_pem = NULL;
+ // struct _u_map mime_types;
+ std::string webrootpath;
+
+ public:
+ PiWebServerThread();
+ ~PiWebServerThread();
+ int CreateSSLCertificate();
+ int CheckSSLandLoad();
+ uint32_t requestRestart = 0;
+ struct _u_instance instanceWeb;
+ struct _u_instance instanceService;
+};
+
+class HttpAPI : public PhoneAPI
+{
+
+ public:
+ // Nothing here yet
+
+ private:
+ // Nothing here yet
+
+ protected:
+ /// Check the current underlying physical link to see if the client is currently connected
+ virtual bool checkIsConnected() override { return true; } // FIXME, be smarter about this
+};
+
+extern PiWebServerThread *piwebServerThread;
+
+#endif
+#endif
\ No newline at end of file
diff --git a/src/modules/Modules.cpp b/src/modules/Modules.cpp
index 2d45868fd..4f0b8f2b0 100644
--- a/src/modules/Modules.cpp
+++ b/src/modules/Modules.cpp
@@ -1,74 +1,112 @@
#include "configuration.h"
+#if !MESHTASTIC_EXCLUDE_INPUTBROKER
#include "input/InputBroker.h"
#include "input/RotaryEncoderInterruptImpl1.h"
#include "input/TrackballInterruptImpl1.h"
#include "input/UpDownInterruptImpl1.h"
#include "input/cardKbI2cImpl.h"
#include "input/kbMatrixImpl.h"
+#endif
#include "modules/AdminModule.h"
+#if !MESHTASTIC_EXCLUDE_ATAK
#include "modules/AtakPluginModule.h"
+#endif
+#if !MESHTASTIC_EXCLUDE_CANNEDMESSAGES
#include "modules/CannedMessageModule.h"
+#endif
+#if !MESHTASTIC_EXCLUDE_DETECTIONSENSOR
#include "modules/DetectionSensorModule.h"
+#endif
+#if !MESHTASTIC_EXCLUDE_NEIGHBORINFO
#include "modules/NeighborInfoModule.h"
+#endif
#include "modules/NodeInfoModule.h"
#include "modules/PositionModule.h"
+#if !MESHTASTIC_EXCLUDE_REMOTEHARDWARE
#include "modules/RemoteHardwareModule.h"
+#endif
#include "modules/RoutingModule.h"
#include "modules/TextMessageModule.h"
+#if !MESHTASTIC_EXCLUDE_TRACEROUTE
#include "modules/TraceRouteModule.h"
+#endif
+#if !MESHTASTIC_EXCLUDE_WAYPOINT
#include "modules/WaypointModule.h"
+#endif
#if ARCH_PORTDUINO
#include "input/LinuxInputImpl.h"
#endif
#if HAS_TELEMETRY
#include "modules/Telemetry/DeviceTelemetry.h"
#endif
-#if HAS_SENSOR
+#if HAS_SENSOR && !EXCLUDE_ENVIRONMENTAL_SENSOR
#include "modules/Telemetry/AirQualityTelemetry.h"
#include "modules/Telemetry/EnvironmentTelemetry.h"
#endif
-#if HAS_TELEMETRY && !defined(ARCH_PORTDUINO)
+#if HAS_TELEMETRY && !defined(ARCH_PORTDUINO) && !EXCLUDE_POWER_TELEMETRY
#include "modules/Telemetry/PowerTelemetry.h"
#endif
#ifdef ARCH_ESP32
-#ifdef USE_SX1280
+#if defined(USE_SX1280) && !MESHTASTIC_EXCLUDE_AUDIO
#include "modules/esp32/AudioModule.h"
#endif
+#if !MESHTASTIC_EXCLUDE_PAXCOUNTER
#include "modules/esp32/PaxcounterModule.h"
+#endif
+#if !MESHTASTIC_EXCLUDE_STOREFORWARD
#include "modules/esp32/StoreForwardModule.h"
#endif
+#endif
#if defined(ARCH_ESP32) || defined(ARCH_NRF52) || defined(ARCH_RP2040)
+#if !MESHTASTIC_EXCLUDE_EXTERNALNOTIFICATION
#include "modules/ExternalNotificationModule.h"
+#endif
+#if !MESHTASTIC_EXCLUDE_RANGETEST
#include "modules/RangeTestModule.h"
+#endif
#if (defined(ARCH_ESP32) || defined(ARCH_NRF52) || defined(ARCH_RP2040)) && !defined(CONFIG_IDF_TARGET_ESP32S2)
+#if !MESHTASTIC_EXCLUDE_SERIAL
#include "modules/SerialModule.h"
#endif
#endif
+#endif
/**
* Create module instances here. If you are adding a new module, you must 'new' it here (or somewhere else)
*/
void setupModules()
{
if (config.device.role != meshtastic_Config_DeviceConfig_Role_REPEATER) {
-#if HAS_BUTTON || ARCH_PORTDUINO
+#if (HAS_BUTTON || ARCH_PORTDUINO) && !MESHTASTIC_EXCLUDE_INPUTBROKER
inputBroker = new InputBroker();
#endif
adminModule = new AdminModule();
nodeInfoModule = new NodeInfoModule();
positionModule = new PositionModule();
+#if !MESHTASTIC_EXCLUDE_WAYPOINT
waypointModule = new WaypointModule();
+#endif
textMessageModule = new TextMessageModule();
+#if !MESHTASTIC_EXCLUDE_TRACEROUTE
traceRouteModule = new TraceRouteModule();
+#endif
+#if !MESHTASTIC_EXCLUDE_NEIGHBORINFO
neighborInfoModule = new NeighborInfoModule();
+#endif
+#if !MESHTASTIC_EXCLUDE_DETECTIONSENSOR
detectionSensorModule = new DetectionSensorModule();
+#endif
+#if !MESHTASTIC_EXCLUDE_ATAK
atakPluginModule = new AtakPluginModule();
+#endif
// Note: if the rest of meshtastic doesn't need to explicitly use your module, you do not need to assign the instance
// to a global variable.
+#if !MESHTASTIC_EXCLUDE_REMOTEHARDWARE
new RemoteHardwareModule();
+#endif
// Example: Put your module here
// new ReplyModule();
-#if HAS_BUTTON || ARCH_PORTDUINO
+#if (HAS_BUTTON || ARCH_PORTDUINO) && !MESHTASTIC_EXCLUDE_INPUTBROKER
rotaryEncoderInterruptImpl1 = new RotaryEncoderInterruptImpl1();
if (!rotaryEncoderInterruptImpl1->init()) {
delete rotaryEncoderInterruptImpl1;
@@ -90,47 +128,59 @@ void setupModules()
aLinuxInputImpl = new LinuxInputImpl();
aLinuxInputImpl->init();
#endif
-#if HAS_TRACKBALL
+#if HAS_TRACKBALL && !MESHTASTIC_EXCLUDE_INPUTBROKER
trackballInterruptImpl1 = new TrackballInterruptImpl1();
trackballInterruptImpl1->init();
#endif
-#if HAS_SCREEN
+#if HAS_SCREEN && !MESHTASTIC_EXCLUDE_CANNEDMESSAGES
cannedMessageModule = new CannedMessageModule();
#endif
-#if HAS_TELEMETRY
+#if HAS_TELEMETRY && !defined(ARCH_PORTDUINO)
new DeviceTelemetryModule();
#endif
-#if HAS_SENSOR
+#if HAS_SENSOR && !EXCLUDE_ENVIRONMENTAL_SENSOR
new EnvironmentTelemetryModule();
if (nodeTelemetrySensorsMap[meshtastic_TelemetrySensorType_PMSA003I].first > 0) {
new AirQualityTelemetryModule();
}
#endif
-#if HAS_TELEMETRY && !defined(ARCH_PORTDUINO)
+#if HAS_TELEMETRY && !defined(ARCH_PORTDUINO) && !EXCLUDE_POWER_TELEMETRY
new PowerTelemetryModule();
#endif
#if (defined(ARCH_ESP32) || defined(ARCH_NRF52) || defined(ARCH_RP2040)) && !defined(CONFIG_IDF_TARGET_ESP32S2) && \
!defined(CONFIG_IDF_TARGET_ESP32C3)
+#if !MESHTASTIC_EXCLUDE_SERIAL
new SerialModule();
#endif
+#endif
#ifdef ARCH_ESP32
// Only run on an esp32 based device.
-#ifdef USE_SX1280
+#if defined(USE_SX1280) && !MESHTASTIC_EXCLUDE_AUDIO
audioModule = new AudioModule();
#endif
+#if !MESHTASTIC_EXCLUDE_STOREFORWARD
storeForwardModule = new StoreForwardModule();
+#endif
+#if !MESHTASTIC_EXCLUDE_PAXCOUNTER
paxcounterModule = new PaxcounterModule();
#endif
+#endif
#if defined(ARCH_ESP32) || defined(ARCH_NRF52) || defined(ARCH_RP2040)
+#if !MESHTASTIC_EXCLUDE_EXTERNALNOTIFICATION
externalNotificationModule = new ExternalNotificationModule();
+#endif
+#if !MESHTASTIC_EXCLUDE_RANGETEST
new RangeTestModule();
+#endif
#endif
} else {
adminModule = new AdminModule();
#if HAS_TELEMETRY
new DeviceTelemetryModule();
#endif
+#if !MESHTASTIC_EXCLUDE_TRACEROUTE
traceRouteModule = new TraceRouteModule();
+#endif
}
// NOTE! This module must be added LAST because it likes to check for replies from other modules and avoid sending extra
// acks
diff --git a/src/modules/NeighborInfoModule.cpp b/src/modules/NeighborInfoModule.cpp
index 4541958fa..2e0b04afa 100644
--- a/src/modules/NeighborInfoModule.cpp
+++ b/src/modules/NeighborInfoModule.cpp
@@ -95,6 +95,7 @@ NeighborInfoModule::NeighborInfoModule()
ourPortNum = meshtastic_PortNum_NEIGHBORINFO_APP;
if (moduleConfig.neighbor_info.enabled) {
+ isPromiscuous = true; // Update neighbors from all packets
this->loadProtoForModule();
setIntervalFromNow(35 * 1000);
} else {
@@ -202,9 +203,12 @@ Pass it to an upper client; do not persist this data on the mesh
*/
bool NeighborInfoModule::handleReceivedProtobuf(const meshtastic_MeshPacket &mp, meshtastic_NeighborInfo *np)
{
- if (enabled) {
+ if (np) {
printNeighborInfo("RECEIVED", np);
updateNeighbors(mp, np);
+ } else if (mp.hop_start != 0 && mp.hop_start == mp.hop_limit) {
+ // If the hopLimit is the same as hopStart, then it is a neighbor
+ getOrCreateNeighbor(mp.from, mp.from, 0, mp.rx_snr); // Set the broadcast interval to 0, as we don't know it
}
// Allow others to handle this packet
return false;
@@ -261,7 +265,7 @@ meshtastic_Neighbor *NeighborInfoModule::getOrCreateNeighbor(NodeNum originalSen
nbr->snr = snr;
nbr->last_rx_time = getTime();
// Only if this is the original sender, the broadcast interval corresponds to it
- if (originalSender == n)
+ if (originalSender == n && node_broadcast_interval_secs != 0)
nbr->node_broadcast_interval_secs = node_broadcast_interval_secs;
saveProtoForModule(); // Save the updated neighbor
return nbr;
@@ -277,8 +281,10 @@ meshtastic_Neighbor *NeighborInfoModule::getOrCreateNeighbor(NodeNum originalSen
new_nbr->snr = snr;
new_nbr->last_rx_time = getTime();
// Only if this is the original sender, the broadcast interval corresponds to it
- if (originalSender == n)
+ if (originalSender == n && node_broadcast_interval_secs != 0)
new_nbr->node_broadcast_interval_secs = node_broadcast_interval_secs;
+ else // Assume the same broadcast interval as us for the neighbor if we don't know it
+ new_nbr->node_broadcast_interval_secs = moduleConfig.neighbor_info.update_interval;
saveProtoForModule(); // Save the new neighbor
return new_nbr;
}
diff --git a/src/modules/NeighborInfoModule.h b/src/modules/NeighborInfoModule.h
index 0e3ec09ca..df5c2c948 100644
--- a/src/modules/NeighborInfoModule.h
+++ b/src/modules/NeighborInfoModule.h
@@ -75,6 +75,9 @@ class NeighborInfoModule : public ProtobufModule, priva
/* Does our periodic broadcast */
int32_t runOnce() override;
+ // Override wantPacket to say we want to see all packets when enabled, not just those for our port number
+ virtual bool wantPacket(const meshtastic_MeshPacket *p) override { return enabled; }
+
/* These are for debugging only */
void printNeighborInfo(const char *header, const meshtastic_NeighborInfo *np);
void printNodeDBNodes(const char *header);
diff --git a/src/modules/RoutingModule.cpp b/src/modules/RoutingModule.cpp
index edeb1fb86..37a7c3755 100644
--- a/src/modules/RoutingModule.cpp
+++ b/src/modules/RoutingModule.cpp
@@ -36,13 +36,28 @@ meshtastic_MeshPacket *RoutingModule::allocReply()
return NULL;
}
-void RoutingModule::sendAckNak(meshtastic_Routing_Error err, NodeNum to, PacketId idFrom, ChannelIndex chIndex)
+void RoutingModule::sendAckNak(meshtastic_Routing_Error err, NodeNum to, PacketId idFrom, ChannelIndex chIndex, uint8_t hopStart,
+ uint8_t hopLimit)
{
- auto p = allocAckNak(err, to, idFrom, chIndex);
+ auto p = allocAckNak(err, to, idFrom, chIndex, hopStart, hopLimit);
router->sendLocal(p); // we sometimes send directly to the local node
}
+uint8_t RoutingModule::getHopLimitForResponse(uint8_t hopStart, uint8_t hopLimit)
+{
+ if (hopStart != 0) {
+ // Hops used by the request. If somebody in between running modified firmware modified it, ignore it
+ uint8_t hopsUsed = hopStart < hopLimit ? config.lora.hop_limit : hopStart - hopLimit;
+ if (hopsUsed > config.lora.hop_limit) {
+ return hopsUsed; // If the request used more hops than the limit, use the same amount of hops
+ } else if (hopsUsed + 2 < config.lora.hop_limit) {
+ return hopsUsed + 2; // Use only the amount of hops needed with some margin as the way back may be different
+ }
+ }
+ return config.lora.hop_limit; // Use the default hop limit
+}
+
RoutingModule::RoutingModule() : ProtobufModule("routing", meshtastic_PortNum_ROUTING_APP, &meshtastic_Routing_msg)
{
isPromiscuous = true;
diff --git a/src/modules/RoutingModule.h b/src/modules/RoutingModule.h
index 06e76cfb4..f085b307b 100644
--- a/src/modules/RoutingModule.h
+++ b/src/modules/RoutingModule.h
@@ -13,7 +13,11 @@ class RoutingModule : public ProtobufModule
*/
RoutingModule();
- void sendAckNak(meshtastic_Routing_Error err, NodeNum to, PacketId idFrom, ChannelIndex chIndex);
+ void sendAckNak(meshtastic_Routing_Error err, NodeNum to, PacketId idFrom, ChannelIndex chIndex, uint8_t hopStart = 0,
+ uint8_t hopLimit = 0);
+
+ // Given the hopStart and hopLimit upon reception of a request, return the hop limit to use for the response
+ uint8_t getHopLimitForResponse(uint8_t hopStart, uint8_t hopLimit);
protected:
friend class Router;
diff --git a/src/modules/Telemetry/EnvironmentTelemetry.cpp b/src/modules/Telemetry/EnvironmentTelemetry.cpp
index e501f17c2..d4f423e54 100644
--- a/src/modules/Telemetry/EnvironmentTelemetry.cpp
+++ b/src/modules/Telemetry/EnvironmentTelemetry.cpp
@@ -16,12 +16,14 @@
// Sensors
#include "Sensor/BME280Sensor.h"
#include "Sensor/BME680Sensor.h"
+#include "Sensor/BMP085Sensor.h"
#include "Sensor/BMP280Sensor.h"
#include "Sensor/LPS22HBSensor.h"
#include "Sensor/MCP9808Sensor.h"
#include "Sensor/SHT31Sensor.h"
#include "Sensor/SHTC3Sensor.h"
+BMP085Sensor bmp085Sensor;
BMP280Sensor bmp280Sensor;
BME280Sensor bme280Sensor;
BME680Sensor bme680Sensor;
@@ -67,6 +69,8 @@ int32_t EnvironmentTelemetryModule::runOnce()
LOG_INFO("Environment Telemetry: Initializing\n");
// it's possible to have this module enabled, only for displaying values on the screen.
// therefore, we should only enable the sensor loop if measurement is also enabled
+ if (bmp085Sensor.hasSensor())
+ result = bmp085Sensor.runOnce();
if (bmp280Sensor.hasSensor())
result = bmp280Sensor.runOnce();
if (bme280Sensor.hasSensor())
@@ -219,6 +223,8 @@ bool EnvironmentTelemetryModule::sendTelemetry(NodeNum dest, bool phoneOnly)
valid = lps22hbSensor.getMetrics(&m);
if (shtc3Sensor.hasSensor())
valid = shtc3Sensor.getMetrics(&m);
+ if (bmp085Sensor.hasSensor())
+ valid = bmp085Sensor.getMetrics(&m);
if (bmp280Sensor.hasSensor())
valid = bmp280Sensor.getMetrics(&m);
if (bme280Sensor.hasSensor())
diff --git a/src/modules/Telemetry/Sensor/BMP085Sensor.cpp b/src/modules/Telemetry/Sensor/BMP085Sensor.cpp
new file mode 100644
index 000000000..b0991749b
--- /dev/null
+++ b/src/modules/Telemetry/Sensor/BMP085Sensor.cpp
@@ -0,0 +1,31 @@
+#include "BMP085Sensor.h"
+#include "../mesh/generated/meshtastic/telemetry.pb.h"
+#include "TelemetrySensor.h"
+#include "configuration.h"
+#include
+#include
+
+BMP085Sensor::BMP085Sensor() : TelemetrySensor(meshtastic_TelemetrySensorType_BMP085, "BMP085") {}
+
+int32_t BMP085Sensor::runOnce()
+{
+ LOG_INFO("Init sensor: %s\n", sensorName);
+ if (!hasSensor()) {
+ return DEFAULT_SENSOR_MINIMUM_WAIT_TIME_BETWEEN_READS;
+ }
+ bmp085 = Adafruit_BMP085();
+ status = bmp085.begin(nodeTelemetrySensorsMap[sensorType].first, nodeTelemetrySensorsMap[sensorType].second);
+
+ return initI2CSensor();
+}
+
+void BMP085Sensor::setup() {}
+
+bool BMP085Sensor::getMetrics(meshtastic_Telemetry *measurement)
+{
+ LOG_DEBUG("BMP085Sensor::getMetrics\n");
+ measurement->variant.environment_metrics.temperature = bmp085.readTemperature();
+ measurement->variant.environment_metrics.barometric_pressure = bmp085.readPressure() / 100.0F;
+
+ return true;
+}
diff --git a/src/modules/Telemetry/Sensor/BMP085Sensor.h b/src/modules/Telemetry/Sensor/BMP085Sensor.h
new file mode 100644
index 000000000..c4a9479b9
--- /dev/null
+++ b/src/modules/Telemetry/Sensor/BMP085Sensor.h
@@ -0,0 +1,17 @@
+#include "../mesh/generated/meshtastic/telemetry.pb.h"
+#include "TelemetrySensor.h"
+#include
+
+class BMP085Sensor : public TelemetrySensor
+{
+ private:
+ Adafruit_BMP085 bmp085;
+
+ protected:
+ virtual void setup() override;
+
+ public:
+ BMP085Sensor();
+ virtual int32_t runOnce() override;
+ virtual bool getMetrics(meshtastic_Telemetry *measurement) override;
+};
\ No newline at end of file
diff --git a/src/mqtt/MQTT.cpp b/src/mqtt/MQTT.cpp
index 898607eca..619815e85 100644
--- a/src/mqtt/MQTT.cpp
+++ b/src/mqtt/MQTT.cpp
@@ -655,6 +655,9 @@ std::string MQTT::meshPacketToJson(meshtastic_MeshPacket *mp)
if ((int)decoded->VDOP) {
msgPayload["VDOP"] = new JSONValue((int)decoded->VDOP);
}
+ if ((int)decoded->precision_bits) {
+ msgPayload["precision_bits"] = new JSONValue((int)decoded->precision_bits);
+ }
jsonObj["payload"] = new JSONValue(msgPayload);
} else {
LOG_ERROR("Error decoding protobuf for position message!\n");
@@ -808,6 +811,8 @@ std::string MQTT::meshPacketToJson(meshtastic_MeshPacket *mp)
jsonObj["rssi"] = new JSONValue((int)mp->rx_rssi);
if (mp->rx_snr != 0)
jsonObj["snr"] = new JSONValue((float)mp->rx_snr);
+ if (mp->hop_start != 0 && mp->hop_limit <= mp->hop_start)
+ jsonObj["hops_away"] = new JSONValue((uint)(mp->hop_start - mp->hop_limit));
// serialize and write it to the stream
JSONValue *value = new JSONValue(jsonObj);
diff --git a/src/mqtt/MQTT.h b/src/mqtt/MQTT.h
index 2b803e3fc..e67958b25 100644
--- a/src/mqtt/MQTT.h
+++ b/src/mqtt/MQTT.h
@@ -80,10 +80,10 @@ class MQTT : private concurrency::OSThread
private:
std::string statusTopic = "/2/stat/";
- std::string cryptTopic = "/2/c/"; // msh/2/c/CHANNELID/NODEID
+ std::string cryptTopic = "/2/e/"; // msh/2/e/CHANNELID/NODEID
std::string jsonTopic = "/2/json/"; // msh/2/json/CHANNELID/NODEID
- /** return true if we have a channel that wants uplink/downlink
- */
+ /** return true if we have a channel that wants uplink/downlink
+ */
bool wantsLink() const;
/** Tell the server what subscriptions we want (based on channels.downlink_enabled)
diff --git a/src/platform/portduino/PortduinoGlue.cpp b/src/platform/portduino/PortduinoGlue.cpp
index 046509fab..997058406 100644
--- a/src/platform/portduino/PortduinoGlue.cpp
+++ b/src/platform/portduino/PortduinoGlue.cpp
@@ -195,6 +195,11 @@ void portduinoSetup()
settingsStrings[keyboardDevice] = (yamlConfig["Input"]["KeyboardDevice"]).as("");
}
+ if (yamlConfig["Webserver"]) {
+ settingsMap[webserverport] = (yamlConfig["Webserver"]["Port"]).as(-1);
+ settingsStrings[webserverrootpath] = (yamlConfig["Webserver"]["RootPath"]).as("");
+ }
+
} catch (YAML::Exception e) {
std::cout << "*** Exception " << e.what() << std::endl;
exit(EXIT_FAILURE);
diff --git a/src/platform/portduino/PortduinoGlue.h b/src/platform/portduino/PortduinoGlue.h
index f8da20e37..3fe5f74bf 100644
--- a/src/platform/portduino/PortduinoGlue.h
+++ b/src/platform/portduino/PortduinoGlue.h
@@ -33,7 +33,10 @@ enum configNames {
displayOffsetY,
displayInvert,
keyboardDevice,
- logoutputlevel
+ logoutputlevel,
+ webserver,
+ webserverport,
+ webserverrootpath
};
enum { no_screen, st7789, st7735, st7735s, ili9341 };
enum { no_touchscreen, xpt2046, stmpe610 };
diff --git a/src/sleep.cpp b/src/sleep.cpp
index 1afba1173..bfacffeb9 100644
--- a/src/sleep.cpp
+++ b/src/sleep.cpp
@@ -200,6 +200,13 @@ void doDeepSleep(uint32_t msecToWake, bool skipPreflight = false)
nodeDB.saveToDisk();
+#ifdef TTGO_T_ECHO
+#ifdef PIN_POWER_EN
+ pinMode(PIN_POWER_EN, INPUT); // power off peripherals
+ pinMode(PIN_POWER_EN1, INPUT_PULLDOWN);
+#endif
+#endif
+
// Kill GPS power completely (even if previously we just had it in sleep mode)
if (gps)
gps->setGPSPower(false, false, 0);
diff --git a/variants/canaryone/variant.h b/variants/canaryone/variant.h
index e31ba3c58..21aa921ce 100644
--- a/variants/canaryone/variant.h
+++ b/variants/canaryone/variant.h
@@ -103,6 +103,9 @@ static const uint8_t A0 = PIN_A0;
#define EXTERNAL_FLASH_DEVICES MX25R1635F
#define EXTERNAL_FLASH_USE_QSPI
+// Add a delay on startup to allow LoRa and GPS to power up
+#define PIN_PWR_DELAY_MS 100
+
/*
* Lora radio
*/
diff --git a/variants/heltec_esp32c3/variant.h b/variants/heltec_esp32c3/variant.h
index de6462a38..6641f9d21 100644
--- a/variants/heltec_esp32c3/variant.h
+++ b/variants/heltec_esp32c3/variant.h
@@ -9,7 +9,7 @@
#define LED_PIN 18 // LED
#define LED_INVERTED 1
-#define HAS_SCREEN 0
+#define HAS_SCREEN 1
#define HAS_GPS 0
#undef GPS_RX_PIN
#undef GPS_TX_PIN
diff --git a/variants/portduino/platformio.ini b/variants/portduino/platformio.ini
index d37c6be21..46417e388 100644
--- a/variants/portduino/platformio.ini
+++ b/variants/portduino/platformio.ini
@@ -1,6 +1,10 @@
[env:native]
extends = portduino_base
-build_flags = ${portduino_base.build_flags} -O0 -I variants/portduino
+; The pkg-config commands below optionally add link flags.
+; the || : is just a "or run the null command" to avoid returning an error code
+build_flags = ${portduino_base.build_flags} -O0 -I variants/portduino -I /usr/include
+ !pkg-config --libs libulfius --silence-errors || :
+ !pkg-config --libs openssl --silence-errors || :
board = cross_platform
lib_deps = ${portduino_base.lib_deps}
-build_src_filter = ${portduino_base.build_src_filter}
\ No newline at end of file
+build_src_filter = ${portduino_base.build_src_filter}
diff --git a/variants/rak10701/variant.h b/variants/rak10701/variant.h
index 837d081ff..d6eeb71dc 100644
--- a/variants/rak10701/variant.h
+++ b/variants/rak10701/variant.h
@@ -133,10 +133,6 @@ static const uint8_t SCK = PIN_SPI_SCK;
#define PIN_EINK_SCLK (0 + 3)
#define PIN_EINK_MOSI (0 + 30) // also called SDI
-// Controls power for the eink display - Board power is enabled either by VBUS from USB or the CPU asserting PWR_ON
-// FIXME - I think this is actually just the board power enable - it enables power to the CPU also
-// #define PIN_EINK_PWR_ON (-1)
-
// #define USE_EINK
// RAKRGB
diff --git a/variants/rak4631/variant.h b/variants/rak4631/variant.h
index 4ad99df44..0ccf3b1d7 100644
--- a/variants/rak4631/variant.h
+++ b/variants/rak4631/variant.h
@@ -133,10 +133,6 @@ static const uint8_t SCK = PIN_SPI_SCK;
#define PIN_EINK_SCLK (0 + 3)
#define PIN_EINK_MOSI (0 + 30) // also called SDI
-// Controls power for the eink display - Board power is enabled either by VBUS from USB or the CPU asserting PWR_ON
-// FIXME - I think this is actually just the board power enable - it enables power to the CPU also
-// #define PIN_EINK_PWR_ON (-1)
-
// #define USE_EINK
// RAKRGB
diff --git a/variants/rak4631_epaper/variant.h b/variants/rak4631_epaper/variant.h
index d8a5e5597..b1bd84d21 100644
--- a/variants/rak4631_epaper/variant.h
+++ b/variants/rak4631_epaper/variant.h
@@ -133,10 +133,6 @@ static const uint8_t SCK = PIN_SPI_SCK;
#define PIN_EINK_SCLK (0 + 3)
#define PIN_EINK_MOSI (0 + 30) // also called SDI
-// Controls power for the eink display - Board power is enabled either by VBUS from USB or the CPU asserting PWR_ON
-// FIXME - I think this is actually just the board power enable - it enables power to the CPU also
-// #define PIN_EINK_PWR_ON (-1)
-
#define USE_EINK
// RAKRGB
diff --git a/variants/rak4631_epaper_onrxtx/variant.h b/variants/rak4631_epaper_onrxtx/variant.h
index 411e3eb17..ec53ebd33 100644
--- a/variants/rak4631_epaper_onrxtx/variant.h
+++ b/variants/rak4631_epaper_onrxtx/variant.h
@@ -119,10 +119,6 @@ static const uint8_t SCK = PIN_SPI_SCK;
#define PIN_EINK_SCLK (0 + 14) // SCL
#define PIN_EINK_MOSI (0 + 13) // SDA
-// Controls power for the eink display - Board power is enabled either by VBUS from USB or the CPU asserting PWR_ON
-// FIXME - I think this is actually just the board power enable - it enables power to the CPU also
-// #define PIN_EINK_PWR_ON (-1)
-
// RAKRGB
#define HAS_NCP5623
diff --git a/variants/t-echo/variant.h b/variants/t-echo/variant.h
index 1af68863e..19a66719f 100644
--- a/variants/t-echo/variant.h
+++ b/variants/t-echo/variant.h
@@ -156,9 +156,9 @@ External serial flash WP25R1635FZUIL0
#define PIN_EINK_SCLK (0 + 31)
#define PIN_EINK_MOSI (0 + 29) // also called SDI
-// Controls power for the eink display - Board power is enabled either by VBUS from USB or the CPU asserting PWR_ON
-// FIXME - I think this is actually just the board power enable - it enables power to the CPU also
-#define PIN_EINK_PWR_ON (0 + 12)
+// Controls power for all peripherals (eink + GPS + LoRa + Sensor)
+#define PIN_POWER_EN (0 + 12)
+#define PIN_POWER_EN1 (0 + 13)
#define USE_EINK
diff --git a/version.properties b/version.properties
index 14d1884fb..8927d1781 100644
--- a/version.properties
+++ b/version.properties
@@ -1,4 +1,4 @@
[VERSION]
major = 2
-minor = 2
-build = 25
+minor = 3
+build = 0