mirror of
https://github.com/meshtastic/firmware.git
synced 2025-02-01 02:09:57 +00:00
Merge remote-tracking branch 'origin/master' into NextHopRouter
This commit is contained in:
commit
dc4279e7fd
@ -1,4 +1,4 @@
|
||||
name: Nightly Debian Packaging
|
||||
name: Daily Packaging
|
||||
on:
|
||||
schedule:
|
||||
- cron: 0 9 * * *
|
||||
@ -8,10 +8,12 @@ on:
|
||||
- master
|
||||
paths:
|
||||
- debian/**
|
||||
- .github/workflows/nightly_debian.yml
|
||||
- "*.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
|
||||
@ -35,3 +37,9 @@ jobs:
|
||||
obs_project: home:meshtastic:daily
|
||||
series: unstable
|
||||
secrets: inherit
|
||||
|
||||
hook-copr:
|
||||
uses: ./.github/workflows/hook_copr.yml
|
||||
with:
|
||||
copr_project: daily
|
||||
secrets: inherit
|
61
.github/workflows/hook_copr.yml
vendored
Normal file
61
.github/workflows/hook_copr.yml
vendored
Normal file
@ -0,0 +1,61 @@
|
||||
name: Trigger COPR build
|
||||
|
||||
on:
|
||||
workflow_call:
|
||||
secrets:
|
||||
COPR_HOOK_DAILY:
|
||||
COPR_HOOK_ALPHA:
|
||||
COPR_HOOK_BETA:
|
||||
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: Install Python dependencies
|
||||
run: |
|
||||
pip install requests
|
||||
|
||||
- name: Trigger COPR build
|
||||
shell: python
|
||||
run: |
|
||||
import requests
|
||||
|
||||
project_name = "${{ inputs.copr_project }}"
|
||||
if project_name == "daily":
|
||||
hook_secret = "${{ secrets.COPR_HOOK_DAILY }}"
|
||||
project_id = 160277
|
||||
elif project_name == "alpha":
|
||||
hook_secret = "${{ secrets.COPR_HOOK_ALPHA }}"
|
||||
project_id = 160278
|
||||
elif project_name == "beta":
|
||||
hook_secret = "${{ secrets.COPR_HOOK_BETA }}"
|
||||
project_id = 160279
|
||||
else:
|
||||
raise ValueError(f"Unknown COPR project: {project_name}")
|
||||
|
||||
webhook_url = f"https://copr.fedorainfracloud.org/webhooks/github/{project_id}/{hook_secret}/meshtasticd/"
|
||||
copr_payload = {
|
||||
"ref": "${{ github.ref }}",
|
||||
"after": "${{ github.sha }}",
|
||||
"repository": {
|
||||
"clone_url": "${{ github.server_url }}/${{ github.repository }}.git",
|
||||
}
|
||||
}
|
||||
r = requests.post(webhook_url, json=copr_payload, headers={"X-GitHub-Event": "push"})
|
||||
r.raise_for_status()
|
26
.github/workflows/main_matrix.yml
vendored
26
.github/workflows/main_matrix.yml
vendored
@ -320,14 +320,13 @@ jobs:
|
||||
run: ls -lR
|
||||
|
||||
- name: Add deb files to release
|
||||
uses: softprops/action-gh-release@v2
|
||||
with:
|
||||
tag_name: v${{ steps.version.outputs.long }}
|
||||
files: |
|
||||
./output/meshtasticd_${{ steps.version.outputs.long }}_arm64.deb
|
||||
./output/meshtasticd_${{ steps.version.outputs.long }}_armhf.deb
|
||||
./output/meshtasticd_${{ steps.version.outputs.long }}_amd64.deb
|
||||
./output/meshtasticd-${{ steps.version.outputs.deb }}-src.zip
|
||||
run: |
|
||||
gh release upload v${{ steps.version.outputs.long }} ./output/meshtasticd_${{ steps.version.outputs.long }}_arm64.deb
|
||||
gh release upload v${{ steps.version.outputs.long }} ./output/meshtasticd_${{ steps.version.outputs.long }}_armhf.deb
|
||||
gh release upload v${{ steps.version.outputs.long }} ./output/meshtasticd_${{ steps.version.outputs.long }}_amd64.deb
|
||||
gh release upload v${{ steps.version.outputs.long }} ./output/meshtasticd-${{ steps.version.outputs.deb }}-src.zip
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Bump version.properties
|
||||
run: >-
|
||||
@ -397,9 +396,8 @@ jobs:
|
||||
run: ls -lR
|
||||
|
||||
- name: Add bins and debug elfs to release
|
||||
uses: softprops/action-gh-release@v2
|
||||
with:
|
||||
tag_name: v${{ steps.version.outputs.long }}
|
||||
files: |
|
||||
./firmware-${{matrix.arch}}-${{ steps.version.outputs.long }}.zip
|
||||
./debug-elfs-${{matrix.arch}}-${{ steps.version.outputs.long }}.zip
|
||||
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: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
11
.github/workflows/release_channels.yml
vendored
11
.github/workflows/release_channels.yml
vendored
@ -4,7 +4,9 @@ on:
|
||||
release:
|
||||
types: [published, released]
|
||||
|
||||
permissions: read-all
|
||||
permissions:
|
||||
contents: write
|
||||
packages: write
|
||||
|
||||
jobs:
|
||||
package-ppa:
|
||||
@ -27,3 +29,10 @@ jobs:
|
||||
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
|
||||
|
@ -23,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
|
||||
@ -39,7 +80,7 @@ Lora:
|
||||
|
||||
# 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,4 +188,4 @@ General:
|
||||
MaxMessageQueue: 100
|
||||
ConfigDirectory: /etc/meshtasticd/config.d/
|
||||
# MACAddress: AA:BB:CC:DD:EE:FF
|
||||
# MACAddressSource: eth0
|
||||
# MACAddressSource: eth0
|
||||
|
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"
|
||||
}
|
5
debian/changelog
vendored
5
debian/changelog
vendored
@ -1,5 +1,6 @@
|
||||
meshtasticd (2.5.19.0) UNRELEASED; urgency=medium
|
||||
meshtasticd (2.5.20.0) UNRELEASED; urgency=medium
|
||||
|
||||
* Initial packaging
|
||||
* GitHub Actions Automatic version bump
|
||||
|
||||
-- Austin Lane <vidplace7@gmail.com> Thu, 02 Jan 2025 12:00:00 +0000
|
||||
-- Austin Lane <github-actions[bot]@users.noreply.github.com> Mon, 13 Jan 2025 19:24:14 +0000
|
||||
|
91
meshtasticd.spec.rpkg
Normal file
91
meshtasticd.spec.rpkg
Normal file
@ -0,0 +1,91 @@
|
||||
# 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/download/latest/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
|
||||
|
||||
%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/*
|
||||
|
||||
%changelog
|
||||
%autochangelog
|
2
rpkg.conf
Normal file
2
rpkg.conf
Normal file
@ -0,0 +1,2 @@
|
||||
[rpkg]
|
||||
user_macros = "${git_props:root}/bin/rpkg.macros"
|
@ -6,6 +6,13 @@
|
||||
static File openFile(const char *filename, bool fullAtomic)
|
||||
{
|
||||
concurrency::LockGuard g(spiLock);
|
||||
LOG_DEBUG("Opening %s, fullAtomic=%d", filename, fullAtomic);
|
||||
#ifdef ARCH_NRF52
|
||||
lfs_assert_failed = false;
|
||||
File file = FSCom.open(filename, FILE_O_WRITE);
|
||||
file.seek(0);
|
||||
return file;
|
||||
#endif
|
||||
if (!fullAtomic)
|
||||
FSCom.remove(filename); // Nuke the old file to make space (ignore if it !exists)
|
||||
|
||||
@ -14,7 +21,6 @@ static File openFile(const char *filename, bool fullAtomic)
|
||||
|
||||
// clear any previous LFS errors
|
||||
lfs_assert_failed = false;
|
||||
|
||||
return FSCom.open(filenameTmp.c_str(), FILE_O_WRITE);
|
||||
}
|
||||
|
||||
@ -55,8 +61,15 @@ bool SafeFile::close()
|
||||
return false;
|
||||
|
||||
spiLock->lock();
|
||||
#ifdef ARCH_NRF52
|
||||
f.truncate();
|
||||
#endif
|
||||
f.close();
|
||||
spiLock->unlock();
|
||||
|
||||
#ifdef ARCH_NRF52
|
||||
return true;
|
||||
#endif
|
||||
if (!testReadback())
|
||||
return false;
|
||||
|
||||
|
136
src/main.cpp
136
src/main.cpp
@ -826,116 +826,56 @@ void setup()
|
||||
#endif
|
||||
|
||||
#ifdef ARCH_PORTDUINO
|
||||
if (settingsMap[use_sx1262]) {
|
||||
if (!rIf) {
|
||||
LOG_DEBUG("Activate sx1262 radio on SPI port %s", settingsStrings[spidev].c_str());
|
||||
const struct {
|
||||
configNames cfgName;
|
||||
std::string strName;
|
||||
} loraModules[] = {{use_rf95, "RF95"}, {use_sx1262, "sx1262"}, {use_sx1268, "sx1268"}, {use_sx1280, "sx1280"},
|
||||
{use_lr1110, "lr1110"}, {use_lr1120, "lr1120"}, {use_lr1121, "lr1121"}, {use_llcc68, "LLCC68"}};
|
||||
// as one can't use a function pointer to the class constructor:
|
||||
auto loraModuleInterface = [](configNames cfgName, LockingArduinoHal *hal, RADIOLIB_PIN_TYPE cs, RADIOLIB_PIN_TYPE irq,
|
||||
RADIOLIB_PIN_TYPE rst, RADIOLIB_PIN_TYPE busy) {
|
||||
switch (cfgName) {
|
||||
case use_rf95:
|
||||
return (RadioInterface *)new RF95Interface(hal, cs, irq, rst, busy);
|
||||
case use_sx1262:
|
||||
return (RadioInterface *)new SX1262Interface(hal, cs, irq, rst, busy);
|
||||
case use_sx1268:
|
||||
return (RadioInterface *)new SX1268Interface(hal, cs, irq, rst, busy);
|
||||
case use_sx1280:
|
||||
return (RadioInterface *)new SX1280Interface(hal, cs, irq, rst, busy);
|
||||
case use_lr1110:
|
||||
return (RadioInterface *)new LR1110Interface(hal, cs, irq, rst, busy);
|
||||
case use_lr1120:
|
||||
return (RadioInterface *)new LR1120Interface(hal, cs, irq, rst, busy);
|
||||
case use_lr1121:
|
||||
return (RadioInterface *)new LR1121Interface(hal, cs, irq, rst, busy);
|
||||
case use_llcc68:
|
||||
return (RadioInterface *)new LLCC68Interface(hal, cs, irq, rst, busy);
|
||||
default:
|
||||
assert(0); // shouldn't happen
|
||||
return (RadioInterface *)nullptr;
|
||||
}
|
||||
};
|
||||
for (auto &loraModule : loraModules) {
|
||||
if (settingsMap[loraModule.cfgName] && !rIf) {
|
||||
LOG_DEBUG("Activate %s radio on SPI port %s", loraModule.strName.c_str(), settingsStrings[spidev].c_str());
|
||||
if (settingsStrings[spidev] == "ch341") {
|
||||
RadioLibHAL = ch341Hal;
|
||||
} else {
|
||||
RadioLibHAL = new LockingArduinoHal(SPI, spiSettings);
|
||||
}
|
||||
rIf = new SX1262Interface((LockingArduinoHal *)RadioLibHAL, settingsMap[cs], settingsMap[irq], settingsMap[reset],
|
||||
settingsMap[busy]);
|
||||
rIf = loraModuleInterface(loraModule.cfgName, (LockingArduinoHal *)RadioLibHAL, settingsMap[cs_pin],
|
||||
settingsMap[irq_pin], settingsMap[reset_pin], settingsMap[busy_pin]);
|
||||
if (!rIf->init()) {
|
||||
LOG_WARN("No SX1262 radio");
|
||||
delete rIf;
|
||||
exit(EXIT_FAILURE);
|
||||
} else {
|
||||
LOG_INFO("SX1262 init success");
|
||||
}
|
||||
}
|
||||
} else if (settingsMap[use_rf95]) {
|
||||
if (!rIf) {
|
||||
LOG_DEBUG("Activate rf95 radio on SPI port %s", settingsStrings[spidev].c_str());
|
||||
RadioLibHAL = new LockingArduinoHal(SPI, spiSettings);
|
||||
rIf = new RF95Interface((LockingArduinoHal *)RadioLibHAL, settingsMap[cs], settingsMap[irq], settingsMap[reset],
|
||||
settingsMap[busy]);
|
||||
if (!rIf->init()) {
|
||||
LOG_WARN("No RF95 radio");
|
||||
LOG_WARN("No %s radio", loraModule.strName.c_str());
|
||||
delete rIf;
|
||||
rIf = NULL;
|
||||
exit(EXIT_FAILURE);
|
||||
} else {
|
||||
LOG_INFO("RF95 init success");
|
||||
}
|
||||
}
|
||||
} else if (settingsMap[use_sx1280]) {
|
||||
if (!rIf) {
|
||||
LOG_DEBUG("Activate sx1280 radio on SPI port %s", settingsStrings[spidev].c_str());
|
||||
RadioLibHAL = new LockingArduinoHal(SPI, spiSettings);
|
||||
rIf = new SX1280Interface((LockingArduinoHal *)RadioLibHAL, settingsMap[cs], settingsMap[irq], settingsMap[reset],
|
||||
settingsMap[busy]);
|
||||
if (!rIf->init()) {
|
||||
LOG_WARN("No SX1280 radio");
|
||||
delete rIf;
|
||||
rIf = NULL;
|
||||
exit(EXIT_FAILURE);
|
||||
} else {
|
||||
LOG_INFO("SX1280 init success");
|
||||
}
|
||||
}
|
||||
} else if (settingsMap[use_lr1110]) {
|
||||
if (!rIf) {
|
||||
LOG_DEBUG("Activate lr1110 radio on SPI port %s", settingsStrings[spidev].c_str());
|
||||
LockingArduinoHal *RadioLibHAL = new LockingArduinoHal(SPI, spiSettings);
|
||||
rIf = new LR1110Interface((LockingArduinoHal *)RadioLibHAL, settingsMap[cs], settingsMap[irq], settingsMap[reset],
|
||||
settingsMap[busy]);
|
||||
if (!rIf->init()) {
|
||||
LOG_WARN("No LR1110 radio");
|
||||
delete rIf;
|
||||
rIf = NULL;
|
||||
exit(EXIT_FAILURE);
|
||||
} else {
|
||||
LOG_INFO("LR1110 init success");
|
||||
}
|
||||
}
|
||||
} else if (settingsMap[use_lr1120]) {
|
||||
if (!rIf) {
|
||||
LOG_DEBUG("Activate lr1120 radio on SPI port %s", settingsStrings[spidev].c_str());
|
||||
LockingArduinoHal *RadioLibHAL = new LockingArduinoHal(SPI, spiSettings);
|
||||
rIf = new LR1120Interface((LockingArduinoHal *)RadioLibHAL, settingsMap[cs], settingsMap[irq], settingsMap[reset],
|
||||
settingsMap[busy]);
|
||||
if (!rIf->init()) {
|
||||
LOG_WARN("No LR1120 radio");
|
||||
delete rIf;
|
||||
rIf = NULL;
|
||||
exit(EXIT_FAILURE);
|
||||
} else {
|
||||
LOG_INFO("LR1120 init success");
|
||||
}
|
||||
}
|
||||
} else if (settingsMap[use_lr1121]) {
|
||||
if (!rIf) {
|
||||
LOG_DEBUG("Activate lr1121 radio on SPI port %s", settingsStrings[spidev].c_str());
|
||||
LockingArduinoHal *RadioLibHAL = new LockingArduinoHal(SPI, spiSettings);
|
||||
rIf = new LR1121Interface((LockingArduinoHal *)RadioLibHAL, settingsMap[cs], settingsMap[irq], settingsMap[reset],
|
||||
settingsMap[busy]);
|
||||
if (!rIf->init()) {
|
||||
LOG_WARN("No LR1121 radio");
|
||||
delete rIf;
|
||||
rIf = NULL;
|
||||
exit(EXIT_FAILURE);
|
||||
} else {
|
||||
LOG_INFO("LR1121 init success");
|
||||
}
|
||||
}
|
||||
} else if (settingsMap[use_sx1268]) {
|
||||
if (!rIf) {
|
||||
LOG_DEBUG("Activate sx1268 radio on SPI port %s", settingsStrings[spidev].c_str());
|
||||
RadioLibHAL = new LockingArduinoHal(SPI, spiSettings);
|
||||
rIf = new SX1268Interface((LockingArduinoHal *)RadioLibHAL, settingsMap[cs], settingsMap[irq], settingsMap[reset],
|
||||
settingsMap[busy]);
|
||||
if (!rIf->init()) {
|
||||
LOG_WARN("No SX1268 radio");
|
||||
delete rIf;
|
||||
rIf = NULL;
|
||||
exit(EXIT_FAILURE);
|
||||
} else {
|
||||
LOG_INFO("SX1268 init success");
|
||||
LOG_INFO("%s init success", loraModule.strName.c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#elif defined(HW_SPI1_DEVICE)
|
||||
LockingArduinoHal *RadioLibHAL = new LockingArduinoHal(SPI1, spiSettings);
|
||||
#else // HW_SPI1_DEVICE
|
||||
@ -1280,4 +1220,4 @@ void loop()
|
||||
mainDelay.delay(delayMsec);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
@ -69,7 +69,11 @@ bool MeshPacketQueue::enqueue(meshtastic_MeshPacket *p)
|
||||
{
|
||||
// no space - try to replace a lower priority packet in the queue
|
||||
if (queue.size() >= maxLen) {
|
||||
return replaceLowerPriorityPacket(p);
|
||||
bool replaced = replaceLowerPriorityPacket(p);
|
||||
if (!replaced) {
|
||||
LOG_WARN("TX queue is full, and there is no lower-priority packet available to evict in favour of 0x%08x", p->id);
|
||||
}
|
||||
return replaced;
|
||||
}
|
||||
|
||||
// Find the correct position using upper_bound to maintain a stable order
|
||||
@ -126,7 +130,10 @@ bool MeshPacketQueue::find(NodeNum from, PacketId id)
|
||||
return false;
|
||||
}
|
||||
|
||||
/** Attempt to find and remove a packet from this queue. Returns the packet which was removed from the queue */
|
||||
/**
|
||||
* Attempt to find a lower-priority packet in the queue and replace it with the provided one.
|
||||
* @return True if the replacement succeeded, false otherwise
|
||||
*/
|
||||
bool MeshPacketQueue::replaceLowerPriorityPacket(meshtastic_MeshPacket *p)
|
||||
{
|
||||
|
||||
@ -135,11 +142,12 @@ bool MeshPacketQueue::replaceLowerPriorityPacket(meshtastic_MeshPacket *p)
|
||||
}
|
||||
|
||||
// Check if the packet at the back has a lower priority than the new packet
|
||||
auto &backPacket = queue.back();
|
||||
auto *backPacket = queue.back();
|
||||
if (!backPacket->tx_after && backPacket->priority < p->priority) {
|
||||
LOG_WARN("Dropping packet 0x%08x to make room in the TX queue for higher-priority packet 0x%08x", backPacket->id, p->id);
|
||||
// Remove the back packet
|
||||
packetPool.release(backPacket);
|
||||
queue.pop_back();
|
||||
packetPool.release(backPacket);
|
||||
// Insert the new packet in the correct order
|
||||
enqueue(p);
|
||||
return true;
|
||||
@ -152,8 +160,12 @@ bool MeshPacketQueue::replaceLowerPriorityPacket(meshtastic_MeshPacket *p)
|
||||
for (; refPacket->tx_after && it != queue.begin(); refPacket = *--it)
|
||||
;
|
||||
if (!refPacket->tx_after && refPacket->priority < p->priority) {
|
||||
LOG_WARN("Dropping non-late packet 0x%08x to make room in the TX queue for higher-priority packet 0x%08x",
|
||||
refPacket->id, p->id);
|
||||
queue.erase(it);
|
||||
packetPool.release(refPacket);
|
||||
enqueue(refPacket);
|
||||
// Insert the new packet in the correct order
|
||||
enqueue(p);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -958,7 +958,7 @@ void NodeDB::loadFromDisk()
|
||||
#endif
|
||||
|
||||
// static DeviceState scratch; We no longer read into a tempbuf because this structure is 15KB of valuable RAM
|
||||
auto state = loadProto(prefFileName, sizeof(meshtastic_DeviceState) + MAX_NUM_NODES_FS * sizeof(meshtastic_NodeInfo),
|
||||
auto state = loadProto(prefFileName, sizeof(meshtastic_DeviceState) + MAX_NUM_NODES_FS * meshtastic_NodeInfoLite_size,
|
||||
sizeof(meshtastic_DeviceState), &meshtastic_DeviceState_msg, &devicestate);
|
||||
|
||||
// See https://github.com/meshtastic/firmware/issues/4184#issuecomment-2269390786
|
||||
@ -1147,8 +1147,9 @@ bool NodeDB::saveDeviceStateToDisk()
|
||||
#endif
|
||||
// Note: if MAX_NUM_NODES=100 and meshtastic_NodeInfoLite_size=166, so will be approximately 17KB
|
||||
// Because so huge we _must_ not use fullAtomic, because the filesystem is probably too small to hold two copies of this
|
||||
return saveProto(prefFileName, sizeof(devicestate) + numMeshNodes * meshtastic_NodeInfoLite_size, &meshtastic_DeviceState_msg,
|
||||
&devicestate, false);
|
||||
size_t deviceStateSize;
|
||||
pb_get_encoded_size(&deviceStateSize, meshtastic_DeviceState_fields, &devicestate);
|
||||
return saveProto(prefFileName, deviceStateSize, &meshtastic_DeviceState_msg, &devicestate, false);
|
||||
}
|
||||
|
||||
bool NodeDB::saveToDiskNoRetry(int saveWhat)
|
||||
|
@ -91,16 +91,16 @@ void RF95Interface::setTransmitEnable(bool txon)
|
||||
#ifdef RF95_TXEN
|
||||
digitalWrite(RF95_TXEN, txon ? 1 : 0);
|
||||
#elif ARCH_PORTDUINO
|
||||
if (settingsMap[txen] != RADIOLIB_NC) {
|
||||
digitalWrite(settingsMap[txen], txon ? 1 : 0);
|
||||
if (settingsMap[txen_pin] != RADIOLIB_NC) {
|
||||
digitalWrite(settingsMap[txen_pin], txon ? 1 : 0);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef RF95_RXEN
|
||||
digitalWrite(RF95_RXEN, txon ? 0 : 1);
|
||||
#elif ARCH_PORTDUINO
|
||||
if (settingsMap[rxen] != RADIOLIB_NC) {
|
||||
digitalWrite(settingsMap[rxen], txon ? 0 : 1);
|
||||
if (settingsMap[rxen_pin] != RADIOLIB_NC) {
|
||||
digitalWrite(settingsMap[rxen_pin], txon ? 0 : 1);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
@ -164,13 +164,13 @@ bool RF95Interface::init()
|
||||
digitalWrite(RF95_RXEN, 1);
|
||||
#endif
|
||||
#if ARCH_PORTDUINO
|
||||
if (settingsMap[txen] != RADIOLIB_NC) {
|
||||
pinMode(settingsMap[txen], OUTPUT);
|
||||
digitalWrite(settingsMap[txen], 0);
|
||||
if (settingsMap[txen_pin] != RADIOLIB_NC) {
|
||||
pinMode(settingsMap[txen_pin], OUTPUT);
|
||||
digitalWrite(settingsMap[txen_pin], 0);
|
||||
}
|
||||
if (settingsMap[rxen] != RADIOLIB_NC) {
|
||||
pinMode(settingsMap[rxen], OUTPUT);
|
||||
digitalWrite(settingsMap[rxen], 0);
|
||||
if (settingsMap[rxen_pin] != RADIOLIB_NC) {
|
||||
pinMode(settingsMap[rxen_pin], OUTPUT);
|
||||
digitalWrite(settingsMap[rxen_pin], 0);
|
||||
}
|
||||
#endif
|
||||
setTransmitEnable(false);
|
||||
@ -337,4 +337,4 @@ bool RF95Interface::sleep()
|
||||
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
@ -277,6 +277,7 @@ void RadioLibInterface::onNotify(uint32_t notification)
|
||||
uint32_t xmitMsec = getPacketTime(txp);
|
||||
airTime->logAirtime(TX_LOG, xmitMsec);
|
||||
}
|
||||
LOG_DEBUG("%d packets remain in the TX queue", txQueue.getMaxLen() - txQueue.getFree());
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -303,8 +304,8 @@ void RadioLibInterface::setTransmitDelay()
|
||||
if (p->tx_after) {
|
||||
unsigned long add_delay = p->rx_rssi ? getTxDelayMsecWeighted(p->rx_snr) : getTxDelayMsec();
|
||||
unsigned long now = millis();
|
||||
p->tx_after = max(p->tx_after + add_delay, now + add_delay);
|
||||
notifyLater(now - p->tx_after, TRANSMIT_DELAY_COMPLETED, false);
|
||||
p->tx_after = min(max(p->tx_after + add_delay, now + add_delay), now + 2 * getTxDelayMsecWeightedWorst(p->rx_snr));
|
||||
notifyLater(p->tx_after - now, TRANSMIT_DELAY_COMPLETED, false);
|
||||
} else if (p->rx_snr == 0 && p->rx_rssi == 0) {
|
||||
/* We assume if rx_snr = 0 and rx_rssi = 0, the packet was generated locally.
|
||||
* This assumption is valid because of the offset generated by the radio to account for the noise
|
||||
|
@ -51,9 +51,9 @@ template <typename T> bool SX126xInterface<T>::init()
|
||||
|
||||
#if ARCH_PORTDUINO
|
||||
float tcxoVoltage = (float)settingsMap[dio3_tcxo_voltage] / 1000;
|
||||
if (settingsMap[sx126x_ant_sw] != RADIOLIB_NC) {
|
||||
digitalWrite(settingsMap[sx126x_ant_sw], HIGH);
|
||||
pinMode(settingsMap[sx126x_ant_sw], OUTPUT);
|
||||
if (settingsMap[sx126x_ant_sw_pin] != RADIOLIB_NC) {
|
||||
digitalWrite(settingsMap[sx126x_ant_sw_pin], HIGH);
|
||||
pinMode(settingsMap[sx126x_ant_sw_pin], OUTPUT);
|
||||
}
|
||||
// FIXME: correct logic to default to not using TCXO if no voltage is specified for SX126X_DIO3_TCXO_VOLTAGE
|
||||
#elif !defined(SX126X_DIO3_TCXO_VOLTAGE)
|
||||
@ -121,8 +121,9 @@ template <typename T> bool SX126xInterface<T>::init()
|
||||
// no effect
|
||||
#if ARCH_PORTDUINO
|
||||
if (res == RADIOLIB_ERR_NONE) {
|
||||
LOG_DEBUG("Use MCU pin %i as RXEN and pin %i as TXEN to control RF switching", settingsMap[rxen], settingsMap[txen]);
|
||||
lora.setRfSwitchPins(settingsMap[rxen], settingsMap[txen]);
|
||||
LOG_DEBUG("Use MCU pin %i as RXEN and pin %i as TXEN to control RF switching", settingsMap[rxen_pin],
|
||||
settingsMap[txen_pin]);
|
||||
lora.setRfSwitchPins(settingsMap[rxen_pin], settingsMap[txen_pin]);
|
||||
}
|
||||
#else
|
||||
#ifndef SX126X_RXEN
|
||||
@ -341,4 +342,4 @@ template <typename T> bool SX126xInterface<T>::sleep()
|
||||
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
@ -38,13 +38,13 @@ template <typename T> bool SX128xInterface<T>::init()
|
||||
#endif
|
||||
|
||||
#if ARCH_PORTDUINO
|
||||
if (settingsMap[rxen] != RADIOLIB_NC) {
|
||||
pinMode(settingsMap[rxen], OUTPUT);
|
||||
digitalWrite(settingsMap[rxen], LOW); // Set low before becoming an output
|
||||
if (settingsMap[rxen_pin] != RADIOLIB_NC) {
|
||||
pinMode(settingsMap[rxen_pin], OUTPUT);
|
||||
digitalWrite(settingsMap[rxen_pin], LOW); // Set low before becoming an output
|
||||
}
|
||||
if (settingsMap[txen] != RADIOLIB_NC) {
|
||||
pinMode(settingsMap[txen], OUTPUT);
|
||||
digitalWrite(settingsMap[txen], LOW); // Set low before becoming an output
|
||||
if (settingsMap[txen_pin] != RADIOLIB_NC) {
|
||||
pinMode(settingsMap[txen_pin], OUTPUT);
|
||||
digitalWrite(settingsMap[txen_pin], LOW); // Set low before becoming an output
|
||||
}
|
||||
#else
|
||||
#if defined(SX128X_RXEN) && (SX128X_RXEN != RADIOLIB_NC) // set not rx or tx mode
|
||||
@ -93,8 +93,8 @@ template <typename T> bool SX128xInterface<T>::init()
|
||||
lora.setRfSwitchPins(SX128X_RXEN, SX128X_TXEN);
|
||||
}
|
||||
#elif ARCH_PORTDUINO
|
||||
if (res == RADIOLIB_ERR_NONE && settingsMap[rxen] != RADIOLIB_NC && settingsMap[txen] != RADIOLIB_NC) {
|
||||
lora.setRfSwitchPins(settingsMap[rxen], settingsMap[txen]);
|
||||
if (res == RADIOLIB_ERR_NONE && settingsMap[rxen_pin] != RADIOLIB_NC && settingsMap[txen_pin] != RADIOLIB_NC) {
|
||||
lora.setRfSwitchPins(settingsMap[rxen_pin], settingsMap[txen_pin]);
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -174,11 +174,11 @@ template <typename T> void SX128xInterface<T>::setStandby()
|
||||
LOG_ERROR("SX128x standby %s%d", radioLibErr, err);
|
||||
assert(err == RADIOLIB_ERR_NONE);
|
||||
#if ARCH_PORTDUINO
|
||||
if (settingsMap[rxen] != RADIOLIB_NC) {
|
||||
digitalWrite(settingsMap[rxen], LOW);
|
||||
if (settingsMap[rxen_pin] != RADIOLIB_NC) {
|
||||
digitalWrite(settingsMap[rxen_pin], LOW);
|
||||
}
|
||||
if (settingsMap[txen] != RADIOLIB_NC) {
|
||||
digitalWrite(settingsMap[txen], LOW);
|
||||
if (settingsMap[txen_pin] != RADIOLIB_NC) {
|
||||
digitalWrite(settingsMap[txen_pin], LOW);
|
||||
}
|
||||
#else
|
||||
#if defined(SX128X_RXEN) && (SX128X_RXEN != RADIOLIB_NC) // we have RXEN/TXEN control - turn off RX and TX power
|
||||
@ -210,11 +210,11 @@ template <typename T> void SX128xInterface<T>::addReceiveMetadata(meshtastic_Mes
|
||||
template <typename T> void SX128xInterface<T>::configHardwareForSend()
|
||||
{
|
||||
#if ARCH_PORTDUINO
|
||||
if (settingsMap[txen] != RADIOLIB_NC) {
|
||||
digitalWrite(settingsMap[txen], HIGH);
|
||||
if (settingsMap[txen_pin] != RADIOLIB_NC) {
|
||||
digitalWrite(settingsMap[txen_pin], HIGH);
|
||||
}
|
||||
if (settingsMap[rxen] != RADIOLIB_NC) {
|
||||
digitalWrite(settingsMap[rxen], LOW);
|
||||
if (settingsMap[rxen_pin] != RADIOLIB_NC) {
|
||||
digitalWrite(settingsMap[rxen_pin], LOW);
|
||||
}
|
||||
|
||||
#else
|
||||
@ -241,11 +241,11 @@ template <typename T> void SX128xInterface<T>::startReceive()
|
||||
setStandby();
|
||||
|
||||
#if ARCH_PORTDUINO
|
||||
if (settingsMap[rxen] != RADIOLIB_NC) {
|
||||
digitalWrite(settingsMap[rxen], HIGH);
|
||||
if (settingsMap[rxen_pin] != RADIOLIB_NC) {
|
||||
digitalWrite(settingsMap[rxen_pin], HIGH);
|
||||
}
|
||||
if (settingsMap[txen] != RADIOLIB_NC) {
|
||||
digitalWrite(settingsMap[txen], LOW);
|
||||
if (settingsMap[txen_pin] != RADIOLIB_NC) {
|
||||
digitalWrite(settingsMap[txen_pin], LOW);
|
||||
}
|
||||
|
||||
#else
|
||||
@ -315,4 +315,4 @@ template <typename T> bool SX128xInterface<T>::sleep()
|
||||
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
@ -222,7 +222,11 @@ void EnvironmentTelemetryModule::drawFrame(OLEDDisplay *display, OLEDDisplayUiSt
|
||||
}
|
||||
|
||||
// Display "Env. From: ..." on its own
|
||||
display->drawString(x, y, "Env. From: " + String(lastSender) + "(" + String(agoSecs) + "s)");
|
||||
display->drawString(x, y, "Env. From: " + String(lastSender) + " (" + String(agoSecs) + "s)");
|
||||
|
||||
// Prepare sensor data strings
|
||||
String sensorData[10];
|
||||
int sensorCount = 0;
|
||||
|
||||
if (lastMeasurement.variant.environment_metrics.has_temperature ||
|
||||
lastMeasurement.variant.environment_metrics.has_relative_humidity) {
|
||||
@ -232,38 +236,73 @@ void EnvironmentTelemetryModule::drawFrame(OLEDDisplay *display, OLEDDisplayUiSt
|
||||
String(UnitConversions::CelsiusToFahrenheit(lastMeasurement.variant.environment_metrics.temperature), 0) + "°F";
|
||||
}
|
||||
|
||||
// Continue with the remaining details
|
||||
display->drawString(x, y += _fontHeight(FONT_SMALL),
|
||||
"Temp/Hum: " + last_temp + " / " +
|
||||
String(lastMeasurement.variant.environment_metrics.relative_humidity, 0) + "%");
|
||||
sensorData[sensorCount++] =
|
||||
"Temp/Hum: " + last_temp + " / " + String(lastMeasurement.variant.environment_metrics.relative_humidity, 0) + "%";
|
||||
}
|
||||
|
||||
if (lastMeasurement.variant.environment_metrics.barometric_pressure != 0) {
|
||||
display->drawString(x, y += _fontHeight(FONT_SMALL),
|
||||
"Press: " + String(lastMeasurement.variant.environment_metrics.barometric_pressure, 0) + "hPA");
|
||||
sensorData[sensorCount++] =
|
||||
"Press: " + String(lastMeasurement.variant.environment_metrics.barometric_pressure, 0) + "hPA";
|
||||
}
|
||||
|
||||
if (lastMeasurement.variant.environment_metrics.voltage != 0) {
|
||||
display->drawString(x, y += _fontHeight(FONT_SMALL),
|
||||
"Volt/Cur: " + String(lastMeasurement.variant.environment_metrics.voltage, 0) + "V / " +
|
||||
String(lastMeasurement.variant.environment_metrics.current, 0) + "mA");
|
||||
sensorData[sensorCount++] = "Volt/Cur: " + String(lastMeasurement.variant.environment_metrics.voltage, 0) + "V / " +
|
||||
String(lastMeasurement.variant.environment_metrics.current, 0) + "mA";
|
||||
}
|
||||
|
||||
if (lastMeasurement.variant.environment_metrics.iaq != 0) {
|
||||
display->drawString(x, y += _fontHeight(FONT_SMALL), "IAQ: " + String(lastMeasurement.variant.environment_metrics.iaq));
|
||||
sensorData[sensorCount++] = "IAQ: " + String(lastMeasurement.variant.environment_metrics.iaq);
|
||||
}
|
||||
|
||||
if (lastMeasurement.variant.environment_metrics.distance != 0)
|
||||
display->drawString(x, y += _fontHeight(FONT_SMALL),
|
||||
"Water Level: " + String(lastMeasurement.variant.environment_metrics.distance, 0) + "mm");
|
||||
if (lastMeasurement.variant.environment_metrics.distance != 0) {
|
||||
sensorData[sensorCount++] = "Water Level: " + String(lastMeasurement.variant.environment_metrics.distance, 0) + "mm";
|
||||
}
|
||||
|
||||
if (lastMeasurement.variant.environment_metrics.weight != 0)
|
||||
display->drawString(x, y += _fontHeight(FONT_SMALL),
|
||||
"Weight: " + String(lastMeasurement.variant.environment_metrics.weight, 0) + "kg");
|
||||
if (lastMeasurement.variant.environment_metrics.weight != 0) {
|
||||
sensorData[sensorCount++] = "Weight: " + String(lastMeasurement.variant.environment_metrics.weight, 0) + "kg";
|
||||
}
|
||||
|
||||
if (lastMeasurement.variant.environment_metrics.radiation != 0)
|
||||
display->drawString(x, y += _fontHeight(FONT_SMALL),
|
||||
"Rad: " + String(lastMeasurement.variant.environment_metrics.radiation, 2) + "µR/h");
|
||||
if (lastMeasurement.variant.environment_metrics.radiation != 0) {
|
||||
sensorData[sensorCount++] = "Rad: " + String(lastMeasurement.variant.environment_metrics.radiation, 2) + "µR/h";
|
||||
}
|
||||
|
||||
if (lastMeasurement.variant.environment_metrics.lux != 0) {
|
||||
sensorData[sensorCount++] = "Illuminance: " + String(lastMeasurement.variant.environment_metrics.lux, 2) + "lx";
|
||||
}
|
||||
|
||||
if (lastMeasurement.variant.environment_metrics.white_lux != 0) {
|
||||
sensorData[sensorCount++] = "W_Lux: " + String(lastMeasurement.variant.environment_metrics.white_lux, 2) + "lx";
|
||||
}
|
||||
|
||||
static int scrollOffset = 0;
|
||||
static bool scrollingDown = true;
|
||||
static uint32_t lastScrollTime = millis();
|
||||
|
||||
// Draw up to 3 sensor data lines
|
||||
int linesToShow = min(3, sensorCount);
|
||||
for (int i = 0; i < linesToShow; i++) {
|
||||
int index = (scrollOffset + i) % sensorCount;
|
||||
display->drawString(x, y += _fontHeight(FONT_SMALL), sensorData[index]);
|
||||
}
|
||||
|
||||
// Only scroll if there are more than 3 sensor data lines
|
||||
if (sensorCount > 3) {
|
||||
// Update scroll offset every 5 seconds
|
||||
if (millis() - lastScrollTime > 5000) {
|
||||
if (scrollingDown) {
|
||||
scrollOffset++;
|
||||
if (scrollOffset + linesToShow >= sensorCount) {
|
||||
scrollingDown = false;
|
||||
}
|
||||
} else {
|
||||
scrollOffset--;
|
||||
if (scrollOffset <= 0) {
|
||||
scrollingDown = true;
|
||||
}
|
||||
}
|
||||
lastScrollTime = millis();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool EnvironmentTelemetryModule::handleReceivedProtobuf(const meshtastic_MeshPacket &mp, meshtastic_Telemetry *t)
|
||||
@ -277,8 +316,10 @@ bool EnvironmentTelemetryModule::handleReceivedProtobuf(const meshtastic_MeshPac
|
||||
sender, t->variant.environment_metrics.barometric_pressure, t->variant.environment_metrics.current,
|
||||
t->variant.environment_metrics.gas_resistance, t->variant.environment_metrics.relative_humidity,
|
||||
t->variant.environment_metrics.temperature);
|
||||
LOG_INFO("(Received from %s): voltage=%f, IAQ=%d, distance=%f, lux=%f", sender, t->variant.environment_metrics.voltage,
|
||||
t->variant.environment_metrics.iaq, t->variant.environment_metrics.distance, t->variant.environment_metrics.lux);
|
||||
LOG_INFO("(Received from %s): voltage=%f, IAQ=%d, distance=%f, lux=%f, white_lux=%f", sender,
|
||||
t->variant.environment_metrics.voltage, t->variant.environment_metrics.iaq,
|
||||
t->variant.environment_metrics.distance, t->variant.environment_metrics.lux,
|
||||
t->variant.environment_metrics.white_lux);
|
||||
|
||||
LOG_INFO("(Received from %s): wind speed=%fm/s, direction=%d degrees, weight=%fkg", sender,
|
||||
t->variant.environment_metrics.wind_speed, t->variant.environment_metrics.wind_direction,
|
||||
|
@ -44,11 +44,7 @@ class BluetoothPhoneAPI : public PhoneAPI
|
||||
}
|
||||
|
||||
/// Check the current underlying physical link to see if the client is currently connected
|
||||
virtual bool checkIsConnected() override
|
||||
{
|
||||
BLEConnection *connection = Bluefruit.Connection(connectionHandle);
|
||||
return connection->connected();
|
||||
}
|
||||
virtual bool checkIsConnected() override { return Bluefruit.connected(connectionHandle); }
|
||||
};
|
||||
|
||||
static BluetoothPhoneAPI *bluetoothPhoneAPI;
|
||||
@ -214,7 +210,10 @@ void NRF52Bluetooth::shutdown()
|
||||
LOG_INFO("NRF52 bluetooth disconnecting handle %d", i);
|
||||
Bluefruit.disconnect(i);
|
||||
}
|
||||
delay(100); // wait for ondisconnect;
|
||||
// Wait for disconnection
|
||||
while (Bluefruit.connected())
|
||||
yield();
|
||||
LOG_INFO("All bluetooth connections ended");
|
||||
}
|
||||
Bluefruit.Advertising.stop();
|
||||
}
|
||||
|
@ -134,21 +134,10 @@ void portduinoSetup()
|
||||
{
|
||||
printf("Set up Meshtastic on Portduino...\n");
|
||||
int max_GPIO = 0;
|
||||
const configNames GPIO_lines[] = {cs,
|
||||
irq,
|
||||
busy,
|
||||
reset,
|
||||
sx126x_ant_sw,
|
||||
txen,
|
||||
rxen,
|
||||
displayDC,
|
||||
displayCS,
|
||||
displayBacklight,
|
||||
displayBacklightPWMChannel,
|
||||
displayReset,
|
||||
touchscreenCS,
|
||||
touchscreenIRQ,
|
||||
user};
|
||||
const configNames GPIO_lines[] = {
|
||||
cs_pin, irq_pin, busy_pin, reset_pin, sx126x_ant_sw_pin, txen_pin,
|
||||
rxen_pin, displayDC, displayCS, displayBacklight, displayBacklightPWMChannel, displayReset,
|
||||
touchscreenCS, touchscreenIRQ, user};
|
||||
|
||||
std::string gpioChipName = "gpiochip";
|
||||
settingsStrings[i2cdev] = "";
|
||||
@ -247,7 +236,7 @@ void portduinoSetup()
|
||||
// Rather important to set this, if not running simulated.
|
||||
randomSeed(time(NULL));
|
||||
|
||||
gpioChipName += std::to_string(settingsMap[gpiochip]);
|
||||
std::string defaultGpioChipName = gpioChipName + std::to_string(settingsMap[default_gpiochip]);
|
||||
|
||||
for (configNames i : GPIO_lines) {
|
||||
if (settingsMap.count(i) && settingsMap[i] > max_GPIO)
|
||||
@ -257,65 +246,51 @@ void portduinoSetup()
|
||||
gpioInit(max_GPIO + 1); // Done here so we can inform Portduino how many GPIOs we need.
|
||||
|
||||
// Need to bind all the configured GPIO pins so they're not simulated
|
||||
// TODO: Can we do this in the for loop above?
|
||||
// TODO: If one of these fails, we should log and terminate
|
||||
if (settingsMap.count(user) > 0 && settingsMap[user] != RADIOLIB_NC) {
|
||||
if (initGPIOPin(settingsMap[user], gpioChipName) != ERRNO_OK) {
|
||||
if (initGPIOPin(settingsMap[user], defaultGpioChipName, settingsMap[user]) != ERRNO_OK) {
|
||||
settingsMap[user] = RADIOLIB_NC;
|
||||
}
|
||||
}
|
||||
if (settingsMap[displayPanel] != no_screen) {
|
||||
if (settingsMap[displayCS] > 0)
|
||||
initGPIOPin(settingsMap[displayCS], gpioChipName);
|
||||
initGPIOPin(settingsMap[displayCS], defaultGpioChipName, settingsMap[displayCS]);
|
||||
if (settingsMap[displayDC] > 0)
|
||||
initGPIOPin(settingsMap[displayDC], gpioChipName);
|
||||
initGPIOPin(settingsMap[displayDC], defaultGpioChipName, settingsMap[displayDC]);
|
||||
if (settingsMap[displayBacklight] > 0)
|
||||
initGPIOPin(settingsMap[displayBacklight], gpioChipName);
|
||||
initGPIOPin(settingsMap[displayBacklight], defaultGpioChipName, settingsMap[displayBacklight]);
|
||||
if (settingsMap[displayReset] > 0)
|
||||
initGPIOPin(settingsMap[displayReset], gpioChipName);
|
||||
initGPIOPin(settingsMap[displayReset], defaultGpioChipName, settingsMap[displayReset]);
|
||||
}
|
||||
if (settingsMap[touchscreenModule] != no_touchscreen) {
|
||||
if (settingsMap[touchscreenCS] > 0)
|
||||
initGPIOPin(settingsMap[touchscreenCS], gpioChipName);
|
||||
initGPIOPin(settingsMap[touchscreenCS], defaultGpioChipName, settingsMap[touchscreenCS]);
|
||||
if (settingsMap[touchscreenIRQ] > 0)
|
||||
initGPIOPin(settingsMap[touchscreenIRQ], gpioChipName);
|
||||
initGPIOPin(settingsMap[touchscreenIRQ], defaultGpioChipName, settingsMap[touchscreenIRQ]);
|
||||
}
|
||||
|
||||
// Only initialize the radio pins when dealing with real, kernel controlled SPI hardware
|
||||
if (settingsStrings[spidev] != "" && settingsStrings[spidev] != "ch341") {
|
||||
if (settingsMap.count(cs) > 0 && settingsMap[cs] != RADIOLIB_NC) {
|
||||
if (initGPIOPin(settingsMap[cs], gpioChipName) != ERRNO_OK) {
|
||||
settingsMap[cs] = RADIOLIB_NC;
|
||||
}
|
||||
}
|
||||
if (settingsMap.count(irq) > 0 && settingsMap[irq] != RADIOLIB_NC) {
|
||||
if (initGPIOPin(settingsMap[irq], gpioChipName) != ERRNO_OK) {
|
||||
settingsMap[irq] = RADIOLIB_NC;
|
||||
}
|
||||
}
|
||||
if (settingsMap.count(busy) > 0 && settingsMap[busy] != RADIOLIB_NC) {
|
||||
if (initGPIOPin(settingsMap[busy], gpioChipName) != ERRNO_OK) {
|
||||
settingsMap[busy] = RADIOLIB_NC;
|
||||
}
|
||||
}
|
||||
if (settingsMap.count(reset) > 0 && settingsMap[reset] != RADIOLIB_NC) {
|
||||
if (initGPIOPin(settingsMap[reset], gpioChipName) != ERRNO_OK) {
|
||||
settingsMap[reset] = RADIOLIB_NC;
|
||||
}
|
||||
}
|
||||
if (settingsMap.count(sx126x_ant_sw) > 0 && settingsMap[sx126x_ant_sw] != RADIOLIB_NC) {
|
||||
if (initGPIOPin(settingsMap[sx126x_ant_sw], gpioChipName) != ERRNO_OK) {
|
||||
settingsMap[sx126x_ant_sw] = RADIOLIB_NC;
|
||||
}
|
||||
}
|
||||
if (settingsMap.count(rxen) > 0 && settingsMap[rxen] != RADIOLIB_NC) {
|
||||
if (initGPIOPin(settingsMap[rxen], gpioChipName) != ERRNO_OK) {
|
||||
settingsMap[rxen] = RADIOLIB_NC;
|
||||
}
|
||||
}
|
||||
if (settingsMap.count(txen) > 0 && settingsMap[txen] != RADIOLIB_NC) {
|
||||
if (initGPIOPin(settingsMap[txen], gpioChipName) != ERRNO_OK) {
|
||||
settingsMap[txen] = RADIOLIB_NC;
|
||||
const struct {
|
||||
configNames pin;
|
||||
configNames gpiochip;
|
||||
configNames line;
|
||||
} pinMappings[] = {{cs_pin, cs_gpiochip, cs_line},
|
||||
{irq_pin, irq_gpiochip, irq_line},
|
||||
{busy_pin, busy_gpiochip, busy_line},
|
||||
{reset_pin, reset_gpiochip, reset_line},
|
||||
{rxen_pin, rxen_gpiochip, rxen_line},
|
||||
{txen_pin, txen_gpiochip, txen_line},
|
||||
{sx126x_ant_sw_pin, sx126x_ant_sw_gpiochip, sx126x_ant_sw_line}};
|
||||
for (auto &pinMap : pinMappings) {
|
||||
auto setMapIter = settingsMap.find(pinMap.pin);
|
||||
if (setMapIter != settingsMap.end() && setMapIter->second != RADIOLIB_NC) {
|
||||
if (initGPIOPin(setMapIter->second, gpioChipName + std::to_string(settingsMap[pinMap.gpiochip]),
|
||||
settingsMap[pinMap.line]) != ERRNO_OK) {
|
||||
printf("Error setting pin number %d. It may not exist, or may already be in use.\n",
|
||||
settingsMap[pinMap.line]);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
}
|
||||
SPI.begin(settingsStrings[spidev].c_str());
|
||||
@ -332,13 +307,13 @@ void portduinoSetup()
|
||||
return;
|
||||
}
|
||||
|
||||
int initGPIOPin(int pinNum, const std::string gpioChipName)
|
||||
int initGPIOPin(int pinNum, const std::string gpioChipName, int line)
|
||||
{
|
||||
#ifdef PORTDUINO_LINUX_HARDWARE
|
||||
std::string gpio_name = "GPIO" + std::to_string(pinNum);
|
||||
try {
|
||||
GPIOPin *csPin;
|
||||
csPin = new LinuxGPIOPin(pinNum, gpioChipName.c_str(), pinNum, gpio_name.c_str());
|
||||
csPin = new LinuxGPIOPin(pinNum, gpioChipName.c_str(), line, gpio_name.c_str());
|
||||
csPin->setSilent();
|
||||
gpioBind(csPin);
|
||||
return ERRNO_OK;
|
||||
@ -376,42 +351,58 @@ bool loadConfig(const char *configPath)
|
||||
}
|
||||
}
|
||||
if (yamlConfig["Lora"]) {
|
||||
settingsMap[use_sx1262] = false;
|
||||
settingsMap[use_rf95] = false;
|
||||
settingsMap[use_sx1280] = false;
|
||||
settingsMap[use_lr1110] = false;
|
||||
settingsMap[use_lr1120] = false;
|
||||
settingsMap[use_lr1121] = false;
|
||||
settingsMap[use_sx1268] = false;
|
||||
|
||||
if (yamlConfig["Lora"]["Module"] && yamlConfig["Lora"]["Module"].as<std::string>("") == "sx1262") {
|
||||
settingsMap[use_sx1262] = true;
|
||||
} else if (yamlConfig["Lora"]["Module"] && yamlConfig["Lora"]["Module"].as<std::string>("") == "RF95") {
|
||||
settingsMap[use_rf95] = true;
|
||||
} else if (yamlConfig["Lora"]["Module"] && yamlConfig["Lora"]["Module"].as<std::string>("") == "sx1280") {
|
||||
settingsMap[use_sx1280] = true;
|
||||
} else if (yamlConfig["Lora"]["Module"] && yamlConfig["Lora"]["Module"].as<std::string>("") == "lr1110") {
|
||||
settingsMap[use_lr1110] = true;
|
||||
} else if (yamlConfig["Lora"]["Module"] && yamlConfig["Lora"]["Module"].as<std::string>("") == "lr1120") {
|
||||
settingsMap[use_lr1120] = true;
|
||||
} else if (yamlConfig["Lora"]["Module"] && yamlConfig["Lora"]["Module"].as<std::string>("") == "lr1121") {
|
||||
settingsMap[use_lr1121] = true;
|
||||
} else if (yamlConfig["Lora"]["Module"] && yamlConfig["Lora"]["Module"].as<std::string>("") == "sx1268") {
|
||||
settingsMap[use_sx1268] = true;
|
||||
const struct {
|
||||
configNames cfgName;
|
||||
std::string strName;
|
||||
} loraModules[] = {{use_rf95, "RF95"}, {use_sx1262, "sx1262"}, {use_sx1268, "sx1268"}, {use_sx1280, "sx1280"},
|
||||
{use_lr1110, "lr1110"}, {use_lr1120, "lr1120"}, {use_lr1121, "lr1121"}, {use_llcc68, "LLCC68"}};
|
||||
for (auto &loraModule : loraModules) {
|
||||
settingsMap[loraModule.cfgName] = false;
|
||||
}
|
||||
if (yamlConfig["Lora"]["Module"]) {
|
||||
for (auto &loraModule : loraModules) {
|
||||
if (yamlConfig["Lora"]["Module"].as<std::string>("") == loraModule.strName) {
|
||||
settingsMap[loraModule.cfgName] = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
settingsMap[dio2_as_rf_switch] = yamlConfig["Lora"]["DIO2_AS_RF_SWITCH"].as<bool>(false);
|
||||
settingsMap[dio3_tcxo_voltage] = yamlConfig["Lora"]["DIO3_TCXO_VOLTAGE"].as<float>(0) * 1000;
|
||||
if (settingsMap[dio3_tcxo_voltage] == 0 && yamlConfig["Lora"]["DIO3_TCXO_VOLTAGE"].as<bool>(false)) {
|
||||
settingsMap[dio3_tcxo_voltage] = 1800; // default millivolts for "true"
|
||||
}
|
||||
settingsMap[cs] = yamlConfig["Lora"]["CS"].as<int>(RADIOLIB_NC);
|
||||
settingsMap[irq] = yamlConfig["Lora"]["IRQ"].as<int>(RADIOLIB_NC);
|
||||
settingsMap[busy] = yamlConfig["Lora"]["Busy"].as<int>(RADIOLIB_NC);
|
||||
settingsMap[reset] = yamlConfig["Lora"]["Reset"].as<int>(RADIOLIB_NC);
|
||||
settingsMap[txen] = yamlConfig["Lora"]["TXen"].as<int>(RADIOLIB_NC);
|
||||
settingsMap[rxen] = yamlConfig["Lora"]["RXen"].as<int>(RADIOLIB_NC);
|
||||
settingsMap[sx126x_ant_sw] = yamlConfig["Lora"]["SX126X_ANT_SW"].as<int>(RADIOLIB_NC);
|
||||
settingsMap[gpiochip] = yamlConfig["Lora"]["gpiochip"].as<int>(0);
|
||||
|
||||
// backwards API compatibility and to globally set gpiochip once
|
||||
int defaultGpioChip = settingsMap[default_gpiochip] = yamlConfig["Lora"]["gpiochip"].as<int>(0);
|
||||
|
||||
const struct {
|
||||
configNames pin;
|
||||
configNames gpiochip;
|
||||
configNames line;
|
||||
std::string strName;
|
||||
} pinMappings[] = {
|
||||
{cs_pin, cs_gpiochip, cs_line, "CS"},
|
||||
{irq_pin, irq_gpiochip, irq_line, "IRQ"},
|
||||
{busy_pin, busy_gpiochip, busy_line, "Busy"},
|
||||
{reset_pin, reset_gpiochip, reset_line, "Reset"},
|
||||
{txen_pin, txen_gpiochip, txen_line, "TXen"},
|
||||
{rxen_pin, rxen_gpiochip, rxen_line, "RXen"},
|
||||
{sx126x_ant_sw_pin, sx126x_ant_sw_gpiochip, sx126x_ant_sw_line, "SX126X_ANT_SW"},
|
||||
};
|
||||
for (auto &pinMap : pinMappings) {
|
||||
if (yamlConfig["Lora"][pinMap.strName].IsMap()) {
|
||||
settingsMap[pinMap.pin] = yamlConfig["Lora"][pinMap.strName]["pin"].as<int>(RADIOLIB_NC);
|
||||
settingsMap[pinMap.line] = yamlConfig["Lora"][pinMap.strName]["line"].as<int>(settingsMap[pinMap.pin]);
|
||||
settingsMap[pinMap.gpiochip] = yamlConfig["Lora"][pinMap.strName]["gpiochip"].as<int>(defaultGpioChip);
|
||||
} else { // backwards API compatibility
|
||||
settingsMap[pinMap.pin] = yamlConfig["Lora"][pinMap.strName].as<int>(RADIOLIB_NC);
|
||||
settingsMap[pinMap.line] = settingsMap[pinMap.pin];
|
||||
settingsMap[pinMap.gpiochip] = defaultGpioChip;
|
||||
}
|
||||
}
|
||||
|
||||
settingsMap[spiSpeed] = yamlConfig["Lora"]["spiSpeed"].as<int>(2000000);
|
||||
settingsStrings[lora_usb_serial_num] = yamlConfig["Lora"]["USB_Serialnum"].as<std::string>("");
|
||||
settingsMap[lora_usb_pid] = yamlConfig["Lora"]["USB_PID"].as<int>(0x5512);
|
||||
@ -577,4 +568,4 @@ bool MAC_from_string(std::string mac_str, uint8_t *dmac)
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
@ -5,27 +5,42 @@
|
||||
#include "platform/portduino/USBHal.h"
|
||||
|
||||
enum configNames {
|
||||
use_sx1262,
|
||||
cs,
|
||||
irq,
|
||||
busy,
|
||||
reset,
|
||||
sx126x_ant_sw,
|
||||
txen,
|
||||
rxen,
|
||||
default_gpiochip,
|
||||
cs_pin,
|
||||
cs_line,
|
||||
cs_gpiochip,
|
||||
irq_pin,
|
||||
irq_line,
|
||||
irq_gpiochip,
|
||||
busy_pin,
|
||||
busy_line,
|
||||
busy_gpiochip,
|
||||
reset_pin,
|
||||
reset_line,
|
||||
reset_gpiochip,
|
||||
txen_pin,
|
||||
txen_line,
|
||||
txen_gpiochip,
|
||||
rxen_pin,
|
||||
rxen_line,
|
||||
rxen_gpiochip,
|
||||
sx126x_ant_sw_pin,
|
||||
sx126x_ant_sw_line,
|
||||
sx126x_ant_sw_gpiochip,
|
||||
dio2_as_rf_switch,
|
||||
dio3_tcxo_voltage,
|
||||
use_rf95,
|
||||
use_sx1262,
|
||||
use_sx1268,
|
||||
use_sx1280,
|
||||
use_lr1110,
|
||||
use_lr1120,
|
||||
use_lr1121,
|
||||
use_sx1268,
|
||||
use_llcc68,
|
||||
lora_usb_serial_num,
|
||||
lora_usb_pid,
|
||||
lora_usb_vid,
|
||||
user,
|
||||
gpiochip,
|
||||
spidev,
|
||||
spiSpeed,
|
||||
i2cdev,
|
||||
@ -75,7 +90,7 @@ extern std::map<configNames, int> settingsMap;
|
||||
extern std::map<configNames, std::string> settingsStrings;
|
||||
extern std::ofstream traceFile;
|
||||
extern Ch341Hal *ch341Hal;
|
||||
int initGPIOPin(int pinNum, std::string gpioChipname);
|
||||
int initGPIOPin(int pinNum, std::string gpioChipname, int line);
|
||||
bool loadConfig(const char *configPath);
|
||||
static bool ends_with(std::string_view str, std::string_view suffix);
|
||||
void getMacAddr(uint8_t *dmac);
|
||||
|
Loading…
Reference in New Issue
Block a user