Commits vergleichen

...
21 Commits
Autor SHA1 Nachricht Datum
tom bb4fc91703 test: add lora sx1276/1278 decision logic
Build of FoxMesh / build-and-test (push) Successful in 2m56s
2026-10-19 12:14:43 +02:00
tom e847e6c750 no funcional code but store
Build of FoxMesh / build-and-test (push) Successful in 2m41s
2026-10-19 03:14:09 +02:00
tom ff975ac87a Add DIO0 Pin to config
Build of FoxMesh / build-and-test (push) Successful in 2m54s
2026-10-19 01:48:50 +02:00
tom 6a8f5db055 add antenna switch automatic 2026-10-19 01:48:03 +02:00
tom 36c303464f Add .venv path to the environment for pio run
Build of FoxMesh / build-and-test (push) Successful in 4m28s
2026-10-18 22:19:57 +02:00
tom 04e95484a6 INstall platfomio in venv
Build of FoxMesh / build-and-test (push) Failing after 14s
2026-10-18 22:14:50 +02:00
tom 8eb3a7ff18 Python already installed on host machine
Build of FoxMesh / build-and-test (push) Failing after 4s
2026-10-18 22:06:51 +02:00
tom 35a2aae086 fix wrong ident in yaml
Build of FoxMesh / build-and-test (push) Failing after 6s
2026-10-18 22:01:53 +02:00
tom f6932c8c91 actions/cache@v6 : remove absolute paths
foxmesh-ci.yml (push) Invalid workflow file
2026-10-18 21:55:15 +02:00
tom fec37babcf FIX yaml with https://yamlvalidate.com
foxmesh-ci.yml (push) Invalid workflow file
2026-10-18 21:43:43 +02:00
tom 7680928dad update yaml file for gitea
foxmesh-ci.yml (push) Invalid workflow file
2026-10-18 21:30:31 +02:00
tom a14c540e1d documentation: LoRa Mesh and Device Settings
foxmesh-ci.yml (push) Invalid workflow file
2026-10-18 21:08:58 +02:00
tom d95a9a4620 lora updates with specific settings 2026-10-18 21:08:32 +02:00
tom 032b9be518 remove spi initialization from main b/c it is done in lora module 2026-10-18 21:07:56 +02:00
tom e7fbdb0f8d add compiler directive for no-include-next in both build_flags and build_src_flags 2026-10-18 21:07:01 +02:00
tom 1d1020716e add lora system snapshot, fix some lora troubles, interrupt
foxmesh-ci.yml (push) Invalid workflow file
2026-10-18 18:06:32 +02:00
tom 9dd939b335 UPD version 1.0.4
foxmesh-ci.yml (push) Invalid workflow file
2026-10-18 15:55:03 +02:00
tom a6ad249526 move calculateTelemetry to the end of private: area, built doxygen style 2026-10-18 14:46:46 +02:00
tom e0767d3322 FIX typo in comments 2026-10-18 14:45:40 +02:00
tom 418042bb3d clean whitespaces
foxmesh-ci.yml (push) Invalid workflow file
2026-10-18 14:34:29 +02:00
tom fb542f9661 Add a static packetCounter inside LoRa receiver and display in hex , refactoring LoRa driver 2026-10-18 14:33:17 +02:00
10 geänderte Dateien mit 1387 neuen und 415 gelöschten Zeilen

Keine Dateien entsprechen Ihrer Suche

