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