diff --git a/.github/actions/setup-native/action.yml b/.github/actions/setup-native/action.yml
new file mode 100644
index 000000000..36c95d943
--- /dev/null
+++ b/.github/actions/setup-native/action.yml
@@ -0,0 +1,14 @@
+name: Setup native build
+description: Install libraries needed for building the Native/Portduino build
+
+runs:
+ using: composite
+ steps:
+ - name: Setup base
+ id: base
+ uses: ./.github/actions/setup-base
+
+ - name: Install libs needed for native build
+ shell: bash
+ run: |
+ sudo apt-get install -y libbluetooth-dev libgpiod-dev libyaml-cpp-dev openssl libssl-dev libulfius-dev liborcania-dev libusb-1.0-0-dev libi2c-dev
diff --git a/.github/workflows/build_native.yml b/.github/workflows/build_native.yml
index 74bc074aa..11ba09ad7 100644
--- a/.github/workflows/build_native.yml
+++ b/.github/workflows/build_native.yml
@@ -10,12 +10,6 @@ jobs:
build-native:
runs-on: ubuntu-latest
steps:
- - name: Install libs needed for native build
- shell: bash
- run: |
- sudo apt-get update --fix-missing
- sudo apt-get install -y libbluetooth-dev libgpiod-dev libyaml-cpp-dev openssl libssl-dev libulfius-dev liborcania-dev libusb-1.0-0-dev libi2c-dev
-
- name: Checkout code
uses: actions/checkout@v4
with:
@@ -23,17 +17,9 @@ jobs:
ref: ${{github.event.pull_request.head.ref}}
repository: ${{github.event.pull_request.head.repo.full_name}}
- - name: Upgrade python tools
- shell: bash
- run: |
- python -m pip install --upgrade pip
- pip install -U platformio adafruit-nrfutil
- pip install -U meshtastic --pre
-
- - name: Upgrade platformio
- shell: bash
- run: |
- pio upgrade
+ - name: Setup native build
+ id: base
+ uses: ./.github/actions/setup-native
- name: Build Native
run: bin/build-native.sh
diff --git a/.github/workflows/main_matrix.yml b/.github/workflows/main_matrix.yml
index 0109bef1a..a437411b5 100644
--- a/.github/workflows/main_matrix.yml
+++ b/.github/workflows/main_matrix.yml
@@ -137,6 +137,9 @@ jobs:
package-native:
uses: ./.github/workflows/package_amd64.yml
+ test-native:
+ uses: ./.github/workflows/test_native.yml
+
build-docker:
if: ${{ github.event_name == 'workflow_dispatch' }}
uses: ./.github/workflows/build_docker.yml
diff --git a/.github/workflows/test_native.yml b/.github/workflows/test_native.yml
new file mode 100644
index 000000000..d016635ef
--- /dev/null
+++ b/.github/workflows/test_native.yml
@@ -0,0 +1,169 @@
+name: Run Tests on Native platform
+
+on:
+ workflow_call:
+ workflow_dispatch:
+
+permissions: {}
+
+env:
+ LCOV_CAPTURE_FLAGS: --quiet --capture --include "${PWD}/src/*" --exclude '*/src/mesh/generated/*' --directory .pio/build/coverage/src --base-directory "${PWD}"
+
+jobs:
+ simulator-tests:
+ name: Native Simulator Tests
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v4
+ with:
+ ref: ${{github.event.pull_request.head.ref}}
+ repository: ${{github.event.pull_request.head.repo.full_name}}
+ submodules: recursive
+
+ - name: Setup native build
+ id: base
+ uses: ./.github/actions/setup-native
+
+ - name: Install simulator dependencies
+ run: pip install -U dotmap
+
+ # We now run integration test before other build steps (to quickly see runtime failures)
+ - name: Build for native/coverage
+ run: platformio run -e coverage
+
+ - name: Capture initial coverage information
+ shell: bash
+ run: |
+ sudo apt-get install -y lcov
+ lcov ${{ env.LCOV_CAPTURE_FLAGS }} --initial --output-file coverage_base.info
+ sed -i -e "s#${PWD}#.#" coverage_base.info # Make paths relative.
+
+ - name: Integration test
+ run: |
+ .pio/build/coverage/program &
+ PID=$!
+ timeout 20 bash -c "until ls -al /proc/$PID/fd | grep socket; do sleep 1; done"
+ echo "Simulator started, launching python test..."
+ python3 -c 'from meshtastic.test import testSimulator; testSimulator()'
+ wait
+
+ - name: Capture coverage information
+ if: always() # run this step even if previous step failed
+ run: |
+ lcov ${{ env.LCOV_CAPTURE_FLAGS }} --test-name integration --output-file coverage_integration.info
+ sed -i -e "s#${PWD}#.#" coverage_integration.info # Make paths relative.
+
+ - name: Get release version string
+ if: always() # run this step even if previous step failed
+ run: echo "version=$(./bin/buildinfo.py long)" >> $GITHUB_OUTPUT
+ id: version
+
+ - name: Save coverage information
+ uses: actions/upload-artifact@v4
+ if: always() # run this step even if previous step failed
+ with:
+ name: lcov-coverage-info-native-simulator-test-${{ steps.version.outputs.version }}.zip
+ overwrite: true
+ path: ./coverage_*.info
+
+ platformio-tests:
+ name: Native PlatformIO Tests
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v4
+ with:
+ ref: ${{github.event.pull_request.head.ref}}
+ repository: ${{github.event.pull_request.head.repo.full_name}}
+ submodules: recursive
+
+ - name: Setup native build
+ id: base
+ uses: ./.github/actions/setup-native
+
+ - name: Get release version string
+ run: echo "version=$(./bin/buildinfo.py long)" >> $GITHUB_OUTPUT
+ id: version
+
+ # Disable (comment-out) BUILD_EPOCH. It causes a full rebuild between tests and resets the
+ # coverage information each time.
+ - name: Disable BUILD_EPOCH
+ run: sed -i 's/-DBUILD_EPOCH=$UNIX_TIME/#-DBUILD_EPOCH=$UNIX_TIME/' platformio.ini
+
+ - name: PlatformIO Tests
+ run: platformio test -e coverage --junit-output-path testreport.xml
+
+ - name: Save test results
+ if: always() # run this step even if previous step failed
+ uses: actions/upload-artifact@v4
+ with:
+ name: platformio-test-report-${{ steps.version.outputs.version }}.zip
+ overwrite: true
+ path: ./testreport.xml
+
+ - name: Capture coverage information
+ if: always() # run this step even if previous step failed
+ run: |
+ sudo apt-get install -y lcov
+ lcov ${{ env.LCOV_CAPTURE_FLAGS }} --test-name tests --output-file coverage_tests.info
+ sed -i -e "s#${PWD}#.#" coverage_tests.info # Make paths relative.
+
+ - name: Save coverage information
+ uses: actions/upload-artifact@v4
+ if: always() # run this step even if previous step failed
+ with:
+ name: lcov-coverage-info-native-platformio-tests-${{ steps.version.outputs.version }}.zip
+ overwrite: true
+ path: ./coverage_*.info
+
+ generate-reports:
+ name: Generate Test Reports
+ runs-on: ubuntu-latest
+ permissions: # Needed for dorny/test-reporter.
+ contents: read
+ actions: read
+ checks: write
+ needs:
+ - simulator-tests
+ - platformio-tests
+ if: always()
+ steps:
+ - uses: actions/checkout@v4
+ with:
+ ref: ${{github.event.pull_request.head.ref}}
+ repository: ${{github.event.pull_request.head.repo.full_name}}
+
+ - name: Get release version string
+ run: echo "version=$(./bin/buildinfo.py long)" >> $GITHUB_OUTPUT
+ id: version
+
+ - name: Download test artifacts
+ uses: actions/download-artifact@v4
+ with:
+ name: platformio-test-report-${{ steps.version.outputs.version }}.zip
+ merge-multiple: true
+
+ - name: Test Report
+ uses: dorny/test-reporter@v1.9.1
+ with:
+ name: PlatformIO Tests
+ path: testreport.xml
+ reporter: java-junit
+
+ - name: Download coverage artifacts
+ uses: actions/download-artifact@v4
+ with:
+ pattern: lcov-coverage-info-native-*-${{ steps.version.outputs.version }}.zip
+ path: code-coverage-report
+ merge-multiple: true
+
+ - name: Generate Code Coverage Report
+ run: |
+ sudo apt-get install -y lcov
+ lcov --quiet --add-tracefile code-coverage-report/coverage_base.info --add-tracefile code-coverage-report/coverage_integration.info --add-tracefile code-coverage-report/coverage_tests.info --output-file code-coverage-report/coverage_src.info
+ genhtml --quiet --legend --prefix "${PWD}" code-coverage-report/coverage_src.info --output-directory code-coverage-report
+
+ - name: Save Code Coverage Report
+ uses: actions/upload-artifact@v4
+ with:
+ name: code-coverage-report-${{ steps.version.outputs.version }}.zip
+ path: code-coverage-report
diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml
index ae9f82543..c9489db1a 100644
--- a/.github/workflows/tests.yml
+++ b/.github/workflows/tests.yml
@@ -6,79 +6,8 @@ on:
workflow_dispatch: {}
jobs:
- test-simulator:
- runs-on: ubuntu-latest
- env:
- LCOV_CAPTURE_FLAGS: --quiet --capture --include "${PWD}/src/*" --exclude '*/src/mesh/generated/*' --directory .pio/build/coverage/src --base-directory "${PWD}"
- steps:
- - name: Install libs needed for native build
- shell: bash
- run: |
- sudo apt-get update --fix-missing
- sudo apt-get install -y libbluetooth-dev libgpiod-dev libyaml-cpp-dev openssl libssl-dev libulfius-dev liborcania-dev libusb-1.0-0-dev libi2c-dev
- sudo apt-get install -y lcov
-
- - name: Checkout code
- uses: actions/checkout@v4
- with:
- submodules: recursive
-
- - name: Upgrade python tools
- shell: bash
- run: |
- python -m pip install --upgrade pip
- pip install -U platformio adafruit-nrfutil dotmap
- pip install -U meshtastic --pre
-
- - name: Upgrade platformio
- shell: bash
- run: |
- pio upgrade
-
- - name: Build Native
- run: bin/build-native.sh
-
- # We now run integration test before other build steps (to quickly see runtime failures)
- - name: Build for native/coverage
- run: |
- platformio run -e coverage
- lcov ${{ env.LCOV_CAPTURE_FLAGS }} --initial --output-file coverage_base.info
-
- - name: Integration test
- run: |
- .pio/build/coverage/program &
- PID=$!
- timeout 20 bash -c "until ls -al /proc/$PID/fd | grep socket; do sleep 1; done"
- echo "Simulator started, launching python test..."
- python3 -c 'from meshtastic.test import testSimulator; testSimulator()'
- wait
- lcov ${{ env.LCOV_CAPTURE_FLAGS }} --test-name integration --output-file coverage_integration.info
-
- - name: PlatformIO Tests
- run: |
- platformio test -e coverage --junit-output-path testreport.xml
- lcov ${{ env.LCOV_CAPTURE_FLAGS }} --test-name tests --output-file coverage_tests.info
-
- - name: Test Report
- uses: dorny/test-reporter@v1.9.1
- if: success() || failure() # run this step even if previous step failed
- with:
- name: PlatformIO Tests
- path: testreport.xml
- reporter: java-junit
-
- - name: Generate Code Coverage Report
- run: |
- lcov --quiet --add-tracefile coverage_base.info --add-tracefile coverage_integration.info --add-tracefile coverage_tests.info --output-file coverage_src.info
- mkdir code-coverage-report
- genhtml --quiet --legend --prefix "${PWD}" coverage_src.info --output-directory code-coverage-report
- mv coverage_*.info code-coverage-report
-
- - name: Save Code Coverage Report
- uses: actions/upload-artifact@v4
- with:
- name: code-coverage-report
- path: code-coverage-report
+ native-tests:
+ uses: ./.github/workflows/test_native.yml
hardware-tests:
runs-on: test-runner
diff --git a/src/configuration.h b/src/configuration.h
index 994f1e72e..2c77b55e3 100644
--- a/src/configuration.h
+++ b/src/configuration.h
@@ -178,13 +178,6 @@ along with this program. If not, see .
#define TCA9535_ADDR 0x20
#define TCA9555_ADDR 0x26
-// -----------------------------------------------------------------------------
-// GPS
-// -----------------------------------------------------------------------------
-#ifndef GPS_THREAD_INTERVAL
-#define GPS_THREAD_INTERVAL 200
-#endif
-
// -----------------------------------------------------------------------------
// Touchscreen
// -----------------------------------------------------------------------------
@@ -206,6 +199,10 @@ along with this program. If not, see .
#define VEXT_ON_VALUE LOW
#endif
+// -----------------------------------------------------------------------------
+// GPS
+// -----------------------------------------------------------------------------
+
#ifndef GPS_BAUDRATE
#define GPS_BAUDRATE 9600
#define GPS_BAUDRATE_FIXED 0
@@ -213,6 +210,10 @@ along with this program. If not, see .
#define GPS_BAUDRATE_FIXED 1
#endif
+#ifndef GPS_THREAD_INTERVAL
+#define GPS_THREAD_INTERVAL 200
+#endif
+
/* Step #2: follow with defines common to the architecture;
also enable HAS_ option not specifically disabled by variant.h */
#include "architecture.h"
diff --git a/src/graphics/Screen.cpp b/src/graphics/Screen.cpp
index 31647c92d..198dcc235 100644
--- a/src/graphics/Screen.cpp
+++ b/src/graphics/Screen.cpp
@@ -1506,7 +1506,7 @@ Screen::Screen(ScanI2C::DeviceAddress address, meshtastic_Config_DisplayConfig_O
#elif defined(USE_ST7567)
dispdev = new ST7567Wire(address.address, -1, -1, geometry,
(address.port == ScanI2C::I2CPort::WIRE1) ? HW_I2C::I2C_TWO : HW_I2C::I2C_ONE);
-#elif ARCH_PORTDUINO
+#elif ARCH_PORTDUINO && !HAS_TFT
if (settingsMap[displayPanel] != no_screen) {
LOG_DEBUG("Make TFTDisplay!");
dispdev = new TFTDisplay(address.address, -1, -1, geometry,
@@ -2756,4 +2756,4 @@ int Screen::handleAdminMessage(const meshtastic_AdminMessage *arg)
} // namespace graphics
#else
graphics::Screen::Screen(ScanI2C::DeviceAddress, meshtastic_Config_DisplayConfig_OledType, OLEDDISPLAY_GEOMETRY) {}
-#endif // HAS_SCREEN
\ No newline at end of file
+#endif // HAS_SCREEN
diff --git a/src/mesh/MeshModule.cpp b/src/mesh/MeshModule.cpp
index 9de54ade5..2f2863fa5 100644
--- a/src/mesh/MeshModule.cpp
+++ b/src/mesh/MeshModule.cpp
@@ -4,6 +4,7 @@
#include "NodeDB.h"
#include "configuration.h"
#include "modules/RoutingModule.h"
+#include
#include
std::vector *MeshModule::modules;
@@ -29,7 +30,9 @@ void MeshModule::setup() {}
MeshModule::~MeshModule()
{
- assert(0); // FIXME - remove from list of modules once someone needs this feature
+ auto it = std::find(modules->begin(), modules->end(), this);
+ assert(it != modules->end());
+ modules->erase(it);
}
meshtastic_MeshPacket *MeshModule::allocAckNak(meshtastic_Routing_Error err, NodeNum to, PacketId idFrom, ChannelIndex chIndex,
diff --git a/src/mesh/NodeDB.cpp b/src/mesh/NodeDB.cpp
index 3d01fd0f1..6720c0d3f 100644
--- a/src/mesh/NodeDB.cpp
+++ b/src/mesh/NodeDB.cpp
@@ -1068,8 +1068,11 @@ void NodeDB::loadFromDisk()
// Make sure we load hard coded admin keys even when the configuration file has none.
// Initialize admin_key_count to zero
byte numAdminKeys = 0;
+#if defined(USERPREFS_USE_ADMIN_KEY_0) || defined(USERPREFS_USE_ADMIN_KEY_1) || defined(USERPREFS_USE_ADMIN_KEY_2)
uint16_t sum = 0;
+#endif
#ifdef USERPREFS_USE_ADMIN_KEY_0
+
for (uint8_t b = 0; b < 32; b++) {
sum += config.security.admin_key[0].bytes[b];
}
@@ -1078,8 +1081,6 @@ void NodeDB::loadFromDisk()
LOG_INFO("Admin 0 key zero. Loading hard coded key from user preferences.");
memcpy(config.security.admin_key[0].bytes, userprefs_admin_key_0, 32);
config.security.admin_key[0].size = 32;
- config.security.admin_key_count = numAdminKeys;
- saveToDisk(SEGMENT_CONFIG);
}
#endif
@@ -1093,8 +1094,6 @@ void NodeDB::loadFromDisk()
LOG_INFO("Admin 1 key zero. Loading hard coded key from user preferences.");
memcpy(config.security.admin_key[1].bytes, userprefs_admin_key_1, 32);
config.security.admin_key[1].size = 32;
- config.security.admin_key_count = numAdminKeys;
- saveToDisk(SEGMENT_CONFIG);
}
#endif
@@ -1108,10 +1107,14 @@ void NodeDB::loadFromDisk()
LOG_INFO("Admin 2 key zero. Loading hard coded key from user preferences.");
memcpy(config.security.admin_key[2].bytes, userprefs_admin_key_2, 32);
config.security.admin_key[2].size = 32;
+ }
+#endif
+
+ if (numAdminKeys > 0) {
+ LOG_INFO("Saving %d hard coded admin keys.", numAdminKeys);
config.security.admin_key_count = numAdminKeys;
saveToDisk(SEGMENT_CONFIG);
}
-#endif
state = loadProto(moduleConfigFileName, meshtastic_LocalModuleConfig_size, sizeof(meshtastic_LocalModuleConfig),
&meshtastic_LocalModuleConfig_msg, &moduleConfig);
diff --git a/src/modules/CannedMessageModule.cpp b/src/modules/CannedMessageModule.cpp
index a96fcc080..c20b7b56e 100644
--- a/src/modules/CannedMessageModule.cpp
+++ b/src/modules/CannedMessageModule.cpp
@@ -982,6 +982,7 @@ bool CannedMessageModule::interceptingKeyboardInput()
}
}
+#if !HAS_TFT
void CannedMessageModule::drawFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y)
{
char buffer[50];
@@ -1140,6 +1141,7 @@ void CannedMessageModule::drawFrame(OLEDDisplay *display, OLEDDisplayUiState *st
}
}
}
+#endif //! HAS_TFT
ProcessMessage CannedMessageModule::handleReceived(const meshtastic_MeshPacket &mp)
{
diff --git a/src/modules/Telemetry/Sensor/CGRadSensSensor.cpp b/src/modules/Telemetry/Sensor/CGRadSensSensor.cpp
index 5e69cc22f..ac5df1b81 100644
--- a/src/modules/Telemetry/Sensor/CGRadSensSensor.cpp
+++ b/src/modules/Telemetry/Sensor/CGRadSensSensor.cpp
@@ -41,13 +41,12 @@ void CGRadSensSensor::begin(TwoWire *wire, uint8_t addr)
float CGRadSensSensor::getStaticRadiation()
{
// Read a register, following the same pattern as the RCWL9620Sensor
- uint32_t data;
_wire->beginTransmission(_addr); // Transfer data to addr.
_wire->write(0x06); // Radiation intensity (static period T = 500 sec)
if (_wire->endTransmission() == 0) {
if (_wire->requestFrom(_addr, (uint8_t)3)) {
; // Request 3 bytes
- data = _wire->read();
+ uint32_t data = _wire->read();
data <<= 8;
data |= _wire->read();
data <<= 8;
diff --git a/src/modules/Telemetry/Sensor/IndicatorSensor.cpp b/src/modules/Telemetry/Sensor/IndicatorSensor.cpp
index f3dcd1727..317357137 100644
--- a/src/modules/Telemetry/Sensor/IndicatorSensor.cpp
+++ b/src/modules/Telemetry/Sensor/IndicatorSensor.cpp
@@ -35,8 +35,8 @@ enum sensor_pkt_type {
static int cmd_send(uint8_t cmd, const char *p_data, uint8_t len)
{
- uint8_t buf[32] = {0};
- uint8_t data[32] = {0};
+ uint8_t send_buf[32] = {0};
+ uint8_t send_data[32] = {0};
if (len > 31) {
return -1;
@@ -44,18 +44,18 @@ static int cmd_send(uint8_t cmd, const char *p_data, uint8_t len)
uint8_t index = 1;
- data[0] = cmd;
+ send_data[0] = cmd;
if (len > 0 && p_data != NULL) {
- memcpy(&data[1], p_data, len);
+ memcpy(&send_data[1], p_data, len);
index += len;
}
- cobs_encode_result ret = cobs_encode(buf, sizeof(buf), data, index);
+ cobs_encode_result ret = cobs_encode(send_buf, sizeof(send_buf), send_data, index);
// LOG_DEBUG("cobs TX status:%d, len:%d, type 0x%x", ret.status, ret.out_len, cmd);
if (ret.status == COBS_ENCODE_OK) {
- return uart_write_bytes(SENSOR_PORT_NUM, buf, ret.out_len + 1);
+ return uart_write_bytes(SENSOR_PORT_NUM, send_buf, ret.out_len + 1);
}
return -1;
@@ -96,7 +96,6 @@ bool IndicatorSensor::getMetrics(meshtastic_Telemetry *measurement)
int len = uart_read_bytes(SENSOR_PORT_NUM, buf, (SENSOR_BUF_SIZE - 1), 100 / portTICK_PERIOD_MS);
float value = 0.0;
- uint8_t pkt_type = 0;
uint8_t *p_buf_start = buf;
uint8_t *p_buf_end = buf;
if (len > 0) {
@@ -117,7 +116,7 @@ bool IndicatorSensor::getMetrics(meshtastic_Telemetry *measurement)
if (ret.out_len > 1 && ret.status == COBS_DECODE_OK) {
value = 0.0;
- pkt_type = data[0];
+ uint8_t pkt_type = data[0];
switch (pkt_type) {
case PKT_TYPE_SENSOR_SCD41_CO2: {
memcpy(&value, &data[1], sizeof(value));
diff --git a/src/mqtt/MQTT.cpp b/src/mqtt/MQTT.cpp
index 4260ae201..46fb607b5 100644
--- a/src/mqtt/MQTT.cpp
+++ b/src/mqtt/MQTT.cpp
@@ -2,6 +2,7 @@
#include "MeshService.h"
#include "NodeDB.h"
#include "PowerFSM.h"
+#include "ServiceEnvelope.h"
#include "configuration.h"
#include "main.h"
#include "mesh/Channels.h"
@@ -25,7 +26,6 @@
#endif
#include
#include
-#include
#include
#include
@@ -47,23 +47,6 @@ static uint8_t bytes[meshtastic_MqttClientProxyMessage_size + 30]; // 12 for cha
static bool isMqttServerAddressPrivate = false;
-// meshtastic_ServiceEnvelope that automatically releases dynamically allocated memory when it goes out of scope.
-struct DecodedServiceEnvelope : public meshtastic_ServiceEnvelope {
- DecodedServiceEnvelope() = delete;
- DecodedServiceEnvelope(const uint8_t *payload, size_t length)
- : meshtastic_ServiceEnvelope(meshtastic_ServiceEnvelope_init_default),
- validDecode(pb_decode_from_bytes(payload, length, &meshtastic_ServiceEnvelope_msg, this))
- {
- }
- ~DecodedServiceEnvelope()
- {
- if (validDecode)
- pb_release(&meshtastic_ServiceEnvelope_msg, this);
- }
- // Clients must check that this is true before using.
- const bool validDecode;
-};
-
inline void onReceiveProto(char *topic, byte *payload, size_t length)
{
const DecodedServiceEnvelope e(payload, length);
@@ -299,7 +282,9 @@ void mqttInit()
}
#if HAS_NETWORKING
-MQTT::MQTT() : concurrency::OSThread("mqtt"), pubSub(mqttClient), mqttQueue(MAX_MQTT_QUEUE)
+MQTT::MQTT() : MQTT(std::unique_ptr(new MQTTClient())) {}
+MQTT::MQTT(std::unique_ptr _mqttClient)
+ : concurrency::OSThread("mqtt"), mqttQueue(MAX_MQTT_QUEUE), mqttClient(std::move(_mqttClient)), pubSub(*mqttClient)
#else
MQTT::MQTT() : concurrency::OSThread("mqtt"), mqttQueue(MAX_MQTT_QUEUE)
#endif
@@ -437,13 +422,13 @@ void MQTT::reconnect()
}
} else {
LOG_INFO("Use non-TLS-encrypted session");
- pubSub.setClient(mqttClient);
+ pubSub.setClient(*mqttClient);
}
#else
- pubSub.setClient(mqttClient);
+ pubSub.setClient(*mqttClient);
#endif
#elif HAS_NETWORKING
- pubSub.setClient(mqttClient);
+ pubSub.setClient(*mqttClient);
#endif
std::pair hostAndPort = parseHostAndPort(serverAddr, serverPort);
@@ -461,7 +446,7 @@ void MQTT::reconnect()
enabled = true; // Start running background process again
runASAP = true;
reconnectCount = 0;
- isMqttServerAddressPrivate = isPrivateIpAddress(mqttClient.remoteIP());
+ isMqttServerAddressPrivate = isPrivateIpAddress(mqttClient->remoteIP());
publishNodeInfo();
sendSubscriptions();
diff --git a/src/mqtt/MQTT.h b/src/mqtt/MQTT.h
index cb1fffcc9..cf52ad877 100644
--- a/src/mqtt/MQTT.h
+++ b/src/mqtt/MQTT.h
@@ -22,6 +22,7 @@
#if HAS_NETWORKING
#include
+#include
#endif
#define MAX_MQTT_QUEUE 16
@@ -32,24 +33,7 @@
*/
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
-#if HAS_WIFI
- WiFiClient mqttClient;
-#if !defined(ARCH_PORTDUINO)
-#if (defined(ESP_ARDUINO_VERSION_MAJOR) && ESP_ARDUINO_VERSION_MAJOR < 3) || defined(RPI_PICO)
- WiFiClientSecure wifiSecureClient;
-#endif
-#endif
-#endif
-#if HAS_ETHERNET
- EthernetClient mqttClient;
-#endif
-
public:
-#if HAS_NETWORKING
- PubSubClient pubSub;
-#endif
MQTT();
/**
@@ -93,7 +77,29 @@ class MQTT : private concurrency::OSThread
virtual int32_t runOnce() override;
+#ifndef PIO_UNIT_TESTING
private:
+#endif
+ // supposedly the current version is busted:
+ // http://www.iotsharing.com/2017/08/how-to-use-esp32-mqtts-with-mqtts-mosquitto-broker-tls-ssl.html
+#if HAS_WIFI
+ using MQTTClient = WiFiClient;
+#if !defined(ARCH_PORTDUINO)
+#if (defined(ESP_ARDUINO_VERSION_MAJOR) && ESP_ARDUINO_VERSION_MAJOR < 3) || defined(RPI_PICO)
+ WiFiClientSecure wifiSecureClient;
+#endif
+#endif
+#endif
+#if HAS_ETHERNET
+ using MQTTClient = EthernetClient;
+#endif
+
+#if HAS_NETWORKING
+ std::unique_ptr mqttClient;
+ PubSubClient pubSub;
+ explicit MQTT(std::unique_ptr mqttClient);
+#endif
+
std::string cryptTopic = "/2/e/"; // msh/2/e/CHANNELID/NODEID
std::string jsonTopic = "/2/json/"; // msh/2/json/CHANNELID/NODEID
std::string mapTopic = "/2/map/"; // For protobuf-encoded MapReport messages
diff --git a/src/mqtt/ServiceEnvelope.cpp b/src/mqtt/ServiceEnvelope.cpp
new file mode 100644
index 000000000..ee55f22f6
--- /dev/null
+++ b/src/mqtt/ServiceEnvelope.cpp
@@ -0,0 +1,23 @@
+#include "ServiceEnvelope.h"
+#include "mesh-pb-constants.h"
+#include
+
+DecodedServiceEnvelope::DecodedServiceEnvelope(const uint8_t *payload, size_t length)
+ : meshtastic_ServiceEnvelope(meshtastic_ServiceEnvelope_init_default),
+ validDecode(pb_decode_from_bytes(payload, length, &meshtastic_ServiceEnvelope_msg, this))
+{
+}
+
+DecodedServiceEnvelope::DecodedServiceEnvelope(DecodedServiceEnvelope &&other)
+ : meshtastic_ServiceEnvelope(meshtastic_ServiceEnvelope_init_zero), validDecode(other.validDecode)
+{
+ std::swap(packet, other.packet);
+ std::swap(channel_id, other.channel_id);
+ std::swap(gateway_id, other.gateway_id);
+}
+
+DecodedServiceEnvelope::~DecodedServiceEnvelope()
+{
+ if (validDecode)
+ pb_release(&meshtastic_ServiceEnvelope_msg, this);
+}
\ No newline at end of file
diff --git a/src/mqtt/ServiceEnvelope.h b/src/mqtt/ServiceEnvelope.h
new file mode 100644
index 000000000..6ab0695db
--- /dev/null
+++ b/src/mqtt/ServiceEnvelope.h
@@ -0,0 +1,13 @@
+#pragma once
+
+#include "mesh/generated/meshtastic/mqtt.pb.h"
+
+// meshtastic_ServiceEnvelope that automatically releases dynamically allocated memory when it goes out of scope.
+struct DecodedServiceEnvelope : public meshtastic_ServiceEnvelope {
+ DecodedServiceEnvelope(const uint8_t *payload, size_t length);
+ DecodedServiceEnvelope(DecodedServiceEnvelope &) = delete;
+ DecodedServiceEnvelope(DecodedServiceEnvelope &&);
+ ~DecodedServiceEnvelope();
+ // Clients must check that this is true before using.
+ const bool validDecode;
+};
\ No newline at end of file
diff --git a/src/platform/portduino/PortduinoGlue.cpp b/src/platform/portduino/PortduinoGlue.cpp
index b020f5991..b042510f5 100644
--- a/src/platform/portduino/PortduinoGlue.cpp
+++ b/src/platform/portduino/PortduinoGlue.cpp
@@ -18,7 +18,6 @@
#include
#include
#include