Compare commits

..

6 Commits

Author SHA1 Message Date
Ben Meadors
700397d3ed ugh 2024-08-27 07:32:05 -05:00
Ben Meadors
cd65497ac4 Update to move setup to its own module 2024-08-27 07:02:49 -05:00
Ben Meadors
3c90a65a66 WIP 2024-08-27 06:24:36 -05:00
Ben Meadors
9e8f0814ab Stuff 2024-08-26 16:34:28 -05:00
Ben Meadors
36cadd03ee wip 2024-08-25 15:27:59 -05:00
Ben Meadors
15ee827efd Hello world 2024-08-25 13:41:58 -05:00
1415 changed files with 18633 additions and 159144 deletions

View File

@@ -1,52 +0,0 @@
# This container is used to build Meshtastic with the libraries required by the fuzzer.
# ClusterFuzzLite starts the container, runs the build.sh script, and then exits.
# As this is not a long running service, health-checks are not required. ClusterFuzzLite
# also only works if the user remains unchanged from the base image (it expects to run
# as root).
# trunk-ignore-all(trivy/DS026): No healthcheck is needed for this builder container
# trunk-ignore-all(checkov/CKV_DOCKER_2): No healthcheck is needed for this builder container
# trunk-ignore-all(checkov/CKV_DOCKER_3): We must run as root for this container
# trunk-ignore-all(trivy/DS002): We must run as root for this container
# trunk-ignore-all(checkov/CKV_DOCKER_8): We must run as root for this container
# trunk-ignore-all(hadolint/DL3002): We must run as root for this container
FROM gcr.io/oss-fuzz-base/base-builder:v1
ENV PIP_ROOT_USER_ACTION=ignore
# trunk-ignore(hadolint/DL3008): apt packages are not pinned.
# trunk-ignore(terrascan/AC_DOCKER_0002): apt packages are not pinned.
RUN apt-get update && apt-get install --no-install-recommends -y \
cmake git zip libgpiod-dev libbluetooth-dev libi2c-dev \
libunistring-dev libmicrohttpd-dev libgnutls28-dev libgcrypt20-dev \
libusb-1.0-0-dev libssl-dev pkg-config && \
apt-get clean && rm -rf /var/lib/apt/lists/* && \
pip install --no-cache-dir -U \
platformio==6.1.16 \
grpcio-tools==1.68.1 \
meshtastic==2.5.9
# Ugly hack to avoid clang detecting a conflict between the math "log" function and the "log" function in framework-portduino/cores/portduino/logging.h
RUN sed -i -e 's/__MATHCALL_VEC (log,, (_Mdouble_ __x));//' /usr/include/x86_64-linux-gnu/bits/mathcalls.h
# A few dependencies are too old on the base-builder image. More recent versions are built from source.
WORKDIR $SRC
RUN git config --global advice.detachedHead false && \
git clone --depth 1 --branch 0.8.0 https://github.com/jbeder/yaml-cpp.git && \
git clone --depth 1 --branch v2.3.3 https://github.com/babelouest/orcania.git && \
git clone --depth 1 --branch v1.4.20 https://github.com/babelouest/yder.git && \
git clone --depth 1 --branch v2.7.15 https://github.com/babelouest/ulfius.git
COPY ./.clusterfuzzlite/build.sh $SRC/
WORKDIR $SRC/firmware
COPY . $SRC/firmware/
# https://docs.platformio.org/en/latest/envvars.html
ENV PLATFORMIO_CORE_DIR=$SRC/pio/core \
PLATFORMIO_LIBDEPS_DIR=$SRC/pio/libdeps \
PLATFORMIO_PACKAGES_DIR=$SRC/pio/packages \
PLATFORMIO_SETTING_ENABLE_CACHE=No \
PIO_ENV=buildroot
RUN platformio pkg install --environment $PIO_ENV

View File

@@ -1,59 +0,0 @@
# ClusterFuzzLite for Meshtastic
This directory contains the fuzzer implementation for Meshtastic using the ClusterFuzzLite framework.
See the [ClusterFuzzLite documentation](https://google.github.io/clusterfuzzlite/) for more details.
## Running locally
ClusterFuzzLite uses the OSS-Fuzz toolchain. To build the fuzzer manually, first grab a copy of OSS-Fuzz.
```shell
git clone https://github.com/google/oss-fuzz.git
cd oss-fuzz
```
To build the fuzzer, run:
```shell
python3 infra/helper.py build_image --external $PATH_TO_MESHTASTIC_FIRMWARE_DIRECTORY
python3 infra/helper.py build_fuzzers --external $PATH_TO_MESHTASTIC_FIRMWARE_DIRECTORY --sanitizer address
```
To run the fuzzer, run:
```shell
python3 infra/helper.py run_fuzzer --external --corpus-dir=<path-to-temp-corpus-dir> $PATH_TO_MESHTASTIC_FIRMWARE_DIRECTORY router_fuzzer
```
More background on these commands can be found in the
[ClusterFuzzLite documentation](https://google.github.io/clusterfuzzlite/build-integration/#testing-locally).
## router_fuzzer.cpp
This fuzzer submits MeshPacket protos to the `Router::enqueueReceivedMessage` method. It takes the binary
data from the fuzzer and decodes that data to a MeshPacket using nanopb. A few fields in
the MeshPacket are modified by the fuzzer.
- If the `to` field is 0, it will be replaced with the NodeID of the running node.
- If the `from` field is 0, it will be replaced with the NodeID of the running node.
- If the `id` field is 0, it will be replaced with an incrementing counter value.
- If the `pki_encrypted` field is true, the `public_key` field will be populated with the first admin key.
The `router_fuzzer_seed_corpus.py` file contains a list of MeshPackets. It is run from inside build.sh and
writes the binary MeshPacket protos to files. These files are use used by the fuzzer as its initial seed data,
helping the fuzzer to start off with a few known inputs.
### Interpreting a fuzzer crash
If the fuzzer crashes, it'll write the input bytes used for the test case to a file and notify about the
location of that file. The contents of the file are a binary serialized MeshPacket protobuf. The following
snippet of Python code can be used to parse the file into a human readable form.
```python
from meshtastic.protobuf import mesh_pb2
mesh_pb2.MeshPacket.FromString(open("crash-XXXX-file", "rb").read())
```
Consider adding any such crash results to the `router_fuzzer_seed_corpus.py` file to ensure there a isn't
a future regression for that crash test case.

View File

@@ -1,71 +0,0 @@
#!/bin/bash -eu
# Build Meshtastic and a few needed dependencies using clang++
# and the OSS-Fuzz required build flags.
env
cd "$SRC"
NPROC=$(nproc || echo 1)
LDFLAGS=-lpthread cmake -S "$SRC/yaml-cpp" -B "$WORK/yaml-cpp/$SANITIZER" \
-DBUILD_SHARED_LIBS=OFF
cmake --build "$WORK/yaml-cpp/$SANITIZER" -j "$NPROC"
cmake --install "$WORK/yaml-cpp/$SANITIZER" --prefix /usr
cmake -S "$SRC/orcania" -B "$WORK/orcania/$SANITIZER" \
-DBUILD_STATIC=ON
cmake --build "$WORK/orcania/$SANITIZER" -j "$NPROC"
cmake --install "$WORK/orcania/$SANITIZER" --prefix /usr
cmake -S "$SRC/yder" -B "$WORK/yder/$SANITIZER" \
-DBUILD_STATIC=ON -DWITH_JOURNALD=OFF
cmake --build "$WORK/yder/$SANITIZER" -j "$NPROC"
cmake --install "$WORK/yder/$SANITIZER" --prefix /usr
cmake -S "$SRC/ulfius" -B "$WORK/ulfius/$SANITIZER" \
-DBUILD_STATIC=ON -DWITH_JANSSON=OFF -DWITH_CURL=OFF -DWITH_WEBSOCKET=OFF
cmake --build "$WORK/ulfius/$SANITIZER" -j "$NPROC"
cmake --install "$WORK/ulfius/$SANITIZER" --prefix /usr
cd "$SRC/firmware"
PLATFORMIO_EXTRA_SCRIPTS=$(echo -e "pre:.clusterfuzzlite/platformio-clusterfuzzlite-pre.py\npost:.clusterfuzzlite/platformio-clusterfuzzlite-post.py")
STATIC_LIBS=$(pkg-config --libs --static libulfius openssl libgpiod yaml-cpp bluez --silence-errors)
export PLATFORMIO_EXTRA_SCRIPTS
export STATIC_LIBS
export PLATFORMIO_WORKSPACE_DIR="$WORK/pio/$SANITIZER"
export TARGET_CC=$CC
export TARGET_CXX=$CXX
export TARGET_LD=$CXX
export TARGET_AR=llvm-ar
export TARGET_AS=llvm-as
export TARGET_OBJCOPY=llvm-objcopy
export TARGET_RANLIB=llvm-ranlib
mkdir -p "$OUT/lib"
cp .clusterfuzzlite/*_fuzzer.options "$OUT/"
for f in .clusterfuzzlite/*_fuzzer.cpp; do
fuzzer=$(basename "$f" .cpp)
cp -f "$f" src/fuzzer.cpp
pio run -vvv --environment "$PIO_ENV"
program="$PLATFORMIO_WORKSPACE_DIR/build/$PIO_ENV/meshtasticd"
cp "$program" "$OUT/$fuzzer"
# Copy shared libraries used by the fuzzer.
read -d '' -ra shared_libs < <(ldd "$program" | sed -n 's/[^=]\+=> \([^ ]\+\).*/\1/p') || true
cp -f "${shared_libs[@]}" "$OUT/lib/"
# Build the initial fuzzer seed corpus.
corpus_name="${fuzzer}_seed_corpus"
corpus_generator="$PWD/.clusterfuzzlite/${corpus_name}.py"
if [[ -f $corpus_generator ]]; then
mkdir "$corpus_name"
pushd "$corpus_name"
python3 "$corpus_generator"
popd
zip -D "$OUT/${corpus_name}.zip" "$corpus_name"/*
fi
done

View File

@@ -1,35 +0,0 @@
"""PlatformIO build script (post: runs after other Meshtastic scripts)."""
import os
import shlex
from SCons.Script import DefaultEnvironment
env = DefaultEnvironment()
# Remove any static libraries from the LIBS environment. Static libraries are
# handled in platformio-clusterfuzzlite-pre.py.
static_libs = set(lib[2:] for lib in shlex.split(os.getenv("STATIC_LIBS")))
env.Replace(
LIBS=[
lib for lib in env["LIBS"] if not (isinstance(lib, str) and lib in static_libs)
],
)
# FrameworkArduino/portduino/main.cpp contains the "main" function the binary.
# The fuzzing framework also provides a "main" function and needs to be run
# before Meshtastic is started. We rename the "main" function for Meshtastic to
# "portduino_main" here so that it can be called inside the fuzzer.
env.AddPostAction(
"$BUILD_DIR/FrameworkArduino/portduino/main.cpp.o",
env.VerboseAction(
" ".join(
[
"$OBJCOPY",
"--redefine-sym=main=portduino_main",
"$BUILD_DIR/FrameworkArduino/portduino/main.cpp.o",
]
),
"Renaming main symbol to portduino_main",
),
)

View File

@@ -1,52 +0,0 @@
"""PlatformIO build script (pre: runs before other Meshtastic scripts).
ClusterFuzzLite executes in a different container from the build. During the build,
attempt to link statically to as many dependencies as possible. For dependencies that
do not have static libraries, the shared library files are copied to the output
directory by the build.sh script.
"""
import glob
import os
import shlex
from SCons.Script import DefaultEnvironment, Literal
env = DefaultEnvironment()
cxxflags = shlex.split(os.getenv("CXXFLAGS"))
sanitizer_flags = shlex.split(os.getenv("SANITIZER_FLAGS"))
lib_fuzzing_engine = shlex.split(os.getenv("LIB_FUZZING_ENGINE"))
statics = glob.glob("/usr/lib/lib*.a") + glob.glob("/usr/lib/*/lib*.a")
no_static = set(("-ldl",))
def replaceStatic(lib):
"""Replace -l<libname> with the static .a file for the library."""
if not lib.startswith("-l") or lib in no_static:
return lib
static_name = f"/lib{lib[2:]}.a"
static = [s for s in statics if s.endswith(static_name)]
if len(static) == 1:
return static[0]
return lib
# Setup the environment for building with Clang and the OSS-Fuzz required build flags.
env.Append(
CFLAGS=os.getenv("CFLAGS"),
CXXFLAGS=cxxflags,
LIBSOURCE_DIRS=["/usr/lib/x86_64-linux-gnu"],
LINKFLAGS=cxxflags
+ sanitizer_flags
+ lib_fuzzing_engine
+ ["-stdlib=libc++", "-std=c++17"],
_LIBFLAGS=[replaceStatic(s) for s in shlex.split(os.getenv("STATIC_LIBS"))]
+ [
"/usr/lib/x86_64-linux-gnu/libunistring.a", # Needs to be at the end.
# Find the shared libraries in a subdirectory named lib
# within the same directory as the binary.
Literal("-Wl,-rpath,$ORIGIN/lib"),
"-Wl,-z,origin",
],
)

View File

@@ -1 +0,0 @@
language: c++

View File

@@ -1,206 +0,0 @@
// Fuzzer implementation that sends MeshPackets to Router::enqueueReceivedMessage.
#include <condition_variable>
#include <cstdlib>
#include <mutex>
#include <pb_decode.h>
#include <stdexcept>
#include <string>
#include <thread>
#include "PortduinoGPIO.h"
#include "PortduinoGlue.h"
#include "PowerFSM.h"
#include "mesh/MeshTypes.h"
#include "mesh/NodeDB.h"
#include "mesh/Router.h"
#include "mesh/TypeConversions.h"
#include "mesh/mesh-pb-constants.h"
namespace
{
constexpr uint32_t nodeId = 0x12345678;
// Set to true when lateInitVariant finishes. Used to ensure lateInitVariant was called during startup.
bool hasBeenConfigured = false;
// These are used to block the Arduino loop() function until a fuzzer input is ready. This is
// an optimization that prevents a sleep from happening before the loop is run. The Arduino loop
// function calls loopCanSleep() before sleeping. loopCanSleep is implemented here in the fuzzer
// and blocks until runLoopOnce() is called to signal for the loop to run.
bool fuzzerRunning = false; // Set to true once LLVMFuzzerTestOneInput has started running.
bool loopCanRun = true; // The main Arduino loop() can run when this is true.
bool loopIsWaiting = false; // The main Arduino loop() is waiting to be signaled to run.
bool loopShouldExit = false; // Indicates that the main Arduino thread should exit by throwing ShouldExitException.
std::mutex loopLock;
std::condition_variable loopCV;
std::thread meshtasticThread;
// This exception is thrown when the portuino main thread should exit.
class ShouldExitException : public std::runtime_error
{
public:
using std::runtime_error::runtime_error;
};
// Start the loop for one test case and wait till the loop has completed. This ensures fuzz
// test cases do not overlap with one another. This helps the fuzzer attribute a crash to the
// single, currently running, test case.
void runLoopOnce()
{
realHardware = true; // Avoids delay(100) within portduino/main.cpp
std::unique_lock<std::mutex> lck(loopLock);
fuzzerRunning = true;
loopCanRun = true;
loopCV.notify_one();
loopCV.wait(lck, [] { return !loopCanRun && loopIsWaiting; });
}
} // namespace
// Called in the main Arduino loop function to determine if the loop can delay/sleep before running again.
// We use this as a way to block the loop from sleeping and to start the loop function immediately when a
// fuzzer input is ready.
bool loopCanSleep()
{
std::unique_lock<std::mutex> lck(loopLock);
loopIsWaiting = true;
loopCV.notify_one();
loopCV.wait(lck, [] { return loopCanRun || loopShouldExit; });
loopIsWaiting = false;
if (loopShouldExit)
throw ShouldExitException("exit");
if (!fuzzerRunning)
return true; // The loop can sleep before the fuzzer starts.
loopCanRun = false; // Only run the loop once before waiting again.
return false;
}
// Called just prior to starting Meshtastic. Allows for setting config values before startup.
void lateInitVariant()
{
portduino_config.logoutputlevel = level_error;
channelFile.channels[0] = meshtastic_Channel{
.has_settings = true,
.settings =
meshtastic_ChannelSettings{
.psk = {.size = 1, .bytes = {/*defaultpskIndex=*/1}},
.name = "LongFast",
.uplink_enabled = true,
.has_module_settings = true,
.module_settings = {.position_precision = 16},
},
.role = meshtastic_Channel_Role_PRIMARY,
};
config.security.admin_key[0] = {
.size = 32,
.bytes = {0xcd, 0xc0, 0xb4, 0x3c, 0x53, 0x24, 0xdf, 0x13, 0xca, 0x5a, 0xa6, 0x0c, 0x0d, 0xec, 0x85, 0x5a,
0x4c, 0xf6, 0x1a, 0x96, 0x04, 0x1a, 0x3e, 0xfc, 0xbb, 0x8e, 0x33, 0x71, 0xe5, 0xfc, 0xff, 0x3c},
};
config.security.admin_key_count = 1;
config.lora.region = meshtastic_Config_LoRaConfig_RegionCode_US;
moduleConfig.has_mqtt = true;
moduleConfig.mqtt = meshtastic_ModuleConfig_MQTTConfig{
.enabled = true,
.proxy_to_client_enabled = true,
};
moduleConfig.has_store_forward = true;
moduleConfig.store_forward = meshtastic_ModuleConfig_StoreForwardConfig{
.enabled = true,
.history_return_max = 4,
.history_return_window = 600,
.is_server = true,
};
meshtastic_Position fixedGPS = meshtastic_Position{
.has_latitude_i = true,
.latitude_i = static_cast<uint32_t>(1 * 1e7),
.has_longitude_i = true,
.longitude_i = static_cast<uint32_t>(3 * 1e7),
.has_altitude = true,
.altitude = 64,
.location_source = meshtastic_Position_LocSource_LOC_MANUAL,
};
nodeDB->setLocalPosition(fixedGPS);
config.has_position = true;
config.position.fixed_position = true;
meshtastic_NodeInfoLite *info = nodeDB->getMeshNode(nodeDB->getNodeNum());
info->has_position = true;
info->position = TypeConversions::ConvertToPositionLite(fixedGPS);
hasBeenConfigured = true;
}
extern "C" {
int portduino_main(int argc, char **argv); // Renamed "main" function from Meshtastic binary.
// Start Meshtastic in a thread and wait till it has reached the ON state.
int LLVMFuzzerInitialize(int *argc, char ***argv)
{
portduino_config.maxtophone = 5;
meshtasticThread = std::thread([program = *argv[0]]() {
char nodeIdStr[12];
strcpy(nodeIdStr, std::to_string(nodeId).c_str());
int argc = 7;
char *argv[] = {program, "-d", "/tmp/meshtastic", "-h", nodeIdStr, "-p", "0", nullptr};
try {
portduino_main(argc, argv);
} catch (const ShouldExitException &) {
}
});
std::atexit([] {
{
const std::lock_guard<std::mutex> lck(loopLock);
loopShouldExit = true;
loopCV.notify_one();
}
meshtasticThread.join();
});
// Wait for startup.
for (int i = 1; i < 20; ++i) {
if (powerFSM.getState() == &stateON) {
assert(hasBeenConfigured);
assert(router);
assert(nodeDB);
return 0;
}
std::this_thread::sleep_for(std::chrono::seconds(1));
}
return 1;
}
// This is the main entrypoint for the fuzzer (the fuzz target). The fuzzer will provide an array of bytes to be
// interpreted by this method. To keep things simple, the bytes are interpreted as a binary serialized MeshPacket
// proto. Any crashes discovered by the fuzzer will be written to a file. Unserialize that file to print the MeshPacket
// that caused the failure.
//
// This guide provides best practices for writing a fuzzer target.
// https://github.com/google/fuzzing/blob/master/docs/good-fuzz-target.md
int LLVMFuzzerTestOneInput(const uint8_t *data, size_t length)
{
meshtastic_MeshPacket p = meshtastic_MeshPacket_init_default;
pb_istream_t stream = pb_istream_from_buffer(data, length);
// Ignore any inputs that fail to decode or have fields set that are not transmitted over LoRa.
if (!pb_decode(&stream, &meshtastic_MeshPacket_msg, &p) || p.rx_time || p.rx_snr || p.priority || p.rx_rssi || p.delayed ||
p.public_key.size || p.next_hop || p.relay_node || p.tx_after)
return -1; // Reject: The input will not be added to the corpus.
if (p.which_payload_variant == meshtastic_MeshPacket_decoded_tag) {
meshtastic_Data d;
stream = pb_istream_from_buffer(p.decoded.payload.bytes, p.decoded.payload.size);
if (!pb_decode(&stream, &meshtastic_Data_msg, &d))
return -1; // Reject: The input will not be added to the corpus.
}
// Provide default values for a few fields so the fuzzer doesn't need to guess them.
if (p.from == 0)
p.from = nodeDB->getNodeNum();
if (p.to == 0)
p.to = nodeDB->getNodeNum();
static uint32_t packetId = 0;
if (p.id == 0)
p.id == ++packetId;
if (p.pki_encrypted && config.security.admin_key_count)
memcpy(&p.public_key, &config.security.admin_key[0], sizeof(p.public_key));
router->enqueueReceivedMessage(packetPool.allocCopy(p));
runLoopOnce();
return 0; // Accept: The input may be added to the corpus.
}
}

View File

@@ -1,2 +0,0 @@
[libfuzzer]
max_len=256

View File

@@ -1,168 +0,0 @@
"""Generate an initial set of MeshPackets.
The fuzzer uses these MeshPackets as an initial seed of test candidates.
It's also good to add any previously discovered crash test cases to this list
to avoid future regressions.
If left unset, the following values will be automatically set by the fuzzer.
- to: automatically set to the running node's NodeID
- from: automatically set to the running node's NodeID
- id: automatically set to the value of an incrementing counter
Additionally, if `pki_encrypted` is populated in the packet, the first admin key
will be copied into the `public_key` field.
"""
import base64
from meshtastic import BROADCAST_NUM
from meshtastic.protobuf import (
admin_pb2,
atak_pb2,
mesh_pb2,
portnums_pb2,
telemetry_pb2,
)
def From(node: int = 9):
"""Return a dict suitable for **kwargs for populating the 'from' field.
'from' is a reserved keyword in Python. It can't be used directly as an
argument to the MeshPacket constructor. Rather **From() can be used as
the final argument to provide the from node as a **kwarg.
Defaults to 9 if no value is provided.
"""
return {"from": node}
packets = (
(
"position",
mesh_pb2.MeshPacket(
decoded=mesh_pb2.Data(
portnum=portnums_pb2.PortNum.POSITION_APP,
payload=mesh_pb2.Position(
latitude_i=int(1 * 1e7),
longitude_i=int(2 * 1e7),
altitude=5,
precision_bits=32,
).SerializeToString(),
),
to=BROADCAST_NUM,
**From(),
),
),
(
"telemetry",
mesh_pb2.MeshPacket(
decoded=mesh_pb2.Data(
portnum=portnums_pb2.PortNum.TELEMETRY_APP,
payload=telemetry_pb2.Telemetry(
time=1736192207,
device_metrics=telemetry_pb2.DeviceMetrics(
battery_level=101,
channel_utilization=8,
air_util_tx=2,
uptime_seconds=42,
),
).SerializeToString(),
),
to=BROADCAST_NUM,
**From(),
),
),
(
"text",
mesh_pb2.MeshPacket(
decoded=mesh_pb2.Data(
portnum=portnums_pb2.PortNum.TEXT_MESSAGE_APP,
payload=b"Hello world",
),
to=BROADCAST_NUM,
**From(),
),
),
(
"user",
mesh_pb2.MeshPacket(
decoded=mesh_pb2.Data(
portnum=portnums_pb2.PortNum.NODEINFO_APP,
payload=mesh_pb2.User(
id="!00000009",
long_name="Node 9",
short_name="N9",
macaddr=b"\x00\x00\x00\x00\x00\x09",
hw_model=mesh_pb2.HardwareModel.RAK4631,
public_key=base64.b64decode(
"L0ih/6F41itofdE8mYyHk1SdfOJ/QRM1KQ+pO4vEEjQ="
),
).SerializeToString(),
),
**From(),
),
),
(
"traceroute",
mesh_pb2.MeshPacket(
decoded=mesh_pb2.Data(
portnum=portnums_pb2.PortNum.TRACEROUTE_APP,
payload=mesh_pb2.RouteDiscovery(
route=[10],
).SerializeToString(),
),
**From(),
),
),
(
"routing",
mesh_pb2.MeshPacket(
decoded=mesh_pb2.Data(
portnum=portnums_pb2.PortNum.ROUTING_APP,
payload=mesh_pb2.Routing(
error_reason=mesh_pb2.Routing.NO_RESPONSE,
).SerializeToString(),
),
**From(),
),
),
(
"admin",
mesh_pb2.MeshPacket(
decoded=mesh_pb2.Data(
portnum=portnums_pb2.PortNum.ADMIN_APP,
payload=admin_pb2.AdminMessage(
get_owner_request=True,
).SerializeToString(),
),
pki_encrypted=True,
**From(),
),
),
(
"atak",
mesh_pb2.MeshPacket(
decoded=mesh_pb2.Data(
portnum=portnums_pb2.PortNum.ATAK_PLUGIN,
payload=atak_pb2.TAKPacket(
is_compressed=True,
# Note, the strings are not valid for a compressed message, but will
# give the fuzzer a starting point.
contact=atak_pb2.Contact(
callsign="callsign", device_callsign="device_callsign"
),
chat=atak_pb2.GeoChat(
message="message", to="to", to_callsign="to_callsign"
),
).SerializeToString(),
),
**From(),
),
),
)
for name, packet in packets:
with open(f"{name}.MeshPacket", "wb") as f:
f.write(packet.SerializeToString())