+189 -181
Datei anzeigen
@@ -1,4 +1,4 @@
name: Automated CI Build of FoxMesh
name: Build of FoxMesh
on:
push:
@@ -19,113 +19,121 @@ jobs:
contents: write # We want also create official Releases
steps:
- run: echo "🎉 The job was automatically triggered by a ${{ gitea.event_name }} event."
- run: echo "🐧 This job is now running on a ${{ runner.os }} server hosted by Gitea!"
- run: echo "🔎 The name of your branch is ${{ gitea.ref }} and your repository is ${{ gitea.repository }}."
# 1. Checkout the target branch
- name: Checkout Target branch
uses: actions/checkout@v7
with:
ref: ${{ github.event.inputs.target_branch || github.ref }}
- run: echo "🎉 The job was automatically triggered by a ${{ gitea.event_name }} event."
- run: echo "🐧 This job is now running on a ${{ runner.os }} server hosted by Gitea!"
- run: echo "🔎 The name of your branch is ${{ gitea.ref }} and your repository is ${{ gitea.repository }}."
# 2. Extract Git and Date Metadata for the dynamic artifact filename
- name: Generate Dynamic Artifact Metadata
id: meta
run: |
# Get current date in YYYYMMDD format
echo "CURRENT_DATE=$(date +'%Y%m%d')" >> $GITHUB_ENV
# 1. Checkout the target branch
- name: Checkout Target branch
uses: actions/checkout@v7
with:
ref: ${{ github.event.inputs.target_branch || github.ref }}
# Get short 7-character git commit hash
echo "GIT_HASH=$(git rev-parse --short HEAD)" >> $GITHUB_ENV
# 2. Extract Git and Date Metadata for the dynamic artifact filename
- name: Generate Dynamic Artifact Metadata
id: meta
run: |
# Get current date in YYYYMMDD format
echo "CURRENT_DATE=$(date +'%Y%m%d')" >> $GITHUB_ENV
# Extract and sanitize branch name (replace slashes and special characters with dashes)
RAW_BRANCH=${{ github.event.inputs.target_branch || github.ref_name }}
CLEAN_BRANCH=$(echo "$RAW_BRANCH" | sed 's/[^a-zA-Z0-9.\-]/_§/g' | sed 's|§|-|g' | sed 's|_||g')
echo "GIT_BRANCH=$CLEAN_BRANCH" >> $GITHUB_ENV
# Get short 7-character git commit hash
echo "GIT_HASH=$(git rev-parse --short HEAD)" >> $GITHUB_ENV
# 3. Set up Python environment
- name: Set up Python 3.x
uses: actions/setup-python@v7
with:
python-version: '3.x'
# Extract and sanitize branch name (replace slashes and special characters with dashes)
RAW_BRANCH=${{ github.event.inputs.target_branch || github.ref_name }}
CLEAN_BRANCH=$(echo "$RAW_BRANCH" | sed 's/[^a-zA-Z0-9.\-]/_§/g' | sed 's|§|-|g' | sed 's|_||g')
echo "GIT_BRANCH=$CLEAN_BRANCH" >> $GITHUB_ENV
# 4. Cache global PlatformIO directories, uses a dynamic key based on platformio.ini
- name: Cache PlatformIO
uses: actions/cache@v6
with:
path: |
~/.cache/pio
~/.platformio
.pio
key: ${{ runner.os }}-pio-${{ hashFiles('**/platformio.ini') }}
restore-keys: |
${{ runner.os }}-pio-
#3 Python alread installed
- name: Show Python Version
run: python --version
# 5. Install PlatformIO Core and the required intelhex extension in a single, quiet command
- name: Install PlatformIO Core
run: python -m pip install --quiet --upgrade pip platformio intelhex
# 4. Cache global PlatformIO directories, uses a dynamic key based on platformio.ini
- name: Cache PlatformIO
uses: actions/cache@v6
with:
path: |
.platformio
.pio
key: ${{ runner.os }}-pio-${{ hashFiles('**/platformio.ini') }}
restore-keys: |
${{ runner.os }}-pio-
# 6. Install ESP32 Platform SDK
- name: Install ESP32 platform
run: pio pkg install --silent --global --platform espressif32
- name: PlatformIO in venv installieren
run: |
python3 -m venv .venv
source .venv/bin/activate
python3 -m pip install --quiet --upgrade pip platformio intelhex
# Ab hier steht platformio in diesem Schritt zur Verfügung
pio --version
# Fügt den Pfad absolut dem GitHub/Gitea-Pfad hinzu:
echo "$PWD/.venv/bin" >> $GITHUB_PATH
# 7. Compile the Project
- name: Compile the Project
run: pio run
# 5. Install PlatformIO Core and the required intelhex extension in a single, quiet command
# - name: Install PlatformIO Core
# run: python -m pip install --quiet --upgrade pip platformio intelhex
# 8. Dynamically create the smart flashing scripts next to the T-Beam binary
# with optional bootloader detection and group check
# the table of flash addresses usually found at /partitions-4MB-safeboot.csv
- name: Create Desktop Flashing Scripts
run: |
# ----------------------------------------------------------------------
# 0. Flash Address Configuration ← edit here to change the layout
# ----------------------------------------------------------------------
FLASH_BOOTLOADER_ADDR="0x1000"
FLASH_PARTITIONS_ADDR="0x8000"
FLASH_OTADATA_ADDR="0xE000"
FLASH_SAFEBOOT_ADDR="0x10000"
FLASH_FIRMWARE_ADDR="0x10000"
# 6. Install ESP32 Platform SDK
# - name: Install ESP32 platform
# run: pio pkg install --silent --global --platform espressif32
# ----------------------------------------------------------------------
# 1. Universal Linux Shell Script
# ----------------------------------------------------------------------
cat << 'EOF' > flash_esp32_board.sh
#!/usr/bin/env bash
GREEN='\033[0;32m'
RED='\033[0;31m'
YELLOW='\033[1;33m'
NC='\033[0m'
# 7. Compile the Project
- name: Compile the Project
run: pio run
echo -e "${YELLOW}=== FoxMesh Universal ESP32 Flashing Script ===${NC}"
# 8. Dynamically create the smart flashing scripts next to the T-Beam binary
# with optional bootloader detection and group check
# the table of flash addresses usually found at /partitions-4MB-safeboot.csv
- name: Create Desktop Flashing Scripts
run: |
# ----------------------------------------------------------------------
# 0. Flash Address Configuration ← edit here to change the layout
# ----------------------------------------------------------------------
FLASH_BOOTLOADER_ADDR="0x1000"
FLASH_PARTITIONS_ADDR="0x8000"
FLASH_OTADATA_ADDR="0xE000"
FLASH_SAFEBOOT_ADDR="0x10000"
FLASH_FIRMWARE_ADDR="0x10000"
if ! command -v esptool &> /dev/null; then
# ----------------------------------------------------------------------
# 1. Universal Linux Shell Script
# ----------------------------------------------------------------------
cat << 'EOF' > flash_esp32_board.sh
#!/usr/bin/env bash
GREEN='\033[0;32m'
RED='\033[0;31m'
YELLOW='\033[1;33m'
NC='\033[0m'
echo -e "${YELLOW}=== FoxMesh Universal ESP32 Flashing Script ===${NC}"
if ! command -v esptool &> /dev/null; then
echo -e "${RED}Error: esptool is not installed.${NC}"
echo "Please install it via your package manager or pip: 'pip install esptool'"
echo "Option Linux Arch: 'sudo pacman -Sy && sudo pacman -S extra-testing/esptool'"
exit 1
fi
fi
FIRMWARE="firmware.bin"
FIRMWARE="firmware.bin"
# Firmware File
if [ ! -f "$FIRMWARE" ]; then
# Firmware File
if [ ! -f "$FIRMWARE" ]; then
echo -e "${RED}Error: No matching firmware binary found in this folder!${NC}"
exit 1
fi
fi
echo -e "${GREEN}Selected Firmware:${NC} $FIRMWARE ($BOARD_NAME)"
PORT=$(ls /dev/ttyUSB* /dev/ttyACM* 2>/dev/null | head -n 1)
if [ -z "$PORT" ]; then
echo -e "${GREEN}Selected Firmware:${NC} $FIRMWARE ($BOARD_NAME)"
PORT=$(ls /dev/ttyUSB* /dev/ttyACM* 2>/dev/null | head -n 1)
if [ -z "$PORT" ]; then
echo -e "${RED}Error: No connected ESP32 Board (ttyUSB/ttyACM) found!${NC}"
exit 1
fi
echo -e "${GREEN}Detected Board on port:${NC} $PORT"
fi
echo -e "${GREEN}Detected Board on port:${NC} $PORT"
# Dynamic Permission Check: Determine required group for the specific TTY device
REQUIRED_GROUP=$(stat -c '%G' "$PORT")
if [ "$REQUIRED_GROUP" != "root" ]; then
# Dynamic Permission Check: Determine required group for the specific TTY device
REQUIRED_GROUP=$(stat -c '%G' "$PORT")
if [ "$REQUIRED_GROUP" != "root" ]; then
if ! groups "$USER" | grep -q "\b${REQUIRED_GROUP}\b"; then
echo -e "${RED}Error: You do not have permissions to access $PORT.${NC}"
echo -e "The device belongs to the group: ${YELLOW}$REQUIRED_GROUP${NC}"
@@ -134,107 +142,107 @@ jobs:
echo -e "After running the command, please log out and log back in for the changes to take effect."
exit 1
fi
fi
fi
# Build flash arguments from the address table (only include files that exist)
FLASH_ARGS=""
if [ -f "bootloader.bin" ]; then
FLASH_ARGS="$FLASH_ARGS __BOOTLOADER_ADDR__ bootloader.bin"
fi
if [ -f "partitions.bin" ]; then
FLASH_ARGS="$FLASH_ARGS __PARTITIONS_ADDR__ partitions.bin"
fi
if [ -f "otadata.bin" ]; then
FLASH_ARGS="$FLASH_ARGS __OTADATA_ADDR__ otadata.bin"
fi
if [ -f "safeboot.bin" ]; then
FLASH_ARGS="$FLASH_ARGS __SAFEBOOT_ADDR__ safeboot.bin"
fi
FLASH_ARGS="$FLASH_ARGS __FIRMWARE_ADDR__ $FIRMWARE"
# Build flash arguments from the address table (only include files that exist)
FLASH_ARGS=""
if [ -f "bootloader.bin" ]; then
FLASH_ARGS="$FLASH_ARGS __BOOTLOADER_ADDR__ bootloader.bin"
fi
if [ -f "partitions.bin" ]; then
FLASH_ARGS="$FLASH_ARGS __PARTITIONS_ADDR__ partitions.bin"
fi
if [ -f "otadata.bin" ]; then
FLASH_ARGS="$FLASH_ARGS __OTADATA_ADDR__ otadata.bin"
fi
if [ -f "safeboot.bin" ]; then
FLASH_ARGS="$FLASH_ARGS __SAFEBOOT_ADDR__ safeboot.bin"
fi
FLASH_ARGS="$FLASH_ARGS __FIRMWARE_ADDR__ $FIRMWARE"
echo -e "${GREEN}Flashing:${NC}$FLASH_ARGS"
esptool --chip esp32 --port "$PORT" --baud 921600 write-flash -z $FLASH_ARGS
echo -e "${GREEN}Flashing:${NC}$FLASH_ARGS"
esptool --chip esp32 --port "$PORT" --baud 921600 write-flash -z $FLASH_ARGS
if [ $? -eq 0 ]; then
if [ $? -eq 0 ]; then
echo -e "${GREEN}=== Success! $BOARD_NAME successfully updated ===${NC}"
else
else
echo -e "${RED}=== Flash failed! ===${NC}"
exit 1
fi
EOF
fi
EOF
# Substitute address placeholders with configured hex values
sed -i \
# Substitute address placeholders with configured hex values
sed -i \
-e "s|__BOOTLOADER_ADDR__|${FLASH_BOOTLOADER_ADDR}|g" \
-e "s|__PARTITIONS_ADDR__|${FLASH_PARTITIONS_ADDR}|g" \
-e "s|__OTADATA_ADDR__|${FLASH_OTADATA_ADDR}|g" \
-e "s|__SAFEBOOT_ADDR__|${FLASH_SAFEBOOT_ADDR}|g" \
-e "s|__FIRMWARE_ADDR__|${FLASH_FIRMWARE_ADDR}|g" \
flash_esp32_board.sh
chmod +x flash_esp32_board.sh
chmod +x flash_esp32_board.sh
# ----------------------------------------------------
# 2. Universal Windows Batch Script
# ----------------------------------------------------
cat << 'EOF' > flash_esp32_board.bat
@echo off
setlocal enabledelayedexpansion
echo ===================================================
echo === FoxMesh Universal ESP32 Windows Flashing ======
echo ===================================================
# ----------------------------------------------------
# 2. Universal Windows Batch Script
# ----------------------------------------------------
cat << 'EOF' > flash_esp32_board.bat
@echo off
setlocal enabledelayedexpansion
echo ===================================================
echo === FoxMesh Universal ESP32 Windows Flashing ======
echo ===================================================
set "FIRMWARE=firmware.bin"
set "FIRMWARE=firmware.bin"
if not exist "!FIRMWARE!" (
if not exist "!FIRMWARE!" (
echo [ERROR] No matching firmware binary found in this folder!
pause
exit /b 1
)
)
echo [INFO] Selected Firmware: %FIRMWARE% (%BOARD_NAME%)
echo [INFO] Selected Firmware: %FIRMWARE% (%BOARD_NAME%)
set "COMPORT="
for /f "tokens=2 delims=()" %%A in ('wmic path Win32_PnPEntity get Name ^| findstr /i "COM" ^| findstr /i "Silicon CP210 CH340 CH9102 USB-to-UART"') do set "COMPORT=%%A"
if "%COMPORT%"=="" (
for /f "tokens=2 delims=()" %%A in ('wmic path Win32_PnPEntity get Name ^| findstr /i "(COM"') do set "COMPORT=%%A"
)
if "%COMPORT%"=="" (
echo [ERROR] No ESP32 Board or USB-UART bridge detected!
set "COMPORT="
for /f "tokens=2 delims=()" %%A in ('wmic path Win32_PnPEntity get Name ^| findstr /i "COM" ^| findstr /i "Silicon CP210 CH340 CH9102 USB-to-UART"') do set "COMPORT=%%A"
if "%COMPORT%"=="" (
for /f "tokens=2 delims=()" %%A in ('wmic path Win32_PnPEntity get Name ^| findstr /i "(COM"') do set "COMPORT=%%A"
)
if "%COMPORT%"=="" (
echo [ERROR] No ESP32 Board or USB-UART bridge detected!
pause
exit /b 1
)
echo [INFO] Detected Board on port: %COMPORT%
set "FLASH_ARGS="
if exist "bootloader.bin" (
set "FLASH_ARGS=!FLASH_ARGS! __BOOTLOADER_ADDR__ bootloader.bin"
)
if exist "partitions.bin" (
set "FLASH_ARGS=!FLASH_ARGS! __PARTITIONS_ADDR__ partitions.bin"
)
if exist "otadata.bin" (
set "FLASH_ARGS=!FLASH_ARGS! __OTADATA_ADDR__ otadata.bin"
)
if exist "safeboot.bin" (
set "FLASH_ARGS=!FLASH_ARGS! __SAFEBOOT_ADDR__ safeboot.bin"
)
set "FLASH_ARGS=!FLASH_ARGS! __FIRMWARE_ADDR__ %FIRMWARE%"
echo [INFO] Flashing: !FLASH_ARGS!
esptool --chip esp32 --port %COMPORT% --baud 921600 write-flash -z !FLASH_ARGS!
if %ERRORLEVEL% EQU 0 (
echo === SUCCESS! Flash operation successfully completed ===
) else (
echo [ERROR] Flash failed!
pause
exit /b 1
)
pause
exit /b 1
)
echo [INFO] Detected Board on port: %COMPORT%
EOF
set "FLASH_ARGS="
if exist "bootloader.bin" (
set "FLASH_ARGS=!FLASH_ARGS! __BOOTLOADER_ADDR__ bootloader.bin"
)
if exist "partitions.bin" (
set "FLASH_ARGS=!FLASH_ARGS! __PARTITIONS_ADDR__ partitions.bin"
)
if exist "otadata.bin" (
set "FLASH_ARGS=!FLASH_ARGS! __OTADATA_ADDR__ otadata.bin"
)
if exist "safeboot.bin" (
set "FLASH_ARGS=!FLASH_ARGS! __SAFEBOOT_ADDR__ safeboot.bin"
)
set "FLASH_ARGS=!FLASH_ARGS! __FIRMWARE_ADDR__ %FIRMWARE%"
echo [INFO] Flashing: !FLASH_ARGS!
esptool --chip esp32 --port %COMPORT% --baud 921600 write-flash -z !FLASH_ARGS!
if %ERRORLEVEL% EQU 0 (
echo === SUCCESS! Flash operation successfully completed ===
) else (
echo [ERROR] Flash failed!
pause
exit /b 1
)
pause
EOF
# Substitute address placeholders with configured hex values
sed -i \
# Substitute address placeholders with configured hex values
sed -i \
-e "s|__BOOTLOADER_ADDR__|${FLASH_BOOTLOADER_ADDR}|g" \
-e "s|__PARTITIONS_ADDR__|${FLASH_PARTITIONS_ADDR}|g" \
-e "s|__OTADATA_ADDR__|${FLASH_OTADATA_ADDR}|g" \
@@ -242,27 +250,27 @@ jobs:
-e "s|__FIRMWARE_ADDR__|${FLASH_FIRMWARE_ADDR}|g" \
flash_esp32_board.bat
# -----------------------------------------------------------------------------
# 3. Gather binaries and scripts into target directory for structural packaging
# -----------------------------------------------------------------------------
mkdir -p deploy_package
BUILD_OUTPUT=".pio/build/ttgo-lora32-v21"
# -----------------------------------------------------------------------------
# 3. Gather binaries and scripts into target directory for structural packaging
# -----------------------------------------------------------------------------
mkdir -p deploy_package
BUILD_OUTPUT=".pio/build/ttgo-lora32-v21"
# Copy binaries only if they exist
[ -f "$BUILD_OUTPUT/firmware.bin" ] && cp "$BUILD_OUTPUT/firmware.bin" ./deploy_package/
[ -f "$BUILD_OUTPUT/bootloader.bin" ] && cp "$BUILD_OUTPUT/bootloader.bin" ./deploy_package/
[ -f "$BUILD_OUTPUT/partitions.bin" ] && cp "$BUILD_OUTPUT/partitions.bin" ./deploy_package/
[ -f "$BUILD_OUTPUT/otadata.bin" ] && cp "$BUILD_OUTPUT/otadata.bin" ./deploy_package/
[ -f "$BUILD_OUTPUT/safeboot.bin" ] && cp "$BUILD_OUTPUT/safeboot.bin" ./deploy_package/
# Copy binaries only if they exist
[ -f "$BUILD_OUTPUT/firmware.bin" ] && cp "$BUILD_OUTPUT/firmware.bin" ./deploy_package/
[ -f "$BUILD_OUTPUT/bootloader.bin" ] && cp "$BUILD_OUTPUT/bootloader.bin" ./deploy_package/
[ -f "$BUILD_OUTPUT/partitions.bin" ] && cp "$BUILD_OUTPUT/partitions.bin" ./deploy_package/
[ -f "$BUILD_OUTPUT/otadata.bin" ] && cp "$BUILD_OUTPUT/otadata.bin" ./deploy_package/
[ -f "$BUILD_OUTPUT/safeboot.bin" ] && cp "$BUILD_OUTPUT/safeboot.bin" ./deploy_package/
# Move flash scripts into the deployment directory
mv flash_esp32_board.sh ./deploy_package/
mv flash_esp32_board.bat ./deploy_package/
# Move flash scripts into the deployment directory
mv flash_esp32_board.sh ./deploy_package/
mv flash_esp32_board.bat ./deploy_package/
# 9. Dynamic Artifact Upload: FoxMesh-branch-date-hash.zip
- name: Upload Compiled Firmware Package
uses: actions/upload-artifact@v7
with:
name: FoxMesh-${{ env.GIT_BRANCH }}-${{ env.CURRENT_DATE }}-${{ env.GIT_HASH }}
path: deploy_package/
# 9. Dynamic Artifact Upload: FoxMesh-branch-date-hash.zip
- name: Upload Compiled Firmware Package
uses: actions/upload-artifact@v7
with:
name: FoxMesh-${{ env.GIT_BRANCH }}-${{ env.CURRENT_DATE }}-${{ env.GIT_HASH }}
path: deploy_package/
retention-days: 10 # Artifacts will be automatically deleted after 10 days
Binäre Datei nicht angezeigt.
+84
Datei anzeigen
@@ -58,3 +58,87 @@ The frequency block from **433.050 to 434.790 MHz** is shared globally as an **I
The 433 MHz ISM band in Europe is heavily congested by consumer devices like car key fobs, weather stations, and garage door openers. If you want to escape this interference completely, the European standard is to switch to the **868 MHz band**.
* **Note:** MeshCom itself is historically tied to 433 MHz in Austria. Shifting to 868 MHz effectively means migrating away from MeshCom infrastructure into the license-free **Meshtastic** ecosystem, which features a massive, highly dense node network across Austria on 868 MHz.
---
## 🔒 Part 3: LoRa Synchronization Words & Hardware Filtering
The **LoRa Synchronization Word (Sync Word)** is a critical 8-bit hardware filter configured inside register **`0x39` (`RegSyncWord`)** of the Semtech SX1276 transceiver. It functions as a physical RF barrier inside the radio's baseband modem. If an incoming packet's preamble synchronization pattern does not perfectly match the receiver's configured value, the hardware discards the payload instantly on chip-level, preventing the **`RxDone`** flag from firing and keeping the physical interrupt line completely silent.
### Technical Reference Matrix
While register `0x39` accepts any 8-bit value from `0x00` to `0xFF`, specific combinations have established themselves as international operational standards:
| Sync Word | Network Profile | Operational Target / Description |
| :--- | :--- | :--- |
| **`0x34`** | **Public LoRaWAN** | **MeshCom Standard** (ÖVSV standard for amateur radio mesh infrastructures operating at **433.175 MHz**). Triggers advanced hardware preamble correlation rules in the silicon for maximum noise immunity near the thermal noise floor. |
| **`0x24`** | **Tactical Mesh** | **Meshtastic Default** (Civilian off-grid digital communications). Used globally on the license-free 433 MHz ISM and 868 MHz bands. Requires modern low-data-rate optimization configurations to eliminate sensitivity degradation on legacy SX127x silicon steps. |
| **`0x12`** | **Private Network** | **Semtech Factory Default**. Standard baseline initialization value utilized for isolated point-to-point (P2P) bridging outside global networks. |
| **`0x55`** | **Isolated Array A** | **Custom / Experimental**. Alternating bit pattern (`01010101`) providing optimal transition density for the internal clock-data recovery (CDR) PLL loop. |
| **`0xAA`** | **Isolated Array B** | **Custom / Experimental**. Alternating bit pattern (`10101010`) offering optimal signal integrity transitions for proprietary cryptography deployments. |
> ⚠️ **The Preamble Correlation Trap:**
> Custom deployments should strictly avoid sync words with sparse bit transitions (such as `0x00` or `0xFF`). The internal baseband correlation engine relies on distinct signal transitions to sync its timing grid. Continuous sequences of zeros or ones drastically degrade receiver sensitivity.
### MeshCom Co-Existence Layout
To successfully capture live telemetry frames from official ÖVSV MeshCom gateways, the firmware forces a multi-register synchronization sequence during the unified thread-safe constructor pass:
```cpp
// Predefined LoRa Sync Word options for hardware correlation filtering
constexpr uint8_t LORA_SYNC_WORD_PUBLIC_NETWORK_MODE = 0x34; // MeshCom (ÖVSV standard for amateur radio mesh)
constexpr uint8_t LORA_SYNC_WORD_TACTICAL_NETWORK_MODE = 0x24; // Meshtastic (Civilian off-grid tactical mesh network)
constexpr uint8_t LORA_SYNC_WORD_PRIVATE_NETWORK_MODE = 0x12; // Semtech Default (Factory default / Private point-to-point)
constexpr uint8_t LORA_SYNC_WORD_CUSTOM_NETWORK_MODE = 0x55; // Custom / Experimental individual networks (highly isolated)
constexpr uint8_t LORA_SYNC_WORD_EXPERIMENTAL_NETWORK_MODE = 0xAA; // Custom / Experimental individual networks (highly isolated)
// Active hardware synchronization configuration selector
constexpr uint8_t LORA_SYNC_WORD = LORA_SYNC_WORD_PUBLIC_NETWORK_MODE;
```
This variable updates the Semtech baseband modem alongside an expanded preamble length of **12 symbols** to prevent packet dropping during long correlation windows:
```cpp
// Write the dynamic sync word byte to register 0x39
writeRegister(0x39, Config::LORA_SYNC_WORD);
// Expand hardware preamble length to 12 symbols for robust network correlation
writeRegister(0x20, 0x00U); // RegPreambleMsb
writeRegister(0x21, 0x0CU); // RegPreambleLsb (12 = 0x0C)
```
---
## 🛠️ Part 4: Troubleshooting Packet Drops & Telemetry Failures
When listening to live MeshCom grids or experimental point-to-point networks, your terminal might remain silent despite active RF activity in your area. This section details how to diagnose, interpret, and resolve low-level hardware anomalies using the automated register metrics layer.
### 1. The Low-Level Interrupt Diagnostics (Bypassing FreeRTOS Flags)
If your application task does not wake up, you must verify if the Semtech silicon is tracking any signals at all. By reading register **`0x12` (`RegIrqFlags`)**, you can isolate the failure source instantly:
```text
Reg 0x12 Value Hardware Status Root Cause & Resolution
-------------- ----------------------- -------------------------------------------------------------
0x00 No Signal Detected - Transceiver is out of range or frequency calibration mismatch.
- Check if your device is actively in RXCONTINUOUS mode [0x85].
0x20 PayloadCrcError Active - The packet was received but failed the hardware checksum.
- Caused by bad SNR (noise floor interference) or SF mismatch.
0x80 RxTimeout Active - The preamble was detected, but the complete frame timed out.
- Increase your preamble length to 12 symbols (Reg 0x20/0x21).
0x40 RxDone Success - The hardware captured, matched, and validated the packet!
- If terminal stays silent, check your FreeRTOS semaphore handles.
```
---
### 2. Common Integration Failure Modes
#### Symptom A: Zero Output from `readRegister(0x42)` during Boot
* **Root Cause:** The SPI peripheral host is misconfigured, or the hardware reset pin failed to pull low during the unified constructor pass.
* **Resolution:** Verify that `spi_bus_initialize()` is bound to the correct Host controller (`SPI2_HOST` for standard LilyGO TTGO boards). Ensure your initialization logic executes safely on **Core 0** inside the main task context to guarantee uniform driver registration.
#### Symptom B: The First Packet Arrives, then Total Silence
* **Root Cause:** The hardware interrupt flags within register `0x12` were not acknowledged, or the internal read pointer (`RegFifoAddrPtr`) was not explicitly reset to the packet's current base address.
* **Resolution:** You must overwrite register `0x12` with its active bit mask at the **absolute beginning** of your processing chain. This forces the physical `DIO0` line to fall back to logic low, enabling the ESP32 to detect subsequent rising edges (`GPIO_INTR_POSEDGE`). Always call `setModeReceiver()` at the end of the extraction loop to clear baseband modulations.
#### Symptom C: Constant `PayloadCrcError` [0x20] on Local MeshCom Traffic
* **Root Cause:** Inverted IQ configurations or local industrial noise (shared 433 MHz ISM congestion) is corrupting incoming headers.
* **Resolution:** Verify that your local modem target bandwidth exactly mirrors the MeshCom standard of **250 kHz** and **SF11**. For extreme near-field interference, ensure your `calculateTelemetry()` float calculation is active to track if sub-noise SNR regressions are pulling the signal strength below `-120 dBm`.
+3 -1
Datei anzeigen
@@ -23,7 +23,7 @@ build_flags =
-D CCACHE_ENABLE=1
; Treats ESP-IDF libc extensions headers as system headers to suppress external warnings
; -isystem /home/tom/.platformio/packages/framework-espidf/components/esp_libc/platform_include
-Wno-include-next
; --- STRICT MODE FOR PROJECT APPLICATION CODE ONLY ---
; These flags are strictly applied ONLY to C++ files inside the src/ directory.
build_src_flags =
@@ -39,5 +39,7 @@ build_src_flags =
-Wconversion
; Warns if a local variable shadows another variable in scope
-Wshadow
-Wno-include-next
; Promotes all warnings to hard compilation errors to guarantee clean code
;-Werror
+18 -10
Datei anzeigen
@@ -101,6 +101,23 @@ void process_command(const char* cmd) {
printf("Mute Timer Period : %lu seconds\r\n", (unsigned long)current_mute_time_sec);
printf("Target CPU Board : ESP32\r\n");
printf("ESP-IDF Version : %s\r\n", esp_get_idf_version());
if (lora_system != nullptr) {
// Holt die atomare, thread-sichere Kopie der Telemetriedaten (Stack-Allokation)
LoraStateSnapshot snapshot = lora_system->getSnapshot();
printf("LoRa Hardware : %s\r\n", snapshot.isInitialized ? "INITIALIZED" : "FAILED / UNINITIALIZED");
printf("LoRa Transceiver : Mode [%s]\r\n", snapshot.currentModeStr);
printf("LoRa Frequency : %lu Hz\r\n", (unsigned long)snapshot.frequencyHz);
printf("LoRa Bandwidth : %lu kHz\r\n", (unsigned long)snapshot.bandwidthKhz);
printf("LoRa SpreadingFact: SF%u\r\n", snapshot.spreadingFactor);
printf("LoRa Coding Rate : 4/%u\r\n", snapshot.codingRate);
printf("Packets Received : %lu\r\n", (unsigned long)snapshot.totalPacketsReceived);
printf("Packets Transmit : %lu\r\n", (unsigned long)snapshot.totalPacketsTransmitted);
printf("History In Memory : %zu Packets\r\n", snapshot.currentHistoryCount);
} else {
printf("LoRa Snapshot : Error (LoraController Handle uninitialized)\r\n");
}
}
else if (strncmp(cmd, "mute ", 5) == 0) {
int parsed_time = atoi(cmd + 5);
@@ -163,16 +180,7 @@ void process_command(const char* cmd) {
if (valid_433 || valid_868) {
if (lora_system != nullptr) {
// SX1276 formula: Frf = Ffreq * 2^19 / 32000000
// Using double to prevent truncation during division before bit masking
double fraction = (static_cast<double>(target_freq_hz) * 524288.0) / 32000000.0;
uint32_t frf = static_cast<uint32_t>(fraction);
uint8_t msb = static_cast<uint8_t>((frf >> 16) & 0xFFU);
uint8_t mid = static_cast<uint8_t>((frf >> 8) & 0xFFU);
uint8_t lsb = static_cast<uint8_t>(frf & 0xFFU);
lora_system->setFrequency(msb, mid, lsb);
lora_system->setFrequency(target_freq_hz);
printf("Success: Frequency shifted to %lu Hz.\r\n", (unsigned long)target_freq_hz);
} else {
printf("Error: LoraController handle is uninitialized.\r\n");
+40 -10
Datei anzeigen
@@ -22,7 +22,7 @@
namespace Config {
// Compile-time constants with strict type enforcement
constexpr const char* PROJECT_TITLE = "FoxMesh";
constexpr const char* PROJECT_VERSION = "1.0.3";
constexpr const char* PROJECT_VERSION = "1.0.5";
constexpr const char* PROJECT_AUTHORS = "Tom OE3TKT";
// CLI Mute Configuration
@@ -44,17 +44,47 @@ namespace Config {
constexpr gpio_num_t LORA_SCK_PIN = GPIO_NUM_5;
constexpr gpio_num_t LORA_CS_PIN = GPIO_NUM_18;
constexpr gpio_num_t LORA_RST_PIN = GPIO_NUM_23; // Adjusted configuration for T3_V1.6 hardware revision
constexpr gpio_num_t LORA_IRQ_PIN = GPIO_NUM_26;
constexpr gpio_num_t LORA_IRQ_PIN = GPIO_NUM_26; // DIO0_PIN
constexpr gpio_num_t LORA_DIO1_PIN = GPIO_NUM_33; // Wichtig für PLL-Lock & Timeout im RX-Modus
// Semtech SX1276 LoRa Configuration Parameters
// 433.175 MHz is calculated by: 433175000 / (32000000 / 2^19) = 7097139.2 = 0x6c4b33 // wrong: 0x06C4CD
constexpr uint8_t LORA_FRF_MSB = 0x6C;
constexpr uint8_t LORA_FRF_MID = 0x4B;
constexpr uint8_t LORA_FRF_LSB = 0x33;
constexpr uint32_t LORA_DEFAULT_FREQ_HZ = 433175000;
constexpr uint32_t LORA_DEFAULT_BW_KHZ = 250;
constexpr uint8_t LORA_DEFAULT_SF = 11;
constexpr uint8_t LORA_DEFAULT_CR = 6; // CR 4/6 -> Denominator is 6
// Modem Config 1: BW 250kHz (0x80), CR 4/6 (0x04), Explicit Header (0x00) -> 0x84
constexpr uint8_t LORA_MODEM_CONFIG_1 = 0x84;
// Predefined LoRa Sync Word options for hardware correlation filtering
constexpr uint8_t LORA_SYNC_WORD_PUBLIC_NETWORK_MODE = 0x34; // MeshCom (ÖVSV standard for amateur radio mesh),
// The Things Network, Helium
constexpr uint8_t LORA_SYNC_WORD_TACTICAL_NETWORK_MODE = 0x24; // Meshtastic (Civilian off-grid tactical mesh network)
constexpr uint8_t LORA_SYNC_WORD_PRIVATE_NETWORK_MODE = 0x12; // Semtech Default (Factory default / Private point-to-point)
constexpr uint8_t LORA_SYNC_WORD_CUSTOM_NETWORK_MODE = 0x55; // Custom / Experimental individual networks (highly isolated)
constexpr uint8_t LORA_SYNC_WORD_EXPERIMENTAL_NETWORK_MODE = 0xAA; // Custom / Experimental individual networks (highly isolated)
// Modem Config 2: SF11 (0xB0), TX Continuous off (0x00), CRC On (0x04) -> 0xB4
constexpr uint8_t LORA_MODEM_CONFIG_2 = 0xB4;
// Active hardware synchronization configuration selector
constexpr uint8_t LORA_SYNC_WORD = LORA_SYNC_WORD_PUBLIC_NETWORK_MODE; // Selected default synchronization profile
// Expand hardware preamble length to 12 symbols for robust network correlation (MeshCom value)
constexpr uint8_t LORA_PREAMBLE_LENGTH_LSB = 0x0C; // Semtech Factor Default is 0x08
// The compiler automatically pre-calculates the 24-bit frequency word at compile-time!
constexpr uint64_t LORA_FRF_CALC = ((uint64_t)LORA_DEFAULT_FREQ_HZ << 19) / 32000000ULL;
constexpr uint8_t LORA_FRF_MSB = static_cast<uint8_t>((LORA_FRF_CALC >> 16) & 0xFFU);
constexpr uint8_t LORA_FRF_MID = static_cast<uint8_t>((LORA_FRF_CALC >> 8) & 0xFFU);
constexpr uint8_t LORA_FRF_LSB = static_cast<uint8_t>(LORA_FRF_CALC & 0xFFU);
// --- DYNAMIC COMPILE-TIME BIT-SHIFTING EXPRESSIONS ---
// Helper to map bandwidth kHz to Semtech Register Bits (7-4 of RegModemConfig1)
constexpr uint8_t LORA_BW_REG_VAL = (LORA_DEFAULT_BW_KHZ == 62) ? 0x06 :
(LORA_DEFAULT_BW_KHZ == 125) ? 0x07 :
(LORA_DEFAULT_BW_KHZ == 250) ? 0x08 :
(LORA_DEFAULT_BW_KHZ == 500) ? 0x09 : 0x08;
// RegModemConfig1 (0x1D): Bandwidth (Bits 7-4), Coding Rate (Bits 3-1), ImplicitHeader (Bit 0 = 0)
constexpr uint8_t LORA_MODEM_CONFIG_1 = static_cast<uint8_t>((LORA_BW_REG_VAL << 4) | ((LORA_DEFAULT_CR - 4) << 1));
// RegModemConfig2 (0x1E): Spreading Factor (Bits 7-4), TxContinuous (Bit 3 = 0), RxPayloadCrcOn (Bit 2 = 1)
constexpr uint8_t LORA_MODEM_CONFIG_2 = static_cast<uint8_t>((LORA_DEFAULT_SF << 4) | 0x04U);
}
+774 -136
Datei anzeigen
Datei-Diff unterdrückt, da er zu groß ist. Diff laden
+163 -44
Datei anzeigen
@@ -1,6 +1,6 @@
/**
* @file lora.hpp
* @brief Thread-safe asynchronous Semtech SX1276 LoRa transceiver driver for FoxMesh
* @brief Thread-safe asynchronous Semtech SX1276 LoRa transceiver driver interface.
* @author OM Tom (OE3TKT)
*
* @license SPDX-License-Identifier: MIT
@@ -10,73 +10,192 @@
#pragma once
#include "driver/gpio.h"
#include "driver/spi_master.h"
#include "freertos/FreeRTOS.h"
#include "freertos/semphr.h"
#include "freertos/task.h"
#include "lora_types.hpp"
#include "esp_err.h"
/**
* @brief Simple internal abstraction layer mirroring the raw incoming packet payload.
*/
struct LoraPacket {
float rssi; /**< High-precision calibrated received signal power in dBm. */
float snr; /**< High-precision calibrated signal-to-noise ratio in dB. */
uint8_t length; /**< Payload size explicitly specified in bytes. */
uint8_t payload[256]; /**< Fixed internal memory buffer capturing raw ingress bytes. Max SX1276 FIFO is 256. */
};
/**
* @brief Controller class orchestrating hardware configurations, data transfers, and metrics collection.
*/
class LoraController {
private:
static const char* TAG; ///< Logging identifier tag for ESP_LOG statements.
void* m_spiHandle = nullptr; ///< SPI device interface reference token pointer.
SemaphoreHandle_t m_isrSemaphore = nullptr; ///< Binary semaphore facilitating hardware-to-task sync notifications.
LoraStateTable m_state; ///< Internal volatile tracking record data context.
SemaphoreHandle_t m_stateMutex = nullptr; ///< Mutex primitive enforcing mutual exclusion over m_state modifications.
/**
* @brief Reads a value from an individual internal register address of the transceiver.
* @param address Target transceiver memory sub-space location address byte.
* @return The read byte value configuration currently active.
*/
uint8_t readRegister(uint8_t address);
/**
* @brief Writes a specific option parameter directly into a single transceiver register address.
* @param address Target transceiver memory sub-space location address byte.
* @param value Setting parameter layout specification code byte.
*/
void writeRegister(uint8_t address, uint8_t value);
/**
* @brief Interrupt Service Routine wrapper triggered directly from GPIO state changes.
* @param arg Opaque payload pointer referencing the target thread synchronization primitive.
*/
static void IRAM_ATTR gpioIsrHandler(void* arg);
/**
* @brief Helper context processing background calculations to prune list overflows.
* @note This internal call assumes that the m_stateMutex lock has already been successfully acquired.
*/
void enforceHistoryLimit();
/**
* @brief Main processing task thread loop loopback entry execution hub.
*/
void run();
/**
* @brief Static FreeRTOS bridge method mapping execution control context flows.
* @param pvParameters Context reference address pointing back into the instantiating class layer.
*/
static void taskTrampoline(void* pvParameters);
/**
* @brief Evaluates raw register readings into calibrated RSSI and SNR telemetry metrics.
* @details Automatically compensates the RSSI offset base based on the active carrier frequency
* band (Low-Band vs High-Band boundary at 525 MHz) as well as sub-noise SNR conditions.
* @param rawRssi The raw digital output read from RegRssiValue (0x1A).
* @param rawSnr The raw digital twos-complement output read from RegPktSnrValue (0x1B).
* @param[out] outRssi Reference destination pointer receiving the calibrated RSSI value in dBm.
* @param[out] outSnr Reference destination pointer receiving the calibrated SNR value in dB.
*/
void calculateTelemetry(uint8_t rawRssi, uint8_t rawSnr, float& outRssi, float& outSnr);
public:
/**
* @brief Structure defining the localized packet buffer space.
* @brief Construct a new Lora Controller instance and allocate threading primitives.
*/
struct LoraPacket {
uint8_t payload[256]; ///< Raw data payload frame matching max SX1276 FIFO allocation
uint8_t length; ///< Total number of active bytes captured inside the frame
int8_t rssi; ///< Received Signal Strength Indicator metric in dBm
int8_t snr; ///< Signal-to-Noise Ratio metric in dB
};
explicit LoraController();
virtual ~LoraController();
// Disallow copying to prevent duplicate hardware resource assignment
LoraController(const LoraController&) = delete;
LoraController& operator=(const LoraController&) = delete;
LoraController();
/**
* @brief Configures peripheral resources and registers the background worker thread on Core 1.
* @param priority Scheduler task priority level execution metric.
* @brief Destroy the Lora Controller object, releasing active allocations and hardware hooks.
*/
void startTask(uint32_t priority = 6);
~LoraController();
/**
* @brief Transmits a raw data frame onto the physical radio frequency layer.
* @param buffer Pointer to the source byte array holding the packet context.
* @param length Total number of bytes to dispatch over the air interface.
* @return esp_err_t status indicating transaction success.
* @brief Initializes active interface bindings, reset signals, and evaluates valid silicon signatures.
* @return ESP_OK on operational handshake match, alternative error codes upon physical failures.
*/
esp_err_t initializeHardware();
/**
* @brief Programs basic standard profiling configurations and flags continuous reception monitoring modes.
*/
void setModeReceiver();
/**
* @brief Directly transmits a raw binary frame layout out onto the RF medium link.
* @param buffer Reference data memory segment holding the outbound bytes block.
* @param length The complete amount of data characters structured within the payload.
* @return ESP_OK upon transmission launch clearance, error conditions otherwise.
*/
esp_err_t transmitFrame(const uint8_t* buffer, uint8_t length);
/**
* @brief Dynamically updates the transceiver operating frequency at runtime.
* @param msb Most Significant Byte of the frequency fraction.
* @param mid Middle Significant Byte of the frequency fraction.
* @param lsb Least Significant Byte of the frequency fraction.
* @brief Spawns a dedicated processing task context onto a specifically designated execution core.
* @param priority FreeRTOS scheduling execution assignment depth factor.
*/
void setFrequency(uint8_t msb, uint8_t mid, uint8_t lsb);
void startTask(uint32_t priority);
/**
* @brief Dynamically updates the LoRa signal bandwidth at runtime.
* @param bw_khz Target bandwidth in kHz (e.g., 62, 125, 250, 500).
* @brief Thread-safely updates the operational state tracking variables and overrides transceiver registers.
* @param freq_hz Core RF targeting frequency structured in absolute Hertz scale units.
*/
void setFrequency(uint32_t freq_hz);
/**
* @brief Thread-safely reads out the active target operation frequency metrics context.
* @return Current system baseline operational tuning value expressed in Hertz units.
*/
uint32_t getFrequency();
/**
* @brief Thread-safely updates the operational modem modulation parameter targets.
* @param bw_khz Operating modulation channel grid width metric parameters.
*/
void setBandwidth(uint32_t bw_khz);
private:
spi_device_handle_t m_spiHandle = nullptr;
TaskHandle_t m_taskHandle = nullptr;
SemaphoreHandle_t m_isrSemaphore = nullptr;
/**
* @brief Thread-safely updates the operational spreading factor configuration.
* @param sf Spreading factor scale (6-12).
*/
void setSpreadingFactor(uint8_t sf);
static const char* TAG;
/**
* @brief Thread-safely updates the operational coding rate protection overhead.
* @param cr_denominator Coding rate denominator index (5-8).
*/
void setCodingRate(uint8_t cr_denominator);
static void taskTrampoline(void* pvParameters);
static void IRAM_ATTR gpioIsrHandler(void* arg);
/**
* @brief Thread-safely logs an incoming transaction capture directly into the historical context nodes collection.
* @param packet Structural dataset mapping telemetry markers alongside the payload block.
* @param sequence Absolute hardware sequence reference step index.
* @return The unique database ID assigned to the tracking instance container wrapper node.
*/
uint32_t addPacketToList(const LoraPacket& packet, uint32_t sequence);
void run();
uint8_t readRegister(uint8_t address);
void writeRegister(uint8_t address, uint8_t value);
/**
* @brief Thread-safely extracts and purges an explicit single tracking record node entry via database criteria.
* @param databaseId Unique identifier associated with the specific targeted row block element to discard.
* @return True if a matching criteria target was located and eliminated, false if no ID matched.
*/
bool removePacketFromList(uint32_t databaseId);
esp_err_t initializeHardware();
void setModeReceiver();
/**
* @brief Thread-safely resets the tracked tracking records data tables list back to empty states.
*/
void clearPacketList();
/**
* @brief Thread-safely sorts the data list according to RSSI signal strength levels.
* @param ascending If true, lowest signal strengths come first; if false, strongest signals sort to front.
*/
void sortListByRssi(bool ascending = false);
/**
* @brief Thread-safely recovers structural chronological data ordering schemes according to database IDs.
*/
void sortListChronologically();
/**
* @brief Performs a deep copy operation over the linked list under mutex locks to return a safe detached copy.
* @return A standalone, thread-isolated linked list duplicate snapshot copy containing current history rows.
*/
std::list<LoraPacketNode> getPacketListCopy();
/**
* @brief Generates an atomic, high-performance runtime snapshot of configuration parameters and metrics.
* @details This routine performs a rapid, thread-safe memory copy of the volatile tracking state variables.
* Unlike getPacketListCopy(), this method explicitly excludes the heavy heap-allocated packet list data,
* making it exceptionally lightweight and highly suitable for high-frequency UI display refreshes,
* CLI updates, or periodic remote health diagnostics.
* @note Acquires the internal synchronization mutex lock momentarily to guarantee structural telemetry alignment.
* @return A self-contained snapshot structure mapping the current system hardware configurations and operational counts.
*/
LoraStateSnapshot getSnapshot();
};
+113
Datei anzeigen
@@ -0,0 +1,113 @@
/**
* @file lora_types.hpp
* @brief Definition of data structures, nodes, and state tables for the LoRa driver.
* @author OM Tom (OE3TKT)
*
* @license SPDX-License-Identifier: MIT
* @copyright Copyright (c) 2026 OM Tom (OE3TKT)
* For the full license terms, see the LICENSE file in the project root.
*/
#pragma once
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wpedantic"
#include <list>
#include <vector>
#pragma GCC diagnostic pop
#include <stdint.h>
/**
* @brief Structure representing a single packet node within the doubly-linked tracking list.
*/
struct LoraPacketNode {
/** @brief Dynamic raw binary storage buffer containing the received message payload. */
std::vector<uint8_t> payload;
/** @brief Unique auto-incremented database identifier for targeting explicit items. */
uint32_t databaseId;
/** @brief The absolute sequence index counting the packets received since device boot. */
uint32_t packetSequence;
/** @brief Received Signal Strength Indicator (RSSI) measured in dBm. */
float rssi;
/** @brief Signal-to-Noise Ratio (SNR) measured in dB. */
float snr;
/** @brief Payload size explicitly specified in bytes. */
uint8_t length;
};
/**
* @brief Runtime operational state table monitoring configurations and historical packet data.
* @note Optimized using "largest-to-smallest" data type ordering to completely eliminate memory padding.
*/
struct LoraStateTable {
/** @brief Central database component built on a doubly-linked list for versatile node operations. (Contains pointers) */
std::list<LoraPacketNode> packetList;
/** @brief Soft-limit threshold capping the maximum number of history records stored before auto-purge. (4 or 8 Bytes) */
size_t maxHistorySize = 10;
/** @brief RF carrier operating frequency configured in Hertz. (4 Bytes) */
uint32_t frequencyHz = 433175000;
/** @brief Accumulator metric track-counting successful ingress frames. (4 Bytes) */
uint32_t totalPacketsReceived = 0;
/** @brief Accumulator metric track-counting egress frames transmitted. (4 Bytes) */
uint32_t totalPacketsTransmitted = 0;
/** @brief Identity sequencer pointer controlling the next node's databaseId field. (4 Bytes) */
uint32_t nextDatabaseId = 1;
/** @brief Modem bandwidth performance target configured in kHz. (4 Bytes) */
uint32_t bandwidthKhz = 250;
/** @brief LoRa Spreading Factor configuration (typically ranges between 6 and 12). (1 Byte) */
uint8_t spreadingFactor = 11;
/** @brief Coding Rate denominator setting (e.g., value 6 yields a 4/6 coding protection overhead). (1 Byte) */
uint8_t codingRate = 6;
/** @brief True if hardware was successfully validated and attached during initialization. (1 Byte) */
bool isInitialized = false;
// The three 1-byte variables at the bottom align perfectly into a 32-bit slot, leaving minimal trailing padding.
};
/**
* @brief Thread-isolated telemetry snapshot for UI displays and remote diagnostics.
* @note Optimized using "largest-to-smallest" data type ordering to minimize memory padding.
*/
struct LoraStateSnapshot {
/** @brief Soft-limit threshold capping the maximum number of history records stored before auto-purge. (4 or 8 Bytes) */
size_t currentHistoryCount;
/** @brief RF carrier operating frequency configured in Hertz. (4 Bytes) */
uint32_t frequencyHz;
/** @brief Modem bandwidth performance target configured in kHz. (4 Bytes) */
uint32_t bandwidthKhz;
/** @brief Accumulator metric track-counting successful ingress frames. (4 Bytes) */
uint32_t totalPacketsReceived;
/** @brief Accumulator metric track-counting egress frames transmitted. (4 Bytes) */
uint32_t totalPacketsTransmitted;
/** @brief LoRa Spreading Factor configuration (typically ranges between 6 and 12). (1 Byte) */
uint8_t spreadingFactor;
/** @brief Coding Rate denominator setting (e.g., value 6 yields a 4/6 coding protection overhead). (1 Byte) */
uint8_t codingRate;
/** @brief True if hardware was successfully validated and attached during initialization. (1 Byte) */
bool isInitialized;
/** @brief Current Mode */
char currentModeStr[16];
// The three 1-byte variables at the bottom align perfectly into a 32-bit slot, leaving only 1 byte of trailing padding.
};
+3 -33
Datei anzeigen
@@ -12,7 +12,7 @@
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "driver/gpio.h"
#include "driver/spi_master.h"
//#include "driver/spi_master.h"
#include "esp_log.h"
#include "config.hpp"
#include "led.hpp"
@@ -46,32 +46,6 @@ LoraController* lora_module = nullptr;
*/
static LedController led(Config::LED_GPIO_PIN);
/**
* @brief Initializes the physical SPI peripheral for the Semtech SX1276 transceiver.
*
* Configures the VSPI (SPI3_HOST) back-end utilizing strict compile-time layouts
* mapped inside config.hpp and configures automatic DMA channel routing.
*/
void init_lora_spi(void) {
esp_err_t ret;
spi_bus_config_t buscfg = {};
buscfg.mosi_io_num = Config::LORA_MOSI_PIN;
buscfg.miso_io_num = Config::LORA_MISO_PIN;
buscfg.sclk_io_num = Config::LORA_SCK_PIN;
buscfg.quadwp_io_num = -1;
buscfg.quadhd_io_num = -1;
buscfg.max_transfer_sz = 0;
// Initialize the physical peripheral bus with automatic DMA channel assignment
ret = spi_bus_initialize(SPI3_HOST, &buscfg, SPI_DMA_CH_AUTO);
if (ret != ESP_OK) {
ESP_LOGE(TAG, "Failed to initialize SPI bus: %s", esp_err_to_name(ret));
return;
}
ESP_LOGI(TAG, "SPI bus initialized successfully on VSPI (SPI3)");
}
// Global application anchor marked as extern "C" for the native ESP-IDF bootloader
extern "C" {
/**
@@ -104,9 +78,6 @@ extern "C" {
// Pass the bus instance dependency to the interactive terminal layer
cli_init(i2c_bus, &led, display);
// Initialize the Semtech LoRa SPI connection layer
init_lora_spi();
// Spin up the background console interface thread on Core 0
start_cli_task();
@@ -117,7 +88,7 @@ extern "C" {
//connects the lora instance with the CLI control directly (commands freq and bw)
cli_init_lora(lora_module);
// start the radio task strict to the Core 1 (Priority 6)
// start the radio task straight to the Core 1 (Priority 6)
lora_module->startTask(6);
ESP_LOGI(TAG, "LoRa subsystem successfully activated on Core 1.");
} else {
@@ -127,11 +98,10 @@ extern "C" {
// Trigger synchronous welcome splash screen frame
if (display != nullptr) {
char msg[32];
//display->printMessage(0, "FoxMesh " Config::PROJECT_VERSION " \x86" "OE3TKT");
snprintf(msg, sizeof(msg), "FoxMesh %s OE3TKT", Config::PROJECT_VERSION);
display->printMessage(1, msg);
//display->printMessage(2, "Bärbel frühstückt ©");
}
// Main system watchdog and status monitor loop
while (true) {
ESP_LOGI(TAG, "[%s v%s] Operational. Free Heap: %lu bytes",