mirror of
https://github.com/meshtastic/firmware.git
synced 2025-09-13 06:13:35 +00:00
Merge branch 'meshtastic:master' into master
This commit is contained in:
commit
ab925529ca
14
.github/actions/setup-native/action.yml
vendored
Normal file
14
.github/actions/setup-native/action.yml
vendored
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
name: Setup native build
|
||||||
|
description: Install libraries needed for building the Native/Portduino build
|
||||||
|
|
||||||
|
runs:
|
||||||
|
using: composite
|
||||||
|
steps:
|
||||||
|
- name: Setup base
|
||||||
|
id: base
|
||||||
|
uses: ./.github/actions/setup-base
|
||||||
|
|
||||||
|
- name: Install libs needed for native build
|
||||||
|
shell: bash
|
||||||
|
run: |
|
||||||
|
sudo apt-get install -y libbluetooth-dev libgpiod-dev libyaml-cpp-dev openssl libssl-dev libulfius-dev liborcania-dev libusb-1.0-0-dev libi2c-dev
|
20
.github/workflows/build_native.yml
vendored
20
.github/workflows/build_native.yml
vendored
@ -10,12 +10,6 @@ jobs:
|
|||||||
build-native:
|
build-native:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: Install libs needed for native build
|
|
||||||
shell: bash
|
|
||||||
run: |
|
|
||||||
sudo apt-get update --fix-missing
|
|
||||||
sudo apt-get install -y libbluetooth-dev libgpiod-dev libyaml-cpp-dev openssl libssl-dev libulfius-dev liborcania-dev libusb-1.0-0-dev libi2c-dev
|
|
||||||
|
|
||||||
- name: Checkout code
|
- name: Checkout code
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v4
|
||||||
with:
|
with:
|
||||||
@ -23,17 +17,9 @@ jobs:
|
|||||||
ref: ${{github.event.pull_request.head.ref}}
|
ref: ${{github.event.pull_request.head.ref}}
|
||||||
repository: ${{github.event.pull_request.head.repo.full_name}}
|
repository: ${{github.event.pull_request.head.repo.full_name}}
|
||||||
|
|
||||||
- name: Upgrade python tools
|
- name: Setup native build
|
||||||
shell: bash
|
id: base
|
||||||
run: |
|
uses: ./.github/actions/setup-native
|
||||||
python -m pip install --upgrade pip
|
|
||||||
pip install -U platformio adafruit-nrfutil
|
|
||||||
pip install -U meshtastic --pre
|
|
||||||
|
|
||||||
- name: Upgrade platformio
|
|
||||||
shell: bash
|
|
||||||
run: |
|
|
||||||
pio upgrade
|
|
||||||
|
|
||||||
- name: Build Native
|
- name: Build Native
|
||||||
run: bin/build-native.sh
|
run: bin/build-native.sh
|
||||||
|
3
.github/workflows/main_matrix.yml
vendored
3
.github/workflows/main_matrix.yml
vendored
@ -137,6 +137,9 @@ jobs:
|
|||||||
package-native:
|
package-native:
|
||||||
uses: ./.github/workflows/package_amd64.yml
|
uses: ./.github/workflows/package_amd64.yml
|
||||||
|
|
||||||
|
test-native:
|
||||||
|
uses: ./.github/workflows/test_native.yml
|
||||||
|
|
||||||
build-docker:
|
build-docker:
|
||||||
if: ${{ github.event_name == 'workflow_dispatch' }}
|
if: ${{ github.event_name == 'workflow_dispatch' }}
|
||||||
uses: ./.github/workflows/build_docker.yml
|
uses: ./.github/workflows/build_docker.yml
|
||||||
|
169
.github/workflows/test_native.yml
vendored
Normal file
169
.github/workflows/test_native.yml
vendored
Normal file
@ -0,0 +1,169 @@
|
|||||||
|
name: Run Tests on Native platform
|
||||||
|
|
||||||
|
on:
|
||||||
|
workflow_call:
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
|
permissions: {}
|
||||||
|
|
||||||
|
env:
|
||||||
|
LCOV_CAPTURE_FLAGS: --quiet --capture --include "${PWD}/src/*" --exclude '*/src/mesh/generated/*' --directory .pio/build/coverage/src --base-directory "${PWD}"
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
simulator-tests:
|
||||||
|
name: Native Simulator Tests
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
ref: ${{github.event.pull_request.head.ref}}
|
||||||
|
repository: ${{github.event.pull_request.head.repo.full_name}}
|
||||||
|
submodules: recursive
|
||||||
|
|
||||||
|
- name: Setup native build
|
||||||
|
id: base
|
||||||
|
uses: ./.github/actions/setup-native
|
||||||
|
|
||||||
|
- name: Install simulator dependencies
|
||||||
|
run: pip install -U dotmap
|
||||||
|
|
||||||
|
# We now run integration test before other build steps (to quickly see runtime failures)
|
||||||
|
- name: Build for native/coverage
|
||||||
|
run: platformio run -e coverage
|
||||||
|
|
||||||
|
- name: Capture initial coverage information
|
||||||
|
shell: bash
|
||||||
|
run: |
|
||||||
|
sudo apt-get install -y lcov
|
||||||
|
lcov ${{ env.LCOV_CAPTURE_FLAGS }} --initial --output-file coverage_base.info
|
||||||
|
sed -i -e "s#${PWD}#.#" coverage_base.info # Make paths relative.
|
||||||
|
|
||||||
|
- name: Integration test
|
||||||
|
run: |
|
||||||
|
.pio/build/coverage/program &
|
||||||
|
PID=$!
|
||||||
|
timeout 20 bash -c "until ls -al /proc/$PID/fd | grep socket; do sleep 1; done"
|
||||||
|
echo "Simulator started, launching python test..."
|
||||||
|
python3 -c 'from meshtastic.test import testSimulator; testSimulator()'
|
||||||
|
wait
|
||||||
|
|
||||||
|
- name: Capture coverage information
|
||||||
|
if: always() # run this step even if previous step failed
|
||||||
|
run: |
|
||||||
|
lcov ${{ env.LCOV_CAPTURE_FLAGS }} --test-name integration --output-file coverage_integration.info
|
||||||
|
sed -i -e "s#${PWD}#.#" coverage_integration.info # Make paths relative.
|
||||||
|
|
||||||
|
- name: Get release version string
|
||||||
|
if: always() # run this step even if previous step failed
|
||||||
|
run: echo "version=$(./bin/buildinfo.py long)" >> $GITHUB_OUTPUT
|
||||||
|
id: version
|
||||||
|
|
||||||
|
- name: Save coverage information
|
||||||
|
uses: actions/upload-artifact@v4
|
||||||
|
if: always() # run this step even if previous step failed
|
||||||
|
with:
|
||||||
|
name: lcov-coverage-info-native-simulator-test-${{ steps.version.outputs.version }}.zip
|
||||||
|
overwrite: true
|
||||||
|
path: ./coverage_*.info
|
||||||
|
|
||||||
|
platformio-tests:
|
||||||
|
name: Native PlatformIO Tests
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
ref: ${{github.event.pull_request.head.ref}}
|
||||||
|
repository: ${{github.event.pull_request.head.repo.full_name}}
|
||||||
|
submodules: recursive
|
||||||
|
|
||||||
|
- name: Setup native build
|
||||||
|
id: base
|
||||||
|
uses: ./.github/actions/setup-native
|
||||||
|
|
||||||
|
- name: Get release version string
|
||||||
|
run: echo "version=$(./bin/buildinfo.py long)" >> $GITHUB_OUTPUT
|
||||||
|
id: version
|
||||||
|
|
||||||
|
# Disable (comment-out) BUILD_EPOCH. It causes a full rebuild between tests and resets the
|
||||||
|
# coverage information each time.
|
||||||
|
- name: Disable BUILD_EPOCH
|
||||||
|
run: sed -i 's/-DBUILD_EPOCH=$UNIX_TIME/#-DBUILD_EPOCH=$UNIX_TIME/' platformio.ini
|
||||||
|
|
||||||
|
- name: PlatformIO Tests
|
||||||
|
run: platformio test -e coverage --junit-output-path testreport.xml
|
||||||
|
|
||||||
|
- name: Save test results
|
||||||
|
if: always() # run this step even if previous step failed
|
||||||
|
uses: actions/upload-artifact@v4
|
||||||
|
with:
|
||||||
|
name: platformio-test-report-${{ steps.version.outputs.version }}.zip
|
||||||
|
overwrite: true
|
||||||
|
path: ./testreport.xml
|
||||||
|
|
||||||
|
- name: Capture coverage information
|
||||||
|
if: always() # run this step even if previous step failed
|
||||||
|
run: |
|
||||||
|
sudo apt-get install -y lcov
|
||||||
|
lcov ${{ env.LCOV_CAPTURE_FLAGS }} --test-name tests --output-file coverage_tests.info
|
||||||
|
sed -i -e "s#${PWD}#.#" coverage_tests.info # Make paths relative.
|
||||||
|
|
||||||
|
- name: Save coverage information
|
||||||
|
uses: actions/upload-artifact@v4
|
||||||
|
if: always() # run this step even if previous step failed
|
||||||
|
with:
|
||||||
|
name: lcov-coverage-info-native-platformio-tests-${{ steps.version.outputs.version }}.zip
|
||||||
|
overwrite: true
|
||||||
|
path: ./coverage_*.info
|
||||||
|
|
||||||
|
generate-reports:
|
||||||
|
name: Generate Test Reports
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
permissions: # Needed for dorny/test-reporter.
|
||||||
|
contents: read
|
||||||
|
actions: read
|
||||||
|
checks: write
|
||||||
|
needs:
|
||||||
|
- simulator-tests
|
||||||
|
- platformio-tests
|
||||||
|
if: always()
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
ref: ${{github.event.pull_request.head.ref}}
|
||||||
|
repository: ${{github.event.pull_request.head.repo.full_name}}
|
||||||
|
|
||||||
|
- name: Get release version string
|
||||||
|
run: echo "version=$(./bin/buildinfo.py long)" >> $GITHUB_OUTPUT
|
||||||
|
id: version
|
||||||
|
|
||||||
|
- name: Download test artifacts
|
||||||
|
uses: actions/download-artifact@v4
|
||||||
|
with:
|
||||||
|
name: platformio-test-report-${{ steps.version.outputs.version }}.zip
|
||||||
|
merge-multiple: true
|
||||||
|
|
||||||
|
- name: Test Report
|
||||||
|
uses: dorny/test-reporter@v1.9.1
|
||||||
|
with:
|
||||||
|
name: PlatformIO Tests
|
||||||
|
path: testreport.xml
|
||||||
|
reporter: java-junit
|
||||||
|
|
||||||
|
- name: Download coverage artifacts
|
||||||
|
uses: actions/download-artifact@v4
|
||||||
|
with:
|
||||||
|
pattern: lcov-coverage-info-native-*-${{ steps.version.outputs.version }}.zip
|
||||||
|
path: code-coverage-report
|
||||||
|
merge-multiple: true
|
||||||
|
|
||||||
|
- name: Generate Code Coverage Report
|
||||||
|
run: |
|
||||||
|
sudo apt-get install -y lcov
|
||||||
|
lcov --quiet --add-tracefile code-coverage-report/coverage_base.info --add-tracefile code-coverage-report/coverage_integration.info --add-tracefile code-coverage-report/coverage_tests.info --output-file code-coverage-report/coverage_src.info
|
||||||
|
genhtml --quiet --legend --prefix "${PWD}" code-coverage-report/coverage_src.info --output-directory code-coverage-report
|
||||||
|
|
||||||
|
- name: Save Code Coverage Report
|
||||||
|
uses: actions/upload-artifact@v4
|
||||||
|
with:
|
||||||
|
name: code-coverage-report-${{ steps.version.outputs.version }}.zip
|
||||||
|
path: code-coverage-report
|
75
.github/workflows/tests.yml
vendored
75
.github/workflows/tests.yml
vendored
@ -6,79 +6,8 @@ on:
|
|||||||
workflow_dispatch: {}
|
workflow_dispatch: {}
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
test-simulator:
|
native-tests:
|
||||||
runs-on: ubuntu-latest
|
uses: ./.github/workflows/test_native.yml
|
||||||
env:
|
|
||||||
LCOV_CAPTURE_FLAGS: --quiet --capture --include "${PWD}/src/*" --exclude '*/src/mesh/generated/*' --directory .pio/build/coverage/src --base-directory "${PWD}"
|
|
||||||
steps:
|
|
||||||
- name: Install libs needed for native build
|
|
||||||
shell: bash
|
|
||||||
run: |
|
|
||||||
sudo apt-get update --fix-missing
|
|
||||||
sudo apt-get install -y libbluetooth-dev libgpiod-dev libyaml-cpp-dev openssl libssl-dev libulfius-dev liborcania-dev libusb-1.0-0-dev libi2c-dev
|
|
||||||
sudo apt-get install -y lcov
|
|
||||||
|
|
||||||
- name: Checkout code
|
|
||||||
uses: actions/checkout@v4
|
|
||||||
with:
|
|
||||||
submodules: recursive
|
|
||||||
|
|
||||||
- name: Upgrade python tools
|
|
||||||
shell: bash
|
|
||||||
run: |
|
|
||||||
python -m pip install --upgrade pip
|
|
||||||
pip install -U platformio adafruit-nrfutil dotmap
|
|
||||||
pip install -U meshtastic --pre
|
|
||||||
|
|
||||||
- name: Upgrade platformio
|
|
||||||
shell: bash
|
|
||||||
run: |
|
|
||||||
pio upgrade
|
|
||||||
|
|
||||||
- name: Build Native
|
|
||||||
run: bin/build-native.sh
|
|
||||||
|
|
||||||
# We now run integration test before other build steps (to quickly see runtime failures)
|
|
||||||
- name: Build for native/coverage
|
|
||||||
run: |
|
|
||||||
platformio run -e coverage
|
|
||||||
lcov ${{ env.LCOV_CAPTURE_FLAGS }} --initial --output-file coverage_base.info
|
|
||||||
|
|
||||||
- name: Integration test
|
|
||||||
run: |
|
|
||||||
.pio/build/coverage/program &
|
|
||||||
PID=$!
|
|
||||||
timeout 20 bash -c "until ls -al /proc/$PID/fd | grep socket; do sleep 1; done"
|
|
||||||
echo "Simulator started, launching python test..."
|
|
||||||
python3 -c 'from meshtastic.test import testSimulator; testSimulator()'
|
|
||||||
wait
|
|
||||||
lcov ${{ env.LCOV_CAPTURE_FLAGS }} --test-name integration --output-file coverage_integration.info
|
|
||||||
|
|
||||||
- name: PlatformIO Tests
|
|
||||||
run: |
|
|
||||||
platformio test -e coverage --junit-output-path testreport.xml
|
|
||||||
lcov ${{ env.LCOV_CAPTURE_FLAGS }} --test-name tests --output-file coverage_tests.info
|
|
||||||
|
|
||||||
- name: Test Report
|
|
||||||
uses: dorny/test-reporter@v1.9.1
|
|
||||||
if: success() || failure() # run this step even if previous step failed
|
|
||||||
with:
|
|
||||||
name: PlatformIO Tests
|
|
||||||
path: testreport.xml
|
|
||||||
reporter: java-junit
|
|
||||||
|
|
||||||
- name: Generate Code Coverage Report
|
|
||||||
run: |
|
|
||||||
lcov --quiet --add-tracefile coverage_base.info --add-tracefile coverage_integration.info --add-tracefile coverage_tests.info --output-file coverage_src.info
|
|
||||||
mkdir code-coverage-report
|
|
||||||
genhtml --quiet --legend --prefix "${PWD}" coverage_src.info --output-directory code-coverage-report
|
|
||||||
mv coverage_*.info code-coverage-report
|
|
||||||
|
|
||||||
- name: Save Code Coverage Report
|
|
||||||
uses: actions/upload-artifact@v4
|
|
||||||
with:
|
|
||||||
name: code-coverage-report
|
|
||||||
path: code-coverage-report
|
|
||||||
|
|
||||||
hardware-tests:
|
hardware-tests:
|
||||||
runs-on: test-runner
|
runs-on: test-runner
|
||||||
|
@ -124,7 +124,8 @@ lib_deps =
|
|||||||
|
|
||||||
[radiolib_base]
|
[radiolib_base]
|
||||||
lib_deps =
|
lib_deps =
|
||||||
jgromes/RadioLib@7.1.0
|
; jgromes/RadioLib@7.1.0
|
||||||
|
https://github.com/jgromes/RadioLib.git#92b687821ff4e6c358d866f84566f66672ab02b8
|
||||||
|
|
||||||
; Common libs for environmental measurements in telemetry module
|
; Common libs for environmental measurements in telemetry module
|
||||||
; (not included in native / portduino)
|
; (not included in native / portduino)
|
||||||
|
@ -9,6 +9,7 @@
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
#include "FSCommon.h"
|
#include "FSCommon.h"
|
||||||
|
#include "SPILock.h"
|
||||||
#include "configuration.h"
|
#include "configuration.h"
|
||||||
|
|
||||||
#ifdef HAS_SDCARD
|
#ifdef HAS_SDCARD
|
||||||
@ -102,6 +103,8 @@ bool copyFile(const char *from, const char *to)
|
|||||||
return true;
|
return true;
|
||||||
|
|
||||||
#elif defined(FSCom)
|
#elif defined(FSCom)
|
||||||
|
// take SPI Lock
|
||||||
|
concurrency::LockGuard g(spiLock);
|
||||||
unsigned char cbuffer[16];
|
unsigned char cbuffer[16];
|
||||||
|
|
||||||
File f1 = FSCom.open(from, FILE_O_READ);
|
File f1 = FSCom.open(from, FILE_O_READ);
|
||||||
@ -145,16 +148,23 @@ bool renameFile(const char *pathFrom, const char *pathTo)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
#elif defined(FSCom)
|
#elif defined(FSCom)
|
||||||
|
|
||||||
#ifdef ARCH_ESP32
|
#ifdef ARCH_ESP32
|
||||||
|
// take SPI Lock
|
||||||
|
spiLock->lock();
|
||||||
// rename was fixed for ESP32 IDF LittleFS in April
|
// rename was fixed for ESP32 IDF LittleFS in April
|
||||||
return FSCom.rename(pathFrom, pathTo);
|
bool result = FSCom.rename(pathFrom, pathTo);
|
||||||
|
spiLock->unlock();
|
||||||
|
return result;
|
||||||
#else
|
#else
|
||||||
|
// copyFile does its own locking.
|
||||||
if (copyFile(pathFrom, pathTo) && FSCom.remove(pathFrom)) {
|
if (copyFile(pathFrom, pathTo) && FSCom.remove(pathFrom)) {
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -164,6 +174,7 @@ bool renameFile(const char *pathFrom, const char *pathTo)
|
|||||||
* @brief Get the list of files in a directory.
|
* @brief Get the list of files in a directory.
|
||||||
*
|
*
|
||||||
* This function returns a list of files in a directory. The list includes the full path of each file.
|
* This function returns a list of files in a directory. The list includes the full path of each file.
|
||||||
|
* We can't use SPILOCK here because of recursion. Callers of this function should use SPILOCK.
|
||||||
*
|
*
|
||||||
* @param dirname The name of the directory.
|
* @param dirname The name of the directory.
|
||||||
* @param levels The number of levels of subdirectories to list.
|
* @param levels The number of levels of subdirectories to list.
|
||||||
@ -212,6 +223,7 @@ std::vector<meshtastic_FileInfo> getFiles(const char *dirname, uint8_t levels)
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Lists the contents of a directory.
|
* Lists the contents of a directory.
|
||||||
|
* We can't use SPILOCK here because of recursion. Callers of this function should use SPILOCK.
|
||||||
*
|
*
|
||||||
* @param dirname The name of the directory to list.
|
* @param dirname The name of the directory to list.
|
||||||
* @param levels The number of levels of subdirectories to list.
|
* @param levels The number of levels of subdirectories to list.
|
||||||
@ -325,18 +337,21 @@ void listDir(const char *dirname, uint8_t levels, bool del)
|
|||||||
void rmDir(const char *dirname)
|
void rmDir(const char *dirname)
|
||||||
{
|
{
|
||||||
#ifdef FSCom
|
#ifdef FSCom
|
||||||
|
|
||||||
#if (defined(ARCH_ESP32) || defined(ARCH_RP2040) || defined(ARCH_PORTDUINO))
|
#if (defined(ARCH_ESP32) || defined(ARCH_RP2040) || defined(ARCH_PORTDUINO))
|
||||||
listDir(dirname, 10, true);
|
listDir(dirname, 10, true);
|
||||||
#elif defined(ARCH_NRF52)
|
#elif defined(ARCH_NRF52)
|
||||||
// nRF52 implementation of LittleFS has a recursive delete function
|
// nRF52 implementation of LittleFS has a recursive delete function
|
||||||
FSCom.rmdir_r(dirname);
|
FSCom.rmdir_r(dirname);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void fsInit()
|
void fsInit()
|
||||||
{
|
{
|
||||||
#ifdef FSCom
|
#ifdef FSCom
|
||||||
|
spiLock->lock();
|
||||||
if (!FSBegin()) {
|
if (!FSBegin()) {
|
||||||
LOG_ERROR("Filesystem mount failed");
|
LOG_ERROR("Filesystem mount failed");
|
||||||
// assert(0); This auto-formats the partition, so no need to fail here.
|
// assert(0); This auto-formats the partition, so no need to fail here.
|
||||||
@ -347,6 +362,7 @@ void fsInit()
|
|||||||
LOG_DEBUG("Filesystem files:");
|
LOG_DEBUG("Filesystem files:");
|
||||||
#endif
|
#endif
|
||||||
listDir("/", 10);
|
listDir("/", 10);
|
||||||
|
spiLock->unlock();
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -356,6 +372,7 @@ void fsInit()
|
|||||||
void setupSDCard()
|
void setupSDCard()
|
||||||
{
|
{
|
||||||
#ifdef HAS_SDCARD
|
#ifdef HAS_SDCARD
|
||||||
|
concurrency::LockGuard g(spiLock);
|
||||||
SDHandler.begin(SPI_SCK, SPI_MISO, SPI_MOSI);
|
SDHandler.begin(SPI_SCK, SPI_MISO, SPI_MOSI);
|
||||||
|
|
||||||
if (!SD.begin(SDCARD_CS, SDHandler)) {
|
if (!SD.begin(SDCARD_CS, SDHandler)) {
|
||||||
|
@ -5,6 +5,7 @@
|
|||||||
// Only way to work on both esp32 and nrf52
|
// Only way to work on both esp32 and nrf52
|
||||||
static File openFile(const char *filename, bool fullAtomic)
|
static File openFile(const char *filename, bool fullAtomic)
|
||||||
{
|
{
|
||||||
|
concurrency::LockGuard g(spiLock);
|
||||||
if (!fullAtomic)
|
if (!fullAtomic)
|
||||||
FSCom.remove(filename); // Nuke the old file to make space (ignore if it !exists)
|
FSCom.remove(filename); // Nuke the old file to make space (ignore if it !exists)
|
||||||
|
|
||||||
@ -53,15 +54,20 @@ bool SafeFile::close()
|
|||||||
if (!f)
|
if (!f)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
spiLock->lock();
|
||||||
f.close();
|
f.close();
|
||||||
|
spiLock->unlock();
|
||||||
if (!testReadback())
|
if (!testReadback())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
{ // Scope for lock
|
||||||
|
concurrency::LockGuard g(spiLock);
|
||||||
// brief window of risk here ;-)
|
// brief window of risk here ;-)
|
||||||
if (fullAtomic && FSCom.exists(filename.c_str()) && !FSCom.remove(filename.c_str())) {
|
if (fullAtomic && FSCom.exists(filename.c_str()) && !FSCom.remove(filename.c_str())) {
|
||||||
LOG_ERROR("Can't remove old pref file");
|
LOG_ERROR("Can't remove old pref file");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
String filenameTmp = filename;
|
String filenameTmp = filename;
|
||||||
filenameTmp += ".tmp";
|
filenameTmp += ".tmp";
|
||||||
@ -76,6 +82,7 @@ bool SafeFile::close()
|
|||||||
/// Read our (closed) tempfile back in and compare the hash
|
/// Read our (closed) tempfile back in and compare the hash
|
||||||
bool SafeFile::testReadback()
|
bool SafeFile::testReadback()
|
||||||
{
|
{
|
||||||
|
concurrency::LockGuard g(spiLock);
|
||||||
bool lfs_failed = lfs_assert_failed;
|
bool lfs_failed = lfs_assert_failed;
|
||||||
lfs_assert_failed = false;
|
lfs_assert_failed = false;
|
||||||
|
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "FSCommon.h"
|
#include "FSCommon.h"
|
||||||
|
#include "SPILock.h"
|
||||||
#include "configuration.h"
|
#include "configuration.h"
|
||||||
|
|
||||||
#ifdef FSCom
|
#ifdef FSCom
|
||||||
|
@ -178,13 +178,6 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|||||||
#define TCA9535_ADDR 0x20
|
#define TCA9535_ADDR 0x20
|
||||||
#define TCA9555_ADDR 0x26
|
#define TCA9555_ADDR 0x26
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
|
||||||
// GPS
|
|
||||||
// -----------------------------------------------------------------------------
|
|
||||||
#ifndef GPS_THREAD_INTERVAL
|
|
||||||
#define GPS_THREAD_INTERVAL 200
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
// Touchscreen
|
// Touchscreen
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
@ -206,6 +199,10 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|||||||
#define VEXT_ON_VALUE LOW
|
#define VEXT_ON_VALUE LOW
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
// GPS
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
|
||||||
#ifndef GPS_BAUDRATE
|
#ifndef GPS_BAUDRATE
|
||||||
#define GPS_BAUDRATE 9600
|
#define GPS_BAUDRATE 9600
|
||||||
#define GPS_BAUDRATE_FIXED 0
|
#define GPS_BAUDRATE_FIXED 0
|
||||||
@ -213,6 +210,10 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|||||||
#define GPS_BAUDRATE_FIXED 1
|
#define GPS_BAUDRATE_FIXED 1
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifndef GPS_THREAD_INTERVAL
|
||||||
|
#define GPS_THREAD_INTERVAL 200
|
||||||
|
#endif
|
||||||
|
|
||||||
/* Step #2: follow with defines common to the architecture;
|
/* Step #2: follow with defines common to the architecture;
|
||||||
also enable HAS_ option not specifically disabled by variant.h */
|
also enable HAS_ option not specifically disabled by variant.h */
|
||||||
#include "architecture.h"
|
#include "architecture.h"
|
||||||
|
@ -364,6 +364,8 @@ void setup()
|
|||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
initSPI();
|
||||||
|
|
||||||
OSThread::setup();
|
OSThread::setup();
|
||||||
|
|
||||||
ledPeriodic = new Periodic("Blink", ledBlinker);
|
ledPeriodic = new Periodic("Blink", ledBlinker);
|
||||||
@ -640,8 +642,6 @@ void setup()
|
|||||||
rp2040Setup();
|
rp2040Setup();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
initSPI(); // needed here before reading from littleFS
|
|
||||||
|
|
||||||
// We do this as early as possible because this loads preferences from flash
|
// We do this as early as possible because this loads preferences from flash
|
||||||
// but we need to do this after main cpu init (esp32setup), because we need the random seed set
|
// but we need to do this after main cpu init (esp32setup), because we need the random seed set
|
||||||
nodeDB = new NodeDB;
|
nodeDB = new NodeDB;
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
#include "NodeDB.h"
|
#include "NodeDB.h"
|
||||||
#include "configuration.h"
|
#include "configuration.h"
|
||||||
#include "modules/RoutingModule.h"
|
#include "modules/RoutingModule.h"
|
||||||
|
#include <algorithm>
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
|
|
||||||
std::vector<MeshModule *> *MeshModule::modules;
|
std::vector<MeshModule *> *MeshModule::modules;
|
||||||
@ -29,7 +30,9 @@ void MeshModule::setup() {}
|
|||||||
|
|
||||||
MeshModule::~MeshModule()
|
MeshModule::~MeshModule()
|
||||||
{
|
{
|
||||||
assert(0); // FIXME - remove from list of modules once someone needs this feature
|
auto it = std::find(modules->begin(), modules->end(), this);
|
||||||
|
assert(it != modules->end());
|
||||||
|
modules->erase(it);
|
||||||
}
|
}
|
||||||
|
|
||||||
meshtastic_MeshPacket *MeshModule::allocAckNak(meshtastic_Routing_Error err, NodeNum to, PacketId idFrom, ChannelIndex chIndex,
|
meshtastic_MeshPacket *MeshModule::allocAckNak(meshtastic_Routing_Error err, NodeNum to, PacketId idFrom, ChannelIndex chIndex,
|
||||||
|
@ -13,6 +13,7 @@
|
|||||||
#include "PowerFSM.h"
|
#include "PowerFSM.h"
|
||||||
#include "RTC.h"
|
#include "RTC.h"
|
||||||
#include "Router.h"
|
#include "Router.h"
|
||||||
|
#include "SPILock.h"
|
||||||
#include "SafeFile.h"
|
#include "SafeFile.h"
|
||||||
#include "TypeConversions.h"
|
#include "TypeConversions.h"
|
||||||
#include "error.h"
|
#include "error.h"
|
||||||
@ -423,12 +424,15 @@ bool NodeDB::factoryReset(bool eraseBleBonds)
|
|||||||
{
|
{
|
||||||
LOG_INFO("Perform factory reset!");
|
LOG_INFO("Perform factory reset!");
|
||||||
// first, remove the "/prefs" (this removes most prefs)
|
// first, remove the "/prefs" (this removes most prefs)
|
||||||
rmDir("/prefs");
|
spiLock->lock();
|
||||||
|
rmDir("/prefs"); // this uses spilock internally...
|
||||||
|
|
||||||
#ifdef FSCom
|
#ifdef FSCom
|
||||||
if (FSCom.exists("/static/rangetest.csv") && !FSCom.remove("/static/rangetest.csv")) {
|
if (FSCom.exists("/static/rangetest.csv") && !FSCom.remove("/static/rangetest.csv")) {
|
||||||
LOG_ERROR("Could not remove rangetest.csv file");
|
LOG_ERROR("Could not remove rangetest.csv file");
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
spiLock->unlock();
|
||||||
// second, install default state (this will deal with the duplicate mac address issue)
|
// second, install default state (this will deal with the duplicate mac address issue)
|
||||||
installDefaultDeviceState();
|
installDefaultDeviceState();
|
||||||
installDefaultConfig(!eraseBleBonds); // Also preserve the private key if we're not erasing BLE bonds
|
installDefaultConfig(!eraseBleBonds); // Also preserve the private key if we're not erasing BLE bonds
|
||||||
@ -913,6 +917,7 @@ LoadFileResult NodeDB::loadProto(const char *filename, size_t protoSize, size_t
|
|||||||
{
|
{
|
||||||
LoadFileResult state = LoadFileResult::OTHER_FAILURE;
|
LoadFileResult state = LoadFileResult::OTHER_FAILURE;
|
||||||
#ifdef FSCom
|
#ifdef FSCom
|
||||||
|
concurrency::LockGuard g(spiLock);
|
||||||
|
|
||||||
auto f = FSCom.open(filename, FILE_O_READ);
|
auto f = FSCom.open(filename, FILE_O_READ);
|
||||||
|
|
||||||
@ -946,8 +951,10 @@ void NodeDB::loadFromDisk()
|
|||||||
// disk we will still factoryReset to restore things.
|
// disk we will still factoryReset to restore things.
|
||||||
|
|
||||||
#ifdef ARCH_ESP32
|
#ifdef ARCH_ESP32
|
||||||
|
spiLock->lock();
|
||||||
if (FSCom.exists("/static/static"))
|
if (FSCom.exists("/static/static"))
|
||||||
rmDir("/static/static"); // Remove bad static web files bundle from initial 2.5.13 release
|
rmDir("/static/static"); // Remove bad static web files bundle from initial 2.5.13 release
|
||||||
|
spiLock->unlock();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// static DeviceState scratch; We no longer read into a tempbuf because this structure is 15KB of valuable RAM
|
// static DeviceState scratch; We no longer read into a tempbuf because this structure is 15KB of valuable RAM
|
||||||
@ -1097,9 +1104,6 @@ void NodeDB::loadFromDisk()
|
|||||||
bool NodeDB::saveProto(const char *filename, size_t protoSize, const pb_msgdesc_t *fields, const void *dest_struct,
|
bool NodeDB::saveProto(const char *filename, size_t protoSize, const pb_msgdesc_t *fields, const void *dest_struct,
|
||||||
bool fullAtomic)
|
bool fullAtomic)
|
||||||
{
|
{
|
||||||
#ifdef ARCH_ESP32
|
|
||||||
concurrency::LockGuard g(spiLock);
|
|
||||||
#endif
|
|
||||||
bool okay = false;
|
bool okay = false;
|
||||||
#ifdef FSCom
|
#ifdef FSCom
|
||||||
auto f = SafeFile(filename, fullAtomic);
|
auto f = SafeFile(filename, fullAtomic);
|
||||||
@ -1127,7 +1131,9 @@ bool NodeDB::saveProto(const char *filename, size_t protoSize, const pb_msgdesc_
|
|||||||
bool NodeDB::saveChannelsToDisk()
|
bool NodeDB::saveChannelsToDisk()
|
||||||
{
|
{
|
||||||
#ifdef FSCom
|
#ifdef FSCom
|
||||||
|
spiLock->lock();
|
||||||
FSCom.mkdir("/prefs");
|
FSCom.mkdir("/prefs");
|
||||||
|
spiLock->unlock();
|
||||||
#endif
|
#endif
|
||||||
return saveProto(channelFileName, meshtastic_ChannelFile_size, &meshtastic_ChannelFile_msg, &channelFile);
|
return saveProto(channelFileName, meshtastic_ChannelFile_size, &meshtastic_ChannelFile_msg, &channelFile);
|
||||||
}
|
}
|
||||||
@ -1135,7 +1141,9 @@ bool NodeDB::saveChannelsToDisk()
|
|||||||
bool NodeDB::saveDeviceStateToDisk()
|
bool NodeDB::saveDeviceStateToDisk()
|
||||||
{
|
{
|
||||||
#ifdef FSCom
|
#ifdef FSCom
|
||||||
|
spiLock->lock();
|
||||||
FSCom.mkdir("/prefs");
|
FSCom.mkdir("/prefs");
|
||||||
|
spiLock->unlock();
|
||||||
#endif
|
#endif
|
||||||
// Note: if MAX_NUM_NODES=100 and meshtastic_NodeInfoLite_size=166, so will be approximately 17KB
|
// 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
|
// Because so huge we _must_ not use fullAtomic, because the filesystem is probably too small to hold two copies of this
|
||||||
@ -1148,7 +1156,9 @@ bool NodeDB::saveToDiskNoRetry(int saveWhat)
|
|||||||
bool success = true;
|
bool success = true;
|
||||||
|
|
||||||
#ifdef FSCom
|
#ifdef FSCom
|
||||||
|
spiLock->lock();
|
||||||
FSCom.mkdir("/prefs");
|
FSCom.mkdir("/prefs");
|
||||||
|
spiLock->unlock();
|
||||||
#endif
|
#endif
|
||||||
if (saveWhat & SEGMENT_CONFIG) {
|
if (saveWhat & SEGMENT_CONFIG) {
|
||||||
config.has_device = true;
|
config.has_device = true;
|
||||||
@ -1199,7 +1209,9 @@ bool NodeDB::saveToDisk(int saveWhat)
|
|||||||
if (!success) {
|
if (!success) {
|
||||||
LOG_ERROR("Failed to save to disk, retrying");
|
LOG_ERROR("Failed to save to disk, retrying");
|
||||||
#ifdef ARCH_NRF52 // @geeksville is not ready yet to say we should do this on other platforms. See bug #4184 discussion
|
#ifdef ARCH_NRF52 // @geeksville is not ready yet to say we should do this on other platforms. See bug #4184 discussion
|
||||||
|
spiLock->lock();
|
||||||
FSCom.format();
|
FSCom.format();
|
||||||
|
spiLock->unlock();
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
success = saveToDiskNoRetry(saveWhat);
|
success = saveToDiskNoRetry(saveWhat);
|
||||||
|
@ -12,6 +12,7 @@
|
|||||||
#include "PhoneAPI.h"
|
#include "PhoneAPI.h"
|
||||||
#include "PowerFSM.h"
|
#include "PowerFSM.h"
|
||||||
#include "RadioInterface.h"
|
#include "RadioInterface.h"
|
||||||
|
#include "SPILock.h"
|
||||||
#include "TypeConversions.h"
|
#include "TypeConversions.h"
|
||||||
#include "main.h"
|
#include "main.h"
|
||||||
#include "xmodem.h"
|
#include "xmodem.h"
|
||||||
@ -54,7 +55,9 @@ void PhoneAPI::handleStartConfig()
|
|||||||
// even if we were already connected - restart our state machine
|
// even if we were already connected - restart our state machine
|
||||||
state = STATE_SEND_MY_INFO;
|
state = STATE_SEND_MY_INFO;
|
||||||
pauseBluetoothLogging = true;
|
pauseBluetoothLogging = true;
|
||||||
|
spiLock->lock();
|
||||||
filesManifest = getFiles("/", 10);
|
filesManifest = getFiles("/", 10);
|
||||||
|
spiLock->unlock();
|
||||||
LOG_DEBUG("Got %d files in manifest", filesManifest.size());
|
LOG_DEBUG("Got %d files in manifest", filesManifest.size());
|
||||||
|
|
||||||
LOG_INFO("Start API client config");
|
LOG_INFO("Start API client config");
|
||||||
|
@ -66,8 +66,9 @@ static int32_t reconnectETH()
|
|||||||
syslog.enable();
|
syslog.enable();
|
||||||
}
|
}
|
||||||
|
|
||||||
// initWebServer();
|
#if !MESHTASTIC_EXCLUDE_SOCKETAPI
|
||||||
initApiServer();
|
initApiServer();
|
||||||
|
#endif
|
||||||
|
|
||||||
ethStartupComplete = true;
|
ethStartupComplete = true;
|
||||||
}
|
}
|
||||||
|
@ -10,6 +10,7 @@
|
|||||||
#include "mesh/wifi/WiFiAPClient.h"
|
#include "mesh/wifi/WiFiAPClient.h"
|
||||||
#endif
|
#endif
|
||||||
#include "Led.h"
|
#include "Led.h"
|
||||||
|
#include "SPILock.h"
|
||||||
#include "power.h"
|
#include "power.h"
|
||||||
#include "serialization/JSON.h"
|
#include "serialization/JSON.h"
|
||||||
#include <FSCommon.h>
|
#include <FSCommon.h>
|
||||||
@ -236,6 +237,7 @@ void handleAPIv1ToRadio(HTTPRequest *req, HTTPResponse *res)
|
|||||||
|
|
||||||
void htmlDeleteDir(const char *dirname)
|
void htmlDeleteDir(const char *dirname)
|
||||||
{
|
{
|
||||||
|
|
||||||
File root = FSCom.open(dirname);
|
File root = FSCom.open(dirname);
|
||||||
if (!root) {
|
if (!root) {
|
||||||
return;
|
return;
|
||||||
@ -318,6 +320,7 @@ void handleFsBrowseStatic(HTTPRequest *req, HTTPResponse *res)
|
|||||||
res->setHeader("Access-Control-Allow-Origin", "*");
|
res->setHeader("Access-Control-Allow-Origin", "*");
|
||||||
res->setHeader("Access-Control-Allow-Methods", "GET");
|
res->setHeader("Access-Control-Allow-Methods", "GET");
|
||||||
|
|
||||||
|
concurrency::LockGuard g(spiLock);
|
||||||
auto fileList = htmlListDir("/static", 10);
|
auto fileList = htmlListDir("/static", 10);
|
||||||
|
|
||||||
// create json output structure
|
// create json output structure
|
||||||
@ -349,9 +352,12 @@ void handleFsDeleteStatic(HTTPRequest *req, HTTPResponse *res)
|
|||||||
res->setHeader("Content-Type", "application/json");
|
res->setHeader("Content-Type", "application/json");
|
||||||
res->setHeader("Access-Control-Allow-Origin", "*");
|
res->setHeader("Access-Control-Allow-Origin", "*");
|
||||||
res->setHeader("Access-Control-Allow-Methods", "DELETE");
|
res->setHeader("Access-Control-Allow-Methods", "DELETE");
|
||||||
|
|
||||||
if (params->getQueryParameter("delete", paramValDelete)) {
|
if (params->getQueryParameter("delete", paramValDelete)) {
|
||||||
std::string pathDelete = "/" + paramValDelete;
|
std::string pathDelete = "/" + paramValDelete;
|
||||||
|
concurrency::LockGuard g(spiLock);
|
||||||
if (FSCom.remove(pathDelete.c_str())) {
|
if (FSCom.remove(pathDelete.c_str())) {
|
||||||
|
|
||||||
LOG_INFO("%s", pathDelete.c_str());
|
LOG_INFO("%s", pathDelete.c_str());
|
||||||
JSONObject jsonObjOuter;
|
JSONObject jsonObjOuter;
|
||||||
jsonObjOuter["status"] = new JSONValue("ok");
|
jsonObjOuter["status"] = new JSONValue("ok");
|
||||||
@ -360,6 +366,7 @@ void handleFsDeleteStatic(HTTPRequest *req, HTTPResponse *res)
|
|||||||
delete value;
|
delete value;
|
||||||
return;
|
return;
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
LOG_INFO("%s", pathDelete.c_str());
|
LOG_INFO("%s", pathDelete.c_str());
|
||||||
JSONObject jsonObjOuter;
|
JSONObject jsonObjOuter;
|
||||||
jsonObjOuter["status"] = new JSONValue("Error");
|
jsonObjOuter["status"] = new JSONValue("Error");
|
||||||
@ -393,6 +400,8 @@ void handleStatic(HTTPRequest *req, HTTPResponse *res)
|
|||||||
filenameGzip = "/static/index.html.gz";
|
filenameGzip = "/static/index.html.gz";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
concurrency::LockGuard g(spiLock);
|
||||||
|
|
||||||
if (FSCom.exists(filename.c_str())) {
|
if (FSCom.exists(filename.c_str())) {
|
||||||
file = FSCom.open(filename.c_str());
|
file = FSCom.open(filename.c_str());
|
||||||
if (!file.available()) {
|
if (!file.available()) {
|
||||||
@ -410,6 +419,7 @@ void handleStatic(HTTPRequest *req, HTTPResponse *res)
|
|||||||
file = FSCom.open(filenameGzip.c_str());
|
file = FSCom.open(filenameGzip.c_str());
|
||||||
res->setHeader("Content-Type", "text/html");
|
res->setHeader("Content-Type", "text/html");
|
||||||
if (!file.available()) {
|
if (!file.available()) {
|
||||||
|
|
||||||
LOG_WARN("File not available - %s", filenameGzip.c_str());
|
LOG_WARN("File not available - %s", filenameGzip.c_str());
|
||||||
res->println("Web server is running.<br><br>The content you are looking for can't be found. Please see: <a "
|
res->println("Web server is running.<br><br>The content you are looking for can't be found. Please see: <a "
|
||||||
"href=https://meshtastic.org/docs/software/web-client/>FAQ</a>.<br><br><a "
|
"href=https://meshtastic.org/docs/software/web-client/>FAQ</a>.<br><br><a "
|
||||||
@ -535,6 +545,7 @@ void handleFormUpload(HTTPRequest *req, HTTPResponse *res)
|
|||||||
// concepts of the body parser functionality easier to understand.
|
// concepts of the body parser functionality easier to understand.
|
||||||
std::string pathname = "/static/" + filename;
|
std::string pathname = "/static/" + filename;
|
||||||
|
|
||||||
|
concurrency::LockGuard g(spiLock);
|
||||||
// Create a new file to stream the data into
|
// Create a new file to stream the data into
|
||||||
File file = FSCom.open(pathname.c_str(), FILE_O_WRITE);
|
File file = FSCom.open(pathname.c_str(), FILE_O_WRITE);
|
||||||
size_t fileLength = 0;
|
size_t fileLength = 0;
|
||||||
@ -571,6 +582,7 @@ void handleFormUpload(HTTPRequest *req, HTTPResponse *res)
|
|||||||
|
|
||||||
file.flush();
|
file.flush();
|
||||||
file.close();
|
file.close();
|
||||||
|
|
||||||
res->printf("<p>Saved %d bytes to %s</p>", (int)fileLength, pathname.c_str());
|
res->printf("<p>Saved %d bytes to %s</p>", (int)fileLength, pathname.c_str());
|
||||||
}
|
}
|
||||||
if (!didwrite) {
|
if (!didwrite) {
|
||||||
@ -642,9 +654,11 @@ void handleReport(HTTPRequest *req, HTTPResponse *res)
|
|||||||
jsonObjMemory["heap_free"] = new JSONValue((int)memGet.getFreeHeap());
|
jsonObjMemory["heap_free"] = new JSONValue((int)memGet.getFreeHeap());
|
||||||
jsonObjMemory["psram_total"] = new JSONValue((int)memGet.getPsramSize());
|
jsonObjMemory["psram_total"] = new JSONValue((int)memGet.getPsramSize());
|
||||||
jsonObjMemory["psram_free"] = new JSONValue((int)memGet.getFreePsram());
|
jsonObjMemory["psram_free"] = new JSONValue((int)memGet.getFreePsram());
|
||||||
|
spiLock->lock();
|
||||||
jsonObjMemory["fs_total"] = new JSONValue((int)FSCom.totalBytes());
|
jsonObjMemory["fs_total"] = new JSONValue((int)FSCom.totalBytes());
|
||||||
jsonObjMemory["fs_used"] = new JSONValue((int)FSCom.usedBytes());
|
jsonObjMemory["fs_used"] = new JSONValue((int)FSCom.usedBytes());
|
||||||
jsonObjMemory["fs_free"] = new JSONValue(int(FSCom.totalBytes() - FSCom.usedBytes()));
|
jsonObjMemory["fs_free"] = new JSONValue(int(FSCom.totalBytes() - FSCom.usedBytes()));
|
||||||
|
spiLock->unlock();
|
||||||
|
|
||||||
// data->power
|
// data->power
|
||||||
JSONObject jsonObjPower;
|
JSONObject jsonObjPower;
|
||||||
@ -786,6 +800,7 @@ void handleDeleteFsContent(HTTPRequest *req, HTTPResponse *res)
|
|||||||
|
|
||||||
LOG_INFO("Delete files from /static/* : ");
|
LOG_INFO("Delete files from /static/* : ");
|
||||||
|
|
||||||
|
concurrency::LockGuard g(spiLock);
|
||||||
htmlDeleteDir("/static");
|
htmlDeleteDir("/static");
|
||||||
|
|
||||||
res->println("<p><hr><p><a href=/admin>Back to admin</a>");
|
res->println("<p><hr><p><a href=/admin>Back to admin</a>");
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
#include "configuration.h"
|
#include "configuration.h"
|
||||||
|
|
||||||
#include "FSCommon.h"
|
#include "FSCommon.h"
|
||||||
|
#include "SPILock.h"
|
||||||
#include "mesh-pb-constants.h"
|
#include "mesh-pb-constants.h"
|
||||||
#include <Arduino.h>
|
#include <Arduino.h>
|
||||||
#include <pb_decode.h>
|
#include <pb_decode.h>
|
||||||
@ -55,9 +56,12 @@ bool readcb(pb_istream_t *stream, uint8_t *buf, size_t count)
|
|||||||
/// Write to an arduino file
|
/// Write to an arduino file
|
||||||
bool writecb(pb_ostream_t *stream, const uint8_t *buf, size_t count)
|
bool writecb(pb_ostream_t *stream, const uint8_t *buf, size_t count)
|
||||||
{
|
{
|
||||||
|
spiLock->lock();
|
||||||
auto file = (Print *)stream->state;
|
auto file = (Print *)stream->state;
|
||||||
// LOG_DEBUG("writing %d bytes to protobuf file", count);
|
// LOG_DEBUG("writing %d bytes to protobuf file", count);
|
||||||
return file->write(buf, count) == count;
|
bool status = file->write(buf, count) == count;
|
||||||
|
spiLock->unlock();
|
||||||
|
return status;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -106,7 +106,9 @@ static void onNetworkConnected()
|
|||||||
#if defined(ARCH_ESP32) && !MESHTASTIC_EXCLUDE_WEBSERVER
|
#if defined(ARCH_ESP32) && !MESHTASTIC_EXCLUDE_WEBSERVER
|
||||||
initWebServer();
|
initWebServer();
|
||||||
#endif
|
#endif
|
||||||
|
#if !MESHTASTIC_EXCLUDE_SOCKETAPI
|
||||||
initApiServer();
|
initApiServer();
|
||||||
|
#endif
|
||||||
APStartupComplete = true;
|
APStartupComplete = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
#include "NodeDB.h"
|
#include "NodeDB.h"
|
||||||
#include "PowerFSM.h"
|
#include "PowerFSM.h"
|
||||||
#include "RTC.h"
|
#include "RTC.h"
|
||||||
|
#include "SPILock.h"
|
||||||
#include "meshUtils.h"
|
#include "meshUtils.h"
|
||||||
#include <FSCommon.h>
|
#include <FSCommon.h>
|
||||||
#if defined(ARCH_ESP32) && !MESHTASTIC_EXCLUDE_BLUETOOTH
|
#if defined(ARCH_ESP32) && !MESHTASTIC_EXCLUDE_BLUETOOTH
|
||||||
@ -358,12 +359,15 @@ bool AdminModule::handleReceivedProtobuf(const meshtastic_MeshPacket &mp, meshta
|
|||||||
}
|
}
|
||||||
case meshtastic_AdminMessage_delete_file_request_tag: {
|
case meshtastic_AdminMessage_delete_file_request_tag: {
|
||||||
LOG_DEBUG("Client requesting to delete file: %s", r->delete_file_request);
|
LOG_DEBUG("Client requesting to delete file: %s", r->delete_file_request);
|
||||||
|
|
||||||
#ifdef FSCom
|
#ifdef FSCom
|
||||||
|
spiLock->lock();
|
||||||
if (FSCom.remove(r->delete_file_request)) {
|
if (FSCom.remove(r->delete_file_request)) {
|
||||||
LOG_DEBUG("Successfully deleted file");
|
LOG_DEBUG("Successfully deleted file");
|
||||||
} else {
|
} else {
|
||||||
LOG_DEBUG("Failed to delete file");
|
LOG_DEBUG("Failed to delete file");
|
||||||
}
|
}
|
||||||
|
spiLock->unlock();
|
||||||
#endif
|
#endif
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -9,6 +9,7 @@
|
|||||||
#include "MeshService.h"
|
#include "MeshService.h"
|
||||||
#include "NodeDB.h"
|
#include "NodeDB.h"
|
||||||
#include "PowerFSM.h" // needed for button bypass
|
#include "PowerFSM.h" // needed for button bypass
|
||||||
|
#include "SPILock.h"
|
||||||
#include "detect/ScanI2C.h"
|
#include "detect/ScanI2C.h"
|
||||||
#include "input/ScanAndSelect.h"
|
#include "input/ScanAndSelect.h"
|
||||||
#include "mesh/generated/meshtastic/cannedmessages.pb.h"
|
#include "mesh/generated/meshtastic/cannedmessages.pb.h"
|
||||||
@ -1184,8 +1185,10 @@ bool CannedMessageModule::saveProtoForModule()
|
|||||||
{
|
{
|
||||||
bool okay = true;
|
bool okay = true;
|
||||||
|
|
||||||
#ifdef FS
|
#ifdef FSCom
|
||||||
FS.mkdir("/prefs");
|
spiLock->lock();
|
||||||
|
FSCom.mkdir("/prefs");
|
||||||
|
spiLock->unlock();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
okay &= nodeDB->saveProto(cannedMessagesConfigFile, meshtastic_CannedMessageModuleConfig_size,
|
okay &= nodeDB->saveProto(cannedMessagesConfigFile, meshtastic_CannedMessageModuleConfig_size,
|
||||||
|
@ -15,6 +15,7 @@
|
|||||||
#include "PowerFSM.h"
|
#include "PowerFSM.h"
|
||||||
#include "RTC.h"
|
#include "RTC.h"
|
||||||
#include "Router.h"
|
#include "Router.h"
|
||||||
|
#include "SPILock.h"
|
||||||
#include "airtime.h"
|
#include "airtime.h"
|
||||||
#include "configuration.h"
|
#include "configuration.h"
|
||||||
#include "gps/GeoCoord.h"
|
#include "gps/GeoCoord.h"
|
||||||
@ -205,6 +206,7 @@ bool RangeTestModuleRadio::appendFile(const meshtastic_MeshPacket &mp)
|
|||||||
LOG_DEBUG("gpsStatus->getDOP() %d", gpsStatus->getDOP());
|
LOG_DEBUG("gpsStatus->getDOP() %d", gpsStatus->getDOP());
|
||||||
LOG_DEBUG("-----------------------------------------");
|
LOG_DEBUG("-----------------------------------------");
|
||||||
*/
|
*/
|
||||||
|
concurrency::LockGuard g(spiLock);
|
||||||
if (!FSBegin()) {
|
if (!FSBegin()) {
|
||||||
LOG_DEBUG("An Error has occurred while mounting the filesystem");
|
LOG_DEBUG("An Error has occurred while mounting the filesystem");
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -5,6 +5,7 @@
|
|||||||
#include "../mesh/generated/meshtastic/telemetry.pb.h"
|
#include "../mesh/generated/meshtastic/telemetry.pb.h"
|
||||||
#include "BME680Sensor.h"
|
#include "BME680Sensor.h"
|
||||||
#include "FSCommon.h"
|
#include "FSCommon.h"
|
||||||
|
#include "SPILock.h"
|
||||||
#include "TelemetrySensor.h"
|
#include "TelemetrySensor.h"
|
||||||
|
|
||||||
BME680Sensor::BME680Sensor() : TelemetrySensor(meshtastic_TelemetrySensorType_BME680, "BME680") {}
|
BME680Sensor::BME680Sensor() : TelemetrySensor(meshtastic_TelemetrySensorType_BME680, "BME680") {}
|
||||||
@ -75,6 +76,7 @@ bool BME680Sensor::getMetrics(meshtastic_Telemetry *measurement)
|
|||||||
void BME680Sensor::loadState()
|
void BME680Sensor::loadState()
|
||||||
{
|
{
|
||||||
#ifdef FSCom
|
#ifdef FSCom
|
||||||
|
spiLock->lock();
|
||||||
auto file = FSCom.open(bsecConfigFileName, FILE_O_READ);
|
auto file = FSCom.open(bsecConfigFileName, FILE_O_READ);
|
||||||
if (file) {
|
if (file) {
|
||||||
file.read((uint8_t *)&bsecState, BSEC_MAX_STATE_BLOB_SIZE);
|
file.read((uint8_t *)&bsecState, BSEC_MAX_STATE_BLOB_SIZE);
|
||||||
@ -84,6 +86,7 @@ void BME680Sensor::loadState()
|
|||||||
} else {
|
} else {
|
||||||
LOG_INFO("No %s state found (File: %s)", sensorName, bsecConfigFileName);
|
LOG_INFO("No %s state found (File: %s)", sensorName, bsecConfigFileName);
|
||||||
}
|
}
|
||||||
|
spiLock->unlock();
|
||||||
#else
|
#else
|
||||||
LOG_ERROR("ERROR: Filesystem not implemented");
|
LOG_ERROR("ERROR: Filesystem not implemented");
|
||||||
#endif
|
#endif
|
||||||
@ -92,6 +95,7 @@ void BME680Sensor::loadState()
|
|||||||
void BME680Sensor::updateState()
|
void BME680Sensor::updateState()
|
||||||
{
|
{
|
||||||
#ifdef FSCom
|
#ifdef FSCom
|
||||||
|
spiLock->lock();
|
||||||
bool update = false;
|
bool update = false;
|
||||||
if (stateUpdateCounter == 0) {
|
if (stateUpdateCounter == 0) {
|
||||||
/* First state update when IAQ accuracy is >= 3 */
|
/* First state update when IAQ accuracy is >= 3 */
|
||||||
@ -127,6 +131,7 @@ void BME680Sensor::updateState()
|
|||||||
LOG_INFO("Can't write %s state (File: %s)", sensorName, bsecConfigFileName);
|
LOG_INFO("Can't write %s state (File: %s)", sensorName, bsecConfigFileName);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
spiLock->unlock();
|
||||||
#else
|
#else
|
||||||
LOG_ERROR("ERROR: Filesystem not implemented");
|
LOG_ERROR("ERROR: Filesystem not implemented");
|
||||||
#endif
|
#endif
|
||||||
|
@ -5,6 +5,7 @@
|
|||||||
#include "../mesh/generated/meshtastic/telemetry.pb.h"
|
#include "../mesh/generated/meshtastic/telemetry.pb.h"
|
||||||
#include "FSCommon.h"
|
#include "FSCommon.h"
|
||||||
#include "NAU7802Sensor.h"
|
#include "NAU7802Sensor.h"
|
||||||
|
#include "SPILock.h"
|
||||||
#include "SafeFile.h"
|
#include "SafeFile.h"
|
||||||
#include "TelemetrySensor.h"
|
#include "TelemetrySensor.h"
|
||||||
#include <Throttle.h>
|
#include <Throttle.h>
|
||||||
@ -111,13 +112,16 @@ bool NAU7802Sensor::saveCalibrationData()
|
|||||||
} else {
|
} else {
|
||||||
okay = true;
|
okay = true;
|
||||||
}
|
}
|
||||||
|
spiLock->lock();
|
||||||
okay &= file.close();
|
okay &= file.close();
|
||||||
|
spiLock->unlock();
|
||||||
|
|
||||||
return okay;
|
return okay;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool NAU7802Sensor::loadCalibrationData()
|
bool NAU7802Sensor::loadCalibrationData()
|
||||||
{
|
{
|
||||||
|
spiLock->lock();
|
||||||
auto file = FSCom.open(nau7802ConfigFileName, FILE_O_READ);
|
auto file = FSCom.open(nau7802ConfigFileName, FILE_O_READ);
|
||||||
bool okay = false;
|
bool okay = false;
|
||||||
if (file) {
|
if (file) {
|
||||||
@ -134,6 +138,7 @@ bool NAU7802Sensor::loadCalibrationData()
|
|||||||
} else {
|
} else {
|
||||||
LOG_INFO("No %s state found (File: %s)", sensorName, nau7802ConfigFileName);
|
LOG_INFO("No %s state found (File: %s)", sensorName, nau7802ConfigFileName);
|
||||||
}
|
}
|
||||||
|
spiLock->unlock();
|
||||||
return okay;
|
return okay;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
#include "MeshService.h"
|
#include "MeshService.h"
|
||||||
#include "NodeDB.h"
|
#include "NodeDB.h"
|
||||||
#include "PowerFSM.h"
|
#include "PowerFSM.h"
|
||||||
|
#include "ServiceEnvelope.h"
|
||||||
#include "configuration.h"
|
#include "configuration.h"
|
||||||
#include "main.h"
|
#include "main.h"
|
||||||
#include "mesh/Channels.h"
|
#include "mesh/Channels.h"
|
||||||
@ -25,7 +26,6 @@
|
|||||||
#endif
|
#endif
|
||||||
#include <Throttle.h>
|
#include <Throttle.h>
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <pb_decode.h>
|
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
|
||||||
#include <IPAddress.h>
|
#include <IPAddress.h>
|
||||||
@ -47,23 +47,6 @@ static uint8_t bytes[meshtastic_MqttClientProxyMessage_size + 30]; // 12 for cha
|
|||||||
|
|
||||||
static bool isMqttServerAddressPrivate = false;
|
static bool isMqttServerAddressPrivate = false;
|
||||||
|
|
||||||
// meshtastic_ServiceEnvelope that automatically releases dynamically allocated memory when it goes out of scope.
|
|
||||||
struct DecodedServiceEnvelope : public meshtastic_ServiceEnvelope {
|
|
||||||
DecodedServiceEnvelope() = delete;
|
|
||||||
DecodedServiceEnvelope(const uint8_t *payload, size_t length)
|
|
||||||
: meshtastic_ServiceEnvelope(meshtastic_ServiceEnvelope_init_default),
|
|
||||||
validDecode(pb_decode_from_bytes(payload, length, &meshtastic_ServiceEnvelope_msg, this))
|
|
||||||
{
|
|
||||||
}
|
|
||||||
~DecodedServiceEnvelope()
|
|
||||||
{
|
|
||||||
if (validDecode)
|
|
||||||
pb_release(&meshtastic_ServiceEnvelope_msg, this);
|
|
||||||
}
|
|
||||||
// Clients must check that this is true before using.
|
|
||||||
const bool validDecode;
|
|
||||||
};
|
|
||||||
|
|
||||||
inline void onReceiveProto(char *topic, byte *payload, size_t length)
|
inline void onReceiveProto(char *topic, byte *payload, size_t length)
|
||||||
{
|
{
|
||||||
const DecodedServiceEnvelope e(payload, length);
|
const DecodedServiceEnvelope e(payload, length);
|
||||||
@ -299,7 +282,9 @@ void mqttInit()
|
|||||||
}
|
}
|
||||||
|
|
||||||
#if HAS_NETWORKING
|
#if HAS_NETWORKING
|
||||||
MQTT::MQTT() : concurrency::OSThread("mqtt"), pubSub(mqttClient), mqttQueue(MAX_MQTT_QUEUE)
|
MQTT::MQTT() : MQTT(std::unique_ptr<MQTTClient>(new MQTTClient())) {}
|
||||||
|
MQTT::MQTT(std::unique_ptr<MQTTClient> _mqttClient)
|
||||||
|
: concurrency::OSThread("mqtt"), mqttQueue(MAX_MQTT_QUEUE), mqttClient(std::move(_mqttClient)), pubSub(*mqttClient)
|
||||||
#else
|
#else
|
||||||
MQTT::MQTT() : concurrency::OSThread("mqtt"), mqttQueue(MAX_MQTT_QUEUE)
|
MQTT::MQTT() : concurrency::OSThread("mqtt"), mqttQueue(MAX_MQTT_QUEUE)
|
||||||
#endif
|
#endif
|
||||||
@ -437,13 +422,13 @@ void MQTT::reconnect()
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
LOG_INFO("Use non-TLS-encrypted session");
|
LOG_INFO("Use non-TLS-encrypted session");
|
||||||
pubSub.setClient(mqttClient);
|
pubSub.setClient(*mqttClient);
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
pubSub.setClient(mqttClient);
|
pubSub.setClient(*mqttClient);
|
||||||
#endif
|
#endif
|
||||||
#elif HAS_NETWORKING
|
#elif HAS_NETWORKING
|
||||||
pubSub.setClient(mqttClient);
|
pubSub.setClient(*mqttClient);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
std::pair<String, uint16_t> hostAndPort = parseHostAndPort(serverAddr, serverPort);
|
std::pair<String, uint16_t> hostAndPort = parseHostAndPort(serverAddr, serverPort);
|
||||||
@ -461,7 +446,7 @@ void MQTT::reconnect()
|
|||||||
enabled = true; // Start running background process again
|
enabled = true; // Start running background process again
|
||||||
runASAP = true;
|
runASAP = true;
|
||||||
reconnectCount = 0;
|
reconnectCount = 0;
|
||||||
isMqttServerAddressPrivate = isPrivateIpAddress(mqttClient.remoteIP());
|
isMqttServerAddressPrivate = isPrivateIpAddress(mqttClient->remoteIP());
|
||||||
|
|
||||||
publishNodeInfo();
|
publishNodeInfo();
|
||||||
sendSubscriptions();
|
sendSubscriptions();
|
||||||
|
@ -22,6 +22,7 @@
|
|||||||
|
|
||||||
#if HAS_NETWORKING
|
#if HAS_NETWORKING
|
||||||
#include <PubSubClient.h>
|
#include <PubSubClient.h>
|
||||||
|
#include <memory>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define MAX_MQTT_QUEUE 16
|
#define MAX_MQTT_QUEUE 16
|
||||||
@ -32,24 +33,7 @@
|
|||||||
*/
|
*/
|
||||||
class MQTT : private concurrency::OSThread
|
class MQTT : private concurrency::OSThread
|
||||||
{
|
{
|
||||||
// supposedly the current version is busted:
|
|
||||||
// http://www.iotsharing.com/2017/08/how-to-use-esp32-mqtts-with-mqtts-mosquitto-broker-tls-ssl.html
|
|
||||||
#if HAS_WIFI
|
|
||||||
WiFiClient mqttClient;
|
|
||||||
#if !defined(ARCH_PORTDUINO)
|
|
||||||
#if (defined(ESP_ARDUINO_VERSION_MAJOR) && ESP_ARDUINO_VERSION_MAJOR < 3) || defined(RPI_PICO)
|
|
||||||
WiFiClientSecure wifiSecureClient;
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
#if HAS_ETHERNET
|
|
||||||
EthernetClient mqttClient;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
#if HAS_NETWORKING
|
|
||||||
PubSubClient pubSub;
|
|
||||||
#endif
|
|
||||||
MQTT();
|
MQTT();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -93,7 +77,29 @@ class MQTT : private concurrency::OSThread
|
|||||||
|
|
||||||
virtual int32_t runOnce() override;
|
virtual int32_t runOnce() override;
|
||||||
|
|
||||||
|
#ifndef PIO_UNIT_TESTING
|
||||||
private:
|
private:
|
||||||
|
#endif
|
||||||
|
// supposedly the current version is busted:
|
||||||
|
// http://www.iotsharing.com/2017/08/how-to-use-esp32-mqtts-with-mqtts-mosquitto-broker-tls-ssl.html
|
||||||
|
#if HAS_WIFI
|
||||||
|
using MQTTClient = WiFiClient;
|
||||||
|
#if !defined(ARCH_PORTDUINO)
|
||||||
|
#if (defined(ESP_ARDUINO_VERSION_MAJOR) && ESP_ARDUINO_VERSION_MAJOR < 3) || defined(RPI_PICO)
|
||||||
|
WiFiClientSecure wifiSecureClient;
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
#if HAS_ETHERNET
|
||||||
|
using MQTTClient = EthernetClient;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if HAS_NETWORKING
|
||||||
|
std::unique_ptr<MQTTClient> mqttClient;
|
||||||
|
PubSubClient pubSub;
|
||||||
|
explicit MQTT(std::unique_ptr<MQTTClient> mqttClient);
|
||||||
|
#endif
|
||||||
|
|
||||||
std::string cryptTopic = "/2/e/"; // msh/2/e/CHANNELID/NODEID
|
std::string cryptTopic = "/2/e/"; // msh/2/e/CHANNELID/NODEID
|
||||||
std::string jsonTopic = "/2/json/"; // msh/2/json/CHANNELID/NODEID
|
std::string jsonTopic = "/2/json/"; // msh/2/json/CHANNELID/NODEID
|
||||||
std::string mapTopic = "/2/map/"; // For protobuf-encoded MapReport messages
|
std::string mapTopic = "/2/map/"; // For protobuf-encoded MapReport messages
|
||||||
|
23
src/mqtt/ServiceEnvelope.cpp
Normal file
23
src/mqtt/ServiceEnvelope.cpp
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
#include "ServiceEnvelope.h"
|
||||||
|
#include "mesh-pb-constants.h"
|
||||||
|
#include <pb_decode.h>
|
||||||
|
|
||||||
|
DecodedServiceEnvelope::DecodedServiceEnvelope(const uint8_t *payload, size_t length)
|
||||||
|
: meshtastic_ServiceEnvelope(meshtastic_ServiceEnvelope_init_default),
|
||||||
|
validDecode(pb_decode_from_bytes(payload, length, &meshtastic_ServiceEnvelope_msg, this))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
DecodedServiceEnvelope::DecodedServiceEnvelope(DecodedServiceEnvelope &&other)
|
||||||
|
: meshtastic_ServiceEnvelope(meshtastic_ServiceEnvelope_init_zero), validDecode(other.validDecode)
|
||||||
|
{
|
||||||
|
std::swap(packet, other.packet);
|
||||||
|
std::swap(channel_id, other.channel_id);
|
||||||
|
std::swap(gateway_id, other.gateway_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
DecodedServiceEnvelope::~DecodedServiceEnvelope()
|
||||||
|
{
|
||||||
|
if (validDecode)
|
||||||
|
pb_release(&meshtastic_ServiceEnvelope_msg, this);
|
||||||
|
}
|
13
src/mqtt/ServiceEnvelope.h
Normal file
13
src/mqtt/ServiceEnvelope.h
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "mesh/generated/meshtastic/mqtt.pb.h"
|
||||||
|
|
||||||
|
// meshtastic_ServiceEnvelope that automatically releases dynamically allocated memory when it goes out of scope.
|
||||||
|
struct DecodedServiceEnvelope : public meshtastic_ServiceEnvelope {
|
||||||
|
DecodedServiceEnvelope(const uint8_t *payload, size_t length);
|
||||||
|
DecodedServiceEnvelope(DecodedServiceEnvelope &) = delete;
|
||||||
|
DecodedServiceEnvelope(DecodedServiceEnvelope &&);
|
||||||
|
~DecodedServiceEnvelope();
|
||||||
|
// Clients must check that this is true before using.
|
||||||
|
const bool validDecode;
|
||||||
|
};
|
@ -49,6 +49,7 @@
|
|||||||
**********************************************************************************************************************/
|
**********************************************************************************************************************/
|
||||||
|
|
||||||
#include "xmodem.h"
|
#include "xmodem.h"
|
||||||
|
#include "SPILock.h"
|
||||||
|
|
||||||
#ifdef FSCom
|
#ifdef FSCom
|
||||||
|
|
||||||
@ -119,8 +120,11 @@ void XModemAdapter::handlePacket(meshtastic_XModem xmodemPacket)
|
|||||||
if ((xmodemPacket.seq == 0) && !isReceiving && !isTransmitting) {
|
if ((xmodemPacket.seq == 0) && !isReceiving && !isTransmitting) {
|
||||||
// NULL packet has the destination filename
|
// NULL packet has the destination filename
|
||||||
memcpy(filename, &xmodemPacket.buffer.bytes, xmodemPacket.buffer.size);
|
memcpy(filename, &xmodemPacket.buffer.bytes, xmodemPacket.buffer.size);
|
||||||
|
|
||||||
if (xmodemPacket.control == meshtastic_XModem_Control_SOH) { // Receive this file and put to Flash
|
if (xmodemPacket.control == meshtastic_XModem_Control_SOH) { // Receive this file and put to Flash
|
||||||
|
spiLock->lock();
|
||||||
file = FSCom.open(filename, FILE_O_WRITE);
|
file = FSCom.open(filename, FILE_O_WRITE);
|
||||||
|
spiLock->unlock();
|
||||||
if (file) {
|
if (file) {
|
||||||
sendControl(meshtastic_XModem_Control_ACK);
|
sendControl(meshtastic_XModem_Control_ACK);
|
||||||
isReceiving = true;
|
isReceiving = true;
|
||||||
@ -132,14 +136,18 @@ void XModemAdapter::handlePacket(meshtastic_XModem xmodemPacket)
|
|||||||
break;
|
break;
|
||||||
} else { // Transmit this file from Flash
|
} else { // Transmit this file from Flash
|
||||||
LOG_INFO("XModem: Transmit file %s", filename);
|
LOG_INFO("XModem: Transmit file %s", filename);
|
||||||
|
spiLock->lock();
|
||||||
file = FSCom.open(filename, FILE_O_READ);
|
file = FSCom.open(filename, FILE_O_READ);
|
||||||
|
spiLock->unlock();
|
||||||
if (file) {
|
if (file) {
|
||||||
packetno = 1;
|
packetno = 1;
|
||||||
isTransmitting = true;
|
isTransmitting = true;
|
||||||
xmodemStore = meshtastic_XModem_init_zero;
|
xmodemStore = meshtastic_XModem_init_zero;
|
||||||
xmodemStore.control = meshtastic_XModem_Control_SOH;
|
xmodemStore.control = meshtastic_XModem_Control_SOH;
|
||||||
xmodemStore.seq = packetno;
|
xmodemStore.seq = packetno;
|
||||||
|
spiLock->lock();
|
||||||
xmodemStore.buffer.size = file.read(xmodemStore.buffer.bytes, sizeof(meshtastic_XModem_buffer_t::bytes));
|
xmodemStore.buffer.size = file.read(xmodemStore.buffer.bytes, sizeof(meshtastic_XModem_buffer_t::bytes));
|
||||||
|
spiLock->unlock();
|
||||||
xmodemStore.crc16 = crc16_ccitt(xmodemStore.buffer.bytes, xmodemStore.buffer.size);
|
xmodemStore.crc16 = crc16_ccitt(xmodemStore.buffer.bytes, xmodemStore.buffer.size);
|
||||||
LOG_DEBUG("XModem: STX Notify Send packet %d, %d Bytes", packetno, xmodemStore.buffer.size);
|
LOG_DEBUG("XModem: STX Notify Send packet %d, %d Bytes", packetno, xmodemStore.buffer.size);
|
||||||
if (xmodemStore.buffer.size < sizeof(meshtastic_XModem_buffer_t::bytes)) {
|
if (xmodemStore.buffer.size < sizeof(meshtastic_XModem_buffer_t::bytes)) {
|
||||||
@ -159,7 +167,9 @@ void XModemAdapter::handlePacket(meshtastic_XModem xmodemPacket)
|
|||||||
if ((xmodemPacket.seq == packetno) &&
|
if ((xmodemPacket.seq == packetno) &&
|
||||||
check(xmodemPacket.buffer.bytes, xmodemPacket.buffer.size, xmodemPacket.crc16)) {
|
check(xmodemPacket.buffer.bytes, xmodemPacket.buffer.size, xmodemPacket.crc16)) {
|
||||||
// valid packet
|
// valid packet
|
||||||
|
spiLock->lock();
|
||||||
file.write(xmodemPacket.buffer.bytes, xmodemPacket.buffer.size);
|
file.write(xmodemPacket.buffer.bytes, xmodemPacket.buffer.size);
|
||||||
|
spiLock->unlock();
|
||||||
sendControl(meshtastic_XModem_Control_ACK);
|
sendControl(meshtastic_XModem_Control_ACK);
|
||||||
packetno++;
|
packetno++;
|
||||||
break;
|
break;
|
||||||
@ -178,16 +188,21 @@ void XModemAdapter::handlePacket(meshtastic_XModem xmodemPacket)
|
|||||||
case meshtastic_XModem_Control_EOT:
|
case meshtastic_XModem_Control_EOT:
|
||||||
// End of transmission
|
// End of transmission
|
||||||
sendControl(meshtastic_XModem_Control_ACK);
|
sendControl(meshtastic_XModem_Control_ACK);
|
||||||
|
spiLock->lock();
|
||||||
file.flush();
|
file.flush();
|
||||||
file.close();
|
file.close();
|
||||||
|
spiLock->unlock();
|
||||||
isReceiving = false;
|
isReceiving = false;
|
||||||
break;
|
break;
|
||||||
case meshtastic_XModem_Control_CAN:
|
case meshtastic_XModem_Control_CAN:
|
||||||
// Cancel transmission and remove file
|
// Cancel transmission and remove file
|
||||||
sendControl(meshtastic_XModem_Control_ACK);
|
sendControl(meshtastic_XModem_Control_ACK);
|
||||||
|
spiLock->lock();
|
||||||
file.flush();
|
file.flush();
|
||||||
file.close();
|
file.close();
|
||||||
|
|
||||||
FSCom.remove(filename);
|
FSCom.remove(filename);
|
||||||
|
spiLock->unlock();
|
||||||
isReceiving = false;
|
isReceiving = false;
|
||||||
break;
|
break;
|
||||||
case meshtastic_XModem_Control_ACK:
|
case meshtastic_XModem_Control_ACK:
|
||||||
@ -195,7 +210,9 @@ void XModemAdapter::handlePacket(meshtastic_XModem xmodemPacket)
|
|||||||
if (isTransmitting) {
|
if (isTransmitting) {
|
||||||
if (isEOT) {
|
if (isEOT) {
|
||||||
sendControl(meshtastic_XModem_Control_EOT);
|
sendControl(meshtastic_XModem_Control_EOT);
|
||||||
|
spiLock->lock();
|
||||||
file.close();
|
file.close();
|
||||||
|
spiLock->unlock();
|
||||||
LOG_INFO("XModem: Finished send file %s", filename);
|
LOG_INFO("XModem: Finished send file %s", filename);
|
||||||
isTransmitting = false;
|
isTransmitting = false;
|
||||||
isEOT = false;
|
isEOT = false;
|
||||||
@ -206,7 +223,9 @@ void XModemAdapter::handlePacket(meshtastic_XModem xmodemPacket)
|
|||||||
xmodemStore = meshtastic_XModem_init_zero;
|
xmodemStore = meshtastic_XModem_init_zero;
|
||||||
xmodemStore.control = meshtastic_XModem_Control_SOH;
|
xmodemStore.control = meshtastic_XModem_Control_SOH;
|
||||||
xmodemStore.seq = packetno;
|
xmodemStore.seq = packetno;
|
||||||
|
spiLock->lock();
|
||||||
xmodemStore.buffer.size = file.read(xmodemStore.buffer.bytes, sizeof(meshtastic_XModem_buffer_t::bytes));
|
xmodemStore.buffer.size = file.read(xmodemStore.buffer.bytes, sizeof(meshtastic_XModem_buffer_t::bytes));
|
||||||
|
spiLock->unlock();
|
||||||
xmodemStore.crc16 = crc16_ccitt(xmodemStore.buffer.bytes, xmodemStore.buffer.size);
|
xmodemStore.crc16 = crc16_ccitt(xmodemStore.buffer.bytes, xmodemStore.buffer.size);
|
||||||
LOG_DEBUG("XModem: ACK Notify Send packet %d, %d Bytes", packetno, xmodemStore.buffer.size);
|
LOG_DEBUG("XModem: ACK Notify Send packet %d, %d Bytes", packetno, xmodemStore.buffer.size);
|
||||||
if (xmodemStore.buffer.size < sizeof(meshtastic_XModem_buffer_t::bytes)) {
|
if (xmodemStore.buffer.size < sizeof(meshtastic_XModem_buffer_t::bytes)) {
|
||||||
@ -224,7 +243,9 @@ void XModemAdapter::handlePacket(meshtastic_XModem xmodemPacket)
|
|||||||
if (isTransmitting) {
|
if (isTransmitting) {
|
||||||
if (--retrans <= 0) {
|
if (--retrans <= 0) {
|
||||||
sendControl(meshtastic_XModem_Control_CAN);
|
sendControl(meshtastic_XModem_Control_CAN);
|
||||||
|
spiLock->lock();
|
||||||
file.close();
|
file.close();
|
||||||
|
spiLock->unlock();
|
||||||
LOG_INFO("XModem: Retransmit timeout, cancel file %s", filename);
|
LOG_INFO("XModem: Retransmit timeout, cancel file %s", filename);
|
||||||
isTransmitting = false;
|
isTransmitting = false;
|
||||||
break;
|
break;
|
||||||
@ -232,8 +253,11 @@ void XModemAdapter::handlePacket(meshtastic_XModem xmodemPacket)
|
|||||||
xmodemStore = meshtastic_XModem_init_zero;
|
xmodemStore = meshtastic_XModem_init_zero;
|
||||||
xmodemStore.control = meshtastic_XModem_Control_SOH;
|
xmodemStore.control = meshtastic_XModem_Control_SOH;
|
||||||
xmodemStore.seq = packetno;
|
xmodemStore.seq = packetno;
|
||||||
|
spiLock->lock();
|
||||||
file.seek((packetno - 1) * sizeof(meshtastic_XModem_buffer_t::bytes));
|
file.seek((packetno - 1) * sizeof(meshtastic_XModem_buffer_t::bytes));
|
||||||
|
|
||||||
xmodemStore.buffer.size = file.read(xmodemStore.buffer.bytes, sizeof(meshtastic_XModem_buffer_t::bytes));
|
xmodemStore.buffer.size = file.read(xmodemStore.buffer.bytes, sizeof(meshtastic_XModem_buffer_t::bytes));
|
||||||
|
spiLock->unlock();
|
||||||
xmodemStore.crc16 = crc16_ccitt(xmodemStore.buffer.bytes, xmodemStore.buffer.size);
|
xmodemStore.crc16 = crc16_ccitt(xmodemStore.buffer.bytes, xmodemStore.buffer.size);
|
||||||
LOG_DEBUG("XModem: NAK Notify Send packet %d, %d Bytes", packetno, xmodemStore.buffer.size);
|
LOG_DEBUG("XModem: NAK Notify Send packet %d, %d Bytes", packetno, xmodemStore.buffer.size);
|
||||||
if (xmodemStore.buffer.size < sizeof(meshtastic_XModem_buffer_t::bytes)) {
|
if (xmodemStore.buffer.size < sizeof(meshtastic_XModem_buffer_t::bytes)) {
|
||||||
|
@ -178,7 +178,7 @@ build_flags = ${mesh_tab_base.build_flags}
|
|||||||
-D LGFX_TOUCH_Y_MIN=0
|
-D LGFX_TOUCH_Y_MIN=0
|
||||||
-D LGFX_TOUCH_Y_MAX=479
|
-D LGFX_TOUCH_Y_MAX=479
|
||||||
-D LGFX_TOUCH_ROTATION=0
|
-D LGFX_TOUCH_ROTATION=0
|
||||||
-D LGFX_TOUCH_I2C_FREQ=1000000
|
-D LGFX_TOUCH_I2C_FREQ=400000
|
||||||
|
|
||||||
; 3.5" IPS TFT ILI9488 / FT6236: https://vi.aliexpress.com/item/1005006893699919.html
|
; 3.5" IPS TFT ILI9488 / FT6236: https://vi.aliexpress.com/item/1005006893699919.html
|
||||||
[env:mesh-tab-3-5-IPS-capacitive]
|
[env:mesh-tab-3-5-IPS-capacitive]
|
||||||
@ -204,7 +204,7 @@ build_flags = ${mesh_tab_base.build_flags}
|
|||||||
-D LGFX_TOUCH_Y_MIN=0
|
-D LGFX_TOUCH_Y_MIN=0
|
||||||
-D LGFX_TOUCH_Y_MAX=479
|
-D LGFX_TOUCH_Y_MAX=479
|
||||||
-D LGFX_TOUCH_ROTATION=1
|
-D LGFX_TOUCH_ROTATION=1
|
||||||
-D LGFX_TOUCH_I2C_FREQ=1000000
|
-D LGFX_TOUCH_I2C_FREQ=400000
|
||||||
|
|
||||||
; 4.0" IPS TFT ILI9488 / FT6236: https://vi.aliexpress.com/item/1005007082906950.html
|
; 4.0" IPS TFT ILI9488 / FT6236: https://vi.aliexpress.com/item/1005007082906950.html
|
||||||
[env:mesh-tab-4-0-IPS-capacitive]
|
[env:mesh-tab-4-0-IPS-capacitive]
|
||||||
@ -230,4 +230,4 @@ build_flags = ${mesh_tab_base.build_flags}
|
|||||||
-D LGFX_TOUCH_Y_MIN=0
|
-D LGFX_TOUCH_Y_MIN=0
|
||||||
-D LGFX_TOUCH_Y_MAX=479
|
-D LGFX_TOUCH_Y_MAX=479
|
||||||
-D LGFX_TOUCH_ROTATION=1
|
-D LGFX_TOUCH_ROTATION=1
|
||||||
-D LGFX_TOUCH_I2C_FREQ=1000000
|
-D LGFX_TOUCH_I2C_FREQ=400000
|
Loading…
Reference in New Issue
Block a user