View File

@@ -1,183 +0,0 @@
# Copyright (c) 2014-present PlatformIO <contact@platformio.org>
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#####################################################################################
#
# INSTALLATION
#
# Please visit > https://docs.platformio.org/en/latest/core/installation/udev-rules.html
#
#####################################################################################
#
# Boards
#
# CP210X USB UART
ATTRS{idVendor}=="10c4", ATTRS{idProduct}=="ea[67][013]", MODE:="0666", ENV{ID_MM_DEVICE_IGNORE}="1", ENV{ID_MM_PORT_IGNORE}="1"
ATTRS{idVendor}=="10c4", ATTRS{idProduct}=="80a9", MODE:="0666", ENV{ID_MM_DEVICE_IGNORE}="1", ENV{ID_MM_PORT_IGNORE}="1"
# FT231XS USB UART
ATTRS{idVendor}=="0403", ATTRS{idProduct}=="6015", MODE:="0666", ENV{ID_MM_DEVICE_IGNORE}="1", ENV{ID_MM_PORT_IGNORE}="1"
# Prolific Technology, Inc. PL2303 Serial Port
ATTRS{idVendor}=="067b", ATTRS{idProduct}=="2303", MODE:="0666", ENV{ID_MM_DEVICE_IGNORE}="1", ENV{ID_MM_PORT_IGNORE}="1"
# QinHeng Electronics HL-340 USB-Serial adapter
ATTRS{idVendor}=="1a86", ATTRS{idProduct}=="7523", MODE:="0666", ENV{ID_MM_DEVICE_IGNORE}="1", ENV{ID_MM_PORT_IGNORE}="1"
# QinHeng Electronics CH343 USB-Serial adapter
ATTRS{idVendor}=="1a86", ATTRS{idProduct}=="55d3", MODE:="0666", ENV{ID_MM_DEVICE_IGNORE}="1", ENV{ID_MM_PORT_IGNORE}="1"
# QinHeng Electronics CH9102 USB-Serial adapter
ATTRS{idVendor}=="1a86", ATTRS{idProduct}=="55d4", MODE:="0666", ENV{ID_MM_DEVICE_IGNORE}="1", ENV{ID_MM_PORT_IGNORE}="1"
# Arduino boards
ATTRS{idVendor}=="2341", ATTRS{idProduct}=="[08][023]*", MODE:="0666", ENV{ID_MM_DEVICE_IGNORE}="1", ENV{ID_MM_PORT_IGNORE}="1"
ATTRS{idVendor}=="2a03", ATTRS{idProduct}=="[08][02]*", MODE:="0666", ENV{ID_MM_DEVICE_IGNORE}="1", ENV{ID_MM_PORT_IGNORE}="1"
# Arduino SAM-BA
ATTRS{idVendor}=="03eb", ATTRS{idProduct}=="6124", MODE:="0666", ENV{ID_MM_DEVICE_IGNORE}="1", ENV{MTP_NO_PROBE}="1"
# Digistump boards
ATTRS{idVendor}=="16d0", ATTRS{idProduct}=="0753", MODE:="0666", ENV{ID_MM_DEVICE_IGNORE}="1", ENV{ID_MM_PORT_IGNORE}="1"
# Maple with DFU
ATTRS{idVendor}=="1eaf", ATTRS{idProduct}=="000[34]", MODE:="0666", ENV{ID_MM_DEVICE_IGNORE}="1", ENV{ID_MM_PORT_IGNORE}="1"
# USBtiny
ATTRS{idProduct}=="0c9f", ATTRS{idVendor}=="1781", MODE:="0666", ENV{ID_MM_DEVICE_IGNORE}="1", ENV{ID_MM_PORT_IGNORE}="1"
# USBasp V2.0
ATTRS{idVendor}=="16c0", ATTRS{idProduct}=="05dc", MODE:="0666", ENV{ID_MM_DEVICE_IGNORE}="1", ENV{ID_MM_PORT_IGNORE}="1"
# Teensy boards
ATTRS{idVendor}=="16c0", ATTRS{idProduct}=="04[789B]?", ENV{ID_MM_DEVICE_IGNORE}="1", ENV{ID_MM_PORT_IGNORE}="1"
ATTRS{idVendor}=="16c0", ATTRS{idProduct}=="04[789A]?", ENV{MTP_NO_PROBE}="1"
SUBSYSTEMS=="usb", ATTRS{idVendor}=="16c0", ATTRS{idProduct}=="04[789ABCD]?", MODE:="0666"
KERNEL=="ttyACM*", ATTRS{idVendor}=="16c0", ATTRS{idProduct}=="04[789B]?", MODE:="0666"
# TI Stellaris Launchpad
ATTRS{idVendor}=="1cbe", ATTRS{idProduct}=="00fd", MODE="0666", ENV{ID_MM_DEVICE_IGNORE}="1", ENV{ID_MM_PORT_IGNORE}="1"
# TI MSP430 Launchpad
ATTRS{idVendor}=="0451", ATTRS{idProduct}=="f432", MODE="0666", ENV{ID_MM_DEVICE_IGNORE}="1", ENV{ID_MM_PORT_IGNORE}="1"
# GD32V DFU Bootloader
ATTRS{idVendor}=="28e9", ATTRS{idProduct}=="0189", MODE="0666", ENV{ID_MM_DEVICE_IGNORE}="1", ENV{ID_MM_PORT_IGNORE}="1"
# FireBeetle-ESP32
ATTRS{idVendor}=="1a86", ATTRS{idProduct}=="7522", MODE="0666", ENV{ID_MM_DEVICE_IGNORE}="1", ENV{ID_MM_PORT_IGNORE}="1"
# Wio Terminal
ATTRS{idVendor}=="2886", ATTRS{idProduct}=="[08]02d", MODE="0666", ENV{ID_MM_DEVICE_IGNORE}="1", ENV{ID_MM_PORT_IGNORE}="1"
# Raspberry Pi Pico
ATTRS{idVendor}=="2e8a", ATTRS{idProduct}=="[01]*", MODE:="0666", ENV{ID_MM_DEVICE_IGNORE}="1", ENV{ID_MM_PORT_IGNORE}="1"
# AIR32F103
ATTRS{idVendor}=="0d28", ATTRS{idProduct}=="0204", MODE="0666", ENV{ID_MM_DEVICE_IGNORE}="1", ENV{ID_MM_PORT_IGNORE}="1"
# STM32 virtual COM port
ATTRS{idVendor}=="0483", ATTRS{idProduct}=="5740", MODE="0666", ENV{ID_MM_DEVICE_IGNORE}="1", ENV{ID_MM_PORT_IGNORE}="1"
#
# Debuggers
#
# Black Magic Probe
SUBSYSTEM=="tty", ATTRS{interface}=="Black Magic GDB Server", MODE="0666", ENV{ID_MM_DEVICE_IGNORE}="1", ENV{ID_MM_PORT_IGNORE}="1"
SUBSYSTEM=="tty", ATTRS{interface}=="Black Magic UART Port", MODE="0666", ENV{ID_MM_DEVICE_IGNORE}="1", ENV{ID_MM_PORT_IGNORE}="1"
# opendous and estick
ATTRS{idVendor}=="03eb", ATTRS{idProduct}=="204f", MODE="0666", ENV{ID_MM_DEVICE_IGNORE}="1", ENV{ID_MM_PORT_IGNORE}="1"
# Original FT232/FT245/FT2232/FT232H/FT4232
ATTRS{idVendor}=="0403", ATTRS{idProduct}=="60[01][104]", MODE="0666", ENV{ID_MM_DEVICE_IGNORE}="1", ENV{ID_MM_PORT_IGNORE}="1"
# DISTORTEC JTAG-lock-pick Tiny 2
ATTRS{idVendor}=="0403", ATTRS{idProduct}=="8220", MODE="0666", ENV{ID_MM_DEVICE_IGNORE}="1", ENV{ID_MM_PORT_IGNORE}="1"
# TUMPA, TUMPA Lite
ATTRS{idVendor}=="0403", ATTRS{idProduct}=="8a9[89]", MODE="0666", ENV{ID_MM_DEVICE_IGNORE}="1", ENV{ID_MM_PORT_IGNORE}="1"
# XDS100v2
ATTRS{idVendor}=="0403", ATTRS{idProduct}=="a6d0", MODE="0666", ENV{ID_MM_DEVICE_IGNORE}="1", ENV{ID_MM_PORT_IGNORE}="1"
# Xverve Signalyzer Tool (DT-USB-ST), Signalyzer LITE (DT-USB-SLITE)
ATTRS{idVendor}=="0403", ATTRS{idProduct}=="bca[01]", MODE="0666", ENV{ID_MM_DEVICE_IGNORE}="1", ENV{ID_MM_PORT_IGNORE}="1"
# TI/Luminary Stellaris Evaluation Board FTDI (several)
ATTRS{idVendor}=="0403", ATTRS{idProduct}=="bcd[9a]", MODE="0666", ENV{ID_MM_DEVICE_IGNORE}="1", ENV{ID_MM_PORT_IGNORE}="1"
# egnite Turtelizer 2
ATTRS{idVendor}=="0403", ATTRS{idProduct}=="bdc8", MODE="0666", ENV{ID_MM_DEVICE_IGNORE}="1", ENV{ID_MM_PORT_IGNORE}="1"
# Section5 ICEbear
ATTRS{idVendor}=="0403", ATTRS{idProduct}=="c14[01]", MODE="0666", ENV{ID_MM_DEVICE_IGNORE}="1", ENV{ID_MM_PORT_IGNORE}="1"
# Amontec JTAGkey and JTAGkey-tiny
ATTRS{idVendor}=="0403", ATTRS{idProduct}=="cff8", MODE="0666", ENV{ID_MM_DEVICE_IGNORE}="1", ENV{ID_MM_PORT_IGNORE}="1"
# TI ICDI
ATTRS{idVendor}=="0451", ATTRS{idProduct}=="c32a", MODE="0666", ENV{ID_MM_DEVICE_IGNORE}="1", ENV{ID_MM_PORT_IGNORE}="1"
# STLink probes
ATTRS{idVendor}=="0483", MODE="0666", ENV{ID_MM_DEVICE_IGNORE}="1", ENV{ID_MM_PORT_IGNORE}="1"
# Hilscher NXHX Boards
ATTRS{idVendor}=="0640", ATTRS{idProduct}=="0028", MODE="0666", ENV{ID_MM_DEVICE_IGNORE}="1", ENV{ID_MM_PORT_IGNORE}="1"
# Hitex probes
ATTRS{idVendor}=="0640", MODE="0666", ENV{ID_MM_DEVICE_IGNORE}="1", ENV{ID_MM_PORT_IGNORE}="1"
# Altera USB Blaster
ATTRS{idVendor}=="09fb", ATTRS{idProduct}=="6001", MODE="0666", ENV{ID_MM_DEVICE_IGNORE}="1", ENV{ID_MM_PORT_IGNORE}="1"
# Amontec JTAGkey-HiSpeed
ATTRS{idVendor}=="0fbb", ATTRS{idProduct}=="1000", MODE="0666", ENV{ID_MM_DEVICE_IGNORE}="1", ENV{ID_MM_PORT_IGNORE}="1"
# SEGGER J-Link
ATTRS{idVendor}=="1366", MODE="0666", ENV{ID_MM_DEVICE_IGNORE}="1", ENV{ID_MM_PORT_IGNORE}="1"
# Raisonance RLink
ATTRS{idVendor}=="138e", ATTRS{idProduct}=="9000", MODE="0666", ENV{ID_MM_DEVICE_IGNORE}="1", ENV{ID_MM_PORT_IGNORE}="1"
# Debug Board for Neo1973
ATTRS{idVendor}=="1457", ATTRS{idProduct}=="5118", MODE="0666", ENV{ID_MM_DEVICE_IGNORE}="1", ENV{ID_MM_PORT_IGNORE}="1"
# Olimex probes
ATTRS{idVendor}=="15ba", MODE="0666", ENV{ID_MM_DEVICE_IGNORE}="1", ENV{ID_MM_PORT_IGNORE}="1"
# USBprog with OpenOCD firmware
ATTRS{idVendor}=="1781", ATTRS{idProduct}=="0c63", MODE="0666", ENV{ID_MM_DEVICE_IGNORE}="1", ENV{ID_MM_PORT_IGNORE}="1"
# TI/Luminary Stellaris In-Circuit Debug Interface (ICDI) Board
ATTRS{idVendor}=="1cbe", ATTRS{idProduct}=="00fd", MODE="0666", ENV{ID_MM_DEVICE_IGNORE}="1", ENV{ID_MM_PORT_IGNORE}="1"
# Marvell Sheevaplug
ATTRS{idVendor}=="9e88", ATTRS{idProduct}=="9e8f", MODE="0666", ENV{ID_MM_DEVICE_IGNORE}="1", ENV{ID_MM_PORT_IGNORE}="1"
# Keil Software, Inc. ULink
ATTRS{idVendor}=="c251", ATTRS{idProduct}=="2710", MODE="0666", ENV{ID_MM_DEVICE_IGNORE}="1", ENV{ID_MM_PORT_IGNORE}="1"
# CMSIS-DAP compatible adapters
ATTRS{product}=="*CMSIS-DAP*", MODE="0666", ENV{ID_MM_DEVICE_IGNORE}="1", ENV{ID_MM_PORT_IGNORE}="1"
# Atmel AVR Dragon
ATTRS{idVendor}=="03eb", ATTRS{idProduct}=="2107", MODE="0666", ENV{ID_MM_DEVICE_IGNORE}="1", ENV{ID_MM_PORT_IGNORE}="1"
# Espressif USB JTAG/serial debug unit
ATTRS{idVendor}=="303a", ATTRS{idProduct}=="1001", MODE="0666", ENV{ID_MM_DEVICE_IGNORE}="1", ENV{ID_MM_PORT_IGNORE}="1"
# Zephyr framework USB CDC-ACM
ATTRS{idVendor}=="2fe3", ATTRS{idProduct}=="0100", MODE="0666", ENV{ID_MM_DEVICE_IGNORE}="1", ENV{ID_MM_PORT_IGNORE}="1"

View File

