mirror of
https://github.com/meshtastic/firmware.git
synced 2025-12-28 13:40:32 +00:00
Compare commits
276 Commits
v2.5.17.b4
...
NextHopRou
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5757b88c48 | ||
|
|
7eb77276cd | ||
|
|
7648391f91 | ||
|
|
4407d9e040 | ||
|
|
27fea5fc07 | ||
|
|
2f6cd02111 | ||
|
|
8c9947b05c | ||
|
|
50b7d6a0f7 | ||
|
|
c83ffd4911 | ||
|
|
9b46cb4ef0 | ||
|
|
01935ea35e | ||
|
|
495f69cf90 | ||
|
|
eb650a6adb | ||
|
|
7fdd262d55 | ||
|
|
d1fa27d353 | ||
|
|
8427072d79 | ||
|
|
4e2b47cc67 | ||
|
|
da1d78c882 | ||
|
|
7c4bf38647 | ||
|
|
96262b106c | ||
|
|
39e45d90e1 | ||
|
|
d70a9392af | ||
|
|
cea072288a | ||
|
|
4e8c4f0d55 | ||
|
|
4a6a0efcfd | ||
|
|
cb0519dd9c | ||
|
|
9db51a72a4 | ||
|
|
64def246ee | ||
|
|
1c8eb7ece3 | ||
|
|
447533aae5 | ||
|
|
1b457bcfbb | ||
|
|
ed07cc067a | ||
|
|
a3a295488c | ||
|
|
5c17afb2ac | ||
|
|
8cacdb65d6 | ||
|
|
3a34f8beaf | ||
|
|
d740934278 | ||
|
|
b370717dcd | ||
|
|
d9534cfc9d | ||
|
|
b91b66bc7a | ||
|
|
4c0e0b8471 | ||
|
|
b5cad2b65e | ||
|
|
cd8592ef4a | ||
|
|
78da8f6fc4 | ||
|
|
6a12760c3d | ||
|
|
30a31a3a13 | ||
|
|
2d42e1b2bc | ||
|
|
4747e73f37 | ||
|
|
10d553087c | ||
|
|
7649e70585 | ||
|
|
a14346bc4f | ||
|
|
fd56995764 | ||
|
|
4c97351187 | ||
|
|
3298df953a | ||
|
|
d1f7739bbe | ||
|
|
0d860882a8 | ||
|
|
3b40fe9805 | ||
|
|
8e8b22edb0 | ||
|
|
01892cbd1e | ||
|
|
7fb22cf678 | ||
|
|
fdc87d492c | ||
|
|
0fdbf70452 | ||
|
|
71591fb06a | ||
|
|
9041af365d | ||
|
|
f87c370123 | ||
|
|
c4fcbad372 | ||
|
|
0f981153eb | ||
|
|
c1beb44678 | ||
|
|
973b453d43 | ||
|
|
950341d1f9 | ||
|
|
b353bcc04a | ||
|
|
c4051c1a7b | ||
|
|
2262d77be4 | ||
|
|
9566d6ffd4 | ||
|
|
e466bf2475 | ||
|
|
b0fe5ef8ba | ||
|
|
f132158c3e | ||
|
|
8179e61fdc | ||
|
|
a085614aaa | ||
|
|
7acd72ede1 | ||
|
|
7ba593432e | ||
|
|
a48df91737 | ||
|
|
262f1d25a2 | ||
|
|
4cd2ba5479 | ||
|
|
dc4279e7fd | ||
|
|
f9876cfe9c | ||
|
|
85de193845 | ||
|
|
fb2c008c89 | ||
|
|
dd9ab7f0e1 | ||
|
|
729c39fb86 | ||
|
|
038430db23 | ||
|
|
d5cd6f87a0 | ||
|
|
de42d96adf | ||
|
|
e2dd845051 | ||
|
|
6366633cd4 | ||
|
|
1c0f43c8e2 | ||
|
|
89a9e0b99d | ||
|
|
4dc8d6e400 | ||
|
|
e0f97c9306 | ||
|
|
6b1c01ce02 | ||
|
|
70296b47bc | ||
|
|
0cf4a2951a | ||
|
|
124936b6cf | ||
|
|
766bd614a4 | ||
|
|
fd60c9b3be | ||
|
|
a0a4c5bc79 | ||
|
|
0fe8d4ccc7 | ||
|
|
00fdf2c9aa | ||
|
|
253ab458ef | ||
|
|
b4a4d2db4e | ||
|
|
a3d9582b35 | ||
|
|
d5a8587deb | ||
|
|
6b8cf164e9 | ||
|
|
812aa35f09 | ||
|
|
e7802d960f | ||
|
|
077ee02426 | ||
|
|
46ea39af45 | ||
|
|
25a5f178e1 | ||
|
|
c144ee77a7 | ||
|
|
b62bdbc46a | ||
|
|
f18a92e8c5 | ||
|
|
2e44de262e | ||
|
|
1d756ae574 | ||
|
|
8aac9f2e8e | ||
|
|
33e5a04508 | ||
|
|
6cf3485d07 | ||
|
|
5154e29b07 | ||
|
|
9421eba027 | ||
|
|
27fbfd03d6 | ||
|
|
353740623f | ||
|
|
cdcbf4c615 | ||
|
|
395469d20a | ||
|
|
86170171a7 | ||
|
|
57766d47a8 | ||
|
|
e5dbcf5bce | ||
|
|
4c3a3ca47d | ||
|
|
78371dfdb7 | ||
|
|
ca32889893 | ||
|
|
35cd600c54 | ||
|
|
70076a4b27 | ||
|
|
f1a8900288 | ||
|
|
16bc89ea57 | ||
|
|
6edf74e8f1 | ||
|
|
7f280dd556 | ||
|
|
2396aa77ca | ||
|
|
d3cbbfd345 | ||
|
|
c003ab0eee | ||
|
|
4fcf7fe027 | ||
|
|
9cc79b1d1e | ||
|
|
403fa15a3f | ||
|
|
b0087fd328 | ||
|
|
fb74e1d182 | ||
|
|
29a7866fc1 | ||
|
|
2f552d15e5 | ||
|
|
892e0922ff | ||
|
|
d21d6c1301 | ||
|
|
031aecac66 | ||
|
|
7c10caa78b | ||
|
|
5196ee39cb | ||
|
|
02a5a91da0 | ||
|
|
b2a89b8136 | ||
|
|
15019e8663 | ||
|
|
35814fd4bc | ||
|
|
6aabbedc00 | ||
|
|
eb72ee0fc1 | ||
|
|
7480378aed | ||
|
|
7c21d7761c | ||
|
|
2c654454cf | ||
|
|
919660e005 | ||
|
|
9afadde2f4 | ||
|
|
66a961cb75 | ||
|
|
e1aaafb77a | ||
|
|
9d710041c4 | ||
|
|
b41efc17ba | ||
|
|
9bda080e3d | ||
|
|
9f7cbf1b4f | ||
|
|
93e2bc7058 | ||
|
|
7a1c32b89a | ||
|
|
88d8ab53c8 | ||
|
|
183f68ba00 | ||
|
|
9f32995d7f | ||
|
|
c2c06ed0ad | ||
|
|
9abd07bb05 | ||
|
|
fdcc0e12aa | ||
|
|
8b34c4ff05 | ||
|
|
9af8c58c40 | ||
|
|
58ebd5bcdb | ||
|
|
d1e5be515a | ||
|
|
f9e71c3fb9 | ||
|
|
bfcfca2e46 | ||
|
|
a2a6b236b7 | ||
|
|
c7d04d7064 | ||
|
|
3c7053c66a | ||
|
|
e45c0e4d40 | ||
|
|
57a9a5ca21 | ||
|
|
6749367a73 | ||
|
|
a8e2446f00 | ||
|
|
89ebafc8b8 | ||
|
|
43d6b31603 | ||
|
|
31a5b9c122 | ||
|
|
ad726ad684 | ||
|
|
b2808063d0 | ||
|
|
2b33be2fea | ||
|
|
5133117936 | ||
|
|
e5accf4e1d | ||
|
|
26a4d6c87a | ||
|
|
ae93f3fa3f | ||
|
|
ed39d14c85 | ||
|
|
8f8e304216 | ||
|
|
cd198fcf3f | ||
|
|
b1d25ac7b7 | ||
|
|
b12ac6d564 | ||
|
|
33d2f78d21 | ||
|
|
b12aa3f360 | ||
|
|
d87b7e49e4 | ||
|
|
cc357df489 | ||
|
|
1281da627e | ||
|
|
835344074c | ||
|
|
13960874ae | ||
|
|
a7d9e8107a | ||
|
|
fbdd6e7223 | ||
|
|
175ff218f1 | ||
|
|
57af51cc18 | ||
|
|
4915a07c2a | ||
|
|
98b4a29ef9 | ||
|
|
41d0a39ba6 | ||
|
|
0952c861ae | ||
|
|
017bff8be7 | ||
|
|
e593d54743 | ||
|
|
6a29793f23 | ||
|
|
47116f65cd | ||
|
|
98719e4c62 | ||
|
|
bfc6a1940d | ||
|
|
360637c25d | ||
|
|
3ea2918f7f | ||
|
|
b229abc2b4 | ||
|
|
dbe520c3ab | ||
|
|
42d17b3322 | ||
|
|
3725319b4b | ||
|
|
17495e7dbf | ||
|
|
93bcee3aab | ||
|
|
71a90b3b78 | ||
|
|
be73b099a7 | ||
|
|
f37abe8f0f | ||
|
|
78bf1e192b | ||
|
|
70aa28c53c | ||
|
|
fbefce7e10 | ||
|
|
69f88b9fdc | ||
|
|
24ff7c0bfb | ||
|
|
bb64b1480b | ||
|
|
790801f8e7 | ||
|
|
28944adf20 | ||
|
|
aab973e81b | ||
|
|
e4c98185d2 | ||
|
|
01344835af | ||
|
|
9de8d5ae66 | ||
|
|
ba4220fe50 | ||
|
|
aae4443e25 | ||
|
|
6fe42ed4c5 | ||
|
|
2e303a33be | ||
|
|
913268b132 | ||
|
|
e91dcb4ec3 | ||
|
|
b8e01b4044 | ||
|
|
d4ef0cdba5 | ||
|
|
b456e34c6e | ||
|
|
25ec0514da | ||
|
|
3ba9ecbbfe | ||
|
|
ef2c6eed05 | ||
|
|
81f57b65e1 | ||
|
|
42757d847f | ||
|
|
c7293cf6f1 | ||
|
|
27a492adf8 | ||
|
|
9b1dd75549 | ||
|
|
44dc270c8a | ||
|
|
3776064b80 | ||
|
|
0d6729b9eb |
52
.clusterfuzzlite/Dockerfile
Normal file
52
.clusterfuzzlite/Dockerfile
Normal file
@@ -0,0 +1,52 @@
|
||||
# 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
|
||||
59
.clusterfuzzlite/README.md
Normal file
59
.clusterfuzzlite/README.md
Normal file
@@ -0,0 +1,59 @@
|
||||
# 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.
|
||||
71
.clusterfuzzlite/build.sh
Normal file
71
.clusterfuzzlite/build.sh
Normal file
@@ -0,0 +1,71 @@
|
||||
#!/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/program"
|
||||
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
|
||||
35
.clusterfuzzlite/platformio-clusterfuzzlite-post.py
Normal file
35
.clusterfuzzlite/platformio-clusterfuzzlite-post.py
Normal file
@@ -0,0 +1,35 @@
|
||||
"""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",
|
||||
),
|
||||
)
|
||||
52
.clusterfuzzlite/platformio-clusterfuzzlite-pre.py
Normal file
52
.clusterfuzzlite/platformio-clusterfuzzlite-pre.py
Normal file
@@ -0,0 +1,52 @@
|
||||
"""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",
|
||||
],
|
||||
)
|
||||
1
.clusterfuzzlite/project.yaml
Normal file
1
.clusterfuzzlite/project.yaml
Normal file
@@ -0,0 +1 @@
|
||||
language: c++
|
||||
206
.clusterfuzzlite/router_fuzzer.cpp
Normal file
206
.clusterfuzzlite/router_fuzzer.cpp
Normal file
@@ -0,0 +1,206 @@
|
||||
// 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()
|
||||
{
|
||||
settingsMap[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)
|
||||
{
|
||||
settingsMap[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.
|
||||
}
|
||||
}
|
||||
2
.clusterfuzzlite/router_fuzzer.options
Normal file
2
.clusterfuzzlite/router_fuzzer.options
Normal file
@@ -0,0 +1,2 @@
|
||||
[libfuzzer]
|
||||
max_len=256
|
||||
168
.clusterfuzzlite/router_fuzzer_seed_corpus.py
Normal file
168
.clusterfuzzlite/router_fuzzer_seed_corpus.py
Normal file
@@ -0,0 +1,168 @@
|
||||
"""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())
|
||||
1
.dockerignore
Symbolic link
1
.dockerignore
Symbolic link
@@ -0,0 +1 @@
|
||||
.gitignore
|
||||
4
.env.example
Normal file
4
.env.example
Normal file
@@ -0,0 +1,4 @@
|
||||
# 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
|
||||
10
.github/actions/build-variant/action.yml
vendored
10
.github/actions/build-variant/action.yml
vendored
@@ -68,6 +68,12 @@ runs:
|
||||
sed -i '/DDEBUG_HEAP/d' ${INI_FILE}
|
||||
done
|
||||
|
||||
- name: PlatformIO ${{ inputs.arch }} download cache
|
||||
uses: actions/cache@v4
|
||||
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 }}
|
||||
@@ -83,13 +89,13 @@ runs:
|
||||
|
||||
- name: Get release version string
|
||||
shell: bash
|
||||
run: echo "version=$(./bin/buildinfo.py long)" >> $GITHUB_OUTPUT
|
||||
run: echo "long=$(./bin/buildinfo.py long)" >> $GITHUB_OUTPUT
|
||||
id: version
|
||||
|
||||
- name: Store binaries as an artifact
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: firmware-${{ inputs.arch }}-${{ inputs.board }}-${{ steps.version.outputs.version }}.zip
|
||||
name: firmware-${{ inputs.arch }}-${{ inputs.board }}-${{ steps.version.outputs.long }}.zip
|
||||
overwrite: true
|
||||
path: |
|
||||
${{ inputs.artifact-paths }}
|
||||
|
||||
13
.github/actions/setup-base/action.yml
vendored
13
.github/actions/setup-base/action.yml
vendored
@@ -20,19 +20,16 @@ runs:
|
||||
shell: bash
|
||||
run: |
|
||||
sudo apt-get -y update --fix-missing
|
||||
sudo apt-get install -y cppcheck libbluetooth-dev libgpiod-dev libyaml-cpp-dev
|
||||
sudo apt-get install -y cppcheck libbluetooth-dev libgpiod-dev libyaml-cpp-dev lsb-release
|
||||
|
||||
- name: Setup Python
|
||||
uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: 3.x
|
||||
|
||||
# - name: Cache python libs
|
||||
# uses: actions/cache@v4
|
||||
# id: cache-pip # needed in if test
|
||||
# with:
|
||||
# path: ~/.cache/pip
|
||||
# key: ${{ runner.os }}-pip
|
||||
cache: pip
|
||||
cache-dependency-path: |
|
||||
.github/actions/**
|
||||
**.ini
|
||||
|
||||
- name: Upgrade python tools
|
||||
shell: bash
|
||||
|
||||
14
.github/actions/setup-native/action.yml
vendored
Normal file
14
.github/actions/setup-native/action.yml
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
name: Setup native build
|
||||
description: Install libraries needed for building the Native/Portduino build
|
||||
|
||||
runs:
|
||||
using: composite
|
||||
steps:
|
||||
- name: Setup base
|
||||
id: base
|
||||
uses: ./.github/actions/setup-base
|
||||
|
||||
- name: Install libs needed for native build
|
||||
shell: bash
|
||||
run: |
|
||||
sudo apt-get install -y libbluetooth-dev libgpiod-dev libyaml-cpp-dev openssl libssl-dev libulfius-dev liborcania-dev libusb-1.0-0-dev libi2c-dev
|
||||
72
.github/workflows/build_debian_src.yml
vendored
Normal file
72
.github/workflows/build_debian_src.yml
vendored
Normal file
@@ -0,0 +1,72 @@
|
||||
name: Build Debian Source Package
|
||||
|
||||
on:
|
||||
workflow_call:
|
||||
secrets:
|
||||
PPA_GPG_PRIVATE_KEY:
|
||||
required: true
|
||||
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@v4
|
||||
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@v4
|
||||
with:
|
||||
name: firmware-debian-${{ steps.version.outputs.deb }}~${{ inputs.series }}-src
|
||||
overwrite: true
|
||||
path: |
|
||||
meshtasticd_${{ steps.version.outputs.deb }}*
|
||||
72
.github/workflows/build_docker.yml
vendored
72
.github/workflows/build_docker.yml
vendored
@@ -1,72 +0,0 @@
|
||||
name: Build Docker
|
||||
|
||||
on: workflow_call
|
||||
|
||||
permissions:
|
||||
contents: write
|
||||
packages: write
|
||||
|
||||
jobs:
|
||||
build-native:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Install libs needed for native build
|
||||
shell: bash
|
||||
run: |
|
||||
sudo apt-get update --fix-missing
|
||||
sudo apt-get install -y libbluetooth-dev libgpiod-dev libyaml-cpp-dev openssl libssl-dev libulfius-dev liborcania-dev libusb-1.0-0-dev
|
||||
|
||||
- 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: Docker login
|
||||
if: ${{ github.event_name != 'pull_request_target' && github.event_name != 'pull_request' }}
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
username: meshtastic
|
||||
password: ${{ secrets.DOCKER_FIRMWARE_TOKEN }}
|
||||
|
||||
- name: Docker setup
|
||||
if: ${{ github.event_name != 'pull_request_target' && github.event_name != 'pull_request' }}
|
||||
uses: docker/setup-buildx-action@v3
|
||||
|
||||
- name: Docker build and push tagged versions
|
||||
if: ${{ github.event_name == 'workflow_dispatch' }}
|
||||
uses: docker/build-push-action@v6
|
||||
with:
|
||||
context: .
|
||||
file: ./Dockerfile
|
||||
push: true
|
||||
tags: meshtastic/meshtasticd:${{ 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' }}
|
||||
uses: docker/build-push-action@v6
|
||||
with:
|
||||
context: .
|
||||
file: ./Dockerfile
|
||||
push: true
|
||||
tags: meshtastic/meshtasticd:latest
|
||||
52
.github/workflows/build_native.yml
vendored
52
.github/workflows/build_native.yml
vendored
@@ -1,52 +0,0 @@
|
||||
name: Build Native
|
||||
|
||||
on: workflow_call
|
||||
|
||||
permissions:
|
||||
contents: write
|
||||
packages: write
|
||||
|
||||
jobs:
|
||||
build-native:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Install libs needed for native build
|
||||
shell: bash
|
||||
run: |
|
||||
sudo apt-get update --fix-missing
|
||||
sudo apt-get install -y libbluetooth-dev libgpiod-dev libyaml-cpp-dev openssl libssl-dev libulfius-dev liborcania-dev libusb-1.0-0-dev libi2c-dev
|
||||
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
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
|
||||
52
.github/workflows/build_raspbian.yml
vendored
52
.github/workflows/build_raspbian.yml
vendored
@@ -1,52 +0,0 @@
|
||||
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: |
|
||||
sudo apt-get update -y --fix-missing
|
||||
sudo apt-get install -y libbluetooth-dev libgpiod-dev libyaml-cpp-dev openssl libssl-dev libulfius-dev liborcania-dev libusb-1.0-0-dev libi2c-dev
|
||||
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
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
|
||||
52
.github/workflows/build_raspbian_armv7l.yml
vendored
52
.github/workflows/build_raspbian_armv7l.yml
vendored
@@ -1,52 +0,0 @@
|
||||
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: |
|
||||
sudo apt-get update -y --fix-missing
|
||||
sudo apt-get install -y libbluetooth-dev libgpiod-dev libyaml-cpp-dev openssl libssl-dev libulfius-dev liborcania-dev libusb-1.0-0-dev libi2c-dev
|
||||
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
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
|
||||
51
.github/workflows/daily_packaging.yml
vendored
Normal file
51
.github/workflows/daily_packaging.yml
vendored
Normal file
@@ -0,0 +1,51 @@
|
||||
name: Daily Packaging
|
||||
on:
|
||||
schedule:
|
||||
- cron: 0 9 * * *
|
||||
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:
|
||||
uses: ./.github/workflows/docker_manifest.yml
|
||||
with:
|
||||
release_channel: daily
|
||||
secrets: inherit
|
||||
|
||||
package-ppa:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
series: [plucky, oracular, noble, jammy]
|
||||
uses: ./.github/workflows/package_ppa.yml
|
||||
with:
|
||||
ppa_repo: ppa:meshtastic/daily
|
||||
series: ${{ matrix.series }}
|
||||
secrets: inherit
|
||||
|
||||
package-obs:
|
||||
uses: ./.github/workflows/package_obs.yml
|
||||
with:
|
||||
obs_project: network:Meshtastic:daily
|
||||
series: unstable
|
||||
secrets: inherit
|
||||
|
||||
hook-copr:
|
||||
uses: ./.github/workflows/hook_copr.yml
|
||||
with:
|
||||
copr_project: daily
|
||||
secrets: inherit
|
||||
92
.github/workflows/docker_build.yml
vendored
Normal file
92
.github/workflows/docker_build.yml
vendored
Normal file
@@ -0,0 +1,92 @@
|
||||
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
|
||||
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@v4
|
||||
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 }}
|
||||
186
.github/workflows/docker_manifest.yml
vendored
Normal file
186
.github/workflows/docker_manifest.yml
vendored
Normal file
@@ -0,0 +1,186 @@
|
||||
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@v4
|
||||
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 }}
|
||||
38
.github/workflows/hook_copr.yml
vendored
Normal file
38
.github/workflows/hook_copr.yml
vendored
Normal file
@@ -0,0 +1,38 @@
|
||||
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@v4
|
||||
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 }}
|
||||
187
.github/workflows/main_matrix.yml
vendored
187
.github/workflows/main_matrix.yml
vendored
@@ -128,20 +128,54 @@ jobs:
|
||||
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
|
||||
|
||||
build-docker:
|
||||
if: ${{ github.event_name == 'workflow_dispatch' }}
|
||||
uses: ./.github/workflows/build_docker.yml
|
||||
build-debian-src:
|
||||
uses: ./.github/workflows/build_debian_src.yml
|
||||
with:
|
||||
series: UNRELEASED
|
||||
build_location: local
|
||||
secrets: inherit
|
||||
|
||||
package-pio-deps-native:
|
||||
uses: ./.github/workflows/package_pio_deps.yml
|
||||
with:
|
||||
pio_env: native
|
||||
secrets: inherit
|
||||
|
||||
test-native:
|
||||
uses: ./.github/workflows/test_native.yml
|
||||
|
||||
docker-debian-amd64:
|
||||
uses: ./.github/workflows/docker_build.yml
|
||||
with:
|
||||
distro: debian
|
||||
platform: linux/amd64
|
||||
runs-on: ubuntu-24.04
|
||||
push: false
|
||||
|
||||
docker-alpine-amd64:
|
||||
uses: ./.github/workflows/docker_build.yml
|
||||
with:
|
||||
distro: alpine
|
||||
platform: linux/amd64
|
||||
runs-on: ubuntu-24.04
|
||||
push: false
|
||||
|
||||
docker-debian-arm64:
|
||||
uses: ./.github/workflows/docker_build.yml
|
||||
with:
|
||||
distro: debian
|
||||
platform: linux/arm64
|
||||
runs-on: ubuntu-24.04-arm
|
||||
push: false
|
||||
|
||||
docker-debian-armv7:
|
||||
uses: ./.github/workflows/docker_build.yml
|
||||
with:
|
||||
distro: debian
|
||||
platform: linux/arm/v7
|
||||
runs-on: ubuntu-24.04-arm
|
||||
push: false
|
||||
|
||||
after-checks:
|
||||
runs-on: ubuntu-latest
|
||||
if: ${{ github.event_name != 'workflow_dispatch' }}
|
||||
@@ -189,7 +223,7 @@ jobs:
|
||||
run: ls -R
|
||||
|
||||
- name: Get release version string
|
||||
run: echo "version=$(./bin/buildinfo.py long)" >> $GITHUB_OUTPUT
|
||||
run: echo "long=$(./bin/buildinfo.py long)" >> $GITHUB_OUTPUT
|
||||
id: version
|
||||
|
||||
- name: Move files up
|
||||
@@ -198,7 +232,7 @@ jobs:
|
||||
- name: Repackage in single firmware zip
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: firmware-${{matrix.arch}}-${{ steps.version.outputs.version }}
|
||||
name: firmware-${{matrix.arch}}-${{ steps.version.outputs.long }}
|
||||
overwrite: true
|
||||
path: |
|
||||
./firmware-*.bin
|
||||
@@ -215,7 +249,7 @@ jobs:
|
||||
|
||||
- uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: firmware-${{matrix.arch}}-${{ steps.version.outputs.version }}
|
||||
name: firmware-${{matrix.arch}}-${{ steps.version.outputs.long }}
|
||||
merge-multiple: true
|
||||
path: ./output
|
||||
|
||||
@@ -229,12 +263,12 @@ jobs:
|
||||
chmod +x ./output/device-update.sh
|
||||
|
||||
- name: Zip firmware
|
||||
run: zip -j -9 -r ./firmware-${{matrix.arch}}-${{ steps.version.outputs.version }}.zip ./output
|
||||
run: zip -j -9 -r ./firmware-${{matrix.arch}}-${{ steps.version.outputs.long }}.zip ./output
|
||||
|
||||
- name: Repackage in single elfs zip
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: debug-elfs-${{matrix.arch}}-${{ steps.version.outputs.version }}.zip
|
||||
name: debug-elfs-${{matrix.arch}}-${{ steps.version.outputs.long }}.zip
|
||||
overwrite: true
|
||||
path: ./*.elf
|
||||
retention-days: 30
|
||||
@@ -242,8 +276,8 @@ jobs:
|
||||
- uses: scruplelesswizard/comment-artifact@main
|
||||
if: ${{ github.event_name == 'pull_request' }}
|
||||
with:
|
||||
name: firmware-${{matrix.arch}}-${{ steps.version.outputs.version }}
|
||||
description: "Download firmware-${{matrix.arch}}-${{ steps.version.outputs.version }}.zip. This artifact will be available for 90 days from creation"
|
||||
name: firmware-${{matrix.arch}}-${{ steps.version.outputs.long }}
|
||||
description: "Download firmware-${{matrix.arch}}-${{ steps.version.outputs.long }}.zip. This artifact will be available for 90 days from creation"
|
||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
release-artifacts:
|
||||
@@ -252,12 +286,9 @@ jobs:
|
||||
outputs:
|
||||
upload_url: ${{ steps.create_release.outputs.upload_url }}
|
||||
needs:
|
||||
[
|
||||
gather-artifacts,
|
||||
package-raspbian,
|
||||
package-raspbian-armv7l,
|
||||
package-native,
|
||||
]
|
||||
- gather-artifacts
|
||||
- build-debian-src
|
||||
- package-pio-deps-native
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
@@ -268,73 +299,70 @@ jobs:
|
||||
python-version: 3.x
|
||||
|
||||
- name: Get release version string
|
||||
run: echo "version=$(./bin/buildinfo.py long)" >> $GITHUB_OUTPUT
|
||||
run: |
|
||||
echo "long=$(./bin/buildinfo.py long)" >> $GITHUB_OUTPUT
|
||||
echo "deb=$(./bin/buildinfo.py deb)" >> $GITHUB_OUTPUT
|
||||
id: version
|
||||
env:
|
||||
BUILD_LOCATION: local
|
||||
|
||||
- name: Create release
|
||||
uses: actions/create-release@v1
|
||||
uses: softprops/action-gh-release@v2
|
||||
id: create_release
|
||||
with:
|
||||
draft: true
|
||||
prerelease: true
|
||||
release_name: Meshtastic Firmware ${{ steps.version.outputs.version }} Alpha
|
||||
tag_name: v${{ steps.version.outputs.version }}
|
||||
name: Meshtastic Firmware ${{ steps.version.outputs.long }} Alpha
|
||||
tag_name: v${{ steps.version.outputs.long }}
|
||||
body: |
|
||||
Autogenerated by github action, developer should edit as required before publishing...
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ github.token }}
|
||||
|
||||
- name: Download deb files
|
||||
- name: Download source deb
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
pattern: meshtasticd_${{ steps.version.outputs.version }}_*.deb
|
||||
pattern: firmware-debian-${{ steps.version.outputs.deb }}~UNRELEASED-src
|
||||
merge-multiple: true
|
||||
path: ./output
|
||||
path: ./output/debian-src
|
||||
|
||||
- name: Download native pio deps
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
pattern: platformio-deps-native-${{ steps.version.outputs.long }}
|
||||
merge-multiple: true
|
||||
path: ./output/pio-deps-native
|
||||
|
||||
- name: Zip linux sources
|
||||
working-directory: output
|
||||
run: |
|
||||
zip -j -9 -r ./meshtasticd-${{ steps.version.outputs.deb }}-src.zip ./debian-src
|
||||
zip -9 -r ./platformio-deps-native-${{ steps.version.outputs.long }}.zip ./pio-deps-native
|
||||
|
||||
# For diagnostics
|
||||
- name: Display structure of downloaded files
|
||||
run: ls -lR
|
||||
|
||||
- name: Add raspbian aarch64 .deb
|
||||
uses: actions/upload-release-asset@v1
|
||||
- name: Add linux sources to release
|
||||
run: |
|
||||
gh release upload v${{ steps.version.outputs.long }} ./output/meshtasticd-${{ steps.version.outputs.deb }}-src.zip
|
||||
gh release upload v${{ steps.version.outputs.long }} ./output/platformio-deps-native-${{ steps.version.outputs.long }}.zip
|
||||
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
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Bump version.properties
|
||||
run: >-
|
||||
bin/bump_version.py
|
||||
|
||||
- name: Update debian changelog
|
||||
run: >-
|
||||
debian/ci_changelog.sh
|
||||
|
||||
- name: Create version.properties pull request
|
||||
uses: peter-evans/create-pull-request@v7
|
||||
with:
|
||||
title: Bump version.properties
|
||||
add-paths: |
|
||||
version.properties
|
||||
debian/changelog
|
||||
|
||||
release-firmware:
|
||||
strategy:
|
||||
@@ -354,12 +382,12 @@ jobs:
|
||||
python-version: 3.x
|
||||
|
||||
- name: Get release version string
|
||||
run: echo "version=$(./bin/buildinfo.py long)" >> $GITHUB_OUTPUT
|
||||
run: echo "long=$(./bin/buildinfo.py long)" >> $GITHUB_OUTPUT
|
||||
id: version
|
||||
|
||||
- uses: actions/download-artifact@v4
|
||||
with:
|
||||
pattern: firmware-${{matrix.arch}}-${{ steps.version.outputs.version }}
|
||||
pattern: firmware-${{matrix.arch}}-${{ steps.version.outputs.long }}
|
||||
merge-multiple: true
|
||||
path: ./output
|
||||
|
||||
@@ -372,37 +400,24 @@ jobs:
|
||||
chmod +x ./output/device-update.sh
|
||||
|
||||
- name: Zip firmware
|
||||
run: zip -j -9 -r ./firmware-${{matrix.arch}}-${{ steps.version.outputs.version }}.zip ./output
|
||||
run: zip -j -9 -r ./firmware-${{matrix.arch}}-${{ steps.version.outputs.long }}.zip ./output
|
||||
|
||||
- uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: debug-elfs-${{matrix.arch}}-${{ steps.version.outputs.version }}.zip
|
||||
name: debug-elfs-${{matrix.arch}}-${{ steps.version.outputs.long }}.zip
|
||||
merge-multiple: true
|
||||
path: ./elfs
|
||||
|
||||
- name: Zip firmware
|
||||
run: zip -j -9 -r ./debug-elfs-${{matrix.arch}}-${{ steps.version.outputs.version }}.zip ./elfs
|
||||
- name: Zip debug elfs
|
||||
run: zip -j -9 -r ./debug-elfs-${{matrix.arch}}-${{ steps.version.outputs.long }}.zip ./elfs
|
||||
|
||||
# For diagnostics
|
||||
- name: Display structure of downloaded files
|
||||
run: ls -lR
|
||||
|
||||
- name: Add bins to release
|
||||
uses: actions/upload-release-asset@v1
|
||||
- name: Add bins and debug elfs to release
|
||||
run: |
|
||||
gh release upload v${{ steps.version.outputs.long }} ./firmware-${{matrix.arch}}-${{ steps.version.outputs.long }}.zip
|
||||
gh release upload v${{ steps.version.outputs.long }} ./debug-elfs-${{matrix.arch}}-${{ steps.version.outputs.long }}.zip
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ github.token }}
|
||||
with:
|
||||
upload_url: ${{needs.release-artifacts.outputs.upload_url}}
|
||||
asset_path: ./firmware-${{matrix.arch}}-${{ steps.version.outputs.version }}.zip
|
||||
asset_name: firmware-${{matrix.arch}}-${{ 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: ${{needs.release-artifacts.outputs.upload_url}}
|
||||
asset_path: ./debug-elfs-${{matrix.arch}}-${{ steps.version.outputs.version }}.zip
|
||||
asset_name: debug-elfs-${{matrix.arch}}-${{ steps.version.outputs.version }}.zip
|
||||
asset_content_type: application/zip
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
90
.github/workflows/package_amd64.yml
vendored
90
.github/workflows/package_amd64.yml
vendored
@@ -1,90 +0,0 @@
|
||||
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-22.04
|
||||
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/meshtasticd/web
|
||||
mkdir -p .debpkg/usr/sbin
|
||||
mkdir -p .debpkg/etc/meshtasticd
|
||||
mkdir -p .debpkg/etc/meshtasticd/config.d
|
||||
mkdir -p .debpkg/etc/meshtasticd/available.d
|
||||
mkdir -p .debpkg/usr/lib/systemd/system/
|
||||
tar -xf build.tar -C .debpkg/usr/share/meshtasticd/web
|
||||
shopt -s dotglob nullglob
|
||||
if [ -d .debpkg/usr/share/meshtasticd/web/build ]; then mv .debpkg/usr/share/meshtasticd/web/build/* .debpkg/usr/share/meshtasticd/web/; fi
|
||||
if [ -d .debpkg/usr/share/meshtasticd/web/build ]; then rmdir .debpkg/usr/share/meshtasticd/web/build; fi
|
||||
if [ -d .debpkg/usr/share/meshtasticd/web/.DS_Store ]; then rm -f .debpkg/usr/share/meshtasticd/web/.DS_Store; fi
|
||||
gunzip .debpkg/usr/share/meshtasticd/web/ -r
|
||||
cp release/meshtasticd_linux_x86_64 .debpkg/usr/sbin/meshtasticd
|
||||
cp bin/config-dist.yaml .debpkg/etc/meshtasticd/config.yaml
|
||||
cp bin/config.d/* .debpkg/etc/meshtasticd/available.d/ -r
|
||||
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
|
||||
# Transition /usr/share/doc/meshtasticd to /usr/share/meshtasticd
|
||||
echo "rm -rf /usr/share/doc/meshtasticd" > .debpkg/DEBIAN/preinst
|
||||
chmod +x .debpkg/DEBIAN/preinst
|
||||
echo "ln -sf /usr/share/meshtasticd /usr/share/doc/meshtasticd" > .debpkg/DEBIAN/postinst
|
||||
chmod +x .debpkg/DEBIAN/postinst
|
||||
|
||||
- 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, libi2c0
|
||||
desc: Native Linux Meshtastic binary.
|
||||
|
||||
- uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: meshtasticd_${{ steps.version.outputs.version }}_amd64.deb
|
||||
overwrite: true
|
||||
path: |
|
||||
./*.deb
|
||||
110
.github/workflows/package_obs.yml
vendored
Normal file
110
.github/workflows/package_obs.yml
vendored
Normal file
@@ -0,0 +1,110 @@
|
||||
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@v4
|
||||
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@v4
|
||||
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 }}"
|
||||
65
.github/workflows/package_pio_deps.yml
vendored
Normal file
65
.github/workflows/package_pio_deps.yml
vendored
Normal file
@@ -0,0 +1,65 @@
|
||||
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@v4
|
||||
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@v5
|
||||
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@v4
|
||||
with:
|
||||
name: platformio-deps-${{ inputs.pio_env }}-${{ steps.version.outputs.long }}
|
||||
overwrite: true
|
||||
include-hidden-files: true
|
||||
path: |
|
||||
pio/*
|
||||
74
.github/workflows/package_ppa.yml
vendored
Normal file
74
.github/workflows/package_ppa.yml
vendored
Normal file
@@ -0,0 +1,74 @@
|
||||
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@v4
|
||||
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@v4
|
||||
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
|
||||
90
.github/workflows/package_raspbian.yml
vendored
90
.github/workflows/package_raspbian.yml
vendored
@@ -1,90 +0,0 @@
|
||||
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-22.04
|
||||
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/meshtasticd/web
|
||||
mkdir -p .debpkg/usr/sbin
|
||||
mkdir -p .debpkg/etc/meshtasticd
|
||||
mkdir -p .debpkg/etc/meshtasticd/config.d
|
||||
mkdir -p .debpkg/etc/meshtasticd/available.d
|
||||
mkdir -p .debpkg/usr/lib/systemd/system/
|
||||
tar -xf build.tar -C .debpkg/usr/share/meshtasticd/web
|
||||
shopt -s dotglob nullglob
|
||||
if [ -d .debpkg/usr/share/meshtasticd/web/build ]; then mv .debpkg/usr/share/meshtasticd/web/build/* .debpkg/usr/share/meshtasticd/web/; fi
|
||||
if [ -d .debpkg/usr/share/meshtasticd/web/build ]; then rmdir .debpkg/usr/share/meshtasticd/web/build; fi
|
||||
if [ -d .debpkg/usr/share/meshtasticd/web/.DS_Store ]; then rm -f .debpkg/usr/share/meshtasticd/web/.DS_Store; fi
|
||||
gunzip .debpkg/usr/share/meshtasticd/web/ -r
|
||||
cp release/meshtasticd_linux_aarch64 .debpkg/usr/sbin/meshtasticd
|
||||
cp bin/config-dist.yaml .debpkg/etc/meshtasticd/config.yaml
|
||||
cp bin/config.d/* .debpkg/etc/meshtasticd/available.d/ -r
|
||||
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
|
||||
# Transition /usr/share/doc/meshtasticd to /usr/share/meshtasticd
|
||||
echo "rm -rf /usr/share/doc/meshtasticd" > .debpkg/DEBIAN/preinst
|
||||
chmod +x .debpkg/DEBIAN/preinst
|
||||
echo "ln -sf /usr/share/meshtasticd /usr/share/doc/meshtasticd" > .debpkg/DEBIAN/postinst
|
||||
chmod +x .debpkg/DEBIAN/postinst
|
||||
|
||||
- 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, libi2c0
|
||||
desc: Native Linux Meshtastic binary.
|
||||
|
||||
- uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: meshtasticd_${{ steps.version.outputs.version }}_arm64.deb
|
||||
overwrite: true
|
||||
path: |
|
||||
./*.deb
|
||||
90
.github/workflows/package_raspbian_armv7l.yml
vendored
90
.github/workflows/package_raspbian_armv7l.yml
vendored
@@ -1,90 +0,0 @@
|
||||
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-22.04
|
||||
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/meshtasticd/web
|
||||
mkdir -p .debpkg/usr/sbin
|
||||
mkdir -p .debpkg/etc/meshtasticd
|
||||
mkdir -p .debpkg/etc/meshtasticd/config.d
|
||||
mkdir -p .debpkg/etc/meshtasticd/available.d
|
||||
mkdir -p .debpkg/usr/lib/systemd/system/
|
||||
tar -xf build.tar -C .debpkg/usr/share/meshtasticd/web
|
||||
shopt -s dotglob nullglob
|
||||
if [ -d .debpkg/usr/share/meshtasticd/web/build ]; then mv .debpkg/usr/share/meshtasticd/web/build/* .debpkg/usr/share/meshtasticd/web/; fi
|
||||
if [ -d .debpkg/usr/share/meshtasticd/web/build ]; then rmdir .debpkg/usr/share/meshtasticd/web/build; fi
|
||||
if [ -d .debpkg/usr/share/meshtasticd/web/.DS_Store ]; then rm -f .debpkg/usr/share/meshtasticd/web/.DS_Store; fi
|
||||
gunzip .debpkg/usr/share/meshtasticd/web/ -r
|
||||
cp release/meshtasticd_linux_armv7l .debpkg/usr/sbin/meshtasticd
|
||||
cp bin/config-dist.yaml .debpkg/etc/meshtasticd/config.yaml
|
||||
cp bin/config.d/* .debpkg/etc/meshtasticd/available.d/ -r
|
||||
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
|
||||
# Transition /usr/share/doc/meshtasticd to /usr/share/meshtasticd
|
||||
echo "rm -rf /usr/share/doc/meshtasticd" > .debpkg/DEBIAN/preinst
|
||||
chmod +x .debpkg/DEBIAN/preinst
|
||||
echo "ln -sf /usr/share/meshtasticd /usr/share/doc/meshtasticd" > .debpkg/DEBIAN/postinst
|
||||
chmod +x .debpkg/DEBIAN/postinst
|
||||
|
||||
- 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, libi2c0
|
||||
desc: Native Linux Meshtastic binary.
|
||||
|
||||
- uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: meshtasticd_${{ steps.version.outputs.version }}_armhf.deb
|
||||
overwrite: true
|
||||
path: |
|
||||
./*.deb
|
||||
45
.github/workflows/release_channels.yml
vendored
Normal file
45
.github/workflows/release_channels.yml
vendored
Normal file
@@ -0,0 +1,45 @@
|
||||
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: [plucky, oracular, noble, jammy]
|
||||
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
|
||||
169
.github/workflows/test_native.yml
vendored
Normal file
169
.github/workflows/test_native.yml
vendored
Normal file
@@ -0,0 +1,169 @@
|
||||
name: Run Tests on Native platform
|
||||
|
||||
on:
|
||||
workflow_call:
|
||||
workflow_dispatch:
|
||||
|
||||
permissions: {}
|
||||
|
||||
env:
|
||||
LCOV_CAPTURE_FLAGS: --quiet --capture --include "${PWD}/src/*" --exclude '*/src/mesh/generated/*' --directory .pio/build/coverage/src --base-directory "${PWD}"
|
||||
|
||||
jobs:
|
||||
simulator-tests:
|
||||
name: Native Simulator Tests
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
ref: ${{github.event.pull_request.head.ref}}
|
||||
repository: ${{github.event.pull_request.head.repo.full_name}}
|
||||
submodules: recursive
|
||||
|
||||
- name: Setup native build
|
||||
id: base
|
||||
uses: ./.github/actions/setup-native
|
||||
|
||||
- name: Install simulator dependencies
|
||||
run: pip install -U dotmap
|
||||
|
||||
# We now run integration test before other build steps (to quickly see runtime failures)
|
||||
- name: Build for native/coverage
|
||||
run: platformio run -e coverage
|
||||
|
||||
- name: Capture initial coverage information
|
||||
shell: bash
|
||||
run: |
|
||||
sudo apt-get install -y lcov
|
||||
lcov ${{ env.LCOV_CAPTURE_FLAGS }} --initial --output-file coverage_base.info
|
||||
sed -i -e "s#${PWD}#.#" coverage_base.info # Make paths relative.
|
||||
|
||||
- name: Integration test
|
||||
run: |
|
||||
.pio/build/coverage/program &
|
||||
PID=$!
|
||||
timeout 20 bash -c "until ls -al /proc/$PID/fd | grep socket; do sleep 1; done"
|
||||
echo "Simulator started, launching python test..."
|
||||
python3 -c 'from meshtastic.test import testSimulator; testSimulator()'
|
||||
wait
|
||||
|
||||
- name: Capture coverage information
|
||||
if: always() # run this step even if previous step failed
|
||||
run: |
|
||||
lcov ${{ env.LCOV_CAPTURE_FLAGS }} --test-name integration --output-file coverage_integration.info
|
||||
sed -i -e "s#${PWD}#.#" coverage_integration.info # Make paths relative.
|
||||
|
||||
- name: Get release version string
|
||||
if: always() # run this step even if previous step failed
|
||||
run: echo "long=$(./bin/buildinfo.py long)" >> $GITHUB_OUTPUT
|
||||
id: version
|
||||
|
||||
- name: Save coverage information
|
||||
uses: actions/upload-artifact@v4
|
||||
if: always() # run this step even if previous step failed
|
||||
with:
|
||||
name: lcov-coverage-info-native-simulator-test-${{ steps.version.outputs.long }}.zip
|
||||
overwrite: true
|
||||
path: ./coverage_*.info
|
||||
|
||||
platformio-tests:
|
||||
name: Native PlatformIO Tests
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
ref: ${{github.event.pull_request.head.ref}}
|
||||
repository: ${{github.event.pull_request.head.repo.full_name}}
|
||||
submodules: recursive
|
||||
|
||||
- name: Setup native build
|
||||
id: base
|
||||
uses: ./.github/actions/setup-native
|
||||
|
||||
- name: Get release version string
|
||||
run: echo "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@v4
|
||||
with:
|
||||
name: platformio-test-report-${{ steps.version.outputs.long }}.zip
|
||||
overwrite: true
|
||||
path: ./testreport.xml
|
||||
|
||||
- name: Capture coverage information
|
||||
if: always() # run this step even if previous step failed
|
||||
run: |
|
||||
sudo apt-get install -y lcov
|
||||
lcov ${{ env.LCOV_CAPTURE_FLAGS }} --test-name tests --output-file coverage_tests.info
|
||||
sed -i -e "s#${PWD}#.#" coverage_tests.info # Make paths relative.
|
||||
|
||||
- name: Save coverage information
|
||||
uses: actions/upload-artifact@v4
|
||||
if: always() # run this step even if previous step failed
|
||||
with:
|
||||
name: lcov-coverage-info-native-platformio-tests-${{ steps.version.outputs.long }}.zip
|
||||
overwrite: true
|
||||
path: ./coverage_*.info
|
||||
|
||||
generate-reports:
|
||||
name: Generate Test Reports
|
||||
runs-on: ubuntu-latest
|
||||
permissions: # Needed for dorny/test-reporter.
|
||||
contents: read
|
||||
actions: read
|
||||
checks: write
|
||||
needs:
|
||||
- simulator-tests
|
||||
- platformio-tests
|
||||
if: always()
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
ref: ${{github.event.pull_request.head.ref}}
|
||||
repository: ${{github.event.pull_request.head.repo.full_name}}
|
||||
|
||||
- name: Get release version string
|
||||
run: echo "long=$(./bin/buildinfo.py long)" >> $GITHUB_OUTPUT
|
||||
id: version
|
||||
|
||||
- name: Download test artifacts
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: platformio-test-report-${{ steps.version.outputs.long }}.zip
|
||||
merge-multiple: true
|
||||
|
||||
- name: Test Report
|
||||
uses: dorny/test-reporter@v1.9.1
|
||||
with:
|
||||
name: PlatformIO Tests
|
||||
path: testreport.xml
|
||||
reporter: java-junit
|
||||
|
||||
- name: Download coverage artifacts
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
pattern: lcov-coverage-info-native-*-${{ steps.version.outputs.long }}.zip
|
||||
path: code-coverage-report
|
||||
merge-multiple: true
|
||||
|
||||
- name: Generate Code Coverage Report
|
||||
run: |
|
||||
sudo apt-get install -y lcov
|
||||
lcov --quiet --add-tracefile code-coverage-report/coverage_base.info --add-tracefile code-coverage-report/coverage_integration.info --add-tracefile code-coverage-report/coverage_tests.info --output-file code-coverage-report/coverage_src.info
|
||||
genhtml --quiet --legend --prefix "${PWD}" code-coverage-report/coverage_src.info --output-directory code-coverage-report
|
||||
|
||||
- name: Save Code Coverage Report
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: code-coverage-report-${{ steps.version.outputs.long }}.zip
|
||||
path: code-coverage-report
|
||||
51
.github/workflows/tests.yml
vendored
51
.github/workflows/tests.yml
vendored
@@ -6,55 +6,8 @@ on:
|
||||
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
|
||||
native-tests:
|
||||
uses: ./.github/workflows/test_native.yml
|
||||
|
||||
hardware-tests:
|
||||
runs-on: test-runner
|
||||
|
||||
6
.github/workflows/trunk_format_pr.yml
vendored
6
.github/workflows/trunk_format_pr.yml
vendored
@@ -22,12 +22,16 @@ jobs:
|
||||
- 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.version }}"
|
||||
git commit -m "Add firmware version ${{ steps.version.outputs.long }}"
|
||||
git push
|
||||
|
||||
- name: Comment on PR
|
||||
|
||||
1
.github/workflows/update_protobufs.yml
vendored
1
.github/workflows/update_protobufs.yml
vendored
@@ -12,6 +12,7 @@ jobs:
|
||||
submodules: true
|
||||
|
||||
- name: Update submodule
|
||||
if: ${{ github.ref == 'refs/heads/master' }}
|
||||
run: |
|
||||
git submodule update --remote protobufs
|
||||
|
||||
|
||||
9
.gitignore
vendored
9
.gitignore
vendored
@@ -1,4 +1,8 @@
|
||||
.pio
|
||||
pio
|
||||
pio.tar
|
||||
web
|
||||
web.tar
|
||||
|
||||
# ignore vscode IDE settings files
|
||||
.vscode/*
|
||||
@@ -8,6 +12,9 @@
|
||||
*.code-workspace
|
||||
|
||||
.idea
|
||||
.platformio
|
||||
.local
|
||||
.cache
|
||||
|
||||
.DS_Store
|
||||
Thumbs.db
|
||||
@@ -30,4 +37,4 @@ release/
|
||||
.vscode/extensions.json
|
||||
/compile_commands.json
|
||||
src/mesh/raspihttp/certificate.pem
|
||||
src/mesh/raspihttp/private_key.pem
|
||||
src/mesh/raspihttp/private_key.pem
|
||||
10
.trunk/configs/.prettierrc
Normal file
10
.trunk/configs/.prettierrc
Normal file
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"overrides": [
|
||||
{
|
||||
"files": "userPrefs.jsonc",
|
||||
"options": {
|
||||
"trailingComma": "none"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
71
Dockerfile
71
Dockerfile
@@ -1,32 +1,29 @@
|
||||
FROM debian:bookworm-slim AS builder
|
||||
# trunk-ignore-all(terrascan/AC_DOCKER_0002): Known terrascan issue
|
||||
# trunk-ignore-all(hadolint/DL3008): Use latest version of apt packages for buildchain
|
||||
# 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 python:3.12-bookworm AS builder
|
||||
ENV DEBIAN_FRONTEND=noninteractive
|
||||
ENV TZ=Etc/UTC
|
||||
|
||||
# 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 \
|
||||
libusb-1.0-0-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
|
||||
# Install Dependencies
|
||||
ENV PIP_ROOT_USER_ACTION=ignore
|
||||
RUN apt-get update && apt-get install --no-install-recommends -y wget g++ zip git ca-certificates \
|
||||
libgpiod-dev libyaml-cpp-dev libbluetooth-dev libi2c-dev \
|
||||
libusb-1.0-0-dev libulfius-dev liborcania-dev libssl-dev pkg-config && \
|
||||
apt-get clean && rm -rf /var/lib/apt/lists/* && \
|
||||
pip install --no-cache-dir -U platformio==6.1.16 && \
|
||||
mkdir /tmp/firmware
|
||||
|
||||
# Copy source code
|
||||
WORKDIR /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"
|
||||
COPY . /tmp/firmware
|
||||
|
||||
# Build
|
||||
RUN bash ./bin/build-native.sh && \
|
||||
cp "/tmp/firmware/release/meshtasticd_linux_$(uname -m)" "/tmp/firmware/release/meshtasticd"
|
||||
|
||||
|
||||
##### PRODUCTION BUILD #############
|
||||
@@ -35,20 +32,26 @@ FROM debian:bookworm-slim
|
||||
ENV DEBIAN_FRONTEND=noninteractive
|
||||
ENV TZ=Etc/UTC
|
||||
|
||||
# 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 libusb-1.0-0-dev liborcania2.3 libssl3 && \
|
||||
apt-get clean && rm -rf /var/lib/apt/lists/*
|
||||
# nosemgrep: dockerfile.security.last-user-is-root.last-user-is-root
|
||||
USER root
|
||||
|
||||
RUN groupadd -g 1000 mesh && useradd -ml -u 1000 -g 1000 mesh
|
||||
USER mesh
|
||||
RUN apt-get update && apt-get --no-install-recommends -y install libc-bin libc6 libgpiod2 libyaml-cpp0.7 libi2c0 libulfius2.7 libusb-1.0-0-dev liborcania2.3 libssl3 && \
|
||||
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
|
||||
|
||||
WORKDIR /home/mesh
|
||||
COPY --from=builder /tmp/firmware/release/meshtasticd /home/mesh/
|
||||
# Fetch compiled binary from the builder
|
||||
COPY --from=builder /tmp/firmware/release/meshtasticd /usr/sbin/
|
||||
# Copy config templates
|
||||
COPY ./bin/config.d /etc/meshtasticd/available.d
|
||||
|
||||
RUN mkdir data
|
||||
VOLUME /home/mesh/data
|
||||
WORKDIR /var/lib/meshtasticd
|
||||
VOLUME /var/lib/meshtasticd
|
||||
|
||||
CMD [ "sh", "-cx", "./meshtasticd -d /home/mesh/data --hwid=${HWID:-$RANDOM}" ]
|
||||
# Expose Meshtastic TCP API port from the host
|
||||
EXPOSE 4403
|
||||
|
||||
CMD [ "sh", "-cx", "meshtasticd -d /var/lib/meshtasticd" ]
|
||||
|
||||
HEALTHCHECK NONE
|
||||
43
alpine.Dockerfile
Normal file
43
alpine.Dockerfile
Normal file
@@ -0,0 +1,43 @@
|
||||
# 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 python:3.12-alpine3.21 AS builder
|
||||
|
||||
ENV PIP_ROOT_USER_ACTION=ignore
|
||||
RUN apk add bash g++ libstdc++-dev linux-headers zip git ca-certificates libgpiod-dev yaml-cpp-dev bluez-dev \
|
||||
libusb-dev i2c-tools-dev openssl-dev pkgconf argp-standalone && \
|
||||
pip install --no-cache-dir -U platformio==6.1.16 && \
|
||||
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 && \
|
||||
cp "/tmp/firmware/release/meshtasticd_linux_$(uname -m)" "/tmp/firmware/release/meshtasticd"
|
||||
|
||||
# ##### PRODUCTION BUILD #############
|
||||
|
||||
FROM alpine:3.21
|
||||
|
||||
# nosemgrep: dockerfile.security.last-user-is-root.last-user-is-root
|
||||
USER root
|
||||
|
||||
RUN apk add libstdc++ libgpiod yaml-cpp libusb i2c-tools \
|
||||
&& mkdir -p /var/lib/meshtasticd \
|
||||
&& mkdir -p /etc/meshtasticd/config.d \
|
||||
&& mkdir -p /etc/meshtasticd/ssl
|
||||
COPY --from=builder /tmp/firmware/release/meshtasticd /usr/sbin/
|
||||
|
||||
WORKDIR /var/lib/meshtasticd
|
||||
VOLUME /var/lib/meshtasticd
|
||||
|
||||
EXPOSE 4403
|
||||
|
||||
CMD [ "sh", "-cx", "meshtasticd --fsdir=/var/lib/meshtasticd" ]
|
||||
|
||||
HEALTHCHECK NONE
|
||||
@@ -4,7 +4,7 @@ platform = platformio/nordicnrf52@^10.7.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
|
||||
framework-arduinoadafruitnrf52 @ https://github.com/meshtastic/Adafruit_nRF52_Arduino.git#e13f5820002a4fb2a5e6754b42ace185277e5adf
|
||||
toolchain-gccarmnoneeabi@~1.90301.0
|
||||
|
||||
build_type = debug
|
||||
|
||||
@@ -25,8 +25,8 @@ lib_deps =
|
||||
${networking_base.lib_deps}
|
||||
${radiolib_base.lib_deps}
|
||||
rweather/Crypto@^0.4.0
|
||||
https://github.com/lovyan03/LovyanGFX.git#1401c28a47646fe00538d487adcb2eb3c72de805
|
||||
https://github.com/pine64/libch341-spi-userspace#8695637adeabf5abf5601d8e82cb0ba19ce9ec46
|
||||
lovyan03/LovyanGFX@^1.2.0
|
||||
https://github.com/pine64/libch341-spi-userspace#a9b17e3452f7fb747000d9b4ad4409155b39f6ef
|
||||
|
||||
build_flags =
|
||||
${arduino_base.build_flags}
|
||||
@@ -40,4 +40,4 @@ build_flags =
|
||||
-lgpiod
|
||||
-lyaml-cpp
|
||||
-li2c
|
||||
-std=c++17
|
||||
-std=c++17
|
||||
|
||||
@@ -7,12 +7,12 @@ platform_packages = framework-arduinopico@https://github.com/earlephilhower/ardu
|
||||
board_build.core = earlephilhower
|
||||
board_build.filesystem_size = 0.5m
|
||||
build_flags =
|
||||
${arduino_base.build_flags} -Wno-unused-variable
|
||||
${arduino_base.build_flags} -Wno-unused-variable -Wcast-align
|
||||
-Isrc/platform/rp2xx0
|
||||
-D__PLAT_RP2040__
|
||||
-D__PLAT_RP2350__
|
||||
# -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>
|
||||
${arduino_base.build_src_filter} -<platform/esp32/> -<nimble/> -<modules/esp32> -<platform/nrf52/> -<platform/stm32wl> -<mesh/eth/> -<mesh/wifi/> -<mesh/http/> -<mesh/raspihttp> -<platform/rp2xx0/pico_sleep> -<platform/rp2xx0/hardware_rosc>
|
||||
|
||||
lib_ignore =
|
||||
BluetoothOTA
|
||||
|
||||
@@ -11,9 +11,15 @@ build_flags =
|
||||
${arduino_base.build_flags}
|
||||
-flto
|
||||
-Isrc/platform/stm32wl -g
|
||||
-DMESHTASTIC_MINIMIZE_BUILD
|
||||
-DMESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR
|
||||
-DMESHTASTIC_EXCLUDE_INPUTBROKER
|
||||
-DMESHTASTIC_EXCLUDE_I2C
|
||||
-DMESHTASTIC_EXCLUDE_POWERMON
|
||||
-DMESHTASTIC_EXCLUDE_SCREEN
|
||||
-DMESHTASTIC_EXCLUDE_MQTT
|
||||
-DMESHTASTIC_EXCLUDE_BLUETOOTH
|
||||
-DMESHTASTIC_EXCLUDE_PKI
|
||||
-DMESHTASTIC_EXCLUDE_GPS
|
||||
-DDEBUG_MUTE
|
||||
; -DVECT_TAB_OFFSET=0x08000000
|
||||
-DconfigUSE_CMSIS_RTOS_V2=1
|
||||
; -DSPI_MODE_0=SPI_MODE0
|
||||
|
||||
1
bin/.gitignore
vendored
Normal file
1
bin/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
||||
config.yaml
|
||||
18
bin/build-firmware.sh
Normal file
18
bin/build-firmware.sh
Normal file
@@ -0,0 +1,18 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
sed -i 's/#-DBUILD_EPOCH=$UNIX_TIME/-DBUILD_EPOCH=$UNIX_TIME/' platformio.ini
|
||||
|
||||
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-rpi2040.sh $1
|
||||
else
|
||||
echo "Unknown target $2"
|
||||
exit 1
|
||||
fi
|
||||
@@ -12,12 +12,6 @@ Lora:
|
||||
# IRQ: 17
|
||||
# Reset: 22
|
||||
|
||||
# Module: RF95 # Adafruit RFM9x
|
||||
# Reset: 25
|
||||
# CS: 7
|
||||
# IRQ: 22
|
||||
# Busy: 23
|
||||
|
||||
# Module: RF95 # Elecrow Lora RFM95 IOT https://www.elecrow.com/lora-rfm95-iot-board-for-rpi.html
|
||||
# Reset: 22
|
||||
# CS: 7
|
||||
@@ -29,6 +23,47 @@ Lora:
|
||||
# Busy: 20
|
||||
# Reset: 18
|
||||
|
||||
### The Radxa Zero 3E/W employs multiple gpio chips.
|
||||
### Each gpio pin must be unique, but can be assigned to a specific gpio chip and line.
|
||||
### In case solely a no. is given, the default gpio chip and pin == line will be employed.
|
||||
###
|
||||
# Module: sx1262 # Radxa Zero 3E/W + Ebyte E22-900M30S
|
||||
# DIO2_AS_RF_SWITCH: true
|
||||
# DIO3_TCXO_VOLTAGE: 1.8
|
||||
# CS: # NSS PIN_24 -> chip 4, line 22
|
||||
# pin: 24
|
||||
# gpiochip: 4
|
||||
# line: 22
|
||||
# SCK: # SCK PIN_23 -> chip 4, line 18
|
||||
# pin: 23
|
||||
# gpiochip: 4
|
||||
# line: 18
|
||||
# Busy: # BUSY PIN_29 -> chip 3!, line 11
|
||||
# pin: 29
|
||||
# gpiochip: 3
|
||||
# line: 11
|
||||
# MOSI: # MOSI PIN_19 -> chip 4, line 19
|
||||
# pin: 19
|
||||
# gpiochip: 4
|
||||
# line: 19
|
||||
# MISO: # MISO PIN_21 -> chip 4, line 21
|
||||
# pin: 21
|
||||
# gpiochip: 4
|
||||
# line: 21
|
||||
# Reset: # NRST PIN_27 -> chip 4, line 10
|
||||
# pin: 27
|
||||
# gpiochip: 4
|
||||
# line: 10
|
||||
# IRQ: # DIO1 PIN_28 -> chip 4, line 11
|
||||
# pin: 28
|
||||
# gpiochip: 4
|
||||
# line: 11
|
||||
# RXen: # RXEN PIN_22 -> chip 3!, line 17
|
||||
# pin: 22
|
||||
# gpiochip: 3
|
||||
# line: 17
|
||||
# TXen: RADIOLIB_NC # TXEN no PIN, no line, fallback to default gpio chip
|
||||
|
||||
# Module: sx1268 # SX1268-based modules, tested with Ebyte E22 400M33S
|
||||
# CS: 21
|
||||
# IRQ: 16
|
||||
@@ -43,9 +78,11 @@ Lora:
|
||||
# TXen: x # TX and RX enable pins
|
||||
# RXen: x
|
||||
|
||||
# SX126X_MAX_POWER: 8 # Limit the output power to 8 dBm, useful for amped nodes
|
||||
|
||||
# spiSpeed: 2000000
|
||||
|
||||
### Set gpio chip to use in /dev/. Defaults to 0.
|
||||
### Set default/fallback gpio chip to use in /dev/. Defaults to 0.
|
||||
### Notably the Raspberry Pi 5 puts the GPIO header on gpiochip4
|
||||
# gpiochip: 4
|
||||
|
||||
@@ -147,6 +184,8 @@ Logging:
|
||||
Webserver:
|
||||
# Port: 443 # Port for Webserver & Webservices
|
||||
# RootPath: /usr/share/meshtasticd/web # Root Dir of WebServer
|
||||
# SSLKey: /etc/meshtasticd/ssl/private_key.pem # Path to SSL Key, generated if not present
|
||||
# SSLCert: /etc/meshtasticd/ssl/certificate.pem # Path to SSL Certificate, generated if not present
|
||||
|
||||
General:
|
||||
MaxNodes: 200
|
||||
|
||||
9
bin/config.d/OpenWRT/BananaPi-BPI-R4-sx1262.yaml
Normal file
9
bin/config.d/OpenWRT/BananaPi-BPI-R4-sx1262.yaml
Normal file
@@ -0,0 +1,9 @@
|
||||
Lora:
|
||||
Module: sx1262 # BananaPi-BPI-R4 SPI via 26p GPIO Header
|
||||
## CS: 28
|
||||
IRQ: 50
|
||||
Busy: 62
|
||||
Reset: 51
|
||||
spidev: spidev1.0
|
||||
DIO2_AS_RF_SWITCH: true
|
||||
DIO3_TCXO_VOLTAGE: true
|
||||
5
bin/config.d/lora-Adafruit-RFM9x
Normal file
5
bin/config.d/lora-Adafruit-RFM9x
Normal file
@@ -0,0 +1,5 @@
|
||||
# Module: RF95 # Adafruit RFM9x
|
||||
# Reset: 25
|
||||
# CS: 7
|
||||
# IRQ: 22
|
||||
# Busy: 23
|
||||
@@ -7,3 +7,6 @@ Lora:
|
||||
TXen: 13
|
||||
RXen: 12
|
||||
DIO3_TCXO_VOLTAGE: true
|
||||
# Only for E22-900M33S:
|
||||
# Limit the output power to 8 dBm
|
||||
# SX126X_MAX_POWER: 8
|
||||
@@ -73,7 +73,7 @@ shift "$((OPTIND - 1))"
|
||||
if [ -f "${FILENAME}" ] && [ -n "${FILENAME##*"update"*}" ]; then
|
||||
echo "Trying to flash ${FILENAME}, but first erasing and writing system information"
|
||||
$ESPTOOL_CMD erase_flash
|
||||
$ESPTOOL_CMD write_flash 0x00 ${FILENAME}
|
||||
$ESPTOOL_CMD write_flash 0x00 "${FILENAME}"
|
||||
# Account for S3 board's different OTA partition
|
||||
if [ -n "${FILENAME##*"s3"*}" ] && [ -n "${FILENAME##*"-v3"*}" ] && [ -n "${FILENAME##*"t-deck"*}" ] && [ -n "${FILENAME##*"wireless-paper"*}" ] && [ -n "${FILENAME##*"wireless-tracker"*}" ] && [ -n "${FILENAME##*"station-g2"*}" ] && [ -n "${FILENAME##*"unphone"*}" ]; then
|
||||
if [ -n "${FILENAME##*"esp32c3"*}" ]; then
|
||||
|
||||
@@ -102,7 +102,7 @@ pref_flags = []
|
||||
for pref in userPrefs:
|
||||
if userPrefs[pref].startswith("{"):
|
||||
pref_flags.append("-D" + pref + "=" + userPrefs[pref])
|
||||
elif userPrefs[pref].replace(".", "").isdigit():
|
||||
elif userPrefs[pref].lstrip("-").replace(".", "").isdigit():
|
||||
pref_flags.append("-D" + pref + "=" + userPrefs[pref])
|
||||
elif userPrefs[pref] == "true" or userPrefs[pref] == "false":
|
||||
pref_flags.append("-D" + pref + "=" + userPrefs[pref])
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
import configparser
|
||||
import subprocess
|
||||
|
||||
import os
|
||||
run_number = os.getenv('GITHUB_RUN_NUMBER', '0')
|
||||
build_location = os.getenv('BUILD_LOCATION', 'local')
|
||||
|
||||
def readProps(prefsLoc):
|
||||
"""Read the version of our project as a string"""
|
||||
@@ -11,6 +13,7 @@ def readProps(prefsLoc):
|
||||
verObj = dict(
|
||||
short="{}.{}.{}".format(version["major"], version["minor"], version["build"]),
|
||||
long="unset",
|
||||
deb="unset",
|
||||
)
|
||||
|
||||
# Try to find current build SHA if if the workspace is clean. This could fail if git is not installed
|
||||
@@ -27,16 +30,16 @@ def readProps(prefsLoc):
|
||||
# if isDirty:
|
||||
# # short for 'dirty', we want to keep our verstrings source for protobuf reasons
|
||||
# suffix = sha + "-d"
|
||||
verObj["long"] = "{}.{}.{}.{}".format(
|
||||
version["major"], version["minor"], version["build"], suffix
|
||||
)
|
||||
verObj["long"] = "{}.{}".format(verObj["short"], suffix)
|
||||
verObj["deb"] = "{}.{}~{}{}".format(verObj["short"], run_number, build_location, sha)
|
||||
except:
|
||||
# print("Unexpected error:", sys.exc_info()[0])
|
||||
# traceback.print_exc()
|
||||
verObj["long"] = verObj["short"]
|
||||
verObj["deb"] = "{}.{}~{}".format(verObj["short"], run_number, build_location)
|
||||
|
||||
# print("firmware version " + verStr)
|
||||
return verObj
|
||||
|
||||
|
||||
# print("path is" + ','.join(sys.path))
|
||||
# print("path is" + ','.join(sys.path))
|
||||
12
bin/rpkg.macros
Normal file
12
bin/rpkg.macros
Normal file
@@ -0,0 +1,12 @@
|
||||
function meshtastic_version {
|
||||
meshtastic_version=$(python3 bin/buildinfo.py short)
|
||||
echo -n "$meshtastic_version"
|
||||
}
|
||||
function git_commits_num {
|
||||
total_commits=$(git rev-list --all --count)
|
||||
echo -n "$total_commits"
|
||||
}
|
||||
function git_commit_sha {
|
||||
commit_sha=$(git rev-parse --short HEAD)
|
||||
echo -n "$commit_sha"
|
||||
}
|
||||
42
boards/mesh-tab.json
Normal file
42
boards/mesh-tab.json
Normal file
@@ -0,0 +1,42 @@
|
||||
{
|
||||
"build": {
|
||||
"arduino": {
|
||||
"ldscript": "esp32s3_out.ld",
|
||||
"partitions": "default_16MB.csv",
|
||||
"memory_type": "qio_qspi"
|
||||
},
|
||||
"core": "esp32",
|
||||
"extra_flags": [
|
||||
"-DBOARD_HAS_PSRAM",
|
||||
"-DARDUINO_USB_CDC_ON_BOOT=1",
|
||||
"-DARDUINO_USB_MODE=0",
|
||||
"-DARDUINO_RUNNING_CORE=1",
|
||||
"-DARDUINO_EVENT_RUNNING_CORE=1"
|
||||
],
|
||||
"f_cpu": "240000000L",
|
||||
"f_flash": "80000000L",
|
||||
"flash_mode": "qio",
|
||||
"hwids": [["0x303A", "0x80D6"]],
|
||||
"mcu": "esp32s3",
|
||||
"variant": "mesh-tab"
|
||||
},
|
||||
"connectivity": ["wifi", "bluetooth", "lora"],
|
||||
"debug": {
|
||||
"default_tool": "esp-builtin",
|
||||
"onboard_tools": ["esp-builtin"],
|
||||
"openocd_target": "esp32s3.cfg"
|
||||
},
|
||||
"frameworks": ["arduino", "espidf"],
|
||||
"name": "ESP32-S3 WROOM-1 N16R2 (16 MB FLASH, 2 MB PSRAM)",
|
||||
"upload": {
|
||||
"flash_size": "16MB",
|
||||
"maximum_ram_size": 327680,
|
||||
"maximum_size": 16777216,
|
||||
"use_1200bps_touch": true,
|
||||
"wait_for_upload_port": true,
|
||||
"require_upload_port": true,
|
||||
"speed": 460800
|
||||
},
|
||||
"url": "https://github.com/valzzu/Mesh-Tab",
|
||||
"vendor": "Espressif"
|
||||
}
|
||||
52
boards/meshlink.json
Normal file
52
boards/meshlink.json
Normal file
@@ -0,0 +1,52 @@
|
||||
{
|
||||
"build": {
|
||||
"arduino": {
|
||||
"ldscript": "nrf52840_s140_v6.ld"
|
||||
},
|
||||
"core": "nRF5",
|
||||
"cpu": "cortex-m4",
|
||||
"extra_flags": "-DMESHLINK -DNRF52840_XXAA",
|
||||
"f_cpu": "64000000L",
|
||||
"hwids": [
|
||||
["0x239A", "0x00B3"],
|
||||
["0x239A", "0x8029"],
|
||||
["0x239A", "0x0029"],
|
||||
["0x239A", "0x002A"],
|
||||
["0x239A", "0x802A"]
|
||||
],
|
||||
"usb_product": "MeshLink",
|
||||
"mcu": "nrf52840",
|
||||
"variant": "meshlink",
|
||||
"bsp": {
|
||||
"name": "adafruit"
|
||||
},
|
||||
"softdevice": {
|
||||
"sd_flags": "-DS140",
|
||||
"sd_name": "s140",
|
||||
"sd_version": "6.1.1",
|
||||
"sd_fwid": "0x00B6"
|
||||
},
|
||||
"bootloader": {
|
||||
"settings_addr": "0xFF000"
|
||||
}
|
||||
},
|
||||
"connectivity": ["bluetooth"],
|
||||
"debug": {
|
||||
"jlink_device": "nRF52840_xxAA",
|
||||
"svd_path": "nrf52840.svd"
|
||||
},
|
||||
"frameworks": ["arduino"],
|
||||
"name": "MeshLink",
|
||||
"upload": {
|
||||
"maximum_ram_size": 248832,
|
||||
"maximum_size": 815104,
|
||||
"speed": 115200,
|
||||
"protocol": "nrfutil",
|
||||
"protocols": ["nrfutil", "jlink", "nrfjprog", "stlink"],
|
||||
"use_1200bps_touch": true,
|
||||
"require_upload_port": true,
|
||||
"wait_for_upload_port": true
|
||||
},
|
||||
"url": "https://www.loraitalia.it",
|
||||
"vendor": "LoraItalia"
|
||||
}
|
||||
@@ -15,10 +15,12 @@
|
||||
],
|
||||
"f_cpu": "240000000L",
|
||||
"f_flash": "80000000L",
|
||||
"f_boot": "120000000L",
|
||||
"boot": "qio",
|
||||
"flash_mode": "qio",
|
||||
"hwids": [["0x1A86", "0x7523"]],
|
||||
"mcu": "esp32s3",
|
||||
"variant": "esp32s3r8"
|
||||
"variant": "esp32s3"
|
||||
},
|
||||
"connectivity": ["wifi", "bluetooth", "lora"],
|
||||
"debug": {
|
||||
@@ -32,9 +34,9 @@
|
||||
"flash_size": "8MB",
|
||||
"maximum_ram_size": 327680,
|
||||
"maximum_size": 8388608,
|
||||
"require_upload_port": true,
|
||||
"require_upload_port": false,
|
||||
"use_1200bps_touch": true,
|
||||
"wait_for_upload_port": true,
|
||||
"wait_for_upload_port": false,
|
||||
"speed": 921600
|
||||
},
|
||||
"url": "https://www.seeedstudio.com/Indicator-for-Meshtastic.html",
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
"-DARDUINO_USB_CDC_ON_BOOT=1",
|
||||
"-DARDUINO_USB_MODE=0",
|
||||
"-DARDUINO_RUNNING_CORE=1",
|
||||
"-DARDUINO_EVENT_RUNNING_CORE=0"
|
||||
"-DARDUINO_EVENT_RUNNING_CORE=1"
|
||||
],
|
||||
"f_cpu": "240000000L",
|
||||
"f_flash": "80000000L",
|
||||
|
||||
6
debian/.gitignore
vendored
Normal file
6
debian/.gitignore
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
.debhelper
|
||||
debhelper-build-stamp
|
||||
meshtasticd
|
||||
files
|
||||
meshtasticd.substvars
|
||||
meshtasticd.postrm.debhelper
|
||||
9
debian/changelog
vendored
Normal file
9
debian/changelog
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
meshtasticd (2.5.22.0) UNRELEASED; urgency=medium
|
||||
|
||||
* Initial packaging
|
||||
* GitHub Actions Automatic version bump
|
||||
* GitHub Actions Automatic version bump
|
||||
* GitHub Actions Automatic version bump
|
||||
* GitHub Actions Automatic version bump
|
||||
|
||||
-- Austin Lane <github-actions[bot]@users.noreply.github.com> Wed, 05 Feb 2025 01:10:33 +0000
|
||||
7
debian/ci_changelog.sh
vendored
Executable file
7
debian/ci_changelog.sh
vendored
Executable file
@@ -0,0 +1,7 @@
|
||||
#!/usr/bin/bash
|
||||
export DEBEMAIL="github-actions[bot]@users.noreply.github.com"
|
||||
PKG_VERSION=$(python3 bin/buildinfo.py short)
|
||||
|
||||
dch --newversion "$PKG_VERSION.0" \
|
||||
--distribution UNRELEASED \
|
||||
"GitHub Actions Automatic version bump"
|
||||
23
debian/ci_pack_sdeb.sh
vendored
Executable file
23
debian/ci_pack_sdeb.sh
vendored
Executable file
@@ -0,0 +1,23 @@
|
||||
#!/usr/bin/bash
|
||||
export DEBEMAIL="jbennett@incomsystems.biz"
|
||||
export PLATFORMIO_LIBDEPS_DIR=pio/libdeps
|
||||
export PLATFORMIO_PACKAGES_DIR=pio/packages
|
||||
export PLATFORMIO_CORE_DIR=pio/core
|
||||
|
||||
# Download libraries to `pio`
|
||||
platformio pkg install -e native
|
||||
platformio pkg install -e native -t platformio/tool-scons@4.40502.0
|
||||
# Compress `pio` directory to prevent dh_clean from sanitizing it
|
||||
tar -cf pio.tar pio/
|
||||
rm -rf pio
|
||||
# Download the latest meshtastic/web release build.tar to `web.tar`
|
||||
curl -L https://github.com/meshtastic/web/releases/latest/download/build.tar -o web.tar
|
||||
|
||||
package=$(dpkg-parsechangelog --show-field Source)
|
||||
|
||||
rm -rf debian/changelog
|
||||
dch --create --distribution "$SERIES" --package "$package" --newversion "$PKG_VERSION~$SERIES" \
|
||||
"GitHub Actions Automatic packaging for $PKG_VERSION~$SERIES"
|
||||
|
||||
# Build the source deb
|
||||
debuild -S -nc -k"$GPG_KEY_ID"
|
||||
32
debian/control
vendored
Normal file
32
debian/control
vendored
Normal file
@@ -0,0 +1,32 @@
|
||||
Source: meshtasticd
|
||||
Section: misc
|
||||
Priority: optional
|
||||
Maintainer: Austin Lane <vidplace7@gmail.com>
|
||||
Build-Depends: debhelper-compat (= 13),
|
||||
tar,
|
||||
gzip,
|
||||
platformio,
|
||||
python3-protobuf,
|
||||
python3-grpcio,
|
||||
git,
|
||||
g++,
|
||||
pkg-config,
|
||||
libyaml-cpp-dev,
|
||||
libgpiod-dev,
|
||||
libbluetooth-dev,
|
||||
libusb-1.0-0-dev,
|
||||
libi2c-dev,
|
||||
openssl,
|
||||
libssl-dev,
|
||||
libulfius-dev,
|
||||
liborcania-dev
|
||||
Standards-Version: 4.6.2
|
||||
Homepage: https://github.com/meshtastic/firmware
|
||||
Rules-Requires-Root: no
|
||||
|
||||
Package: meshtasticd
|
||||
Architecture: any
|
||||
Depends: ${misc:Depends}, ${shlibs:Depends}
|
||||
Description: Meshtastic daemon for communicating with Meshtastic devices
|
||||
Meshtastic is an off-grid text communication platform that uses inexpensive
|
||||
LoRa radios.
|
||||
5
debian/meshtasticd.dirs
vendored
Normal file
5
debian/meshtasticd.dirs
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
etc/meshtasticd
|
||||
etc/meshtasticd/config.d
|
||||
etc/meshtasticd/available.d
|
||||
usr/share/meshtasticd/web
|
||||
etc/meshtasticd/ssl
|
||||
8
debian/meshtasticd.install
vendored
Normal file
8
debian/meshtasticd.install
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
.pio/build/native/meshtasticd usr/sbin
|
||||
|
||||
bin/config.yaml etc/meshtasticd
|
||||
bin/config.d/* etc/meshtasticd/available.d
|
||||
|
||||
bin/meshtasticd.service lib/systemd/system
|
||||
|
||||
web/* usr/share/meshtasticd/web
|
||||
23
debian/rules
vendored
Executable file
23
debian/rules
vendored
Executable file
@@ -0,0 +1,23 @@
|
||||
#!/usr/bin/make -f
|
||||
# export DH_VERBOSE = 1
|
||||
|
||||
# Use the "dh" sequencer
|
||||
%:
|
||||
dh $@
|
||||
|
||||
# https://docs.platformio.org/en/latest/envvars.html
|
||||
PIO_ENV:=\
|
||||
PLATFORMIO_CORE_DIR=pio/core \
|
||||
PLATFORMIO_LIBDEPS_DIR=pio/libdeps \
|
||||
PLATFORMIO_PACKAGES_DIR=pio/packages
|
||||
|
||||
override_dh_auto_build:
|
||||
# Extract tarballs within source deb
|
||||
tar -xf pio.tar
|
||||
mkdir -p web && tar -xf web.tar -C web
|
||||
gunzip web/ -r
|
||||
# Build with platformio
|
||||
$(PIO_ENV) platformio run -e native
|
||||
# Move the binary and default config to the correct name
|
||||
mv .pio/build/native/program .pio/build/native/meshtasticd
|
||||
cp bin/config-dist.yaml bin/config.yaml
|
||||
1
debian/source/format
vendored
Normal file
1
debian/source/format
vendored
Normal file
@@ -0,0 +1 @@
|
||||
3.0 (native)
|
||||
2
debian/source/include-binaries
vendored
Normal file
2
debian/source/include-binaries
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
pio.tar
|
||||
web.tar
|
||||
1
debian/source/options
vendored
Normal file
1
debian/source/options
vendored
Normal file
@@ -0,0 +1 @@
|
||||
extend-diff-ignore = "\.pio"
|
||||
@@ -1,13 +1,26 @@
|
||||
version: "3.7"
|
||||
# USB-Based Meshtastic container-node!
|
||||
|
||||
# Copy .env.example to .env and set the USB_DEVICE and CONFIG_PATH variables
|
||||
|
||||
services:
|
||||
meshtastic-node:
|
||||
build: .
|
||||
deploy:
|
||||
mode: replicated
|
||||
replicas: 4
|
||||
networks:
|
||||
- mesh
|
||||
container_name: meshtasticd
|
||||
|
||||
networks:
|
||||
mesh:
|
||||
# Pass USB device through to the container
|
||||
devices:
|
||||
- "${USB_DEVICE}"
|
||||
|
||||
# Mount local config file and named volume for data persistence
|
||||
volumes:
|
||||
- "${CONFIG_PATH}:/etc/meshtasticd/config.yaml:ro"
|
||||
- meshtastic_data:/var/lib/meshtasticd
|
||||
|
||||
# Forward the container’s port 4403 to the host
|
||||
ports:
|
||||
- 4403:4403
|
||||
|
||||
restart: unless-stopped
|
||||
|
||||
volumes:
|
||||
meshtastic_data:
|
||||
|
||||
94
meshtasticd.spec.rpkg
Normal file
94
meshtasticd.spec.rpkg
Normal file
@@ -0,0 +1,94 @@
|
||||
# meshtasticd spec file for RPM-based distributions
|
||||
#
|
||||
# Build locally with:
|
||||
# ```
|
||||
# sudo dnf install rpkg-util
|
||||
# rpkg local
|
||||
# ```
|
||||
#
|
||||
# See:
|
||||
# - https://docs.pagure.org/rpkg-util/v3/index.html
|
||||
# - https://docs.fedoraproject.org/en-US/packaging-guidelines/Versioning/
|
||||
|
||||
Name: meshtasticd
|
||||
# Version Ex: 2.5.19
|
||||
Version: {{{ meshtastic_version }}}
|
||||
# Release Ex: 9127.daily.gitd7f5f620.fc41
|
||||
Release: {{{ git_commits_num }}}%{?copr_projectname:.%{copr_projectname}}.git{{{ git_commit_sha }}}%{?dist}
|
||||
VCS: {{{ git_dir_vcs }}}
|
||||
Summary: Meshtastic daemon for communicating with Meshtastic devices
|
||||
|
||||
License: GPL-3.0
|
||||
URL: https://github.com/meshtastic/firmware
|
||||
Source0: {{{ git_dir_pack }}}
|
||||
Source1: https://github.com/meshtastic/web/releases/latest/download/build.tar
|
||||
|
||||
BuildRequires: systemd-rpm-macros
|
||||
BuildRequires: python3-devel
|
||||
BuildRequires: platformio
|
||||
BuildRequires: python3dist(protobuf)
|
||||
BuildRequires: python3dist(grpcio[protobuf])
|
||||
BuildRequires: python3dist(grpcio-tools)
|
||||
BuildRequires: git-core
|
||||
BuildRequires: gcc-c++
|
||||
BuildRequires: pkgconfig(yaml-cpp)
|
||||
BuildRequires: pkgconfig(libgpiod)
|
||||
BuildRequires: pkgconfig(bluez)
|
||||
BuildRequires: pkgconfig(libusb-1.0)
|
||||
BuildRequires: libi2c-devel
|
||||
# Web components:
|
||||
BuildRequires: pkgconfig(openssl)
|
||||
BuildRequires: pkgconfig(liborcania)
|
||||
BuildRequires: pkgconfig(libyder)
|
||||
BuildRequires: pkgconfig(libulfius)
|
||||
|
||||
%description
|
||||
Meshtastic daemon for controlling Meshtastic devices. Meshtastic is an off-grid
|
||||
text communication platform that uses inexpensive LoRa radios.
|
||||
|
||||
%prep
|
||||
{{{ git_dir_setup_macro }}}
|
||||
# Unpack the web files
|
||||
mkdir -p web
|
||||
tar -xf %{SOURCE1} -C web
|
||||
gzip -dr web
|
||||
|
||||
%build
|
||||
# Use the “native” environment from platformio to build a Linux binary
|
||||
platformio run -e native
|
||||
|
||||
%install
|
||||
mkdir -p %{buildroot}%{_sbindir}
|
||||
install -m 0755 .pio/build/native/program %{buildroot}%{_sbindir}/meshtasticd
|
||||
|
||||
mkdir -p %{buildroot}%{_sysconfdir}/meshtasticd
|
||||
install -m 0644 bin/config-dist.yaml %{buildroot}%{_sysconfdir}/meshtasticd/config.yaml
|
||||
mkdir -p %{buildroot}%{_sysconfdir}/meshtasticd/config.d
|
||||
mkdir -p %{buildroot}%{_sysconfdir}/meshtasticd/available.d
|
||||
cp -r bin/config.d/* %{buildroot}%{_sysconfdir}/meshtasticd/available.d
|
||||
|
||||
install -D -m 0644 bin/meshtasticd.service %{buildroot}%{_unitdir}/meshtasticd.service
|
||||
|
||||
# Install the web files under /usr/share/meshtasticd/web
|
||||
mkdir -p %{buildroot}%{_datadir}/meshtasticd/web
|
||||
cp -r web/* %{buildroot}%{_datadir}/meshtasticd/web
|
||||
# Install default SSL storage directory (for web)
|
||||
mkdir -p %{buildroot}%{_sysconfdir}/meshtasticd/ssl
|
||||
|
||||
%files
|
||||
%license LICENSE
|
||||
%doc README.md
|
||||
%{_sbindir}/meshtasticd
|
||||
%dir %{_sysconfdir}/meshtasticd
|
||||
%dir %{_sysconfdir}/meshtasticd/config.d
|
||||
%dir %{_sysconfdir}/meshtasticd/available.d
|
||||
%config(noreplace) %{_sysconfdir}/meshtasticd/config.yaml
|
||||
%config %{_sysconfdir}/meshtasticd/available.d/*
|
||||
%{_unitdir}/meshtasticd.service
|
||||
%dir %{_datadir}/meshtasticd
|
||||
%dir %{_datadir}/meshtasticd/web
|
||||
%{_datadir}/meshtasticd/web/*
|
||||
%dir %{_sysconfdir}/meshtasticd/ssl
|
||||
|
||||
%changelog
|
||||
%autochangelog
|
||||
@@ -3,42 +3,7 @@
|
||||
|
||||
[platformio]
|
||||
default_envs = tbeam
|
||||
;default_envs = pico
|
||||
;default_envs = tbeam-s3-core
|
||||
;default_envs = tbeam0.7
|
||||
;default_envs = heltec-v1
|
||||
;default_envs = heltec-v2_0
|
||||
;default_envs = heltec-v2_1
|
||||
;default_envs = heltec-wireless-tracker
|
||||
;default_envs = chatter2
|
||||
;default_envs = tlora-v1
|
||||
;default_envs = tlora_v1_3
|
||||
;default_envs = tlora-v2
|
||||
;default_envs = tlora-v2-1-1_6
|
||||
;default_envs = tlora-v2-1-1_6-tcxo
|
||||
;default_envs = tlora-v3-3-0-tcxo
|
||||
;default_envs = tlora-t3s3-v1
|
||||
;default_envs = t-echo
|
||||
;default_envs = canaryone
|
||||
;default_envs = native
|
||||
;default_envs = nano-g1
|
||||
;default_envs = pca10059_diy_eink
|
||||
;default_envs = meshtastic-diy-v1
|
||||
;default_envs = meshtastic-diy-v1_1
|
||||
;default_envs = meshtastic-dr-dev
|
||||
;default_envs = m5stack-coreink
|
||||
;default_envs = rak4631
|
||||
;default_envs = rak4631_eth_gw
|
||||
;default_envs = rak2560
|
||||
;default_envs = rak_wismeshtap
|
||||
;default_envs = wio-e5
|
||||
;default_envs = radiomaster_900_bandit_nano
|
||||
;default_envs = radiomaster_900_bandit_micro
|
||||
;default_envs = radiomaster_900_bandit
|
||||
;default_envs = heltec_vision_master_t190
|
||||
;default_envs = heltec_vision_master_e213
|
||||
;default_envs = heltec_vision_master_e290
|
||||
;default_envs = heltec_mesh_node_t114
|
||||
|
||||
extra_configs =
|
||||
arch/*/*.ini
|
||||
variants/*/platformio.ini
|
||||
@@ -55,7 +20,7 @@ extra_scripts = bin/platformio-custom.py
|
||||
build_flags = -Wno-missing-field-initializers
|
||||
|
||||
-Wno-format
|
||||
-Isrc -Isrc/mesh -Isrc/mesh/generated -Isrc/gps -Isrc/buzz -Wl,-Map,.pio/build/output.map
|
||||
-Isrc -Isrc/mesh -Isrc/mesh/generated -Isrc/gps -Isrc/buzz -Wl,-Map,"${platformio.build_dir}"/output.map
|
||||
-DUSE_THREAD_NAMES
|
||||
-DTINYGPS_OPTION_NO_CUSTOM_FIELDS
|
||||
-DPB_ENABLE_MALLOC=1
|
||||
@@ -81,9 +46,10 @@ build_flags = -Wno-missing-field-initializers
|
||||
-DRADIOLIB_EXCLUDE_LORAWAN=1
|
||||
-DMESHTASTIC_EXCLUDE_DROPZONE=1
|
||||
-DMESHTASTIC_EXCLUDE_REMOTEHARDWARE=1
|
||||
-DMESHTASTIC_EXCLUDE_POWERSTRESS=1 ; exclude power stress test module from main firmware
|
||||
-DMESHTASTIC_EXCLUDE_HEALTH_TELEMETRY=1
|
||||
-DMESHTASTIC_EXCLUDE_POWERSTRESS=1 ; exclude power stress test module from main firmware
|
||||
#-DBUILD_EPOCH=$UNIX_TIME
|
||||
;-D OLED_PL
|
||||
#-D OLED_PL=1
|
||||
|
||||
monitor_speed = 115200
|
||||
monitor_filters = direct
|
||||
@@ -122,7 +88,7 @@ lib_deps =
|
||||
|
||||
[radiolib_base]
|
||||
lib_deps =
|
||||
jgromes/RadioLib@7.1.0
|
||||
jgromes/RadioLib@7.1.2
|
||||
|
||||
; Common libs for environmental measurements in telemetry module
|
||||
; (not included in native / portduino)
|
||||
@@ -153,7 +119,6 @@ lib_deps =
|
||||
sparkfun/SparkFun 9DoF IMU Breakout - ICM 20948 - Arduino Library@1.2.13
|
||||
ClosedCube OPT3001@1.1.2
|
||||
emotibit/EmotiBit MLX90632@1.0.8
|
||||
sparkfun/SparkFun MAX3010x Pulse and Proximity Sensor Library@1.1.2
|
||||
adafruit/Adafruit MLX90614 Library@2.1.5
|
||||
https://github.com/boschsensortec/Bosch-BSEC2-Library#v1.7.2502
|
||||
boschsensortec/BME68x Sensor Library@1.1.40407
|
||||
@@ -161,4 +126,8 @@ lib_deps =
|
||||
mprograms/QMC5883LCompass@1.2.3
|
||||
dfrobot/DFRobot_RTU@1.0.3
|
||||
https://github.com/meshtastic/DFRobot_LarkWeatherStation#4de3a9cadef0f6a5220a8a906cf9775b02b0040d
|
||||
robtillaart/INA226@0.6.0
|
||||
https://github.com/DFRobot/DFRobot_RainfallSensor#38fea5e02b40a5430be6dab39a99a6f6347d667e
|
||||
robtillaart/INA226@0.6.0
|
||||
|
||||
; Health Sensor Libraries
|
||||
sparkfun/SparkFun MAX3010x Pulse and Proximity Sensor Library@1.1.2
|
||||
|
||||
Submodule protobufs updated: 2cffaf53e3...068646653e
2
rpkg.conf
Normal file
2
rpkg.conf
Normal file
@@ -0,0 +1,2 @@
|
||||
[rpkg]
|
||||
user_macros = "${git_props:root}/bin/rpkg.macros"
|
||||
@@ -153,7 +153,7 @@ class AmbientLightingThread : public concurrency::OSThread
|
||||
pixels.fill(BUTTON1_COLOR, BUTTON1_COLOR_INDEX, 1);
|
||||
#endif
|
||||
#if defined(BUTTON2_COLOR) && defined(BUTTON2_COLOR_INDEX)
|
||||
pixels.fill(BUTTON2_COLOR, BUTTON1_COLOR_INDEX, 1);
|
||||
pixels.fill(BUTTON2_COLOR, BUTTON2_COLOR_INDEX, 1);
|
||||
#endif
|
||||
#endif
|
||||
pixels.show();
|
||||
|
||||
@@ -190,6 +190,20 @@ int32_t ButtonThread::runOnce()
|
||||
case 4:
|
||||
digitalWrite(PIN_EINK_EN, digitalRead(PIN_EINK_EN) == LOW);
|
||||
break;
|
||||
#endif
|
||||
#if defined(RAK_4631)
|
||||
// 5 clicks: start accelerometer/magenetometer calibration for 30 seconds
|
||||
case 5:
|
||||
if (accelerometerThread) {
|
||||
accelerometerThread->calibrate(30);
|
||||
}
|
||||
break;
|
||||
// 6 clicks: start accelerometer/magenetometer calibration for 60 seconds
|
||||
case 6:
|
||||
if (accelerometerThread) {
|
||||
accelerometerThread->calibrate(60);
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
// No valid multipress action
|
||||
default:
|
||||
|
||||
@@ -45,7 +45,7 @@
|
||||
#define LOG_CRIT(...) SEGGER_RTT_printf(0, __VA_ARGS__)
|
||||
#define LOG_TRACE(...) SEGGER_RTT_printf(0, __VA_ARGS__)
|
||||
#else
|
||||
#if defined(DEBUG_PORT) && !defined(DEBUG_MUTE) && !defined(PIO_UNIT_TESTING)
|
||||
#if defined(DEBUG_PORT) && !defined(DEBUG_MUTE)
|
||||
#define LOG_DEBUG(...) DEBUG_PORT.log(MESHTASTIC_LOG_LEVEL_DEBUG, __VA_ARGS__)
|
||||
#define LOG_INFO(...) DEBUG_PORT.log(MESHTASTIC_LOG_LEVEL_INFO, __VA_ARGS__)
|
||||
#define LOG_WARN(...) DEBUG_PORT.log(MESHTASTIC_LOG_LEVEL_WARN, __VA_ARGS__)
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
*
|
||||
*/
|
||||
#include "FSCommon.h"
|
||||
#include "SPILock.h"
|
||||
#include "configuration.h"
|
||||
|
||||
#ifdef HAS_SDCARD
|
||||
@@ -48,15 +49,6 @@ void OSFS::writeNBytes(uint16_t address, unsigned int num, const byte *input)
|
||||
}
|
||||
#endif
|
||||
|
||||
bool lfs_assert_failed =
|
||||
false; // Note: we use this global on all platforms, though it can only be set true on nrf52 (in our modified lfs_util.h)
|
||||
|
||||
extern "C" void lfs_assert(const char *reason)
|
||||
{
|
||||
LOG_ERROR("LFS assert: %s", reason);
|
||||
lfs_assert_failed = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Copies a file from one location to another.
|
||||
*
|
||||
@@ -93,6 +85,8 @@ bool copyFile(const char *from, const char *to)
|
||||
return true;
|
||||
|
||||
#elif defined(FSCom)
|
||||
// take SPI Lock
|
||||
concurrency::LockGuard g(spiLock);
|
||||
unsigned char cbuffer[16];
|
||||
|
||||
File f1 = FSCom.open(from, FILE_O_READ);
|
||||
@@ -136,16 +130,23 @@ bool renameFile(const char *pathFrom, const char *pathTo)
|
||||
return false;
|
||||
}
|
||||
#elif defined(FSCom)
|
||||
|
||||
#ifdef ARCH_ESP32
|
||||
// take SPI Lock
|
||||
spiLock->lock();
|
||||
// rename was fixed for ESP32 IDF LittleFS in April
|
||||
return FSCom.rename(pathFrom, pathTo);
|
||||
bool result = FSCom.rename(pathFrom, pathTo);
|
||||
spiLock->unlock();
|
||||
return result;
|
||||
#else
|
||||
// copyFile does its own locking.
|
||||
if (copyFile(pathFrom, pathTo) && FSCom.remove(pathFrom)) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -155,6 +156,7 @@ bool renameFile(const char *pathFrom, const char *pathTo)
|
||||
* @brief Get the list of files in a directory.
|
||||
*
|
||||
* This function returns a list of files in a directory. The list includes the full path of each file.
|
||||
* We can't use SPILOCK here because of recursion. Callers of this function should use SPILOCK.
|
||||
*
|
||||
* @param dirname The name of the directory.
|
||||
* @param levels The number of levels of subdirectories to list.
|
||||
@@ -183,7 +185,7 @@ std::vector<meshtastic_FileInfo> getFiles(const char *dirname, uint8_t levels)
|
||||
file.close();
|
||||
}
|
||||
} else {
|
||||
meshtastic_FileInfo fileInfo = {"", file.size()};
|
||||
meshtastic_FileInfo fileInfo = {"", static_cast<uint32_t>(file.size())};
|
||||
#ifdef ARCH_ESP32
|
||||
strcpy(fileInfo.file_name, file.path());
|
||||
#else
|
||||
@@ -203,6 +205,7 @@ std::vector<meshtastic_FileInfo> getFiles(const char *dirname, uint8_t levels)
|
||||
|
||||
/**
|
||||
* Lists the contents of a directory.
|
||||
* We can't use SPILOCK here because of recursion. Callers of this function should use SPILOCK.
|
||||
*
|
||||
* @param dirname The name of the directory to list.
|
||||
* @param levels The number of levels of subdirectories to list.
|
||||
@@ -316,18 +319,27 @@ void listDir(const char *dirname, uint8_t levels, bool del)
|
||||
void rmDir(const char *dirname)
|
||||
{
|
||||
#ifdef FSCom
|
||||
|
||||
#if (defined(ARCH_ESP32) || defined(ARCH_RP2040) || defined(ARCH_PORTDUINO))
|
||||
listDir(dirname, 10, true);
|
||||
#elif defined(ARCH_NRF52)
|
||||
// nRF52 implementation of LittleFS has a recursive delete function
|
||||
FSCom.rmdir_r(dirname);
|
||||
#endif
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* Some platforms (nrf52) might need to do an extra step before FSBegin().
|
||||
*/
|
||||
__attribute__((weak, noinline)) void preFSBegin() {}
|
||||
|
||||
void fsInit()
|
||||
{
|
||||
#ifdef FSCom
|
||||
concurrency::LockGuard g(spiLock);
|
||||
preFSBegin();
|
||||
if (!FSBegin()) {
|
||||
LOG_ERROR("Filesystem mount failed");
|
||||
// assert(0); This auto-formats the partition, so no need to fail here.
|
||||
@@ -347,6 +359,7 @@ void fsInit()
|
||||
void setupSDCard()
|
||||
{
|
||||
#ifdef HAS_SDCARD
|
||||
concurrency::LockGuard g(spiLock);
|
||||
SDHandler.begin(SPI_SCK, SPI_MISO, SPI_MOSI);
|
||||
|
||||
if (!SD.begin(SDCARD_CS, SDHandler)) {
|
||||
|
||||
@@ -57,7 +57,4 @@ bool renameFile(const char *pathFrom, const char *pathTo);
|
||||
std::vector<meshtastic_FileInfo> getFiles(const char *dirname, uint8_t levels);
|
||||
void listDir(const char *dirname, uint8_t levels, bool del = false);
|
||||
void rmDir(const char *dirname);
|
||||
void setupSDCard();
|
||||
|
||||
extern bool lfs_assert_failed; // Note: we use this global on all platforms, though it can only be set true on nrf52 (in our
|
||||
// modified lfs_util.h)
|
||||
void setupSDCard();
|
||||
@@ -87,7 +87,7 @@ MAX17048Sensor max17048Sensor;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if HAS_RAKPROT && !defined(ARCH_PORTDUINO)
|
||||
#if HAS_TELEMETRY && !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR && HAS_RAKPROT && !defined(ARCH_PORTDUINO)
|
||||
RAK9154Sensor rak9154Sensor;
|
||||
#endif
|
||||
|
||||
@@ -243,7 +243,8 @@ class AnalogBatteryLevel : public HasBatteryLevel
|
||||
virtual uint16_t getBattVoltage() override
|
||||
{
|
||||
|
||||
#if defined(HAS_RAKPROT) && !defined(ARCH_PORTDUINO) && !defined(HAS_PMU)
|
||||
#if HAS_TELEMETRY && defined(HAS_RAKPROT) && !defined(ARCH_PORTDUINO) && !defined(HAS_PMU) && \
|
||||
!MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR
|
||||
if (hasRAK()) {
|
||||
return getRAKVoltage();
|
||||
}
|
||||
@@ -406,7 +407,8 @@ class AnalogBatteryLevel : public HasBatteryLevel
|
||||
/// we can't be smart enough to say 'full'?
|
||||
virtual bool isCharging() override
|
||||
{
|
||||
#if defined(HAS_RAKPROT) && !defined(ARCH_PORTDUINO) && !defined(HAS_PMU)
|
||||
#if HAS_TELEMETRY && !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR && defined(HAS_RAKPROT) && !defined(ARCH_PORTDUINO) && \
|
||||
!defined(HAS_PMU)
|
||||
if (hasRAK()) {
|
||||
return (rak9154Sensor.isCharging()) ? OptTrue : OptFalse;
|
||||
}
|
||||
@@ -447,7 +449,7 @@ class AnalogBatteryLevel : public HasBatteryLevel
|
||||
float last_read_value = (OCV[NUM_OCV_POINTS - 1] * NUM_CELLS);
|
||||
uint32_t last_read_time_ms = 0;
|
||||
|
||||
#if defined(HAS_RAKPROT)
|
||||
#if HAS_TELEMETRY && !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR && defined(HAS_RAKPROT)
|
||||
|
||||
uint16_t getRAKVoltage() { return rak9154Sensor.getBusVoltageMv(); }
|
||||
|
||||
|
||||
@@ -79,17 +79,17 @@ size_t RedirectablePrint::vprintf(const char *logLevel, const char *format, va_l
|
||||
}
|
||||
if (color && logLevel != nullptr) {
|
||||
if (strcmp(logLevel, MESHTASTIC_LOG_LEVEL_DEBUG) == 0)
|
||||
Print::write("\u001b[34m", 6);
|
||||
Print::write("\u001b[34m", 5);
|
||||
if (strcmp(logLevel, MESHTASTIC_LOG_LEVEL_INFO) == 0)
|
||||
Print::write("\u001b[32m", 6);
|
||||
Print::write("\u001b[32m", 5);
|
||||
if (strcmp(logLevel, MESHTASTIC_LOG_LEVEL_WARN) == 0)
|
||||
Print::write("\u001b[33m", 6);
|
||||
Print::write("\u001b[33m", 5);
|
||||
if (strcmp(logLevel, MESHTASTIC_LOG_LEVEL_ERROR) == 0)
|
||||
Print::write("\u001b[31m", 6);
|
||||
Print::write("\u001b[31m", 5);
|
||||
}
|
||||
len = Print::write(printBuf, len);
|
||||
if (color && logLevel != nullptr) {
|
||||
Print::write("\u001b[0m", 5);
|
||||
Print::write("\u001b[0m", 4);
|
||||
}
|
||||
return len;
|
||||
}
|
||||
@@ -107,15 +107,15 @@ void RedirectablePrint::log_to_serial(const char *logLevel, const char *format,
|
||||
// include the header
|
||||
if (color) {
|
||||
if (strcmp(logLevel, MESHTASTIC_LOG_LEVEL_DEBUG) == 0)
|
||||
Print::write("\u001b[34m", 6);
|
||||
Print::write("\u001b[34m", 5);
|
||||
if (strcmp(logLevel, MESHTASTIC_LOG_LEVEL_INFO) == 0)
|
||||
Print::write("\u001b[32m", 6);
|
||||
Print::write("\u001b[32m", 5);
|
||||
if (strcmp(logLevel, MESHTASTIC_LOG_LEVEL_WARN) == 0)
|
||||
Print::write("\u001b[33m", 6);
|
||||
Print::write("\u001b[33m", 5);
|
||||
if (strcmp(logLevel, MESHTASTIC_LOG_LEVEL_ERROR) == 0)
|
||||
Print::write("\u001b[31m", 6);
|
||||
Print::write("\u001b[31m", 5);
|
||||
if (strcmp(logLevel, MESHTASTIC_LOG_LEVEL_TRACE) == 0)
|
||||
Print::write("\u001b[35m", 6);
|
||||
Print::write("\u001b[35m", 5);
|
||||
}
|
||||
|
||||
uint32_t rtc_sec = getValidTime(RTCQuality::RTCQualityDevice, true); // display local time on logfile
|
||||
@@ -393,4 +393,4 @@ std::string RedirectablePrint::mt_sprintf(const std::string fmt_str, ...)
|
||||
break;
|
||||
}
|
||||
return std::string(formatted.get());
|
||||
}
|
||||
}
|
||||
@@ -5,6 +5,12 @@
|
||||
// Only way to work on both esp32 and nrf52
|
||||
static File openFile(const char *filename, bool fullAtomic)
|
||||
{
|
||||
concurrency::LockGuard g(spiLock);
|
||||
LOG_DEBUG("Opening %s, fullAtomic=%d", filename, fullAtomic);
|
||||
#ifdef ARCH_NRF52
|
||||
FSCom.remove(filename);
|
||||
return FSCom.open(filename, FILE_O_WRITE);
|
||||
#endif
|
||||
if (!fullAtomic)
|
||||
FSCom.remove(filename); // Nuke the old file to make space (ignore if it !exists)
|
||||
|
||||
@@ -12,8 +18,6 @@ static File openFile(const char *filename, bool fullAtomic)
|
||||
filenameTmp += ".tmp";
|
||||
|
||||
// clear any previous LFS errors
|
||||
lfs_assert_failed = false;
|
||||
|
||||
return FSCom.open(filenameTmp.c_str(), FILE_O_WRITE);
|
||||
}
|
||||
|
||||
@@ -53,14 +57,23 @@ bool SafeFile::close()
|
||||
if (!f)
|
||||
return false;
|
||||
|
||||
spiLock->lock();
|
||||
f.close();
|
||||
spiLock->unlock();
|
||||
|
||||
#ifdef ARCH_NRF52
|
||||
return true;
|
||||
#endif
|
||||
if (!testReadback())
|
||||
return false;
|
||||
|
||||
// brief window of risk here ;-)
|
||||
if (fullAtomic && FSCom.exists(filename.c_str()) && !FSCom.remove(filename.c_str())) {
|
||||
LOG_ERROR("Can't remove old pref file");
|
||||
return false;
|
||||
{ // Scope for lock
|
||||
concurrency::LockGuard g(spiLock);
|
||||
// brief window of risk here ;-)
|
||||
if (fullAtomic && FSCom.exists(filename.c_str()) && !FSCom.remove(filename.c_str())) {
|
||||
LOG_ERROR("Can't remove old pref file");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
String filenameTmp = filename;
|
||||
@@ -76,8 +89,7 @@ bool SafeFile::close()
|
||||
/// Read our (closed) tempfile back in and compare the hash
|
||||
bool SafeFile::testReadback()
|
||||
{
|
||||
bool lfs_failed = lfs_assert_failed;
|
||||
lfs_assert_failed = false;
|
||||
concurrency::LockGuard g(spiLock);
|
||||
|
||||
String filenameTmp = filename;
|
||||
filenameTmp += ".tmp";
|
||||
@@ -99,7 +111,7 @@ bool SafeFile::testReadback()
|
||||
return false;
|
||||
}
|
||||
|
||||
return !lfs_failed;
|
||||
return true;
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,6 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "FSCommon.h"
|
||||
#include "SPILock.h"
|
||||
#include "configuration.h"
|
||||
|
||||
#ifdef FSCom
|
||||
|
||||
@@ -145,6 +145,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#define OPT3001_ADDR_ALT 0x44
|
||||
#define MLX90632_ADDR 0x3A
|
||||
#define DFROBOT_LARK_ADDR 0x42
|
||||
#define DFROBOT_RAIN_ADDR 0x1d
|
||||
#define NAU7802_ADDR 0x2A
|
||||
#define MAX30102_ADDR 0x57
|
||||
#define MLX90614_ADDR_DEF 0x5A
|
||||
@@ -178,13 +179,6 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#define TCA9535_ADDR 0x20
|
||||
#define TCA9555_ADDR 0x26
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// GPS
|
||||
// -----------------------------------------------------------------------------
|
||||
#ifndef GPS_THREAD_INTERVAL
|
||||
#define GPS_THREAD_INTERVAL 200
|
||||
#endif
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Touchscreen
|
||||
// -----------------------------------------------------------------------------
|
||||
@@ -206,6 +200,10 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#define VEXT_ON_VALUE LOW
|
||||
#endif
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// GPS
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
#ifndef GPS_BAUDRATE
|
||||
#define GPS_BAUDRATE 9600
|
||||
#define GPS_BAUDRATE_FIXED 0
|
||||
@@ -213,6 +211,10 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#define GPS_BAUDRATE_FIXED 1
|
||||
#endif
|
||||
|
||||
#ifndef GPS_THREAD_INTERVAL
|
||||
#define GPS_THREAD_INTERVAL 200
|
||||
#endif
|
||||
|
||||
/* Step #2: follow with defines common to the architecture;
|
||||
also enable HAS_ option not specifically disabled by variant.h */
|
||||
#include "architecture.h"
|
||||
@@ -250,6 +252,9 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#ifndef HAS_SCREEN
|
||||
#define HAS_SCREEN 0
|
||||
#endif
|
||||
#ifndef HAS_TFT
|
||||
#define HAS_TFT 0
|
||||
#endif
|
||||
#ifndef HAS_WIRE
|
||||
#define HAS_WIRE 0
|
||||
#endif
|
||||
@@ -312,6 +317,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#define MESHTASTIC_EXCLUDE_AUDIO 1
|
||||
#define MESHTASTIC_EXCLUDE_DETECTIONSENSOR 1
|
||||
#define MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR 1
|
||||
#define MESHTASTIC_EXCLUDE_HEALTH_TELEMETRY 1
|
||||
#define MESHTASTIC_EXCLUDE_EXTERNALNOTIFICATION 1
|
||||
#define MESHTASTIC_EXCLUDE_PAXCOUNTER 1
|
||||
#define MESHTASTIC_EXCLUDE_POWER_TELEMETRY 1
|
||||
@@ -361,4 +367,4 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#endif
|
||||
|
||||
#include "DebugConfiguration.h"
|
||||
#include "RF95Configuration.h"
|
||||
#include "RF95Configuration.h"
|
||||
|
||||
@@ -66,6 +66,7 @@ class ScanI2C
|
||||
CGRADSENS,
|
||||
INA226,
|
||||
NXP_SE050,
|
||||
DFROBOT_RAIN,
|
||||
} DeviceType;
|
||||
|
||||
// typedef uint8_t DeviceAddress;
|
||||
|
||||
@@ -84,23 +84,33 @@ ScanI2C::DeviceType ScanI2CTwoWire::probeOLED(ScanI2C::DeviceAddress addr) const
|
||||
return o_probe;
|
||||
}
|
||||
uint16_t ScanI2CTwoWire::getRegisterValue(const ScanI2CTwoWire::RegisterLocation ®isterLocation,
|
||||
ScanI2CTwoWire::ResponseWidth responseWidth) const
|
||||
ScanI2CTwoWire::ResponseWidth responseWidth, bool zeropad = false) const
|
||||
{
|
||||
uint16_t value = 0x00;
|
||||
TwoWire *i2cBus = fetchI2CBus(registerLocation.i2cAddress);
|
||||
|
||||
i2cBus->beginTransmission(registerLocation.i2cAddress.address);
|
||||
i2cBus->write(registerLocation.registerAddress);
|
||||
if (zeropad) {
|
||||
// Lark Commands need the argument list length in 2 bytes.
|
||||
i2cBus->write((int)0);
|
||||
i2cBus->write((int)0);
|
||||
}
|
||||
i2cBus->endTransmission();
|
||||
delay(20);
|
||||
i2cBus->requestFrom(registerLocation.i2cAddress.address, responseWidth);
|
||||
if (i2cBus->available() == 2) {
|
||||
if (i2cBus->available() > 1) {
|
||||
// Read MSB, then LSB
|
||||
value = (uint16_t)i2cBus->read() << 8;
|
||||
value |= i2cBus->read();
|
||||
} else if (i2cBus->available()) {
|
||||
value = i2cBus->read();
|
||||
}
|
||||
// Drain excess bytes
|
||||
for (uint8_t i = 0; i < responseWidth - 1; i++) {
|
||||
if (i2cBus->available())
|
||||
i2cBus->read();
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
@@ -286,7 +296,7 @@ void ScanI2CTwoWire::scanPort(I2CPort port, uint8_t *address, uint8_t asize)
|
||||
RESPONSE_PAYLOAD 0x01
|
||||
RESPONSE_PAYLOAD+1 0x00
|
||||
*/
|
||||
registerValue = getRegisterValue(ScanI2CTwoWire::RegisterLocation(addr, 0x05), 2);
|
||||
registerValue = getRegisterValue(ScanI2CTwoWire::RegisterLocation(addr, 0x05), 6, true);
|
||||
LOG_DEBUG("Register MFG_UID 05: 0x%x", registerValue);
|
||||
if (registerValue == 0x5305) {
|
||||
logFoundDevice("DFRobot Lark", (uint8_t)addr.address);
|
||||
@@ -402,6 +412,7 @@ void ScanI2CTwoWire::scanPort(I2CPort port, uint8_t *address, uint8_t asize)
|
||||
SCAN_SIMPLE_CASE(MLX90632_ADDR, MLX90632, "MLX90632", (uint8_t)addr.address);
|
||||
SCAN_SIMPLE_CASE(NAU7802_ADDR, NAU7802, "NAU7802", (uint8_t)addr.address);
|
||||
SCAN_SIMPLE_CASE(MAX1704X_ADDR, MAX17048, "MAX17048", (uint8_t)addr.address);
|
||||
SCAN_SIMPLE_CASE(DFROBOT_RAIN_ADDR, DFROBOT_RAIN, "DFRobot Rain Gauge", (uint8_t)addr.address);
|
||||
#ifdef HAS_TPS65233
|
||||
SCAN_SIMPLE_CASE(TPS65233_ADDR, TPS65233, "TPS65233", (uint8_t)addr.address);
|
||||
#endif
|
||||
@@ -458,11 +469,11 @@ void ScanI2CTwoWire::scanPort(I2CPort port, uint8_t *address, uint8_t asize)
|
||||
i2cBus->endTransmission();
|
||||
len = i2cBus->readBytes(info, 5);
|
||||
if (len == 5 && memcmp(expectedInfo, info, len) == 0) {
|
||||
LOG_INFO("NXP SE050 crypto chip found\n");
|
||||
LOG_INFO("NXP SE050 crypto chip found");
|
||||
type = NXP_SE050;
|
||||
|
||||
} else {
|
||||
LOG_INFO("FT6336U touchscreen found\n");
|
||||
LOG_INFO("FT6336U touchscreen found");
|
||||
type = FT6336U;
|
||||
}
|
||||
break;
|
||||
@@ -510,4 +521,4 @@ void ScanI2CTwoWire::logFoundDevice(const char *device, uint8_t address)
|
||||
{
|
||||
LOG_INFO("%s found at address 0x%x", device, address);
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
@@ -53,7 +53,7 @@ class ScanI2CTwoWire : public ScanI2C
|
||||
|
||||
concurrency::Lock lock;
|
||||
|
||||
uint16_t getRegisterValue(const RegisterLocation &, ResponseWidth) const;
|
||||
uint16_t getRegisterValue(const RegisterLocation &, ResponseWidth, bool) const;
|
||||
|
||||
DeviceType probeOLED(ScanI2C::DeviceAddress) const;
|
||||
|
||||
|
||||
@@ -6,28 +6,28 @@
|
||||
|
||||
void d_writeCommand(uint8_t c)
|
||||
{
|
||||
SPI1.beginTransaction(SPISettings(4000000, MSBFIRST, SPI_MODE0));
|
||||
SPI.beginTransaction(SPISettings(4000000, MSBFIRST, SPI_MODE0));
|
||||
if (PIN_EINK_DC >= 0)
|
||||
digitalWrite(PIN_EINK_DC, LOW);
|
||||
if (PIN_EINK_CS >= 0)
|
||||
digitalWrite(PIN_EINK_CS, LOW);
|
||||
SPI1.transfer(c);
|
||||
SPI.transfer(c);
|
||||
if (PIN_EINK_CS >= 0)
|
||||
digitalWrite(PIN_EINK_CS, HIGH);
|
||||
if (PIN_EINK_DC >= 0)
|
||||
digitalWrite(PIN_EINK_DC, HIGH);
|
||||
SPI1.endTransaction();
|
||||
SPI.endTransaction();
|
||||
}
|
||||
|
||||
void d_writeData(uint8_t d)
|
||||
{
|
||||
SPI1.beginTransaction(SPISettings(4000000, MSBFIRST, SPI_MODE0));
|
||||
SPI.beginTransaction(SPISettings(4000000, MSBFIRST, SPI_MODE0));
|
||||
if (PIN_EINK_CS >= 0)
|
||||
digitalWrite(PIN_EINK_CS, LOW);
|
||||
SPI1.transfer(d);
|
||||
SPI.transfer(d);
|
||||
if (PIN_EINK_CS >= 0)
|
||||
digitalWrite(PIN_EINK_CS, HIGH);
|
||||
SPI1.endTransaction();
|
||||
SPI.endTransaction();
|
||||
}
|
||||
|
||||
unsigned long d_waitWhileBusy(uint16_t busy_time)
|
||||
@@ -53,7 +53,7 @@ unsigned long d_waitWhileBusy(uint16_t busy_time)
|
||||
|
||||
void scanEInkDevice(void)
|
||||
{
|
||||
SPI1.begin();
|
||||
SPI.begin();
|
||||
d_writeCommand(0x22);
|
||||
d_writeData(0x83);
|
||||
d_writeCommand(0x20);
|
||||
@@ -62,6 +62,6 @@ void scanEInkDevice(void)
|
||||
LOG_DEBUG("EInk display found");
|
||||
else
|
||||
LOG_DEBUG("EInk display not found");
|
||||
SPI1.end();
|
||||
SPI.end();
|
||||
}
|
||||
#endif
|
||||
@@ -35,7 +35,11 @@ template <typename T, std::size_t N> std::size_t array_count(const T (&)[N])
|
||||
}
|
||||
|
||||
#if defined(NRF52840_XXAA) || defined(NRF52833_XXAA) || defined(ARCH_ESP32) || defined(ARCH_PORTDUINO)
|
||||
#if defined(RAK2560)
|
||||
HardwareSerial *GPS::_serial_gps = &Serial2;
|
||||
#else
|
||||
HardwareSerial *GPS::_serial_gps = &Serial1;
|
||||
#endif
|
||||
#elif defined(ARCH_RP2040)
|
||||
SerialUART *GPS::_serial_gps = &Serial1;
|
||||
#else
|
||||
@@ -445,7 +449,22 @@ bool GPS::setup()
|
||||
if (!didSerialInit) {
|
||||
int msglen = 0;
|
||||
if (tx_gpio && gnssModel == GNSS_MODEL_UNKNOWN) {
|
||||
#ifdef TRACKER_T1000_E
|
||||
// add power up/down strategy, improve ag3335 detection success
|
||||
digitalWrite(PIN_GPS_EN, LOW);
|
||||
delay(500);
|
||||
digitalWrite(GPS_VRTC_EN, LOW);
|
||||
delay(1000);
|
||||
digitalWrite(GPS_VRTC_EN, HIGH);
|
||||
delay(500);
|
||||
digitalWrite(PIN_GPS_EN, HIGH);
|
||||
delay(1000);
|
||||
#endif
|
||||
#ifdef TRACKER_T1000_E
|
||||
if (probeTries < 5) {
|
||||
#else
|
||||
if (probeTries < 2) {
|
||||
#endif
|
||||
LOG_DEBUG("Probe for GPS at %d", serialSpeeds[speedSelect]);
|
||||
gnssModel = probe(serialSpeeds[speedSelect]);
|
||||
if (gnssModel == GNSS_MODEL_UNKNOWN) {
|
||||
@@ -456,7 +475,11 @@ bool GPS::setup()
|
||||
}
|
||||
}
|
||||
// Rare Serial Speeds
|
||||
#ifdef TRACKER_T1000_E
|
||||
if (probeTries == 5) {
|
||||
#else
|
||||
if (probeTries == 2) {
|
||||
#endif
|
||||
LOG_DEBUG("Probe for GPS at %d", rareSerialSpeeds[speedSelect]);
|
||||
gnssModel = probe(rareSerialSpeeds[speedSelect]);
|
||||
if (gnssModel == GNSS_MODEL_UNKNOWN) {
|
||||
@@ -768,6 +791,9 @@ void GPS::setPowerState(GPSPowerState newState, uint32_t sleepTime)
|
||||
setPowerPMU(true); // Power (PMU): on
|
||||
writePinStandby(false); // Standby (pin): awake (not standby)
|
||||
setPowerUBLOX(true); // Standby (UBLOX): awake
|
||||
#ifdef GNSS_AIROHA
|
||||
lastFixStartMsec = 0;
|
||||
#endif
|
||||
break;
|
||||
|
||||
case GPS_SOFTSLEEP:
|
||||
@@ -1190,6 +1216,8 @@ GnssModel_t GPS::probe(int serialSpeed)
|
||||
PROBE_SIMPLE("L76B", "$PMTK605*31", "Quectel-L76B", GNSS_MODEL_MTK_L76B, 500);
|
||||
PROBE_SIMPLE("PA1616S", "$PMTK605*31", "1616S", GNSS_MODEL_MTK_PA1616S, 500);
|
||||
|
||||
PROBE_SIMPLE("LS20031", "$PMTK605*31", "MC-1513", GNSS_MODEL_LS20031, 500);
|
||||
|
||||
uint8_t cfg_rate[] = {0xB5, 0x62, 0x06, 0x08, 0x00, 0x00, 0x00, 0x00};
|
||||
UBXChecksum(cfg_rate, sizeof(cfg_rate));
|
||||
clearBuffer();
|
||||
@@ -1750,4 +1778,4 @@ void GPS::toggleGpsMode()
|
||||
enable();
|
||||
}
|
||||
}
|
||||
#endif // Exclude GPS
|
||||
#endif // Exclude GPS
|
||||
|
||||
@@ -29,7 +29,8 @@ typedef enum {
|
||||
GNSS_MODEL_MTK_L76B,
|
||||
GNSS_MODEL_MTK_PA1616S,
|
||||
GNSS_MODEL_AG3335,
|
||||
GNSS_MODEL_AG3352
|
||||
GNSS_MODEL_AG3352,
|
||||
GNSS_MODEL_LS20031
|
||||
} GnssModel_t;
|
||||
|
||||
typedef enum {
|
||||
@@ -239,4 +240,4 @@ class GPS : private concurrency::OSThread
|
||||
};
|
||||
|
||||
extern GPS *gps;
|
||||
#endif // Exclude GPS
|
||||
#endif // Exclude GPS
|
||||
|
||||
@@ -140,6 +140,15 @@ bool EInkDisplay::connect()
|
||||
adafruitDisplay->setRotation(3);
|
||||
adafruitDisplay->setPartialWindow(0, 0, displayWidth, displayHeight);
|
||||
}
|
||||
#elif defined(MESHLINK)
|
||||
{
|
||||
auto lowLevel = new EINK_DISPLAY_MODEL(PIN_EINK_CS, PIN_EINK_DC, PIN_EINK_RES, PIN_EINK_BUSY, SPI1);
|
||||
|
||||
adafruitDisplay = new GxEPD2_BW<EINK_DISPLAY_MODEL, EINK_DISPLAY_MODEL::HEIGHT>(*lowLevel);
|
||||
adafruitDisplay->init();
|
||||
adafruitDisplay->setRotation(3);
|
||||
adafruitDisplay->setPartialWindow(0, 0, displayWidth, displayHeight);
|
||||
}
|
||||
#elif defined(RAK4630) || defined(MAKERPYTHON)
|
||||
{
|
||||
if (eink_found) {
|
||||
|
||||
@@ -238,7 +238,7 @@ void EInkDynamicDisplay::checkRateLimiting()
|
||||
|
||||
// Skip update: too soon for BACKGROUND
|
||||
if (frameFlags == BACKGROUND) {
|
||||
if (Throttle::isWithinTimespanMs(previousRunMs, EINK_LIMIT_RATE_BACKGROUND_SEC * 1000)) {
|
||||
if (Throttle::isWithinTimespanMs(previousRunMs, 30000)) {
|
||||
refresh = SKIPPED;
|
||||
reason = EXCEEDED_RATELIMIT_FULL;
|
||||
return;
|
||||
@@ -251,7 +251,7 @@ void EInkDynamicDisplay::checkRateLimiting()
|
||||
|
||||
// Skip update: too soon for RESPONSIVE
|
||||
if (frameFlags & RESPONSIVE) {
|
||||
if (Throttle::isWithinTimespanMs(previousRunMs, EINK_LIMIT_RATE_RESPONSIVE_SEC * 1000)) {
|
||||
if (Throttle::isWithinTimespanMs(previousRunMs, 1000)) {
|
||||
refresh = SKIPPED;
|
||||
reason = EXCEEDED_RATELIMIT_FAST;
|
||||
LOG_DEBUG("refresh=SKIPPED, reason=EXCEEDED_RATELIMIT_FAST, frameFlags=0x%x", frameFlags);
|
||||
|
||||
@@ -123,10 +123,10 @@ static bool heartbeat = false;
|
||||
|
||||
#define getStringCenteredX(s) ((SCREEN_WIDTH - display->getStringWidth(s)) / 2)
|
||||
|
||||
/// Check if the display can render a string (detect special chars; emoji)
|
||||
// Check if the display can render a string (detect special chars; emoji)
|
||||
static bool haveGlyphs(const char *str)
|
||||
{
|
||||
#if defined(OLED_PL) || defined(OLED_UA) || defined(OLED_RU)
|
||||
#if defined(OLED_PL) || defined(OLED_UA) || defined(OLED_RU) || defined(OLED_CS)
|
||||
// Don't want to make any assumptions about custom language support
|
||||
return true;
|
||||
#endif
|
||||
@@ -162,11 +162,7 @@ static void drawIconScreen(const char *upperMsg, OLEDDisplay *display, OLEDDispl
|
||||
|
||||
display->setFont(FONT_MEDIUM);
|
||||
display->setTextAlignment(TEXT_ALIGN_LEFT);
|
||||
#ifdef USERPREFS_SPLASH_TITLE
|
||||
const char *title = USERPREFS_SPLASH_TITLE;
|
||||
#else
|
||||
const char *title = "meshtastic.org";
|
||||
#endif
|
||||
display->drawString(x + getStringCenteredX(title), y + SCREEN_HEIGHT - FONT_HEIGHT_MEDIUM, title);
|
||||
display->setFont(FONT_SMALL);
|
||||
|
||||
@@ -185,6 +181,56 @@ static void drawIconScreen(const char *upperMsg, OLEDDisplay *display, OLEDDispl
|
||||
display->setTextAlignment(TEXT_ALIGN_LEFT); // Restore left align, just to be kind to any other unsuspecting code
|
||||
}
|
||||
|
||||
#ifdef USERPREFS_OEM_TEXT
|
||||
|
||||
static void drawOEMIconScreen(const char *upperMsg, OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y)
|
||||
{
|
||||
static const uint8_t xbm[] = USERPREFS_OEM_IMAGE_DATA;
|
||||
display->drawXbm(x + (SCREEN_WIDTH - USERPREFS_OEM_IMAGE_WIDTH) / 2,
|
||||
y + (SCREEN_HEIGHT - FONT_HEIGHT_MEDIUM - USERPREFS_OEM_IMAGE_HEIGHT) / 2 + 2, USERPREFS_OEM_IMAGE_WIDTH,
|
||||
USERPREFS_OEM_IMAGE_HEIGHT, xbm);
|
||||
|
||||
switch (USERPREFS_OEM_FONT_SIZE) {
|
||||
case 0:
|
||||
display->setFont(FONT_SMALL);
|
||||
break;
|
||||
case 2:
|
||||
display->setFont(FONT_LARGE);
|
||||
break;
|
||||
default:
|
||||
display->setFont(FONT_MEDIUM);
|
||||
break;
|
||||
}
|
||||
|
||||
display->setTextAlignment(TEXT_ALIGN_LEFT);
|
||||
const char *title = USERPREFS_OEM_TEXT;
|
||||
display->drawString(x + getStringCenteredX(title), y + SCREEN_HEIGHT - FONT_HEIGHT_MEDIUM, title);
|
||||
display->setFont(FONT_SMALL);
|
||||
|
||||
// Draw region in upper left
|
||||
if (upperMsg)
|
||||
display->drawString(x + 0, y + 0, upperMsg);
|
||||
|
||||
// Draw version and shortname in upper right
|
||||
char buf[25];
|
||||
snprintf(buf, sizeof(buf), "%s\n%s", xstr(APP_VERSION_SHORT), haveGlyphs(owner.short_name) ? owner.short_name : "");
|
||||
|
||||
display->setTextAlignment(TEXT_ALIGN_RIGHT);
|
||||
display->drawString(x + SCREEN_WIDTH, y + 0, buf);
|
||||
screen->forceDisplay();
|
||||
|
||||
display->setTextAlignment(TEXT_ALIGN_LEFT); // Restore left align, just to be kind to any other unsuspecting code
|
||||
}
|
||||
|
||||
static void drawOEMBootScreen(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y)
|
||||
{
|
||||
// Draw region in upper left
|
||||
const char *region = myRegion ? myRegion->name : NULL;
|
||||
drawOEMIconScreen(region, display, state, x, y);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
void Screen::drawFrameText(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y, const char *message)
|
||||
{
|
||||
uint16_t x_offset = display->width() / 2;
|
||||
@@ -1015,7 +1061,7 @@ static void drawTextMessageFrame(OLEDDisplay *display, OLEDDisplayUiState *state
|
||||
y + (SCREEN_HEIGHT - FONT_HEIGHT_MEDIUM - devil_height) / 2 + 2 + 5, devil_width, devil_height, devil);
|
||||
} else if (strcmp(msg, "♥️") == 0 || strcmp(msg, "\U0001F9E1") == 0 || strcmp(msg, "\U00002763") == 0 ||
|
||||
strcmp(msg, "\U00002764") == 0 || strcmp(msg, "\U0001F495") == 0 || strcmp(msg, "\U0001F496") == 0 ||
|
||||
strcmp(msg, "\U0001F497") == 0 || strcmp(msg, "\U0001F496") == 0) {
|
||||
strcmp(msg, "\U0001F497") == 0 || strcmp(msg, "\U0001F498") == 0) {
|
||||
display->drawXbm(x + (SCREEN_WIDTH - heart_width) / 2,
|
||||
y + (SCREEN_HEIGHT - FONT_HEIGHT_MEDIUM - heart_height) / 2 + 2 + 5, heart_width, heart_height, heart);
|
||||
} else {
|
||||
@@ -1400,9 +1446,9 @@ static void drawNodeInfo(OLEDDisplay *display, OLEDDisplayUiState *state, int16_
|
||||
|
||||
static char distStr[20];
|
||||
if (config.display.units == meshtastic_Config_DisplayConfig_DisplayUnits_IMPERIAL) {
|
||||
strncpy(distStr, "? mi", sizeof(distStr)); // might not have location data
|
||||
strncpy(distStr, "? mi ?°", sizeof(distStr)); // might not have location data
|
||||
} else {
|
||||
strncpy(distStr, "? km", sizeof(distStr));
|
||||
strncpy(distStr, "? km ?°", sizeof(distStr));
|
||||
}
|
||||
meshtastic_NodeInfoLite *ourNode = nodeDB->getMeshNode(nodeDB->getNodeNum());
|
||||
const char *fields[] = {username, lastStr, signalStr, distStr, NULL};
|
||||
@@ -1435,18 +1481,6 @@ static void drawNodeInfo(OLEDDisplay *display, OLEDDisplayUiState *state, int16_
|
||||
float d =
|
||||
GeoCoord::latLongToMeter(DegD(p.latitude_i), DegD(p.longitude_i), DegD(op.latitude_i), DegD(op.longitude_i));
|
||||
|
||||
if (config.display.units == meshtastic_Config_DisplayConfig_DisplayUnits_IMPERIAL) {
|
||||
if (d < (2 * MILES_TO_FEET))
|
||||
snprintf(distStr, sizeof(distStr), "%.0f ft", d * METERS_TO_FEET);
|
||||
else
|
||||
snprintf(distStr, sizeof(distStr), "%.1f mi", d * METERS_TO_FEET / MILES_TO_FEET);
|
||||
} else {
|
||||
if (d < 2000)
|
||||
snprintf(distStr, sizeof(distStr), "%.0f m", d);
|
||||
else
|
||||
snprintf(distStr, sizeof(distStr), "%.1f km", d / 1000);
|
||||
}
|
||||
|
||||
float bearingToOther =
|
||||
GeoCoord::bearing(DegD(op.latitude_i), DegD(op.longitude_i), DegD(p.latitude_i), DegD(p.longitude_i));
|
||||
// If the top of the compass is a static north then bearingToOther can be drawn on the compass directly
|
||||
@@ -1454,6 +1488,22 @@ static void drawNodeInfo(OLEDDisplay *display, OLEDDisplayUiState *state, int16_
|
||||
if (!config.display.compass_north_top)
|
||||
bearingToOther -= myHeading;
|
||||
screen->drawNodeHeading(display, compassX, compassY, compassDiam, bearingToOther);
|
||||
|
||||
float bearingToOtherDegrees = (bearingToOther < 0) ? bearingToOther + 2 * PI : bearingToOther;
|
||||
bearingToOtherDegrees = bearingToOtherDegrees * 180 / PI;
|
||||
|
||||
if (config.display.units == meshtastic_Config_DisplayConfig_DisplayUnits_IMPERIAL) {
|
||||
if (d < (2 * MILES_TO_FEET))
|
||||
snprintf(distStr, sizeof(distStr), "%.0fft %.0f°", d * METERS_TO_FEET, bearingToOtherDegrees);
|
||||
else
|
||||
snprintf(distStr, sizeof(distStr), "%.1fmi %.0f°", d * METERS_TO_FEET / MILES_TO_FEET,
|
||||
bearingToOtherDegrees);
|
||||
} else {
|
||||
if (d < 2000)
|
||||
snprintf(distStr, sizeof(distStr), "%.0fm %.0f°", d, bearingToOtherDegrees);
|
||||
else
|
||||
snprintf(distStr, sizeof(distStr), "%.1fkm %.0f°", d / 1000, bearingToOtherDegrees);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!hasNodeHeading) {
|
||||
@@ -1506,7 +1556,7 @@ Screen::Screen(ScanI2C::DeviceAddress address, meshtastic_Config_DisplayConfig_O
|
||||
#elif defined(USE_ST7567)
|
||||
dispdev = new ST7567Wire(address.address, -1, -1, geometry,
|
||||
(address.port == ScanI2C::I2CPort::WIRE1) ? HW_I2C::I2C_TWO : HW_I2C::I2C_ONE);
|
||||
#elif ARCH_PORTDUINO
|
||||
#elif ARCH_PORTDUINO && !HAS_TFT
|
||||
if (settingsMap[displayPanel] != no_screen) {
|
||||
LOG_DEBUG("Make TFTDisplay!");
|
||||
dispdev = new TFTDisplay(address.address, -1, -1, geometry,
|
||||
@@ -1658,6 +1708,10 @@ void Screen::setup()
|
||||
// Set the utf8 conversion function
|
||||
dispdev->setFontTableLookupFunction(customFontTableLookup);
|
||||
|
||||
#ifdef USERPREFS_OEM_TEXT
|
||||
logo_timeout *= 2; // Double the time if we have a custom logo
|
||||
#endif
|
||||
|
||||
// Add frames.
|
||||
EINK_ADD_FRAMEFLAG(dispdev, DEMAND_FAST);
|
||||
alertFrames[0] = [this](OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y) -> void {
|
||||
@@ -1718,7 +1772,7 @@ void Screen::setup()
|
||||
#endif
|
||||
serialSinceMsec = millis();
|
||||
|
||||
#if ARCH_PORTDUINO
|
||||
#if ARCH_PORTDUINO && !HAS_TFT
|
||||
if (settingsMap[touchscreenModule]) {
|
||||
touchScreenImpl1 =
|
||||
new TouchScreenImpl1(dispdev->getWidth(), dispdev->getHeight(), static_cast<TFTDisplay *>(dispdev)->getTouch);
|
||||
@@ -1803,6 +1857,22 @@ int32_t Screen::runOnce()
|
||||
showingBootScreen = false;
|
||||
}
|
||||
|
||||
#ifdef USERPREFS_OEM_TEXT
|
||||
static bool showingOEMBootScreen = true;
|
||||
if (showingOEMBootScreen && (millis() > ((logo_timeout / 2) + serialSinceMsec))) {
|
||||
LOG_INFO("Switch to OEM screen...");
|
||||
// Change frames.
|
||||
static FrameCallback bootOEMFrames[] = {drawOEMBootScreen};
|
||||
static const int bootOEMFrameCount = sizeof(bootOEMFrames) / sizeof(bootOEMFrames[0]);
|
||||
ui->setFrames(bootOEMFrames, bootOEMFrameCount);
|
||||
ui->update();
|
||||
#ifndef USE_EINK
|
||||
ui->update();
|
||||
#endif
|
||||
showingOEMBootScreen = false;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef DISABLE_WELCOME_UNSET
|
||||
if (showingNormalScreen && config.lora.region == meshtastic_Config_LoRaConfig_RegionCode_UNSET) {
|
||||
setWelcomeFrames();
|
||||
@@ -2578,13 +2648,12 @@ void DebugInfo::drawFrameSettings(OLEDDisplay *display, OLEDDisplayUiState *stat
|
||||
display->drawString(x + 1, y, String("USB"));
|
||||
}
|
||||
|
||||
auto mode = DisplayFormatters::getModemPresetDisplayName(config.lora.modem_preset, true);
|
||||
// auto mode = DisplayFormatters::getModemPresetDisplayName(config.lora.modem_preset, true);
|
||||
|
||||
display->drawString(x + SCREEN_WIDTH - display->getStringWidth(mode), y, mode);
|
||||
if (config.display.heading_bold)
|
||||
display->drawString(x + SCREEN_WIDTH - display->getStringWidth(mode) - 1, y, mode);
|
||||
// display->drawString(x + SCREEN_WIDTH - display->getStringWidth(mode), y, mode);
|
||||
// if (config.display.heading_bold)
|
||||
// display->drawString(x + SCREEN_WIDTH - display->getStringWidth(mode) - 1, y, mode);
|
||||
|
||||
// Line 2
|
||||
uint32_t currentMillis = millis();
|
||||
uint32_t seconds = currentMillis / 1000;
|
||||
uint32_t minutes = seconds / 60;
|
||||
@@ -2597,6 +2666,9 @@ void DebugInfo::drawFrameSettings(OLEDDisplay *display, OLEDDisplayUiState *stat
|
||||
|
||||
display->setColor(WHITE);
|
||||
|
||||
// Setup string to assemble analogClock string
|
||||
std::string analogClock = "";
|
||||
|
||||
// Show uptime as days, hours, minutes OR seconds
|
||||
std::string uptime = screen->drawTimeDelta(days, hours, minutes, seconds);
|
||||
|
||||
@@ -2613,17 +2685,36 @@ void DebugInfo::drawFrameSettings(OLEDDisplay *display, OLEDDisplayUiState *stat
|
||||
int min = (hms % SEC_PER_HOUR) / SEC_PER_MIN;
|
||||
int sec = (hms % SEC_PER_HOUR) % SEC_PER_MIN; // or hms % SEC_PER_MIN
|
||||
|
||||
char timebuf[10];
|
||||
snprintf(timebuf, sizeof(timebuf), " %02d:%02d:%02d", hour, min, sec);
|
||||
uptime += timebuf;
|
||||
char timebuf[12];
|
||||
|
||||
if (config.display.use_12h_clock) {
|
||||
std::string meridiem = "am";
|
||||
if (hour >= 12) {
|
||||
if (hour > 12)
|
||||
hour -= 12;
|
||||
meridiem = "pm";
|
||||
}
|
||||
if (hour == 00) {
|
||||
hour = 12;
|
||||
}
|
||||
snprintf(timebuf, sizeof(timebuf), "%d:%02d:%02d%s", hour, min, sec, meridiem.c_str());
|
||||
} else {
|
||||
snprintf(timebuf, sizeof(timebuf), "%02d:%02d:%02d", hour, min, sec);
|
||||
}
|
||||
analogClock += timebuf;
|
||||
}
|
||||
|
||||
display->drawString(x, y + FONT_HEIGHT_SMALL * 1, uptime.c_str());
|
||||
// Line 1
|
||||
display->drawString(x + SCREEN_WIDTH - display->getStringWidth(uptime.c_str()), y, uptime.c_str());
|
||||
|
||||
// Line 2
|
||||
display->drawString(x, y + FONT_HEIGHT_SMALL * 1, analogClock.c_str());
|
||||
|
||||
// Display Channel Utilization
|
||||
char chUtil[13];
|
||||
snprintf(chUtil, sizeof(chUtil), "ChUtil %2.0f%%", airTime->channelUtilizationPercent());
|
||||
display->drawString(x + SCREEN_WIDTH - display->getStringWidth(chUtil), y + FONT_HEIGHT_SMALL * 1, chUtil);
|
||||
|
||||
#if HAS_GPS
|
||||
if (config.position.gps_mode == meshtastic_Config_PositionConfig_GpsMode_ENABLED) {
|
||||
// Line 3
|
||||
@@ -2756,4 +2847,4 @@ int Screen::handleAdminMessage(const meshtastic_AdminMessage *arg)
|
||||
} // namespace graphics
|
||||
#else
|
||||
graphics::Screen::Screen(ScanI2C::DeviceAddress, meshtastic_Config_DisplayConfig_OledType, OLEDDISPLAY_GEOMETRY) {}
|
||||
#endif // HAS_SCREEN
|
||||
#endif // HAS_SCREEN
|
||||
@@ -278,6 +278,10 @@ class Screen : public concurrency::OSThread
|
||||
bool hasHeading() { return hasCompass; }
|
||||
|
||||
long getHeading() { return compassHeading; }
|
||||
|
||||
void setEndCalibration(uint32_t _endCalibrationAt) { endCalibrationAt = _endCalibrationAt; }
|
||||
uint32_t getEndCalibration() { return endCalibrationAt; }
|
||||
|
||||
// functions for display brightness
|
||||
void increaseBrightness();
|
||||
void decreaseBrightness();
|
||||
@@ -427,6 +431,86 @@ class Screen : public concurrency::OSThread
|
||||
if (ch == 0xC2 || ch == 0xC3 || ch == 0x82 || ch == 0xD0 || ch == 0xD1)
|
||||
return (uint8_t)0;
|
||||
|
||||
#endif
|
||||
|
||||
#if defined(OLED_CS)
|
||||
|
||||
switch (last) {
|
||||
case 0xC2: {
|
||||
SKIPREST = false;
|
||||
return (uint8_t)ch;
|
||||
}
|
||||
|
||||
case 0xC3: {
|
||||
SKIPREST = false;
|
||||
return (uint8_t)(ch | 0xC0);
|
||||
}
|
||||
|
||||
case 0xC4: {
|
||||
SKIPREST = false;
|
||||
if (ch == 140)
|
||||
return (uint8_t)(129); // Č
|
||||
if (ch == 141)
|
||||
return (uint8_t)(138); // č
|
||||
if (ch == 142)
|
||||
return (uint8_t)(130); // Ď
|
||||
if (ch == 143)
|
||||
return (uint8_t)(139); // ď
|
||||
if (ch == 154)
|
||||
return (uint8_t)(131); // Ě
|
||||
if (ch == 155)
|
||||
return (uint8_t)(140); // ě
|
||||
// Slovak specific glyphs
|
||||
if (ch == 185)
|
||||
return (uint8_t)(147); // Ĺ
|
||||
if (ch == 186)
|
||||
return (uint8_t)(148); // ĺ
|
||||
if (ch == 189)
|
||||
return (uint8_t)(149); // Ľ
|
||||
if (ch == 190)
|
||||
return (uint8_t)(150); // ľ
|
||||
break;
|
||||
}
|
||||
|
||||
case 0xC5: {
|
||||
SKIPREST = false;
|
||||
if (ch == 135)
|
||||
return (uint8_t)(132); // Ň
|
||||
if (ch == 136)
|
||||
return (uint8_t)(141); // ň
|
||||
if (ch == 152)
|
||||
return (uint8_t)(133); // Ř
|
||||
if (ch == 153)
|
||||
return (uint8_t)(142); // ř
|
||||
if (ch == 160)
|
||||
return (uint8_t)(134); // Š
|
||||
if (ch == 161)
|
||||
return (uint8_t)(143); // š
|
||||
if (ch == 164)
|
||||
return (uint8_t)(135); // Ť
|
||||
if (ch == 165)
|
||||
return (uint8_t)(144); // ť
|
||||
if (ch == 174)
|
||||
return (uint8_t)(136); // Ů
|
||||
if (ch == 175)
|
||||
return (uint8_t)(145); // ů
|
||||
if (ch == 189)
|
||||
return (uint8_t)(137); // Ž
|
||||
if (ch == 190)
|
||||
return (uint8_t)(146); // ž
|
||||
// Slovak specific glyphs
|
||||
if (ch == 148)
|
||||
return (uint8_t)(151); // Ŕ
|
||||
if (ch == 149)
|
||||
return (uint8_t)(152); // ŕ
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// We want to strip out prefix chars for two-byte char formats
|
||||
if (ch == 0xC2 || ch == 0xC3 || ch == 0xC4 || ch == 0xC5)
|
||||
return (uint8_t)0;
|
||||
|
||||
#endif
|
||||
|
||||
// If we already returned an unconvertable-character symbol for this unconvertable-character sequence, return NULs for the
|
||||
@@ -593,6 +677,8 @@ class Screen : public concurrency::OSThread
|
||||
|
||||
bool hasCompass = false;
|
||||
float compassHeading;
|
||||
uint32_t endCalibrationAt;
|
||||
|
||||
/// Holds state for debug information
|
||||
DebugInfo debugInfo;
|
||||
|
||||
|
||||
@@ -12,37 +12,65 @@
|
||||
#include "graphics/fonts/OLEDDisplayFontsUA.h"
|
||||
#endif
|
||||
|
||||
#ifdef OLED_CS
|
||||
#include "graphics/fonts/OLEDDisplayFontsCS.h"
|
||||
#endif
|
||||
|
||||
#ifdef OLED_PL
|
||||
#define FONT_SMALL_LOCAL ArialMT_Plain_10_PL
|
||||
#else
|
||||
#ifdef OLED_RU
|
||||
#define FONT_SMALL_LOCAL ArialMT_Plain_10_RU
|
||||
#else
|
||||
#ifdef OLED_UA
|
||||
#define FONT_SMALL_LOCAL ArialMT_Plain_10_UA // Height: 13
|
||||
#else
|
||||
#ifdef OLED_CS
|
||||
#define FONT_SMALL_LOCAL ArialMT_Plain_10_CS
|
||||
#else
|
||||
#define FONT_SMALL_LOCAL ArialMT_Plain_10 // Height: 13
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
#ifdef OLED_PL
|
||||
#define FONT_MEDIUM_LOCAL ArialMT_Plain_16_PL // Height: 19
|
||||
#else
|
||||
#ifdef OLED_UA
|
||||
#define FONT_MEDIUM_LOCAL ArialMT_Plain_16_UA // Height: 19
|
||||
#else
|
||||
#ifdef OLED_CS
|
||||
#define FONT_MEDIUM_LOCAL ArialMT_Plain_16_CS
|
||||
#else
|
||||
#define FONT_MEDIUM_LOCAL ArialMT_Plain_16 // Height: 19
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
#ifdef OLED_PL
|
||||
#define FONT_LARGE_LOCAL ArialMT_Plain_24_PL // Height: 28
|
||||
#else
|
||||
#ifdef OLED_UA
|
||||
#define FONT_LARGE_LOCAL ArialMT_Plain_24_UA // Height: 28
|
||||
#else
|
||||
#ifdef OLED_CS
|
||||
#define FONT_LARGE_LOCAL ArialMT_Plain_24_CS // Height: 28
|
||||
#else
|
||||
#define FONT_LARGE_LOCAL ArialMT_Plain_24 // Height: 28
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if (defined(USE_EINK) || defined(ILI9341_DRIVER) || defined(ILI9342_DRIVER) || defined(ST7701_CS) || defined(ST7735_CS) || \
|
||||
defined(ST7789_CS) || defined(USE_ST7789) || defined(HX8357_CS)) && \
|
||||
!defined(DISPLAY_FORCE_SMALL_FONTS)
|
||||
// The screen is bigger so use bigger fonts
|
||||
#define FONT_SMALL ArialMT_Plain_16 // Height: 19
|
||||
#define FONT_MEDIUM ArialMT_Plain_24 // Height: 28
|
||||
#define FONT_LARGE ArialMT_Plain_24 // Height: 28
|
||||
#define FONT_SMALL FONT_MEDIUM_LOCAL // Height: 19
|
||||
#define FONT_MEDIUM FONT_LARGE_LOCAL // Height: 28
|
||||
#define FONT_LARGE FONT_LARGE_LOCAL // Height: 28
|
||||
#else
|
||||
#ifdef OLED_PL
|
||||
#define FONT_SMALL ArialMT_Plain_10_PL
|
||||
#else
|
||||
#ifdef OLED_RU
|
||||
#define FONT_SMALL ArialMT_Plain_10_RU
|
||||
#else
|
||||
#ifdef OLED_UA
|
||||
#define FONT_SMALL ArialMT_Plain_10_UA // Height: 13
|
||||
#else
|
||||
#define FONT_SMALL ArialMT_Plain_10 // Height: 13
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
#ifdef OLED_UA
|
||||
#define FONT_MEDIUM ArialMT_Plain_16_UA // Height: 19
|
||||
#else
|
||||
#define FONT_MEDIUM ArialMT_Plain_16 // Height: 19
|
||||
#endif
|
||||
#ifdef OLED_UA
|
||||
#define FONT_LARGE ArialMT_Plain_24_UA // Height: 28
|
||||
#else
|
||||
#define FONT_LARGE ArialMT_Plain_24 // Height: 28
|
||||
#endif
|
||||
#define FONT_SMALL FONT_SMALL_LOCAL // Height: 13
|
||||
#define FONT_MEDIUM FONT_MEDIUM_LOCAL // Height: 19
|
||||
#define FONT_LARGE FONT_LARGE_LOCAL // Height: 28
|
||||
#endif
|
||||
|
||||
#define _fontHeight(font) ((font)[1] + 1) // height is position 1
|
||||
|
||||
@@ -347,12 +347,12 @@ static LGFX *tft = nullptr;
|
||||
#include <TFT_eSPI.h> // Graphics and font library for ILI9342 driver chip
|
||||
|
||||
static TFT_eSPI *tft = nullptr; // Invoke library, pins defined in User_Setup.h
|
||||
#elif ARCH_PORTDUINO && HAS_SCREEN != 0
|
||||
#elif ARCH_PORTDUINO && HAS_SCREEN != 0 && !HAS_TFT
|
||||
#include <LovyanGFX.hpp> // Graphics and font library for ST7735 driver chip
|
||||
|
||||
class LGFX : public lgfx::LGFX_Device
|
||||
{
|
||||
lgfx::Panel_LCD *_panel_instance;
|
||||
lgfx::Panel_Device *_panel_instance;
|
||||
lgfx::Bus_SPI _bus_instance;
|
||||
|
||||
lgfx::ITouch *_touch_instance;
|
||||
@@ -366,10 +366,21 @@ class LGFX : public lgfx::LGFX_Device
|
||||
_panel_instance = new lgfx::Panel_ST7735;
|
||||
else if (settingsMap[displayPanel] == st7735s)
|
||||
_panel_instance = new lgfx::Panel_ST7735S;
|
||||
else if (settingsMap[displayPanel] == st7796)
|
||||
_panel_instance = new lgfx::Panel_ST7796;
|
||||
else if (settingsMap[displayPanel] == ili9341)
|
||||
_panel_instance = new lgfx::Panel_ILI9341;
|
||||
else if (settingsMap[displayPanel] == ili9342)
|
||||
_panel_instance = new lgfx::Panel_ILI9342;
|
||||
else if (settingsMap[displayPanel] == ili9488)
|
||||
_panel_instance = new lgfx::Panel_ILI9488;
|
||||
else if (settingsMap[displayPanel] == hx8357d)
|
||||
_panel_instance = new lgfx::Panel_HX8357D;
|
||||
else {
|
||||
_panel_instance = new lgfx::Panel_NULL;
|
||||
LOG_ERROR("Unknown display panel configured!");
|
||||
}
|
||||
|
||||
auto buscfg = _bus_instance.config();
|
||||
buscfg.spi_mode = 0;
|
||||
buscfg.spi_host = settingsMap[displayspidev];
|
||||
@@ -383,12 +394,12 @@ class LGFX : public lgfx::LGFX_Device
|
||||
LOG_DEBUG("Height: %d, Width: %d ", settingsMap[displayHeight], settingsMap[displayWidth]);
|
||||
cfg.pin_cs = settingsMap[displayCS]; // Pin number where CS is connected (-1 = disable)
|
||||
cfg.pin_rst = settingsMap[displayReset];
|
||||
cfg.panel_width = settingsMap[displayWidth]; // actual displayable width
|
||||
cfg.panel_height = settingsMap[displayHeight]; // actual displayable height
|
||||
cfg.offset_x = settingsMap[displayOffsetX]; // Panel offset amount in X direction
|
||||
cfg.offset_y = settingsMap[displayOffsetY]; // Panel offset amount in Y direction
|
||||
cfg.offset_rotation = 0; // Rotation direction value offset 0~7 (4~7 is mirrored)
|
||||
cfg.invert = settingsMap[displayInvert]; // Set to true if the light/darkness of the panel is reversed
|
||||
cfg.panel_width = settingsMap[displayWidth]; // actual displayable width
|
||||
cfg.panel_height = settingsMap[displayHeight]; // actual displayable height
|
||||
cfg.offset_x = settingsMap[displayOffsetX]; // Panel offset amount in X direction
|
||||
cfg.offset_y = settingsMap[displayOffsetY]; // Panel offset amount in Y direction
|
||||
cfg.offset_rotation = settingsMap[displayOffsetRotate]; // Rotation direction value offset 0~7 (4~7 is mirrored)
|
||||
cfg.invert = settingsMap[displayInvert]; // Set to true if the light/darkness of the panel is reversed
|
||||
|
||||
_panel_instance->config(cfg);
|
||||
|
||||
@@ -410,7 +421,7 @@ class LGFX : public lgfx::LGFX_Device
|
||||
touch_cfg.y_max = settingsMap[displayWidth] - 1;
|
||||
touch_cfg.pin_int = settingsMap[touchscreenIRQ];
|
||||
touch_cfg.bus_shared = true;
|
||||
touch_cfg.offset_rotation = 1;
|
||||
touch_cfg.offset_rotation = settingsMap[touchscreenRotate];
|
||||
if (settingsMap[touchscreenI2CAddr] != -1) {
|
||||
touch_cfg.i2c_addr = settingsMap[touchscreenI2CAddr];
|
||||
} else {
|
||||
|
||||
1863
src/graphics/fonts/OLEDDisplayFontsCS.cpp
Normal file
1863
src/graphics/fonts/OLEDDisplayFontsCS.cpp
Normal file
File diff suppressed because it is too large
Load Diff
16
src/graphics/fonts/OLEDDisplayFontsCS.h
Normal file
16
src/graphics/fonts/OLEDDisplayFontsCS.h
Normal file
@@ -0,0 +1,16 @@
|
||||
#ifndef OLEDDISPLAYFONTSCS_h
|
||||
#define OLEDDISPLAYFONTSCS_h
|
||||
|
||||
#ifdef ARDUINO
|
||||
#include <Arduino.h>
|
||||
#elif __MBED__
|
||||
#define PROGMEM
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Localization for Czech and Slovak language containing glyphs with diacritic.
|
||||
*/
|
||||
extern const uint8_t ArialMT_Plain_10_CS[] PROGMEM;
|
||||
extern const uint8_t ArialMT_Plain_16_CS[] PROGMEM;
|
||||
extern const uint8_t ArialMT_Plain_24_CS[] PROGMEM;
|
||||
#endif
|
||||
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user