mirror of
https://github.com/meshtastic/firmware.git
synced 2025-12-15 15:22:34 +00:00
Compare commits
13 Commits
renovate/n
...
sfpp
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7373fce2e1 | ||
|
|
f10d2fb8c2 | ||
|
|
4552efce81 | ||
|
|
ecdcbe5c09 | ||
|
|
4dd43c7753 | ||
|
|
471da2e632 | ||
|
|
03961161af | ||
|
|
dfe74653f2 | ||
|
|
6b2bd09dd8 | ||
|
|
4fd7960371 | ||
|
|
5f0e86a27e | ||
|
|
9ce1a7ff79 | ||
|
|
bf32f17f28 |
4
.github/actions/build-variant/action.yml
vendored
4
.github/actions/build-variant/action.yml
vendored
@@ -76,7 +76,7 @@ runs:
|
||||
done
|
||||
|
||||
- name: PlatformIO ${{ inputs.arch }} download cache
|
||||
uses: actions/cache@v5
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: ~/.platformio/.cache
|
||||
key: pio-cache-${{ inputs.arch }}-${{ hashFiles('.github/actions/**', '**.ini') }}
|
||||
@@ -100,7 +100,7 @@ runs:
|
||||
id: version
|
||||
|
||||
- name: Store binaries as an artifact
|
||||
uses: actions/upload-artifact@v6
|
||||
uses: actions/upload-artifact@v5
|
||||
with:
|
||||
name: firmware-${{ inputs.arch }}-${{ inputs.board }}-${{ steps.version.outputs.long }}
|
||||
overwrite: true
|
||||
|
||||
2
.github/workflows/build_debian_src.yml
vendored
2
.github/workflows/build_debian_src.yml
vendored
@@ -64,7 +64,7 @@ jobs:
|
||||
PKG_VERSION: ${{ steps.version.outputs.deb }}
|
||||
|
||||
- name: Store binaries as an artifact
|
||||
uses: actions/upload-artifact@v6
|
||||
uses: actions/upload-artifact@v5
|
||||
with:
|
||||
name: firmware-debian-${{ steps.version.outputs.deb }}~${{ inputs.series }}-src
|
||||
overwrite: true
|
||||
|
||||
10
.github/workflows/build_firmware.yml
vendored
10
.github/workflows/build_firmware.yml
vendored
@@ -56,19 +56,21 @@ jobs:
|
||||
ota_firmware_source: ${{ steps.ota_dir.outputs.src || '' }}
|
||||
ota_firmware_target: ${{ steps.ota_dir.outputs.tgt || '' }}
|
||||
|
||||
- name: Echo manifest from release/firmware-*.mt.json to job summary
|
||||
if: ${{ always() }}
|
||||
- name: Job summary
|
||||
env:
|
||||
PIO_ENV: ${{ inputs.pio_env }}
|
||||
run: |
|
||||
echo "## Manifest: \`$PIO_ENV\`" >> $GITHUB_STEP_SUMMARY
|
||||
echo "## $PIO_ENV" >> $GITHUB_STEP_SUMMARY
|
||||
echo "<details><summary><strong>Manifest</strong></summary>" >> $GITHUB_STEP_SUMMARY
|
||||
echo '' >> $GITHUB_STEP_SUMMARY
|
||||
echo '```json' >> $GITHUB_STEP_SUMMARY
|
||||
cat release/firmware-*.mt.json >> $GITHUB_STEP_SUMMARY
|
||||
echo '' >> $GITHUB_STEP_SUMMARY
|
||||
echo '```' >> $GITHUB_STEP_SUMMARY
|
||||
echo "</details>" >> $GITHUB_STEP_SUMMARY
|
||||
|
||||
- name: Store binaries as an artifact
|
||||
uses: actions/upload-artifact@v6
|
||||
uses: actions/upload-artifact@v5
|
||||
id: upload
|
||||
with:
|
||||
name: firmware-${{ inputs.platform }}-${{ inputs.pio_env }}-${{ inputs.version }}
|
||||
|
||||
8
.github/workflows/build_one_target.yml
vendored
8
.github/workflows/build_one_target.yml
vendored
@@ -98,7 +98,7 @@ jobs:
|
||||
ref: ${{github.event.pull_request.head.ref}}
|
||||
repository: ${{github.event.pull_request.head.repo.full_name}}
|
||||
|
||||
- uses: actions/download-artifact@v7
|
||||
- uses: actions/download-artifact@v6
|
||||
with:
|
||||
path: ./
|
||||
pattern: firmware-*-*
|
||||
@@ -111,7 +111,7 @@ jobs:
|
||||
run: mv -b -t ./ ./bin/device-*.sh ./bin/device-*.bat
|
||||
|
||||
- name: Repackage in single firmware zip
|
||||
uses: actions/upload-artifact@v6
|
||||
uses: actions/upload-artifact@v5
|
||||
with:
|
||||
name: firmware-${{inputs.target}}-${{ needs.version.outputs.long }}
|
||||
overwrite: true
|
||||
@@ -127,7 +127,7 @@ jobs:
|
||||
./Meshtastic_nRF52_factory_erase*.uf2
|
||||
retention-days: 30
|
||||
|
||||
- uses: actions/download-artifact@v7
|
||||
- uses: actions/download-artifact@v6
|
||||
with:
|
||||
pattern: firmware-*-${{ needs.version.outputs.long }}
|
||||
merge-multiple: true
|
||||
@@ -146,7 +146,7 @@ jobs:
|
||||
run: zip -j -9 -r ./firmware-${{inputs.target}}-${{ needs.version.outputs.long }}.zip ./output
|
||||
|
||||
- name: Repackage in single elfs zip
|
||||
uses: actions/upload-artifact@v6
|
||||
uses: actions/upload-artifact@v5
|
||||
with:
|
||||
name: debug-elfs-${{inputs.target}}-${{ needs.version.outputs.long }}.zip
|
||||
overwrite: true
|
||||
|
||||
22
.github/workflows/main_matrix.yml
vendored
22
.github/workflows/main_matrix.yml
vendored
@@ -173,7 +173,7 @@ jobs:
|
||||
ref: ${{github.event.pull_request.head.ref}}
|
||||
repository: ${{github.event.pull_request.head.repo.full_name}}
|
||||
|
||||
- uses: actions/download-artifact@v7
|
||||
- uses: actions/download-artifact@v6
|
||||
with:
|
||||
path: ./
|
||||
pattern: firmware-${{matrix.arch}}-*
|
||||
@@ -183,7 +183,7 @@ jobs:
|
||||
run: ls -R
|
||||
|
||||
- name: Repackage in single firmware zip
|
||||
uses: actions/upload-artifact@v6
|
||||
uses: actions/upload-artifact@v5
|
||||
with:
|
||||
name: firmware-${{matrix.arch}}-${{ needs.version.outputs.long }}
|
||||
overwrite: true
|
||||
@@ -200,7 +200,7 @@ jobs:
|
||||
./Meshtastic_nRF52_factory_erase*.uf2
|
||||
retention-days: 30
|
||||
|
||||
- uses: actions/download-artifact@v7
|
||||
- uses: actions/download-artifact@v6
|
||||
with:
|
||||
name: firmware-${{matrix.arch}}-${{ needs.version.outputs.long }}
|
||||
merge-multiple: true
|
||||
@@ -219,7 +219,7 @@ jobs:
|
||||
run: zip -j -9 -r ./firmware-${{matrix.arch}}-${{ needs.version.outputs.long }}.zip ./output
|
||||
|
||||
- name: Repackage in single elfs zip
|
||||
uses: actions/upload-artifact@v6
|
||||
uses: actions/upload-artifact@v5
|
||||
with:
|
||||
name: debug-elfs-${{matrix.arch}}-${{ needs.version.outputs.long }}
|
||||
overwrite: true
|
||||
@@ -260,14 +260,14 @@ jobs:
|
||||
Autogenerated by github action, developer should edit as required before publishing...
|
||||
|
||||
- name: Download source deb
|
||||
uses: actions/download-artifact@v7
|
||||
uses: actions/download-artifact@v6
|
||||
with:
|
||||
pattern: firmware-debian-${{ needs.version.outputs.deb }}~UNRELEASED-src
|
||||
merge-multiple: true
|
||||
path: ./output/debian-src
|
||||
|
||||
- name: Download `native-tft` pio deps
|
||||
uses: actions/download-artifact@v7
|
||||
uses: actions/download-artifact@v6
|
||||
with:
|
||||
pattern: platformio-deps-native-tft-${{ needs.version.outputs.long }}
|
||||
merge-multiple: true
|
||||
@@ -291,7 +291,7 @@ jobs:
|
||||
}' > firmware-${{ needs.version.outputs.long }}.json
|
||||
|
||||
- name: Save Release manifest artifact
|
||||
uses: actions/upload-artifact@v6
|
||||
uses: actions/upload-artifact@v5
|
||||
with:
|
||||
name: manifest-${{ needs.version.outputs.long }}
|
||||
overwrite: true
|
||||
@@ -332,7 +332,7 @@ jobs:
|
||||
with:
|
||||
python-version: 3.x
|
||||
|
||||
- uses: actions/download-artifact@v7
|
||||
- uses: actions/download-artifact@v6
|
||||
with:
|
||||
pattern: firmware-${{matrix.arch}}-${{ needs.version.outputs.long }}
|
||||
merge-multiple: true
|
||||
@@ -349,7 +349,7 @@ jobs:
|
||||
- name: Zip firmware
|
||||
run: zip -j -9 -r ./firmware-${{matrix.arch}}-${{ needs.version.outputs.long }}.zip ./output
|
||||
|
||||
- uses: actions/download-artifact@v7
|
||||
- uses: actions/download-artifact@v6
|
||||
with:
|
||||
name: debug-elfs-${{matrix.arch}}-${{ needs.version.outputs.long }}
|
||||
merge-multiple: true
|
||||
@@ -388,14 +388,14 @@ jobs:
|
||||
python-version: 3.x
|
||||
|
||||
- name: Get firmware artifacts
|
||||
uses: actions/download-artifact@v7
|
||||
uses: actions/download-artifact@v6
|
||||
with:
|
||||
pattern: firmware-{${{ env.targets }}}-${{ needs.version.outputs.long }}
|
||||
merge-multiple: true
|
||||
path: ./publish
|
||||
|
||||
- name: Get manifest artifact
|
||||
uses: actions/download-artifact@v7
|
||||
uses: actions/download-artifact@v6
|
||||
with:
|
||||
pattern: manifest-${{ needs.version.outputs.long }}
|
||||
path: ./publish
|
||||
|
||||
18
.github/workflows/merge_queue.yml
vendored
18
.github/workflows/merge_queue.yml
vendored
@@ -147,7 +147,7 @@ jobs:
|
||||
ref: ${{github.event.pull_request.head.ref}}
|
||||
repository: ${{github.event.pull_request.head.repo.full_name}}
|
||||
|
||||
- uses: actions/download-artifact@v7
|
||||
- uses: actions/download-artifact@v6
|
||||
with:
|
||||
path: ./
|
||||
pattern: firmware-${{matrix.arch}}-*
|
||||
@@ -160,7 +160,7 @@ jobs:
|
||||
run: mv -b -t ./ ./bin/device-*.sh ./bin/device-*.bat
|
||||
|
||||
- name: Repackage in single firmware zip
|
||||
uses: actions/upload-artifact@v6
|
||||
uses: actions/upload-artifact@v5
|
||||
with:
|
||||
name: firmware-${{matrix.arch}}-${{ needs.version.outputs.long }}
|
||||
overwrite: true
|
||||
@@ -176,7 +176,7 @@ jobs:
|
||||
./Meshtastic_nRF52_factory_erase*.uf2
|
||||
retention-days: 30
|
||||
|
||||
- uses: actions/download-artifact@v7
|
||||
- uses: actions/download-artifact@v6
|
||||
with:
|
||||
name: firmware-${{matrix.arch}}-${{ needs.version.outputs.long }}
|
||||
merge-multiple: true
|
||||
@@ -195,7 +195,7 @@ jobs:
|
||||
run: zip -j -9 -r ./firmware-${{matrix.arch}}-${{ needs.version.outputs.long }}.zip ./output
|
||||
|
||||
- name: Repackage in single elfs zip
|
||||
uses: actions/upload-artifact@v6
|
||||
uses: actions/upload-artifact@v5
|
||||
with:
|
||||
name: debug-elfs-${{matrix.arch}}-${{ needs.version.outputs.long }}
|
||||
overwrite: true
|
||||
@@ -235,14 +235,14 @@ jobs:
|
||||
Autogenerated by github action, developer should edit as required before publishing...
|
||||
|
||||
- name: Download source deb
|
||||
uses: actions/download-artifact@v7
|
||||
uses: actions/download-artifact@v6
|
||||
with:
|
||||
pattern: firmware-debian-${{ needs.version.outputs.deb }}~UNRELEASED-src
|
||||
merge-multiple: true
|
||||
path: ./output/debian-src
|
||||
|
||||
- name: Download `native-tft` pio deps
|
||||
uses: actions/download-artifact@v7
|
||||
uses: actions/download-artifact@v6
|
||||
with:
|
||||
pattern: platformio-deps-native-tft-${{ needs.version.outputs.long }}
|
||||
merge-multiple: true
|
||||
@@ -292,7 +292,7 @@ jobs:
|
||||
with:
|
||||
python-version: 3.x
|
||||
|
||||
- uses: actions/download-artifact@v7
|
||||
- uses: actions/download-artifact@v6
|
||||
with:
|
||||
pattern: firmware-${{matrix.arch}}-${{ needs.version.outputs.long }}
|
||||
merge-multiple: true
|
||||
@@ -309,7 +309,7 @@ jobs:
|
||||
- name: Zip firmware
|
||||
run: zip -j -9 -r ./firmware-${{matrix.arch}}-${{ needs.version.outputs.long }}.zip ./output
|
||||
|
||||
- uses: actions/download-artifact@v7
|
||||
- uses: actions/download-artifact@v6
|
||||
with:
|
||||
name: debug-elfs-${{matrix.arch}}-${{ needs.version.outputs.long }}
|
||||
merge-multiple: true
|
||||
@@ -347,7 +347,7 @@ jobs:
|
||||
with:
|
||||
python-version: 3.x
|
||||
|
||||
- uses: actions/download-artifact@v7
|
||||
- uses: actions/download-artifact@v6
|
||||
with:
|
||||
pattern: firmware-{${{ env.targets }}}-${{ needs.version.outputs.long }}
|
||||
merge-multiple: true
|
||||
|
||||
2
.github/workflows/package_obs.yml
vendored
2
.github/workflows/package_obs.yml
vendored
@@ -58,7 +58,7 @@ jobs:
|
||||
id: version
|
||||
|
||||
- name: Download artifacts
|
||||
uses: actions/download-artifact@v7
|
||||
uses: actions/download-artifact@v6
|
||||
with:
|
||||
name: firmware-debian-${{ steps.version.outputs.deb }}~${{ inputs.series }}-src
|
||||
merge-multiple: true
|
||||
|
||||
2
.github/workflows/package_pio_deps.yml
vendored
2
.github/workflows/package_pio_deps.yml
vendored
@@ -56,7 +56,7 @@ jobs:
|
||||
PLATFORMIO_CORE_DIR: pio/core
|
||||
|
||||
- name: Store binaries as an artifact
|
||||
uses: actions/upload-artifact@v6
|
||||
uses: actions/upload-artifact@v5
|
||||
with:
|
||||
name: platformio-deps-${{ inputs.pio_env }}-${{ steps.version.outputs.long }}
|
||||
overwrite: true
|
||||
|
||||
2
.github/workflows/package_ppa.yml
vendored
2
.github/workflows/package_ppa.yml
vendored
@@ -60,7 +60,7 @@ jobs:
|
||||
id: version
|
||||
|
||||
- name: Download artifacts
|
||||
uses: actions/download-artifact@v7
|
||||
uses: actions/download-artifact@v6
|
||||
with:
|
||||
name: firmware-debian-${{ steps.version.outputs.deb }}~${{ inputs.series }}-src
|
||||
merge-multiple: true
|
||||
|
||||
2
.github/workflows/pr_tests.yml
vendored
2
.github/workflows/pr_tests.yml
vendored
@@ -50,7 +50,7 @@ jobs:
|
||||
|
||||
- name: Download test artifacts
|
||||
if: needs.native-tests.result != 'skipped'
|
||||
uses: actions/download-artifact@v7
|
||||
uses: actions/download-artifact@v6
|
||||
with:
|
||||
name: platformio-test-report-${{ steps.version.outputs.long }}
|
||||
merge-multiple: true
|
||||
|
||||
2
.github/workflows/sec_sast_semgrep_cron.yml
vendored
2
.github/workflows/sec_sast_semgrep_cron.yml
vendored
@@ -33,7 +33,7 @@ jobs:
|
||||
|
||||
# step 3
|
||||
- name: save report as pipeline artifact
|
||||
uses: actions/upload-artifact@v6
|
||||
uses: actions/upload-artifact@v5
|
||||
with:
|
||||
name: report.sarif
|
||||
overwrite: true
|
||||
|
||||
12
.github/workflows/test_native.yml
vendored
12
.github/workflows/test_native.yml
vendored
@@ -59,7 +59,7 @@ jobs:
|
||||
id: version
|
||||
|
||||
- name: Save coverage information
|
||||
uses: actions/upload-artifact@v6
|
||||
uses: actions/upload-artifact@v5
|
||||
if: always() # run this step even if previous step failed
|
||||
with:
|
||||
name: lcov-coverage-info-native-simulator-test-${{ steps.version.outputs.long }}
|
||||
@@ -94,7 +94,7 @@ jobs:
|
||||
|
||||
- name: Save test results
|
||||
if: always() # run this step even if previous step failed
|
||||
uses: actions/upload-artifact@v6
|
||||
uses: actions/upload-artifact@v5
|
||||
with:
|
||||
name: platformio-test-report-${{ steps.version.outputs.long }}
|
||||
overwrite: true
|
||||
@@ -108,7 +108,7 @@ jobs:
|
||||
sed -i -e "s#${PWD}#.#" coverage_tests.info # Make paths relative.
|
||||
|
||||
- name: Save coverage information
|
||||
uses: actions/upload-artifact@v6
|
||||
uses: actions/upload-artifact@v5
|
||||
if: always() # run this step even if previous step failed
|
||||
with:
|
||||
name: lcov-coverage-info-native-platformio-tests-${{ steps.version.outputs.long }}
|
||||
@@ -137,7 +137,7 @@ jobs:
|
||||
id: version
|
||||
|
||||
- name: Download test artifacts
|
||||
uses: actions/download-artifact@v7
|
||||
uses: actions/download-artifact@v6
|
||||
with:
|
||||
name: platformio-test-report-${{ steps.version.outputs.long }}
|
||||
merge-multiple: true
|
||||
@@ -150,7 +150,7 @@ jobs:
|
||||
reporter: java-junit
|
||||
|
||||
- name: Download coverage artifacts
|
||||
uses: actions/download-artifact@v7
|
||||
uses: actions/download-artifact@v6
|
||||
with:
|
||||
pattern: lcov-coverage-info-native-*-${{ steps.version.outputs.long }}
|
||||
path: code-coverage-report
|
||||
@@ -163,7 +163,7 @@ jobs:
|
||||
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@v6
|
||||
uses: actions/upload-artifact@v5
|
||||
with:
|
||||
name: code-coverage-report-${{ steps.version.outputs.long }}
|
||||
path: code-coverage-report
|
||||
|
||||
@@ -9,16 +9,16 @@ plugins:
|
||||
lint:
|
||||
enabled:
|
||||
- checkov@3.2.495
|
||||
- renovate@42.52.8
|
||||
- renovate@42.42.2
|
||||
- prettier@3.7.4
|
||||
- trufflehog@3.92.3
|
||||
- trufflehog@3.92.1
|
||||
- yamllint@1.37.1
|
||||
- bandit@1.9.2
|
||||
- trivy@0.68.1
|
||||
- taplo@0.10.0
|
||||
- ruff@0.14.9
|
||||
- ruff@0.14.8
|
||||
- isort@7.0.0
|
||||
- markdownlint@0.47.0
|
||||
- markdownlint@0.46.0
|
||||
- oxipng@10.0.0
|
||||
- svgo@4.0.0
|
||||
- actionlint@1.7.9
|
||||
|
||||
@@ -184,8 +184,6 @@ Input:
|
||||
Logging:
|
||||
LogLevel: info # debug, info, warn, error
|
||||
# TraceFile: /var/log/meshtasticd.json
|
||||
# JSONFile: /packets.json # File location for JSON output of decoded packets
|
||||
# JSONFilter: position # filter for packets to save to JSON file
|
||||
# AsciiLogs: true # default if not specified is !isatty() on stdout
|
||||
|
||||
Webserver:
|
||||
|
||||
@@ -123,7 +123,7 @@ lib_deps =
|
||||
[device-ui_base]
|
||||
lib_deps =
|
||||
# renovate: datasource=git-refs depName=meshtastic/device-ui packageName=https://github.com/meshtastic/device-ui gitBranch=master
|
||||
https://github.com/meshtastic/device-ui/archive/2746a1ce3804998460a2cb319b8ea8a238dfd8c9.zip
|
||||
https://github.com/meshtastic/device-ui/archive/4fb5f24787caa841b58dbf623a52c4c5861d6722.zip
|
||||
|
||||
; Common libs for environmental measurements in telemetry module
|
||||
[environmental_base]
|
||||
|
||||
@@ -53,7 +53,6 @@ typedef struct _InputEvent {
|
||||
class InputPollable
|
||||
{
|
||||
public:
|
||||
virtual ~InputPollable() = default;
|
||||
virtual void pollOnce() = 0;
|
||||
};
|
||||
|
||||
|
||||
@@ -3,9 +3,6 @@
|
||||
#include "RotaryEncoderImpl.h"
|
||||
#include "InputBroker.h"
|
||||
#include "RotaryEncoder.h"
|
||||
#ifdef ARCH_ESP32
|
||||
#include "sleep.h"
|
||||
#endif
|
||||
|
||||
#define ORIGIN_NAME "RotaryEncoder"
|
||||
|
||||
@@ -14,20 +11,6 @@ RotaryEncoderImpl *rotaryEncoderImpl;
|
||||
RotaryEncoderImpl::RotaryEncoderImpl()
|
||||
{
|
||||
rotary = nullptr;
|
||||
#ifdef ARCH_ESP32
|
||||
isFirstInit = true;
|
||||
#endif
|
||||
}
|
||||
|
||||
RotaryEncoderImpl::~RotaryEncoderImpl()
|
||||
{
|
||||
LOG_DEBUG("RotaryEncoderImpl destructor");
|
||||
detachRotaryEncoderInterrupts();
|
||||
|
||||
if (rotary != nullptr) {
|
||||
delete rotary;
|
||||
rotary = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
bool RotaryEncoderImpl::init()
|
||||
@@ -42,22 +25,15 @@ bool RotaryEncoderImpl::init()
|
||||
eventCcw = static_cast<input_broker_event>(moduleConfig.canned_message.inputbroker_event_ccw);
|
||||
eventPressed = static_cast<input_broker_event>(moduleConfig.canned_message.inputbroker_event_press);
|
||||
|
||||
if (rotary == nullptr) {
|
||||
rotary = new RotaryEncoder(moduleConfig.canned_message.inputbroker_pin_a, moduleConfig.canned_message.inputbroker_pin_b,
|
||||
moduleConfig.canned_message.inputbroker_pin_press);
|
||||
}
|
||||
rotary = new RotaryEncoder(moduleConfig.canned_message.inputbroker_pin_a, moduleConfig.canned_message.inputbroker_pin_b,
|
||||
moduleConfig.canned_message.inputbroker_pin_press);
|
||||
rotary->resetButton();
|
||||
|
||||
attachRotaryEncoderInterrupts();
|
||||
|
||||
#ifdef ARCH_ESP32
|
||||
// Register callbacks for before and after lightsleep
|
||||
// Used to detach and reattach interrupts
|
||||
if (isFirstInit) {
|
||||
lsObserver.observe(¬ifyLightSleep);
|
||||
lsEndObserver.observe(¬ifyLightSleepEnd);
|
||||
isFirstInit = false;
|
||||
}
|
||||
#endif
|
||||
interruptInstance = this;
|
||||
auto interruptHandler = []() { inputBroker->requestPollSoon(interruptInstance); };
|
||||
attachInterrupt(moduleConfig.canned_message.inputbroker_pin_a, interruptHandler, CHANGE);
|
||||
attachInterrupt(moduleConfig.canned_message.inputbroker_pin_b, interruptHandler, CHANGE);
|
||||
attachInterrupt(moduleConfig.canned_message.inputbroker_pin_press, interruptHandler, CHANGE);
|
||||
|
||||
LOG_INFO("RotaryEncoder initialized pins(%d, %d, %d), events(%d, %d, %d)", moduleConfig.canned_message.inputbroker_pin_a,
|
||||
moduleConfig.canned_message.inputbroker_pin_b, moduleConfig.canned_message.inputbroker_pin_press, eventCw, eventCcw,
|
||||
@@ -95,50 +71,6 @@ void RotaryEncoderImpl::pollOnce()
|
||||
}
|
||||
}
|
||||
|
||||
void RotaryEncoderImpl::detachRotaryEncoderInterrupts()
|
||||
{
|
||||
LOG_DEBUG("RotaryEncoderImpl detach button interrupts");
|
||||
if (interruptInstance == this) {
|
||||
detachInterrupt(moduleConfig.canned_message.inputbroker_pin_a);
|
||||
detachInterrupt(moduleConfig.canned_message.inputbroker_pin_b);
|
||||
detachInterrupt(moduleConfig.canned_message.inputbroker_pin_press);
|
||||
interruptInstance = nullptr;
|
||||
} else {
|
||||
LOG_WARN("RotaryEncoderImpl: interrupts already detached");
|
||||
}
|
||||
}
|
||||
|
||||
void RotaryEncoderImpl::attachRotaryEncoderInterrupts()
|
||||
{
|
||||
LOG_DEBUG("RotaryEncoderImpl attach button interrupts");
|
||||
if (rotary != nullptr && interruptInstance == nullptr) {
|
||||
rotary->resetButton();
|
||||
|
||||
interruptInstance = this;
|
||||
auto interruptHandler = []() { inputBroker->requestPollSoon(interruptInstance); };
|
||||
attachInterrupt(moduleConfig.canned_message.inputbroker_pin_a, interruptHandler, CHANGE);
|
||||
attachInterrupt(moduleConfig.canned_message.inputbroker_pin_b, interruptHandler, CHANGE);
|
||||
attachInterrupt(moduleConfig.canned_message.inputbroker_pin_press, interruptHandler, CHANGE);
|
||||
} else {
|
||||
LOG_WARN("RotaryEncoderImpl: interrupts already attached");
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef ARCH_ESP32
|
||||
|
||||
int RotaryEncoderImpl::beforeLightSleep(void *unused)
|
||||
{
|
||||
detachRotaryEncoderInterrupts();
|
||||
return 0; // Indicates success;
|
||||
}
|
||||
|
||||
int RotaryEncoderImpl::afterLightSleep(esp_sleep_wakeup_cause_t cause)
|
||||
{
|
||||
attachRotaryEncoderInterrupts();
|
||||
return 0; // Indicates success;
|
||||
}
|
||||
#endif
|
||||
|
||||
RotaryEncoderImpl *RotaryEncoderImpl::interruptInstance;
|
||||
|
||||
#endif
|
||||
@@ -8,18 +8,12 @@
|
||||
|
||||
class RotaryEncoder;
|
||||
|
||||
class RotaryEncoderImpl final : public InputPollable
|
||||
class RotaryEncoderImpl : public InputPollable
|
||||
{
|
||||
public:
|
||||
RotaryEncoderImpl();
|
||||
~RotaryEncoderImpl() override;
|
||||
bool init();
|
||||
bool init(void);
|
||||
virtual void pollOnce() override;
|
||||
// Disconnect and reconnect interrupts for light sleep
|
||||
#ifdef ARCH_ESP32
|
||||
int beforeLightSleep(void *unused);
|
||||
int afterLightSleep(esp_sleep_wakeup_cause_t cause);
|
||||
#endif
|
||||
|
||||
protected:
|
||||
static RotaryEncoderImpl *interruptInstance;
|
||||
@@ -29,21 +23,6 @@ class RotaryEncoderImpl final : public InputPollable
|
||||
input_broker_event eventPressed = INPUT_BROKER_NONE;
|
||||
|
||||
RotaryEncoder *rotary;
|
||||
|
||||
private:
|
||||
#ifdef ARCH_ESP32
|
||||
bool isFirstInit;
|
||||
#endif
|
||||
void detachRotaryEncoderInterrupts();
|
||||
void attachRotaryEncoderInterrupts();
|
||||
|
||||
#ifdef ARCH_ESP32
|
||||
// Get notified when lightsleep begins and ends
|
||||
CallbackObserver<RotaryEncoderImpl, void *> lsObserver =
|
||||
CallbackObserver<RotaryEncoderImpl, void *>(this, &RotaryEncoderImpl::beforeLightSleep);
|
||||
CallbackObserver<RotaryEncoderImpl, esp_sleep_wakeup_cause_t> lsEndObserver =
|
||||
CallbackObserver<RotaryEncoderImpl, esp_sleep_wakeup_cause_t>(this, &RotaryEncoderImpl::afterLightSleep);
|
||||
#endif
|
||||
};
|
||||
|
||||
extern RotaryEncoderImpl *rotaryEncoderImpl;
|
||||
|
||||
@@ -428,10 +428,17 @@ void setup()
|
||||
#endif
|
||||
|
||||
#if ARCH_PORTDUINO
|
||||
RTCQuality ourQuality = RTCQualityDevice;
|
||||
|
||||
std::string timeCommandResult = exec("timedatectl status | grep synchronized | grep yes -c");
|
||||
if (timeCommandResult[0] == '1') {
|
||||
ourQuality = RTCQualityNTP;
|
||||
}
|
||||
|
||||
struct timeval tv;
|
||||
tv.tv_sec = time(NULL);
|
||||
tv.tv_usec = 0;
|
||||
perhapsSetRTC(RTCQualityDevice, &tv);
|
||||
perhapsSetRTC(ourQuality, &tv);
|
||||
#endif
|
||||
|
||||
powerMonInit();
|
||||
|
||||
@@ -96,6 +96,8 @@ class Channels
|
||||
|
||||
bool setDefaultPresetCryptoForHash(ChannelHash channelHash);
|
||||
|
||||
int16_t getHash(ChannelIndex i) { return hashes[i]; }
|
||||
|
||||
private:
|
||||
/** Given a channel index, change to use the crypto key specified by that index
|
||||
*
|
||||
@@ -113,8 +115,6 @@ class Channels
|
||||
*/
|
||||
int16_t generateHash(ChannelIndex channelNum);
|
||||
|
||||
int16_t getHash(ChannelIndex i) { return hashes[i]; }
|
||||
|
||||
/**
|
||||
* Validate a channel, fixing any errors as needed
|
||||
*/
|
||||
|
||||
@@ -526,10 +526,6 @@ DecodeState perhapsDecode(meshtastic_MeshPacket *p)
|
||||
#elif ARCH_PORTDUINO
|
||||
if (portduino_config.traceFilename != "" || portduino_config.logoutputlevel == level_trace) {
|
||||
LOG_TRACE("%s", MeshPacketSerializer::JsonSerialize(p, false).c_str());
|
||||
} else if (portduino_config.JSONFilename != "") {
|
||||
if (portduino_config.JSONFilter == (_meshtastic_PortNum)0 || portduino_config.JSONFilter == p->decoded.portnum) {
|
||||
JSONFile << MeshPacketSerializer::JsonSerialize(p, false) << std::endl;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
return DecodeState::DECODE_SUCCESS;
|
||||
@@ -692,7 +688,7 @@ void Router::handleReceived(meshtastic_MeshPacket *p, RxSource src)
|
||||
|
||||
// Store a copy of encrypted packet for MQTT
|
||||
DEBUG_HEAP_BEFORE;
|
||||
meshtastic_MeshPacket *p_encrypted = packetPool.allocCopy(*p);
|
||||
p_encrypted = packetPool.allocCopy(*p);
|
||||
DEBUG_HEAP_AFTER("Router::handleReceived", p_encrypted);
|
||||
|
||||
// Take those raw bytes and convert them back into a well structured protobuf we can understand
|
||||
|
||||
@@ -91,6 +91,9 @@ class Router : protected concurrency::OSThread, protected PacketHistory
|
||||
before us */
|
||||
uint32_t rxDupe = 0, txRelayCanceled = 0;
|
||||
|
||||
// pointer to the encrypted packet
|
||||
meshtastic_MeshPacket *p_encrypted;
|
||||
|
||||
protected:
|
||||
friend class RoutingModule;
|
||||
|
||||
|
||||
@@ -24,6 +24,9 @@ PB_BIND(meshtastic_Data, meshtastic_Data, 2)
|
||||
PB_BIND(meshtastic_KeyVerification, meshtastic_KeyVerification, AUTO)
|
||||
|
||||
|
||||
PB_BIND(meshtastic_StoreForwardPlusPlus, meshtastic_StoreForwardPlusPlus, 2)
|
||||
|
||||
|
||||
PB_BIND(meshtastic_Waypoint, meshtastic_Waypoint, AUTO)
|
||||
|
||||
|
||||
@@ -121,6 +124,8 @@ PB_BIND(meshtastic_ChunkedPayloadResponse, meshtastic_ChunkedPayloadResponse, AU
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -478,6 +478,17 @@ typedef enum _meshtastic_Routing_Error {
|
||||
meshtastic_Routing_Error_RATE_LIMIT_EXCEEDED = 38
|
||||
} meshtastic_Routing_Error;
|
||||
|
||||
/* enum message type? */
|
||||
typedef enum _meshtastic_StoreForwardPlusPlus_SFPP_message_type {
|
||||
/* message hash without chain hash means that no, it is not on the chain */
|
||||
meshtastic_StoreForwardPlusPlus_SFPP_message_type_CANON_ANNOUNCE = 0,
|
||||
meshtastic_StoreForwardPlusPlus_SFPP_message_type_CHAIN_QUERY = 1,
|
||||
meshtastic_StoreForwardPlusPlus_SFPP_message_type_LINK_REQUEST = 3,
|
||||
meshtastic_StoreForwardPlusPlus_SFPP_message_type_LINK_PROVIDE = 4,
|
||||
meshtastic_StoreForwardPlusPlus_SFPP_message_type_LINK_PROVIDE_FIRSTHALF = 5,
|
||||
meshtastic_StoreForwardPlusPlus_SFPP_message_type_LINK_PROVIDE_SECONDHALF = 6
|
||||
} meshtastic_StoreForwardPlusPlus_SFPP_message_type;
|
||||
|
||||
/* The priority of this message for sending.
|
||||
Higher priorities are sent first (when managing the transmit queue).
|
||||
This field is never sent over the air, it is only used internally inside of a local device node.
|
||||
@@ -782,6 +793,24 @@ typedef struct _meshtastic_KeyVerification {
|
||||
meshtastic_KeyVerification_hash2_t hash2;
|
||||
} meshtastic_KeyVerification;
|
||||
|
||||
typedef PB_BYTES_ARRAY_T(32) meshtastic_StoreForwardPlusPlus_message_hash_t;
|
||||
typedef PB_BYTES_ARRAY_T(32) meshtastic_StoreForwardPlusPlus_chain_hash_t;
|
||||
typedef PB_BYTES_ARRAY_T(32) meshtastic_StoreForwardPlusPlus_root_hash_t;
|
||||
typedef PB_BYTES_ARRAY_T(240) meshtastic_StoreForwardPlusPlus_message_t;
|
||||
/* The actual over-the-mesh message doing store and forward++ */
|
||||
typedef struct _meshtastic_StoreForwardPlusPlus { /* */
|
||||
meshtastic_StoreForwardPlusPlus_SFPP_message_type sfpp_message_type;
|
||||
meshtastic_StoreForwardPlusPlus_message_hash_t message_hash;
|
||||
meshtastic_StoreForwardPlusPlus_chain_hash_t chain_hash;
|
||||
meshtastic_StoreForwardPlusPlus_root_hash_t root_hash;
|
||||
/* encapsulated message to share (may be split in half) */
|
||||
meshtastic_StoreForwardPlusPlus_message_t message;
|
||||
uint32_t encapsulated_id;
|
||||
uint32_t encapsulated_to;
|
||||
uint32_t encapsulated_from;
|
||||
uint32_t encapsulated_rxtime;
|
||||
} meshtastic_StoreForwardPlusPlus;
|
||||
|
||||
/* Waypoint message, used to share arbitrary locations across the mesh */
|
||||
typedef struct _meshtastic_Waypoint {
|
||||
/* Id of the waypoint */
|
||||
@@ -1310,6 +1339,10 @@ extern "C" {
|
||||
#define _meshtastic_Routing_Error_MAX meshtastic_Routing_Error_RATE_LIMIT_EXCEEDED
|
||||
#define _meshtastic_Routing_Error_ARRAYSIZE ((meshtastic_Routing_Error)(meshtastic_Routing_Error_RATE_LIMIT_EXCEEDED+1))
|
||||
|
||||
#define _meshtastic_StoreForwardPlusPlus_SFPP_message_type_MIN meshtastic_StoreForwardPlusPlus_SFPP_message_type_CANON_ANNOUNCE
|
||||
#define _meshtastic_StoreForwardPlusPlus_SFPP_message_type_MAX meshtastic_StoreForwardPlusPlus_SFPP_message_type_LINK_PROVIDE_SECONDHALF
|
||||
#define _meshtastic_StoreForwardPlusPlus_SFPP_message_type_ARRAYSIZE ((meshtastic_StoreForwardPlusPlus_SFPP_message_type)(meshtastic_StoreForwardPlusPlus_SFPP_message_type_LINK_PROVIDE_SECONDHALF+1))
|
||||
|
||||
#define _meshtastic_MeshPacket_Priority_MIN meshtastic_MeshPacket_Priority_UNSET
|
||||
#define _meshtastic_MeshPacket_Priority_MAX meshtastic_MeshPacket_Priority_MAX
|
||||
#define _meshtastic_MeshPacket_Priority_ARRAYSIZE ((meshtastic_MeshPacket_Priority)(meshtastic_MeshPacket_Priority_MAX+1))
|
||||
@@ -1338,6 +1371,8 @@ extern "C" {
|
||||
#define meshtastic_Data_portnum_ENUMTYPE meshtastic_PortNum
|
||||
|
||||
|
||||
#define meshtastic_StoreForwardPlusPlus_sfpp_message_type_ENUMTYPE meshtastic_StoreForwardPlusPlus_SFPP_message_type
|
||||
|
||||
|
||||
|
||||
#define meshtastic_MeshPacket_priority_ENUMTYPE meshtastic_MeshPacket_Priority
|
||||
@@ -1380,6 +1415,7 @@ extern "C" {
|
||||
#define meshtastic_Routing_init_default {0, {meshtastic_RouteDiscovery_init_default}}
|
||||
#define meshtastic_Data_init_default {_meshtastic_PortNum_MIN, {0, {0}}, 0, 0, 0, 0, 0, 0, false, 0}
|
||||
#define meshtastic_KeyVerification_init_default {0, {0, {0}}, {0, {0}}}
|
||||
#define meshtastic_StoreForwardPlusPlus_init_default {_meshtastic_StoreForwardPlusPlus_SFPP_message_type_MIN, {0, {0}}, {0, {0}}, {0, {0}}, {0, {0}}, 0, 0, 0, 0}
|
||||
#define meshtastic_Waypoint_init_default {0, false, 0, false, 0, 0, 0, "", "", 0}
|
||||
#define meshtastic_MqttClientProxyMessage_init_default {"", 0, {{0, {0}}}, 0}
|
||||
#define meshtastic_MeshPacket_init_default {0, 0, 0, 0, {meshtastic_Data_init_default}, 0, 0, 0, 0, 0, _meshtastic_MeshPacket_Priority_MIN, 0, _meshtastic_MeshPacket_Delayed_MIN, 0, 0, {0, {0}}, 0, 0, 0, 0, _meshtastic_MeshPacket_TransportMechanism_MIN}
|
||||
@@ -1411,6 +1447,7 @@ extern "C" {
|
||||
#define meshtastic_Routing_init_zero {0, {meshtastic_RouteDiscovery_init_zero}}
|
||||
#define meshtastic_Data_init_zero {_meshtastic_PortNum_MIN, {0, {0}}, 0, 0, 0, 0, 0, 0, false, 0}
|
||||
#define meshtastic_KeyVerification_init_zero {0, {0, {0}}, {0, {0}}}
|
||||
#define meshtastic_StoreForwardPlusPlus_init_zero {_meshtastic_StoreForwardPlusPlus_SFPP_message_type_MIN, {0, {0}}, {0, {0}}, {0, {0}}, {0, {0}}, 0, 0, 0, 0}
|
||||
#define meshtastic_Waypoint_init_zero {0, false, 0, false, 0, 0, 0, "", "", 0}
|
||||
#define meshtastic_MqttClientProxyMessage_init_zero {"", 0, {{0, {0}}}, 0}
|
||||
#define meshtastic_MeshPacket_init_zero {0, 0, 0, 0, {meshtastic_Data_init_zero}, 0, 0, 0, 0, 0, _meshtastic_MeshPacket_Priority_MIN, 0, _meshtastic_MeshPacket_Delayed_MIN, 0, 0, {0, {0}}, 0, 0, 0, 0, _meshtastic_MeshPacket_TransportMechanism_MIN}
|
||||
@@ -1489,6 +1526,15 @@ extern "C" {
|
||||
#define meshtastic_KeyVerification_nonce_tag 1
|
||||
#define meshtastic_KeyVerification_hash1_tag 2
|
||||
#define meshtastic_KeyVerification_hash2_tag 3
|
||||
#define meshtastic_StoreForwardPlusPlus_sfpp_message_type_tag 1
|
||||
#define meshtastic_StoreForwardPlusPlus_message_hash_tag 2
|
||||
#define meshtastic_StoreForwardPlusPlus_chain_hash_tag 3
|
||||
#define meshtastic_StoreForwardPlusPlus_root_hash_tag 4
|
||||
#define meshtastic_StoreForwardPlusPlus_message_tag 5
|
||||
#define meshtastic_StoreForwardPlusPlus_encapsulated_id_tag 6
|
||||
#define meshtastic_StoreForwardPlusPlus_encapsulated_to_tag 7
|
||||
#define meshtastic_StoreForwardPlusPlus_encapsulated_from_tag 8
|
||||
#define meshtastic_StoreForwardPlusPlus_encapsulated_rxtime_tag 9
|
||||
#define meshtastic_Waypoint_id_tag 1
|
||||
#define meshtastic_Waypoint_latitude_i_tag 2
|
||||
#define meshtastic_Waypoint_longitude_i_tag 3
|
||||
@@ -1705,6 +1751,19 @@ X(a, STATIC, SINGULAR, BYTES, hash2, 3)
|
||||
#define meshtastic_KeyVerification_CALLBACK NULL
|
||||
#define meshtastic_KeyVerification_DEFAULT NULL
|
||||
|
||||
#define meshtastic_StoreForwardPlusPlus_FIELDLIST(X, a) \
|
||||
X(a, STATIC, SINGULAR, UENUM, sfpp_message_type, 1) \
|
||||
X(a, STATIC, SINGULAR, BYTES, message_hash, 2) \
|
||||
X(a, STATIC, SINGULAR, BYTES, chain_hash, 3) \
|
||||
X(a, STATIC, SINGULAR, BYTES, root_hash, 4) \
|
||||
X(a, STATIC, SINGULAR, BYTES, message, 5) \
|
||||
X(a, STATIC, SINGULAR, UINT32, encapsulated_id, 6) \
|
||||
X(a, STATIC, SINGULAR, UINT32, encapsulated_to, 7) \
|
||||
X(a, STATIC, SINGULAR, UINT32, encapsulated_from, 8) \
|
||||
X(a, STATIC, SINGULAR, UINT32, encapsulated_rxtime, 9)
|
||||
#define meshtastic_StoreForwardPlusPlus_CALLBACK NULL
|
||||
#define meshtastic_StoreForwardPlusPlus_DEFAULT NULL
|
||||
|
||||
#define meshtastic_Waypoint_FIELDLIST(X, a) \
|
||||
X(a, STATIC, SINGULAR, UINT32, id, 1) \
|
||||
X(a, STATIC, OPTIONAL, SFIXED32, latitude_i, 2) \
|
||||
@@ -1980,6 +2039,7 @@ extern const pb_msgdesc_t meshtastic_RouteDiscovery_msg;
|
||||
extern const pb_msgdesc_t meshtastic_Routing_msg;
|
||||
extern const pb_msgdesc_t meshtastic_Data_msg;
|
||||
extern const pb_msgdesc_t meshtastic_KeyVerification_msg;
|
||||
extern const pb_msgdesc_t meshtastic_StoreForwardPlusPlus_msg;
|
||||
extern const pb_msgdesc_t meshtastic_Waypoint_msg;
|
||||
extern const pb_msgdesc_t meshtastic_MqttClientProxyMessage_msg;
|
||||
extern const pb_msgdesc_t meshtastic_MeshPacket_msg;
|
||||
@@ -2013,6 +2073,7 @@ extern const pb_msgdesc_t meshtastic_ChunkedPayloadResponse_msg;
|
||||
#define meshtastic_Routing_fields &meshtastic_Routing_msg
|
||||
#define meshtastic_Data_fields &meshtastic_Data_msg
|
||||
#define meshtastic_KeyVerification_fields &meshtastic_KeyVerification_msg
|
||||
#define meshtastic_StoreForwardPlusPlus_fields &meshtastic_StoreForwardPlusPlus_msg
|
||||
#define meshtastic_Waypoint_fields &meshtastic_Waypoint_msg
|
||||
#define meshtastic_MqttClientProxyMessage_fields &meshtastic_MqttClientProxyMessage_msg
|
||||
#define meshtastic_MeshPacket_fields &meshtastic_MeshPacket_msg
|
||||
@@ -2069,6 +2130,7 @@ extern const pb_msgdesc_t meshtastic_ChunkedPayloadResponse_msg;
|
||||
#define meshtastic_QueueStatus_size 23
|
||||
#define meshtastic_RouteDiscovery_size 256
|
||||
#define meshtastic_Routing_size 259
|
||||
#define meshtastic_StoreForwardPlusPlus_size 371
|
||||
#define meshtastic_ToRadio_size 504
|
||||
#define meshtastic_User_size 115
|
||||
#define meshtastic_Waypoint_size 165
|
||||
|
||||
@@ -86,6 +86,9 @@ typedef enum _meshtastic_PortNum {
|
||||
/* Paxcounter lib included in the firmware
|
||||
ENCODING: protobuf */
|
||||
meshtastic_PortNum_PAXCOUNTER_APP = 34,
|
||||
/* Store and Forward++ module included in the firmware
|
||||
ENCODING: protobuf */
|
||||
meshtastic_PortNum_STORE_FORWARD_PLUSPLUS_APP = 35,
|
||||
/* Provides a hardware serial interface to send and receive from the Meshtastic network.
|
||||
Connect to the RX/TX pins of a device with 38400 8N1. Packets received from the Meshtastic
|
||||
network is forwarded to the RX pin while sending a packet to TX will go out to the Mesh network.
|
||||
|
||||
@@ -61,6 +61,7 @@
|
||||
#if ARCH_PORTDUINO
|
||||
#include "input/LinuxInputImpl.h"
|
||||
#include "input/SeesawRotary.h"
|
||||
#include "modules/Native/StoreForwardPlusPlus.h"
|
||||
#include "modules/Telemetry/HostMetrics.h"
|
||||
#if !MESHTASTIC_EXCLUDE_STOREFORWARD
|
||||
#include "modules/StoreForwardModule.h"
|
||||
@@ -243,6 +244,7 @@ void setupModules()
|
||||
#endif
|
||||
#if ARCH_PORTDUINO
|
||||
new HostMetricsModule();
|
||||
new StoreForwardPlusPlusModule();
|
||||
#endif
|
||||
#if HAS_TELEMETRY
|
||||
new DeviceTelemetryModule();
|
||||
|
||||
653
src/modules/Native/StoreForwardPlusPlus.cpp
Normal file
653
src/modules/Native/StoreForwardPlusPlus.cpp
Normal file
@@ -0,0 +1,653 @@
|
||||
// create second module for satellites?
|
||||
|
||||
// The central node will generate a 256 or 128 bit value as its seed. This is the value other nodes subscribe to, and serves as
|
||||
// the root of the chain
|
||||
|
||||
//
|
||||
|
||||
// Basic design:
|
||||
// This module watches a channel for text messages.
|
||||
// each message gets sha256 summed, and then appended to a git-style blockchain. Probably need a counter, too
|
||||
// then the message, metadata, hash, and git hash information are saved. sqlite?
|
||||
|
||||
// nodes/sub-controllers can subscribe to a database
|
||||
|
||||
// A node can DM the controller, querying if a single message is on the chain, or asking for the last message hash
|
||||
|
||||
// if the message is not on the chain, the node can resend the message
|
||||
|
||||
// if the node lacks messages, it can request them
|
||||
|
||||
// will need the concept of sub-controllers, that subscribe to the central controller, can help push updates
|
||||
|
||||
// catch-up messages only go out when the mesh is low use %
|
||||
|
||||
// Normal firmware will only attempt to sync the chain a few times, then just ask for the latest few messages. A phone app can try
|
||||
// harder
|
||||
|
||||
// host will periodically advertise its presence
|
||||
|
||||
// at least initially, there can only be one authoritative host
|
||||
|
||||
// first draft is just to save channel 0 in a git-style database
|
||||
|
||||
// message objects get a hash value
|
||||
// the message chain gets a commit hash
|
||||
//
|
||||
|
||||
#include "StoreForwardPlusPlus.h"
|
||||
#include "MeshService.h"
|
||||
#include "RTC.h"
|
||||
#include "SHA256.h"
|
||||
#include "meshUtils.h"
|
||||
|
||||
StoreForwardPlusPlusModule::StoreForwardPlusPlusModule()
|
||||
: ProtobufModule("StoreForwardpp", meshtastic_PortNum_STORE_FORWARD_PLUSPLUS_APP, &meshtastic_StoreForwardPlusPlus_msg),
|
||||
concurrency::OSThread("StoreForwardpp")
|
||||
{
|
||||
LOG_WARN("StoreForwardPlusPlusModule init");
|
||||
if (portduino_config.sfpp_stratum0)
|
||||
LOG_WARN("SF++ stratum0");
|
||||
int res = sqlite3_open("test.db", &ppDb);
|
||||
LOG_WARN("Result1 %u", res);
|
||||
char *err = nullptr;
|
||||
res = sqlite3_exec(ppDb, " \
|
||||
CREATE TABLE channel_messages( \
|
||||
destination INT NOT NULL, \
|
||||
sender INT NOT NULL, \
|
||||
packet_id INT NOT NULL, \
|
||||
want_ack BOOL NOT NULL, \
|
||||
channel_hash INT NOT NULL, \
|
||||
encrypted_bytes BLOB NOT NULL, \
|
||||
message_hash BLOB NOT NULL, \
|
||||
rx_time INT NOT NULL, \
|
||||
commit_hash BLOB NOT NULL, \
|
||||
payload TEXT, \
|
||||
PRIMARY KEY (message_hash) \
|
||||
);",
|
||||
NULL, NULL, &err);
|
||||
LOG_WARN("Result2 %u", res);
|
||||
if (err != nullptr)
|
||||
;
|
||||
LOG_ERROR("%s", err);
|
||||
sqlite3_free(err);
|
||||
|
||||
// create table DMs
|
||||
res = sqlite3_exec(ppDb, " \
|
||||
CREATE TABLE direct_messages( \
|
||||
destination INT NOT NULL, \
|
||||
sender INT NOT NULL, \
|
||||
packet_id INT NOT NULL, \
|
||||
want_ack BOOL NOT NULL, \
|
||||
channel_hash INT NOT NULL, \
|
||||
commit_hash BLOB NOT NULL, \
|
||||
encrypted_bytes BLOB NOT NULL, \
|
||||
message_hash BLOB NOT NULL, \
|
||||
payload TEXT, \
|
||||
rx_time INT NOT NULL, \
|
||||
PRIMARY KEY (message_hash) \
|
||||
);",
|
||||
NULL, NULL, &err);
|
||||
LOG_WARN("Result2 %u", res);
|
||||
if (err != nullptr)
|
||||
;
|
||||
LOG_ERROR("%s", err);
|
||||
sqlite3_free(err);
|
||||
|
||||
// create table mappings
|
||||
// create table DMs
|
||||
res = sqlite3_exec(ppDb, " \
|
||||
CREATE TABLE mappings( \
|
||||
chain_type INT NOT NULL, \
|
||||
identifier INT NOT NULL, \
|
||||
root_hash BLOB NOT NULL, \
|
||||
PRIMARY KEY (identifier) \
|
||||
);",
|
||||
NULL, NULL, &err);
|
||||
LOG_WARN("Result2 %u", res);
|
||||
if (err != nullptr)
|
||||
;
|
||||
LOG_ERROR("%s", err);
|
||||
sqlite3_free(err);
|
||||
|
||||
// store schema version somewhere
|
||||
|
||||
std::string insert_statement = "INSERT INTO channel_messages (destination, sender, packet_id, want_ack, channel_hash, \
|
||||
encrypted_bytes, message_hash, rx_time, commit_hash, payload) VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, ?);";
|
||||
sqlite3_prepare_v2(ppDb, insert_statement.c_str(), insert_statement.length(), &stmt, NULL);
|
||||
|
||||
encryptedOk = true;
|
||||
|
||||
this->setInterval(15 * 1000);
|
||||
}
|
||||
|
||||
int32_t StoreForwardPlusPlusModule::runOnce()
|
||||
{
|
||||
LOG_WARN("StoreForward++ runONce");
|
||||
if (getRTCQuality() < RTCQualityNTP) {
|
||||
LOG_WARN("StoreForward++ deferred due to time quality %u", getRTCQuality());
|
||||
return 60 * 60 * 1000;
|
||||
}
|
||||
uint8_t root_hash_bytes[32] = {0};
|
||||
ChannelHash hash = channels.getHash(0);
|
||||
getOrAddRootFromChannelHash(hash, root_hash_bytes);
|
||||
|
||||
// get tip of chain for this channel
|
||||
uint8_t last_message_chain_hash[32] = {0};
|
||||
uint8_t last_message_hash[32] = {0};
|
||||
LOG_WARN("here5");
|
||||
|
||||
if (!getChainEnd(hash, last_message_chain_hash, last_message_hash)) {
|
||||
LOG_WARN("Store and Forward++ database lookup returned null");
|
||||
return 60 * 60 * 1000;
|
||||
}
|
||||
|
||||
meshtastic_StoreForwardPlusPlus storeforward = meshtastic_StoreForwardPlusPlus_init_zero;
|
||||
storeforward.sfpp_message_type = meshtastic_StoreForwardPlusPlus_SFPP_message_type_CANON_ANNOUNCE;
|
||||
// set root hash
|
||||
|
||||
// set message hash
|
||||
storeforward.message_hash.size = 32;
|
||||
memcpy(storeforward.message_hash.bytes, last_message_hash, 32);
|
||||
|
||||
// set chain hash
|
||||
storeforward.chain_hash.size = 32;
|
||||
memcpy(storeforward.chain_hash.bytes, last_message_chain_hash, 32);
|
||||
|
||||
// set root hash
|
||||
storeforward.root_hash.size = 32;
|
||||
memcpy(storeforward.root_hash.bytes, root_hash_bytes, 32);
|
||||
|
||||
// storeforward.
|
||||
meshtastic_MeshPacket *p = allocDataProtobuf(storeforward);
|
||||
p->to = NODENUM_BROADCAST;
|
||||
p->decoded.want_response = false;
|
||||
p->priority = meshtastic_MeshPacket_Priority_BACKGROUND;
|
||||
p->channel = 0;
|
||||
LOG_INFO("Send packet to mesh");
|
||||
service->sendToMesh(p, RX_SRC_LOCAL, true);
|
||||
|
||||
return 60 * 60 * 1000;
|
||||
}
|
||||
|
||||
bool StoreForwardPlusPlusModule::handleReceivedProtobuf(const meshtastic_MeshPacket &mp, meshtastic_StoreForwardPlusPlus *t)
|
||||
{
|
||||
LOG_WARN("in handleReceivedProtobuf");
|
||||
LOG_WARN("Sfp++ node %u is informing us of packet", mp.from);
|
||||
printBytes("chain_hash ", t->chain_hash.bytes, t->chain_hash.size);
|
||||
if (t->sfpp_message_type == meshtastic_StoreForwardPlusPlus_SFPP_message_type_CANON_ANNOUNCE) {
|
||||
// check chain_hash.size
|
||||
|
||||
if (portduino_config.sfpp_stratum0) {
|
||||
LOG_WARN("Received a CANON_ANNOUNCE while stratum 0");
|
||||
} else {
|
||||
uint8_t tmp_root_hash_bytes[32] = {0};
|
||||
|
||||
LOG_WARN("Received a CANON_ANNOUNCE");
|
||||
if (getRootFromChannelHash(router->p_encrypted->channel, tmp_root_hash_bytes)) {
|
||||
// we found the hash, check if it's the right one
|
||||
if (memcmp(tmp_root_hash_bytes, t->root_hash.bytes, 32) != 0) {
|
||||
LOG_WARN("Found root hash, and it doesn't match!");
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
// There's the possibility that
|
||||
addRootToMappings(router->p_encrypted->channel, t->root_hash.bytes);
|
||||
LOG_WARN("Adding root hash to mappings");
|
||||
}
|
||||
|
||||
// get tip of chain for this channel
|
||||
uint8_t last_message_chain_hash[32] = {0};
|
||||
uint8_t last_message_hash[32] = {0};
|
||||
|
||||
// get chain tip
|
||||
if (getChainEnd(router->p_encrypted->channel, last_message_chain_hash, last_message_hash)) {
|
||||
if (memcmp(last_message_chain_hash, t->chain_hash.bytes, 32) == 0) {
|
||||
LOG_WARN("End of chain matches!");
|
||||
} else
|
||||
("End of chain does not match!");
|
||||
} else {
|
||||
LOG_WARN("No Messages on this chain, request!");
|
||||
requestNextMessage(t->root_hash.bytes, t->root_hash.bytes);
|
||||
}
|
||||
|
||||
// compare to chain tip in incoming message
|
||||
|
||||
// if not found, request the next message
|
||||
}
|
||||
} else if (t->sfpp_message_type == meshtastic_StoreForwardPlusPlus_SFPP_message_type_LINK_REQUEST) {
|
||||
uint8_t next_chain_hash[32] = {0};
|
||||
|
||||
LOG_WARN("Received link request");
|
||||
getNextHash(t->root_hash.bytes, t->chain_hash.bytes, next_chain_hash);
|
||||
printBytes("next chain hash: ", next_chain_hash, 32);
|
||||
|
||||
broadcastLink(next_chain_hash, t->root_hash.bytes);
|
||||
|
||||
// if root and chain hashes are the same, grab the first message on the chain
|
||||
// if different, get the message directly after.
|
||||
// check if the root
|
||||
|
||||
} else if (t->sfpp_message_type == meshtastic_StoreForwardPlusPlus_SFPP_message_type_LINK_PROVIDE) {
|
||||
LOG_WARN("Link Provide received!");
|
||||
ChannelHash _channel_hash = getChannelHashFromRoot(t->root_hash.bytes);
|
||||
|
||||
addToChain(t->encapsulated_to, t->encapsulated_from, t->encapsulated_id, false, _channel_hash, t->message.bytes,
|
||||
t->message.size, t->message_hash.bytes, t->chain_hash.bytes, t->root_hash.bytes, t->encapsulated_rxtime, "",
|
||||
0);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
ProcessMessage StoreForwardPlusPlusModule::handleReceived(const meshtastic_MeshPacket &mp)
|
||||
{
|
||||
// To avoid terrible time problems, require NTP or GPS time
|
||||
if (getRTCQuality() < RTCQualityNTP) {
|
||||
return ProcessMessage::CONTINUE; // Let others look at this message also if they want
|
||||
}
|
||||
|
||||
// the sender+destination pair is an interesting unique id (though ordering) (smaller one goes first?)
|
||||
// so messages with a unique pair become a chain
|
||||
// These get a table
|
||||
|
||||
// message to broadcast get a chain per channel hash
|
||||
// second table
|
||||
// for now, channel messages are limited to decryptable
|
||||
// limited to text messages
|
||||
|
||||
// create a unique-from-nodenums() class that returns a 64-bit value
|
||||
|
||||
SHA256 message_hash, chain_hash;
|
||||
uint8_t message_hash_bytes[32] = {0};
|
||||
uint8_t chain_hash_bytes[32] = {0};
|
||||
uint8_t root_hash_bytes[32] = {0};
|
||||
|
||||
// For the moment, this is strictly LoRa
|
||||
if (mp.transport_mechanism != meshtastic_MeshPacket_TransportMechanism_TRANSPORT_LORA) {
|
||||
return ProcessMessage::CONTINUE; // Let others look at this message also if they want
|
||||
}
|
||||
|
||||
// will eventually host DMs and other undecodable messages
|
||||
if (mp.which_payload_variant != meshtastic_MeshPacket_decoded_tag) {
|
||||
return ProcessMessage::CONTINUE; // Let others look at this message also if they want
|
||||
}
|
||||
// refuse without valid time?
|
||||
LOG_WARN("in handleReceived");
|
||||
if (mp.decoded.portnum == meshtastic_PortNum_TEXT_MESSAGE_APP && mp.to == NODENUM_BROADCAST) {
|
||||
|
||||
// do not include rxtime in the message hash. We want these to match when more then one node receives and compares notes.
|
||||
// maybe include it in the commit hash
|
||||
|
||||
message_hash.reset();
|
||||
message_hash.update(router->p_encrypted->encrypted.bytes, router->p_encrypted->encrypted.size);
|
||||
message_hash.update(&mp.to, sizeof(mp.to));
|
||||
message_hash.update(&mp.from, sizeof(mp.from));
|
||||
message_hash.update(&mp.id, sizeof(mp.id));
|
||||
message_hash.finalize(message_hash_bytes, 32);
|
||||
|
||||
sqlite3_stmt *checkDup;
|
||||
sqlite3_prepare_v2(ppDb, "SELECT COUNT(*) from channel_messages where commit_hash=?", -1, &checkDup, NULL);
|
||||
sqlite3_bind_blob(checkDup, 1, message_hash_bytes, 32, NULL);
|
||||
sqlite3_step(checkDup);
|
||||
int numberFound = sqlite3_column_int(checkDup, 0);
|
||||
LOG_WARN("found %u times in db", numberFound);
|
||||
|
||||
if (numberFound != 0)
|
||||
return ProcessMessage::CONTINUE;
|
||||
|
||||
if (!portduino_config.sfpp_stratum0) {
|
||||
LOG_WARN("TODO: downstream collection of messages");
|
||||
return ProcessMessage::CONTINUE;
|
||||
}
|
||||
|
||||
// need to resolve the channel hash to the root hash
|
||||
getRootFromChannelHash(router->p_encrypted->channel, root_hash_bytes);
|
||||
|
||||
std::string getEntry_string =
|
||||
"select commit_hash from channel_messages where channel_hash=? order by rowid desc LIMIT 1;";
|
||||
sqlite3_stmt *getEntry;
|
||||
int rc = sqlite3_prepare_v2(ppDb, getEntry_string.c_str(), getEntry_string.size(), &getEntry, NULL);
|
||||
sqlite3_bind_int(getEntry, 1, router->p_encrypted->channel);
|
||||
sqlite3_step(getEntry);
|
||||
|
||||
// this is allocated by sqlite3 and will be deleted when finalize is called
|
||||
uint8_t *last_message_hash = (uint8_t *)sqlite3_column_blob(getEntry, 0);
|
||||
if (last_message_hash) {
|
||||
printBytes("last message: 0x", last_message_hash, 32);
|
||||
} else {
|
||||
printBytes("new chain root: 0x", root_hash_bytes, 32);
|
||||
}
|
||||
|
||||
// look for message_hash_bytes in db
|
||||
// if found, we bail early
|
||||
|
||||
chain_hash.reset();
|
||||
if (last_message_hash) {
|
||||
chain_hash.update(last_message_hash, 32);
|
||||
} else {
|
||||
chain_hash.update(root_hash_bytes, 32);
|
||||
}
|
||||
chain_hash.update(message_hash_bytes, 32);
|
||||
// message_hash.update(&mp.rx_time, sizeof(mp.rx_time));
|
||||
chain_hash.finalize(chain_hash_bytes, 32);
|
||||
|
||||
sqlite3_finalize(getEntry);
|
||||
|
||||
// select HEX(commit_hash),HEX(channel_hash), payload, destination from channel_messages order by rowid desc;
|
||||
|
||||
// push a message into the local chain DB
|
||||
|
||||
addToChain(mp.to, mp.from, mp.id, mp.want_ack, router->p_encrypted->channel, router->p_encrypted->encrypted.bytes,
|
||||
router->p_encrypted->encrypted.size, message_hash_bytes, chain_hash_bytes, root_hash_bytes, mp.rx_time,
|
||||
(char *)mp.decoded.payload.bytes, mp.decoded.payload.size);
|
||||
|
||||
return ProcessMessage::CONTINUE; // Let others look at this message also if they want
|
||||
|
||||
// one of the command messages
|
||||
} else if (mp.decoded.portnum == meshtastic_PortNum_STORE_FORWARD_PLUSPLUS_APP) {
|
||||
LOG_WARN("Got a STORE_FORWARD++ packet");
|
||||
meshtastic_StoreForwardPlusPlus scratch;
|
||||
pb_decode_from_bytes(mp.decoded.payload.bytes, mp.decoded.payload.size, meshtastic_StoreForwardPlusPlus_fields, &scratch);
|
||||
handleReceivedProtobuf(mp, &scratch);
|
||||
// when we get an update this way, if the message isn't on the chain, this node hasn't seen it, and can rebroadcast.
|
||||
return ProcessMessage::CONTINUE;
|
||||
}
|
||||
return ProcessMessage::CONTINUE;
|
||||
}
|
||||
|
||||
bool StoreForwardPlusPlusModule::getRootFromChannelHash(ChannelHash _ch_hash, uint8_t *_root_hash)
|
||||
{
|
||||
bool found = false;
|
||||
sqlite3_stmt *getHash;
|
||||
int rc = sqlite3_prepare_v2(ppDb, "select root_hash from mappings where identifier=?;", -1, &getHash, NULL);
|
||||
sqlite3_bind_int(getHash, 1, _ch_hash);
|
||||
sqlite3_step(getHash);
|
||||
uint8_t *tmp_root_hash = (uint8_t *)sqlite3_column_blob(getHash, 0);
|
||||
if (tmp_root_hash) {
|
||||
LOG_WARN("Found root hash!");
|
||||
memcpy(_root_hash, tmp_root_hash, 32);
|
||||
found = true;
|
||||
}
|
||||
sqlite3_finalize(getHash);
|
||||
return found;
|
||||
}
|
||||
|
||||
ChannelHash StoreForwardPlusPlusModule::getChannelHashFromRoot(uint8_t *_root_hash)
|
||||
{
|
||||
sqlite3_stmt *getHash;
|
||||
int rc = sqlite3_prepare_v2(ppDb, "select identifier from mappings where root_hash=?;", -1, &getHash, NULL);
|
||||
sqlite3_bind_blob(getHash, 1, _root_hash, 32, NULL);
|
||||
sqlite3_step(getHash);
|
||||
ChannelHash tmp_hash = (ChannelHash)sqlite3_column_int(getHash, 0);
|
||||
sqlite3_finalize(getHash);
|
||||
return tmp_hash;
|
||||
}
|
||||
|
||||
// return code indicates newly created chain
|
||||
bool StoreForwardPlusPlusModule::getOrAddRootFromChannelHash(ChannelHash _ch_hash, uint8_t *_root_hash)
|
||||
{
|
||||
LOG_WARN("getOrAddRootFromChannelHash()");
|
||||
bool isNew = !getRootFromChannelHash(_ch_hash, _root_hash);
|
||||
|
||||
if (isNew) {
|
||||
if (portduino_config.sfpp_stratum0) {
|
||||
LOG_WARN("Generating Root hash!");
|
||||
// generate root hash
|
||||
SHA256 chain_hash;
|
||||
chain_hash.update(&_ch_hash, sizeof(_ch_hash));
|
||||
NodeNum ourNode = nodeDB->getNodeNum();
|
||||
chain_hash.update(&ourNode, sizeof(ourNode));
|
||||
uint32_t rtc_sec = getValidTime(RTCQuality::RTCQualityDevice, true);
|
||||
chain_hash.update(&rtc_sec, sizeof(rtc_sec));
|
||||
chain_hash.finalize(_root_hash, 32);
|
||||
|
||||
addRootToMappings(_ch_hash, _root_hash);
|
||||
LOG_WARN("here4");
|
||||
}
|
||||
}
|
||||
return isNew;
|
||||
}
|
||||
|
||||
bool StoreForwardPlusPlusModule::addRootToMappings(ChannelHash _ch_hash, uint8_t *_root_hash)
|
||||
{
|
||||
LOG_WARN("addRootToMappings()");
|
||||
printBytes("_root_hash", _root_hash, 32);
|
||||
sqlite3_stmt *getHash;
|
||||
|
||||
// write to the table
|
||||
int rc =
|
||||
sqlite3_prepare_v2(ppDb, "INSERT INTO mappings (chain_type, identifier, root_hash) VALUES(?, ?, ?);", -1, &getHash, NULL);
|
||||
LOG_WARN("%d", rc);
|
||||
int type = chain_types::channel_chain;
|
||||
// note, must be an int variable
|
||||
|
||||
sqlite3_bind_int(getHash, 1, type);
|
||||
sqlite3_bind_int(getHash, 2, _ch_hash);
|
||||
sqlite3_bind_blob(getHash, 3, _root_hash, 32, NULL);
|
||||
LOG_WARN("here1");
|
||||
// sqlite3_bind_int(getHash, 4, nodeToAdd);
|
||||
rc = sqlite3_step(getHash);
|
||||
LOG_WARN("here2 %u, %s", rc, sqlite3_errmsg(ppDb));
|
||||
sqlite3_finalize(getHash);
|
||||
LOG_WARN("here3");
|
||||
return true;
|
||||
}
|
||||
|
||||
bool StoreForwardPlusPlusModule::getChainEnd(ChannelHash _ch_hash, uint8_t *_chain_hash, uint8_t *_message_hash)
|
||||
{
|
||||
LOG_WARN("getChainEnd");
|
||||
|
||||
std::string getEntry_string =
|
||||
"select commit_hash, message_hash from channel_messages where channel_hash=? order by rowid desc LIMIT 1;";
|
||||
sqlite3_stmt *getEntry;
|
||||
int rc = sqlite3_prepare_v2(ppDb, getEntry_string.c_str(), getEntry_string.size(), &getEntry, NULL);
|
||||
sqlite3_bind_int(getEntry, 1, _ch_hash);
|
||||
sqlite3_step(getEntry);
|
||||
uint8_t *last_message_chain_hash = (uint8_t *)sqlite3_column_blob(getEntry, 0);
|
||||
uint8_t *last_message_hash = (uint8_t *)sqlite3_column_blob(getEntry, 1);
|
||||
|
||||
if (last_message_chain_hash == nullptr || last_message_hash == nullptr) {
|
||||
LOG_WARN("Store and Forward++ database lookup returned null");
|
||||
sqlite3_finalize(getEntry);
|
||||
|
||||
return false;
|
||||
}
|
||||
memcpy(_chain_hash, last_message_chain_hash, 32);
|
||||
memcpy(_message_hash, last_message_hash, 32);
|
||||
sqlite3_finalize(getEntry);
|
||||
return true;
|
||||
}
|
||||
|
||||
void StoreForwardPlusPlusModule::requestNextMessage(uint8_t *_root_hash, uint8_t *_chain_hash)
|
||||
{
|
||||
|
||||
meshtastic_StoreForwardPlusPlus storeforward = meshtastic_StoreForwardPlusPlus_init_zero;
|
||||
storeforward.sfpp_message_type = meshtastic_StoreForwardPlusPlus_SFPP_message_type_LINK_REQUEST;
|
||||
// set root hash
|
||||
|
||||
// set chain hash
|
||||
storeforward.chain_hash.size = 32;
|
||||
memcpy(storeforward.chain_hash.bytes, _chain_hash, 32);
|
||||
|
||||
// set root hash
|
||||
storeforward.root_hash.size = 32;
|
||||
memcpy(storeforward.root_hash.bytes, _root_hash, 32);
|
||||
|
||||
// storeforward.
|
||||
meshtastic_MeshPacket *p = allocDataProtobuf(storeforward);
|
||||
p->to = NODENUM_BROADCAST;
|
||||
p->decoded.want_response = false;
|
||||
p->priority = meshtastic_MeshPacket_Priority_BACKGROUND;
|
||||
p->channel = 0;
|
||||
LOG_INFO("Send packet to mesh");
|
||||
service->sendToMesh(p, RX_SRC_LOCAL, true);
|
||||
}
|
||||
|
||||
bool StoreForwardPlusPlusModule::getNextHash(uint8_t *_root_hash, uint8_t *_chain_hash, uint8_t *next_chain_hash)
|
||||
{
|
||||
LOG_WARN("getNextHash");
|
||||
|
||||
ChannelHash _channel_hash = getChannelHashFromRoot(_root_hash);
|
||||
LOG_WARN("_channel_hash %u", _channel_hash);
|
||||
|
||||
sqlite3_stmt *getHash;
|
||||
int rc = sqlite3_prepare_v2(ppDb, "select commit_hash from channel_messages where channel_hash=? order by rowid ASC;", -1,
|
||||
&getHash, NULL);
|
||||
|
||||
LOG_WARN("%d", rc);
|
||||
if (rc != SQLITE_OK) {
|
||||
LOG_WARN("here2 %u, %s", rc, sqlite3_errmsg(ppDb));
|
||||
}
|
||||
sqlite3_bind_int(getHash, 1, _channel_hash);
|
||||
sqlite3_step(getHash);
|
||||
bool found_hash = false;
|
||||
|
||||
// asking for the first entry on the chain
|
||||
if (memcmp(_root_hash, _chain_hash, 32) == 0) {
|
||||
uint8_t *tmp_chain_hash = (uint8_t *)sqlite3_column_blob(getHash, 0);
|
||||
memcpy(next_chain_hash, tmp_chain_hash, 32);
|
||||
found_hash = true;
|
||||
} else {
|
||||
uint8_t *tmp_chain_hash;
|
||||
while (sqlite3_step(getHash) != SQLITE_DONE) {
|
||||
tmp_chain_hash = (uint8_t *)sqlite3_column_blob(getHash, 0);
|
||||
if (found_hash) {
|
||||
memcpy(next_chain_hash, tmp_chain_hash, 32);
|
||||
break;
|
||||
}
|
||||
if (memcmp(tmp_chain_hash, _chain_hash, 32) == 0)
|
||||
found_hash = true;
|
||||
}
|
||||
}
|
||||
|
||||
sqlite3_finalize(getHash);
|
||||
return found_hash;
|
||||
}
|
||||
|
||||
bool StoreForwardPlusPlusModule::broadcastLink(uint8_t *_chain_hash, uint8_t *_root_hash)
|
||||
{
|
||||
sqlite3_stmt *getHash;
|
||||
int rc = sqlite3_prepare_v2(ppDb, "select destination, sender, packet_id, encrypted_bytes, message_hash, rx_time \
|
||||
from channel_messages where commit_hash=?;",
|
||||
-1, &getHash, NULL);
|
||||
|
||||
LOG_WARN("%d", rc);
|
||||
if (rc != SQLITE_OK) {
|
||||
LOG_WARN("here2 %u, %s", rc, sqlite3_errmsg(ppDb));
|
||||
}
|
||||
sqlite3_bind_blob(getHash, 1, _chain_hash, 32, NULL);
|
||||
sqlite3_step(getHash);
|
||||
|
||||
meshtastic_StoreForwardPlusPlus storeforward = meshtastic_StoreForwardPlusPlus_init_zero;
|
||||
storeforward.sfpp_message_type = meshtastic_StoreForwardPlusPlus_SFPP_message_type_LINK_PROVIDE;
|
||||
|
||||
storeforward.encapsulated_to = sqlite3_column_int(getHash, 0);
|
||||
storeforward.encapsulated_from = sqlite3_column_int(getHash, 1);
|
||||
storeforward.encapsulated_id = sqlite3_column_int(getHash, 2);
|
||||
|
||||
uint8_t *_payload = (uint8_t *)sqlite3_column_blob(getHash, 3);
|
||||
storeforward.message.size = sqlite3_column_bytes(getHash, 3);
|
||||
memcpy(storeforward.message.bytes, _payload, storeforward.message.size);
|
||||
|
||||
uint8_t *_message_hash = (uint8_t *)sqlite3_column_blob(getHash, 4);
|
||||
storeforward.message_hash.size = 32;
|
||||
memcpy(storeforward.message_hash.bytes, _message_hash, storeforward.message_hash.size);
|
||||
|
||||
storeforward.encapsulated_rxtime = sqlite3_column_int(getHash, 5);
|
||||
|
||||
storeforward.chain_hash.size = 32;
|
||||
memcpy(storeforward.chain_hash.bytes, _chain_hash, 32);
|
||||
|
||||
storeforward.root_hash.size = 32;
|
||||
memcpy(storeforward.root_hash.bytes, _root_hash, 32);
|
||||
|
||||
sqlite3_finalize(getHash);
|
||||
|
||||
meshtastic_MeshPacket *p = allocDataProtobuf(storeforward);
|
||||
p->to = NODENUM_BROADCAST;
|
||||
p->decoded.want_response = false;
|
||||
p->priority = meshtastic_MeshPacket_Priority_BACKGROUND;
|
||||
p->channel = 0;
|
||||
LOG_INFO("Send link to mesh");
|
||||
service->sendToMesh(p, RX_SRC_LOCAL, true);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool StoreForwardPlusPlusModule::addToChain(uint32_t to, uint32_t from, uint32_t id, bool want_ack, ChannelHash channel_hash,
|
||||
uint8_t *encrypted_bytes, size_t encrypted_len, uint8_t *_message_hash,
|
||||
uint8_t *_chain_hash, uint8_t *_root_hash, uint32_t _rx_time, char *payload_bytes,
|
||||
size_t payload_len)
|
||||
|
||||
{
|
||||
// push a message into the local chain DB
|
||||
// destination
|
||||
sqlite3_bind_int(stmt, 1, to);
|
||||
// sender
|
||||
sqlite3_bind_int(stmt, 2, from);
|
||||
// packet_id
|
||||
sqlite3_bind_int(stmt, 3, id);
|
||||
// want_ack
|
||||
sqlite3_bind_int(stmt, 4, want_ack);
|
||||
// channel_hash
|
||||
sqlite3_bind_int(stmt, 5, channel_hash);
|
||||
// encrypted_bytes
|
||||
sqlite3_bind_blob(stmt, 6, encrypted_bytes, encrypted_len, NULL);
|
||||
|
||||
// message_hash
|
||||
sqlite3_bind_blob(stmt, 7, _message_hash, 32, NULL);
|
||||
// rx_time
|
||||
sqlite3_bind_int(stmt, 8, _rx_time);
|
||||
|
||||
// commit_hash
|
||||
sqlite3_bind_blob(stmt, 9, _chain_hash, 32, NULL);
|
||||
// payload
|
||||
sqlite3_bind_text(stmt, 10, payload_bytes, payload_len, NULL);
|
||||
|
||||
sqlite3_step(stmt);
|
||||
sqlite3_reset(stmt);
|
||||
return true;
|
||||
}
|
||||
|
||||
// announce latest hash
|
||||
// chain_end_announce
|
||||
|
||||
// check if hash is known
|
||||
// hash_query
|
||||
|
||||
// request next message
|
||||
// link_request
|
||||
|
||||
// send encapsulated message
|
||||
// link_provide_whole
|
||||
// link_provide_half1
|
||||
// link_provide_half2
|
||||
|
||||
// onboard request message?
|
||||
|
||||
// get x from top?
|
||||
|
||||
// messages
|
||||
// Given this chain root, do you have a packet that matches this message hash?
|
||||
// responds with chain hash etc
|
||||
|
||||
// given this chain root, what is your last chain and message hash?
|
||||
// given this chain root, what is your next message after this chain hash? (do we have an overhead problem here?) (blegh,
|
||||
// fragmentation) (but also, trunking)
|
||||
|
||||
// broadcast on this chain root, here is my last chain hash
|
||||
|
||||
// consider third-order nodes
|
||||
|
||||
// I can't talk directly to strata, I can talk to a satellite. Inform sat of a message. Sat stores it as if had seen it locally,
|
||||
// and pushes it to central
|
||||
|
||||
// message Eventually works out through chain
|
||||
|
||||
// sat can capture time of receipt
|
||||
|
||||
// terms:
|
||||
// CANON
|
||||
// stratum
|
||||
// chain
|
||||
// links on the chain
|
||||
74
src/modules/Native/StoreForwardPlusPlus.h
Normal file
74
src/modules/Native/StoreForwardPlusPlus.h
Normal file
@@ -0,0 +1,74 @@
|
||||
#pragma once
|
||||
#include "Channels.h"
|
||||
#include "ProtobufModule.h"
|
||||
#include "Router.h"
|
||||
#include "SinglePortModule.h"
|
||||
#include "sqlite3.h"
|
||||
|
||||
/**
|
||||
* A simple example module that just replies with "Message received" to any message it receives.
|
||||
*/
|
||||
class StoreForwardPlusPlusModule : public ProtobufModule<meshtastic_StoreForwardPlusPlus>, private concurrency::OSThread
|
||||
{
|
||||
public:
|
||||
/** Constructor
|
||||
* name is for debugging output
|
||||
*/
|
||||
StoreForwardPlusPlusModule();
|
||||
|
||||
/*
|
||||
-Override the wantPacket method.
|
||||
*/
|
||||
virtual bool wantPacket(const meshtastic_MeshPacket *p) override
|
||||
{
|
||||
// if encrypted but not too FFFF
|
||||
// want
|
||||
switch (p->decoded.portnum) {
|
||||
case meshtastic_PortNum_TEXT_MESSAGE_APP:
|
||||
case 35:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
protected:
|
||||
/** Called to handle a particular incoming message
|
||||
@return ProcessMessage::STOP if you've guaranteed you've handled this message and no other handlers should be considered for
|
||||
it
|
||||
*/
|
||||
virtual ProcessMessage handleReceived(const meshtastic_MeshPacket &mp) override;
|
||||
virtual bool handleReceivedProtobuf(const meshtastic_MeshPacket &mp, meshtastic_StoreForwardPlusPlus *t) override;
|
||||
|
||||
virtual int32_t runOnce() override;
|
||||
|
||||
private:
|
||||
sqlite3 *ppDb;
|
||||
sqlite3_stmt *stmt;
|
||||
|
||||
// returns wasfound
|
||||
bool getRootFromChannelHash(ChannelHash, uint8_t *);
|
||||
|
||||
ChannelHash getChannelHashFromRoot(uint8_t *_root_hash);
|
||||
|
||||
bool getNextHash(uint8_t *_root_hash, uint8_t *_chain_hash, uint8_t *next_chain_hash);
|
||||
|
||||
// returns isnew
|
||||
bool getOrAddRootFromChannelHash(ChannelHash, uint8_t *);
|
||||
|
||||
bool addRootToMappings(ChannelHash, uint8_t *);
|
||||
|
||||
// return indicates message found
|
||||
bool getChainEnd(ChannelHash, uint8_t *, uint8_t *);
|
||||
|
||||
void requestNextMessage(uint8_t *, uint8_t *);
|
||||
|
||||
bool broadcastLink(uint8_t *_chain_hash, uint8_t *_root_hash);
|
||||
|
||||
bool addToChain(uint32_t, uint32_t, uint32_t, bool, ChannelHash, uint8_t *, size_t, uint8_t *, uint8_t *, uint8_t *, uint32_t,
|
||||
char *, size_t);
|
||||
|
||||
enum chain_types {
|
||||
channel_chain = 0,
|
||||
};
|
||||
};
|
||||
235
src/modules/Native/StoreForwardPlusPlusSat.cpp
Normal file
235
src/modules/Native/StoreForwardPlusPlusSat.cpp
Normal file
@@ -0,0 +1,235 @@
|
||||
// create second module for satellites?
|
||||
|
||||
// The central node will generate a 256 or 128 bit value as its seed. This is the value other nodes subscribe to, and serves as
|
||||
// the root of the chain
|
||||
|
||||
//
|
||||
|
||||
// Basic design:
|
||||
// This module watches a channel for text messages.
|
||||
// each message gets sha256 summed, and then appended to a git-style blockchain. Probably need a counter, too
|
||||
// then the message, metadata, hash, and git hash information are saved. sqlite?
|
||||
|
||||
// nodes/sub-controllers can subscribe to a database
|
||||
|
||||
// A node can DM the controller, querying if a single message is on the chain, or asking for the last message hash
|
||||
|
||||
// if the message is not on the chain, the node can resend the message
|
||||
|
||||
// if the node lacks messages, it can request them
|
||||
|
||||
// will need the concept of sub-controllers, that subscribe to the central controller, can help push updates
|
||||
|
||||
// catch-up messages only go out when the mesh is low use %
|
||||
|
||||
// Normal firmware will only attempt to sync the chain a few times, then just ask for the latest few messages. A phone app can try
|
||||
// harder
|
||||
|
||||
// host will periodically advertise its presence
|
||||
|
||||
// at least initially, there can only be one authoritative host
|
||||
|
||||
// first draft is just to save channel 0 in a git-style database
|
||||
|
||||
// message objects get a hash value
|
||||
// the message chain gets a commit hash
|
||||
//
|
||||
|
||||
#include "StoreForwardPlusPlusSat.h"
|
||||
#include "SHA256.h"
|
||||
#include "meshUtils.h"
|
||||
|
||||
StoreForwardPlusPlusSatModule::StoreForwardPlusPlusSatModule() : SinglePortModule("StoreForwardPlusPlus", (_meshtastic_PortNum)35)
|
||||
{
|
||||
LOG_WARN("StoreForwardPlusPlusSatModule init");
|
||||
int res = sqlite3_open("test.db", &ppDb);
|
||||
LOG_WARN("Result1 %u", res);
|
||||
char *err = nullptr;
|
||||
res = sqlite3_exec(ppDb, " \
|
||||
CREATE TABLE channel_messages( \
|
||||
destination INT NOT NULL, \
|
||||
sender INT NOT NULL, \
|
||||
packet_id INT NOT NULL, \
|
||||
want_ack BOOL NOT NULL, \
|
||||
channel_hash INT NOT NULL, \
|
||||
encrypted_bytes BLOB NOT NULL, \
|
||||
message_hash BLOB NOT NULL, \
|
||||
rx_time INT NOT NULL, \
|
||||
commit_hash BLOB NOT NULL, \
|
||||
payload TEXT, \
|
||||
PRIMARY KEY (message_hash) \
|
||||
);",
|
||||
NULL, NULL, &err);
|
||||
LOG_WARN("Result2 %u", res);
|
||||
if (err != nullptr)
|
||||
;
|
||||
LOG_ERROR("%s", err);
|
||||
sqlite3_free(err);
|
||||
|
||||
// create table DMs
|
||||
res = sqlite3_exec(ppDb, " \
|
||||
CREATE TABLE direct_messages( \
|
||||
destination INT NOT NULL, \
|
||||
sender INT NOT NULL, \
|
||||
packet_id INT NOT NULL, \
|
||||
want_ack BOOL NOT NULL, \
|
||||
channel_hash INT NOT NULL, \
|
||||
commit_hash BLOB NOT NULL, \
|
||||
encrypted_bytes BLOB NOT NULL, \
|
||||
message_hash BLOB NOT NULL, \
|
||||
payload TEXT, \
|
||||
rx_time INT NOT NULL, \
|
||||
PRIMARY KEY (message_hash) \
|
||||
);",
|
||||
NULL, NULL, &err);
|
||||
LOG_WARN("Result2 %u", res);
|
||||
if (err != nullptr)
|
||||
;
|
||||
LOG_ERROR("%s", err);
|
||||
sqlite3_free(err);
|
||||
|
||||
// create table mappings
|
||||
// create table DMs
|
||||
res = sqlite3_exec(ppDb, " \
|
||||
CREATE TABLE mappings( \
|
||||
chain_type INT NOT NULL, \
|
||||
identifier INT NOT NULL, \
|
||||
root_hash BLOB NOT NULL, \
|
||||
PRIMARY KEY (identifier) \
|
||||
);",
|
||||
NULL, NULL, &err);
|
||||
LOG_WARN("Result2 %u", res);
|
||||
if (err != nullptr)
|
||||
;
|
||||
LOG_ERROR("%s", err);
|
||||
sqlite3_free(err);
|
||||
// type
|
||||
// sha256hash
|
||||
// channelhash or 64 bit combination
|
||||
// The sat version needs a scratch database of messages that have not been checked in
|
||||
|
||||
// store schema version somewhere
|
||||
|
||||
std::string insert_statement = "INSERT INTO channel_messages (destination, sender, packet_id, want_ack, channel_hash, \
|
||||
encrypted_bytes, message_hash, rx_time, commit_hash, payload) VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, ?);";
|
||||
sqlite3_prepare(ppDb, insert_statement.c_str(), insert_statement.length(), &stmt, NULL);
|
||||
|
||||
encryptedOk = true;
|
||||
}
|
||||
|
||||
ProcessMessage StoreForwardPlusPlusSatModule::handleReceived(const meshtastic_MeshPacket &mp)
|
||||
{
|
||||
|
||||
// the sender+destination pair is an interesting unique id (though ordering) (smaller one goes first?)
|
||||
// so messages with a unique pair become a chain
|
||||
// These get a table
|
||||
|
||||
// message to broadcast get a chain per channel hash
|
||||
// second table
|
||||
// for now, channel messages are limited to decryptable
|
||||
// limited to text messages
|
||||
|
||||
// create a unique-from-nodenums() class that returns a 64-bit value
|
||||
|
||||
SHA256 message_hash, chain_hash;
|
||||
uint8_t message_hash_bytes[32] = {0};
|
||||
uint8_t chain_hash_bytes[32] = {0};
|
||||
|
||||
// For the moment, this is strictly LoRa
|
||||
if (mp.transport_mechanism != meshtastic_MeshPacket_TransportMechanism_TRANSPORT_LORA) {
|
||||
return ProcessMessage::CONTINUE; // Let others look at this message also if they want
|
||||
}
|
||||
|
||||
// will eventually host DMs and other undecodable messages
|
||||
if (mp.which_payload_variant != meshtastic_MeshPacket_decoded_tag) {
|
||||
return ProcessMessage::CONTINUE; // Let others look at this message also if they want
|
||||
}
|
||||
// refuse without valid time?
|
||||
LOG_WARN("in handleReceived");
|
||||
std::string getEntry_string = "select commit_hash from channel_messages where channel_hash=? order by rowid desc LIMIT 1;";
|
||||
sqlite3_stmt *getEntry;
|
||||
int rc = sqlite3_prepare(ppDb, getEntry_string.c_str(), getEntry_string.size(), &getEntry, NULL);
|
||||
sqlite3_bind_int(getEntry, 1, router->p_encrypted->channel);
|
||||
sqlite3_step(getEntry);
|
||||
|
||||
// this is allocated by sqlite3 and will be deleted when finalize is called
|
||||
uint8_t *last_message_hash = (uint8_t *)sqlite3_column_blob(getEntry, 0);
|
||||
if (last_message_hash) {
|
||||
printBytes("last message: 0x", last_message_hash, 32);
|
||||
} else {
|
||||
// generate root hash and populate lookup table
|
||||
}
|
||||
|
||||
// do not include rxtime in the message hash. We want these to match when more then one node receives and compares notes.
|
||||
// feel free to include it in the commit hash
|
||||
|
||||
message_hash.reset();
|
||||
message_hash.update(router->p_encrypted->encrypted.bytes, router->p_encrypted->encrypted.size);
|
||||
message_hash.update(&mp.to, sizeof(mp.to));
|
||||
message_hash.update(&mp.from, sizeof(mp.from));
|
||||
message_hash.update(&mp.id, sizeof(mp.id));
|
||||
message_hash.finalize(message_hash_bytes, 32);
|
||||
|
||||
chain_hash.reset();
|
||||
if (last_message_hash) {
|
||||
chain_hash.update(last_message_hash, 32);
|
||||
}
|
||||
chain_hash.update(message_hash_bytes, 32);
|
||||
// message_hash.update(&mp.rx_time, sizeof(mp.rx_time));
|
||||
chain_hash.finalize(chain_hash_bytes, 32);
|
||||
|
||||
sqlite3_finalize(getEntry);
|
||||
|
||||
// select HEX(commit_hash),HEX(channel_hash), payload, destination from channel_messages order by rowid desc;
|
||||
|
||||
// push a message into the local chain DB
|
||||
// destination
|
||||
sqlite3_bind_int(stmt, 1, mp.to);
|
||||
// sender
|
||||
sqlite3_bind_int(stmt, 2, mp.from);
|
||||
// packet_id
|
||||
sqlite3_bind_int(stmt, 3, mp.id);
|
||||
// want_ack
|
||||
sqlite3_bind_int(stmt, 4, mp.want_ack);
|
||||
// channel_hash
|
||||
sqlite3_bind_int(stmt, 5, router->p_encrypted->channel);
|
||||
// encrypted_bytes
|
||||
sqlite3_bind_blob(stmt, 6, router->p_encrypted->encrypted.bytes, router->p_encrypted->encrypted.size, NULL);
|
||||
|
||||
// message_hash
|
||||
sqlite3_bind_blob(stmt, 7, message_hash_bytes, 32, NULL);
|
||||
// rx_time
|
||||
sqlite3_bind_int(stmt, 8, mp.rx_time);
|
||||
|
||||
// commit_hash
|
||||
sqlite3_bind_blob(stmt, 9, chain_hash_bytes, 32, NULL);
|
||||
// payload
|
||||
sqlite3_bind_text(stmt, 10, (char *)mp.decoded.payload.bytes, mp.decoded.payload.size, NULL);
|
||||
|
||||
sqlite3_step(stmt);
|
||||
sqlite3_reset(stmt);
|
||||
|
||||
return ProcessMessage::CONTINUE; // Let others look at this message also if they want
|
||||
}
|
||||
|
||||
// when we get an update this way, if the message isn't on the chain or in the scratch table, this node hasn't seen it, and can
|
||||
// rebroadcast.
|
||||
|
||||
// messages
|
||||
// Given this chain root, do you have a packet that matches this message hash?
|
||||
// responds with chain hash etc
|
||||
|
||||
// given this chain root, what is your last chain and message hash?
|
||||
// given this chain root, what is your next message after this chain hash? (do we have an overhead problem here?) (blegh,
|
||||
// fragmentation) (but also, trunking)
|
||||
|
||||
// broadcast on this chain root, here is my last chain hash
|
||||
|
||||
// consider third-order nodes
|
||||
|
||||
// I can't talk directly to strata, I can talk to a satellite. Inform sat of a message. Sat stores it as if had seen it locally,
|
||||
// and pushes it to central
|
||||
|
||||
// message Eventually works out through chain
|
||||
|
||||
// sat can capture time of receipt
|
||||
41
src/modules/Native/StoreForwardPlusPlusSat.h
Normal file
41
src/modules/Native/StoreForwardPlusPlusSat.h
Normal file
@@ -0,0 +1,41 @@
|
||||
#pragma once
|
||||
#include "Router.h"
|
||||
#include "SinglePortModule.h"
|
||||
#include "sqlite3.h"
|
||||
|
||||
/**
|
||||
* A simple example module that just replies with "Message received" to any message it receives.
|
||||
*/
|
||||
class StoreForwardPlusPlusSatModule : public SinglePortModule // should probably derive this from the main class
|
||||
{
|
||||
public:
|
||||
/** Constructor
|
||||
* name is for debugging output
|
||||
*/
|
||||
StoreForwardPlusPlusSatModule();
|
||||
|
||||
/*
|
||||
-Override the wantPacket method.
|
||||
*/
|
||||
virtual bool wantPacket(const meshtastic_MeshPacket *p) override
|
||||
{
|
||||
switch (p->decoded.portnum) {
|
||||
case meshtastic_PortNum_TEXT_MESSAGE_APP:
|
||||
case 35:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
protected:
|
||||
/** Called to handle a particular incoming message
|
||||
@return ProcessMessage::STOP if you've guaranteed you've handled this message and no other handlers should be considered for
|
||||
it
|
||||
*/
|
||||
virtual ProcessMessage handleReceived(const meshtastic_MeshPacket &mp) override;
|
||||
|
||||
private:
|
||||
sqlite3 *ppDb;
|
||||
sqlite3_stmt *stmt;
|
||||
};
|
||||
@@ -29,7 +29,6 @@
|
||||
|
||||
portduino_config_struct portduino_config;
|
||||
std::ofstream traceFile;
|
||||
std::ofstream JSONFile;
|
||||
Ch341Hal *ch341Hal = nullptr;
|
||||
char *configPath = nullptr;
|
||||
char *optionMac = nullptr;
|
||||
@@ -464,7 +463,6 @@ void portduinoSetup()
|
||||
if (portduino_config.lora_spi_dev != "" && portduino_config.lora_spi_dev != "ch341") {
|
||||
SPI.begin(portduino_config.lora_spi_dev.c_str());
|
||||
}
|
||||
|
||||
if (portduino_config.traceFilename != "") {
|
||||
try {
|
||||
traceFile.open(portduino_config.traceFilename, std::ios::out | std::ios::app);
|
||||
@@ -472,21 +470,6 @@ void portduinoSetup()
|
||||
std::cout << "*** traceFile Exception " << e.what() << std::endl;
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
if (!traceFile.is_open()) {
|
||||
std::cout << "*** traceFile open failure" << std::endl;
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
} else if (portduino_config.JSONFilename != "") {
|
||||
try {
|
||||
JSONFile.open(portduino_config.JSONFilename, std::ios::out | std::ios::app);
|
||||
} catch (std::ofstream::failure &e) {
|
||||
std::cout << "*** JSONFile Exception " << e.what() << std::endl;
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
if (!JSONFile.is_open()) {
|
||||
std::cout << "*** JSONFile open failure" << std::endl;
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
if (verboseEnabled && portduino_config.logoutputlevel != level_trace) {
|
||||
portduino_config.logoutputlevel = level_debug;
|
||||
@@ -534,29 +517,6 @@ bool loadConfig(const char *configPath)
|
||||
portduino_config.logoutputlevel = level_error;
|
||||
}
|
||||
portduino_config.traceFilename = yamlConfig["Logging"]["TraceFile"].as<std::string>("");
|
||||
portduino_config.JSONFilename = yamlConfig["Logging"]["JSONFile"].as<std::string>("");
|
||||
portduino_config.JSONFilter = (_meshtastic_PortNum)yamlConfig["Logging"]["JSONFilter"].as<int>(0);
|
||||
if (yamlConfig["Logging"]["JSONFilter"].as<std::string>("") == "textmessage")
|
||||
portduino_config.JSONFilter = meshtastic_PortNum_TEXT_MESSAGE_APP;
|
||||
else if (yamlConfig["Logging"]["JSONFilter"].as<std::string>("") == "telemetry")
|
||||
portduino_config.JSONFilter = meshtastic_PortNum_TELEMETRY_APP;
|
||||
else if (yamlConfig["Logging"]["JSONFilter"].as<std::string>("") == "nodeinfo")
|
||||
portduino_config.JSONFilter = meshtastic_PortNum_NODEINFO_APP;
|
||||
else if (yamlConfig["Logging"]["JSONFilter"].as<std::string>("") == "position")
|
||||
portduino_config.JSONFilter = meshtastic_PortNum_POSITION_APP;
|
||||
else if (yamlConfig["Logging"]["JSONFilter"].as<std::string>("") == "waypoint")
|
||||
portduino_config.JSONFilter = meshtastic_PortNum_WAYPOINT_APP;
|
||||
else if (yamlConfig["Logging"]["JSONFilter"].as<std::string>("") == "neighborinfo")
|
||||
portduino_config.JSONFilter = meshtastic_PortNum_NEIGHBORINFO_APP;
|
||||
else if (yamlConfig["Logging"]["JSONFilter"].as<std::string>("") == "traceroute")
|
||||
portduino_config.JSONFilter = meshtastic_PortNum_TRACEROUTE_APP;
|
||||
else if (yamlConfig["Logging"]["JSONFilter"].as<std::string>("") == "detection")
|
||||
portduino_config.JSONFilter = meshtastic_PortNum_DETECTION_SENSOR_APP;
|
||||
else if (yamlConfig["Logging"]["JSONFilter"].as<std::string>("") == "paxcounter")
|
||||
portduino_config.JSONFilter = meshtastic_PortNum_PAXCOUNTER_APP;
|
||||
else if (yamlConfig["Logging"]["JSONFilter"].as<std::string>("") == "remotehardware")
|
||||
portduino_config.JSONFilter = meshtastic_PortNum_REMOTE_HARDWARE_APP;
|
||||
|
||||
if (yamlConfig["Logging"]["AsciiLogs"]) {
|
||||
// Default is !isatty(1) but can be set explicitly in config.yaml
|
||||
portduino_config.ascii_logs = yamlConfig["Logging"]["AsciiLogs"].as<bool>();
|
||||
@@ -786,6 +746,10 @@ bool loadConfig(const char *configPath)
|
||||
}
|
||||
}
|
||||
|
||||
if (yamlConfig["StoreAndForward"]) {
|
||||
portduino_config.sfpp_stratum0 = (yamlConfig["StoreAndForward"]["Stratum0"]).as<bool>(false);
|
||||
}
|
||||
|
||||
if (yamlConfig["General"]) {
|
||||
portduino_config.MaxNodes = (yamlConfig["General"]["MaxNodes"]).as<int>(200);
|
||||
portduino_config.maxtophone = (yamlConfig["General"]["MaxMessageQueue"]).as<int>(100);
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
|
||||
#include "LR11x0Interface.h"
|
||||
#include "Module.h"
|
||||
#include "mesh/generated/meshtastic/mesh.pb.h"
|
||||
#include "platform/portduino/USBHal.h"
|
||||
#include "yaml-cpp/yaml.h"
|
||||
|
||||
@@ -47,8 +46,6 @@ struct pinMapping {
|
||||
};
|
||||
|
||||
extern std::ofstream traceFile;
|
||||
extern std::ofstream JSONFile;
|
||||
|
||||
extern Ch341Hal *ch341Hal;
|
||||
int initGPIOPin(int pinNum, std::string gpioChipname, int line);
|
||||
bool loadConfig(const char *configPath);
|
||||
@@ -151,9 +148,6 @@ extern struct portduino_config_struct {
|
||||
bool ascii_logs = !isatty(1);
|
||||
bool ascii_logs_explicit = false;
|
||||
|
||||
std::string JSONFilename;
|
||||
meshtastic_PortNum JSONFilter = (_meshtastic_PortNum)0;
|
||||
|
||||
// Webserver
|
||||
std::string webserver_root_path = "";
|
||||
std::string webserver_ssl_key_path = "/etc/meshtasticd/ssl/private_key.pem";
|
||||
@@ -169,6 +163,9 @@ extern struct portduino_config_struct {
|
||||
int configDisplayMode = 0;
|
||||
bool has_configDisplayMode = false;
|
||||
|
||||
// Store and Forward++
|
||||
bool sfpp_stratum0 = false;
|
||||
|
||||
// General
|
||||
std::string mac_address = "";
|
||||
bool mac_address_explicit = false;
|
||||
@@ -419,29 +416,6 @@ extern struct portduino_config_struct {
|
||||
}
|
||||
if (traceFilename != "")
|
||||
out << YAML::Key << "TraceFile" << YAML::Value << traceFilename;
|
||||
if (JSONFilename != "") {
|
||||
out << YAML::Key << "JSONFile" << YAML::Value << JSONFilename;
|
||||
if (JSONFilter == meshtastic_PortNum_TEXT_MESSAGE_APP)
|
||||
out << YAML::Key << "JSONFilter" << YAML::Value << "textmessage";
|
||||
else if (JSONFilter == meshtastic_PortNum_TELEMETRY_APP)
|
||||
out << YAML::Key << "JSONFilter" << YAML::Value << "telemetry";
|
||||
else if (JSONFilter == meshtastic_PortNum_NODEINFO_APP)
|
||||
out << YAML::Key << "JSONFilter" << YAML::Value << "nodeinfo";
|
||||
else if (JSONFilter == meshtastic_PortNum_POSITION_APP)
|
||||
out << YAML::Key << "JSONFilter" << YAML::Value << "position";
|
||||
else if (JSONFilter == meshtastic_PortNum_WAYPOINT_APP)
|
||||
out << YAML::Key << "JSONFilter" << YAML::Value << "waypoint";
|
||||
else if (JSONFilter == meshtastic_PortNum_NEIGHBORINFO_APP)
|
||||
out << YAML::Key << "JSONFilter" << YAML::Value << "neighborinfo";
|
||||
else if (JSONFilter == meshtastic_PortNum_TRACEROUTE_APP)
|
||||
out << YAML::Key << "JSONFilter" << YAML::Value << "traceroute";
|
||||
else if (JSONFilter == meshtastic_PortNum_DETECTION_SENSOR_APP)
|
||||
out << YAML::Key << "JSONFilter" << YAML::Value << "detection";
|
||||
else if (JSONFilter == meshtastic_PortNum_PAXCOUNTER_APP)
|
||||
out << YAML::Key << "JSONFilter" << YAML::Value << "paxcounter";
|
||||
else if (JSONFilter == meshtastic_PortNum_REMOTE_HARDWARE_APP)
|
||||
out << YAML::Key << "JSONFilter" << YAML::Value << "remotehardware";
|
||||
}
|
||||
if (ascii_logs_explicit) {
|
||||
out << YAML::Key << "AsciiLogs" << YAML::Value << ascii_logs;
|
||||
}
|
||||
|
||||
@@ -605,13 +605,12 @@ void test_receiveAcksOwnSentMessages(void)
|
||||
|
||||
unitTest->publish(&p, nodeDB->getNodeId().c_str());
|
||||
|
||||
// FIXME: Better assertion for this test
|
||||
// TEST_ASSERT_TRUE(mockRouter->packets_.empty());
|
||||
// TEST_ASSERT_EQUAL(1, mockRoutingModule->ackNacks_.size());
|
||||
// const auto &[err, to, idFrom, chIndex, hopLimit] = mockRoutingModule->ackNacks_.front();
|
||||
// TEST_ASSERT_EQUAL(meshtastic_Routing_Error_NONE, err);
|
||||
// TEST_ASSERT_EQUAL(myNodeInfo.my_node_num, to);
|
||||
// TEST_ASSERT_EQUAL(p.id, idFrom);
|
||||
TEST_ASSERT_TRUE(mockRouter->packets_.empty());
|
||||
TEST_ASSERT_EQUAL(1, mockRoutingModule->ackNacks_.size());
|
||||
const auto &[err, to, idFrom, chIndex, hopLimit] = mockRoutingModule->ackNacks_.front();
|
||||
TEST_ASSERT_EQUAL(meshtastic_Routing_Error_NONE, err);
|
||||
TEST_ASSERT_EQUAL(myNodeInfo.my_node_num, to);
|
||||
TEST_ASSERT_EQUAL(p.id, idFrom);
|
||||
}
|
||||
|
||||
// Should ignore our own messages from MQTT that were heard by other nodes.
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
[env:meshtastic-dr-dev]
|
||||
extends = esp32_base
|
||||
board = esp32doit-devkit-v1
|
||||
board_level = extra
|
||||
board_upload.maximum_size = 4194304
|
||||
board_upload.maximum_ram_size = 532480
|
||||
build_flags =
|
||||
|
||||
@@ -59,7 +59,7 @@ lib_deps =
|
||||
# renovate: datasource=git-refs depName=meshtastic-esp32_https_server packageName=https://github.com/meshtastic/esp32_https_server gitBranch=master
|
||||
https://github.com/meshtastic/esp32_https_server/archive/3223704846752e6d545139204837bdb2a55459ca.zip
|
||||
# renovate: datasource=custom.pio depName=NimBLE-Arduino packageName=h2zero/library/NimBLE-Arduino
|
||||
h2zero/NimBLE-Arduino@2.3.7
|
||||
h2zero/NimBLE-Arduino@^1.4.3
|
||||
# renovate: datasource=git-refs depName=libpax packageName=https://github.com/dbinfrago/libpax gitBranch=master
|
||||
https://github.com/dbinfrago/libpax/archive/3cdc0371c375676a97967547f4065607d4c53fd1.zip
|
||||
# renovate: datasource=github-tags depName=XPowersLib packageName=lewisxhe/XPowersLib
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
[env:tbeam]
|
||||
extends = esp32_base
|
||||
board = ttgo-t-beam
|
||||
board_level = extra
|
||||
board_level = pr
|
||||
board_check = true
|
||||
lib_deps = ${esp32_base.lib_deps}
|
||||
build_flags = ${esp32_base.build_flags}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
[env:link32-s3-v1]
|
||||
extends = esp32s3_base
|
||||
board = esp32-s3-devkitc-1
|
||||
board_level = extra
|
||||
build_flags =
|
||||
${esp32_base.build_flags}
|
||||
-D LINK_32
|
||||
|
||||
@@ -45,6 +45,7 @@ build_flags = ${native_base.build_flags} -Os -lX11 -linput -lxkbcommon -ffunctio
|
||||
!pkg-config --libs openssl --silence-errors || :
|
||||
!pkg-config --cflags --libs sdl2 --silence-errors || :
|
||||
!pkg-config --cflags --libs libbsd-overlay --silence-errors || :
|
||||
!pkg-config --cflags --libs sqlite3 --silence-errors || :
|
||||
build_src_filter =
|
||||
${native_base.build_src_filter}
|
||||
|
||||
|
||||
@@ -63,20 +63,9 @@ void initVariant()
|
||||
// called from main-nrf52.cpp during the cpuDeepSleep() function
|
||||
void variant_shutdown()
|
||||
{
|
||||
digitalWrite(red_LED_PIN, HIGH);
|
||||
digitalWrite(green_LED_PIN, HIGH);
|
||||
digitalWrite(LED_BLUE, HIGH);
|
||||
|
||||
digitalWrite(PIN_EN1, LOW);
|
||||
digitalWrite(PIN_EN2, LOW);
|
||||
digitalWrite(EEPROM_POWER, LOW);
|
||||
digitalWrite(KEY_POWER, LOW);
|
||||
digitalWrite(DHT_POWER, LOW);
|
||||
digitalWrite(ACC_POWER, LOW);
|
||||
digitalWrite(Battery_POWER, LOW);
|
||||
digitalWrite(GPS_POWER, LOW);
|
||||
|
||||
// This sets the pin to OUTPUT and LOW for the pins *not* in the if block.
|
||||
for (int pin = 0; pin < 48; pin++) {
|
||||
if (pin == PIN_POWER_USB || pin == BUTTON_PIN || pin == PIN_EN1 || pin == PIN_EN2 || pin == DHT_POWER ||
|
||||
pin == ACC_POWER || pin == Battery_POWER || pin == GPS_POWER || pin == LR1110_SPI_MISO_PIN ||
|
||||
|
||||
@@ -19,6 +19,7 @@ build_type = release
|
||||
build_flags =
|
||||
-include variants/nrf52840/cpp_overrides/lfs_util.h
|
||||
${arduino_base.build_flags}
|
||||
-DSERIAL_BUFFER_SIZE=1024
|
||||
-Wno-unused-variable
|
||||
-Isrc/platform/nrf52
|
||||
-DLFS_NO_ASSERT ; Disable LFS assertions , see https://github.com/meshtastic/firmware/pull/3818
|
||||
|
||||
@@ -1,9 +1,7 @@
|
||||
[nrf52832_base]
|
||||
extends = nrf52_base
|
||||
|
||||
build_flags =
|
||||
${nrf52_base.build_flags}
|
||||
-DSERIAL_BUFFER_SIZE=1024
|
||||
build_flags = ${nrf52_base.build_flags}
|
||||
|
||||
lib_deps =
|
||||
${nrf52_base.lib_deps}
|
||||
|
||||
@@ -1,9 +1,7 @@
|
||||
[nrf52840_base]
|
||||
extends = nrf52_base
|
||||
|
||||
build_flags =
|
||||
${nrf52_base.build_flags}
|
||||
-DSERIAL_BUFFER_SIZE=4096
|
||||
build_flags = ${nrf52_base.build_flags}
|
||||
|
||||
lib_deps =
|
||||
${nrf52_base.lib_deps}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
[env:feather_rp2040_rfm95]
|
||||
extends = rp2040_base
|
||||
board = adafruit_feather
|
||||
board_level = extra
|
||||
upload_protocol = picotool
|
||||
# add our variants files to the include and src paths
|
||||
build_flags =
|
||||
|
||||
Reference in New Issue
Block a user