@@ -1,10 +1,6 @@
# trunk-ignore-all(terrascan/AC_DOCKER_0002): Known terrascan issue
# trunk-ignore-all(hadolint/DL3008): Do not pin apt package versions
# trunk-ignore-all(hadolint/DL3013): Do not pin pip package versions
FROM mcr.microsoft.com/devcontainers/cpp:2-debian-13
USER root
FROM mcr.microsoft.com/devcontainers/cpp:1-debian-12
# [Optional] Uncomment this section to install additional packages.
RUN apt-get update && export DEBIAN_FRONTEND=noninteractive \
&& apt-get -y install --no-install-recommends \
ca-certificates \
@@ -16,7 +12,6 @@ RUN apt-get update && export DEBIAN_FRONTEND=noninteractive \
libssl-dev \
libulfius-dev \
libyaml-cpp-dev \
pipx \
pkg-config \
python3 \
python3-pip \
@@ -24,22 +19,6 @@ RUN apt-get update && export DEBIAN_FRONTEND=noninteractive \
python3-wheel \
wget \
zip \
usbutils \
hwdata \
gpg \
gnupg2 \
libusb-1.0-0-dev \
libuv1-dev \
libi2c-dev \
libxcb-xkb-dev \
libxkbcommon-dev \
libinput-dev \
&& apt-get clean && rm -rf /var/lib/apt/lists/*
RUN pipx install platformio
COPY 99-platformio-udev.rules /etc/udev/rules.d/99-platformio-udev.rules
USER vscode
HEALTHCHECK NONE
RUN pip3 install --no-cache-dir -U platformio==6.1.15

View File

@@ -8,7 +8,7 @@
"features": {
"ghcr.io/devcontainers/features/python:1": {
"installTools": true,
"version": "3.14"
"version": "latest"
}
},
"customizations": {
@@ -16,21 +16,13 @@
"extensions": [
"ms-vscode.cpptools",
"platformio.platformio-ide",
"Trunk.io"
],
"unwantedRecommendations": ["ms-azuretools.vscode-docker"],
"settings": {
"extensions.ignoreRecommendations": true
}
]
}
},
// Use 'forwardPorts' to make a list of ports inside the container available locally.
"forwardPorts": [4403],
// Use "--device=" to make a local device available inside the container.
// "runArgs": ["--device=/dev/ttyACM0"],
"forwardPorts": [ 4403 ],
// Run commands to prepare the container for use
"postCreateCommand": ".devcontainer/setup.sh"
"postCreateCommand": ".devcontainer/setup.sh",
}

View File

@@ -1,6 +1,3 @@
#!/usr/bin/env sh
git submodule update --init
pip install --no-cache-dir setuptools
pipx install esptool
git submodule update --init

View File

@@ -1 +0,0 @@
.gitignore

View File

@@ -1,4 +0,0 @@
# Absolute path to the local meshtastic config.yaml file
CONFIG_PATH=/path/to/meshtastic/config.yaml
# USB device to passthrough (`lsusb -t`: look for `ch341`)
USB_DEVICE=/dev/bus/usb/001/037

5
.gitattributes vendored
View File

@@ -1,5 +1,4 @@
* text=auto eol=lf
*.cmd text eol=crlf
*.bat text eol=crlf
*.ps1 text eol=crlf
*.{cmd,[cC][mM][dD]} text eol=crlf
*.{bat,[bB][aA][tT]} text eol=crlf
*.{sh,[sS][hH]} text eol=lf

3
.github/FUNDING.yml vendored
View File

@@ -1,3 +0,0 @@
# These are supported funding model platforms
open_collective: meshtastic

View File

@@ -1,7 +1,7 @@
name: Bug Report
description: File a bug report
title: "[Bug]: "
labels: [bug, triage]
labels: ["bug", "triage"]
body:
- type: markdown
attributes:
@@ -49,38 +49,15 @@ body:
- Heltec V3
- Heltec Wireless Paper
- Heltec Wireless Tracker
- Heltec Mesh Node T114
- Heltec Vision Master E213
- Heltec Vision Master E290
- Heltec Vision Master T190
- Nano G1
- Nano G1 Explorer
- Nano G2 Ultra
- Raspberry Pi Pico (W)
- Relay v1
- Relay v2
- Seeed Wio Tracker 1110
- Seeed Card Tracker T1000-E
- Station G1
- Station G2
- unPhone
- CanaryOne
- Chatter
- Linux Native
- DIY
- Other
validations:
required: true
- type: checkboxes
id: mui
attributes:
label: Is this bug report about any UI component firmware like InkHUD or Meshtatic UI (MUI)?
options:
- label: Meshtastic UI aka MUI colorTFT
- label: InkHUD ePaper
- label: OLED slide UI on any display
- type: input
id: version
attributes:

View File

@@ -1,7 +1,7 @@
name: New Board
description: Request us to support new hardware
title: "[Board]: "
labels: [enhancement, triage]
labels: ["enhancement", "triage"]
body:
- type: markdown
attributes:

View File

@@ -1,7 +1,7 @@
name: Feature Request
description: Request a new feature
title: "[Feature Request]: "
labels: [enhancement]
labels: ["enhancement"]
body:
- type: markdown
attributes:
@@ -18,7 +18,6 @@ body:
- ESP32
- RP2040
- Linux Native
- Cross-Platform
- other
validations:
required: true

View File

@@ -1,6 +0,0 @@
# Configuration related to self-hosted runner.
self-hosted-runner:
# Labels of self-hosted runner in array of strings.
labels:
- arctastic
- test-runner

View File

@@ -1,108 +0,0 @@
name: Setup Build Variant Composite Action
description: Variant build actions for Meshtastic Platform IO steps
inputs:
board:
description: The board to build for
required: true
github_token:
description: GitHub token
required: true
build-script-path:
description: Path to the build script
required: true
remove-debug-flags:
description: A space separated list of files to remove debug flags from
required: false
default: ""
ota-firmware-source:
description: The OTA firmware file to pull
required: false
default: ""
ota-firmware-target:
description: The target path to store the OTA firmware file
required: false
default: ""
artifact-paths:
description: A newline separated list of paths to store as artifacts
required: false
default: ""
# include-web-ui:
# description: Include the web UI in the build
# required: false
# default: "false"
arch:
description: Processor arch name
required: true
default: esp32
runs:
using: composite
steps:
- name: Build base
id: base
uses: ./.github/actions/setup-base
# - name: Get web ui version
# if: inputs.include-web-ui == 'true'
# id: webver
# shell: bash
# run: |
# echo "ver=$(cat bin/web.version)" >> $GITHUB_OUTPUT
# - name: Pull web ui
# if: inputs.include-web-ui == 'true'
# uses: dsaltares/fetch-gh-release-asset@master
# with:
# repo: meshtastic/web
# file: build.tar
# target: build.tar
# token: ${{ inputs.github_token }}
# version: tags/v${{ steps.webver.outputs.ver }}
# - name: Unpack web ui
# if: inputs.include-web-ui == 'true'
# shell: bash
# run: |
# tar -xf build.tar -C data/static
# rm build.tar
- name: Remove debug flags for release
shell: bash
if: inputs.remove-debug-flags != ''
run: |
for INI_FILE in ${{ inputs.remove-debug-flags }}; do
sed -i '/DDEBUG_HEAP/d' ${INI_FILE}
done
- name: PlatformIO ${{ inputs.arch }} download cache
uses: actions/cache@v5
with:
path: ~/.platformio/.cache
key: pio-cache-${{ inputs.arch }}-${{ hashFiles('.github/actions/**', '**.ini') }}
- name: Build ${{ inputs.board }}
shell: bash
run: ${{ inputs.build-script-path }} ${{ inputs.board }}
- name: Pull OTA Firmware
if: inputs.ota-firmware-source != '' && inputs.ota-firmware-target != ''
uses: dsaltares/fetch-gh-release-asset@master
with:
repo: meshtastic/firmware-ota
file: ${{ inputs.ota-firmware-source }}
target: ${{ inputs.ota-firmware-target }}
token: ${{ inputs.github_token }}
- name: Get release version string
shell: bash
run: echo "long=$(./bin/buildinfo.py long)" >> $GITHUB_OUTPUT
id: version
- name: Store binaries as an artifact
uses: actions/upload-artifact@v5
with:
name: firmware-${{ inputs.arch }}-${{ inputs.board }}-${{ steps.version.outputs.long }}
overwrite: true
path: |
${{ inputs.artifact-paths }}

View File

@@ -1,13 +1,13 @@
name: Setup Build Base Composite Action
description: Base build actions for Meshtastic Platform IO steps
name: "Setup Build Base Composite Action"
description: "Base build actions for Meshtastic Platform IO steps"
runs:
using: composite
using: "composite"
steps:
- name: Checkout code
uses: actions/checkout@v6
uses: actions/checkout@v4
with:
submodules: recursive
submodules: "recursive"
ref: ${{github.event.pull_request.head.ref}}
repository: ${{github.event.pull_request.head.repo.full_name}}
@@ -15,16 +15,19 @@ runs:
shell: bash
run: |
sudo apt-get -y update --fix-missing
sudo apt-get install -y cppcheck libbluetooth-dev libgpiod-dev libyaml-cpp-dev lsb-release
sudo apt-get install -y cppcheck libbluetooth-dev libgpiod-dev libyaml-cpp-dev
- name: Setup Python
uses: actions/setup-python@v6
uses: actions/setup-python@v5
with:
python-version: 3.x
cache: pip
cache-dependency-path: |
.github/actions/**
**.ini
# - name: Cache python libs
# uses: actions/cache@v4
# id: cache-pip # needed in if test
# with:
# path: ~/.cache/pip
# key: ${{ runner.os }}-pip
- name: Upgrade python tools
shell: bash

View File

@@ -1,14 +0,0 @@
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 libuv1-dev

Binary file not shown.

Before

Width:  |  Height:  |  Size: 89 KiB

View File

@@ -1,9 +1,9 @@
## 🙏 Thank you for sending in a pull request, here's some tips to get started!
## Thank you for sending in a pull request, here's some tips to get started!
### ❌ (Please delete all these tips and replace them with your text)
(Please delete all these tips and replace with your text)
- Before starting on some new big chunk of code, it it is optional but highly recommended to open an issue first
to say "Hey, I think this idea X should be implemented and I'm starting work on it. My general plan is Y, any feedback
to say "hey, I think this idea X should be implemented and I'm starting work on it. My general plan is Y, any feedback
is appreciated." This will allow other devs to potentially save you time by not accidentially duplicating work etc...
- Please do not check in files that don't have real changes
- Please do not reformat lines that you didn't have to change the code on
@@ -12,17 +12,3 @@
- If your PR fixes a bug, mention "fixes #bugnum" somewhere in your pull request description.
- If your other co-developers have comments on your PR please tweak as needed.
- Please also enable "Allow edits by maintainers".
- Please do not submit untested code.
- If you do not have the affected hardware to test your code changes adequately against regressions, please indicate this, so that contributors and commnunity members can help test your changes.
- If your PR gets accepted you can request a "Contributor" role in the Meshtastic Discord
## 🤝 Attestations
- [ ] I have tested that my proposed changes behave as described.
- [ ] I have tested that my proposed changes do not cause any obvious regressions on the following devices:
- [ ] Heltec (Lora32) V3
- [ ] LilyGo T-Deck
- [ ] LilyGo T-Beam
- [ ] RAK WisBlock 4631
- [ ] Seeed Studio T-1000E tracker card
- [ ] Other (please specify below)

View File

@@ -1,72 +0,0 @@
name: Build Debian Source Package
on:
workflow_call:
secrets:
PPA_GPG_PRIVATE_KEY:
required: false
inputs:
series:
description: Ubuntu/Debian series to target
required: true
type: string
build_location:
description: Location where build will execute
required: true
type: string
permissions:
contents: write
packages: write
jobs:
build-debian-src:
runs-on: ubuntu-24.04
steps:
- name: Checkout code
uses: actions/checkout@v6
with:
submodules: recursive
path: meshtasticd
ref: ${{github.event.pull_request.head.ref}}
repository: ${{github.event.pull_request.head.repo.full_name}}
- name: Install deps
shell: bash
working-directory: meshtasticd
run: |
sudo apt-get update -y --fix-missing
sudo apt-get install -y software-properties-common build-essential devscripts equivs
sudo add-apt-repository ppa:meshtastic/build-tools -y
sudo apt-get update -y --fix-missing
sudo mk-build-deps --install --remove --tool='apt-get -o Debug::pkgProblemResolver=yes --no-install-recommends --yes' debian/control
- name: Import GPG key
uses: crazy-max/ghaction-import-gpg@v6
with:
gpg_private_key: ${{ secrets.PPA_GPG_PRIVATE_KEY }}
id: gpg
- name: Get release version string
working-directory: meshtasticd
run: |
echo "deb=$(./bin/buildinfo.py deb)" >> $GITHUB_OUTPUT
env:
BUILD_LOCATION: ${{ inputs.build_location }}
id: version
- name: Fetch libdeps, package debian source
working-directory: meshtasticd
run: debian/ci_pack_sdeb.sh
env:
SERIES: ${{ inputs.series }}
GPG_KEY_ID: ${{ steps.gpg.outputs.keyid }}
PKG_VERSION: ${{ steps.version.outputs.deb }}
- name: Store binaries as an artifact
uses: actions/upload-artifact@v5
with:
name: firmware-debian-${{ steps.version.outputs.deb }}~${{ inputs.series }}-src
overwrite: true
path: |
meshtasticd_${{ steps.version.outputs.deb }}*

63
.github/workflows/build_esp32.yml vendored Normal file
View File

@@ -0,0 +1,63 @@
name: Build ESP32
on:
workflow_call:
inputs:
board:
required: true
type: string
jobs:
build-esp32:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Build base
id: base
uses: ./.github/actions/setup-base
- name: Pull web ui
uses: dsaltares/fetch-gh-release-asset@master
with:
repo: meshtastic/web
file: build.tar
target: build.tar
token: ${{ secrets.GITHUB_TOKEN }}
- name: Unpack web ui
run: |
tar -xf build.tar -C data/static
rm build.tar
- name: Remove debug flags for release
if: ${{ github.event_name == 'workflow_dispatch' }}
run: |
sed -i '/DDEBUG_HEAP/d' ./arch/esp32/esp32.ini
sed -i '/DDEBUG_HEAP/d' ./arch/esp32/esp32s2.ini
sed -i '/DDEBUG_HEAP/d' ./arch/esp32/esp32s3.ini
sed -i '/DDEBUG_HEAP/d' ./arch/esp32/esp32c3.ini
- name: Build ESP32
run: bin/build-esp32.sh ${{ inputs.board }}
- name: Pull OTA Firmware
uses: dsaltares/fetch-gh-release-asset@master
with:
repo: meshtastic/firmware-ota
file: firmware.bin
target: release/bleota.bin
token: ${{ secrets.GITHUB_TOKEN }}
- name: Get release version string
shell: bash
run: echo "version=$(./bin/buildinfo.py long)" >> $GITHUB_OUTPUT
id: version
- name: Store binaries as an artifact
uses: actions/upload-artifact@v4
with:
name: firmware-${{ inputs.board }}-${{ steps.version.outputs.version }}.zip
overwrite: true
path: |
release/*.bin
release/*.elf

63
.github/workflows/build_esp32_c3.yml vendored Normal file
View File

@@ -0,0 +1,63 @@
name: Build ESP32-C3
on:
workflow_call:
inputs:
board:
required: true
type: string
permissions: read-all
jobs:
build-esp32-c3:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Build base
id: base
uses: ./.github/actions/setup-base
- name: Pull web ui
uses: dsaltares/fetch-gh-release-asset@master
with:
repo: meshtastic/web
file: build.tar
target: build.tar
token: ${{ secrets.GITHUB_TOKEN }}
- name: Unpack web ui
run: |
tar -xf build.tar -C data/static
rm build.tar
- name: Remove debug flags for release
if: ${{ github.event_name == 'workflow_dispatch' }}
run: |
sed -i '/DDEBUG_HEAP/d' ./arch/esp32/esp32.ini
sed -i '/DDEBUG_HEAP/d' ./arch/esp32/esp32s2.ini
sed -i '/DDEBUG_HEAP/d' ./arch/esp32/esp32s3.ini
sed -i '/DDEBUG_HEAP/d' ./arch/esp32/esp32c3.ini
- name: Build ESP32
run: bin/build-esp32.sh ${{ inputs.board }}
- name: Pull OTA Firmware
uses: dsaltares/fetch-gh-release-asset@master
with:
repo: meshtastic/firmware-ota
file: firmware-c3.bin
target: release/bleota-c3.bin
token: ${{ secrets.GITHUB_TOKEN }}
- name: Get release version string
shell: bash
run: echo "version=$(./bin/buildinfo.py long)" >> $GITHUB_OUTPUT
id: version
- name: Store binaries as an artifact
uses: actions/upload-artifact@v4
with:
name: firmware-${{ inputs.board }}-${{ steps.version.outputs.version }}.zip
overwrite: true
path: |
release/*.bin
release/*.elf

61
.github/workflows/build_esp32_s3.yml vendored Normal file
View File

@@ -0,0 +1,61 @@
name: Build ESP32-S3
on:
workflow_call:
inputs:
board:
required: true
type: string
jobs:
build-esp32-s3:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Build base
id: base
uses: ./.github/actions/setup-base
- name: Pull web ui
uses: dsaltares/fetch-gh-release-asset@master
with:
repo: meshtastic/web
file: build.tar
target: build.tar
token: ${{ secrets.GITHUB_TOKEN }}
- name: Unpack web ui
run: |
tar -xf build.tar -C data/static
rm build.tar
- name: Remove debug flags for release
if: ${{ github.event_name == 'workflow_dispatch' }}
run: |
sed -i '/DDEBUG_HEAP/d' ./arch/esp32/esp32.ini
sed -i '/DDEBUG_HEAP/d' ./arch/esp32/esp32s2.ini
sed -i '/DDEBUG_HEAP/d' ./arch/esp32/esp32s3.ini
sed -i '/DDEBUG_HEAP/d' ./arch/esp32/esp32c3.ini
- name: Build ESP32
run: bin/build-esp32.sh ${{ inputs.board }}
- name: Pull OTA Firmware
uses: dsaltares/fetch-gh-release-asset@master
with:
repo: meshtastic/firmware-ota
file: firmware-s3.bin
target: release/bleota-s3.bin
token: ${{ secrets.GITHUB_TOKEN }}
- name: Get release version string
shell: bash
run: echo "version=$(./bin/buildinfo.py long)" >> $GITHUB_OUTPUT
id: version
- name: Store binaries as an artifact
uses: actions/upload-artifact@v4
with:
name: firmware-${{ inputs.board }}-${{ steps.version.outputs.version }}.zip
overwrite: true
path: |
release/*.bin
release/*.elf

View File

@@ -1,84 +0,0 @@
name: Build
on:
workflow_call:
inputs:
version:
required: true
type: string
platform:
required: true
type: string
pio_env:
required: true
type: string
permissions: read-all
jobs:
pio-build:
name: build-${{ inputs.platform }}
# Use 'arctastic' self-hosted runner pool when building in the main repo
runs-on: ${{ github.repository_owner == 'meshtastic' && 'arctastic' || 'ubuntu-latest' }}
outputs:
artifact-id: ${{ steps.upload.outputs.artifact-id }}
steps:
- uses: actions/checkout@v6
with:
submodules: recursive
ref: ${{github.event.pull_request.head.ref}}
repository: ${{github.event.pull_request.head.repo.full_name}}
- name: Set OTA firmware source and target
if: startsWith(inputs.platform, 'esp32')
id: ota_dir
env:
PIO_PLATFORM: ${{ inputs.platform }}
run: |
if [ "$PIO_PLATFORM" = "esp32s3" ]; then
echo "src=firmware-s3.bin" >> $GITHUB_OUTPUT
echo "tgt=release/bleota-s3.bin" >> $GITHUB_OUTPUT
elif [ "$PIO_PLATFORM" = "esp32c3" ] || [ "$PIO_PLATFORM" = "esp32c6" ]; then
echo "src=firmware-c3.bin" >> $GITHUB_OUTPUT
echo "tgt=release/bleota-c3.bin" >> $GITHUB_OUTPUT
elif [ "$PIO_PLATFORM" = "esp32" ]; then
echo "src=firmware.bin" >> $GITHUB_OUTPUT
echo "tgt=release/bleota.bin" >> $GITHUB_OUTPUT
fi
- name: Build ${{ inputs.platform }}
id: build
uses: meshtastic/gh-action-firmware@main
with:
pio_platform: ${{ inputs.platform }}
pio_env: ${{ inputs.pio_env }}
pio_target: build
ota_firmware_source: ${{ steps.ota_dir.outputs.src || '' }}
ota_firmware_target: ${{ steps.ota_dir.outputs.tgt || '' }}
- name: Echo manifest from release/firmware-*.mt.json to job summary
if: ${{ always() }}
env:
PIO_ENV: ${{ inputs.pio_env }}
run: |
echo "## Manifest: \`$PIO_ENV\`" >> $GITHUB_STEP_SUMMARY
echo '```json' >> $GITHUB_STEP_SUMMARY
cat release/firmware-*.mt.json >> $GITHUB_STEP_SUMMARY
echo '' >> $GITHUB_STEP_SUMMARY
echo '```' >> $GITHUB_STEP_SUMMARY
- name: Store binaries as an artifact
uses: actions/upload-artifact@v5
id: upload
with:
name: firmware-${{ inputs.platform }}-${{ inputs.pio_env }}-${{ inputs.version }}
overwrite: true
path: |
release/*.mt.json
release/*.bin
release/*.elf
release/*.uf2
release/*.hex
release/*.zip
release/device-*.sh
release/device-*.bat

85
.github/workflows/build_native.yml vendored Normal file
View File

@@ -0,0 +1,85 @@
name: Build Native
on: workflow_call
permissions:
contents: write
packages: write
jobs:
build-native:
runs-on: ubuntu-latest
steps:
- name: Install libbluetooth
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
- name: Checkout code
uses: actions/checkout@v4
with:
submodules: recursive
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: Build Native
run: bin/build-native.sh
- name: Get release version string
run: echo "version=$(./bin/buildinfo.py long)" >> $GITHUB_OUTPUT
id: version
- name: Store binaries as an artifact
uses: actions/upload-artifact@v4
with:
name: firmware-native-${{ steps.version.outputs.version }}.zip
overwrite: true
path: |
release/meshtasticd_linux_x86_64
bin/config-dist.yaml
- name: Docker login
if: ${{ github.event_name != 'pull_request_target' && github.event_name != 'pull_request' }}
uses: docker/login-action@v3
continue-on-error: true # FIXME: Failing docker login auth
with:
username: meshtastic
password: ${{ secrets.DOCKER_FIRMWARE_TOKEN }}
- name: Docker setup
if: ${{ github.event_name != 'pull_request_target' && github.event_name != 'pull_request' }}
continue-on-error: true # FIXME: Failing docker login auth
uses: docker/setup-buildx-action@v3
- name: Docker build and push tagged versions
if: ${{ github.event_name == 'workflow_dispatch' }}
continue-on-error: true # FIXME: Failing docker login auth
uses: docker/build-push-action@v5
with:
context: .
file: ./Dockerfile
push: true
tags: meshtastic/device-simulator:${{ steps.version.outputs.version }}
- name: Docker build and push
if: ${{ github.ref == 'refs/heads/master' && github.event_name != 'pull_request_target' && github.event_name != 'pull_request' }}
continue-on-error: true # FIXME: Failing docker login auth
uses: docker/build-push-action@v5
with:
context: .
file: ./Dockerfile
push: true
tags: meshtastic/device-simulator:latest

35
.github/workflows/build_nrf52.yml vendored Normal file
View File

@@ -0,0 +1,35 @@
name: Build NRF52
on:
workflow_call:
inputs:
board:
required: true
type: string
jobs:
build-nrf52:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Build base
id: base
uses: ./.github/actions/setup-base
- name: Build NRF52
run: bin/build-nrf52.sh ${{ inputs.board }}
- name: Get release version string
run: echo "version=$(./bin/buildinfo.py long)" >> $GITHUB_OUTPUT
id: version
- name: Store binaries as an artifact
uses: actions/upload-artifact@v4
with:
name: firmware-${{ inputs.board }}-${{ steps.version.outputs.version }}.zip
overwrite: true
path: |
release/*.hex
release/*.uf2
release/*.elf
release/*.zip

View File

@@ -1,161 +0,0 @@
name: Build One Target
on:
workflow_dispatch:
inputs:
# trunk-ignore(checkov/CKV_GHA_7)
arch:
type: choice
options:
- esp32
- esp32s3
- esp32c3
- esp32c6
- nrf52840
- rp2040
- rp2350
- stm32
target:
type: string
required: false
description: Choose the target board, e.g. nrf52_promicro_diy_tcxo. If blank, will find available targets.
# find-target:
# type: boolean
# default: true
# description: 'Find the available targets'
permissions: read-all
jobs:
find-targets:
if: ${{ inputs.target == '' }}
strategy:
fail-fast: false
matrix:
arch:
- esp32
- esp32s3
- esp32c3
- esp32c6
- nrf52840
- rp2040
- rp2350
- stm32
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@v6
- uses: actions/setup-python@v6
with:
python-version: 3.x
cache: pip
- run: pip install -U platformio
- name: Generate matrix
id: jsonStep
run: |
TARGETS=$(./bin/generate_ci_matrix.py ${{matrix.arch}} --level extra)
echo "Name: $GITHUB_REF_NAME" >> $GITHUB_STEP_SUMMARY
echo "Base: $GITHUB_BASE_REF" >> $GITHUB_STEP_SUMMARY
echo "Arch: ${{matrix.arch}}" >> $GITHUB_STEP_SUMMARY
echo "Ref: $GITHUB_REF" >> $GITHUB_STEP_SUMMARY
echo "Targets:" >> $GITHUB_STEP_SUMMARY
echo $TARGETS | jq -r 'sort_by(.board) |.[] | "- " + .board' >> $GITHUB_STEP_SUMMARY
version:
if: ${{ inputs.target != '' }}
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- name: Get release version string
run: |
echo "long=$(./bin/buildinfo.py long)" >> $GITHUB_OUTPUT
echo "deb=$(./bin/buildinfo.py deb)" >> $GITHUB_OUTPUT
id: version
env:
BUILD_LOCATION: local
outputs:
long: ${{ steps.version.outputs.long }}
deb: ${{ steps.version.outputs.deb }}
build:
if: ${{ inputs.target != '' && inputs.arch != 'native' }}
needs: [version]
uses: ./.github/workflows/build_firmware.yml
with:
version: ${{ needs.version.outputs.long }}
pio_env: ${{ inputs.target }}
platform: ${{ inputs.arch }}
gather-artifacts:
permissions:
contents: write
pull-requests: write
runs-on: ubuntu-latest
needs: [version, build]
steps:
- name: Checkout code
uses: actions/checkout@v6
with:
ref: ${{github.event.pull_request.head.ref}}
repository: ${{github.event.pull_request.head.repo.full_name}}
- uses: actions/download-artifact@v6
with:
path: ./
pattern: firmware-*-*
merge-multiple: true
- name: Display structure of downloaded files
run: ls -R
- name: Move files up
run: mv -b -t ./ ./bin/device-*.sh ./bin/device-*.bat
- name: Repackage in single firmware zip
uses: actions/upload-artifact@v5
with:
name: firmware-${{inputs.target}}-${{ needs.version.outputs.long }}
overwrite: true
path: |
./firmware-*.bin
./firmware-*.uf2
./firmware-*.hex
./firmware-*.zip
./device-*.sh
./device-*.bat
./littlefs-*.bin
./bleota*bin
./Meshtastic_nRF52_factory_erase*.uf2
retention-days: 30
- uses: actions/download-artifact@v6
with:
pattern: firmware-*-${{ needs.version.outputs.long }}
merge-multiple: true
path: ./output
# For diagnostics
- name: Show artifacts
run: ls -lR
- name: Device scripts permissions
run: |
chmod +x ./output/device-install.sh || true
chmod +x ./output/device-update.sh || true
- name: Zip firmware
run: zip -j -9 -r ./firmware-${{inputs.target}}-${{ needs.version.outputs.long }}.zip ./output
- name: Repackage in single elfs zip
uses: actions/upload-artifact@v5
with:
name: debug-elfs-${{inputs.target}}-${{ needs.version.outputs.long }}.zip
overwrite: true
path: ./*.elf
retention-days: 30
- uses: scruplelesswizard/comment-artifact@main
if: ${{ github.event_name == 'pull_request' }}
with:
name: firmware-${{inputs.target}}-${{ needs.version.outputs.long }}
description: "Download firmware-${{inputs.target}}-${{ needs.version.outputs.long }}.zip. This artifact will be available for 90 days from creation"
github-token: ${{ secrets.GITHUB_TOKEN }}

52
.github/workflows/build_raspbian.yml vendored Normal file
View File

@@ -0,0 +1,52 @@
name: Build Raspbian
on: workflow_call
permissions:
contents: write
packages: write
jobs:
build-raspbian:
runs-on: [self-hosted, linux, ARM64]
steps:
- name: Install libbluetooth
shell: bash
run: |
apt-get update -y --fix-missing
apt-get install -y libbluetooth-dev libgpiod-dev libyaml-cpp-dev openssl libssl-dev libulfius-dev liborcania-dev
- name: Checkout code
uses: actions/checkout@v4
with:
submodules: recursive
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: Build Raspbian
run: bin/build-native.sh
- name: Get release version string
run: echo "version=$(./bin/buildinfo.py long)" >> $GITHUB_OUTPUT
id: version
- name: Store binaries as an artifact
uses: actions/upload-artifact@v4
with:
name: firmware-raspbian-${{ steps.version.outputs.version }}.zip
overwrite: true
path: |
release/meshtasticd_linux_aarch64
bin/config-dist.yaml

View File

@@ -0,0 +1,52 @@
name: Build Raspbian Arm
on: workflow_call
permissions:
contents: write
packages: write
jobs:
build-raspbian-armv7l:
runs-on: [self-hosted, linux, ARM]
steps:
- name: Install libbluetooth
shell: bash
run: |
apt-get update -y --fix-missing
apt-get install -y libbluetooth-dev libgpiod-dev libyaml-cpp-dev openssl libssl-dev libulfius-dev liborcania-dev
- name: Checkout code
uses: actions/checkout@v4
with:
submodules: recursive
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: Build Raspbian
run: bin/build-native.sh
- name: Get release version string
run: echo "version=$(./bin/buildinfo.py long)" >> $GITHUB_OUTPUT
id: version
- name: Store binaries as an artifact
uses: actions/upload-artifact@v4
with:
name: firmware-raspbian-armv7l-${{ steps.version.outputs.version }}.zip
overwrite: true
path: |
release/meshtasticd_linux_armv7l
bin/config-dist.yaml

33
.github/workflows/build_rpi2040.yml vendored Normal file
View File

@@ -0,0 +1,33 @@
name: Build RPI2040
on:
workflow_call:
inputs:
board:
required: true
type: string
jobs:
build-rpi2040:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Build base
id: base
uses: ./.github/actions/setup-base
- name: Build Raspberry Pi 2040
run: ./bin/build-rpi2040.sh ${{ inputs.board }}
- name: Get release version string
run: echo "version=$(./bin/buildinfo.py long)" >> $GITHUB_OUTPUT
id: version
- name: Store binaries as an artifact
uses: actions/upload-artifact@v4
with:
name: firmware-${{ inputs.board }}-${{ steps.version.outputs.version }}.zip
overwrite: true
path: |
release/*.uf2
release/*.elf

33
.github/workflows/build_stm32.yml vendored Normal file
View File

@@ -0,0 +1,33 @@
name: Build STM32
on:
workflow_call:
inputs:
board:
required: true
type: string
jobs:
build-stm32:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Build base
id: base
uses: ./.github/actions/setup-base
- name: Build STM32
run: bin/build-stm32.sh ${{ inputs.board }}
- name: Get release version string
run: echo "version=$(./bin/buildinfo.py long)" >> $GITHUB_OUTPUT
id: version
- name: Store binaries as an artifact
uses: actions/upload-artifact@v4
with:
name: firmware-${{ inputs.board }}-${{ steps.version.outputs.version }}.zip
overwrite: true
path: |
release/*.hex
release/*.bin

View File

@@ -1,59 +0,0 @@
name: Daily Packaging
on:
schedule:
- cron: 0 2 * * *
workflow_dispatch:
push:
branches:
- master
paths:
- debian/**
- "*.rpkg"
- .github/workflows/nightly_packaging.yml
- .github/workflows/build_debian_src.yml
- .github/workflows/package_ppa.yml
- .github/workflows/package_obs.yml
- .github/workflows/hook_copr.yml
permissions:
contents: write
packages: write
jobs:
docker-multiarch:
if: github.repository == 'meshtastic/firmware'
uses: ./.github/workflows/docker_manifest.yml
with:
release_channel: daily
secrets: inherit
package-ppa:
if: github.repository == 'meshtastic/firmware'
strategy:
fail-fast: false
matrix:
series:
- jammy # 22.04 LTS
- noble # 24.04 LTS
- plucky # 25.04
- questing # 25.10
uses: ./.github/workflows/package_ppa.yml
with:
ppa_repo: ppa:meshtastic/daily
series: ${{ matrix.series }}
secrets: inherit
package-obs:
if: github.repository == 'meshtastic/firmware'
uses: ./.github/workflows/package_obs.yml
with:
obs_project: network:Meshtastic:daily
series: unstable
secrets: inherit
hook-copr:
if: github.repository == 'meshtastic/firmware'
uses: ./.github/workflows/hook_copr.yml
with:
copr_project: daily
secrets: inherit

View File

@@ -1,99 +0,0 @@
name: Build Docker
# Build Docker image, push untagged (digest-only)
on:
workflow_call:
secrets:
DOCKER_FIRMWARE_TOKEN:
required: false # Only required for push
inputs:
distro:
description: Distro to target
required: true
type: string
# choices: [debian, alpine]
platform:
description: Platform to target
required: true
type: string
runs-on:
description: Runner to use
required: true
type: string
push:
description: Push images to registry
required: false
type: boolean
default: false
pio_env:
description: PlatformIO environment to build
required: false
type: string
default: native
outputs:
digest:
description: Digest of built image
value: ${{ jobs.docker-build.outputs.digest }}
permissions:
contents: write
packages: write
jobs:
docker-build:
outputs:
digest: ${{ steps.docker_variant.outputs.digest }}
runs-on: ${{ inputs.runs-on }}
steps:
- name: Checkout code
uses: actions/checkout@v6
with:
submodules: recursive
ref: ${{github.event.pull_request.head.ref}}
repository: ${{github.event.pull_request.head.repo.full_name}}
- name: Get release version string
run: |
echo "long=$(./bin/buildinfo.py long)" >> $GITHUB_OUTPUT
id: version
- name: Docker login
if: ${{ inputs.push }}
uses: docker/login-action@v3
with:
username: meshtastic
password: ${{ secrets.DOCKER_FIRMWARE_TOKEN }}
- name: Set up QEMU
uses: docker/setup-qemu-action@v3
- name: Docker setup
uses: docker/setup-buildx-action@v3
- name: Sanitize platform string
id: sanitize_platform
# Replace slashes with underscores
run: echo "cleaned_platform=${{ inputs.platform }}" | sed 's/\//_/g' >> $GITHUB_OUTPUT
- name: Docker tag
id: meta
uses: docker/metadata-action@v5
with:
images: meshtastic/meshtasticd
tags: |
GHA-${{ steps.version.outputs.long }}-${{ inputs.distro }}-${{ steps.sanitize_platform.outputs.cleaned_platform }}
flavor: latest=false
- name: Docker build and push
uses: docker/build-push-action@v6
id: docker_variant
with:
context: .
file: |
${{ contains(inputs.distro, 'debian') && './Dockerfile' || contains(inputs.distro, 'alpine') && './alpine.Dockerfile' }}
push: ${{ inputs.push }}
tags: ${{ steps.meta.outputs.tags }} # Tag is only meant to be consumed by the "manifest" job
platforms: ${{ inputs.platform }}
build-args: |
PIO_ENV=${{ inputs.pio_env }}

View File

@@ -1,186 +0,0 @@
name: Build Docker Multi-Arch Manifest
on:
workflow_call:
secrets:
DOCKER_FIRMWARE_TOKEN:
required: true
inputs:
release_channel:
description: Release channel to target
required: true
type: string
permissions:
contents: write
packages: write
jobs:
docker-debian-amd64:
uses: ./.github/workflows/docker_build.yml
with:
distro: debian
platform: linux/amd64
runs-on: ubuntu-24.04
push: true
secrets: inherit
docker-debian-arm64:
uses: ./.github/workflows/docker_build.yml
with:
distro: debian
platform: linux/arm64
runs-on: ubuntu-24.04-arm
push: true
secrets: inherit
docker-debian-armv7:
uses: ./.github/workflows/docker_build.yml
with:
distro: debian
platform: linux/arm/v7
runs-on: ubuntu-24.04-arm
push: true
secrets: inherit
docker-alpine-amd64:
uses: ./.github/workflows/docker_build.yml
with:
distro: alpine
platform: linux/amd64
runs-on: ubuntu-24.04
push: true
secrets: inherit
docker-alpine-arm64:
uses: ./.github/workflows/docker_build.yml
with:
distro: alpine
platform: linux/arm64
runs-on: ubuntu-24.04-arm
push: true
secrets: inherit
docker-alpine-armv7:
uses: ./.github/workflows/docker_build.yml
with:
distro: alpine
platform: linux/arm/v7
runs-on: ubuntu-24.04-arm
push: true
secrets: inherit
docker-manifest:
needs:
# Debian
- docker-debian-amd64
- docker-debian-arm64
- docker-debian-armv7
# Alpine
- docker-alpine-amd64
- docker-alpine-arm64
- docker-alpine-armv7
runs-on: ubuntu-24.04
steps:
- name: Checkout code
uses: actions/checkout@v6
with:
submodules: recursive
ref: ${{github.event.pull_request.head.ref}}
repository: ${{github.event.pull_request.head.repo.full_name}}
- name: Get release version string
run: |
echo "long=$(./bin/buildinfo.py long)" >> $GITHUB_OUTPUT
echo "short=$(./bin/buildinfo.py short)" >> $GITHUB_OUTPUT
id: version
- name: Enumerate tags
shell: python
run: |
import os
short = "${{ steps.version.outputs.short }}"
long = "${{ steps.version.outputs.long }}"
release_channel = "${{ inputs.release_channel }}"
tags = {
"beta": {
"debian": [
f"{short}", f"{long}", f"{short}-beta", f"{long}-beta", "beta", "latest",
f"{short}-debian", f"{long}-debian", f"{short}-beta-debian", f"{long}-beta-debian", "beta-debian"
],
"alpine": [
f"{short}-alpine", f"{long}-alpine", f"{short}-beta-alpine", f"{long}-beta-alpine", "beta-alpine"
]
},
"alpha": {
"debian": [
f"{short}-alpha", f"{long}-alpha", "alpha",
f"{short}-alpha-debian", f"{long}-alpha-debian", "alpha-debian"
],
"alpine": [
f"{short}-alpha-alpine", f"{long}-alpha-alpine", "alpha-alpine"
]
},
"daily": {
"debian": ["daily", "daily-debian"],
"alpine": ["daily-alpine"]
}
}
with open(os.environ["GITHUB_OUTPUT"], "a") as fh:
fh.write("debian<<EOF\n")
fh.write("\n".join(tags[release_channel]["debian"]))
fh.write("\nEOF\n")
fh.write("alpine<<EOF\n")
fh.write("\n".join(tags[release_channel]["alpine"]))
fh.write("\nEOF\n")
id: tags
- name: Docker login
uses: docker/login-action@v3
with:
username: meshtastic
password: ${{ secrets.DOCKER_FIRMWARE_TOKEN }}
- name: Docker meta (Debian)
id: meta_debian
uses: docker/metadata-action@v5
with:
images: meshtastic/meshtasticd
tags: |
${{ steps.tags.outputs.debian }}
flavor: latest=false
- name: Create Docker manifest (Debian)
id: manifest_debian
uses: int128/docker-manifest-create-action@v2
with:
tags: |
${{ steps.meta_debian.outputs.tags }}
push: true
sources: |
meshtastic/meshtasticd@${{ needs.docker-debian-amd64.outputs.digest }}
meshtastic/meshtasticd@${{ needs.docker-debian-arm64.outputs.digest }}
meshtastic/meshtasticd@${{ needs.docker-debian-armv7.outputs.digest }}
- name: Docker meta (Alpine)
id: meta_alpine
uses: docker/metadata-action@v5
with:
images: meshtastic/meshtasticd
tags: |
${{ steps.tags.outputs.alpine }}
- name: Create Docker manifest (Alpine)
id: manifest_alpine
uses: int128/docker-manifest-create-action@v2
with:
tags: |
${{ steps.meta_alpine.outputs.tags }}
push: true
sources: |
meshtastic/meshtasticd@${{ needs.docker-alpine-amd64.outputs.digest }}
meshtastic/meshtasticd@${{ needs.docker-alpine-arm64.outputs.digest }}
meshtastic/meshtasticd@${{ needs.docker-alpine-armv7.outputs.digest }}

View File

@@ -1,38 +0,0 @@
name: Trigger COPR build
on:
workflow_call:
secrets:
COPR_API_CONFIG:
inputs:
copr_project:
description: COPR project to target
required: true
type: string
permissions:
contents: write
packages: write
jobs:
build-copr-hook:
runs-on: ubuntu-24.04
steps:
- name: Checkout code
uses: actions/checkout@v6
with:
submodules: recursive
ref: ${{ github.ref }}
repository: ${{ github.repository }}
- name: Trigger COPR build
uses: vidplace7/copr-build@main
id: copr_build
env:
COPR_API_TOKEN_CONFIG: ${{ secrets.COPR_API_CONFIG }}
with:
owner: "@meshtastic"
package-name: meshtasticd
project-name: ${{ inputs.copr_project }}
git-remote: "${{ github.server_url }}/${{ github.repository }}.git"
committish: ${{ github.sha }}

View File

@@ -1,24 +1,18 @@
name: CI
concurrency:
group: ci-${{ github.head_ref || github.run_id }}
cancel-in-progress: true
#concurrency:
# group: ${{ github.ref }}
# cancel-in-progress: ${{ github.ref != 'refs/heads/master' }}
on:
# # Triggers the workflow on push but only for the main branches
# # Triggers the workflow on push but only for the master branch
push:
branches:
- master
- develop
- event/*
branches: [master, develop]
paths-ignore:
- "**.md"
- version.properties
# Note: This is different from "pull_request". Need to specify ref when doing checkouts.
pull_request_target:
branches:
- master
- develop
- event/*
branches: [master, develop]
paths-ignore:
- "**.md"
#- "**.yml"
@@ -28,181 +22,177 @@ on:
jobs:
setup:
strategy:
fail-fast: true
fail-fast: false
matrix:
arch:
- all
- check
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@v6
- uses: actions/setup-python@v6
with:
python-version: 3.x
cache: pip
- run: pip install -U platformio
- name: Generate matrix
id: jsonStep
run: |
if [[ "$GITHUB_HEAD_REF" == "" ]]; then
TARGETS=$(./bin/generate_ci_matrix.py ${{matrix.arch}})
else
TARGETS=$(./bin/generate_ci_matrix.py ${{matrix.arch}} --level pr)
fi
echo "Name: $GITHUB_REF_NAME Base: $GITHUB_BASE_REF Ref: $GITHUB_REF"
echo "${{matrix.arch}}=$TARGETS" >> $GITHUB_OUTPUT
echo "$TARGETS" >> $GITHUB_STEP_SUMMARY
outputs:
all: ${{ steps.jsonStep.outputs.all }}
check: ${{ steps.jsonStep.outputs.check }}
version:
arch: [esp32, esp32s3, esp32c3, nrf52840, rp2040, stm32, check]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- name: Get release version string
- id: checkout
uses: actions/checkout@v4
name: Checkout base
- id: jsonStep
run: |
echo "long=$(./bin/buildinfo.py long)" >> $GITHUB_OUTPUT
echo "deb=$(./bin/buildinfo.py deb)" >> $GITHUB_OUTPUT
id: version
env:
BUILD_LOCATION: local
TARGETS=$(./bin/generate_ci_matrix.py ${{matrix.arch}})
echo "$TARGETS"
echo "${{matrix.arch}}=$(jq -cn --argjson environments "$TARGETS" '{board: $environments}')" >> $GITHUB_OUTPUT
outputs:
long: ${{ steps.version.outputs.long }}
deb: ${{ steps.version.outputs.deb }}
esp32: ${{ steps.jsonStep.outputs.esp32 }}
esp32s3: ${{ steps.jsonStep.outputs.esp32s3 }}
esp32c3: ${{ steps.jsonStep.outputs.esp32c3 }}
nrf52840: ${{ steps.jsonStep.outputs.nrf52840 }}
rp2040: ${{ steps.jsonStep.outputs.rp2040 }}
stm32: ${{ steps.jsonStep.outputs.stm32 }}
check: ${{ steps.jsonStep.outputs.check }}
check:
needs: setup
strategy:
fail-fast: false
matrix:
check: ${{ fromJson(needs.setup.outputs.check) }}
# Use 'arctastic' self-hosted runner pool when checking in the main repo
runs-on: ${{ github.repository_owner == 'meshtastic' && 'arctastic' || 'ubuntu-latest' }}
if: ${{ github.event_name != 'workflow_dispatch' && github.repository == 'meshtastic/firmware' }}
matrix: ${{ fromJson(needs.setup.outputs.check) }}
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- uses: actions/checkout@v4
- name: Build base
id: base
uses: ./.github/actions/setup-base
- name: Check ${{ matrix.board }}
run: bin/check-all.sh ${{ matrix.board }}
build-esp32:
needs: setup
strategy:
fail-fast: false
matrix: ${{ fromJson(needs.setup.outputs.esp32) }}
uses: ./.github/workflows/build_esp32.yml
with:
board: ${{ matrix.board }}
build-esp32-s3:
needs: setup
strategy:
fail-fast: false
matrix: ${{ fromJson(needs.setup.outputs.esp32s3) }}
uses: ./.github/workflows/build_esp32_s3.yml
with:
board: ${{ matrix.board }}
build-esp32-c3:
needs: setup
strategy:
fail-fast: false
matrix: ${{ fromJson(needs.setup.outputs.esp32c3) }}
uses: ./.github/workflows/build_esp32_c3.yml
with:
board: ${{ matrix.board }}
build-nrf52:
needs: setup
strategy:
fail-fast: false
matrix: ${{ fromJson(needs.setup.outputs.nrf52840) }}
uses: ./.github/workflows/build_nrf52.yml
with:
board: ${{ matrix.board }}
build-rpi2040:
needs: setup
strategy:
fail-fast: false
matrix: ${{ fromJson(needs.setup.outputs.rp2040) }}
uses: ./.github/workflows/build_rpi2040.yml
with:
board: ${{ matrix.board }}
build-stm32:
needs: setup
strategy:
fail-fast: false
matrix: ${{ fromJson(needs.setup.outputs.stm32) }}
uses: ./.github/workflows/build_stm32.yml
with:
board: ${{ matrix.board }}
package-raspbian:
uses: ./.github/workflows/package_raspbian.yml
package-raspbian-armv7l:
uses: ./.github/workflows/package_raspbian_armv7l.yml
package-native:
uses: ./.github/workflows/package_amd64.yml
after-checks:
runs-on: ubuntu-latest
needs: [check]
steps:
- name: Checkout code
uses: actions/checkout@v4
with:
submodules: recursive
ref: ${{github.event.pull_request.head.ref}}
repository: ${{github.event.pull_request.head.repo.full_name}}
- name: Check ${{ matrix.check.board }}
uses: meshtastic/gh-action-firmware@main
with:
pio_platform: ${{ matrix.check.platform }}
pio_env: ${{ matrix.check.board }}
pio_target: check
build:
needs: [setup, version]
strategy:
fail-fast: false
matrix:
build: ${{ fromJson(needs.setup.outputs.all) }}
uses: ./.github/workflows/build_firmware.yml
with:
version: ${{ needs.version.outputs.long }}
pio_env: ${{ matrix.build.board }}
platform: ${{ matrix.build.platform }}
build-debian-src:
if: github.repository == 'meshtastic/firmware'
uses: ./.github/workflows/build_debian_src.yml
with:
series: UNRELEASED
build_location: local
secrets: inherit
package-pio-deps-native-tft:
if: ${{ github.repository == 'meshtastic/firmware' && github.event_name == 'workflow_dispatch' }}
uses: ./.github/workflows/package_pio_deps.yml
with:
pio_env: native-tft
secrets: inherit
test-native:
if: ${{ !contains(github.ref_name, 'event/') && github.repository == 'meshtastic/firmware' }}
uses: ./.github/workflows/test_native.yml
docker:
strategy:
fail-fast: false
matrix:
distro: [debian, alpine]
platform: [linux/amd64, linux/arm64, linux/arm/v7]
pio_env: [native, native-tft]
exclude:
- distro: alpine
platform: linux/arm/v7
- pio_env: native-tft
platform: linux/arm64
- pio_env: native-tft
platform: linux/arm/v7
uses: ./.github/workflows/docker_build.yml
with:
distro: ${{ matrix.distro }}
platform: ${{ matrix.platform }}
runs-on: ${{ contains(matrix.platform, 'arm') && 'ubuntu-24.04-arm' || 'ubuntu-24.04' }}
pio_env: ${{ matrix.pio_env }}
push: false
gather-artifacts:
# trunk-ignore(checkov/CKV2_GHA_1)
if: github.repository == 'meshtastic/firmware'
permissions:
contents: write
pull-requests: write
strategy:
fail-fast: false
matrix:
arch:
- esp32
- esp32s3
- esp32c3
- esp32c6
- nrf52840
- rp2040
- rp2350
- stm32
runs-on: ubuntu-latest
needs: [version, build]
needs:
[
build-esp32,
build-esp32-s3,
build-esp32-c3,
build-nrf52,
build-rpi2040,
build-stm32,
package-raspbian,
package-raspbian-armv7l,
package-native,
]
steps:
- name: Checkout code
uses: actions/checkout@v6
uses: actions/checkout@v4
with:
ref: ${{github.event.pull_request.head.ref}}
repository: ${{github.event.pull_request.head.repo.full_name}}
- uses: actions/download-artifact@v6
- uses: actions/download-artifact@v4
with:
path: ./
pattern: firmware-${{matrix.arch}}-*
merge-multiple: true
- name: Display structure of downloaded files
run: ls -R
- name: Get release version string
run: echo "version=$(./bin/buildinfo.py long)" >> $GITHUB_OUTPUT
id: version
- name: Move files up
run: mv -b -t ./ ./release/meshtasticd_linux_* ./bin/config-dist.yaml ./bin/device-*.sh ./bin/device-*.bat
- name: Repackage in single firmware zip
uses: actions/upload-artifact@v5
uses: actions/upload-artifact@v4
with:
name: firmware-${{matrix.arch}}-${{ needs.version.outputs.long }}
name: firmware-${{ steps.version.outputs.version }}
overwrite: true
path: |
./firmware-*.mt.json
./firmware-*.bin
./firmware-*.uf2
./firmware-*.hex
./firmware-*.zip
./firmware-*-ota.zip
./device-*.sh
./device-*.bat
./meshtasticd_linux_*
./config-dist.yaml
./littlefs-*.bin
./bleota*bin
./Meshtastic_nRF52_factory_erase*.uf2
retention-days: 30
retention-days: 90
- uses: actions/download-artifact@v6
- uses: actions/download-artifact@v4
with:
name: firmware-${{matrix.arch}}-${{ needs.version.outputs.long }}
name: firmware-${{ steps.version.outputs.version }}
merge-multiple: true
path: ./output
@@ -212,207 +202,154 @@ jobs:
- name: Device scripts permissions
run: |
chmod +x ./output/device-install.sh || true
chmod +x ./output/device-update.sh || true
chmod +x ./output/device-install.sh
chmod +x ./output/device-update.sh
- name: Zip firmware
run: zip -j -9 -r ./firmware-${{matrix.arch}}-${{ needs.version.outputs.long }}.zip ./output
run: zip -j -9 -r ./firmware-${{ steps.version.outputs.version }}.zip ./output
- name: Repackage in single elfs zip
uses: actions/upload-artifact@v5
uses: actions/upload-artifact@v4
with:
name: debug-elfs-${{matrix.arch}}-${{ needs.version.outputs.long }}
name: debug-elfs-${{ steps.version.outputs.version }}.zip
overwrite: true
path: ./*.elf
retention-days: 30
- uses: scruplelesswizard/comment-artifact@main
if: ${{ github.event_name == 'pull_request' }}
- name: Create request artifacts
continue-on-error: true # FIXME: Why are we getting 502, but things still work?
if: ${{ github.event_name == 'pull_request_target' || github.event_name == 'pull_request' }}
uses: gavv/pull-request-artifacts@v2.1.0
with:
name: firmware-${{matrix.arch}}-${{ needs.version.outputs.long }}
description: "Download firmware-${{matrix.arch}}-${{ needs.version.outputs.long }}.zip. This artifact will be available for 90 days from creation"
github-token: ${{ secrets.GITHUB_TOKEN }}
commit: ${{ (github.event.pull_request_target || github.event.pull_request).head.sha }}
repo-token: ${{ secrets.GITHUB_TOKEN }}
artifacts-token: ${{ secrets.ARTIFACTS_TOKEN }}
artifacts-repo: meshtastic/artifacts
artifacts-branch: device
artifacts: ./firmware-${{ steps.version.outputs.version }}.zip
release-artifacts:
runs-on: ubuntu-latest
if: ${{ github.event_name == 'workflow_dispatch' && github.repository == 'meshtastic/firmware' }}
outputs:
upload_url: ${{ steps.create_release.outputs.upload_url }}
needs:
- setup
- version
- gather-artifacts
- build-debian-src
- package-pio-deps-native-tft
if: ${{ github.event_name == 'workflow_dispatch' }}
needs: [gather-artifacts, after-checks]
steps:
- name: Checkout
uses: actions/checkout@v6
- name: Create release
uses: softprops/action-gh-release@v2
id: create_release
with:
draft: true
prerelease: true
name: Meshtastic Firmware ${{ needs.version.outputs.long }} Alpha
tag_name: v${{ needs.version.outputs.long }}
body: |
Autogenerated by github action, developer should edit as required before publishing...
- name: Download source deb
uses: actions/download-artifact@v6
with:
pattern: firmware-debian-${{ needs.version.outputs.deb }}~UNRELEASED-src
merge-multiple: true
path: ./output/debian-src
- name: Download `native-tft` pio deps
uses: actions/download-artifact@v6
with:
pattern: platformio-deps-native-tft-${{ needs.version.outputs.long }}
merge-multiple: true
path: ./output/pio-deps-native-tft
- name: Zip Linux sources
working-directory: output
run: |
zip -j -9 -r ./meshtasticd-${{ needs.version.outputs.deb }}-src.zip ./debian-src
zip -9 -r ./platformio-deps-native-tft-${{ needs.version.outputs.long }}.zip ./pio-deps-native-tft
# For diagnostics
- name: Display structure of downloaded files
run: ls -lR
- name: Generate Release manifest
run: |
jq -n --arg ver "${{ needs.version.outputs.long }}" --argjson targets ${{ toJson(needs.setup.outputs.all) }} '{
"version": $ver,
"targets": $targets
}' > firmware-${{ needs.version.outputs.long }}.json
- name: Save Release manifest artifact
uses: actions/upload-artifact@v5
with:
name: manifest-${{ needs.version.outputs.long }}
overwrite: true
path: firmware-${{ needs.version.outputs.long }}.json
- name: Add sources to GitHub Release
# Only run when targeting master branch with workflow_dispatch
if: ${{ github.ref_name == 'master' }}
run: |
gh release upload v${{ needs.version.outputs.long }} ./firmware-${{ needs.version.outputs.long }}.json
gh release upload v${{ needs.version.outputs.long }} ./output/meshtasticd-${{ needs.version.outputs.deb }}-src.zip
gh release upload v${{ needs.version.outputs.long }} ./output/platformio-deps-native-tft-${{ needs.version.outputs.long }}.zip
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
release-firmware:
strategy:
fail-fast: false
matrix:
arch:
- esp32
- esp32s3
- esp32c3
- esp32c6
- nrf52840
- rp2040
- rp2350
- stm32
runs-on: ubuntu-latest
if: ${{ github.event_name == 'workflow_dispatch' && github.repository == 'meshtastic/firmware'}}
needs: [release-artifacts, version]
steps:
- name: Checkout
uses: actions/checkout@v6
uses: actions/checkout@v4
- name: Setup Python
uses: actions/setup-python@v6
uses: actions/setup-python@v5
with:
python-version: 3.x
- uses: actions/download-artifact@v6
- name: Get release version string
run: echo "version=$(./bin/buildinfo.py long)" >> $GITHUB_OUTPUT
id: version
- uses: actions/download-artifact@v4
with:
pattern: firmware-${{matrix.arch}}-${{ needs.version.outputs.long }}
name: firmware-${{ steps.version.outputs.version }}
merge-multiple: true
path: ./output
- uses: actions/download-artifact@v4
with:
pattern: meshtasticd_${{ steps.version.outputs.version }}_*.deb
merge-multiple: true
path: ./output
- name: Display structure of downloaded files
run: ls -lR
run: ls -R
- name: Device scripts permissions
run: |
chmod +x ./output/device-install.sh || true
chmod +x ./output/device-update.sh || true
chmod +x ./output/device-install.sh
chmod +x ./output/device-update.sh
- name: Zip firmware
run: zip -j -9 -r ./firmware-${{matrix.arch}}-${{ needs.version.outputs.long }}.zip ./output
run: zip -j -9 -r ./firmware-${{ steps.version.outputs.version }}.zip ./output -x *.deb
- uses: actions/download-artifact@v6
- uses: actions/download-artifact@v4
with:
name: debug-elfs-${{matrix.arch}}-${{ needs.version.outputs.long }}
name: debug-elfs-${{ steps.version.outputs.version }}.zip
merge-multiple: true
path: ./elfs
- name: Zip debug elfs
run: zip -j -9 -r ./debug-elfs-${{matrix.arch}}-${{ needs.version.outputs.long }}.zip ./elfs
- name: Zip Elfs
run: zip -j -9 -r ./debug-elfs-${{ steps.version.outputs.version }}.zip ./elfs
# For diagnostics
- name: Display structure of downloaded files
- name: Show artifacts
run: ls -lR
- name: Add bins and debug elfs to GitHub Release
# Only run when targeting master branch with workflow_dispatch
if: ${{ github.ref_name == 'master' }}
run: |
gh release upload v${{ needs.version.outputs.long }} ./firmware-${{matrix.arch}}-${{ needs.version.outputs.long }}.zip
gh release upload v${{ needs.version.outputs.long }} ./debug-elfs-${{matrix.arch}}-${{ needs.version.outputs.long }}.zip
- name: Create release
uses: actions/create-release@v1
id: create_release
with:
draft: true
prerelease: true
release_name: Meshtastic Firmware ${{ steps.version.outputs.version }} Alpha
tag_name: v${{ steps.version.outputs.version }}
body: |
Autogenerated by github action, developer should edit as required before publishing...
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
GITHUB_TOKEN: ${{ github.token }}
publish-firmware:
runs-on: ubuntu-24.04
if: ${{ github.event_name == 'workflow_dispatch' }}
needs: [release-firmware, version]
env:
targets: |-
esp32,esp32s3,esp32c3,esp32c6,nrf52840,rp2040,rp2350,stm32
steps:
- name: Checkout
uses: actions/checkout@v6
- name: Setup Python
uses: actions/setup-python@v6
with:
python-version: 3.x
- name: Get firmware artifacts
uses: actions/download-artifact@v6
with:
pattern: firmware-{${{ env.targets }}}-${{ needs.version.outputs.long }}
merge-multiple: true
path: ./publish
- name: Get manifest artifact
uses: actions/download-artifact@v6
with:
pattern: manifest-${{ needs.version.outputs.long }}
path: ./publish
- name: Publish firmware to meshtastic.github.io
uses: peaceiris/actions-gh-pages@v4
- name: Add bins to release
uses: actions/upload-release-asset@v1
env:
# On event/* branches, use the event name as the destination prefix
DEST_PREFIX: ${{ contains(github.ref_name, 'event/') && format('{0}/', github.ref_name) || '' }}
GITHUB_TOKEN: ${{ github.token }}
with:
deploy_key: ${{ secrets.DIST_PAGES_DEPLOY_KEY }}
external_repository: meshtastic/meshtastic.github.io
publish_branch: master
publish_dir: ./publish
destination_dir: ${{ env.DEST_PREFIX }}firmware-${{ needs.version.outputs.long }}
keep_files: true
user_name: github-actions[bot]
user_email: github-actions[bot]@users.noreply.github.com
commit_message: ${{ needs.version.outputs.long }}
enable_jekyll: true
upload_url: ${{ steps.create_release.outputs.upload_url }}
asset_path: ./firmware-${{ steps.version.outputs.version }}.zip
asset_name: firmware-${{ steps.version.outputs.version }}.zip
asset_content_type: application/zip
- name: Add debug elfs to release
uses: actions/upload-release-asset@v1
env:
GITHUB_TOKEN: ${{ github.token }}
with:
upload_url: ${{ steps.create_release.outputs.upload_url }}
asset_path: ./debug-elfs-${{ steps.version.outputs.version }}.zip
asset_name: debug-elfs-${{ steps.version.outputs.version }}.zip
asset_content_type: application/zip
- name: Add raspbian aarch64 .deb
uses: actions/upload-release-asset@v1
env:
GITHUB_TOKEN: ${{ github.token }}
with:
upload_url: ${{ steps.create_release.outputs.upload_url }}
asset_path: ./output/meshtasticd_${{ steps.version.outputs.version }}_arm64.deb
asset_name: meshtasticd_${{ steps.version.outputs.version }}_arm64.deb
asset_content_type: application/vnd.debian.binary-package
- name: Add raspbian armv7l .deb
uses: actions/upload-release-asset@v1
env:
GITHUB_TOKEN: ${{ github.token }}
with:
upload_url: ${{ steps.create_release.outputs.upload_url }}
asset_path: ./output/meshtasticd_${{ steps.version.outputs.version }}_armhf.deb
asset_name: meshtasticd_${{ steps.version.outputs.version }}_armhf.deb
asset_content_type: application/vnd.debian.binary-package
- name: Add raspbian amd64 .deb
uses: actions/upload-release-asset@v1
env:
GITHUB_TOKEN: ${{ github.token }}
with:
upload_url: ${{ steps.create_release.outputs.upload_url }}
asset_path: ./output/meshtasticd_${{ steps.version.outputs.version }}_amd64.deb
asset_name: meshtasticd_${{ steps.version.outputs.version }}_amd64.deb
asset_content_type: application/vnd.debian.binary-package
- name: Bump version.properties
run: >-
bin/bump_version.py
- name: Create version.properties pull request
uses: peter-evans/create-pull-request@v6
with:
add-paths: |
version.properties

View File

@@ -1,371 +0,0 @@
name: Merge Queue
# Not sure how concurrency works in merge_queue, removing for now.
# concurrency:
# group: merge-queue-${{ github.head_ref || github.run_id }}
# cancel-in-progress: true
on:
# Merge group is a special trigger that is used to trigger the workflow when a merge group is created.
merge_group:
jobs:
setup:
strategy:
fail-fast: true
matrix:
arch:
- all
- check
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@v6
- uses: actions/setup-python@v6
with:
python-version: 3.x
cache: pip
- run: pip install -U platformio
- name: Generate matrix
id: jsonStep
run: |
if [[ "$GITHUB_HEAD_REF" == "" ]]; then
TARGETS=$(./bin/generate_ci_matrix.py ${{matrix.arch}})
else
TARGETS=$(./bin/generate_ci_matrix.py ${{matrix.arch}} --level pr)
fi
echo "Name: $GITHUB_REF_NAME Base: $GITHUB_BASE_REF Ref: $GITHUB_REF"
echo "${{matrix.arch}}=$TARGETS" >> $GITHUB_OUTPUT
outputs:
all: ${{ steps.jsonStep.outputs.all }}
check: ${{ steps.jsonStep.outputs.check }}
version:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- name: Get release version string
run: |
echo "long=$(./bin/buildinfo.py long)" >> $GITHUB_OUTPUT
echo "deb=$(./bin/buildinfo.py deb)" >> $GITHUB_OUTPUT
id: version
env:
BUILD_LOCATION: local
outputs:
long: ${{ steps.version.outputs.long }}
deb: ${{ steps.version.outputs.deb }}
check:
needs: setup
strategy:
fail-fast: true
matrix:
check: ${{ fromJson(needs.setup.outputs.check) }}
runs-on: ubuntu-latest
if: ${{ github.event_name != 'workflow_dispatch' }}
steps:
- uses: actions/checkout@v6
- name: Build base
id: base
uses: ./.github/actions/setup-base
- name: Check ${{ matrix.check.board }}
run: bin/check-all.sh ${{ matrix.check.board }}
build:
needs: [setup, version]
strategy:
matrix:
build: ${{ fromJson(needs.setup.outputs.all) }}
uses: ./.github/workflows/build_firmware.yml
with:
version: ${{ needs.version.outputs.long }}
pio_env: ${{ matrix.build.board }}
platform: ${{ matrix.build.platform }}
build-debian-src:
if: github.repository == 'meshtastic/firmware'
uses: ./.github/workflows/build_debian_src.yml
with:
series: UNRELEASED
build_location: local
secrets: inherit
package-pio-deps-native-tft:
if: ${{ github.event_name == 'workflow_dispatch' }}
uses: ./.github/workflows/package_pio_deps.yml
with:
pio_env: native-tft
secrets: inherit
test-native:
if: ${{ !contains(github.ref_name, 'event/') }}
uses: ./.github/workflows/test_native.yml
docker:
strategy:
fail-fast: false
matrix:
distro: [debian, alpine]
platform: [linux/amd64, linux/arm64, linux/arm/v7]
pio_env: [native, native-tft]
exclude:
- distro: alpine
platform: linux/arm/v7
- pio_env: native-tft
platform: linux/arm64
- pio_env: native-tft
platform: linux/arm/v7
uses: ./.github/workflows/docker_build.yml
with:
distro: ${{ matrix.distro }}
platform: ${{ matrix.platform }}
runs-on: ${{ contains(matrix.platform, 'arm') && 'ubuntu-24.04-arm' || 'ubuntu-24.04' }}
pio_env: ${{ matrix.pio_env }}
push: false
gather-artifacts:
# trunk-ignore(checkov/CKV2_GHA_1)
permissions:
contents: write
pull-requests: write
strategy:
fail-fast: false
matrix:
arch:
- esp32
- esp32s3
- esp32c3
- esp32c6
- nrf52840
- rp2040
- rp2350
- stm32
runs-on: ubuntu-latest
needs: [version, build]
steps:
- name: Checkout code
uses: actions/checkout@v6
with:
ref: ${{github.event.pull_request.head.ref}}
repository: ${{github.event.pull_request.head.repo.full_name}}
- uses: actions/download-artifact@v6
with:
path: ./
pattern: firmware-${{matrix.arch}}-*
merge-multiple: true
- name: Display structure of downloaded files
run: ls -R
- name: Move files up
run: mv -b -t ./ ./bin/device-*.sh ./bin/device-*.bat
- name: Repackage in single firmware zip
uses: actions/upload-artifact@v5
with:
name: firmware-${{matrix.arch}}-${{ needs.version.outputs.long }}
overwrite: true
path: |
./firmware-*.bin
./firmware-*.uf2
./firmware-*.hex
./firmware-*.zip
./device-*.sh
./device-*.bat
./littlefs-*.bin
./bleota*bin
./Meshtastic_nRF52_factory_erase*.uf2
retention-days: 30
- uses: actions/download-artifact@v6
with:
name: firmware-${{matrix.arch}}-${{ needs.version.outputs.long }}
merge-multiple: true
path: ./output
# For diagnostics
- name: Show artifacts
run: ls -lR
- name: Device scripts permissions
run: |
chmod +x ./output/device-install.sh || true
chmod +x ./output/device-update.sh || true
- name: Zip firmware
run: zip -j -9 -r ./firmware-${{matrix.arch}}-${{ needs.version.outputs.long }}.zip ./output
- name: Repackage in single elfs zip
uses: actions/upload-artifact@v5
with:
name: debug-elfs-${{matrix.arch}}-${{ needs.version.outputs.long }}
overwrite: true
path: ./*.elf
retention-days: 30
- uses: scruplelesswizard/comment-artifact@main
if: ${{ github.event_name == 'pull_request' }}
with:
name: firmware-${{matrix.arch}}-${{ needs.version.outputs.long }}
description: "Download firmware-${{matrix.arch}}-${{ needs.version.outputs.long }}.zip. This artifact will be available for 90 days from creation"
github-token: ${{ secrets.GITHUB_TOKEN }}
release-artifacts:
runs-on: ubuntu-latest
if: ${{ github.event_name == 'workflow_dispatch' }}
outputs:
upload_url: ${{ steps.create_release.outputs.upload_url }}
needs:
- version
- gather-artifacts
- build-debian-src
- package-pio-deps-native-tft
steps:
- name: Checkout
uses: actions/checkout@v6
- name: Create release
uses: softprops/action-gh-release@v2
id: create_release
with:
draft: true
prerelease: true
name: Meshtastic Firmware ${{ needs.version.outputs.long }} Alpha
tag_name: v${{ needs.version.outputs.long }}
body: |
Autogenerated by github action, developer should edit as required before publishing...
- name: Download source deb
uses: actions/download-artifact@v6
with:
pattern: firmware-debian-${{ needs.version.outputs.deb }}~UNRELEASED-src
merge-multiple: true
path: ./output/debian-src
- name: Download `native-tft` pio deps
uses: actions/download-artifact@v6
with:
pattern: platformio-deps-native-tft-${{ needs.version.outputs.long }}
merge-multiple: true
path: ./output/pio-deps-native-tft
- name: Zip Linux sources
working-directory: output
run: |
zip -j -9 -r ./meshtasticd-${{ needs.version.outputs.deb }}-src.zip ./debian-src
zip -9 -r ./platformio-deps-native-tft-${{ needs.version.outputs.long }}.zip ./pio-deps-native-tft
# For diagnostics
- name: Display structure of downloaded files
run: ls -lR
- name: Add Linux sources to GtiHub Release
# Only run when targeting master branch with workflow_dispatch
if: ${{ github.ref_name == 'master' }}
run: |
gh release upload v${{ needs.version.outputs.long }} ./output/meshtasticd-${{ needs.version.outputs.deb }}-src.zip
gh release upload v${{ needs.version.outputs.long }} ./output/platformio-deps-native-tft-${{ needs.version.outputs.long }}.zip
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
release-firmware:
strategy:
fail-fast: false
matrix:
arch:
- esp32
- esp32s3
- esp32c3
- esp32c6
- nrf52840
- rp2040
- rp2350
- stm32
runs-on: ubuntu-latest
if: ${{ github.event_name == 'workflow_dispatch' }}
needs: [release-artifacts, version]
steps:
- name: Checkout
uses: actions/checkout@v6
- name: Setup Python
uses: actions/setup-python@v6
with:
python-version: 3.x
- uses: actions/download-artifact@v6
with:
pattern: firmware-${{matrix.arch}}-${{ needs.version.outputs.long }}
merge-multiple: true
path: ./output
- name: Display structure of downloaded files
run: ls -lR
- name: Device scripts permissions
run: |
chmod +x ./output/device-install.sh || true
chmod +x ./output/device-update.sh || true
- name: Zip firmware
run: zip -j -9 -r ./firmware-${{matrix.arch}}-${{ needs.version.outputs.long }}.zip ./output
- uses: actions/download-artifact@v6
with:
name: debug-elfs-${{matrix.arch}}-${{ needs.version.outputs.long }}
merge-multiple: true
path: ./elfs
- name: Zip debug elfs
run: zip -j -9 -r ./debug-elfs-${{matrix.arch}}-${{ needs.version.outputs.long }}.zip ./elfs
# For diagnostics
- name: Display structure of downloaded files
run: ls -lR
- name: Add bins and debug elfs to GitHub Release
# Only run when targeting master branch with workflow_dispatch
if: ${{ github.ref_name == 'master' }}
run: |
gh release upload v${{ needs.version.outputs.long }} ./firmware-${{matrix.arch}}-${{ needs.version.outputs.long }}.zip
gh release upload v${{ needs.version.outputs.long }} ./debug-elfs-${{matrix.arch}}-${{ needs.version.outputs.long }}.zip
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
publish-firmware:
runs-on: ubuntu-24.04
if: ${{ github.event_name == 'workflow_dispatch' }}
needs: [release-firmware, version]
env:
targets: |-
esp32,esp32s3,esp32c3,esp32c6,nrf52840,rp2040,rp2350,stm32
steps:
- name: Checkout
uses: actions/checkout@v6
- name: Setup Python
uses: actions/setup-python@v6
with:
python-version: 3.x
- uses: actions/download-artifact@v6
with:
pattern: firmware-{${{ env.targets }}}-${{ needs.version.outputs.long }}
merge-multiple: true
path: ./publish
- name: Publish firmware to meshtastic.github.io
uses: peaceiris/actions-gh-pages@v4
env:
# On event/* branches, use the event name as the destination prefix
DEST_PREFIX: ${{ contains(github.ref_name, 'event/') && format('{0}/', github.ref_name) || '' }}
with:
deploy_key: ${{ secrets.DIST_PAGES_DEPLOY_KEY }}
external_repository: meshtastic/meshtastic.github.io
publish_branch: master
publish_dir: ./publish
destination_dir: ${{ env.DEST_PREFIX }}firmware-${{ needs.version.outputs.long }}
keep_files: true
user_name: github-actions[bot]
user_email: github-actions[bot]@users.noreply.github.com
commit_message: ${{ needs.version.outputs.long }}
enable_jekyll: true

View File

@@ -4,36 +4,16 @@ on:
- cron: 0 8 * * 1-5
workflow_dispatch: {}
permissions: read-all
jobs:
trunk_check:
if: github.repository == 'meshtastic/firmware'
name: Trunk Check and Upload
runs-on: ubuntu-24.04
name: Trunk Check Upload
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v6
uses: actions/checkout@v4
- name: Trunk Check
uses: trunk-io/trunk-action@v1
uses: trunk-io/trunk-action@782e83f803ca6e369f035d64c6ba2768174ba61b
with:
trunk-token: ${{ secrets.TRUNK_TOKEN }}
trunk_upgrade:
if: github.repository == 'meshtastic/firmware'
# See: https://github.com/trunk-io/trunk-action/blob/v1/readme.md#automatic-upgrades
name: Trunk Upgrade (PR)
runs-on: ubuntu-24.04
permissions:
contents: write # For trunk to create PRs
pull-requests: write # For trunk to create PRs
steps:
- name: Checkout
uses: actions/checkout@v6
- name: Trunk Upgrade
uses: trunk-io/trunk-action/upgrade@v1
with:
base: master

78
.github/workflows/package_amd64.yml vendored Normal file
View File

@@ -0,0 +1,78 @@
name: Package Native
on:
workflow_call:
workflow_dispatch:
permissions:
contents: write
packages: write
jobs:
build-native:
uses: ./.github/workflows/build_native.yml
package-native:
runs-on: ubuntu-latest
needs: build-native
steps:
- name: Checkout code
uses: actions/checkout@v4
with:
submodules: recursive
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@master
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
- name: Download artifacts
uses: actions/download-artifact@v4
with:
name: firmware-native-${{ steps.version.outputs.version }}.zip
merge-multiple: true
- name: Display structure of downloaded files
run: ls -R
- name: build .debpkg
run: |
mkdir -p .debpkg/DEBIAN
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_x86_64 .debpkg/usr/sbin/meshtasticd
cp bin/config-dist.yaml .debpkg/etc/meshtasticd/config.yaml
chmod +x .debpkg/usr/sbin/meshtasticd
cp bin/meshtasticd.service .debpkg/usr/lib/systemd/system/meshtasticd.service
echo "/etc/meshtasticd/config.yaml" > .debpkg/DEBIAN/conffiles
chmod +x .debpkg/DEBIAN/conffiles
- uses: jiro4989/build-deb-action@v3
with:
package: meshtasticd
package_root: .debpkg
maintainer: Jonathan Bennett
version: ${{ steps.version.outputs.version }} # refs/tags/v*.*.*
arch: amd64
depends: libyaml-cpp0.7, openssl, libulfius2.7
desc: Native Linux Meshtastic binary.
- uses: actions/upload-artifact@v4
with:
name: meshtasticd_${{ steps.version.outputs.version }}_amd64.deb
overwrite: true
path: |
./*.deb

View File

@@ -1,110 +0,0 @@
name: Package for OpenSUSE Build Service
on:
workflow_call:
secrets:
OBS_PASSWORD:
required: true
PPA_GPG_PRIVATE_KEY:
required: true
inputs:
obs_project:
description: Meshtastic OBS project to target
required: true
type: string
series:
description: Debian series to target
required: true
type: string
permissions:
contents: write
packages: write
jobs:
build-debian-src:
uses: ./.github/workflows/build_debian_src.yml
secrets: inherit
with:
series: ${{ inputs.series }}
build_location: obs
package-obs:
runs-on: ubuntu-24.04
needs: build-debian-src
steps:
- name: Checkout code
uses: actions/checkout@v6
with:
submodules: recursive
path: meshtasticd
ref: ${{github.event.pull_request.head.ref}}
repository: ${{github.event.pull_request.head.repo.full_name}}
- name: Install OpenSUSE Build Service deps
shell: bash
run: |
echo 'deb http://download.opensuse.org/repositories/openSUSE:/Tools/xUbuntu_24.04/ /' | sudo tee /etc/apt/sources.list.d/openSUSE:Tools.list
curl -fsSL https://download.opensuse.org/repositories/openSUSE:Tools/xUbuntu_24.04/Release.key | gpg --dearmor | sudo tee /etc/apt/trusted.gpg.d/openSUSE_Tools.gpg > /dev/null
sudo apt-get update -y --fix-missing
sudo apt-get install -y osc
- name: Get release version string
working-directory: meshtasticd
run: |
echo "deb=$(./bin/buildinfo.py deb)" >> $GITHUB_OUTPUT
env:
BUILD_LOCATION: obs
id: version
- name: Download artifacts
uses: actions/download-artifact@v6
with:
name: firmware-debian-${{ steps.version.outputs.deb }}~${{ inputs.series }}-src
merge-multiple: true
- name: Display structure of downloaded files
run: ls -lah
- name: Configure osc
env:
OBS_USERNAME: meshtastic
run: |
# Setup OpenSUSE Build Service credentials
mkdir -p ~/.config/osc
echo "[general]" > ~/.config/osc/oscrc
echo "apiurl=https://api.opensuse.org" >> ~/.config/osc/oscrc
echo "[https://api.opensuse.org]" >> ~/.config/osc/oscrc
echo "user=${{ env.OBS_USERNAME }}" >> ~/.config/osc/oscrc
echo "pass=${{ secrets.OBS_PASSWORD }}" >> ~/.config/osc/oscrc
echo "credentials_mgr_class=osc.credentials.PlaintextConfigFileCredentialsManager" >> ~/.config/osc/oscrc
# Create a temporary directory for osc checkout
mkdir -p osc
# Intentionally fail if credentials are invalid
# Update secrets if this returns `401`
- name: Verify OBS authentication
run: osc token
- name: Upload package to OBS
shell: bash
working-directory: osc
env:
OBS_PROJECT: ${{ inputs.obs_project }}
OBS_PACKAGE: meshtasticd
run: |
# Initialize the package in the current directory
osc checkout --output-dir . $OBS_PROJECT $OBS_PACKAGE
# Remove the existing package files
rm -rf *.dsc *.tar.xz
# Copy new package files to the directory
cp $GITHUB_WORKSPACE/*.dsc .
cp $GITHUB_WORKSPACE/*.tar.xz .
# Add/Remove the files
osc addremove
# Commit changes and push to OpenSUSE Build Service
osc commit -m "GitHub Actions: ${{ steps.version.outputs.deb }}~${{ inputs.series }}"

View File

@@ -1,65 +0,0 @@
name: Package PlatformIO Library Dependencies
# trunk-ignore-all(checkov/CKV_GHA_7): Allow workflow_dispatch inputs for testing
on:
workflow_call:
inputs:
pio_env:
description: PlatformIO environment to target
required: true
type: string
workflow_dispatch:
inputs:
pio_env:
description: PlatformIO environment to target
required: true
type: string
permissions:
contents: write
packages: write
jobs:
pkg-pio-libdeps:
runs-on: ubuntu-24.04
steps:
- name: Checkout code
uses: actions/checkout@v6
with:
submodules: recursive
ref: ${{github.event.pull_request.head.ref}}
repository: ${{github.event.pull_request.head.repo.full_name}}
- name: Setup Python
uses: actions/setup-python@v6
with:
python-version: 3.x
- name: Install deps
shell: bash
run: |
pip install platformio
- name: Get release version string
run: |
echo "long=$(./bin/buildinfo.py long)" >> $GITHUB_OUTPUT
id: version
- name: Fetch libdeps
shell: bash
run: |-
platformio pkg install -e ${{ inputs.pio_env }}
platformio pkg install -e ${{ inputs.pio_env }} -t platformio/tool-scons@4.40502.0
env:
PLATFORMIO_LIBDEPS_DIR: pio/libdeps
PLATFORMIO_PACKAGES_DIR: pio/packages
PLATFORMIO_CORE_DIR: pio/core
- name: Store binaries as an artifact
uses: actions/upload-artifact@v5
with:
name: platformio-deps-${{ inputs.pio_env }}-${{ steps.version.outputs.long }}
overwrite: true
include-hidden-files: true
path: |
pio/*

View File

@@ -1,74 +0,0 @@
name: Package for Launchpad PPA
on:
workflow_call:
secrets:
PPA_GPG_PRIVATE_KEY:
required: true
inputs:
ppa_repo:
description: Meshtastic PPA to target
required: true
type: string
series:
description: Ubuntu series to target
required: true
type: string
permissions:
contents: write
packages: write
jobs:
build-debian-src:
uses: ./.github/workflows/build_debian_src.yml
secrets: inherit
with:
series: ${{ inputs.series }}
build_location: ppa
package-ppa:
runs-on: ubuntu-24.04
needs: build-debian-src
steps:
- name: Checkout code
uses: actions/checkout@v6
with:
submodules: recursive
path: meshtasticd
ref: ${{github.event.pull_request.head.ref}}
repository: ${{github.event.pull_request.head.repo.full_name}}
- name: Install deps
shell: bash
run: |
sudo apt-get update -y --fix-missing
sudo apt-get install -y dput
- name: Import GPG key
uses: crazy-max/ghaction-import-gpg@v6
with:
gpg_private_key: ${{ secrets.PPA_GPG_PRIVATE_KEY }}
id: gpg
- name: Get release version string
working-directory: meshtasticd
run: |
echo "deb=$(./bin/buildinfo.py deb)" >> $GITHUB_OUTPUT
env:
BUILD_LOCATION: ppa
id: version
- name: Download artifacts
uses: actions/download-artifact@v6
with:
name: firmware-debian-${{ steps.version.outputs.deb }}~${{ inputs.series }}-src
merge-multiple: true
- name: Display structure of downloaded files
run: ls -lah
- name: Publish with dput
if: ${{ github.event_name != 'pull_request_target' && github.event_name != 'pull_request' }}
run: |
dput ${{ inputs.ppa_repo }} meshtasticd_${{ steps.version.outputs.deb }}~${{ inputs.series }}_source.changes

78
.github/workflows/package_raspbian.yml vendored Normal file
View File

@@ -0,0 +1,78 @@
name: Package Raspbian
on:
workflow_call:
workflow_dispatch:
permissions:
contents: write
packages: write
jobs:
build-raspbian:
uses: ./.github/workflows/build_raspbian.yml
package-raspbian:
runs-on: ubuntu-latest
needs: build-raspbian
steps:
- name: Checkout code
uses: actions/checkout@v4
with:
submodules: recursive
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@master
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
- name: Download artifacts
uses: actions/download-artifact@v4
with:
name: firmware-raspbian-${{ steps.version.outputs.version }}.zip
merge-multiple: true
- name: Display structure of downloaded files
run: ls -R
- name: build .debpkg
run: |
mkdir -p .debpkg/DEBIAN
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
cp bin/meshtasticd.service .debpkg/usr/lib/systemd/system/meshtasticd.service
echo "/etc/meshtasticd/config.yaml" > .debpkg/DEBIAN/conffiles
chmod +x .debpkg/DEBIAN/conffiles
- uses: jiro4989/build-deb-action@v3
with:
package: meshtasticd
package_root: .debpkg
maintainer: Jonathan Bennett
version: ${{ steps.version.outputs.version }} # refs/tags/v*.*.*
arch: arm64
depends: libyaml-cpp0.7, openssl, libulfius2.7
desc: Native Linux Meshtastic binary.
- uses: actions/upload-artifact@v4
with:
name: meshtasticd_${{ steps.version.outputs.version }}_arm64.deb
overwrite: true
path: |
./*.deb

View File

@@ -0,0 +1,78 @@
name: Package Raspbian
on:
workflow_call:
workflow_dispatch:
permissions:
contents: write
packages: write
jobs:
build-raspbian_armv7l:
uses: ./.github/workflows/build_raspbian_armv7l.yml
package-raspbian_armv7l:
runs-on: ubuntu-latest
needs: build-raspbian_armv7l
steps:
- name: Checkout code
uses: actions/checkout@v4
with:
submodules: recursive
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@master
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
- name: Download artifacts
uses: actions/download-artifact@v4
with:
name: firmware-raspbian-armv7l-${{ steps.version.outputs.version }}.zip
merge-multiple: true
- name: Display structure of downloaded files
run: ls -R
- name: build .debpkg
run: |
mkdir -p .debpkg/DEBIAN
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_armv7l .debpkg/usr/sbin/meshtasticd
cp bin/config-dist.yaml .debpkg/etc/meshtasticd/config.yaml
chmod +x .debpkg/usr/sbin/meshtasticd
cp bin/meshtasticd.service .debpkg/usr/lib/systemd/system/meshtasticd.service
echo "/etc/meshtasticd/config.yaml" > .debpkg/DEBIAN/conffiles
chmod +x .debpkg/DEBIAN/conffiles
- uses: jiro4989/build-deb-action@v3
with:
package: meshtasticd
package_root: .debpkg
maintainer: Jonathan Bennett
version: ${{ steps.version.outputs.version }} # refs/tags/v*.*.*
arch: armhf
depends: libyaml-cpp0.7, openssl, libulfius2.7
desc: Native Linux Meshtastic binary.
- uses: actions/upload-artifact@v4
with:
name: meshtasticd_${{ steps.version.outputs.version }}_armhf.deb
overwrite: true
path: |
./*.deb

View File

@@ -1,24 +0,0 @@
name: Check PR Labels
on:
pull_request:
types: [opened, edited, labeled, unlabeled, synchronize, reopened]
permissions:
pull-requests: read
contents: read
jobs:
check-label:
runs-on: ubuntu-latest
steps:
- name: Check for PR labels
uses: actions/github-script@v8
with:
script: |
const labels = context.payload.pull_request.labels.map(label => label.name);
const requiredLabels = ['bugfix', 'enhancement', 'hardware-support', 'dependencies', 'submodules', 'github_actions', 'trunk', 'cleanup'];
const hasRequiredLabel = labels.some(label => requiredLabels.includes(label));
if (!hasRequiredLabel) {
core.setFailed(`PR must have at least one of the following labels before it can be merged: ${requiredLabels.join(', ')}.`);
}

View File

@@ -1,238 +0,0 @@
name: Tests
# DISABLED: Changed from automatic PR triggers to manual only
on:
workflow_dispatch:
inputs:
reason:
description: "Reason for manual test run"
required: false
default: "Manual test execution"
concurrency:
group: tests-${{ github.head_ref || github.run_id }}
cancel-in-progress: true
permissions:
contents: read
actions: read
checks: write
pull-requests: write
jobs:
native-tests:
name: "🧪 Native Tests"
if: github.repository == 'meshtastic/firmware'
uses: ./.github/workflows/test_native.yml
permissions:
contents: read
actions: read
checks: write
test-summary:
name: "📊 Test Results"
runs-on: ubuntu-latest
needs: [native-tests]
if: always()
permissions:
contents: read
actions: read
checks: write
pull-requests: write
steps:
- uses: actions/checkout@v6
with:
submodules: recursive
- name: Get release version string
run: echo "long=$(./bin/buildinfo.py long)" >> $GITHUB_OUTPUT
id: version
- name: Download test artifacts
if: needs.native-tests.result != 'skipped'
uses: actions/download-artifact@v6
with:
name: platformio-test-report-${{ steps.version.outputs.long }}
merge-multiple: true
- name: Parse test results and create detailed summary
id: test-results
run: |
echo "## 🧪 Test Results Summary" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
# Check overall job status first
if [[ "${{ needs.native-tests.result }}" == "success" ]]; then
echo "✅ **Overall Status**: PASSED" >> $GITHUB_STEP_SUMMARY
elif [[ "${{ needs.native-tests.result }}" == "failure" ]]; then
echo "❌ **Overall Status**: FAILED" >> $GITHUB_STEP_SUMMARY
elif [[ "${{ needs.native-tests.result }}" == "cancelled" ]]; then
echo "⏸️ **Overall Status**: CANCELLED" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "Tests were cancelled before completion." >> $GITHUB_STEP_SUMMARY
exit 0
else
echo "⚠️ **Overall Status**: SKIPPED" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "Tests were skipped." >> $GITHUB_STEP_SUMMARY
exit 0
fi
echo "" >> $GITHUB_STEP_SUMMARY
# Parse detailed test results if available
if [ -f "testreport.xml" ]; then
echo "### 🔍 Individual Test Results" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
python3 << 'EOF'
import xml.etree.ElementTree as ET
import os
try:
tree = ET.parse('testreport.xml')
root = tree.getroot()
total_tests = 0
passed_tests = 0
failed_tests = 0
skipped_tests = 0
# Parse testsuite elements
for testsuite in root.findall('.//testsuite'):
suite_name = testsuite.get('name', 'Unknown')
suite_tests = int(testsuite.get('tests', '0'))
suite_failures = int(testsuite.get('failures', '0'))
suite_errors = int(testsuite.get('errors', '0'))
suite_skipped = int(testsuite.get('skipped', '0'))
total_tests += suite_tests
failed_tests += suite_failures + suite_errors
skipped_tests += suite_skipped
passed_tests += suite_tests - suite_failures - suite_errors - suite_skipped
if suite_tests > 0:
status = "✅" if (suite_failures + suite_errors) == 0 else "❌"
print(f"**{status} Test Suite: {suite_name}**")
print(f"- Total: {suite_tests}")
print(f"- Passed: ✅ {suite_tests - suite_failures - suite_errors - suite_skipped}")
print(f"- Failed: ❌ {suite_failures + suite_errors}")
if suite_skipped > 0:
print(f"- Skipped: ⏭️ {suite_skipped}")
print("")
# Show individual test results for failed suites
if suite_failures + suite_errors > 0:
print("**Failed Tests:**")
for testcase in testsuite.findall('testcase'):
test_name = testcase.get('name', 'Unknown')
failure = testcase.find('failure')
error = testcase.find('error')
if failure is not None:
msg = failure.get('message', 'Unknown error')[:100]
print(f"- ❌ `{test_name}`: {msg}")
elif error is not None:
msg = error.get('message', 'Unknown error')[:100]
print(f"- ❌ `{test_name}`: ERROR - {msg}")
print("")
else:
# Show passed tests for successful suites
passed_count = 0
for testcase in testsuite.findall('testcase'):
if testcase.find('failure') is None and testcase.find('error') is None:
if passed_count < 5: # Limit to first 5 to avoid spam
test_name = testcase.get('name', 'Unknown')
print(f"- ✅ `{test_name}`: PASSED")
passed_count += 1
if passed_count > 5:
print(f"- ... and {passed_count - 5} more tests passed")
print("")
# Summary statistics
print("### 📊 Test Statistics")
print(f"- **Total Tests**: {total_tests}")
print(f"- **Passed**: ✅ {passed_tests}")
print(f"- **Failed**: ❌ {failed_tests}")
if skipped_tests > 0:
print(f"- **Skipped**: ⏭️ {skipped_tests}")
if failed_tests > 0:
print(f"\n❌ **{failed_tests} tests failed out of {total_tests} total**")
else:
print(f"\n✅ **All {total_tests} tests passed!**")
except Exception as e:
print(f"❌ Error parsing test results: {e}")
EOF
else
echo "⚠️ **No detailed test report available**" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "Test artifacts may not have been generated properly." >> $GITHUB_STEP_SUMMARY
fi
echo "" >> $GITHUB_STEP_SUMMARY
echo "---" >> $GITHUB_STEP_SUMMARY
echo "View detailed logs in the [Actions tab](${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }})" >> $GITHUB_STEP_SUMMARY
- name: Comment test results on PR
if: github.event_name == 'pull_request' && needs.native-tests.result != 'skipped'
uses: actions/github-script@v8
with:
script: |
const fs = require('fs');
// Read the step summary to use as PR comment
let testSummary = "## 🧪 Test Results Summary\n\n";
if ("${{ needs.native-tests.result }}" === "success") {
testSummary += "✅ **All tests passed!**\n\n";
} else if ("${{ needs.native-tests.result }}" === "failure") {
testSummary += "❌ **Some tests failed.**\n\n";
} else {
testSummary += "⚠️ **Tests did not complete normally.**\n\n";
}
testSummary += `View detailed results: [Actions Run](${context.payload.repository.html_url}/actions/runs/${context.runId})\n\n`;
testSummary += "---\n";
testSummary += "*This comment will be automatically updated when new commits are pushed.*";
// Find existing comment
const comments = await github.rest.issues.listComments({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.issue.number
});
const botComment = comments.data.find(comment =>
comment.user.type === 'Bot' &&
comment.body.includes('🧪 Test Results Summary')
);
if (botComment) {
// Update existing comment
await github.rest.issues.updateComment({
owner: context.repo.owner,
repo: context.repo.repo,
comment_id: botComment.id,
body: testSummary
});
} else {
// Create new comment
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.issue.number,
body: testSummary
});
}
- name: Set overall status
run: |
if [[ "${{ needs.native-tests.result }}" == "success" ]]; then
echo "All tests passed! ✅"
exit 0
else
echo "Some tests failed! ❌"
exit 1
fi

View File

@@ -1,115 +0,0 @@
name: Trigger release workflows upon Publish
on:
release:
types: [published, released]
permissions:
contents: write
packages: write
jobs:
build-docker:
uses: ./.github/workflows/docker_manifest.yml
with:
release_channel: |-
${{ contains(github.event.release.name, 'Beta') && 'beta' || contains(github.event.release.name, 'Alpha') && 'alpha' }}
secrets: inherit
package-ppa:
strategy:
fail-fast: false
matrix:
series:
- jammy # 22.04 LTS
- noble # 24.04 LTS
- plucky # 25.04
- questing # 25.10
uses: ./.github/workflows/package_ppa.yml
with:
ppa_repo: |-
ppa:meshtastic/${{ contains(github.event.release.name, 'Beta') && 'beta' || contains(github.event.release.name, 'Alpha') && 'alpha' }}
series: ${{ matrix.series }}
secrets: inherit
package-obs:
uses: ./.github/workflows/package_obs.yml
with:
obs_project: |-
network:Meshtastic:${{ contains(github.event.release.name, 'Beta') && 'beta' || contains(github.event.release.name, 'Alpha') && 'alpha' }}
series: |-
${{ contains(github.event.release.name, 'Beta') && 'beta' || contains(github.event.release.name, 'Alpha') && 'alpha' }}
secrets: inherit
hook-copr:
uses: ./.github/workflows/hook_copr.yml
with:
copr_project: |-
${{ contains(github.event.release.name, 'Beta') && 'beta' || contains(github.event.release.name, 'Alpha') && 'alpha' }}
secrets: inherit
# Create a PR to bump version when a release is Published
bump-version:
if: github.event.action == 'published'
runs-on: ubuntu-latest
permissions:
pull-requests: write
contents: write
defaults:
run:
shell: bash
steps:
- name: Checkout
uses: actions/checkout@v6
with:
# Always use master branch for version bumps
ref: master
- name: Setup Python
uses: actions/setup-python@v6
with:
python-version: 3.x
- name: Bump version.properties
run: |
# Bump version.properties
chmod +x ./bin/bump_version.py
./bin/bump_version.py
- name: Get new release version string
run: |
echo "short=$(./bin/buildinfo.py short)" >> $GITHUB_OUTPUT
id: new_version
- name: Ensure debian deps are installed
run: |
sudo apt-get update -y --fix-missing
sudo apt-get install -y devscripts
- name: Update debian changelog
run: |
# Update debian changelog
chmod +x ./debian/ci_changelog.sh
./debian/ci_changelog.sh
- name: Bump org.meshtastic.meshtasticd.metainfo.xml
run: |
# Bump org.meshtastic.meshtasticd.metainfo.xml
pip install -r bin/bump_metainfo/requirements.txt -q
chmod +x ./bin/bump_metainfo/bump_metainfo.py
./bin/bump_metainfo/bump_metainfo.py --file bin/org.meshtastic.meshtasticd.metainfo.xml "${{ steps.new_version.outputs.short }}"
env:
PIP_DISABLE_PIP_VERSION_CHECK: 1
- name: Create Bumps pull request
uses: peter-evans/create-pull-request@v8
with:
base: ${{ github.event.repository.default_branch }}
branch: create-pull-request/bump-version
labels: github_actions
title: Bump release version
commit-message: Automated version bumps
add-paths: |
version.properties
debian/changelog
bin/org.meshtastic.meshtasticd.metainfo.xml

View File

@@ -0,0 +1,41 @@
---
name: Flawfinder Scan
on:
push:
branches: [master, develop]
paths-ignore:
- "**.md"
- "version.properties"
jobs:
flawfinder:
runs-on: ubuntu-latest
name: Flawfinder
steps:
# step 1
- name: clone application source code
uses: actions/checkout@v4
# step 2
- name: flawfinder_scan
uses: david-a-wheeler/flawfinder@2.0.19
with:
arguments: "--sarif ./"
output: "flawfinder_report.sarif"
# step 3
- name: save report as pipeline artifact
uses: actions/upload-artifact@v4
with:
name: flawfinder_report.sarif
overwrite: true
path: flawfinder_report.sarif
# step 4
- name: publish code scanning alerts
uses: github/codeql-action/upload-sarif@v3
with:
sarif_file: flawfinder_report.sarif
category: flawfinder

View File

@@ -3,25 +3,21 @@ name: Semgrep Full Scan
on:
workflow_dispatch:
branches:
- master
schedule:
- cron: 0 1 * * 6
permissions:
actions: read
contents: read
security-events: write
- cron: "0 1 * * 6"
jobs:
semgrep-full:
if: github.repository == 'meshtastic/firmware'
runs-on: ubuntu-24.04
runs-on: ubuntu-latest
container:
image: semgrep/semgrep
image: returntocorp/semgrep
steps:
# step 1
- name: clone application source code
uses: actions/checkout@v6
uses: actions/checkout@v4
# step 2
- name: full scan
@@ -33,7 +29,7 @@ jobs:
# step 3
- name: save report as pipeline artifact
uses: actions/upload-artifact@v5
uses: actions/upload-artifact@v4
with:
name: report.sarif
overwrite: true
@@ -41,7 +37,7 @@ jobs:
# step 4
- name: publish code scanning alerts
uses: github/codeql-action/upload-sarif@v4
uses: github/codeql-action/upload-sarif@v3
with:
sarif_file: report.sarif
category: semgrep

View File

@@ -2,18 +2,16 @@
name: Semgrep Differential Scan
on: pull_request
permissions: read-all
jobs:
semgrep-diff:
runs-on: ubuntu-24.04
runs-on: ubuntu-latest
container:
image: semgrep/semgrep
image: returntocorp/semgrep
steps:
# step 1
- name: clone application source code
uses: actions/checkout@v6
uses: actions/checkout@v4
with:
fetch-depth: 0

View File

@@ -1,26 +0,0 @@
name: process stale Issues and PR's
on:
schedule:
- cron: 0 6 * * *
workflow_dispatch: {}
permissions:
issues: write
pull-requests: write
actions: write
jobs:
stale_issues:
if: github.repository == 'meshtastic/firmware'
name: Close Stale Issues
runs-on: ubuntu-latest
steps:
- name: Stale PR+Issues
uses: actions/stale@v10.1.1
with:
days-before-stale: 45
stale-issue-message: This issue has not had any comment or update in the last month. If it is still relevant, please post update comments. If no comments are made, this issue will be closed automagically in 7 days.
close-issue-message: This issue has not had any comment since the last notice. It has been closed automatically. If this is incorrect, or the issue becomes relevant again, please request that it is reopened.
exempt-issue-labels: pinned,3.0,triaged,backlog
exempt-pr-labels: pinned,3.0,triaged,backlog

View File

@@ -1,169 +0,0 @@
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@v6
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/meshtasticd -s &
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 "long=$(./bin/buildinfo.py long)" >> $GITHUB_OUTPUT
id: version
- name: Save coverage information
uses: actions/upload-artifact@v5
if: always() # run this step even if previous step failed
with:
name: lcov-coverage-info-native-simulator-test-${{ steps.version.outputs.long }}
overwrite: true
path: ./coverage_*.info
platformio-tests:
name: Native PlatformIO Tests
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
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 "long=$(./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 -v --junit-output-path testreport.xml
- name: Save test results
if: always() # run this step even if previous step failed
uses: actions/upload-artifact@v5
with:
name: platformio-test-report-${{ steps.version.outputs.long }}
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@v5
if: always() # run this step even if previous step failed
with:
name: lcov-coverage-info-native-platformio-tests-${{ steps.version.outputs.long }}
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@v6
with:
ref: ${{github.event.pull_request.head.ref}}
repository: ${{github.event.pull_request.head.repo.full_name}}
- name: Get release version string
run: echo "long=$(./bin/buildinfo.py long)" >> $GITHUB_OUTPUT
id: version
- name: Download test artifacts
uses: actions/download-artifact@v6
with:
name: platformio-test-report-${{ steps.version.outputs.long }}
merge-multiple: true
- name: Test Report
uses: dorny/test-reporter@v2.3.0
with:
name: PlatformIO Tests
path: testreport.xml
reporter: java-junit
- name: Download coverage artifacts
uses: actions/download-artifact@v6
with:
pattern: lcov-coverage-info-native-*-${{ steps.version.outputs.long }}
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@v5
with:
name: code-coverage-report-${{ steps.version.outputs.long }}
path: code-coverage-report

57
.github/workflows/test_simulator.yml vendored Normal file
View File

@@ -0,0 +1,57 @@
name: Test Simulator
on:
schedule:
- cron: "0 0 * * *" # Run every day at midnight
workflow_dispatch: {}
jobs:
test-simulator:
runs-on: ubuntu-latest
steps:
- name: Install libbluetooth
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
- 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
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
run: platformio run -e native
- name: Integration test
run: |
.pio/build/native/program & sleep 10 # 5 seconds was not enough
echo "Simulator started, launching python test..."
python3 -c 'from meshtastic.test import testSimulator; testSimulator()'
- name: PlatformIO Tests
run: platformio test -e native --junit-output-path testreport.xml
- 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

View File

@@ -1,66 +0,0 @@
name: End to end tests
on:
schedule:
- cron: 0 0 * * * # Run every day at midnight
workflow_dispatch: {}
permissions:
contents: read
actions: read
checks: write
jobs:
native-tests:
if: github.repository == 'meshtastic/firmware'
uses: ./.github/workflows/test_native.yml
hardware-tests:
if: github.repository == 'meshtastic/firmware'
runs-on: test-runner
steps:
- name: Checkout code
uses: actions/checkout@v6
# - uses: actions/setup-python@v6
# with:
# python-version: '3.10'
# pipx install "setuptools<72"
- name: Upgrade python tools
shell: bash
run: |
pipx install adafruit-nrfutil
pipx install poetry
pipx install meshtastic --pip-args=--pre
- name: Install PlatformIO from script
shell: bash
run: |
curl -fsSL -o get-platformio.py https://raw.githubusercontent.com/platformio/platformio-core-installer/master/get-platformio.py
python3 get-platformio.py
- name: Upgrade platformio
shell: bash
run: |
export PATH=$PATH:$HOME/.local/bin
pio upgrade
- name: Setup Node
uses: actions/setup-node@v6
with:
node-version: 24
- name: Setup pnpm
uses: pnpm/action-setup@v4
with:
version: latest
- name: Install dependencies, setup devices and run
shell: bash
run: |
git submodule update --init --recursive
cd meshtestic/
pnpm install
pnpm run setup
pnpm run test

View File

@@ -9,16 +9,14 @@ permissions: read-all
jobs:
trunk_check:
name: Trunk Check Runner
runs-on: ubuntu-24.04
runs-on: ubuntu-latest
permissions:
checks: write # For trunk to post annotations
contents: read # For repo checkout
steps:
- name: Checkout
uses: actions/checkout@v6
uses: actions/checkout@v4
- name: Trunk Check
uses: trunk-io/trunk-action@v1
with:
save-annotations: true

View File

@@ -1,26 +0,0 @@
name: Annotate PR with trunk issues
# See: https://github.com/trunk-io/trunk-action/blob/v1/readme.md#getting-inline-annotations-for-fork-prs
on:
workflow_run:
workflows: [Pull Request] # Name from `trunk_check.yml`
types: [completed]
permissions: read-all
jobs:
trunk_check:
name: Trunk Code Quality Annotate
runs-on: ubuntu-24.04
permissions:
checks: write # For trunk to post annotations
contents: read # For repo checkout
steps:
- name: Checkout
uses: actions/checkout@v6
- name: Trunk Check
uses: trunk-io/trunk-action@v1
with:
post-annotations: true

View File

@@ -1,51 +0,0 @@
name: Run Trunk Fmt on PR Comment
on:
issue_comment:
types: [created]
permissions: read-all
jobs:
trunk-fmt:
if: github.event.issue.pull_request != null && contains(github.event.comment.body, 'trunk fmt')
runs-on: ubuntu-latest
permissions:
contents: write
pull-requests: write
steps:
- name: Checkout repository
uses: actions/checkout@v6
with:
ref: ${{github.event.pull_request.head.ref}}
repository: ${{github.event.pull_request.head.repo.full_name}}
- name: Install trunk
run: curl https://get.trunk.io -fsSL | bash
- name: Run Trunk Fmt
run: trunk fmt
- name: Get release version string
run: echo "long=$(./bin/buildinfo.py long)" >> $GITHUB_OUTPUT
id: version
- name: Commit and push changes
run: |
git config --global user.name "github-actions[bot]"
git config --global user.email "github-actions[bot]@users.noreply.github.com"
git add .
git commit -m "Add firmware version ${{ steps.version.outputs.long }}"
git push
- name: Comment on PR
uses: actions/github-script@v8
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
script: |
github.issues.createComment({
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
body: '`trunk fmt` has been run on this PR.'
})

View File

@@ -1,42 +1,33 @@
name: Update protobufs and regenerate classes
name: "Update protobufs and regenerate classes"
on: workflow_dispatch
permissions: read-all
jobs:
update-protobufs:
runs-on: ubuntu-latest
permissions:
contents: write
pull-requests: write
steps:
- name: Checkout code
uses: actions/checkout@v6
uses: actions/checkout@v4
with:
submodules: true
- name: Update submodule
if: ${{ github.ref == 'refs/heads/master' }}
run: |
git submodule update --remote protobufs
- name: Download nanopb
run: |
wget https://jpa.kapsi.fi/nanopb/download/nanopb-0.4.9.1-linux-x86.tar.gz
tar xvzf nanopb-0.4.9.1-linux-x86.tar.gz
mv nanopb-0.4.9.1-linux-x86 nanopb-0.4.9
wget https://jpa.kapsi.fi/nanopb/download/nanopb-0.4.8-linux-x86.tar.gz
tar xvzf nanopb-0.4.8-linux-x86.tar.gz
mv nanopb-0.4.8-linux-x86 nanopb-0.4.8
- name: Re-generate protocol buffers
run: |
./bin/regen-protos.sh
- name: Create pull request
uses: peter-evans/create-pull-request@v8
uses: peter-evans/create-pull-request@v6
with:
branch: create-pull-request/update-protobufs
labels: submodules
title: Update protobufs and classes
commit-message: Update protobufs
add-paths: |
protobufs
src/mesh

14
.gitignore vendored
View File

@@ -1,8 +1,6 @@
.pio
pio
pio.tar
web
web.tar
main/configuration.h
main/credentials.h
# ignore vscode IDE settings files
.vscode/*
@@ -12,9 +10,6 @@ web.tar
*.code-workspace
.idea
.platformio
.local
.cache
.DS_Store
Thumbs.db
@@ -37,7 +32,4 @@ release/
.vscode/extensions.json
/compile_commands.json
src/mesh/raspihttp/certificate.pem
src/mesh/raspihttp/private_key.pem
# Ignore logo (set at build time with platformio-custom.py)
data/boot/logo.*
src/mesh/raspihttp/private_key.pem

3
.gitmodules vendored
View File

@@ -1,6 +1,3 @@
[submodule "protobufs"]
path = protobufs
url = https://github.com/meshtastic/protobufs.git
[submodule "meshtestic"]
path = meshtestic
url = https://github.com/meshtastic/meshTestic

View File

@@ -8,4 +8,3 @@ line_length: false
spaces: false
url: false
whitespace: false
headings: false

View File

@@ -1 +0,0 @@
renovate.json

View File

@@ -1,10 +0,0 @@
{
"overrides": [
{
"files": "userPrefs.jsonc",
"options": {
"trailingComma": "none"
}
}
]
}

View File

@@ -1,35 +1,36 @@
version: 0.1
cli:
version: 1.25.0
version: 1.22.2
plugins:
sources:
- id: trunk
ref: v1.7.4
ref: v1.5.0
uri: https://github.com/trunk-io/plugins
lint:
enabled:
- checkov@3.2.495
- renovate@42.48.0
- prettier@3.7.4
- trufflehog@3.92.3
- yamllint@1.37.1
- bandit@1.9.2
- trivy@0.68.1
- taplo@0.10.0
- ruff@0.14.9
- isort@7.0.0
- markdownlint@0.47.0
- oxipng@10.0.0
- svgo@4.0.0
- actionlint@1.7.9
- flake8@7.3.0
- hadolint@2.14.0
- trufflehog@3.76.3
- yamllint@1.35.1
- bandit@1.7.8
- checkov@3.2.95
- terrascan@1.19.1
- trivy@0.51.1
#- trufflehog@3.63.2-rc0
- taplo@0.8.1
- ruff@0.4.4
- isort@5.13.2
- markdownlint@0.40.0
- oxipng@9.1.1
- svgo@3.3.2
- actionlint@1.7.0
- flake8@7.0.0
- hadolint@2.12.0
- shfmt@3.6.0
- shellcheck@0.11.0
- black@25.12.0
- shellcheck@0.10.0
- black@24.4.2
- git-diff-check
- gitleaks@8.30.0
- gitleaks@8.18.2
- clang-format@16.0.3
- prettier@3.2.5
ignore:
- linters: [ALL]
paths:
@@ -38,7 +39,7 @@ runtimes:
enabled:
- python@3.10.8
- go@1.21.0
- node@22.16.0
- node@18.12.1
actions:
disabled:
- trunk-announce

View File

@@ -2,9 +2,8 @@
// See http://go.microsoft.com/fwlink/?LinkId=827846
// for the documentation about the extensions.json format
"recommendations": [
"platformio.platformio-ide"
"ms-vscode.cpptools",
"platformio.platformio-ide",
"trunk.io"
],
"unwantedRecommendations": [
"ms-vscode.cpptools-extension-pack"
]
}

View File

@@ -7,8 +7,5 @@
"cmake.configureOnOpen": false,
"[cpp]": {
"editor.defaultFormatter": "trunk.io"
},
"[powershell]": {
"editor.defaultFormatter": "ms-vscode.powershell"
}
}

View File

@@ -1,4 +0,0 @@
# Contributor Covenant Code of Conduct
The Meshtastic Firmware project is subject to the code of conduct for the parent project, which can be found here:
https://meshtastic.org/docs/legal/conduct/

View File

@@ -1,47 +0,0 @@
# Contributing to Meshtastic Firmware
We're excited that you're interested in contributing to the Meshtastic firmware! This document provides a high-level overview of how you can get involved.
## Important First Steps
Before you begin, please:
1. **Read our documentation**: Our [official documentation](https://meshtastic.org/docs/) is a crucial resource. It contains essential information about the project.
2. **Check out the firmware build guide**: For specific instructions on setting up your development environment and building the firmware, refer to our [Firmware Build Guide](https://meshtastic.org/docs/development/firmware/build/).
3. Read our [Code of Conduct](https://meshtastic.org/docs/legal/conduct/)
4. Join our [Discord community](https://discord.com/invite/ktMAKGBnBs) to connect with developers and other contributors to get help.
## Getting Help and Discussing Ideas
We encourage open communication and discussion before diving into code changes:
1. **Use GitHub Discussions**: For new ideas, questions, or to discuss potential changes, start a conversation in our [GitHub Discussions](https://github.com/meshtastic/firmware/discussions) first. This helps us collaborate and avoid duplicate work.
2. **Join our Discord**: For real-time chat and quick questions, join our [Discord server](https://discord.com/invite/ktMAKGBnBs). It's a great place to get help and connect with other developers and the community.
3. **Reporting Issues**: If you've identified a bug, please use our bug report template when creating a new issue in the [issue tracker](https://github.com/meshtastic/firmware/issues). Ensure you've searched existing issues to avoid duplicates.
## Making Contributions
> [!IMPORTANT]
> Before making any contributions, you must sign our Contributor License Agreement (CLA). You can do this by visiting https://cla-assistant.io/meshtastic/firmware. Be sure to use the GitHub account you will use to submit your contributions when signing.
1. Fork the repository
2. Create a new branch for your feature or bug fix
3. Make your changes
4. Test your changes thoroughly
5. Create a pull request with a clear description, using the provided template, of your changes. Be sure to enable "Allow edits from maintainers".
## Coding Standards
To ensure consistent code formatting across the project:
1. Install the [Trunk](https://marketplace.visualstudio.com/items?itemName=Trunk.io) extension for Visual Studio Code.
2. Before submitting your changes, run `trunk fmt` to automatically format your code according to our standards.
Adhering to these formatting guidelines helps maintain code consistency and makes the review process smoother.
Thank you for contributing to Meshtastic!

View File

@@ -1,78 +1,54 @@
# trunk-ignore-all(trivy/DS002): We must run as root for this container
# trunk-ignore-all(hadolint/DL3002): We must run as root for this container
# trunk-ignore-all(hadolint/DL3008): Do not pin apt package versions
# trunk-ignore-all(hadolint/DL3013): Do not pin pip package versions
FROM debian:bookworm-slim AS builder
FROM python:3.14-slim-trixie AS builder
ARG PIO_ENV=native
ENV DEBIAN_FRONTEND=noninteractive
ENV TZ=Etc/UTC
# Install Dependencies
ENV PIP_ROOT_USER_ACTION=ignore
RUN apt-get update && apt-get install --no-install-recommends -y \
curl wget g++ zip git ca-certificates pkg-config \
libgpiod-dev libyaml-cpp-dev libbluetooth-dev libi2c-dev libuv1-dev \
libusb-1.0-0-dev libulfius-dev liborcania-dev libssl-dev \
libx11-dev libinput-dev libxkbcommon-x11-dev \
&& apt-get clean && rm -rf /var/lib/apt/lists/* \
&& pip install --no-cache-dir -U platformio \
&& mkdir /tmp/firmware
# http://bugs.python.org/issue19846
# > At the moment, setting "LANG=C" on a Linux system *fundamentally breaks Python 3*, and that's not OK.
ENV LANG C.UTF-8
# Install build deps
USER root
# trunk-ignore(terrascan/AC_DOCKER_0002): Known terrascan issue
# trunk-ignore(hadolint/DL3008): Use latest version of packages for buildchain
RUN apt-get update && apt-get install --no-install-recommends -y wget python3 python3-pip python3-wheel python3-venv g++ zip git \
ca-certificates libgpiod-dev libyaml-cpp-dev libbluetooth-dev \
libulfius-dev liborcania-dev libssl-dev pkg-config && \
apt-get clean && rm -rf /var/lib/apt/lists/* && mkdir /tmp/firmware
RUN groupadd -g 1000 mesh && useradd -ml -u 1000 -g 1000 mesh && chown mesh:mesh /tmp/firmware
USER mesh
# Copy source code
WORKDIR /tmp/firmware
COPY . /tmp/firmware
RUN python3 -m venv /tmp/firmware
RUN bash -o pipefail -c "source bin/activate; pip3 install --no-cache-dir -U platformio==6.1.15"
# trunk-ignore(terrascan/AC_DOCKER_00024): We would actually like these files to be owned by mesh tyvm
COPY --chown=mesh:mesh . /tmp/firmware
RUN bash -o pipefail -c "source ./bin/activate && bash ./bin/build-native.sh"
RUN cp "/tmp/firmware/release/meshtasticd_linux_$(uname -m)" "/tmp/firmware/release/meshtasticd"
# Build
RUN bash ./bin/build-native.sh "$PIO_ENV" && \
cp "/tmp/firmware/release/meshtasticd_linux_$(uname -m)" "/tmp/firmware/release/meshtasticd"
# Fetch web assets
RUN curl -L "https://github.com/meshtastic/web/releases/download/v$(cat /tmp/firmware/bin/web.version)/build.tar" -o /tmp/web.tar \
&& mkdir -p /tmp/web \
&& tar -xf /tmp/web.tar -C /tmp/web/ \
&& gzip -dr /tmp/web \
&& rm /tmp/web.tar
##### PRODUCTION BUILD #############
FROM debian:trixie-slim
LABEL org.opencontainers.image.title="Meshtastic" \
org.opencontainers.image.description="Debian Meshtastic daemon and web interface" \
org.opencontainers.image.url="https://meshtastic.org" \
org.opencontainers.image.documentation="https://meshtastic.org/docs/" \
org.opencontainers.image.authors="Meshtastic" \
org.opencontainers.image.licenses="GPL-3.0-or-later" \
org.opencontainers.image.source="https://github.com/meshtastic/firmware/"
FROM debian:bookworm-slim
ENV DEBIAN_FRONTEND=noninteractive
ENV TZ=Etc/UTC
# nosemgrep: dockerfile.security.last-user-is-root.last-user-is-root
USER root
# trunk-ignore(terrascan/AC_DOCKER_0002): Known terrascan issue
# trunk-ignore(hadolint/DL3008): Use latest version of packages for buildchain
RUN apt-get update && apt-get --no-install-recommends -y install libc-bin libc6 libgpiod2 libyaml-cpp0.7 libulfius2.7 liborcania2.3 libssl3 && \
apt-get clean && rm -rf /var/lib/apt/lists/*
RUN apt-get update && apt-get --no-install-recommends -y install \
libc-bin libc6 libgpiod3 libyaml-cpp0.8 libi2c0 libuv1t64 libusb-1.0-0-dev \
liborcania2.3 libulfius2.7t64 libssl3t64 \
libx11-6 libinput10 libxkbcommon-x11-0 \
&& apt-get clean && rm -rf /var/lib/apt/lists/* \
&& mkdir -p /var/lib/meshtasticd \
&& mkdir -p /etc/meshtasticd/config.d \
&& mkdir -p /etc/meshtasticd/ssl
RUN groupadd -g 1000 mesh && useradd -ml -u 1000 -g 1000 mesh
USER mesh
# Fetch compiled binary from the builder
COPY --from=builder /tmp/firmware/release/meshtasticd /usr/bin/
COPY --from=builder /tmp/web /usr/share/meshtasticd/web/
# Copy config templates
COPY ./bin/config.d /etc/meshtasticd/available.d
WORKDIR /home/mesh
COPY --from=builder /tmp/firmware/release/meshtasticd /home/mesh/
WORKDIR /var/lib/meshtasticd
VOLUME /var/lib/meshtasticd
RUN mkdir data
VOLUME /home/mesh/data
# Expose Meshtastic TCP API port from the host
EXPOSE 4403
# Expose Meshtastic Web UI port from the host
EXPOSE 9443
CMD [ "sh", "-cx", "meshtasticd --fsdir=/var/lib/meshtasticd" ]
CMD [ "sh", "-cx", "./meshtasticd -d /home/mesh/data --hwid=${HWID:-$RANDOM}" ]
HEALTHCHECK NONE

View File

@@ -1,7 +1,4 @@
<div align="center" markdown="1">
<img src=".github/meshtastic_logo.png" alt="Meshtastic Logo" width="80"/>
<h1>Meshtastic Firmware</h1>
# Meshtastic Firmware
![GitHub release downloads](https://img.shields.io/github/downloads/meshtastic/firmware/total)
[![CI](https://img.shields.io/github/actions/workflow/status/meshtastic/firmware/main_matrix.yml?branch=master&label=actions&logo=github&color=yellow)](https://github.com/meshtastic/firmware/actions/workflows/ci.yml)
@@ -9,31 +6,13 @@
[![Fiscal Contributors](https://opencollective.com/meshtastic/tiers/badge.svg?label=Fiscal%20Contributors&color=deeppink)](https://opencollective.com/meshtastic/)
[![Vercel](https://img.shields.io/static/v1?label=Powered%20by&message=Vercel&style=flat&logo=vercel&color=000000)](https://vercel.com?utm_source=meshtastic&utm_campaign=oss)
<a href="https://trendshift.io/repositories/5524" target="_blank"><img src="https://trendshift.io/api/badge/repositories/5524" alt="meshtastic%2Ffirmware | Trendshift" style="width: 250px; height: 55px;" width="250" height="55"/></a>
</div>
</div>
<div align="center">
<a href="https://meshtastic.org">Website</a>
-
<a href="https://meshtastic.org/docs/">Documentation</a>
</div>
## Overview
This repository contains the official device firmware for Meshtastic, an open-source LoRa mesh networking project designed for long-range, low-power communication without relying on internet or cellular infrastructure. The firmware supports various hardware platforms, including ESP32, nRF52, RP2040/RP2350, and Linux-based devices.
This repository contains the device firmware for the Meshtastic project.
Meshtastic enables text messaging, location sharing, and telemetry over a decentralized mesh network, making it ideal for outdoor adventures, emergency preparedness, and remote operations.
### Get Started
- 🔧 **[Building Instructions](https://meshtastic.org/docs/development/firmware/build)** Learn how to compile the firmware from source.
-**[Flashing Instructions](https://meshtastic.org/docs/getting-started/flashing-firmware/)** Install or update the firmware on your device.
Join our community and help improve Meshtastic! 🚀
- **[Building Instructions](https://meshtastic.org/docs/development/firmware/build)**
- **[Flashing Instructions](https://meshtastic.org/docs/getting-started/flashing-firmware/)**
## Stats
![Alt](https://repobeats.axiom.co/api/embed/8025e56c482ec63541593cc5bd322c19d5c0bdcf.svg "Repobeats analytics image")
![Alt](https://repobeats.axiom.co/api/embed/a92f097d9197ae853e780ec53d7d126e545629ab.svg "Repobeats analytics image")

View File

@@ -1,12 +0,0 @@
# Security Policy
## Supported Versions
| Firmware Version | Supported |
| ---------------- | ------------------ |
| 2.6.x | :white_check_mark: |
| <= 2.5.x | :x: |
## Reporting a Vulnerability
We support the private reporting of potential security vulnerabilities. Please go to the Security tab to file a report with a description of the potential vulnerability and reproduction scripts (preferred) or steps, and our developers will review.

View File

@@ -1,63 +0,0 @@
# trunk-ignore-all(trivy/DS002): We must run as root for this container
# trunk-ignore-all(hadolint/DL3002): We must run as root for this container
# trunk-ignore-all(hadolint/DL3018): Do not pin apk package versions
# trunk-ignore-all(hadolint/DL3013): Do not pin pip package versions
FROM python:3.14-alpine3.22 AS builder
ARG PIO_ENV=native
ENV PIP_ROOT_USER_ACTION=ignore
RUN apk --no-cache add \
bash g++ libstdc++-dev linux-headers zip git ca-certificates libbsd-dev \
libgpiod-dev yaml-cpp-dev bluez-dev \
libusb-dev i2c-tools-dev libuv-dev openssl-dev pkgconf argp-standalone \
libx11-dev libinput-dev libxkbcommon-dev \
&& rm -rf /var/cache/apk/* \
&& pip install --no-cache-dir -U platformio \
&& mkdir /tmp/firmware
WORKDIR /tmp/firmware
COPY . /tmp/firmware
# Create small package (no debugging symbols)
# Add `argp` for musl
ENV PLATFORMIO_BUILD_FLAGS="-Os -ffunction-sections -fdata-sections -Wl,--gc-sections -largp"
RUN bash ./bin/build-native.sh "$PIO_ENV" && \
cp "/tmp/firmware/release/meshtasticd_linux_$(uname -m)" "/tmp/firmware/release/meshtasticd"
# ##### PRODUCTION BUILD #############
FROM alpine:3.23
LABEL org.opencontainers.image.title="Meshtastic" \
org.opencontainers.image.description="Alpine Meshtastic daemon" \
org.opencontainers.image.url="https://meshtastic.org" \
org.opencontainers.image.documentation="https://meshtastic.org/docs/" \
org.opencontainers.image.authors="Meshtastic" \
org.opencontainers.image.licenses="GPL-3.0-or-later" \
org.opencontainers.image.source="https://github.com/meshtastic/firmware/"
# nosemgrep: dockerfile.security.last-user-is-root.last-user-is-root
USER root
RUN apk --no-cache add \
shadow libstdc++ libbsd libgpiod yaml-cpp libusb \
i2c-tools libuv libx11 libinput libxkbcommon \
&& rm -rf /var/cache/apk/* \
&& mkdir -p /var/lib/meshtasticd \
&& mkdir -p /etc/meshtasticd/config.d \
&& mkdir -p /etc/meshtasticd/ssl
# Fetch compiled binary from the builder
COPY --from=builder /tmp/firmware/release/meshtasticd /usr/bin/
# Copy config templates
COPY ./bin/config.d /etc/meshtasticd/available.d
WORKDIR /var/lib/meshtasticd
VOLUME /var/lib/meshtasticd
EXPOSE 4403
CMD [ "sh", "-cx", "meshtasticd --fsdir=/var/lib/meshtasticd" ]
HEALTHCHECK NONE

View File

@@ -2,18 +2,10 @@
[esp32_base]
extends = arduino_base
custom_esp32_kind = esp32
custom_mtjson_part =
platform =
# renovate: datasource=custom.pio depName=platformio/espressif32 packageName=platformio/platform/espressif32
platformio/espressif32@6.12.0
extra_scripts =
${env.extra_scripts}
pre:extra_scripts/esp32_pre.py
extra_scripts/esp32_extra.py
platform = platformio/espressif32@6.7.0
build_src_filter =
${arduino_base.build_src_filter} -<platform/nrf52/> -<platform/stm32wl> -<platform/rp2xx0> -<mesh/eth/> -<mesh/raspihttp>
${arduino_base.build_src_filter} -<platform/nrf52/> -<platform/stm32wl> -<platform/rp2040> -<mesh/eth/> -<mesh/raspihttp>
upload_speed = 921600
debug_init_break = tbreak setup
@@ -37,37 +29,26 @@ build_flags =
-DMYNEWT_VAL_BLE_HS_LOG_LVL=LOG_LEVEL_CRITICAL
-DAXP_DEBUG_PORT=Serial
-DCONFIG_BT_NIMBLE_ENABLED
-DCONFIG_BT_NIMBLE_MAX_BONDS=6 # default is 3
-DCONFIG_NIMBLE_CPP_LOG_LEVEL=2
-DCONFIG_BT_NIMBLE_MAX_CCCDS=20
-DCONFIG_BT_NIMBLE_HOST_TASK_STACK_SIZE=8192
-DCONFIG_BT_NIMBLE_HOST_TASK_STACK_SIZE=5120
-DESP_OPENSSL_SUPPRESS_LEGACY_WARNING
-DSERIAL_BUFFER_SIZE=4096
-DSERIAL_HAS_ON_RECEIVE
-DLIBPAX_ARDUINO
-DLIBPAX_WIFI
-DLIBPAX_BLE
-DHAS_UDP_MULTICAST=1
;-DDEBUG_HEAP
lib_deps =
${arduino_base.lib_deps}
${networking_base.lib_deps}
${environmental_base.lib_deps}
${environmental_extra.lib_deps}
${radiolib_base.lib_deps}
# renovate: datasource=git-refs depName=meshtastic-esp32_https_server packageName=https://github.com/meshtastic/esp32_https_server gitBranch=master
https://github.com/meshtastic/esp32_https_server/archive/3223704846752e6d545139204837bdb2a55459ca.zip
# renovate: datasource=custom.pio depName=NimBLE-Arduino packageName=h2zero/library/NimBLE-Arduino
h2zero/NimBLE-Arduino@^1.4.3
# renovate: datasource=git-refs depName=libpax packageName=https://github.com/dbinfrago/libpax gitBranch=master
https://github.com/dbinfrago/libpax/archive/3cdc0371c375676a97967547f4065607d4c53fd1.zip
# renovate: datasource=github-tags depName=XPowersLib packageName=lewisxhe/XPowersLib
https://github.com/lewisxhe/XPowersLib/archive/v0.3.2.zip
# renovate: datasource=git-refs depName=meshtastic-ESP32_Codec2 packageName=https://github.com/meshtastic/ESP32_Codec2 gitBranch=master
https://github.com/meshtastic/ESP32_Codec2/archive/633326c78ac251c059ab3a8c430fcdf25b41672f.zip
# renovate: datasource=custom.pio depName=rweather/Crypto packageName=rweather/library/Crypto
rweather/Crypto@0.4.0
https://github.com/meshtastic/esp32_https_server.git#23665b3adc080a311dcbb586ed5941b5f94d6ea2
h2zero/NimBLE-Arduino@^1.4.2
https://github.com/dbSuS/libpax.git#7bcd3fcab75037505be9b122ab2b24cc5176b587
https://github.com/lewisxhe/XPowersLib.git#84b7373faea3118b6c37954d52f98b8a337148d6
https://github.com/meshtastic/ESP32_Codec2.git#633326c78ac251c059ab3a8c430fcdf25b41672f
rweather/Crypto@^0.4.0
lib_ignore =
segger_rtt
@@ -83,4 +64,4 @@ lib_ignore =
; customize the partition table
; http://docs.platformio.org/en/latest/platforms/espressif32.html#partition-tables
board_build.partitions = partition-table.csv
board_build.partitions = partition-table.csv

View File

@@ -16,4 +16,4 @@ build_flags =
lib_ignore =
${esp32_base.lib_ignore}
NimBLE-Arduino
libpax
libpax

View File

@@ -3,3 +3,4 @@ extends = esp32_base
custom_esp32_kind = esp32s3
monitor_speed = 115200

26
arch/nrf52/nrf52.ini Normal file
View File

@@ -0,0 +1,26 @@
[nrf52_base]
; Instead of the standard nordicnrf52 platform, we use our fork which has our added variant files
platform = platformio/nordicnrf52@^10.5.0
extends = arduino_base
platform_packages =
; our custom Git version until they merge our PR
framework-arduinoadafruitnrf52 @ https://github.com/geeksville/Adafruit_nRF52_Arduino.git
build_type = debug
build_flags =
-include arch/nrf52/cpp_overrides/lfs_util.h
${arduino_base.build_flags}
-DSERIAL_BUFFER_SIZE=1024
-Wno-unused-variable
-Isrc/platform/nrf52
-DLFS_NO_ASSERT ; Disable LFS assertions , see https://github.com/meshtastic/firmware/pull/3818
build_src_filter =
${arduino_base.build_src_filter} -<platform/esp32/> -<platform/stm32wl> -<nimble/> -<mesh/wifi/> -<mesh/api/> -<mesh/http/> -<modules/esp32> -<platform/rp2040> -<mesh/eth/> -<mesh/raspihttp>
lib_deps=
${arduino_base.lib_deps}
rweather/Crypto@^0.4.0
lib_ignore =
BluetoothOTA

View File

@@ -1,9 +1,7 @@
[nrf52832_base]
extends = nrf52_base
build_flags =
${nrf52_base.build_flags}
-DSERIAL_BUFFER_SIZE=1024
build_flags = ${nrf52_base.build_flags}
lib_deps =
${nrf52_base.lib_deps}

View File

@@ -1,16 +1,12 @@
[nrf52840_base]
extends = nrf52_base
build_flags =
${nrf52_base.build_flags}
-DSERIAL_BUFFER_SIZE=4096
build_flags = ${nrf52_base.build_flags}
lib_deps =
${nrf52_base.lib_deps}
${environmental_base.lib_deps}
${environmental_extra.lib_deps}
# renovate: datasource=git-refs depName=Kongduino-Adafruit_nRFCrypto packageName=https://github.com/Kongduino/Adafruit_nRFCrypto gitBranch=master
https://github.com/Kongduino/Adafruit_nRFCrypto/archive/8cde7189b5ead9dcd49f72601b43b969c0bbc06e.zip
https://github.com/Kongduino/Adafruit_nRFCrypto.git#e31a8825ea3300b163a0a3c1ddd5de34e10e1371
; Common NRF52 debugging settings follow. See the Meshtastic developer docs for how to connect SWD debugging probes to your board.

View File

@@ -0,0 +1,37 @@
; The Portduino based sim environment on top of any host OS, all hardware will be simulated
[portduino_base]
platform = https://github.com/meshtastic/platform-native.git#ad8112adf82ce1f5b917092cf32be07a077801a0
framework = arduino
build_src_filter =
${env.build_src_filter}
-<platform/esp32/>
-<nimble/>
-<platform/nrf52/>
-<platform/stm32wl/>
-<platform/rp2040>
-<mesh/wifi/>
-<mesh/http/>
+<mesh/raspihttp/>
-<mesh/eth/>
-<modules/esp32>
-<modules/Telemetry/EnvironmentTelemetry.cpp>
-<modules/Telemetry/AirQualityTelemetry.cpp>
-<modules/Telemetry/Sensor>
+<../variants/portduino>
lib_deps =
${env.lib_deps}
${networking_base.lib_deps}
rweather/Crypto@^0.4.0
https://github.com/lovyan03/LovyanGFX.git#5a39989aa2c9492572255b22f033843ec8900233
build_flags =
${arduino_base.build_flags}
-fPIC
-Isrc/platform/portduino
-DRADIOLIB_EEPROM_UNSUPPORTED
-DPORTDUINO_LINUX_HARDWARE
-lbluetooth
-lgpiod
-lyaml-cpp

23
arch/rp2040/rp2040.ini Normal file
View File

@@ -0,0 +1,23 @@
; Common settings for rp2040 Processor based targets
[rp2040_base]
platform = https://github.com/maxgerhardt/platform-raspberrypi.git#60d6ae81fcc73c34b1493ca9e261695e471bc0c2
extends = arduino_base
platform_packages = framework-arduinopico@https://github.com/earlephilhower/arduino-pico.git#3.7.2
board_build.core = earlephilhower
board_build.filesystem_size = 0.5m
build_flags =
${arduino_base.build_flags} -Wno-unused-variable
-Isrc/platform/rp2040
-D__PLAT_RP2040__
# -D _POSIX_THREADS
build_src_filter =
${arduino_base.build_src_filter} -<platform/esp32/> -<nimble/> -<modules/esp32> -<platform/nrf52/> -<platform/stm32wl> -<mesh/eth/> -<mesh/wifi/> -<mesh/http/> -<mesh/raspihttp>
lib_ignore =
BluetoothOTA
lib_deps =
${arduino_base.lib_deps}
${environmental_base.lib_deps}
rweather/Crypto

37
arch/stm32/stm32.ini Normal file
View File

@@ -0,0 +1,37 @@
[stm32_base]
extends = arduino_base
platform = ststm32
platform_packages = platformio/framework-arduinoststm32@https://github.com/stm32duino/Arduino_Core_STM32.git#361a7fdb67e2a7104e99b4f42a802469eef8b129
build_type = release
;board_build.flash_offset = 0x08000000
build_flags =
${arduino_base.build_flags}
-flto
-Isrc/platform/stm32wl -g
-DMESHTASTIC_MINIMIZE_BUILD
-DMESHTASTIC_EXCLUDE_GPS
-DDEBUG_MUTE
; -DVECT_TAB_OFFSET=0x08000000
-DconfigUSE_CMSIS_RTOS_V2=1
; -DSPI_MODE_0=SPI_MODE0
-fmerge-all-constants
-ffunction-sections
-fdata-sections
build_src_filter =
${arduino_base.build_src_filter} -<platform/esp32/> -<nimble/> -<mesh/api/> -<mesh/wifi/> -<mesh/http/> -<modules/esp32> -<mesh/eth/> -<input> -<buzz> -<modules/RemoteHardwareModule.cpp> -<platform/nrf52> -<platform/portduino> -<platform/rp2040> -<mesh/raspihttp>
board_upload.offset_address = 0x08000000
upload_protocol = stlink
lib_deps =
${env.lib_deps}
charlesbaynham/OSFS@^1.2.3
https://github.com/caveman99/Crypto.git#f61ae26a53f7a2d0ba5511625b8bf8eff3a35d5e
lib_ignore =
https://github.com/mathertel/OneButton@~2.6.1
Wire

1
bin/.gitignore vendored
View File

@@ -1 +0,0 @@
config.yaml

View File

@@ -1,7 +0,0 @@
# Set spidev ownership to 'spi' group
SUBSYSTEM=="spidev", KERNEL=="spidev*", GROUP="spi", MODE="0660"
# Allow access to USB CH341 devices
SUBSYSTEM=="usb", ATTRS{idVendor}=="1a86", ATTRS{idProduct}=="5512", MODE="0666"
# Set gpio ownership to 'gpio' group
SUBSYSTEM=="*gpiomem*", GROUP="gpio", MODE="0660"
SUBSYSTEM=="gpio", GROUP="gpio", MODE="0660"

Binary file not shown.

View File

@@ -1,165 +0,0 @@
#!/usr/bin/env python3
"""Summarise linker map output to highlight heavy object files and libraries.
Usage:
python bin/analyze_map.py --map .pio/build/rak4631/output.map --top 20
The script parses GNU ld map files and aggregates section sizes per object file
and per archive/library, then prints sortable tables that make it easy to spot
modules worth trimming or hiding behind feature flags.
"""
from __future__ import annotations
import argparse
import collections
import os
import re
import sys
from typing import DefaultDict, Dict, Tuple
SECTION_LINE_RE = re.compile(r"^\s+(?P<section>\S+)\s+0x[0-9A-Fa-f]+\s+0x(?P<size>[0-9A-Fa-f]+)\s+(?P<object>.+)$")
ARCHIVE_MEMBER_RE = re.compile(r"^(?P<archive>.+)\((?P<object>[^)]+)\)$")
def human_size(num_bytes: int) -> str:
"""Return a friendly size string with one decimal place."""
if num_bytes < 1024:
return f"{num_bytes:,} B"
num = float(num_bytes)
for unit in ("KB", "MB", "GB"):
num /= 1024.0
if num < 1024.0:
return f"{num:.1f} {unit}"
return f"{num:.1f} TB"
def shorten_path(path: str, root: str) -> str:
"""Prefer repository-relative paths for readability."""
path = path.strip()
if not path:
return path
# Normalise Windows archives (backslashes) to POSIX style for consistency.
path = path.replace("\\", "/")
# Attempt to strip the root when an absolute path lives inside the repo.
if os.path.isabs(path):
try:
rel = os.path.relpath(path, root)
if not rel.startswith(".."):
return rel
except ValueError:
# relpath can fail on mixed drives on Windows; fall back to basename.
pass
return path
def describe_object(raw_object: str, root: str) -> Tuple[str, str]:
"""Return a human friendly object label and the library it belongs to."""
raw_object = raw_object.strip()
lib_label = "[app]"
match = ARCHIVE_MEMBER_RE.match(raw_object)
if match:
archive = shorten_path(match.group("archive"), root)
obj = match.group("object")
lib_label = os.path.basename(archive) or archive
label = f"{archive}:{obj}"
else:
label = shorten_path(raw_object, root)
# If the object lives under libs, hint at the containing directory.
parent = os.path.basename(os.path.dirname(label))
if parent:
lib_label = parent
return label, lib_label
def parse_map(map_path: str, repo_root: str) -> Tuple[Dict[str, int], Dict[str, int], Dict[str, Dict[str, int]]]:
per_object: DefaultDict[str, int] = collections.defaultdict(int)
per_library: DefaultDict[str, int] = collections.defaultdict(int)
per_object_sections: DefaultDict[str, DefaultDict[str, int]] = collections.defaultdict(lambda: collections.defaultdict(int))
try:
with open(map_path, "r", encoding="utf-8", errors="ignore") as handle:
for line in handle:
match = SECTION_LINE_RE.match(line)
if not match:
continue
section = match.group("section")
if section.startswith("*") or section in {"LOAD", "ORIGIN"}:
continue
size = int(match.group("size"), 16)
if size == 0:
continue
obj_token = match.group("object").strip()
if not obj_token or obj_token.startswith("*") or "load address" in obj_token:
continue
label, lib_label = describe_object(obj_token, repo_root)
per_object[label] += size
per_library[lib_label] += size
per_object_sections[label][section] += size
except FileNotFoundError:
raise SystemExit(f"error: map file '{map_path}' not found. Run a build first.")
return per_object, per_library, per_object_sections
def format_section_breakdown(section_sizes: Dict[str, int], total: int, limit: int = 3) -> str:
items = sorted(section_sizes.items(), key=lambda kv: kv[1], reverse=True)
parts = []
for section, size in items[:limit]:
pct = (size / total) * 100 if total else 0
parts.append(f"{section} {pct:.1f}%")
if len(items) > limit:
remainder = total - sum(size for _, size in items[:limit])
pct = (remainder / total) * 100 if total else 0
parts.append(f"other {pct:.1f}%")
return ", ".join(parts)
def print_report(map_path: str, top_n: int, per_object: Dict[str, int], per_library: Dict[str, int], per_object_sections: Dict[str, Dict[str, int]]):
total_bytes = sum(per_object.values())
if total_bytes == 0:
print("No section data found in map file.")
return
print(f"Map file: {map_path}")
print(f"Accounted size: {human_size(total_bytes)} across {len(per_object)} object files\n")
sorted_objects = sorted(per_object.items(), key=lambda kv: kv[1], reverse=True)
print(f"Top {min(top_n, len(sorted_objects))} object files by linked size:")
for idx, (obj, size) in enumerate(sorted_objects[:top_n], 1):
pct = (size / total_bytes) * 100
breakdown = format_section_breakdown(per_object_sections[obj], size)
print(f"{idx:2}. {human_size(size):>9} ({size:,} B, {pct:5.2f}% of linked size)")
print(f" {obj}")
if breakdown:
print(f" sections: {breakdown}")
print()
sorted_libs = sorted(per_library.items(), key=lambda kv: kv[1], reverse=True)
print(f"Top {min(top_n, len(sorted_libs))} libraries or source roots:")
for idx, (lib, size) in enumerate(sorted_libs[:top_n], 1):
pct = (size / total_bytes) * 100
print(f"{idx:2}. {human_size(size):>9} ({size:,} B, {pct:5.2f}% of linked size) {lib}")
def main() -> None:
parser = argparse.ArgumentParser(description="Highlight heavy object files from a GNU ld map file.")
parser.add_argument("--map", default=".pio/build/rak4631/output.map", help="Path to the map file (default: %(default)s)")
parser.add_argument("--top", type=int, default=20, help="Number of entries to display per table (default: %(default)s)")
args = parser.parse_args()
map_path = os.path.abspath(args.map)
repo_root = os.path.abspath(os.getcwd())
per_object, per_library, per_object_sections = parse_map(map_path, repo_root)
print_report(os.path.relpath(map_path, repo_root), args.top, per_object, per_library, per_object_sections)
if __name__ == "__main__":
main()

View File

@@ -1,33 +0,0 @@
import sys
import base64
def base64_to_hex_string(b64_string):
try:
# Decode the Base64 string to raw bytes
decoded_bytes = base64.b64decode(b64_string)
except Exception as e:
raise ValueError(f"Invalid Base64 input: {e}")
# Check if the decoded result is exactly 32 bytes
if len(decoded_bytes) != 32:
raise ValueError("Decoded Base64 input must be exactly 32 bytes.")
# Convert each byte to its hex representation
hex_values = [f"0x{byte:02x}" for byte in decoded_bytes]
# Join the formatted hex values with commas
formatted_output = "{ " + ", ".join(hex_values) + " };"
return formatted_output
if __name__ == "__main__":
# Check if a Base64 string was provided in command line arguments
if len(sys.argv) != 2:
print("Usage: python script.py <base64-string>")
sys.exit(1)
b64_string = sys.argv[1]
try:
formatted_hex = base64_to_hex_string(b64_string)
print(formatted_hex)
except ValueError as e:
print(e)

View File

@@ -5,37 +5,36 @@ set -e
VERSION=`bin/buildinfo.py long`
SHORT_VERSION=`bin/buildinfo.py short`
BUILDDIR=.pio/build/$1
OUTDIR=release
OUTDIR=release/
rm -f $OUTDIR/firmware*
rm -r $OUTDIR/* || true
# Important to pull latest version of libs into all device flavors, otherwise some devices might be stale
platformio pkg install -e $1
platformio pkg update -e $1
echo "Building for $1 with $PLATFORMIO_BUILD_FLAGS"
rm -f $BUILDDIR/firmware*
rm -f .pio/build/$1/firmware.*
# The shell vars the build tool expects to find
export APP_VERSION=$VERSION
basename=firmware-$1-$VERSION
pio run --environment $1 -t mtjson # -v
cp $BUILDDIR/$basename.elf $OUTDIR/$basename.elf
pio run --environment $1 # -v
SRCELF=.pio/build/$1/firmware.elf
cp $SRCELF $OUTDIR/$basename.elf
echo "Copying ESP32 bin file"
cp $BUILDDIR/$basename.factory.bin $OUTDIR/$basename.factory.bin
SRCBIN=.pio/build/$1/firmware.factory.bin
cp $SRCBIN $OUTDIR/$basename.bin
echo "Copying ESP32 update bin file"
cp $BUILDDIR/$basename.bin $OUTDIR/$basename.bin
SRCBIN=.pio/build/$1/firmware.bin
cp $SRCBIN $OUTDIR/$basename-update.bin
echo "Copying Filesystem for ESP32 targets"
cp $BUILDDIR/littlefs-$1-$VERSION.bin $OUTDIR/littlefs-$1-$VERSION.bin
cp bin/device-install.* $OUTDIR/
cp bin/device-update.* $OUTDIR/
echo "Copying manifest"
cp $BUILDDIR/$basename.mt.json $OUTDIR/$basename.mt.json
echo "Building Filesystem for ESP32 targets"
pio run --environment $1 -t buildfs
cp .pio/build/$1/littlefs.bin $OUTDIR/littlefs-$VERSION.bin
cp bin/device-install.* $OUTDIR
cp bin/device-update.* $OUTDIR

View File

@@ -1,16 +0,0 @@
#!/usr/bin/env bash
export PIP_BREAK_SYSTEM_PACKAGES=1
if (echo $2 | grep -q "esp32"); then
bin/build-esp32.sh $1
elif (echo $2 | grep -q "nrf52"); then
bin/build-nrf52.sh $1
elif (echo $2 | grep -q "stm32"); then
bin/build-stm32.sh $1
elif (echo $2 | grep -q "rpi2040"); then
bin/build-rp2xx0.sh $1
else
echo "Unknown target $2"
exit 1
fi

View File

@@ -15,21 +15,17 @@ platformioFailed() {
VERSION=$(bin/buildinfo.py long)
SHORT_VERSION=$(bin/buildinfo.py short)
PIO_ENV=${1:-native}
BUILDDIR=.pio/build/$PIO_ENV
OUTDIR=release
OUTDIR=release/
rm -f $OUTDIR/meshtasticd*
rm -f $OUTDIR/firmware*
mkdir -p $OUTDIR/
rm -r $OUTDIR/* || true
basename=meshtasticd-$1-$VERSION
# Important to pull latest version of libs into all device flavors, otherwise some devices might be stale
pio pkg install --environment "$PIO_ENV" || platformioFailed
pio run --environment "$PIO_ENV" || platformioFailed
cp "$BUILDDIR/meshtasticd" "$OUTDIR/meshtasticd_linux_$(uname -m)"
cp bin/native-install.* $OUTDIR/
platformio pkg update --environment native || platformioFailed
pio run --environment native || platformioFailed
cp .pio/build/native/program "$OUTDIR/meshtasticd_linux_$(uname -m)"
cp bin/device-install.* $OUTDIR
cp bin/device-update.* $OUTDIR

Some files were not shown because too many files have changed in this diff Show More