diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile
index 4b9f069ab..30af24bd2 100644
--- a/.devcontainer/Dockerfile
+++ b/.devcontainer/Dockerfile
@@ -29,6 +29,7 @@ RUN apt-get update && export DEBIAN_FRONTEND=noninteractive \
gpg \
gnupg2 \
libusb-1.0-0-dev \
+ libuv1-dev \
libi2c-dev \
libxcb-xkb-dev \
libxkbcommon-dev \
diff --git a/.github/actions/setup-native/action.yml b/.github/actions/setup-native/action.yml
index 36c95d943..05f95cd40 100644
--- a/.github/actions/setup-native/action.yml
+++ b/.github/actions/setup-native/action.yml
@@ -11,4 +11,4 @@ runs:
- 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
+ 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 libuv1-dev
diff --git a/Dockerfile b/Dockerfile
index fd1bb6164..733a46325 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -13,7 +13,7 @@ ENV TZ=Etc/UTC
ENV PIP_ROOT_USER_ACTION=ignore
RUN apt-get update && apt-get install --no-install-recommends -y \
wget g++ zip git ca-certificates \
- libgpiod-dev libyaml-cpp-dev libbluetooth-dev libi2c-dev \
+ libgpiod-dev libyaml-cpp-dev libbluetooth-dev libi2c-dev libuv1-dev \
libusb-1.0-0-dev libulfius-dev liborcania-dev libssl-dev pkg-config \
&& apt-get clean && rm -rf /var/lib/apt/lists/* \
&& pip install --no-cache-dir -U platformio \
@@ -38,7 +38,7 @@ ENV TZ=Etc/UTC
USER root
RUN apt-get update && apt-get --no-install-recommends -y install \
- libc-bin libc6 libgpiod2 libyaml-cpp0.7 libi2c0 libulfius2.7 libusb-1.0-0-dev liborcania2.3 libssl3 \
+ libc-bin libc6 libgpiod2 libyaml-cpp0.7 libi2c0 libuv1 libusb-1.0-0-dev liborcania2.3 libulfius2.7 libssl3 \
&& apt-get clean && rm -rf /var/lib/apt/lists/* \
&& mkdir -p /var/lib/meshtasticd \
&& mkdir -p /etc/meshtasticd/config.d \
diff --git a/alpine.Dockerfile b/alpine.Dockerfile
index b6d91a75a..17afc2964 100644
--- a/alpine.Dockerfile
+++ b/alpine.Dockerfile
@@ -9,7 +9,7 @@ FROM python:3.13-alpine3.21 AS builder
ENV PIP_ROOT_USER_ACTION=ignore
RUN apk --no-cache add \
bash g++ libstdc++-dev linux-headers zip git ca-certificates libgpiod-dev yaml-cpp-dev bluez-dev \
- libusb-dev i2c-tools-dev openssl-dev pkgconf argp-standalone \
+ libusb-dev i2c-tools-dev libuv-dev openssl-dev pkgconf argp-standalone \
&& rm -rf /var/cache/apk/* \
&& pip install --no-cache-dir -U platformio \
&& mkdir /tmp/firmware
@@ -32,7 +32,7 @@ FROM alpine:3.21
USER root
RUN apk --no-cache add \
- libstdc++ libgpiod yaml-cpp libusb i2c-tools \
+ libstdc++ libgpiod yaml-cpp libusb i2c-tools libuv \
&& rm -rf /var/cache/apk/* \
&& mkdir -p /var/lib/meshtasticd \
&& mkdir -p /etc/meshtasticd/config.d \
diff --git a/arch/portduino/portduino.ini b/arch/portduino/portduino.ini
index 7ea6a77a2..734a4f91e 100644
--- a/arch/portduino/portduino.ini
+++ b/arch/portduino/portduino.ini
@@ -1,6 +1,6 @@
; The Portduino based 'native' environment. Currently supported on Linux targets with real LoRa hardware (or simulated).
[portduino_base]
-platform = https://github.com/meshtastic/platform-native.git#562d189828f09fbf4c4093b3c0104bae9d8e9ff9
+platform = https://github.com/meshtastic/platform-native.git#df71ed0040e9aad767a002829330965b78fc452a
framework = arduino
build_src_filter =
@@ -34,10 +34,12 @@ build_flags =
-Isrc/platform/portduino
-DRADIOLIB_EEPROM_UNSUPPORTED
-DPORTDUINO_LINUX_HARDWARE
+ -DHAS_UDP_MULTICAST
-lpthread
-lstdc++fs
-lbluetooth
-lgpiod
-lyaml-cpp
-li2c
+ -luv
-std=c++17
diff --git a/debian/control b/debian/control
index b3a8eb58e..693cd6aa5 100644
--- a/debian/control
+++ b/debian/control
@@ -17,6 +17,7 @@ Build-Depends: debhelper-compat (= 13),
libbluetooth-dev,
libusb-1.0-0-dev,
libi2c-dev,
+ libuv1-dev,
openssl,
libssl-dev,
libulfius-dev,
diff --git a/meshtasticd.spec.rpkg b/meshtasticd.spec.rpkg
index 0a0f03557..a09261056 100644
--- a/meshtasticd.spec.rpkg
+++ b/meshtasticd.spec.rpkg
@@ -36,6 +36,7 @@ BuildRequires: pkgconfig(libgpiod)
BuildRequires: pkgconfig(bluez)
BuildRequires: pkgconfig(libusb-1.0)
BuildRequires: libi2c-devel
+BuildRequires: pkgconfig(libuv)
# Web components:
BuildRequires: pkgconfig(openssl)
BuildRequires: pkgconfig(liborcania)
diff --git a/src/main.cpp b/src/main.cpp
index 797d911d1..e9e0c9d4b 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -822,6 +822,11 @@ void setup()
#ifdef HAS_UDP_MULTICAST
LOG_DEBUG("Start multicast thread");
udpThread = new UdpMulticastThread();
+#ifdef ARCH_PORTDUINO
+ // FIXME: portduino does not ever call onNetworkConnected so call it here because I don't know what happen if I call
+ // onNetworkConnected there
+ udpThread->start();
+#endif
#endif
service = new MeshService();
service->init();
diff --git a/src/mesh/udp/UdpMulticastThread.h b/src/mesh/udp/UdpMulticastThread.h
index e5eb28d00..7067cced9 100644
--- a/src/mesh/udp/UdpMulticastThread.h
+++ b/src/mesh/udp/UdpMulticastThread.h
@@ -22,8 +22,13 @@ class UdpMulticastThread : public concurrency::OSThread
void start()
{
- if (udp.listenMulticast(udpIpAddress, UDP_MULTICAST_DEFAUL_PORT)) {
+ if (udp.listenMulticast(udpIpAddress, UDP_MULTICAST_DEFAUL_PORT, 64)) {
+#if !defined(ARCH_PORTDUINO)
+ // FIXME(PORTDUINO): arduino lacks IPAddress::toString()
LOG_DEBUG("UDP Listening on IP: %s", WiFi.localIP().toString().c_str());
+#else
+ LOG_DEBUG("UDP Listening");
+#endif
udp.onPacket([this](AsyncUDPPacket packet) { onReceive(packet); });
} else {
LOG_DEBUG("Failed to listen on UDP");
@@ -33,7 +38,10 @@ class UdpMulticastThread : public concurrency::OSThread
void onReceive(AsyncUDPPacket packet)
{
size_t packetLength = packet.length();
+#ifndef ARCH_PORTDUINO
+ // FIXME(PORTDUINO): arduino lacks IPAddress::toString()
LOG_DEBUG("UDP broadcast from: %s, len=%u", packet.remoteIP().toString().c_str(), packetLength);
+#endif
meshtastic_MeshPacket mp;
LOG_DEBUG("Decoding MeshPacket from UDP len=%u", packetLength);
bool isPacketDecoded = pb_decode_from_bytes(packet.data(), packetLength, &meshtastic_MeshPacket_msg, &mp);
@@ -48,9 +56,14 @@ class UdpMulticastThread : public concurrency::OSThread
bool onSend(const meshtastic_MeshPacket *mp)
{
- if (!mp || WiFi.status() != WL_CONNECTED) {
+ if (!mp || !udp) {
return false;
}
+#if !defined(ARCH_PORTDUINO)
+ if (WiFi.status() != WL_CONNECTED) {
+ return false;
+ }
+#endif
LOG_DEBUG("Broadcasting packet over UDP (id=%u)", mp->id);
uint8_t buffer[meshtastic_MeshPacket_size];
size_t encodedLength = pb_encode_to_bytes(buffer, sizeof(buffer), &meshtastic_MeshPacket_msg, mp);
@@ -70,4 +83,4 @@ class UdpMulticastThread : public concurrency::OSThread
IPAddress udpIpAddress;
AsyncUDP udp;
};
-#endif // ARCH_ESP32
\ No newline at end of file
+#endif // HAS_UDP_MULTICAST
\ No newline at end of file
diff --git a/src/modules/SerialModule.cpp b/src/modules/SerialModule.cpp
index 811d1ec91..34ece2312 100644
--- a/src/modules/SerialModule.cpp
+++ b/src/modules/SerialModule.cpp
@@ -468,81 +468,83 @@ void SerialModule::processWXSerial()
// Extract the current line
char line[meshtastic_Constants_DATA_PAYLOAD_LEN];
memset(line, '\0', sizeof(line));
- memcpy(line, &serialBytes[lineStart], lineEnd - lineStart);
- if (strstr(line, "Wind") != NULL) // we have a wind line
- {
- gotwind = true;
- // Find the positions of "=" signs in the line
- char *windDirPos = strstr(line, "WindDir = ");
- char *windSpeedPos = strstr(line, "WindSpeed = ");
- char *windGustPos = strstr(line, "WindGust = ");
+ if (lineEnd - lineStart < sizeof(line) - 1) {
+ memcpy(line, &serialBytes[lineStart], lineEnd - lineStart);
+ if (strstr(line, "Wind") != NULL) // we have a wind line
+ {
+ gotwind = true;
+ // Find the positions of "=" signs in the line
+ char *windDirPos = strstr(line, "WindDir = ");
+ char *windSpeedPos = strstr(line, "WindSpeed = ");
+ char *windGustPos = strstr(line, "WindGust = ");
- if (windDirPos != NULL) {
- // Extract data after "=" for WindDir
- strcpy(windDir, windDirPos + 15); // Add 15 to skip "WindDir = "
- double radians = GeoCoord::toRadians(strtof(windDir, nullptr));
- dir_sum_sin += sin(radians);
- dir_sum_cos += cos(radians);
- dirCount++;
- } else if (windSpeedPos != NULL) {
- // Extract data after "=" for WindSpeed
- strcpy(windVel, windSpeedPos + 15); // Add 15 to skip "WindSpeed = "
- float newv = strtof(windVel, nullptr);
- velSum += newv;
- velCount++;
- if (newv < lull || lull == -1)
- lull = newv;
+ if (windDirPos != NULL) {
+ // Extract data after "=" for WindDir
+ strlcpy(windDir, windDirPos + 15, sizeof(windDir)); // Add 15 to skip "WindDir = "
+ double radians = GeoCoord::toRadians(strtof(windDir, nullptr));
+ dir_sum_sin += sin(radians);
+ dir_sum_cos += cos(radians);
+ dirCount++;
+ } else if (windSpeedPos != NULL) {
+ // Extract data after "=" for WindSpeed
+ strlcpy(windVel, windSpeedPos + 15, sizeof(windVel)); // Add 15 to skip "WindSpeed = "
+ float newv = strtof(windVel, nullptr);
+ velSum += newv;
+ velCount++;
+ if (newv < lull || lull == -1)
+ lull = newv;
- } else if (windGustPos != NULL) {
- strcpy(windGust, windGustPos + 15); // Add 15 to skip "WindSpeed = "
- float newg = strtof(windGust, nullptr);
- if (newg > gust)
- gust = newg;
- }
+ } else if (windGustPos != NULL) {
+ strlcpy(windGust, windGustPos + 15, sizeof(windGust)); // Add 15 to skip "WindSpeed = "
+ float newg = strtof(windGust, nullptr);
+ if (newg > gust)
+ gust = newg;
+ }
- // these are also voltage data we care about possibly
- } else if (strstr(line, "BatVoltage") != NULL) { // we have a battVoltage line
- char *batVoltagePos = strstr(line, "BatVoltage = ");
- if (batVoltagePos != NULL) {
- strcpy(batVoltage, batVoltagePos + 17); // 18 for ws 80, 17 for ws85
- batVoltageF = strtof(batVoltage, nullptr);
- break; // last possible data we want so break
- }
- } else if (strstr(line, "CapVoltage") != NULL) { // we have a cappVoltage line
- char *capVoltagePos = strstr(line, "CapVoltage = ");
- if (capVoltagePos != NULL) {
- strcpy(capVoltage, capVoltagePos + 17); // 18 for ws 80, 17 for ws85
- capVoltageF = strtof(capVoltage, nullptr);
- }
- // GXTS04Temp = 24.4
- } else if (strstr(line, "GXTS04Temp") != NULL) { // we have a temperature line
- char *tempPos = strstr(line, "GXTS04Temp = ");
- if (tempPos != NULL) {
- strcpy(temperature, tempPos + 15); // 15 spaces for ws85
- temperatureF = strtof(temperature, nullptr);
- }
+ // these are also voltage data we care about possibly
+ } else if (strstr(line, "BatVoltage") != NULL) { // we have a battVoltage line
+ char *batVoltagePos = strstr(line, "BatVoltage = ");
+ if (batVoltagePos != NULL) {
+ strlcpy(batVoltage, batVoltagePos + 17, sizeof(batVoltage)); // 18 for ws 80, 17 for ws85
+ batVoltageF = strtof(batVoltage, nullptr);
+ break; // last possible data we want so break
+ }
+ } else if (strstr(line, "CapVoltage") != NULL) { // we have a cappVoltage line
+ char *capVoltagePos = strstr(line, "CapVoltage = ");
+ if (capVoltagePos != NULL) {
+ strlcpy(capVoltage, capVoltagePos + 17, sizeof(capVoltage)); // 18 for ws 80, 17 for ws85
+ capVoltageF = strtof(capVoltage, nullptr);
+ }
+ // GXTS04Temp = 24.4
+ } else if (strstr(line, "GXTS04Temp") != NULL) { // we have a temperature line
+ char *tempPos = strstr(line, "GXTS04Temp = ");
+ if (tempPos != NULL) {
+ strlcpy(temperature, tempPos + 15, sizeof(temperature)); // 15 spaces for ws85
+ temperatureF = strtof(temperature, nullptr);
+ }
- } else if (strstr(line, "RainIntSum") != NULL) { // we have a rainsum line
- // LOG_INFO(line);
- char *pos = strstr(line, "RainIntSum = ");
- if (pos != NULL) {
- strcpy(rainStr, pos + 17); // 17 spaces for ws85
- rainSum = int(strtof(rainStr, nullptr));
- }
-
- } else if (strstr(line, "Rain") != NULL) { // we have a rain line
- if (strstr(line, "WaveRain") == NULL) { // skip WaveRain lines though.
+ } else if (strstr(line, "RainIntSum") != NULL) { // we have a rainsum line
// LOG_INFO(line);
- char *pos = strstr(line, "Rain = ");
+ char *pos = strstr(line, "RainIntSum = ");
if (pos != NULL) {
- strcpy(rainStr, pos + 17); // 17 spaces for ws85
- rain = strtof(rainStr, nullptr);
+ strlcpy(rainStr, pos + 17, sizeof(rainStr)); // 17 spaces for ws85
+ rainSum = int(strtof(rainStr, nullptr));
+ }
+
+ } else if (strstr(line, "Rain") != NULL) { // we have a rain line
+ if (strstr(line, "WaveRain") == NULL) { // skip WaveRain lines though.
+ // LOG_INFO(line);
+ char *pos = strstr(line, "Rain = ");
+ if (pos != NULL) {
+ strlcpy(rainStr, pos + 17, sizeof(rainStr)); // 17 spaces for ws85
+ rain = strtof(rainStr, nullptr);
+ }
}
}
- }
- // Update lineStart for the next line
- lineStart = lineEnd + 1;
+ // Update lineStart for the next line
+ lineStart = lineEnd + 1;
+ }
}
}
break;
diff --git a/variants/rpipico2w/platformio.ini b/variants/rpipico2w/platformio.ini
index 351774221..282be1a42 100644
--- a/variants/rpipico2w/platformio.ini
+++ b/variants/rpipico2w/platformio.ini
@@ -23,8 +23,9 @@ build_flags = ${rp2350_base.build_flags}
-DHAS_WIFI=1
-L "${platformio.libdeps_dir}/${this.__env__}/bsec2/src/cortex-m33"
-fexceptions # for exception handling in MQTT
+ -DHAS_UDP_MULTICAST=1
build_src_filter = ${rp2350_base.build_src_filter} +
lib_deps =
${rp2350_base.lib_deps}
${networking_base.lib_deps}
-debug_build_flags = ${rp2350_base.build_flags}, -g
\ No newline at end of file
+debug_build_flags = ${rp2350_base.build_flags}, -g
diff --git a/variants/rpipicow/platformio.ini b/variants/rpipicow/platformio.ini
index 7a43ece3b..4b714434a 100644
--- a/variants/rpipicow/platformio.ini
+++ b/variants/rpipicow/platformio.ini
@@ -10,9 +10,10 @@ build_flags = ${rp2040_base.build_flags}
-DHW_SPI1_DEVICE
-L "${platformio.libdeps_dir}/${this.__env__}/bsec2/src/cortex-m0plus"
-fexceptions # for exception handling in MQTT
+ -DHAS_UDP_MULTICAST=1
build_src_filter = ${rp2040_base.build_src_filter} +
lib_deps =
${rp2040_base.lib_deps}
${networking_base.lib_deps}
debug_build_flags = ${rp2040_base.build_flags}, -g
-debug_tool = cmsis-dap ; for e.g. Picotool
\ No newline at end of file
+debug_tool = cmsis-dap ; for e.g. Picotool