diff --git a/.github/workflows/build_one_target.yml b/.github/workflows/build_one_target.yml index 706b9cfe7..806df4e7a 100644 --- a/.github/workflows/build_one_target.yml +++ b/.github/workflows/build_one_target.yml @@ -4,9 +4,14 @@ on: workflow_dispatch: inputs: # trunk-ignore(checkov/CKV_GHA_7) + target: + type: string + required: false + description: Choose the target board, e.g. nrf52_promicro_diy_tcxo. If blank, will find available targets. arch: type: choice options: + - all - esp32 - esp32s3 - esp32c3 @@ -15,32 +20,18 @@ on: - rp2040 - rp2350 - stm32 - target: - type: string - required: false - description: Choose the target board, e.g. nrf52_promicro_diy_tcxo. If blank, will find available targets. - # find-target: - # type: boolean - # default: true - # description: 'Find the available targets' + description: Choose an arch to limit the search, or 'all' to search all architectures. + default: all permissions: read-all jobs: find-targets: - if: ${{ inputs.target == '' }} strategy: fail-fast: false matrix: arch: - - esp32 - - esp32s3 - - esp32c3 - - esp32c6 - - nrf52840 - - rp2040 - - rp2350 - - stm32 + - all runs-on: ubuntu-24.04 steps: - uses: actions/checkout@v6 @@ -51,14 +42,37 @@ jobs: - run: pip install -U platformio - name: Generate matrix id: jsonStep + env: + BUILDTARGET: ${{ inputs.target }} + MATRIXARCH: ${{ inputs.arch }} run: | TARGETS=$(./bin/generate_ci_matrix.py ${{matrix.arch}} --level extra) - echo "Name: $GITHUB_REF_NAME" >> $GITHUB_STEP_SUMMARY - echo "Base: $GITHUB_BASE_REF" >> $GITHUB_STEP_SUMMARY - echo "Arch: ${{matrix.arch}}" >> $GITHUB_STEP_SUMMARY - echo "Ref: $GITHUB_REF" >> $GITHUB_STEP_SUMMARY - echo "Targets:" >> $GITHUB_STEP_SUMMARY - echo $TARGETS | jq -r 'sort_by(.board) |.[] | "- " + .board' >> $GITHUB_STEP_SUMMARY + if [ "$BUILDTARGET" = "" ]; then + echo "Name: $GITHUB_REF_NAME" >> $GITHUB_STEP_SUMMARY + echo "Base: $GITHUB_BASE_REF" >> $GITHUB_STEP_SUMMARY + echo "Arch: $MATRIXARCH" >> $GITHUB_STEP_SUMMARY + echo "Ref: $GITHUB_REF" >> $GITHUB_STEP_SUMMARY + echo "## 🎯 The following target boards are available to build:" >> $GITHUB_STEP_SUMMARY + echo "| Platform | Board |" >> $GITHUB_STEP_SUMMARY + echo "| -------- | ----- |" >> $GITHUB_STEP_SUMMARY + echo $TARGETS | jq -r 'sort_by(.board) | sort_by(.platform) |.[] | "| " + .platform + " | " + .board + " |" ' >> $GITHUB_STEP_SUMMARY + else + echo "We build this one:" >> $GITHUB_STEP_SUMMARY + ARCH=$(echo "$TARGETS" | jq --arg BUILDTARGET "$BUILDTARGET" -r '.[] | select(.board==$BUILDTARGET) | .platform') + echo "| Platform | Board |" >> $GITHUB_STEP_SUMMARY + echo "| -------- | ----- |" >> $GITHUB_STEP_SUMMARY + echo "| $ARCH | "$BUILDTARGET" |" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + if [[ "$ARCH" == "" ]]; then + echo "## ❌ Error: Target "$BUILDTARGET" not found!" >> $GITHUB_STEP_SUMMARY + else + echo "## ✅ Target "$BUILDTARGET" found, proceeding to build." >> $GITHUB_STEP_SUMMARY + fi + echo "You may need to refresh this page to make the built firmware appear below." >> $GITHUB_STEP_SUMMARY + echo "arch=$ARCH" >> $GITHUB_OUTPUT + fi + outputs: + arch: ${{ steps.jsonStep.outputs.arch }} version: if: ${{ inputs.target != '' }} @@ -78,12 +92,12 @@ jobs: build: if: ${{ inputs.target != '' && inputs.arch != 'native' }} - needs: [version] + needs: [version, find-targets] uses: ./.github/workflows/build_firmware.yml with: version: ${{ needs.version.outputs.long }} pio_env: ${{ inputs.target }} - platform: ${{ inputs.arch }} + platform: ${{ needs.find-targets.outputs.arch }} gather-artifacts: permissions: diff --git a/.github/workflows/docker_build.yml b/.github/workflows/docker_build.yml index 72987c01e..d9b23a7e8 100644 --- a/.github/workflows/docker_build.yml +++ b/.github/workflows/docker_build.yml @@ -56,6 +56,25 @@ jobs: echo "long=$(./bin/buildinfo.py long)" >> $GITHUB_OUTPUT id: version + - name: Set up QEMU + uses: docker/setup-qemu-action@v4 + with: + cache-image: true + + - name: Docker setup + uses: docker/setup-buildx-action@v4 + with: + # Add Google/Amazon DockerHub mirrors to buildkit config + # https://docs.docker.com/build/ci/github-actions/configure-builder/#registry-mirror + buildkitd-config-inline: | + [registry."docker.io"] + mirrors = ["mirror.gcr.io", "public.ecr.aws"] + + - name: Sanitize platform string + id: sanitize_platform + # Replace slashes with underscores + run: echo "cleaned_platform=${{ inputs.platform }}" | sed 's/\//_/g' >> $GITHUB_OUTPUT + - name: Docker login if: ${{ inputs.push }} uses: docker/login-action@v4 @@ -63,17 +82,6 @@ jobs: username: meshtastic password: ${{ secrets.DOCKER_FIRMWARE_TOKEN }} - - name: Set up QEMU - uses: docker/setup-qemu-action@v4 - - - name: Docker setup - uses: docker/setup-buildx-action@v4 - - - name: Sanitize platform string - id: sanitize_platform - # Replace slashes with underscores - run: echo "cleaned_platform=${{ inputs.platform }}" | sed 's/\//_/g' >> $GITHUB_OUTPUT - - name: Docker tag id: meta uses: docker/metadata-action@v6 @@ -95,3 +103,6 @@ jobs: platforms: ${{ inputs.platform }} build-args: | PIO_ENV=${{ inputs.pio_env }} + # Cache image layers in GitHub Actions cache to speed up subsequent builds. + cache-from: type=gha + cache-to: type=gha,mode=max diff --git a/.github/workflows/main_matrix.yml b/.github/workflows/main_matrix.yml index 1221c171f..f0b16a31f 100644 --- a/.github/workflows/main_matrix.yml +++ b/.github/workflows/main_matrix.yml @@ -309,7 +309,7 @@ jobs: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - name: Create release - uses: softprops/action-gh-release@v2 + uses: softprops/action-gh-release@v3 id: create_release with: draft: true diff --git a/.github/workflows/models_issue_triage.yml b/.github/workflows/models_issue_triage.yml index ef12885f8..a02646ea0 100644 --- a/.github/workflows/models_issue_triage.yml +++ b/.github/workflows/models_issue_triage.yml @@ -38,7 +38,7 @@ jobs: - name: Apply quality label if needed if: steps.quality.outputs.response != '' && steps.quality.outputs.response != 'ok' - uses: actions/github-script@v8 + uses: actions/github-script@v9 env: QUALITY_LABEL: ${{ steps.quality.outputs.response }} with: @@ -80,7 +80,7 @@ jobs: # ───────────────────────────────────────────────────────────────────────── - name: Determine if completeness check should be skipped if: steps.quality.outputs.response == 'ok' || steps.quality.outputs.response == '' - uses: actions/github-script@v8 + uses: actions/github-script@v9 id: check-skip with: script: | @@ -134,7 +134,7 @@ jobs: - name: Process analysis result if: (steps.quality.outputs.response == 'ok' || steps.quality.outputs.response == '') && steps.check-skip.outputs.should_skip != 'true' && steps.analysis.outputs.response != '' - uses: actions/github-script@v8 + uses: actions/github-script@v9 id: process env: AI_RESPONSE: ${{ steps.analysis.outputs.response }} @@ -174,7 +174,7 @@ jobs: - name: Apply triage label if: steps.process.outputs.label != '' && steps.process.outputs.label != 'none' - uses: actions/github-script@v8 + uses: actions/github-script@v9 env: LABEL_NAME: ${{ steps.process.outputs.label }} with: @@ -200,7 +200,7 @@ jobs: - name: Comment on issue if: steps.process.outputs.should_comment == 'true' - uses: actions/github-script@v8 + uses: actions/github-script@v9 env: COMMENT_BODY: ${{ steps.process.outputs.comment_body }} with: diff --git a/.github/workflows/models_pr_triage.yml b/.github/workflows/models_pr_triage.yml index d4c8509d2..f39ee4845 100644 --- a/.github/workflows/models_pr_triage.yml +++ b/.github/workflows/models_pr_triage.yml @@ -22,7 +22,7 @@ jobs: # Step 1: Check if PR already has automation/type labels (skip if so) # ───────────────────────────────────────────────────────────────────────── - name: Check existing labels - uses: actions/github-script@v8 + uses: actions/github-script@v9 id: check-labels with: script: | @@ -58,7 +58,7 @@ jobs: - name: Apply quality label if needed if: steps.check-labels.outputs.skip_all != 'true' && steps.quality.outputs.response != '' && steps.quality.outputs.response != 'ok' - uses: actions/github-script@v8 + uses: actions/github-script@v9 id: quality-label env: QUALITY_LABEL: ${{ steps.quality.outputs.response }} @@ -113,7 +113,7 @@ jobs: - name: Apply type label if: steps.check-labels.outputs.skip_all != 'true' && steps.check-labels.outputs.has_type_label != 'true' && steps.classify.outputs.response != '' - uses: actions/github-script@v8 + uses: actions/github-script@v9 env: TYPE_LABEL: ${{ steps.classify.outputs.response }} with: diff --git a/.github/workflows/package_ppa.yml b/.github/workflows/package_ppa.yml index 334a7016d..c51e64e78 100644 --- a/.github/workflows/package_ppa.yml +++ b/.github/workflows/package_ppa.yml @@ -5,6 +5,8 @@ on: secrets: PPA_GPG_PRIVATE_KEY: required: true + PPA_SFTP_PRIVATE_KEY: + required: true inputs: ppa_repo: description: Meshtastic PPA to target @@ -27,6 +29,7 @@ jobs: build_location: ppa package-ppa: + if: ${{ github.event_name != 'pull_request_target' && github.event_name != 'pull_request' }} runs-on: ubuntu-24.04 needs: build-debian-src steps: @@ -40,7 +43,7 @@ jobs: shell: bash run: | sudo apt-get update -y --fix-missing - sudo apt-get install -y dput + sudo apt-get install -y dput openssh-client - name: Import GPG key uses: crazy-max/ghaction-import-gpg@v7 @@ -65,8 +68,42 @@ jobs: - name: Display structure of downloaded files run: ls -lah - - name: Publish with dput - if: ${{ github.event_name != 'pull_request_target' && github.event_name != 'pull_request' }} - timeout-minutes: 15 # dput is terrible, sometimes runs 'forever' + - name: Trust Launchpad's SSH key run: | - dput ${{ inputs.ppa_repo }} meshtasticd_${{ steps.version.outputs.deb }}~${{ inputs.series }}_source.changes + mkdir -p ~/.ssh + ssh-keyscan -H ppa.launchpad.net >> ~/.ssh/known_hosts + + - name: Setup dput config + env: + ppa_login: meshtasticorg + run: | + sudo tee /etc/meshtastic-dput.cf >/dev/null < + dput -c /etc/meshtastic-dput.cf + ssh-${up_ppa_repo} + meshtasticd_${up_version}~${up_series}_source.changes diff --git a/.github/workflows/pr_enforce_labels.yml b/.github/workflows/pr_enforce_labels.yml index d60c9c8ca..bf2239f63 100644 --- a/.github/workflows/pr_enforce_labels.yml +++ b/.github/workflows/pr_enforce_labels.yml @@ -13,7 +13,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Check for PR labels - uses: actions/github-script@v8 + uses: actions/github-script@v9 with: script: | const labels = context.payload.pull_request.labels.map(label => label.name); diff --git a/.github/workflows/pr_tests.yml b/.github/workflows/pr_tests.yml index 3556226ba..e3321712e 100644 --- a/.github/workflows/pr_tests.yml +++ b/.github/workflows/pr_tests.yml @@ -177,7 +177,7 @@ jobs: - name: Comment test results on PR if: github.event_name == 'pull_request' && needs.native-tests.result != 'skipped' - uses: actions/github-script@v8 + uses: actions/github-script@v9 with: script: | const fs = require('fs'); diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index daa18e6af..be5142843 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -52,7 +52,7 @@ jobs: node-version: 24 - name: Setup pnpm - uses: pnpm/action-setup@v5 + uses: pnpm/action-setup@v6 with: version: latest diff --git a/.trunk/trunk.yaml b/.trunk/trunk.yaml index 5ecc0aeba..d0cbaa8bc 100644 --- a/.trunk/trunk.yaml +++ b/.trunk/trunk.yaml @@ -8,20 +8,20 @@ plugins: uri: https://github.com/trunk-io/plugins lint: enabled: - - checkov@3.2.511 - - renovate@43.92.1 + - checkov@3.2.517 + - renovate@43.110.9 - prettier@3.8.1 - - trufflehog@3.94.1 + - trufflehog@3.94.3 - yamllint@1.38.0 - bandit@1.9.4 - trivy@0.69.3 - taplo@0.10.0 - - ruff@0.15.8 + - ruff@0.15.9 - isort@8.0.1 - markdownlint@0.48.0 - oxipng@10.1.0 - svgo@4.0.1 - - actionlint@1.7.11 + - actionlint@1.7.12 - flake8@7.3.0 - hadolint@2.14.0 - shfmt@3.6.0 diff --git a/bin/config.d/femtofox/femtofox_E80-900M2213S.yaml b/bin/config.d/femtofox/femtofox_E80-900M2213S.yaml new file mode 100644 index 000000000..2f2b24603 --- /dev/null +++ b/bin/config.d/femtofox/femtofox_E80-900M2213S.yaml @@ -0,0 +1,30 @@ +--- +Lora: +## Ebyte E80-900M22S +## This is a bit experimental +## +## + Module: lr1121 + gpiochip: 1 # subtract 32 from the gpio numbers + DIO3_TCXO_VOLTAGE: 1.8 + CS: 16 #pin6 / GPIO48 1C0 + IRQ: 23 #pin17 / GPIO55 1C7 + Busy: 22 #pin16 / GPIO54 1C6 + Reset: 25 #pin13 / GPIO57 1D1 + + + spidev: spidev0.0 #pins are (CS=16, CLK=17, MOSI=18, MISO=19) + spiSpeed: 2000000 + +rfswitch_table: + pins: [DIO5, DIO6, DIO7] + MODE_STBY: [LOW, LOW, LOW] + MODE_RX: [LOW, HIGH, LOW] + MODE_TX: [HIGH, HIGH, LOW] + MODE_TX_HP: [HIGH, LOW, LOW] + MODE_TX_HF: [LOW, LOW, LOW] + MODE_GNSS: [LOW, LOW, HIGH] + MODE_WIFI: [LOW, LOW, LOW] + +General: + MACAddressSource: eth0 diff --git a/bin/config.d/femtofox/femtofox_LR1121 generic.yaml b/bin/config.d/femtofox/femtofox_LR1121 generic.yaml new file mode 100644 index 000000000..c66eebed5 --- /dev/null +++ b/bin/config.d/femtofox/femtofox_LR1121 generic.yaml @@ -0,0 +1,46 @@ +--- +Lora: +## Ebyte E80-900M22S +## This is a bit experimental +## +## + Module: lr1121 + gpiochip: 1 # subtract 32 from the gpio numbers + DIO3_TCXO_VOLTAGE: 1.8 + CS: 16 #pin6 / GPIO48 1C0 + IRQ: 23 #pin17 / GPIO55 1C7 + Busy: 22 #pin16 / GPIO54 1C6 + Reset: 25 #pin13 / GPIO57 1D1 + + + spidev: spidev0.0 #pins are (CS=16, CLK=17, MOSI=18, MISO=19) + spiSpeed: 2000000 + +rfswitch_table: + pins: + - DIO5 + - DIO6 + MODE_STBY: + - LOW + - LOW + MODE_RX: + - HIGH + - LOW + MODE_TX: + - HIGH + - HIGH + MODE_TX_HP: + - LOW + - HIGH + MODE_TX_HF: + - LOW + - LOW + MODE_GNSS: + - LOW + - LOW + MODE_WIFI: + - LOW + - LOW + +General: + MACAddressSource: eth0 diff --git a/bin/config.d/femtofox/femtofox_WIO-LR1121.yaml b/bin/config.d/femtofox/femtofox_WIO-LR1121.yaml new file mode 100644 index 000000000..c2ab76d46 --- /dev/null +++ b/bin/config.d/femtofox/femtofox_WIO-LR1121.yaml @@ -0,0 +1,30 @@ +--- +Lora: +## Ebyte E80-900M22S +## This is a bit experimental +## +## + Module: lr1121 + gpiochip: 1 # subtract 32 from the gpio numbers + DIO3_TCXO_VOLTAGE: 1.8 + CS: 16 #pin6 / GPIO48 1C0 + IRQ: 23 #pin17 / GPIO55 1C7 + Busy: 22 #pin16 / GPIO54 1C6 + Reset: 25 #pin13 / GPIO57 1D1 + + + spidev: spidev0.0 #pins are (CS=16, CLK=17, MOSI=18, MISO=19) + spiSpeed: 2000000 + +rfswitch_table: + pins: [DIO5, DIO6, DIO7] + MODE_STBY: [LOW, LOW, LOW] + MODE_RX: [LOW, LOW, LOW] + MODE_TX: [LOW, HIGH, LOW] + MODE_TX_HP: [HIGH, LOW, LOW] + # MODE_TX_HF: [] + # MODE_GNSS: [] + MODE_WIFI: [LOW, LOW, LOW] + +General: + MACAddressSource: eth0 diff --git a/bin/config.d/lora-ecb41-pge-MeshAdv-900M30S.yaml b/bin/config.d/lora-ecb41-pge-MeshAdv-900M30S.yaml new file mode 100644 index 000000000..25fd5e359 --- /dev/null +++ b/bin/config.d/lora-ecb41-pge-MeshAdv-900M30S.yaml @@ -0,0 +1,39 @@ +# MeshAdv-Pi E22-900M30S +# https://github.com/chrismyers2000/MeshAdv-Pi-Hat +Meta: + name: MeshAdv-Pi E22-900M30S + support: community + compatible: + - ebyte-ecb41-pge # Armbian + +Lora: + Module: sx1262 + CS: # GPIO0_A1 (physical 40) + pin: 1 + gpiochip: 0 + line: 1 + IRQ: # GPIO0_A3 (physical 36) + pin: 3 + gpiochip: 0 + line: 3 + Busy: # GPIO0_A0 (physical 38) + pin: 0 + gpiochip: 0 + line: 0 + Reset: # GPIO0_B4 (physical 12) + pin: 12 + gpiochip: 0 + line: 12 + TXen: # GPIO1_D1 (physical 33) + pin: 57 + gpiochip: 1 + line: 25 + RXen: # GPIO1_B3 (physical 32) + pin: 43 + gpiochip: 1 + line: 11 + DIO3_TCXO_VOLTAGE: true + # Only for E22-900M33S: + # Limit the output power to 8 dBm + # SX126X_MAX_POWER: 8 + spidev: spidev0.0 diff --git a/bin/config.d/lora-ecb41-pge-MeshAdv-Mini-900M22S.yaml b/bin/config.d/lora-ecb41-pge-MeshAdv-Mini-900M22S.yaml new file mode 100644 index 000000000..e1f385312 --- /dev/null +++ b/bin/config.d/lora-ecb41-pge-MeshAdv-Mini-900M22S.yaml @@ -0,0 +1,33 @@ +# MeshAdv Mini E22-900M22S +# https://github.com/chrismyers2000/MeshAdv-Mini +Meta: + name: MeshAdv Mini E22-900M22S + support: community + compatible: + - ebyte-ecb41-pge # Armbian + +Lora: + Module: sx1262 # Ebyte E22-900M22S + CS: # GPIO0_B6 (physical 24, SPI1_CSN0) + pin: 14 + gpiochip: 0 + line: 14 + IRQ: # GPIO0_A3 (physical 36) + pin: 3 + gpiochip: 0 + line: 3 + Busy: # GPIO0_A0 (physical 38) + pin: 0 + gpiochip: 0 + line: 0 + Reset: # GPIO1_C3 (physical 18) + pin: 51 + gpiochip: 1 + line: 19 + RXen: # GPIO1_B3 (physical 32) + pin: 43 + gpiochip: 1 + line: 11 + DIO2_AS_RF_SWITCH: true + DIO3_TCXO_VOLTAGE: true + spidev: spidev0.0 diff --git a/bin/config.d/lora-ecb41-pge-RAK6421-13300-slot1.yaml b/bin/config.d/lora-ecb41-pge-RAK6421-13300-slot1.yaml new file mode 100644 index 000000000..8782876ac --- /dev/null +++ b/bin/config.d/lora-ecb41-pge-RAK6421-13300-slot1.yaml @@ -0,0 +1,38 @@ +Meta: + name: RAK6421 + RAK13300 Slot 1 + support: community # Promote when tested + compatible: + - ebyte-ecb41-pge # Armbian + +Lora: + Module: sx1262 + IRQ: # GPIO0_A5 (IO6, physical 15) + pin: 5 + gpiochip: 0 + line: 5 + Reset: # GPIO0_A3 (IO4, physical 36) + pin: 3 + gpiochip: 0 + line: 3 + Busy: # GPIO1_C3 (IO5, physical 18) + pin: 51 + gpiochip: 1 + line: 19 + # Ant_sw: # GPIO1_C2 (IO3, physical 16) + # pin: 50 + # gpiochip: 1 + # line: 18 + Enable_Pins: + - pin: 43 # GPIO1_B3 (physical 32) + gpiochip: 1 + line: 11 + - pin: 57 # GPIO1_D1 (physical 33) + gpiochip: 1 + line: 25 + DIO3_TCXO_VOLTAGE: true + DIO2_AS_RF_SWITCH: true + spidev: spidev0.0 + # CS: # GPIO0_B6 (SPI1_CSN0, physical 24) + # pin: 14 + # gpiochip: 0 + # line: 14 diff --git a/bin/config.d/lora-ecb41-pge-RAK6421-13300-slot2.yaml b/bin/config.d/lora-ecb41-pge-RAK6421-13300-slot2.yaml new file mode 100644 index 000000000..e0ef946d9 --- /dev/null +++ b/bin/config.d/lora-ecb41-pge-RAK6421-13300-slot2.yaml @@ -0,0 +1,36 @@ +Meta: + name: RAK6421 + RAK13300 Slot 2 + support: community # Promote when tested + compatible: + - ebyte-ecb41-pge # Armbian + +Lora: + Module: sx1262 + IRQ: # GPIO0_B4 (IO6, physical 12) + pin: 12 + gpiochip: 0 + line: 12 + Reset: # GPIO1_C3 (IO4, physical 18) + pin: 51 + gpiochip: 1 + line: 19 + Busy: # GPIO0_B3 (IO5, physical 35) + pin: 11 + gpiochip: 0 + line: 11 + # Ant_sw: # GPIO1_C2 (IO3, physical 16) + # pin: 50 + # gpiochip: 1 + # line: 18 + Enable_Pins: + - pin: 2 # GPIO0_A2 (physical 37) + gpiochip: 0 + line: 2 + - pin: 50 # GPIO1_C2 (physical 16) + gpiochip: 1 + line: 18 + spidev: spidev0.1 + # CS: # GPIO0_A7 (SPI1_CSN1, physical 26) + # pin: 7 + # gpiochip: 0 + # line: 7 diff --git a/bin/config.d/lora-ecb41-pge-RAK6421-13302-slot1.yaml b/bin/config.d/lora-ecb41-pge-RAK6421-13302-slot1.yaml new file mode 100644 index 000000000..374be8e35 --- /dev/null +++ b/bin/config.d/lora-ecb41-pge-RAK6421-13302-slot1.yaml @@ -0,0 +1,39 @@ +Meta: + name: RAK6421 + RAK13302 Slot 1 + support: community # Promote when tested + compatible: + - ebyte-ecb41-pge # Armbian + +Lora: + Module: sx1262 + IRQ: # GPIO0_A5 (IO6, physical 15) + pin: 5 + gpiochip: 0 + line: 5 + Reset: # GPIO0_A3 (IO4, physical 36) + pin: 3 + gpiochip: 0 + line: 3 + Busy: # GPIO1_C3 (IO5, physical 18) + pin: 51 + gpiochip: 1 + line: 19 + # Ant_sw: # GPIO1_C2 (IO3, physical 16) + # pin: 50 + # gpiochip: 1 + # line: 18 + Enable_Pins: + - pin: 43 # GPIO1_B3 (physical 32) + gpiochip: 1 + line: 11 + - pin: 57 # GPIO1_D1 (physical 33) + gpiochip: 1 + line: 25 + DIO3_TCXO_VOLTAGE: true + DIO2_AS_RF_SWITCH: true + spidev: spidev0.0 + # CS: # GPIO0_B6 (SPI1_CSN0, physical 24) + # pin: 14 + # gpiochip: 0 + # line: 14 + TX_GAIN_LORA: [9, 9, 10, 11, 9, 8, 9, 10, 10, 10, 11, 12, 12, 12, 12, 12, 12, 12, 12, 10, 9, 8] diff --git a/bin/config.d/lora-ecb41-pge-RAK6421-13302-slot2.yaml b/bin/config.d/lora-ecb41-pge-RAK6421-13302-slot2.yaml new file mode 100644 index 000000000..5548bc5c7 --- /dev/null +++ b/bin/config.d/lora-ecb41-pge-RAK6421-13302-slot2.yaml @@ -0,0 +1,37 @@ +Meta: + name: RAK6421 + RAK13302 Slot 2 + support: community # Promote when tested + compatible: + - ebyte-ecb41-pge # Armbian + +Lora: + Module: sx1262 + IRQ: # GPIO0_B4 (IO6, physical 12) + pin: 12 + gpiochip: 0 + line: 12 + Reset: # GPIO1_C3 (IO4, physical 18) + pin: 51 + gpiochip: 1 + line: 19 + Busy: # GPIO0_B3 (IO5, physical 35) + pin: 11 + gpiochip: 0 + line: 11 + # Ant_sw: # GPIO1_C2 (IO3, physical 16) + # pin: 50 + # gpiochip: 1 + # line: 18 + Enable_Pins: + - pin: 2 # GPIO0_A2 (physical 37) + gpiochip: 0 + line: 2 + - pin: 50 # GPIO1_C2 (physical 16) + gpiochip: 1 + line: 18 + spidev: spidev0.1 + # CS: # GPIO0_A7 (SPI1_CSN1, physical 26) + # pin: 7 + # gpiochip: 0 + # line: 7 + TX_GAIN_LORA: [9, 9, 10, 11, 9, 8, 9, 10, 10, 10, 11, 12, 12, 12, 12, 12, 12, 12, 12, 10, 9, 8] diff --git a/bin/config.d/lora-ecb41-pge-waveshare-sxxx.yaml b/bin/config.d/lora-ecb41-pge-waveshare-sxxx.yaml new file mode 100644 index 000000000..1253d3e31 --- /dev/null +++ b/bin/config.d/lora-ecb41-pge-waveshare-sxxx.yaml @@ -0,0 +1,30 @@ +Meta: + name: Waveshare SX1262 + support: deprecated + compatible: + - ebyte-ecb41-pge # Armbian + +Lora: + Module: sx1262 # Waveshare SX126X XXXM + DIO2_AS_RF_SWITCH: true + CS: # GPIO0_A1 (physical 40) + pin: 1 + gpiochip: 0 + line: 1 + IRQ: # GPIO0_A3 (physical 36) + pin: 3 + gpiochip: 0 + line: 3 + Busy: # GPIO0_A0 (physical 38) + pin: 0 + gpiochip: 0 + line: 0 + Reset: # GPIO0_B4 (physical 12) + pin: 12 + gpiochip: 0 + line: 12 + SX126X_ANT_SW: # GPIO1_B2 (physical 31) + pin: 42 + gpiochip: 1 + line: 10 + spidev: spidev0.0 diff --git a/bin/config.d/lora-lyra-zero-MeshAdv-900M30S.yaml b/bin/config.d/lora-lyra-zero-MeshAdv-900M30S.yaml new file mode 100644 index 000000000..ea22c7953 --- /dev/null +++ b/bin/config.d/lora-lyra-zero-MeshAdv-900M30S.yaml @@ -0,0 +1,39 @@ +# MeshAdv-Pi E22-900M30S +# https://github.com/chrismyers2000/MeshAdv-Pi-Hat +Meta: + name: MeshAdv-Pi E22-900M30S + support: community + compatible: + - luckfox-lyra-zero-w # Armbian + +Lora: + Module: sx1262 + CS: # GPIO0_C2 (physical 40) + pin: 18 + gpiochip: 0 + line: 18 + IRQ: # GPIO1_D1 (physical 36) + pin: 57 + gpiochip: 1 + line: 25 + Busy: # GPIO0_C1 (physical 38) + pin: 17 + gpiochip: 0 + line: 17 + Reset: # GPIO0_B6 (physical 12) + pin: 14 + gpiochip: 0 + line: 14 + TXen: # GPIO1_C2 (physical 33) + pin: 50 + gpiochip: 1 + line: 18 + RXen: # GPIO1_D2 (physical 32) + pin: 58 + gpiochip: 1 + line: 26 + DIO3_TCXO_VOLTAGE: true + # Only for E22-900M33S: + # Limit the output power to 8 dBm + # SX126X_MAX_POWER: 8 + spidev: spidev0.0 diff --git a/bin/config.d/lora-lyra-zero-MeshAdv-Mini-900M22S.yaml b/bin/config.d/lora-lyra-zero-MeshAdv-Mini-900M22S.yaml new file mode 100644 index 000000000..1fb150b15 --- /dev/null +++ b/bin/config.d/lora-lyra-zero-MeshAdv-Mini-900M22S.yaml @@ -0,0 +1,33 @@ +# MeshAdv Mini E22-900M22S +# https://github.com/chrismyers2000/MeshAdv-Mini +Meta: + name: MeshAdv Mini E22-900M22S + support: community + compatible: + - luckfox-lyra-zero-w # Armbian + +Lora: + Module: sx1262 # Ebyte E22-900M22S + CS: # GPIO0_B2_d (phys 24, RPi CE0) + pin: 10 + gpiochip: 0 + line: 10 + IRQ: # GPIO1_D1_d (phys 36, RPi GPIO16) + pin: 57 + gpiochip: 1 + line: 25 + Busy: # GPIO0_C1_d (phys 38, RPi GPIO20) + pin: 17 + gpiochip: 0 + line: 17 + Reset: # GPIO0_B4_d (phys 18, RPi GPIO24) + pin: 12 + gpiochip: 0 + line: 12 + RXen: # GPIO1_D2_d (phys 32, RPi GPIO12) + pin: 58 + gpiochip: 1 + line: 26 + DIO2_AS_RF_SWITCH: true + DIO3_TCXO_VOLTAGE: true + spidev: spidev0.0 diff --git a/bin/config.d/lora-lyra-zero-RAK6421-13300-slot1.yaml b/bin/config.d/lora-lyra-zero-RAK6421-13300-slot1.yaml new file mode 100644 index 000000000..b65a30c20 --- /dev/null +++ b/bin/config.d/lora-lyra-zero-RAK6421-13300-slot1.yaml @@ -0,0 +1,38 @@ +Meta: + name: RAK6421 + RAK13300 Slot 1 + support: community # Promote when tested + compatible: + - luckfox-lyra-zero-w # Armbian + +Lora: + Module: sx1262 + IRQ: # GPIO0_A5 (IO6) + pin: 5 + gpiochip: 0 + line: 5 + Reset: # GPIO1_D1 (IO4) + pin: 57 + gpiochip: 1 + line: 25 + Busy: # GPIO0_B4 (IO5) + pin: 12 + gpiochip: 0 + line: 12 + # Ant_sw: # GPIO1_C2 (IO3) + # pin: 50 + # gpiochip: 1 + # line: 18 + Enable_Pins: + - pin: 58 # GPIO1_D2 + gpiochip: 1 + line: 26 + - pin: 50 # GPIO1_C2 + gpiochip: 1 + line: 18 + DIO3_TCXO_VOLTAGE: true + DIO2_AS_RF_SWITCH: true + spidev: spidev0.0 + # CS: # GPIO0_B2 + # pin: 10 + # gpiochip: 0 + # line: 10 diff --git a/bin/config.d/lora-lyra-zero-RAK6421-13300-slot2.yaml b/bin/config.d/lora-lyra-zero-RAK6421-13300-slot2.yaml new file mode 100644 index 000000000..255a3eca3 --- /dev/null +++ b/bin/config.d/lora-lyra-zero-RAK6421-13300-slot2.yaml @@ -0,0 +1,36 @@ +Meta: + name: RAK6421 + RAK13300 Slot 2 + support: community # Promote when tested + compatible: + - luckfox-lyra-zero-w # Armbian + +Lora: + Module: sx1262 + IRQ: # GPIO0_B6 (IO6) + pin: 14 + gpiochip: 0 + line: 14 + Reset: # GPIO0_B4 (IO4) + pin: 12 + gpiochip: 0 + line: 12 + Busy: # GPIO1_C0 (IO5) + pin: 48 + gpiochip: 1 + line: 16 + # Ant_sw: # GPIO0_B5 (IO3) + # pin: 13 + # gpiochip: 0 + # line: 13 + Enable_Pins: + - pin: 51 # GPIO1_C3 + gpiochip: 1 + line: 19 + - pin: 13 # GPIO0_B5 + gpiochip: 0 + line: 13 + spidev: spidev0.1 + # CS: # GPIO0_B1 + # pin: 9 + # gpiochip: 0 + # line: 9 diff --git a/bin/config.d/lora-lyra-zero-RAK6421-13302-slot1.yaml b/bin/config.d/lora-lyra-zero-RAK6421-13302-slot1.yaml new file mode 100644 index 000000000..c37c6fb3a --- /dev/null +++ b/bin/config.d/lora-lyra-zero-RAK6421-13302-slot1.yaml @@ -0,0 +1,39 @@ +Meta: + name: RAK6421 + RAK13300 Slot 1 + support: community # Promote when tested + compatible: + - luckfox-lyra-zero-w # Armbian + +Lora: + Module: sx1262 + IRQ: # GPIO0_A5 (IO6) + pin: 5 + gpiochip: 0 + line: 5 + Reset: # GPIO1_D1 (IO4) + pin: 57 + gpiochip: 1 + line: 25 + Busy: # GPIO0_B4 (IO5) + pin: 12 + gpiochip: 0 + line: 12 + # Ant_sw: # GPIO1_C2 (IO3) + # pin: 50 + # gpiochip: 1 + # line: 18 + Enable_Pins: + - pin: 58 # GPIO1_D2 + gpiochip: 1 + line: 26 + - pin: 50 # GPIO1_C2 + gpiochip: 1 + line: 18 + DIO3_TCXO_VOLTAGE: true + DIO2_AS_RF_SWITCH: true + spidev: spidev0.0 + # CS: # GPIO0_B2 + # pin: 10 + # gpiochip: 0 + # line: 10 + TX_GAIN_LORA: [9, 9, 10, 11, 9, 8, 9, 10, 10, 10, 11, 12, 12, 12, 12, 12, 12, 12, 12, 10, 9, 8] diff --git a/bin/config.d/lora-lyra-zero-RAK6421-13302-slot2.yaml b/bin/config.d/lora-lyra-zero-RAK6421-13302-slot2.yaml new file mode 100644 index 000000000..773a35ab0 --- /dev/null +++ b/bin/config.d/lora-lyra-zero-RAK6421-13302-slot2.yaml @@ -0,0 +1,37 @@ +Meta: + name: RAK6421 + RAK13300 Slot 2 + support: community # Promote when tested + compatible: + - luckfox-lyra-zero-w # Armbian + +Lora: + Module: sx1262 + IRQ: # GPIO0_B6 (IO6) + pin: 14 + gpiochip: 0 + line: 14 + Reset: # GPIO0_B4 (IO4) + pin: 12 + gpiochip: 0 + line: 12 + Busy: # GPIO1_C0 (IO5) + pin: 48 + gpiochip: 1 + line: 16 + # Ant_sw: # GPIO0_B5 (IO3) + # pin: 13 + # gpiochip: 0 + # line: 13 + Enable_Pins: + - pin: 51 # GPIO1_C3 + gpiochip: 1 + line: 19 + - pin: 13 # GPIO0_B5 + gpiochip: 0 + line: 13 + spidev: spidev0.1 + # CS: # GPIO0_B1 + # pin: 9 + # gpiochip: 0 + # line: 9 + TX_GAIN_LORA: [9, 9, 10, 11, 9, 8, 9, 10, 10, 10, 11, 12, 12, 12, 12, 12, 12, 12, 12, 10, 9, 8] diff --git a/bin/config.d/lora-lyra-zero-waveshare-sxxx.yaml b/bin/config.d/lora-lyra-zero-waveshare-sxxx.yaml new file mode 100644 index 000000000..934945202 --- /dev/null +++ b/bin/config.d/lora-lyra-zero-waveshare-sxxx.yaml @@ -0,0 +1,30 @@ +Meta: + name: Waveshare SX1262 + support: deprecated + compatible: + - luckfox-lyra-zero-w # Armbian + +Lora: + Module: sx1262 # Waveshare SX126X XXXM + DIO2_AS_RF_SWITCH: true + CS: # GPIO0_C2 (physical 40) + pin: 18 + gpiochip: 0 + line: 18 + IRQ: # GPIO1_D1 (physical 36) + pin: 57 + gpiochip: 1 + line: 25 + Busy: # GPIO0_C1 (physical 38) + pin: 17 + gpiochip: 0 + line: 17 + Reset: # GPIO0_B6 (physical 12) + pin: 14 + gpiochip: 0 + line: 14 + SX126X_ANT_SW: # GPIO1_B3 (physical 31) + pin: 43 + gpiochip: 1 + line: 11 + spidev: spidev0.0 diff --git a/bin/config.d/lora-ok3506-MeshAdv-900M30S.yaml b/bin/config.d/lora-ok3506-MeshAdv-900M30S.yaml new file mode 100644 index 000000000..c39a07ccd --- /dev/null +++ b/bin/config.d/lora-ok3506-MeshAdv-900M30S.yaml @@ -0,0 +1,41 @@ +# !! WARNING: Hats on the OK3506 board are installed "backwards" (facing outwards) + +# MeshAdv-Pi E22-900M30S +# https://github.com/chrismyers2000/MeshAdv-Pi-Hat +Meta: + name: MeshAdv-Pi E22-900M30S + support: community + compatible: + - forlinx-ok3506-s12 # Armbian + +Lora: + Module: sx1262 + CS: # GPIO0_B0 (physical 40) + pin: 8 + gpiochip: 0 + line: 8 + IRQ: # GPIO3_B0 (physical 36) + pin: 104 + gpiochip: 3 + line: 8 + Busy: # GPIO0_B1 (physical 38) + pin: 9 + gpiochip: 0 + line: 9 + Reset: # GPIO0_B6 (physical 12) + pin: 14 + gpiochip: 0 + line: 14 + TXen: # GPIO0_A3 (physical 33) + pin: 3 + gpiochip: 0 + line: 3 + RXen: # GPIO0_A2 (physical 32) + pin: 2 + gpiochip: 0 + line: 2 + DIO3_TCXO_VOLTAGE: true + # Only for E22-900M33S: + # Limit the output power to 8 dBm + # SX126X_MAX_POWER: 8 + spidev: spidev0.0 diff --git a/bin/config.d/lora-ok3506-MeshAdv-Mini-900M22S.yaml b/bin/config.d/lora-ok3506-MeshAdv-Mini-900M22S.yaml new file mode 100644 index 000000000..8f2c4a417 --- /dev/null +++ b/bin/config.d/lora-ok3506-MeshAdv-Mini-900M22S.yaml @@ -0,0 +1,35 @@ +# !! WARNING: Hats on the OK3506 board are installed "backwards" (facing outwards) + +# MeshAdv Mini E22-900M22S +# https://github.com/chrismyers2000/MeshAdv-Mini +Meta: + name: MeshAdv Mini E22-900M22S + support: community + compatible: + - forlinx-ok3506-s12 # Armbian + +Lora: + Module: sx1262 # Ebyte E22-900M22S + CS: # GPIO0_C3 (physical 24, SPI0_CSN0) + pin: 19 + gpiochip: 0 + line: 19 + IRQ: # GPIO3_B0 (physical 36) + pin: 104 + gpiochip: 3 + line: 8 + Busy: # GPIO0_B1 (physical 38) + pin: 9 + gpiochip: 0 + line: 9 + Reset: # GPIO3_A6 (physical 18) + pin: 102 + gpiochip: 3 + line: 6 + RXen: # GPIO0_A2 (physical 32) + pin: 2 + gpiochip: 0 + line: 2 + DIO2_AS_RF_SWITCH: true + DIO3_TCXO_VOLTAGE: true + spidev: spidev0.0 diff --git a/bin/config.d/lora-ok3506-RAK6421-13300-slot1.yaml b/bin/config.d/lora-ok3506-RAK6421-13300-slot1.yaml new file mode 100644 index 000000000..d97bdd327 --- /dev/null +++ b/bin/config.d/lora-ok3506-RAK6421-13300-slot1.yaml @@ -0,0 +1,40 @@ +# !! WARNING: Hats on the OK3506 board are installed "backwards" (facing outwards) + +Meta: + name: RAK6421 + RAK13300 Slot 1 + support: community # Promote when tested + compatible: + - forlinx-ok3506-s12 # Armbian + +Lora: + Module: sx1262 + IRQ: # GPIO3_B5 (IO6, physical 15) + pin: 109 + gpiochip: 3 + line: 13 + Reset: # GPIO3_B0 (IO4, physical 36) + pin: 104 + gpiochip: 3 + line: 8 + Busy: # GPIO3_A6 (IO5, physical 18) + pin: 102 + gpiochip: 3 + line: 6 + # Ant_sw: # GPIO0_A3 (IO3, physical 33) + # pin: 3 + # gpiochip: 0 + # line: 3 + Enable_Pins: + - pin: 2 # GPIO0_A2 (physical 32) + gpiochip: 0 + line: 2 + - pin: 3 # GPIO0_A3 (physical 33) + gpiochip: 0 + line: 3 + DIO3_TCXO_VOLTAGE: true + DIO2_AS_RF_SWITCH: true + spidev: spidev0.0 + # CS: # GPIO0_C3 (SPI0_CSN0, physical 24) + # pin: 19 + # gpiochip: 0 + # line: 19 diff --git a/bin/config.d/lora-ok3506-RAK6421-13300-slot2.yaml b/bin/config.d/lora-ok3506-RAK6421-13300-slot2.yaml new file mode 100644 index 000000000..969c20ad3 --- /dev/null +++ b/bin/config.d/lora-ok3506-RAK6421-13300-slot2.yaml @@ -0,0 +1,38 @@ +# !! WARNING: Hats on the OK3506 board are installed "backwards" (facing outwards) + +Meta: + name: RAK6421 + RAK13300 Slot 2 + support: community # Promote when tested + compatible: + - forlinx-ok3506-s12 # Armbian + +Lora: + Module: sx1262 + IRQ: # GPIO0_B6 (IO6, physical 12) + pin: 14 + gpiochip: 0 + line: 14 + Reset: # GPIO3_A6 (IO4, physical 18) + pin: 102 + gpiochip: 3 + line: 6 + Busy: # GPIO0_B2 (IO5, physical 35) + pin: 10 + gpiochip: 0 + line: 10 + # Ant_sw: # GPIO3_A7 (IO3, physical 16) + # pin: 103 + # gpiochip: 3 + # line: 7 + Enable_Pins: + - pin: 106 # GPIO3_B2 (physical 37) + gpiochip: 3 + line: 10 + - pin: 103 # GPIO3_A7 (physical 16) + gpiochip: 3 + line: 7 + spidev: spidev0.1 + # CS: # GPIO0_B7 (SPI0_CSN1, physical 26) + # pin: 15 + # gpiochip: 0 + # line: 15 diff --git a/bin/config.d/lora-ok3506-RAK6421-13302-slot1.yaml b/bin/config.d/lora-ok3506-RAK6421-13302-slot1.yaml new file mode 100644 index 000000000..d73eaf7a0 --- /dev/null +++ b/bin/config.d/lora-ok3506-RAK6421-13302-slot1.yaml @@ -0,0 +1,41 @@ +# !! WARNING: Hats on the OK3506 board are installed "backwards" (facing outwards) + +Meta: + name: RAK6421 + RAK13302 Slot 1 + support: community # Promote when tested + compatible: + - forlinx-ok3506-s12 # Armbian + +Lora: + Module: sx1262 + IRQ: # GPIO3_B5 (IO6, physical 15) + pin: 109 + gpiochip: 3 + line: 13 + Reset: # GPIO3_B0 (IO4, physical 36) + pin: 104 + gpiochip: 3 + line: 8 + Busy: # GPIO3_A6 (IO5, physical 18) + pin: 102 + gpiochip: 3 + line: 6 + # Ant_sw: # GPIO0_A3 (IO3, physical 33) + # pin: 3 + # gpiochip: 0 + # line: 3 + Enable_Pins: + - pin: 2 # GPIO0_A2 (physical 32) + gpiochip: 0 + line: 2 + - pin: 3 # GPIO0_A3 (physical 33) + gpiochip: 0 + line: 3 + DIO3_TCXO_VOLTAGE: true + DIO2_AS_RF_SWITCH: true + spidev: spidev0.0 + # CS: # GPIO0_C3 (SPI0_CSN0, physical 24) + # pin: 19 + # gpiochip: 0 + # line: 19 + TX_GAIN_LORA: [9, 9, 10, 11, 9, 8, 9, 10, 10, 10, 11, 12, 12, 12, 12, 12, 12, 12, 12, 10, 9, 8] diff --git a/bin/config.d/lora-ok3506-RAK6421-13302-slot2.yaml b/bin/config.d/lora-ok3506-RAK6421-13302-slot2.yaml new file mode 100644 index 000000000..36b70658b --- /dev/null +++ b/bin/config.d/lora-ok3506-RAK6421-13302-slot2.yaml @@ -0,0 +1,39 @@ +# !! WARNING: Hats on the OK3506 board are installed "backwards" (facing outwards) + +Meta: + name: RAK6421 + RAK13302 Slot 2 + support: community # Promote when tested + compatible: + - forlinx-ok3506-s12 # Armbian + +Lora: + Module: sx1262 + IRQ: # GPIO0_B6 (IO6, physical 12) + pin: 14 + gpiochip: 0 + line: 14 + Reset: # GPIO3_A6 (IO4, physical 18) + pin: 102 + gpiochip: 3 + line: 6 + Busy: # GPIO0_B2 (IO5, physical 35) + pin: 10 + gpiochip: 0 + line: 10 + # Ant_sw: # GPIO3_A7 (IO3, physical 16) + # pin: 103 + # gpiochip: 3 + # line: 7 + Enable_Pins: + - pin: 106 # GPIO3_B2 (physical 37) + gpiochip: 3 + line: 10 + - pin: 103 # GPIO3_A7 (physical 16) + gpiochip: 3 + line: 7 + spidev: spidev0.1 + # CS: # GPIO0_B7 (SPI0_CSN1, physical 26) + # pin: 15 + # gpiochip: 0 + # line: 15 + TX_GAIN_LORA: [9, 9, 10, 11, 9, 8, 9, 10, 10, 10, 11, 12, 12, 12, 12, 12, 12, 12, 12, 10, 9, 8] diff --git a/bin/config.d/lora-ok3506-waveshare-sxxx.yaml b/bin/config.d/lora-ok3506-waveshare-sxxx.yaml new file mode 100644 index 000000000..1f5795f92 --- /dev/null +++ b/bin/config.d/lora-ok3506-waveshare-sxxx.yaml @@ -0,0 +1,32 @@ +# !! WARNING: Hats on the OK3506 board are installed "backwards" (facing outwards) + +Meta: + name: Waveshare SX1262 + support: deprecated + compatible: + - forlinx-ok3506-s12 # Armbian + +Lora: + Module: sx1262 # Waveshare SX126X XXXM + DIO2_AS_RF_SWITCH: true + CS: # GPIO0_B0 (physical 40) + pin: 8 + gpiochip: 0 + line: 8 + IRQ: # GPIO3_B0 (physical 36) + pin: 104 + gpiochip: 3 + line: 8 + Busy: # GPIO0_B1 (physical 38) + pin: 9 + gpiochip: 0 + line: 9 + Reset: # GPIO0_B6 (physical 12) + pin: 14 + gpiochip: 0 + line: 14 + SX126X_ANT_SW: # GPIO3_B3 (physical 31) + pin: 107 + gpiochip: 3 + line: 11 + spidev: spidev0.0 diff --git a/bin/generate_ci_matrix.py b/bin/generate_ci_matrix.py index b4c18c05b..1458e4390 100755 --- a/bin/generate_ci_matrix.py +++ b/bin/generate_ci_matrix.py @@ -43,7 +43,7 @@ for pio_env in pio_envs: env = { "ci": {"board": pio_env, "platform": env_platform}, "board_level": cfg.get(f"env:{pio_env}", "board_level", default=None), - "board_check": bool(cfg.get(f"env:{pio_env}", "board_check", default=False)), + "board_check": cfg.get(f"env:{pio_env}", "board_check", default="false").strip().lower() == "true", } all_envs.append(env) diff --git a/bin/org.meshtastic.meshtasticd.metainfo.xml b/bin/org.meshtastic.meshtasticd.metainfo.xml index fe3a3a533..0642fdb07 100644 --- a/bin/org.meshtastic.meshtasticd.metainfo.xml +++ b/bin/org.meshtastic.meshtasticd.metainfo.xml @@ -87,6 +87,9 @@ + + https://github.com/meshtastic/firmware/releases?q=tag%3Av2.7.22 + https://github.com/meshtastic/firmware/releases?q=tag%3Av2.7.21 diff --git a/boards/ttgo-tbeam.json b/boards/ttgo-tbeam.json new file mode 100644 index 000000000..a4c43d525 --- /dev/null +++ b/boards/ttgo-tbeam.json @@ -0,0 +1,29 @@ +{ + "build": { + "arduino": { + "ldscript": "esp32_out.ld" + }, + "core": "esp32", + "extra_flags": "-DARDUINO_T_Beam", + "f_cpu": "240000000L", + "f_flash": "40000000L", + "flash_mode": "dio", + "mcu": "esp32", + "variant": "tbeam" + }, + "connectivity": ["wifi", "bluetooth", "can", "ethernet"], + "debug": { + "openocd_board": "esp-wroom-32.cfg" + }, + "frameworks": ["arduino", "espidf"], + "name": "TTGO T-Beam (PSRAM Disabled)", + "upload": { + "flash_size": "4MB", + "maximum_ram_size": 1310720, + "maximum_size": 4194304, + "require_upload_port": true, + "speed": 460800 + }, + "url": "https://github.com/LilyGO/TTGO-T-Beam", + "vendor": "TTGO" +} diff --git a/debian/changelog b/debian/changelog index 13d751ecf..b13a2ae9d 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,9 @@ +meshtasticd (2.7.22.0) unstable; urgency=medium + + * Version 2.7.22 + + -- GitHub Actions Mon, 06 Apr 2026 11:34:12 +0000 + meshtasticd (2.7.21.0) unstable; urgency=medium * Version 2.7.21 diff --git a/platformio.ini b/platformio.ini index 45d59942d..43cb1fcd1 100644 --- a/platformio.ini +++ b/platformio.ini @@ -126,112 +126,122 @@ lib_deps = [device-ui_base] lib_deps = # renovate: datasource=git-refs depName=meshtastic/device-ui packageName=https://github.com/meshtastic/device-ui gitBranch=master - https://github.com/meshtastic/device-ui/archive/7b1485b86c8d55a40e5226749097767e8b87f396.zip + https://github.com/meshtastic/device-ui/archive/1897dd17fceb1f101bb1a3245680aa3439edcfdd.zip ; Common libs for environmental measurements in telemetry module [environmental_base] lib_deps = - # renovate: datasource=custom.pio depName=Adafruit BusIO packageName=adafruit/library/Adafruit BusIO - adafruit/Adafruit BusIO@1.17.4 - # renovate: datasource=custom.pio depName=Adafruit Unified Sensor packageName=adafruit/library/Adafruit Unified Sensor - adafruit/Adafruit Unified Sensor@1.1.15 - # renovate: datasource=custom.pio depName=Adafruit BMP280 packageName=adafruit/library/Adafruit BMP280 Library - adafruit/Adafruit BMP280 Library@3.0.0 - # renovate: datasource=custom.pio depName=Adafruit BMP085 packageName=adafruit/library/Adafruit BMP085 Library - adafruit/Adafruit BMP085 Library@1.2.4 - # renovate: datasource=custom.pio depName=Adafruit BME280 packageName=adafruit/library/Adafruit BME280 Library - adafruit/Adafruit BME280 Library@2.3.0 - # renovate: datasource=custom.pio depName=Adafruit DPS310 packageName=adafruit/library/Adafruit DPS310 - adafruit/Adafruit DPS310@1.1.6 - # renovate: datasource=custom.pio depName=Adafruit MCP9808 packageName=adafruit/library/Adafruit MCP9808 Library - adafruit/Adafruit MCP9808 Library@2.0.2 - # renovate: datasource=custom.pio depName=Adafruit INA260 packageName=adafruit/library/Adafruit INA260 Library - adafruit/Adafruit INA260 Library@1.5.3 - # renovate: datasource=custom.pio depName=Adafruit INA219 packageName=adafruit/library/Adafruit INA219 - adafruit/Adafruit INA219@1.2.3 - # renovate: datasource=custom.pio depName=Adafruit MPU6050 packageName=adafruit/library/Adafruit MPU6050 - adafruit/Adafruit MPU6050@2.2.9 - # renovate: datasource=custom.pio depName=Adafruit LIS3DH packageName=adafruit/library/Adafruit LIS3DH - adafruit/Adafruit LIS3DH@1.3.0 - # renovate: datasource=custom.pio depName=Adafruit AHTX0 packageName=adafruit/library/Adafruit AHTX0 - adafruit/Adafruit AHTX0@2.0.6 - # renovate: datasource=custom.pio depName=Adafruit LSM6DS packageName=adafruit/library/Adafruit LSM6DS - adafruit/Adafruit LSM6DS@4.7.4 - # renovate: datasource=custom.pio depName=Adafruit TSL2591 packageName=adafruit/library/Adafruit TSL2591 Library - adafruit/Adafruit TSL2591 Library@1.4.5 - # renovate: datasource=custom.pio depName=EmotiBit MLX90632 packageName=emotibit/library/EmotiBit MLX90632 - emotibit/EmotiBit MLX90632@1.0.8 - # renovate: datasource=custom.pio depName=Adafruit MLX90614 packageName=adafruit/library/Adafruit MLX90614 Library - adafruit/Adafruit MLX90614 Library@2.1.6 + # renovate: datasource=github-tags depName=Adafruit BusIO packageName=adafruit/Adafruit_BusIO + https://github.com/adafruit/Adafruit_BusIO/archive/refs/tags/1.17.4.zip + # renovate: datasource=github-tags depName=Adafruit Unified Sensor packageName=adafruit/Adafruit_Sensor + https://github.com/adafruit/Adafruit_Sensor/archive/refs/tags/1.1.15.zip + # renovate: datasource=github-tags depName=Adafruit GFX packageName=adafruit/Adafruit-GFX-Library + https://github.com/adafruit/Adafruit-GFX-Library/archive/refs/tags/1.12.6.zip + # renovate: datasource=github-tags depName=NeoPixel packageName=adafruit/Adafruit_NeoPixel + https://github.com/adafruit/Adafruit_NeoPixel/archive/refs/tags/1.15.4.zip + # renovate: datasource=github-tags depName=Adafruit SSD1306 packageName=adafruit/Adafruit_SSD1306 + https://github.com/adafruit/Adafruit_SSD1306/archive/refs/tags/2.5.16.zip + # renovate: datasource=github-tags depName=Adafruit BMP280 packageName=adafruit/Adafruit_BMP280_Library + https://github.com/adafruit/Adafruit_BMP280_Library/archive/refs/tags/3.0.0.zip + # renovate: datasource=github-tags depName=Adafruit BMP085 packageName=adafruit/Adafruit-BMP085-Library + https://github.com/adafruit/Adafruit-BMP085-Library/archive/refs/tags/1.2.4.zip + # renovate: datasource=github-tags depName=Adafruit BME280 packageName=adafruit/Adafruit_BME280_Library + https://github.com/adafruit/Adafruit_BME280_Library/archive/refs/tags/2.3.0.zip + # renovate: datasource=github-tags depName=Adafruit DPS310 packageName=adafruit/Adafruit_DPS310 + https://github.com/adafruit/Adafruit_DPS310/archive/refs/tags/1.1.6.zip + # renovate: datasource=github-tags depName=Adafruit SH110x packageName=adafruit/Adafruit_SH110x + https://github.com/adafruit/Adafruit_SH110x/archive/refs/tags/2.1.14.zip + # renovate: datasource=github-tags depName=Adafruit MCP9808 packageName=adafruit/Adafruit_MCP9808_Library + https://github.com/adafruit/Adafruit_MCP9808_Library/archive/refs/tags/2.0.2.zip + # renovate: datasource=github-tags depName=Adafruit INA260 packageName=adafruit/Adafruit_INA260 + https://github.com/adafruit/Adafruit_INA260/archive/refs/tags/1.5.3.zip + # renovate: datasource=github-tags depName=Adafruit INA219 packageName=adafruit/Adafruit_INA219 + https://github.com/adafruit/Adafruit_INA219/archive/refs/tags/1.2.3.zip + # renovate: datasource=github-tags depName=Adafruit MPU6050 packageName=adafruit/Adafruit_MPU6050 + https://github.com/adafruit/Adafruit_MPU6050/archive/refs/tags/2.2.9.zip + # renovate: datasource=github-tags depName=Adafruit LIS3DH packageName=adafruit/Adafruit_LIS3DH + https://github.com/adafruit/Adafruit_LIS3DH/archive/refs/tags/1.3.0.zip + # renovate: datasource=github-tags depName=Adafruit AHTX0 packageName=adafruit/Adafruit_AHTX0 + https://github.com/adafruit/Adafruit_AHTX0/archive/refs/tags/2.0.6.zip + # renovate: datasource=github-tags depName=Adafruit LSM6DS packageName=adafruit/Adafruit_LSM6DS + https://github.com/adafruit/Adafruit_LSM6DS/archive/refs/tags/4.7.4.zip + # renovate: datasource=github-tags depName=Adafruit TSL2591 packageName=adafruit/Adafruit_TSL2591_Library + https://github.com/adafruit/Adafruit_TSL2591_Library/archive/refs/tags/1.4.5.zip + # renovate: datasource=github-tags depName=EmotiBit MLX90632 packageName=emotibit/EmotiBit_MLX90632 + https://github.com/EmotiBit/EmotiBit_MLX90632/archive/refs/tags/v1.0.8.zip + # renovate: datasource=github-tags depName=Adafruit MLX90614 packageName=adafruit/Adafruit_MLX90614 + https://github.com/adafruit/Adafruit-MLX90614-Library/archive/refs/tags/2.1.6.zip # renovate: datasource=git-refs depName=INA3221 packageName=https://github.com/sgtwilko/INA3221 gitBranch=FixOverflow https://github.com/sgtwilko/INA3221/archive/bb03d7e9bfcc74fc798838a54f4f99738f29fc6a.zip - # renovate: datasource=custom.pio depName=QMC5883L Compass packageName=mprograms/library/QMC5883LCompass - mprograms/QMC5883LCompass@1.2.3 - # renovate: datasource=custom.pio depName=DFRobot_RTU packageName=dfrobot/library/DFRobot_RTU - dfrobot/DFRobot_RTU@1.0.6 + # renovate: datasource=github-tags depName=QMC5883L Compass packageName=mprograms/QMC5883LCompass + https://github.com/mprograms/QMC5883LCompass/archive/refs/tags/v1.2.3.zip + # renovate: datasource=github-tags depName=DFRobot_RTU packageName=dfrobot/DFRobot_RTU + https://github.com/DFRobot/DFRobot_RTU/archive/refs/tags/V1.0.6.zip # renovate: datasource=git-refs depName=DFRobot_RainfallSensor packageName=https://github.com/DFRobot/DFRobot_RainfallSensor gitBranch=master https://github.com/DFRobot/DFRobot_RainfallSensor/archive/38fea5e02b40a5430be6dab39a99a6f6347d667e.zip - # renovate: datasource=custom.pio depName=INA226 packageName=robtillaart/library/INA226 - robtillaart/INA226@0.6.6 - # renovate: datasource=custom.pio depName=SparkFun MAX3010x packageName=sparkfun/library/SparkFun MAX3010x Pulse and Proximity Sensor Library - sparkfun/SparkFun MAX3010x Pulse and Proximity Sensor Library@1.1.2 - # renovate: datasource=custom.pio depName=SparkFun 9DoF IMU Breakout ICM 20948 packageName=sparkfun/library/SparkFun 9DoF IMU Breakout - ICM 20948 - Arduino Library - sparkfun/SparkFun 9DoF IMU Breakout - ICM 20948 - Arduino Library@1.3.2 - # renovate: datasource=custom.pio depName=Adafruit LTR390 Library packageName=adafruit/library/Adafruit LTR390 Library - adafruit/Adafruit LTR390 Library@1.1.2 - # renovate: datasource=custom.pio depName=Adafruit PCT2075 packageName=adafruit/library/Adafruit PCT2075 - adafruit/Adafruit PCT2075@1.0.6 - # renovate: datasource=custom.pio depName=DFRobot_BMM150 packageName=dfrobot/library/DFRobot_BMM150 - dfrobot/DFRobot_BMM150@1.0.0 - # renovate: datasource=custom.pio depName=Adafruit_TSL2561 packageName=adafruit/library/Adafruit TSL2561 - adafruit/Adafruit TSL2561@1.1.3 - # renovate: datasource=custom.pio depName=BH1750_WE packageName=wollewald/library/BH1750_WE - wollewald/BH1750_WE@1.1.10 + # renovate: datasource=github-tags depName=INA226 packageName=robtillaart/INA226 + https://github.com/RobTillaart/INA226/archive/refs/tags/0.6.6.zip + # renovate: datasource=github-tags depName=SparkFun MAX3010x packageName=sparkfun/SparkFun_MAX3010x_Sensor_Library + https://github.com/sparkfun/SparkFun_MAX3010x_Sensor_Library/archive/refs/tags/v1.1.2.zip + # renovate: datasource=github-tags depName=SparkFun 9DoF IMU Breakout ICM 20948 packageName=sparkfun/SparkFun_ICM-20948_ArduinoLibrary + https://github.com/sparkfun/SparkFun_ICM-20948_ArduinoLibrary/archive/refs/tags/v1.3.2.zip + # renovate: datasource=github-tags depName=Adafruit LTR390 Library packageName=adafruit/Adafruit_LTR390 + https://github.com/adafruit/Adafruit_LTR390/archive/refs/tags/1.1.2.zip + # renovate: datasource=github-tags depName=Adafruit PCT2075 packageName=adafruit/Adafruit_PCT2075 + https://github.com/adafruit/Adafruit_PCT2075/archive/refs/tags/1.0.6.zip + # renovate: datasource=github-tags depName=DFRobot_BMM150 packageName=dfrobot/DFRobot_BMM150 + https://github.com/DFRobot/DFRobot_BMM150/archive/refs/tags/V1.0.0.zip + # renovate: datasource=github-tags depName=Adafruit_TSL2561 packageName=adafruit/Adafruit_TSL2561 + https://github.com/adafruit/Adafruit_TSL2561/archive/refs/tags/1.1.3.zip + # renovate: datasource=github-tags depName=BH1750_WE packageName=wollewald/BH1750_WE + https://github.com/wollewald/BH1750_WE/archive/refs/tags/1.1.10.zip ; Common environmental sensor libraries (not included in native / portduino) [environmental_extra_common] lib_deps = - # renovate: datasource=custom.pio depName=Adafruit BMP3XX packageName=adafruit/library/Adafruit BMP3XX Library - adafruit/Adafruit BMP3XX Library@2.1.6 - # renovate: datasource=custom.pio depName=Adafruit MAX1704X packageName=adafruit/library/Adafruit MAX1704X - adafruit/Adafruit MAX1704X@1.0.3 - # renovate: datasource=custom.pio depName=Adafruit SHTC3 packageName=adafruit/library/Adafruit SHTC3 Library - adafruit/Adafruit SHTC3 Library@1.0.2 - # renovate: datasource=custom.pio depName=Adafruit LPS2X packageName=adafruit/library/Adafruit LPS2X - adafruit/Adafruit LPS2X@2.0.6 - # renovate: datasource=custom.pio depName=Adafruit SHT31 packageName=adafruit/library/Adafruit SHT31 Library - adafruit/Adafruit SHT31 Library@2.2.2 - # renovate: datasource=custom.pio depName=Adafruit VEML7700 packageName=adafruit/library/Adafruit VEML7700 Library - adafruit/Adafruit VEML7700 Library@2.1.6 - # renovate: datasource=custom.pio depName=Adafruit SHT4x packageName=adafruit/library/Adafruit SHT4x Library - adafruit/Adafruit SHT4x Library@1.0.5 - # renovate: datasource=custom.pio depName=SparkFun Qwiic Scale NAU7802 packageName=sparkfun/library/SparkFun Qwiic Scale NAU7802 Arduino Library - sparkfun/SparkFun Qwiic Scale NAU7802 Arduino Library@1.0.6 + # renovate: datasource=github-tags depName=Adafruit BMP3XX packageName=adafruit/Adafruit_BMP3XX + https://github.com/adafruit/Adafruit_BMP3XX/archive/refs/tags/2.1.6.zip + # renovate: datasource=github-tags depName=Adafruit MAX1704X packageName=adafruit/Adafruit_MAX1704X + https://github.com/adafruit/Adafruit_MAX1704X/archive/refs/tags/1.0.3.zip + # renovate: datasource=github-tags depName=Adafruit SHTC3 packageName=adafruit/Adafruit_SHTC3 + https://github.com/adafruit/Adafruit_SHTC3/archive/refs/tags/1.0.2.zip + # renovate: datasource=github-tags depName=Adafruit LPS2X packageName=adafruit/Adafruit_LPS2X + https://github.com/adafruit/Adafruit_LPS2X/archive/refs/tags/2.0.6.zip + # renovate: datasource=github-tags depName=Adafruit SHT31 packageName=adafruit/Adafruit_SHT31 + https://github.com/adafruit/Adafruit_SHT31/archive/refs/tags/2.2.2.zip + # renovate: datasource=github-tags depName=Adafruit VEML7700 packageName=adafruit/Adafruit_VEML7700 + https://github.com/adafruit/Adafruit_VEML7700/archive/refs/tags/2.1.6.zip + # renovate: datasource=github-tags depName=Adafruit SHT4x packageName=adafruit/Adafruit_SHT4X + https://github.com/adafruit/Adafruit_SHT4X/archive/refs/tags/1.0.5.zip + # renovate: datasource=github-tags depName=SparkFun Qwiic Scale NAU7802 packageName=sparkfun/SparkFun_Qwiic_Scale_NAU7802_Arduino_Library + https://github.com/sparkfun/SparkFun_Qwiic_Scale_NAU7802_Arduino_Library/archive/refs/tags/v1.0.6.zip # renovate: datasource=custom.pio depName=ClosedCube OPT3001 packageName=closedcube/library/ClosedCube OPT3001 closedcube/ClosedCube OPT3001@1.1.2 # renovate: datasource=git-refs depName=meshtastic-DFRobot_LarkWeatherStation packageName=https://github.com/meshtastic/DFRobot_LarkWeatherStation gitBranch=master https://github.com/meshtastic/DFRobot_LarkWeatherStation/archive/4de3a9cadef0f6a5220a8a906cf9775b02b0040d.zip - # renovate: datasource=custom.pio depName=Sensirion Core packageName=sensirion/library/Sensirion Core - sensirion/Sensirion Core@0.7.3 - # renovate: datasource=custom.pio depName=Sensirion I2C SCD4x packageName=sensirion/library/Sensirion I2C SCD4x - sensirion/Sensirion I2C SCD4x@1.1.0 - # renovate: datasource=custom.pio depName=Sensirion I2C SFA3x packageName=sensirion/library/Sensirion I2C SFA3x - sensirion/Sensirion I2C SFA3x@1.0.0 - # renovate: datasource=custom.pio depName=Sensirion I2C SCD30 packageName=sensirion/library/Sensirion I2C SCD30 - sensirion/Sensirion I2C SCD30@1.0.0 + # renovate: datasource=github-tags depName=Sensirion Core packageName=sensirion/arduino-core + https://github.com/Sensirion/arduino-core/archive/refs/tags/0.7.3.zip + # renovate: datasource=github-tags depName=Sensirion I2C SCD4x packageName=sensirion/arduino-i2c-scd4x + https://github.com/Sensirion/arduino-i2c-scd4x/archive/refs/tags/1.1.0.zip + # renovate: datasource=github-tags depName=Sensirion I2C SFA3x packageName=sensirion/arduino-i2c-sfa3x + https://github.com/Sensirion/arduino-i2c-sfa3x/archive/refs/tags/1.0.0.zip + # renovate: datasource=github-tags depName=Sensirion I2C SCD30 packageName=sensirion/arduino-i2c-scd30 + https://github.com/Sensirion/arduino-i2c-scd30/archive/refs/tags/1.0.0.zip + # renovate: datasource=github-tags depName=arduino-sht packageName=sensirion/arduino-sht + https://github.com/Sensirion/arduino-sht/archive/refs/tags/v1.2.6.zip ; Environmental sensors with BSEC2 (Bosch proprietary IAQ) [environmental_extra] lib_deps = ${environmental_extra_common.lib_deps} - # renovate: datasource=custom.pio depName=Bosch BSEC2 packageName=boschsensortec/library/bsec2 - boschsensortec/bsec2@1.10.2610 - # renovate: datasource=custom.pio depName=Bosch BME68x packageName=boschsensortec/library/BME68x Sensor Library - boschsensortec/BME68x Sensor Library@1.3.40408 + # renovate: datasource=github-tags depName=Bosch BSEC2 packageName=boschsensortec/Bosch-BSEC2-Library + https://github.com/boschsensortec/Bosch-BSEC2-Library/archive/refs/tags/1.10.2610.zip + # renovate: datasource=github-tags depName=Bosch BME68x packageName=boschsensortec/Bosch-BME68x-Library + https://github.com/boschsensortec/Bosch-BME68x-Library/archive/refs/tags/v1.3.40408.zip ; Environmental sensors without BSEC (saves ~3.5KB DRAM for original ESP32 targets) [environmental_extra_no_bsec] lib_deps = ${environmental_extra_common.lib_deps} - # renovate: datasource=custom.pio depName=Adafruit_BME680 packageName=adafruit/library/Adafruit BME680 Library - adafruit/Adafruit BME680 Library@2.0.6 + # renovate: datasource=github-tags depName=Adafruit_BME680 packageName=adafruit/Adafruit_BME680 + https://github.com/adafruit/Adafruit_BME680/archive/refs/tags/2.0.6.zip diff --git a/protobufs b/protobufs index cb1f89372..e30092e61 160000 --- a/protobufs +++ b/protobufs @@ -1 +1 @@ -Subproject commit cb1f89372a70b0d4b4f8caf05aec28de8d4a13e0 +Subproject commit e30092e6168b13341c2b7ec4be19c789ad5cd77f diff --git a/renovate.json b/renovate.json index d761f61c1..60c51b59e 100644 --- a/renovate.json +++ b/renovate.json @@ -4,6 +4,7 @@ ":dependencyDashboard", ":semanticCommitTypeAll(chore)", ":ignoreModulesAndTests", + ":noUnscheduledUpdates", "schedule:daily", "group:recommended", "replacements:all", diff --git a/src/RedirectablePrint.cpp b/src/RedirectablePrint.cpp index f205ef378..641138d84 100644 --- a/src/RedirectablePrint.cpp +++ b/src/RedirectablePrint.cpp @@ -137,7 +137,7 @@ void RedirectablePrint::log_to_serial(const char *logLevel, const char *format, if (color) { ::printf("\u001b[0m"); } - ::printf("| %02d:%02d:%02d %u ", hour, min, sec, millis() / 1000); + ::printf("| %02d:%02d:%02d %u.%03u ", hour, min, sec, millis() / 1000, millis() % 1000); #else printf("%s ", logLevel); if (color) { @@ -151,7 +151,7 @@ void RedirectablePrint::log_to_serial(const char *logLevel, const char *format, if (color) { ::printf("\u001b[0m"); } - ::printf("| ??:??:?? %u ", millis() / 1000); + ::printf("| ??:??:?? %u.%03u ", millis() / 1000, millis() % 1000); #else printf("%s ", logLevel); if (color) { diff --git a/src/concurrency/BinarySemaphorePosix.cpp b/src/concurrency/BinarySemaphorePosix.cpp index dc49a489b..4bc60c31f 100644 --- a/src/concurrency/BinarySemaphorePosix.cpp +++ b/src/concurrency/BinarySemaphorePosix.cpp @@ -1,10 +1,85 @@ #include "concurrency/BinarySemaphorePosix.h" #include "configuration.h" +#include +#include + #ifndef HAS_FREE_RTOS namespace concurrency { +#ifdef ARCH_PORTDUINO + +BinarySemaphorePosix::BinarySemaphorePosix() +{ + if (pthread_mutex_init(&mutex, NULL) != 0) { + throw std::runtime_error("pthread_mutex_init failed"); + } + if (pthread_cond_init(&cond, NULL) != 0) { + pthread_mutex_destroy(&mutex); + throw std::runtime_error("pthread_cond_init failed"); + } + signaled = false; +} + +BinarySemaphorePosix::~BinarySemaphorePosix() +{ + pthread_cond_destroy(&cond); + pthread_mutex_destroy(&mutex); +} + +/** + * Returns false if we timed out + */ +bool BinarySemaphorePosix::take(uint32_t msec) +{ + pthread_mutex_lock(&mutex); + + if (!signaled) { + struct timespec ts; + clock_gettime(CLOCK_REALTIME, &ts); + + ts.tv_sec += msec / 1000; + ts.tv_nsec += (msec % 1000) * 1000000L; + if (ts.tv_nsec >= 1000000000L) { + ts.tv_sec += 1; + ts.tv_nsec -= 1000000000L; + } + + while (!signaled) { + int rc = pthread_cond_timedwait(&cond, &mutex, &ts); + if (rc == ETIMEDOUT) + break; + if (rc != 0) { + // Some other error occurred + pthread_mutex_unlock(&mutex); + throw std::runtime_error("pthread_cond_timedwait failed: " + std::to_string(rc)); + } + } + } + + bool wasSignaled = signaled; + signaled = false; // consume the signal (binary semaphore) + + pthread_mutex_unlock(&mutex); + return wasSignaled; +} + +void BinarySemaphorePosix::give() +{ + pthread_mutex_lock(&mutex); + signaled = true; + pthread_cond_signal(&cond); + pthread_mutex_unlock(&mutex); +} + +IRAM_ATTR void BinarySemaphorePosix::giveFromISR(BaseType_t *pxHigherPriorityTaskWoken) +{ + give(); + if (pxHigherPriorityTaskWoken) + *pxHigherPriorityTaskWoken = true; +} +#else BinarySemaphorePosix::BinarySemaphorePosix() {} @@ -22,7 +97,8 @@ bool BinarySemaphorePosix::take(uint32_t msec) void BinarySemaphorePosix::give() {} IRAM_ATTR void BinarySemaphorePosix::giveFromISR(BaseType_t *pxHigherPriorityTaskWoken) {} +#endif } // namespace concurrency -#endif \ No newline at end of file +#endif diff --git a/src/concurrency/BinarySemaphorePosix.h b/src/concurrency/BinarySemaphorePosix.h index 475b29874..80edb567b 100644 --- a/src/concurrency/BinarySemaphorePosix.h +++ b/src/concurrency/BinarySemaphorePosix.h @@ -2,6 +2,10 @@ #include "../freertosinc.h" +#ifdef ARCH_PORTDUINO +#include +#endif + namespace concurrency { @@ -9,7 +13,12 @@ namespace concurrency class BinarySemaphorePosix { - // SemaphoreHandle_t semaphore; + +#ifdef ARCH_PORTDUINO + pthread_mutex_t mutex; + pthread_cond_t cond; + bool signaled; +#endif public: BinarySemaphorePosix(); @@ -27,4 +36,4 @@ class BinarySemaphorePosix #endif -} // namespace concurrency \ No newline at end of file +} // namespace concurrency diff --git a/src/configuration.h b/src/configuration.h index 11be86007..84dabee4e 100644 --- a/src/configuration.h +++ b/src/configuration.h @@ -231,7 +231,7 @@ along with this program. If not, see . #define BME_ADDR 0x76 #define BME_ADDR_ALTERNATE 0x77 #define MCP9808_ADDR 0x18 -#define INA_ADDR 0x40 +#define INA_ADDR 0x40 // same as SHT2X #define INA_ADDR_ALTERNATE 0x41 #define INA_ADDR_WAVESHARE_UPS 0x43 #define INA3221_ADDR 0x42 @@ -244,8 +244,8 @@ along with this program. If not, see . #define LPS22HB_ADDR 0x5C #define LPS22HB_ADDR_ALT 0x5D #define SFA30_ADDR 0x5D -#define SHT31_4x_ADDR 0x44 -#define SHT31_4x_ADDR_ALT 0x45 +#define SHTXX_ADDR 0x44 +#define SHTXX_ADDR_ALT 0x45 #define PMSA003I_ADDR 0x12 #define QMA6100P_ADDR 0x12 #define AHT10_ADDR 0x38 diff --git a/src/detect/ScanI2C.h b/src/detect/ScanI2C.h index cc83a8d7b..d451d3948 100644 --- a/src/detect/ScanI2C.h +++ b/src/detect/ScanI2C.h @@ -31,9 +31,6 @@ class ScanI2C INA3221, MAX17048, MCP9808, - SHT31, - SHT4X, - SHTC3, LPS22HB, QMC6310U, QMC6310N, @@ -94,7 +91,8 @@ class ScanI2C SFA30, CW2015, SCD30, - ADS1115 + ADS1115, + SHTXX } DeviceType; // typedef uint8_t DeviceAddress; diff --git a/src/detect/ScanI2CTwoWire.cpp b/src/detect/ScanI2CTwoWire.cpp index 2e00c11ce..052b2245a 100644 --- a/src/detect/ScanI2CTwoWire.cpp +++ b/src/detect/ScanI2CTwoWire.cpp @@ -136,7 +136,9 @@ bool ScanI2CTwoWire::i2cCommandResponseLength(ScanI2C::DeviceAddress addr, uint1 return match; } -/// for SEN5X detection +#if HAS_TELEMETRY && !MESHTASTIC_EXCLUDE_AIR_QUALITY_SENSOR +// FIXME Move to a separate file for detection of sensors that require more complex interactions? +// For SEN5X detection // Note, this code needs to be called before setting the I2C bus speed // for the screen at high speed. The speed needs to be at 100kHz, otherwise // detection will not work @@ -174,6 +176,46 @@ String readSEN5xProductName(TwoWire *i2cBus, uint8_t address) return String(productName); } +#endif + +#if HAS_TELEMETRY && !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR +bool detectSHT21SerialNumber(TwoWire *i2cBus, uint8_t address) +{ + + i2cBus->beginTransmission(address); + i2cBus->write(0xFA); + i2cBus->write(0x0F); + + if (i2cBus->endTransmission() != 0) + return false; + + if (i2cBus->requestFrom(address, (uint8_t)8) != 8) + return false; + + // Just flush the data + while (i2cBus->available() < 8) { + i2cBus->read(); + } + + i2cBus->beginTransmission(address); + i2cBus->write(0xFC); + i2cBus->write(0xC9); + + if (i2cBus->endTransmission() != 0) + return false; + + if (i2cBus->requestFrom(address, (uint8_t)6) != 6) + return false; + + // Just flush the data + while (i2cBus->available() < 6) { + i2cBus->read(); + } + + // Assume we detect the SHT21 if something came back from the request + return true; +} +#endif #define SCAN_SIMPLE_CASE(ADDR, T, ...) \ case ADDR: \ @@ -371,7 +413,7 @@ void ScanI2CTwoWire::scanPort(I2CPort port, uint8_t *address, uint8_t asize) break; #endif #if !defined(M5STACK_UNITC6L) - case INA_ADDR: + case INA_ADDR: // Same as SHT2X case INA_ADDR_ALTERNATE: case INA_ADDR_WAVESHARE_UPS: registerValue = getRegisterValue(ScanI2CTwoWire::RegisterLocation(addr, 0xFE), 2); @@ -387,7 +429,12 @@ void ScanI2CTwoWire::scanPort(I2CPort port, uint8_t *address, uint8_t asize) logFoundDevice("INA260", (uint8_t)addr.address); type = INA260; } - } else { // Assume INA219 if INA260 ID is not found +#if HAS_TELEMETRY && !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR + } else if (detectSHT21SerialNumber(i2cBus, (uint8_t)addr.address)) { + logFoundDevice("SHTXX (SHT2X)", (uint8_t)addr.address); + type = SHTXX; +#endif + } else { // Assume INA219 if none of the above ones are found logFoundDevice("INA219", (uint8_t)addr.address); type = INA219; } @@ -448,22 +495,19 @@ void ScanI2CTwoWire::scanPort(I2CPort port, uint8_t *address, uint8_t asize) } break; } - case SHT31_4x_ADDR: // same as OPT3001_ADDR_ALT - case SHT31_4x_ADDR_ALT: // same as OPT3001_ADDR + case SHTXX_ADDR: // same as OPT3001_ADDR_ALT + case SHTXX_ADDR_ALT: // same as OPT3001_ADDR if (getRegisterValue(ScanI2CTwoWire::RegisterLocation(addr, 0x7E), 2) == 0x5449) { type = OPT3001; logFoundDevice("OPT3001", (uint8_t)addr.address); - } else if (i2cCommandResponseLength(addr, 0x89, 6)) { // SHT4x serial number (6 bytes inc. CRC) - type = SHT4X; - logFoundDevice("SHT4X", (uint8_t)addr.address); - } else { - type = SHT31; - logFoundDevice("SHT31", (uint8_t)addr.address); + } else { // SHTXX + type = SHTXX; + logFoundDevice("SHTXX", (uint8_t)addr.address); } break; - SCAN_SIMPLE_CASE(SHTC3_ADDR, SHTC3, "SHTC3", (uint8_t)addr.address) + SCAN_SIMPLE_CASE(SHTC3_ADDR, SHTXX, "SHTXX", (uint8_t)addr.address) case RCWL9620_ADDR: // get MAX30102 PARTID registerValue = getRegisterValue(ScanI2CTwoWire::RegisterLocation(addr, 0xFF), 1); @@ -675,6 +719,7 @@ void ScanI2CTwoWire::scanPort(I2CPort port, uint8_t *address, uint8_t asize) logFoundDevice("BMX160", (uint8_t)addr.address); break; } else { +#if HAS_TELEMETRY && !MESHTASTIC_EXCLUDE_AIR_QUALITY_SENSOR String prod = ""; prod = readSEN5xProductName(i2cBus, addr.address); if (prod.startsWith("SEN55")) { @@ -690,6 +735,7 @@ void ScanI2CTwoWire::scanPort(I2CPort port, uint8_t *address, uint8_t asize) logFoundDevice("Sensirion SEN50", addr.address); break; } +#endif if (addr.address == BMX160_ADDR) { type = BMX160; logFoundDevice("BMX160", (uint8_t)addr.address); diff --git a/src/graphics/EInkParallelDisplay.cpp b/src/graphics/EInkParallelDisplay.cpp index b870e111b..293f57e81 100644 --- a/src/graphics/EInkParallelDisplay.cpp +++ b/src/graphics/EInkParallelDisplay.cpp @@ -202,7 +202,7 @@ void EInkParallelDisplay::display(void) // Get pointers to internal buffers uint8_t *cur = epaper->currentBuffer(); - uint8_t *prev = epaper->previousBuffer(); // may be NULL on first init + const uint8_t *prev = epaper->previousBuffer(); // may be NULL on first init // Track changed row range while converting int newTop = h; // min changed row (initialized to out-of-range) diff --git a/src/graphics/TFTDisplay.cpp b/src/graphics/TFTDisplay.cpp index 005ead292..4c8272955 100644 --- a/src/graphics/TFTDisplay.cpp +++ b/src/graphics/TFTDisplay.cpp @@ -1254,14 +1254,14 @@ void TFTDisplay::display(bool fromBlank) // Did we find a pixel that needs updating on this row? if (x_FirstPixelUpdate < displayWidth) { + // Align the first pixel for update to an even number so the total alignment of + // the data will be at 32-bit boundary, which is required by GDMA SPI transfers. + x_FirstPixelUpdate &= ~1; - // Quickly write out the first changed pixel (saves another array lookup) - linePixelBuffer[x_FirstPixelUpdate] = isset ? colorTftMesh : colorTftBlack; - x_LastPixelUpdate = x_FirstPixelUpdate; - - // Step 3: copy all remaining pixels in this row into the pixel line buffer, - // while also recording the last pixel in the row that needs updating - for (x = x_FirstPixelUpdate + 1; x < displayWidth; x++) { + // Step 3a: copy rest of the pixels in this row into the pixel line buffer, + // while also recording the last pixel in the row that needs updating. + // Since the first changed pixel will be looked up, the x_LastPixelUpdate will be set. + for (x = x_FirstPixelUpdate; x < displayWidth; x++) { isset = buffer[x + y_byteIndex] & y_byteMask; linePixelBuffer[x] = isset ? colorTftMesh : colorTftBlack; @@ -1274,6 +1274,14 @@ void TFTDisplay::display(bool fromBlank) x_LastPixelUpdate = x; } } + // Step 3b: Round up the last pixel to odd number to maintain 32-bit alignment for SPIs. + // Most displays will have even number of pixels in a row -- this will be in bounds + // of the displayWidth. (Hopefully odd displays will just ignore that extra pixel.) + x_LastPixelUpdate |= 1; + // Ensure the last pixel index does not exceed the display width. + if (x_LastPixelUpdate >= displayWidth) { + x_LastPixelUpdate = displayWidth - 1; + } #if defined(HACKADAY_COMMUNICATOR) tft->draw16bitBeRGBBitmap(x_FirstPixelUpdate, y, &linePixelBuffer[x_FirstPixelUpdate], (x_LastPixelUpdate - x_FirstPixelUpdate + 1), 1); diff --git a/src/graphics/draw/MenuHandler.cpp b/src/graphics/draw/MenuHandler.cpp index 157d4c314..e92ba4839 100644 --- a/src/graphics/draw/MenuHandler.cpp +++ b/src/graphics/draw/MenuHandler.cpp @@ -163,9 +163,11 @@ void menuHandler::LoraRegionPicker(uint32_t duration) // Guard: without a reboot, reconfigure() applies the region directly. // Reject LORA_24 on sub-GHz-only hardware — getRadio() used to catch this post-reboot. + // TODO: change this to either use the validateLoraConfig() logic or at least check the region for wideLora + // rather than a hardcoded check for LORA_24. if (selectedRegion == meshtastic_Config_LoRaConfig_RegionCode_LORA_24 && !(RadioLibInterface::instance && RadioLibInterface::instance->wideLora())) { - LOG_WARN("Radio hardware does not support 2.4 GHz; ignoring LORA_24 selection"); + LOG_WARN("Radio hardware does not support 2.4 GHz; ignoring region selection"); return; } diff --git a/src/input/InputBroker.cpp b/src/input/InputBroker.cpp index e3125ca12..b7c9b27a9 100644 --- a/src/input/InputBroker.cpp +++ b/src/input/InputBroker.cpp @@ -299,6 +299,7 @@ void InputBroker::Init() // Buttons. Moved here cause we need NodeDB to be initialized // If your variant.h has a BUTTON_PIN defined, go ahead and define BUTTON_ACTIVE_LOW and BUTTON_ACTIVE_PULLUP UserButtonThread = new ButtonThread("UserButton"); +#if !MESHTASTIC_EXCLUDE_SCREEN if (screen) { ButtonConfig userConfig; userConfig.pinNumber = (uint8_t)_pinNum; @@ -317,7 +318,9 @@ void InputBroker::Init() userConfig.longPressTime = 500; userConfig.longLongPress = INPUT_BROKER_SHUTDOWN; UserButtonThread->initButton(userConfig); - } else { + } else +#endif + { ButtonConfig userConfigNoScreen; userConfigNoScreen.pinNumber = (uint8_t)_pinNum; userConfigNoScreen.activeLow = BUTTON_ACTIVE_LOW; @@ -379,11 +382,13 @@ void InputBroker::Init() } #endif // HAS_BUTTON #if ARCH_PORTDUINO - if (config.display.displaymode != meshtastic_Config_DisplayConfig_DisplayMode_COLOR && portduino_config.i2cdev != "") { - seesawRotary = new SeesawRotary("SeesawRotary"); - if (!seesawRotary->init()) { - delete seesawRotary; - seesawRotary = nullptr; + if (config.display.displaymode != meshtastic_Config_DisplayConfig_DisplayMode_COLOR) { + if (portduino_config.i2cdev != "") { + seesawRotary = new SeesawRotary("SeesawRotary"); + if (!seesawRotary->init()) { + delete seesawRotary; + seesawRotary = nullptr; + } } aLinuxInputImpl = new LinuxInputImpl(); aLinuxInputImpl->init(); diff --git a/src/mesh/CryptoEngine.cpp b/src/mesh/CryptoEngine.cpp index 4a613b644..daa7a3a75 100644 --- a/src/mesh/CryptoEngine.cpp +++ b/src/mesh/CryptoEngine.cpp @@ -4,6 +4,7 @@ #include #if !(MESHTASTIC_EXCLUDE_PKI) +#include "HardwareRNG.h" #include "NodeDB.h" #include "aes-ccm.h" #include "meshUtils.h" @@ -26,6 +27,15 @@ void CryptoEngine::generateKeyPair(uint8_t *pubKey, uint8_t *privKey) { // Mix in any randomness we can, to make key generation stronger. CryptRNG.begin(optstr(APP_VERSION)); + + uint8_t hardwareEntropy[64] = {0}; + if (HardwareRNG::fill(hardwareEntropy, sizeof(hardwareEntropy), true)) { + CryptRNG.stir(hardwareEntropy, sizeof(hardwareEntropy)); + } else { + LOG_WARN("Hardware entropy unavailable, falling back to software RNG"); + } + memset(hardwareEntropy, 0, sizeof(hardwareEntropy)); + if (myNodeInfo.device_id.size == 16) { CryptRNG.stir(myNodeInfo.device_id.bytes, myNodeInfo.device_id.size); } diff --git a/src/mesh/Default.h b/src/mesh/Default.h index 069ffc0eb..59425042e 100644 --- a/src/mesh/Default.h +++ b/src/mesh/Default.h @@ -32,8 +32,8 @@ #define default_map_publish_interval_secs 60 * 60 // Traffic management defaults -#define default_traffic_mgmt_position_precision_bits 24 // ~10m grid cells -#define default_traffic_mgmt_position_min_interval_secs ONE_DAY // 1 day between identical positions +#define default_traffic_mgmt_position_precision_bits 24 // ~10m grid cells +#define default_traffic_mgmt_position_min_interval_secs (ONE_DAY / 2) // 12 hours between identical positions #ifdef USERPREFS_RINGTONE_NAG_SECS #define default_ringtone_nag_secs USERPREFS_RINGTONE_NAG_SECS diff --git a/src/mesh/HardwareRNG.cpp b/src/mesh/HardwareRNG.cpp new file mode 100644 index 000000000..b455128ac --- /dev/null +++ b/src/mesh/HardwareRNG.cpp @@ -0,0 +1,159 @@ +#include "HardwareRNG.h" + +#include +#include +#include + +#include "configuration.h" + +#if HAS_RADIO +#include "RadioLibInterface.h" +#endif + +#if defined(ARCH_NRF52) +#include +extern Adafruit_nRFCrypto nRFCrypto; +#elif defined(ARCH_ESP32) +#include +#elif defined(ARCH_RP2040) +#include +#elif defined(ARCH_PORTDUINO) +#include +#include +#include +#endif + +namespace HardwareRNG +{ + +namespace +{ +void fillWithRandomDevice(uint8_t *buffer, size_t length) +{ + std::random_device rd; + size_t offset = 0; + while (offset < length) { + uint32_t value = rd(); + size_t toCopy = std::min(length - offset, sizeof(value)); + memcpy(buffer + offset, &value, toCopy); + offset += toCopy; + } +} + +#if HAS_RADIO +bool mixWithLoRaEntropy(uint8_t *buffer, size_t length) +{ + // Only attempt to pull entropy from the modem if it is initialized and exposes the helper. + // When the radio stack is disabled or has not yet been configured, we simply skip this step + // and return false so callers know no extra mixing occurred. + RadioLibInterface *radio = RadioLibInterface::instance; + if (!radio) { + LOG_ERROR("No radio instance available to provide entropy"); + return false; + } + + constexpr size_t chunkSize = 16; + uint8_t scratch[chunkSize]; + size_t offset = 0; + bool mixed = false; + + while (offset < length) { + size_t toCopy = std::min(length - offset, chunkSize); + + // randomBytes() returns false if the modem does not support it or is not ready + // (for instance, when the radio is powered down). We break immediately to avoid + // blocking or returning partially-filled entropy and simply report failure. + if (!radio->randomBytes(scratch, toCopy)) { + break; + } + + for (size_t i = 0; i < toCopy; ++i) { + buffer[offset + i] ^= scratch[i]; + } + + mixed = true; + offset += toCopy; + } + + // Avoid leaving the modem-sourced bytes sitting on the stack longer than needed. + if (mixed) { + memset(scratch, 0, sizeof(scratch)); + } + + return mixed; +} +#endif +} // namespace + +bool fill(uint8_t *buffer, size_t length, bool useRadioEntropy) +{ + if (!buffer || length == 0) { + return false; + } + + bool filled = false; + +#if defined(ARCH_NRF52) + // The Nordic SDK RNG provides cryptographic-quality randomness backed by hardware. + nRFCrypto.begin(); + auto result = nRFCrypto.Random.generate(buffer, length); + nRFCrypto.end(); + filled = result; +#elif defined(ARCH_ESP32) + // ESP32 exposes a true RNG via esp_fill_random(). + esp_fill_random(buffer, length); + filled = true; +#elif defined(ARCH_RP2040) + // RP2040 has a hardware random number generator accessible through the Arduino core. + size_t offset = 0; + while (offset < length) { + uint32_t value = rp2040.hwrand32(); + size_t toCopy = std::min(length - offset, sizeof(value)); + memcpy(buffer + offset, &value, toCopy); + offset += toCopy; + } + filled = true; +#elif defined(ARCH_PORTDUINO) + // Prefer the host OS RNG first when running under Portduino. + ssize_t generated = ::getrandom(buffer, length, 0); + if (generated == static_cast(length)) { + filled = true; + } + + if (!filled) { + fillWithRandomDevice(buffer, length); + filled = true; + } +#endif + + if (!filled) { + // As a last resort, fall back to std::random_device. This should only be reached + // if a platform-specific source was unavailable. + fillWithRandomDevice(buffer, length); + filled = true; + } + +#if HAS_RADIO + if (useRadioEntropy) { + // Best-effort: if the radio is active and can provide modem entropy, XOR it over the + // buffer to improve overall quality. We consider the filling a success if either a + // good platform RNG or the modem RNG provided data, so we return true as long as at + // least one of those steps succeeded. + filled = mixWithLoRaEntropy(buffer, length) || filled; + } +#endif + + return filled; +} + +bool seed(uint32_t &seedOut) +{ + uint32_t candidate = 0; + if (!fill(reinterpret_cast(&candidate), sizeof(candidate), true)) { + return false; + } + seedOut = candidate; + return true; +} + +} // namespace HardwareRNG diff --git a/src/mesh/HardwareRNG.h b/src/mesh/HardwareRNG.h new file mode 100644 index 000000000..2dacb6c23 --- /dev/null +++ b/src/mesh/HardwareRNG.h @@ -0,0 +1,28 @@ +#pragma once + +#include +#include + +namespace HardwareRNG +{ + +/** + * Fill the provided buffer with random bytes sourced from the most + * appropriate hardware-backed RNG available on the current platform. + * + * @param buffer Destination buffer for random bytes + * @param length Number of bytes to write + * @param useRadioEntropy If true, attempt to mix radio entropy into the output as well. + * @return true if the buffer was fully populated with entropy, false on failure + */ +bool fill(uint8_t *buffer, size_t length, bool useRadioEntropy = false); + +/** + * Populate a 32-bit seed value with hardware-backed randomness where possible. + * + * @param seedOut Destination for the generated seed value + * @return true if a seed was produced from a reliable entropy source + */ +bool seed(uint32_t &seedOut); + +} // namespace HardwareRNG diff --git a/src/mesh/LR11x0Interface.cpp b/src/mesh/LR11x0Interface.cpp index 9f808da26..7a193f7f3 100644 --- a/src/mesh/LR11x0Interface.cpp +++ b/src/mesh/LR11x0Interface.cpp @@ -71,12 +71,10 @@ template bool LR11x0Interface::init() RadioLibInterface::init(); - limitPower(LR1110_MAX_POWER); - - if ((power > LR1120_MAX_POWER) && - (config.lora.region == meshtastic_Config_LoRaConfig_RegionCode_LORA_24)) { // clamp again if wide freq range - power = LR1120_MAX_POWER; - preambleLength = 12; // 12 is the default for operation above 2GHz + if (config.lora.region == meshtastic_Config_LoRaConfig_RegionCode_LORA_24) { // clamp if wide freq range + limitPower(LR1120_MAX_POWER); + } else { + limitPower(LR1110_MAX_POWER); // default clamp for non-wide freq range } #ifdef LR11X0_RF_SWITCH_SUBGHZ @@ -177,6 +175,12 @@ template bool LR11x0Interface::reconfigure() err = lora.setSyncWord(syncWord); assert(err == RADIOLIB_ERR_NONE); + if (config.lora.region == meshtastic_Config_LoRaConfig_RegionCode_LORA_24) { // clamp if wide freq range + limitPower(LR1120_MAX_POWER); + } else { + limitPower(LR1110_MAX_POWER); // default clamp for non-wide freq range + } + err = lora.setPreambleLength(preambleLength); assert(err == RADIOLIB_ERR_NONE); @@ -184,11 +188,6 @@ template bool LR11x0Interface::reconfigure() if (err != RADIOLIB_ERR_NONE) RECORD_CRITICALERROR(meshtastic_CriticalErrorCode_INVALID_RADIO_SETTING); - if (power > LR1110_MAX_POWER) // This chip has lower power limits than some - power = LR1110_MAX_POWER; - if ((power > LR1120_MAX_POWER) && (config.lora.region == meshtastic_Config_LoRaConfig_RegionCode_LORA_24)) // 2.4G power limit - power = LR1120_MAX_POWER; - err = lora.setOutputPower(power); assert(err == RADIOLIB_ERR_NONE); diff --git a/src/mesh/NodeDB.cpp b/src/mesh/NodeDB.cpp index 01be50c26..4b0871566 100644 --- a/src/mesh/NodeDB.cpp +++ b/src/mesh/NodeDB.cpp @@ -819,7 +819,7 @@ void NodeDB::installDefaultModuleConfig() moduleConfig.has_store_forward = true; moduleConfig.has_telemetry = true; moduleConfig.has_external_notification = true; -#if defined(PIN_BUZZER) || defined(PIN_VIBRATION) || defined(LED_NOTIFICATION) +#if defined(PIN_BUZZER) || defined(PIN_VIBRATION) || defined(LED_NOTIFICATION) || defined(PCA_LED_NOTIFICATION) moduleConfig.external_notification.enabled = true; #endif #if defined(PIN_BUZZER) diff --git a/src/mesh/PointerQueue.h b/src/mesh/PointerQueue.h index b45245eb8..972eb65fd 100644 --- a/src/mesh/PointerQueue.h +++ b/src/mesh/PointerQueue.h @@ -17,14 +17,4 @@ template class PointerQueue : public TypedQueue return this->dequeue(&p, maxWait) ? p : nullptr; } - -#ifdef HAS_FREE_RTOS - // returns a ptr or null if the queue was empty - T *dequeuePtrFromISR(BaseType_t *higherPriWoken) - { - T *p; - - return this->dequeueFromISR(&p, higherPriWoken) ? p : nullptr; - } -#endif }; diff --git a/src/mesh/RF95Interface.cpp b/src/mesh/RF95Interface.cpp index b3aa72f7a..32c92de93 100644 --- a/src/mesh/RF95Interface.cpp +++ b/src/mesh/RF95Interface.cpp @@ -240,8 +240,7 @@ bool RF95Interface::reconfigure() if (err != RADIOLIB_ERR_NONE) RECORD_CRITICALERROR(meshtastic_CriticalErrorCode_INVALID_RADIO_SETTING); - if (power > RF95_MAX_POWER) // This chip has lower power limits than some - power = RF95_MAX_POWER; + limitPower(RF95_MAX_POWER); #ifdef USE_RF95_RFO err = lora->setOutputPower(power, true); diff --git a/src/mesh/RadioInterface.cpp b/src/mesh/RadioInterface.cpp index 9ce944002..b7b672d8b 100644 --- a/src/mesh/RadioInterface.cpp +++ b/src/mesh/RadioInterface.cpp @@ -152,8 +152,10 @@ const RegionInfo regions[] = { /* https://lora-alliance.org/wp-content/uploads/2020/11/lorawan_regional_parameters_v1.0.3reva_0.pdf + https://standard.nbtc.go.th/getattachment/Standards/%E0%B8%A1%E0%B8%B2%E0%B8%95%E0%B8%A3%E0%B8%90%E0%B8%B2%E0%B8%99%E0%B8%97%E0%B8%B2%E0%B8%87%E0%B9%80%E0%B8%97%E0%B8%84%E0%B8%99%E0%B8%B4%E0%B8%84%E0%B8%82%E0%B8%AD%E0%B8%87%E0%B9%80%E0%B8%84%E0%B8%A3%E0%B8%B7%E0%B9%88%E0%B8%AD%E0%B8%87%E0%B9%82%E0%B8%97%E0%B8%A3%E0%B8%84%E0%B8%A1%E0%B8%99%E0%B8%B2%E0%B8%84%E0%B8%A1/1033-2565.pdf.aspx?lang=th-TH + Thailand 920–925 MHz set max TX power to 27 dBm and enforce 10% duty cycle, aligned with NBTC regulations. */ - RDEF(TH, 920.0f, 925.0f, 100, 16, false, false, PROFILE_STD), + RDEF(TH, 920.0f, 925.0f, 10, 27, false, false, PROFILE_STD), /* 433,05-434,7 Mhz 10 mW @@ -961,7 +963,7 @@ void RadioInterface::applyModemConfig() cr = loraConfig.coding_rate; LOG_INFO("Using custom Coding Rate %u", cr); } else { - cr = loraConfig.coding_rate; + cr = newcr; } } else { // if not using preset, then just use the custom settings @@ -1036,6 +1038,13 @@ void RadioInterface::applyModemConfig() saveFreq(freq + loraConfig.frequency_offset); const char *channelName = channels.getName(channels.getPrimaryIndex()); + if (newRegion->wideLora) { // clamp if wide freq range + preambleLength = wideLoraPreambleLengthDefault; // 12 is the default for operation above 2GHz + } else { + preambleLength = + preambleLengthDefault; // 8 is default, but we use longer to increase the amount of sleep time when receiving + } + slotTimeMsec = computeSlotTimeMsec(); preambleTimeMsec = preambleLength * (pow_of_2(sf) / bw); diff --git a/src/mesh/RadioInterface.h b/src/mesh/RadioInterface.h index a7176f388..a1c692e24 100644 --- a/src/mesh/RadioInterface.h +++ b/src/mesh/RadioInterface.h @@ -92,15 +92,20 @@ class RadioInterface uint8_t sf = 9; uint8_t cr = 5; - const uint8_t NUM_SYM_CAD = 2; // Number of symbols used for CAD, 2 is the default since RadioLib 6.3.0 as per AN1200.48 - const uint8_t NUM_SYM_CAD_24GHZ = 4; // Number of symbols used for CAD in 2.4 GHz, 4 is recommended in AN1200.22 of SX1280 + static constexpr uint8_t NUM_SYM_CAD = + 2; // Number of symbols used for CAD, 2 is the default since RadioLib 6.3.0 as per AN1200.48 + static constexpr uint8_t NUM_SYM_CAD_24GHZ = + 4; // Number of symbols used for CAD in 2.4 GHz, 4 is recommended in AN1200.22 of SX1280 uint32_t slotTimeMsec = computeSlotTimeMsec(); - uint16_t preambleLength = 16; // 8 is default, but we use longer to increase the amount of sleep time when receiving - uint32_t preambleTimeMsec = 165; // calculated on startup, this is the default for LongFast - const uint32_t PROCESSING_TIME_MSEC = - 4500; // time to construct, process and construct a packet again (empirically determined) - const uint8_t CWmin = 3; // minimum CWsize - const uint8_t CWmax = 8; // maximum CWsize + uint16_t preambleLength = 16; // 8 is default, but we use longer to increase the amount of sleep time when receiving + static constexpr uint16_t preambleLengthDefault = + 16; // 8 is default, but we use longer to increase the amount of sleep time when receiving + static constexpr uint16_t wideLoraPreambleLengthDefault = 12; // 12 is default for wide Lora + uint32_t preambleTimeMsec = 165; // calculated on startup, this is the default for LongFast + static constexpr uint32_t PROCESSING_TIME_MSEC = + 4500; // time to construct, process and construct a packet again (empirically determined) + static constexpr uint8_t CWmin = 3; // minimum CWsize + static constexpr uint8_t CWmax = 8; // maximum CWsize meshtastic_MeshPacket *sendingPacket = NULL; // The packet we are currently sending uint32_t lastTxStart = 0L; diff --git a/src/mesh/RadioLibInterface.cpp b/src/mesh/RadioLibInterface.cpp index 30cd587da..7ef707e0d 100644 --- a/src/mesh/RadioLibInterface.cpp +++ b/src/mesh/RadioLibInterface.cpp @@ -246,6 +246,24 @@ bool RadioLibInterface::findInTxQueue(NodeNum from, PacketId id) return txQueue.find(from, id); } +bool RadioLibInterface::randomBytes(uint8_t *buffer, size_t length) +{ + if (!buffer || length == 0 || !iface) { + return false; + } + + // Older RadioLib versions only expose random(min, max), so fill the buffer byte-by-byte. + for (size_t i = 0; i < length; ++i) { + int32_t value = iface->random(0, 255); + if (value < 0) { + return false; + } + buffer[i] = static_cast(value & 0xFF); + } + + return true; +} + /** radio helper thread callback. We never immediately transmit after any operation (either Rx or Tx). Instead we should wait a random multiple of 'slotTimes' (see definition in RadioInterface.h) taken from a contention window (CW) to lower the chance of collision. @@ -587,4 +605,4 @@ bool RadioLibInterface::startSend(meshtastic_MeshPacket *txp) return res == RADIOLIB_ERR_NONE; } -} \ No newline at end of file +} diff --git a/src/mesh/RadioLibInterface.h b/src/mesh/RadioLibInterface.h index ca3d78503..310ca76bb 100644 --- a/src/mesh/RadioLibInterface.h +++ b/src/mesh/RadioLibInterface.h @@ -172,6 +172,12 @@ class RadioLibInterface : public RadioInterface, protected concurrency::Notified /** Attempt to find a packet in the TxQueue. Returns true if the packet was found. */ virtual bool findInTxQueue(NodeNum from, PacketId id) override; + /** + * Request randomness sourced from the LoRa modem, if supported by the active RadioLib interface. + * @return true if len bytes were produced, false otherwise. + */ + bool randomBytes(uint8_t *buffer, size_t length); + private: /** if we have something waiting to send, start a short (random) timer so we can come check for collision before actually * doing the transmit */ diff --git a/src/mesh/SX126xInterface.cpp b/src/mesh/SX126xInterface.cpp index a4e82011e..bcb08f2c5 100644 --- a/src/mesh/SX126xInterface.cpp +++ b/src/mesh/SX126xInterface.cpp @@ -245,8 +245,10 @@ template bool SX126xInterface::reconfigure() if (err != RADIOLIB_ERR_NONE) RECORD_CRITICALERROR(meshtastic_CriticalErrorCode_INVALID_RADIO_SETTING); - if (power > SX126X_MAX_POWER) // This chip has lower power limits than some - power = SX126X_MAX_POWER; + limitPower(SX126X_MAX_POWER); + // Make sure we reach the minimum power supported to turn the chip on (-9dBm) + if (power < -9) + power = -9; err = lora.setOutputPower(power); if (err != RADIOLIB_ERR_NONE) diff --git a/src/mesh/SX128xInterface.cpp b/src/mesh/SX128xInterface.cpp index 0e882ef05..cb21c0770 100644 --- a/src/mesh/SX128xInterface.cpp +++ b/src/mesh/SX128xInterface.cpp @@ -144,8 +144,7 @@ template bool SX128xInterface::reconfigure() if (err != RADIOLIB_ERR_NONE) RECORD_CRITICALERROR(meshtastic_CriticalErrorCode_INVALID_RADIO_SETTING); - if (power > SX128X_MAX_POWER) // This chip has lower power limits than some - power = SX128X_MAX_POWER; + limitPower(SX128X_MAX_POWER); err = lora.setOutputPower(power); if (err != RADIOLIB_ERR_NONE) diff --git a/src/mesh/generated/meshtastic/atak.pb.cpp b/src/mesh/generated/meshtastic/atak.pb.cpp index a0368cf6b..bbafa33e2 100644 --- a/src/mesh/generated/meshtastic/atak.pb.cpp +++ b/src/mesh/generated/meshtastic/atak.pb.cpp @@ -24,6 +24,18 @@ PB_BIND(meshtastic_Contact, meshtastic_Contact, AUTO) PB_BIND(meshtastic_PLI, meshtastic_PLI, AUTO) +PB_BIND(meshtastic_AircraftTrack, meshtastic_AircraftTrack, AUTO) + + +PB_BIND(meshtastic_TAKPacketV2, meshtastic_TAKPacketV2, 2) + + + + + + + + diff --git a/src/mesh/generated/meshtastic/atak.pb.h b/src/mesh/generated/meshtastic/atak.pb.h index 8533bcbf9..c12b042f4 100644 --- a/src/mesh/generated/meshtastic/atak.pb.h +++ b/src/mesh/generated/meshtastic/atak.pb.h @@ -65,6 +65,197 @@ typedef enum _meshtastic_MemberRole { meshtastic_MemberRole_K9 = 8 } meshtastic_MemberRole; +/* CoT how field values. + Represents how the coordinates were generated. */ +typedef enum _meshtastic_CotHow { + /* Unspecified */ + meshtastic_CotHow_CotHow_Unspecified = 0, + /* Human entered */ + meshtastic_CotHow_CotHow_h_e = 1, + /* Machine generated */ + meshtastic_CotHow_CotHow_m_g = 2, + /* Human GPS/INS derived */ + meshtastic_CotHow_CotHow_h_g_i_g_o = 3, + /* Machine relayed (imported from another system/gateway) */ + meshtastic_CotHow_CotHow_m_r = 4, + /* Machine fused (corroborated from multiple sources) */ + meshtastic_CotHow_CotHow_m_f = 5, + /* Machine predicted */ + meshtastic_CotHow_CotHow_m_p = 6, + /* Machine simulated */ + meshtastic_CotHow_CotHow_m_s = 7 +} meshtastic_CotHow; + +/* Well-known CoT event types. + When the type is known, use the enum value for efficient encoding. + For unknown types, set cot_type_id to CotType_Other and populate cot_type_str. */ +typedef enum _meshtastic_CotType { + /* Unknown or unmapped type, use cot_type_str */ + meshtastic_CotType_CotType_Other = 0, + /* a-f-G-U-C: Friendly ground unit combat */ + meshtastic_CotType_CotType_a_f_G_U_C = 1, + /* a-f-G-U-C-I: Friendly ground unit combat infantry */ + meshtastic_CotType_CotType_a_f_G_U_C_I = 2, + /* a-n-A-C-F: Neutral aircraft civilian fixed-wing */ + meshtastic_CotType_CotType_a_n_A_C_F = 3, + /* a-n-A-C-H: Neutral aircraft civilian helicopter */ + meshtastic_CotType_CotType_a_n_A_C_H = 4, + /* a-n-A-C: Neutral aircraft civilian */ + meshtastic_CotType_CotType_a_n_A_C = 5, + /* a-f-A-M-H: Friendly aircraft military helicopter */ + meshtastic_CotType_CotType_a_f_A_M_H = 6, + /* a-f-A-M: Friendly aircraft military */ + meshtastic_CotType_CotType_a_f_A_M = 7, + /* a-f-A-M-F-F: Friendly aircraft military fixed-wing fighter */ + meshtastic_CotType_CotType_a_f_A_M_F_F = 8, + /* a-f-A-M-H-A: Friendly aircraft military helicopter attack */ + meshtastic_CotType_CotType_a_f_A_M_H_A = 9, + /* a-f-A-M-H-U-M: Friendly aircraft military helicopter utility medium */ + meshtastic_CotType_CotType_a_f_A_M_H_U_M = 10, + /* a-h-A-M-F-F: Hostile aircraft military fixed-wing fighter */ + meshtastic_CotType_CotType_a_h_A_M_F_F = 11, + /* a-h-A-M-H-A: Hostile aircraft military helicopter attack */ + meshtastic_CotType_CotType_a_h_A_M_H_A = 12, + /* a-u-A-C: Unknown aircraft civilian */ + meshtastic_CotType_CotType_a_u_A_C = 13, + /* t-x-d-d: Tasking delete/disconnect */ + meshtastic_CotType_CotType_t_x_d_d = 14, + /* a-f-G-E-S-E: Friendly ground equipment sensor */ + meshtastic_CotType_CotType_a_f_G_E_S_E = 15, + /* a-f-G-E-V-C: Friendly ground equipment vehicle */ + meshtastic_CotType_CotType_a_f_G_E_V_C = 16, + /* a-f-S: Friendly sea */ + meshtastic_CotType_CotType_a_f_S = 17, + /* a-f-A-M-F: Friendly aircraft military fixed-wing */ + meshtastic_CotType_CotType_a_f_A_M_F = 18, + /* a-f-A-M-F-C-H: Friendly aircraft military fixed-wing cargo heavy */ + meshtastic_CotType_CotType_a_f_A_M_F_C_H = 19, + /* a-f-A-M-F-U-L: Friendly aircraft military fixed-wing utility light */ + meshtastic_CotType_CotType_a_f_A_M_F_U_L = 20, + /* a-f-A-M-F-L: Friendly aircraft military fixed-wing liaison */ + meshtastic_CotType_CotType_a_f_A_M_F_L = 21, + /* a-f-A-M-F-P: Friendly aircraft military fixed-wing patrol */ + meshtastic_CotType_CotType_a_f_A_M_F_P = 22, + /* a-f-A-C-H: Friendly aircraft civilian helicopter */ + meshtastic_CotType_CotType_a_f_A_C_H = 23, + /* a-n-A-M-F-Q: Neutral aircraft military fixed-wing drone */ + meshtastic_CotType_CotType_a_n_A_M_F_Q = 24, + /* b-t-f: GeoChat message */ + meshtastic_CotType_CotType_b_t_f = 25, + /* b-r-f-h-c: CASEVAC/MEDEVAC report */ + meshtastic_CotType_CotType_b_r_f_h_c = 26, + /* b-a-o-pan: Ring the bell / alert all */ + meshtastic_CotType_CotType_b_a_o_pan = 27, + /* b-a-o-opn: Troops in contact */ + meshtastic_CotType_CotType_b_a_o_opn = 28, + /* b-a-o-can: Cancel alert */ + meshtastic_CotType_CotType_b_a_o_can = 29, + /* b-a-o-tbl: 911 alert */ + meshtastic_CotType_CotType_b_a_o_tbl = 30, + /* b-a-g: Geofence breach alert */ + meshtastic_CotType_CotType_b_a_g = 31, + /* a-f-G: Friendly ground (generic) */ + meshtastic_CotType_CotType_a_f_G = 32, + /* a-f-G-U: Friendly ground unit (generic) */ + meshtastic_CotType_CotType_a_f_G_U = 33, + /* a-h-G: Hostile ground (generic) */ + meshtastic_CotType_CotType_a_h_G = 34, + /* a-u-G: Unknown ground (generic) */ + meshtastic_CotType_CotType_a_u_G = 35, + /* a-n-G: Neutral ground (generic) */ + meshtastic_CotType_CotType_a_n_G = 36, + /* b-m-r: Route */ + meshtastic_CotType_CotType_b_m_r = 37, + /* b-m-p-w: Route waypoint */ + meshtastic_CotType_CotType_b_m_p_w = 38, + /* b-m-p-s-p-i: Self-position marker */ + meshtastic_CotType_CotType_b_m_p_s_p_i = 39, + /* u-d-f: Freeform shape (line/polygon) */ + meshtastic_CotType_CotType_u_d_f = 40, + /* u-d-r: Rectangle */ + meshtastic_CotType_CotType_u_d_r = 41, + /* u-d-c-c: Circle */ + meshtastic_CotType_CotType_u_d_c_c = 42, + /* u-rb-a: Range/bearing line */ + meshtastic_CotType_CotType_u_rb_a = 43, + /* a-h-A: Hostile aircraft (generic) */ + meshtastic_CotType_CotType_a_h_A = 44, + /* a-u-A: Unknown aircraft (generic) */ + meshtastic_CotType_CotType_a_u_A = 45, + /* a-f-A-M-H-Q: Friendly aircraft military helicopter observation */ + meshtastic_CotType_CotType_a_f_A_M_H_Q = 46, + /* a-f-A-C-F: Friendly aircraft civilian fixed-wing */ + meshtastic_CotType_CotType_a_f_A_C_F = 47, + /* a-f-A-C: Friendly aircraft civilian (generic) */ + meshtastic_CotType_CotType_a_f_A_C = 48, + /* a-f-A-C-L: Friendly aircraft civilian lighter-than-air */ + meshtastic_CotType_CotType_a_f_A_C_L = 49, + /* a-f-A: Friendly aircraft (generic) */ + meshtastic_CotType_CotType_a_f_A = 50, + /* a-f-A-M-H-C: Friendly aircraft military helicopter cargo */ + meshtastic_CotType_CotType_a_f_A_M_H_C = 51, + /* a-n-A-M-F-F: Neutral aircraft military fixed-wing fighter */ + meshtastic_CotType_CotType_a_n_A_M_F_F = 52, + /* a-u-A-C-F: Unknown aircraft civilian fixed-wing */ + meshtastic_CotType_CotType_a_u_A_C_F = 53, + /* a-f-G-U-C-F-T-A: Friendly ground unit combat forces theater aviation */ + meshtastic_CotType_CotType_a_f_G_U_C_F_T_A = 54, + /* a-f-G-U-C-V-S: Friendly ground unit combat vehicle support */ + meshtastic_CotType_CotType_a_f_G_U_C_V_S = 55, + /* a-f-G-U-C-R-X: Friendly ground unit combat reconnaissance exploitation */ + meshtastic_CotType_CotType_a_f_G_U_C_R_X = 56, + /* a-f-G-U-C-I-Z: Friendly ground unit combat infantry mechanized */ + meshtastic_CotType_CotType_a_f_G_U_C_I_Z = 57, + /* a-f-G-U-C-E-C-W: Friendly ground unit combat engineer construction wheeled */ + meshtastic_CotType_CotType_a_f_G_U_C_E_C_W = 58, + /* a-f-G-U-C-I-L: Friendly ground unit combat infantry light */ + meshtastic_CotType_CotType_a_f_G_U_C_I_L = 59, + /* a-f-G-U-C-R-O: Friendly ground unit combat reconnaissance other */ + meshtastic_CotType_CotType_a_f_G_U_C_R_O = 60, + /* a-f-G-U-C-R-V: Friendly ground unit combat reconnaissance cavalry */ + meshtastic_CotType_CotType_a_f_G_U_C_R_V = 61, + /* a-f-G-U-H: Friendly ground unit headquarters */ + meshtastic_CotType_CotType_a_f_G_U_H = 62, + /* a-f-G-U-U-M-S-E: Friendly ground unit support medical surgical evacuation */ + meshtastic_CotType_CotType_a_f_G_U_U_M_S_E = 63, + /* a-f-G-U-S-M-C: Friendly ground unit support maintenance collection */ + meshtastic_CotType_CotType_a_f_G_U_S_M_C = 64, + /* a-f-G-E-S: Friendly ground equipment sensor (generic) */ + meshtastic_CotType_CotType_a_f_G_E_S = 65, + /* a-f-G-E: Friendly ground equipment (generic) */ + meshtastic_CotType_CotType_a_f_G_E = 66, + /* a-f-G-E-V-C-U: Friendly ground equipment vehicle utility */ + meshtastic_CotType_CotType_a_f_G_E_V_C_U = 67, + /* a-f-G-E-V-C-ps: Friendly ground equipment vehicle public safety */ + meshtastic_CotType_CotType_a_f_G_E_V_C_ps = 68, + /* a-u-G-E-V: Unknown ground equipment vehicle */ + meshtastic_CotType_CotType_a_u_G_E_V = 69, + /* a-f-S-N-N-R: Friendly sea surface non-naval rescue */ + meshtastic_CotType_CotType_a_f_S_N_N_R = 70, + /* a-f-F-B: Friendly force boundary */ + meshtastic_CotType_CotType_a_f_F_B = 71, + /* b-m-p-s-p-loc: Self-position location marker */ + meshtastic_CotType_CotType_b_m_p_s_p_loc = 72, + /* b-i-v: Imagery/video */ + meshtastic_CotType_CotType_b_i_v = 73, + /* b-f-t-r: File transfer request */ + meshtastic_CotType_CotType_b_f_t_r = 74, + /* b-f-t-a: File transfer acknowledgment */ + meshtastic_CotType_CotType_b_f_t_a = 75 +} meshtastic_CotType; + +/* Geopoint and altitude source */ +typedef enum _meshtastic_GeoPointSource { + /* Unspecified */ + meshtastic_GeoPointSource_GeoPointSource_Unspecified = 0, + /* GPS derived */ + meshtastic_GeoPointSource_GeoPointSource_GPS = 1, + /* User entered */ + meshtastic_GeoPointSource_GeoPointSource_USER = 2, + /* Network/external */ + meshtastic_GeoPointSource_GeoPointSource_NETWORK = 3 +} meshtastic_GeoPointSource; + /* Struct definitions */ /* ATAK GeoChat message */ typedef struct _meshtastic_GeoChat { @@ -146,6 +337,95 @@ typedef struct _meshtastic_TAKPacket { } payload_variant; } meshtastic_TAKPacket; +/* Aircraft track information from ADS-B or military air tracking. + Covers the majority of observed real-world CoT traffic. */ +typedef struct _meshtastic_AircraftTrack { + /* ICAO hex identifier (e.g. "AD237C") */ + char icao[8]; + /* Aircraft registration (e.g. "N946AK") */ + char registration[16]; + /* Flight number/callsign (e.g. "ASA864") */ + char flight[16]; + /* ICAO aircraft type designator (e.g. "B39M") */ + char aircraft_type[8]; + /* Transponder squawk code (0-7777 octal) */ + uint16_t squawk; + /* ADS-B emitter category (e.g. "A3") */ + char category[4]; + /* Received signal strength * 10 (e.g. -194 for -19.4 dBm) */ + int32_t rssi_x10; + /* Whether receiver has GPS fix */ + bool gps; + /* CoT host ID for source attribution */ + char cot_host_id[64]; +} meshtastic_AircraftTrack; + +typedef PB_BYTES_ARRAY_T(220) meshtastic_TAKPacketV2_raw_detail_t; +/* ATAK v2 packet with expanded CoT field support and zstd dictionary compression. + Sent on ATAK_PLUGIN_V2 port. The wire payload is: + [1 byte flags][zstd-compressed TAKPacketV2 protobuf] + Flags byte: bits 0-5 = dictionary ID, bits 6-7 = reserved. */ +typedef struct _meshtastic_TAKPacketV2 { + /* Well-known CoT event type enum. + Use CotType_Other with cot_type_str for unknown types. */ + meshtastic_CotType cot_type_id; + /* How the coordinates were generated */ + meshtastic_CotHow how; + /* Callsign */ + char callsign[120]; + /* Team color assignment */ + meshtastic_Team team; + /* Role of the group member */ + meshtastic_MemberRole role; + /* Latitude, multiply by 1e-7 to get degrees in floating point */ + int32_t latitude_i; + /* Longitude, multiply by 1e-7 to get degrees in floating point */ + int32_t longitude_i; + /* Altitude in meters (HAE) */ + int32_t altitude; + /* Speed in cm/s */ + uint32_t speed; + /* Course in degrees * 100 (0-36000) */ + uint16_t course; + /* Battery level 0-100 */ + uint8_t battery; + /* Geopoint source */ + meshtastic_GeoPointSource geo_src; + /* Altitude source */ + meshtastic_GeoPointSource alt_src; + /* Device UID (UUID string or device ID like "ANDROID-xxxx") */ + char uid[48]; + /* Device callsign */ + char device_callsign[120]; + /* Stale time as seconds offset from event time */ + uint16_t stale_seconds; + /* TAK client version string */ + char tak_version[64]; + /* TAK device model */ + char tak_device[32]; + /* TAK platform (ATAK-CIV, WebTAK, etc.) */ + char tak_platform[32]; + /* TAK OS version */ + char tak_os[16]; + /* Connection endpoint */ + char endpoint[32]; + /* Phone number */ + char phone[20]; + /* CoT event type string, only populated when cot_type_id is CotType_Other */ + char cot_type_str[32]; + pb_size_t which_payload_variant; + union { + /* Position report (true = PLI, no extra fields beyond the common ones above) */ + bool pli; + /* ATAK GeoChat message */ + meshtastic_GeoChat chat; + /* Aircraft track data (ADS-B, military air) */ + meshtastic_AircraftTrack aircraft; + /* Generic CoT detail XML for unmapped types */ + meshtastic_TAKPacketV2_raw_detail_t raw_detail; + } payload_variant; +} meshtastic_TAKPacketV2; + #ifdef __cplusplus extern "C" { @@ -160,6 +440,18 @@ extern "C" { #define _meshtastic_MemberRole_MAX meshtastic_MemberRole_K9 #define _meshtastic_MemberRole_ARRAYSIZE ((meshtastic_MemberRole)(meshtastic_MemberRole_K9+1)) +#define _meshtastic_CotHow_MIN meshtastic_CotHow_CotHow_Unspecified +#define _meshtastic_CotHow_MAX meshtastic_CotHow_CotHow_m_s +#define _meshtastic_CotHow_ARRAYSIZE ((meshtastic_CotHow)(meshtastic_CotHow_CotHow_m_s+1)) + +#define _meshtastic_CotType_MIN meshtastic_CotType_CotType_Other +#define _meshtastic_CotType_MAX meshtastic_CotType_CotType_b_f_t_a +#define _meshtastic_CotType_ARRAYSIZE ((meshtastic_CotType)(meshtastic_CotType_CotType_b_f_t_a+1)) + +#define _meshtastic_GeoPointSource_MIN meshtastic_GeoPointSource_GeoPointSource_Unspecified +#define _meshtastic_GeoPointSource_MAX meshtastic_GeoPointSource_GeoPointSource_NETWORK +#define _meshtastic_GeoPointSource_ARRAYSIZE ((meshtastic_GeoPointSource)(meshtastic_GeoPointSource_GeoPointSource_NETWORK+1)) + #define meshtastic_Group_role_ENUMTYPE meshtastic_MemberRole @@ -169,6 +461,14 @@ extern "C" { +#define meshtastic_TAKPacketV2_cot_type_id_ENUMTYPE meshtastic_CotType +#define meshtastic_TAKPacketV2_how_ENUMTYPE meshtastic_CotHow +#define meshtastic_TAKPacketV2_team_ENUMTYPE meshtastic_Team +#define meshtastic_TAKPacketV2_role_ENUMTYPE meshtastic_MemberRole +#define meshtastic_TAKPacketV2_geo_src_ENUMTYPE meshtastic_GeoPointSource +#define meshtastic_TAKPacketV2_alt_src_ENUMTYPE meshtastic_GeoPointSource + + /* Initializer values for message structs */ #define meshtastic_TAKPacket_init_default {0, false, meshtastic_Contact_init_default, false, meshtastic_Group_init_default, false, meshtastic_Status_init_default, 0, {meshtastic_PLI_init_default}} #define meshtastic_GeoChat_init_default {"", false, "", false, ""} @@ -176,12 +476,16 @@ extern "C" { #define meshtastic_Status_init_default {0} #define meshtastic_Contact_init_default {"", ""} #define meshtastic_PLI_init_default {0, 0, 0, 0, 0} +#define meshtastic_AircraftTrack_init_default {"", "", "", "", 0, "", 0, 0, ""} +#define meshtastic_TAKPacketV2_init_default {_meshtastic_CotType_MIN, _meshtastic_CotHow_MIN, "", _meshtastic_Team_MIN, _meshtastic_MemberRole_MIN, 0, 0, 0, 0, 0, 0, _meshtastic_GeoPointSource_MIN, _meshtastic_GeoPointSource_MIN, "", "", 0, "", "", "", "", "", "", "", 0, {0}} #define meshtastic_TAKPacket_init_zero {0, false, meshtastic_Contact_init_zero, false, meshtastic_Group_init_zero, false, meshtastic_Status_init_zero, 0, {meshtastic_PLI_init_zero}} #define meshtastic_GeoChat_init_zero {"", false, "", false, ""} #define meshtastic_Group_init_zero {_meshtastic_MemberRole_MIN, _meshtastic_Team_MIN} #define meshtastic_Status_init_zero {0} #define meshtastic_Contact_init_zero {"", ""} #define meshtastic_PLI_init_zero {0, 0, 0, 0, 0} +#define meshtastic_AircraftTrack_init_zero {"", "", "", "", 0, "", 0, 0, ""} +#define meshtastic_TAKPacketV2_init_zero {_meshtastic_CotType_MIN, _meshtastic_CotHow_MIN, "", _meshtastic_Team_MIN, _meshtastic_MemberRole_MIN, 0, 0, 0, 0, 0, 0, _meshtastic_GeoPointSource_MIN, _meshtastic_GeoPointSource_MIN, "", "", 0, "", "", "", "", "", "", "", 0, {0}} /* Field tags (for use in manual encoding/decoding) */ #define meshtastic_GeoChat_message_tag 1 @@ -204,6 +508,42 @@ extern "C" { #define meshtastic_TAKPacket_pli_tag 5 #define meshtastic_TAKPacket_chat_tag 6 #define meshtastic_TAKPacket_detail_tag 7 +#define meshtastic_AircraftTrack_icao_tag 1 +#define meshtastic_AircraftTrack_registration_tag 2 +#define meshtastic_AircraftTrack_flight_tag 3 +#define meshtastic_AircraftTrack_aircraft_type_tag 4 +#define meshtastic_AircraftTrack_squawk_tag 5 +#define meshtastic_AircraftTrack_category_tag 6 +#define meshtastic_AircraftTrack_rssi_x10_tag 7 +#define meshtastic_AircraftTrack_gps_tag 8 +#define meshtastic_AircraftTrack_cot_host_id_tag 9 +#define meshtastic_TAKPacketV2_cot_type_id_tag 1 +#define meshtastic_TAKPacketV2_how_tag 2 +#define meshtastic_TAKPacketV2_callsign_tag 3 +#define meshtastic_TAKPacketV2_team_tag 4 +#define meshtastic_TAKPacketV2_role_tag 5 +#define meshtastic_TAKPacketV2_latitude_i_tag 6 +#define meshtastic_TAKPacketV2_longitude_i_tag 7 +#define meshtastic_TAKPacketV2_altitude_tag 8 +#define meshtastic_TAKPacketV2_speed_tag 9 +#define meshtastic_TAKPacketV2_course_tag 10 +#define meshtastic_TAKPacketV2_battery_tag 11 +#define meshtastic_TAKPacketV2_geo_src_tag 12 +#define meshtastic_TAKPacketV2_alt_src_tag 13 +#define meshtastic_TAKPacketV2_uid_tag 14 +#define meshtastic_TAKPacketV2_device_callsign_tag 15 +#define meshtastic_TAKPacketV2_stale_seconds_tag 16 +#define meshtastic_TAKPacketV2_tak_version_tag 17 +#define meshtastic_TAKPacketV2_tak_device_tag 18 +#define meshtastic_TAKPacketV2_tak_platform_tag 19 +#define meshtastic_TAKPacketV2_tak_os_tag 20 +#define meshtastic_TAKPacketV2_endpoint_tag 21 +#define meshtastic_TAKPacketV2_phone_tag 22 +#define meshtastic_TAKPacketV2_cot_type_str_tag 23 +#define meshtastic_TAKPacketV2_pli_tag 30 +#define meshtastic_TAKPacketV2_chat_tag 31 +#define meshtastic_TAKPacketV2_aircraft_tag 32 +#define meshtastic_TAKPacketV2_raw_detail_tag 33 /* Struct field encoding specification for nanopb */ #define meshtastic_TAKPacket_FIELDLIST(X, a) \ @@ -255,12 +595,60 @@ X(a, STATIC, SINGULAR, UINT32, course, 5) #define meshtastic_PLI_CALLBACK NULL #define meshtastic_PLI_DEFAULT NULL +#define meshtastic_AircraftTrack_FIELDLIST(X, a) \ +X(a, STATIC, SINGULAR, STRING, icao, 1) \ +X(a, STATIC, SINGULAR, STRING, registration, 2) \ +X(a, STATIC, SINGULAR, STRING, flight, 3) \ +X(a, STATIC, SINGULAR, STRING, aircraft_type, 4) \ +X(a, STATIC, SINGULAR, UINT32, squawk, 5) \ +X(a, STATIC, SINGULAR, STRING, category, 6) \ +X(a, STATIC, SINGULAR, SINT32, rssi_x10, 7) \ +X(a, STATIC, SINGULAR, BOOL, gps, 8) \ +X(a, STATIC, SINGULAR, STRING, cot_host_id, 9) +#define meshtastic_AircraftTrack_CALLBACK NULL +#define meshtastic_AircraftTrack_DEFAULT NULL + +#define meshtastic_TAKPacketV2_FIELDLIST(X, a) \ +X(a, STATIC, SINGULAR, UENUM, cot_type_id, 1) \ +X(a, STATIC, SINGULAR, UENUM, how, 2) \ +X(a, STATIC, SINGULAR, STRING, callsign, 3) \ +X(a, STATIC, SINGULAR, UENUM, team, 4) \ +X(a, STATIC, SINGULAR, UENUM, role, 5) \ +X(a, STATIC, SINGULAR, SFIXED32, latitude_i, 6) \ +X(a, STATIC, SINGULAR, SFIXED32, longitude_i, 7) \ +X(a, STATIC, SINGULAR, SINT32, altitude, 8) \ +X(a, STATIC, SINGULAR, UINT32, speed, 9) \ +X(a, STATIC, SINGULAR, UINT32, course, 10) \ +X(a, STATIC, SINGULAR, UINT32, battery, 11) \ +X(a, STATIC, SINGULAR, UENUM, geo_src, 12) \ +X(a, STATIC, SINGULAR, UENUM, alt_src, 13) \ +X(a, STATIC, SINGULAR, STRING, uid, 14) \ +X(a, STATIC, SINGULAR, STRING, device_callsign, 15) \ +X(a, STATIC, SINGULAR, UINT32, stale_seconds, 16) \ +X(a, STATIC, SINGULAR, STRING, tak_version, 17) \ +X(a, STATIC, SINGULAR, STRING, tak_device, 18) \ +X(a, STATIC, SINGULAR, STRING, tak_platform, 19) \ +X(a, STATIC, SINGULAR, STRING, tak_os, 20) \ +X(a, STATIC, SINGULAR, STRING, endpoint, 21) \ +X(a, STATIC, SINGULAR, STRING, phone, 22) \ +X(a, STATIC, SINGULAR, STRING, cot_type_str, 23) \ +X(a, STATIC, ONEOF, BOOL, (payload_variant,pli,payload_variant.pli), 30) \ +X(a, STATIC, ONEOF, MESSAGE, (payload_variant,chat,payload_variant.chat), 31) \ +X(a, STATIC, ONEOF, MESSAGE, (payload_variant,aircraft,payload_variant.aircraft), 32) \ +X(a, STATIC, ONEOF, BYTES, (payload_variant,raw_detail,payload_variant.raw_detail), 33) +#define meshtastic_TAKPacketV2_CALLBACK NULL +#define meshtastic_TAKPacketV2_DEFAULT NULL +#define meshtastic_TAKPacketV2_payload_variant_chat_MSGTYPE meshtastic_GeoChat +#define meshtastic_TAKPacketV2_payload_variant_aircraft_MSGTYPE meshtastic_AircraftTrack + extern const pb_msgdesc_t meshtastic_TAKPacket_msg; extern const pb_msgdesc_t meshtastic_GeoChat_msg; extern const pb_msgdesc_t meshtastic_Group_msg; extern const pb_msgdesc_t meshtastic_Status_msg; extern const pb_msgdesc_t meshtastic_Contact_msg; extern const pb_msgdesc_t meshtastic_PLI_msg; +extern const pb_msgdesc_t meshtastic_AircraftTrack_msg; +extern const pb_msgdesc_t meshtastic_TAKPacketV2_msg; /* Defines for backwards compatibility with code written before nanopb-0.4.0 */ #define meshtastic_TAKPacket_fields &meshtastic_TAKPacket_msg @@ -269,14 +657,18 @@ extern const pb_msgdesc_t meshtastic_PLI_msg; #define meshtastic_Status_fields &meshtastic_Status_msg #define meshtastic_Contact_fields &meshtastic_Contact_msg #define meshtastic_PLI_fields &meshtastic_PLI_msg +#define meshtastic_AircraftTrack_fields &meshtastic_AircraftTrack_msg +#define meshtastic_TAKPacketV2_fields &meshtastic_TAKPacketV2_msg /* Maximum encoded size of messages (where known) */ -#define MESHTASTIC_MESHTASTIC_ATAK_PB_H_MAX_SIZE meshtastic_TAKPacket_size +#define MESHTASTIC_MESHTASTIC_ATAK_PB_H_MAX_SIZE meshtastic_TAKPacketV2_size +#define meshtastic_AircraftTrack_size 134 #define meshtastic_Contact_size 242 #define meshtastic_GeoChat_size 444 #define meshtastic_Group_size 4 #define meshtastic_PLI_size 31 #define meshtastic_Status_size 3 +#define meshtastic_TAKPacketV2_size 1027 #define meshtastic_TAKPacket_size 705 #ifdef __cplusplus diff --git a/src/mesh/generated/meshtastic/mesh.pb.h b/src/mesh/generated/meshtastic/mesh.pb.h index 477c3b31b..fc6931d73 100644 --- a/src/mesh/generated/meshtastic/mesh.pb.h +++ b/src/mesh/generated/meshtastic/mesh.pb.h @@ -308,6 +308,8 @@ typedef enum _meshtastic_HardwareModel { meshtastic_HardwareModel_TDISPLAY_S3_PRO = 126, /* Heltec Mesh Node T096 board features an nRF52840 CPU and a TFT screen. */ meshtastic_HardwareModel_HELTEC_MESH_NODE_T096 = 127, + /* Seeed studio T1000-E Pro tracker card. NRF52840 w/ LR2021 radio, GPS, button, buzzer, and sensors. */ + meshtastic_HardwareModel_TRACKER_T1000_E_PRO = 128, /* ------------------------------------------------------------------------------------------------------------------------------------------ Reserved ID For developing private Ports. These will show up in live traffic sparsely, so we can use a high number. Keep it within 8 bits. ------------------------------------------------------------------------------------------------------------------------------------------ */ diff --git a/src/mesh/generated/meshtastic/portnums.pb.h b/src/mesh/generated/meshtastic/portnums.pb.h index bd1fe48c4..a474e5b92 100644 --- a/src/mesh/generated/meshtastic/portnums.pb.h +++ b/src/mesh/generated/meshtastic/portnums.pb.h @@ -150,6 +150,10 @@ typedef enum _meshtastic_PortNum { arbitrary telemetry over meshtastic that is not covered by telemetry.proto ENCODING: CayenneLLP */ meshtastic_PortNum_CAYENNE_APP = 77, + /* ATAK Plugin V2 + Portnum for payloads from the official Meshtastic ATAK plugin using + TAKPacketV2 with zstd dictionary compression. */ + meshtastic_PortNum_ATAK_PLUGIN_V2 = 78, /* GroupAlarm integration Used for transporting GroupAlarm-related messages between Meshtastic nodes and companion applications/services. */ diff --git a/src/modules/ExternalNotificationModule.cpp b/src/modules/ExternalNotificationModule.cpp index 3addc4b3a..16ccdd744 100644 --- a/src/modules/ExternalNotificationModule.cpp +++ b/src/modules/ExternalNotificationModule.cpp @@ -203,6 +203,10 @@ void ExternalNotificationModule::setExternalState(uint8_t index, bool on) default: if (output > 0) digitalWrite(output, (moduleConfig.external_notification.active ? on : !on)); +#ifdef PCA_LED_NOTIFICATION + io.digitalWrite(PCA_LED_NOTIFICATION, on); + +#endif break; } diff --git a/src/modules/SerialModule.cpp b/src/modules/SerialModule.cpp index 7a969343e..20d4d7d8c 100644 --- a/src/modules/SerialModule.cpp +++ b/src/modules/SerialModule.cpp @@ -651,7 +651,7 @@ void SerialModule::processWXSerial() LOG_INFO("WS8X : %i %.1fg%.1f %.1fv %.1fv %.1fC rain: %.1f, %i sum", atoi(windDir), strtof(windVel, nullptr), strtof(windGust, nullptr), batVoltageF, capVoltageF, temperatureF, rain, rainSum); } - if (gotwind && !Throttle::isWithinTimespanMs(lastAveraged, averageIntervalMillis)) { + if (gotwind && !Throttle::isWithinTimespanMs(lastAveraged, averageIntervalMillis) && velCount > 0 && dirCount > 0) { // calculate averages and send to the mesh float velAvg = 1.0 * velSum / velCount; diff --git a/src/modules/Telemetry/EnvironmentTelemetry.cpp b/src/modules/Telemetry/EnvironmentTelemetry.cpp index b7b6e04a9..684d408a1 100644 --- a/src/modules/Telemetry/EnvironmentTelemetry.cpp +++ b/src/modules/Telemetry/EnvironmentTelemetry.cpp @@ -66,18 +66,10 @@ extern void drawCommonHeader(OLEDDisplay *display, int16_t x, int16_t y, const c #include "Sensor/MCP9808Sensor.h" #endif -#if __has_include() -#include "Sensor/SHT31Sensor.h" -#endif - #if __has_include() #include "Sensor/LPS22HBSensor.h" #endif -#if __has_include() -#include "Sensor/SHTC3Sensor.h" -#endif - #if __has_include("RAK12035_SoilMoisture.h") && defined(RAK_4631) && RAK_4631 == 1 #include "Sensor/RAK12035Sensor.h" #endif @@ -94,8 +86,8 @@ extern void drawCommonHeader(OLEDDisplay *display, int16_t x, int16_t y, const c #include "Sensor/OPT3001Sensor.h" #endif -#if __has_include() -#include "Sensor/SHT4XSensor.h" +#if __has_include() +#include "Sensor/SHTXXSensor.h" #endif #if __has_include() @@ -155,6 +147,15 @@ void EnvironmentTelemetryModule::i2cScanFinished(ScanI2C *i2cScanner) } LOG_INFO("Environment Telemetry adding I2C devices..."); + /* + Uncomment the preferences below if you want to use the module + without having to configure it from the PythonAPI or WebUI. + */ + + // moduleConfig.telemetry.environment_measurement_enabled = 1; + // moduleConfig.telemetry.environment_screen_enabled = 1; + // moduleConfig.telemetry.environment_update_interval = 15; + // order by priority of metrics/values (low top, high bottom) #if !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR @@ -202,15 +203,9 @@ void EnvironmentTelemetryModule::i2cScanFinished(ScanI2C *i2cScanner) #if __has_include() addSensor(i2cScanner, ScanI2C::DeviceType::MCP9808); #endif -#if __has_include() - addSensor(i2cScanner, ScanI2C::DeviceType::SHT31); -#endif #if __has_include() addSensor(i2cScanner, ScanI2C::DeviceType::LPS22HB); #endif -#if __has_include() - addSensor(i2cScanner, ScanI2C::DeviceType::SHTC3); -#endif #if __has_include("RAK12035_SoilMoisture.h") && defined(RAK_4631) && RAK_4631 == 1 addSensor(i2cScanner, ScanI2C::DeviceType::RAK12035); #endif @@ -223,13 +218,9 @@ void EnvironmentTelemetryModule::i2cScanFinished(ScanI2C *i2cScanner) #if __has_include() addSensor(i2cScanner, ScanI2C::DeviceType::OPT3001); #endif -#if __has_include() - addSensor(i2cScanner, ScanI2C::DeviceType::SHT4X); -#endif #if __has_include() addSensor(i2cScanner, ScanI2C::DeviceType::MLX90632); #endif - #if __has_include() addSensor(i2cScanner, ScanI2C::DeviceType::BMP_3XX); #endif @@ -245,7 +236,10 @@ void EnvironmentTelemetryModule::i2cScanFinished(ScanI2C *i2cScanner) #if __has_include() addSensor(i2cScanner, ScanI2C::DeviceType::BH1750); #endif - +#if __has_include() + // TODO Can we scan for multiple sensors connected on the same bus? + addSensor(i2cScanner, ScanI2C::DeviceType::SHTXX); +#endif #endif } @@ -260,14 +254,6 @@ int32_t EnvironmentTelemetryModule::runOnce() } uint32_t result = UINT32_MAX; - /* - Uncomment the preferences below if you want to use the module - without having to configure it from the PythonAPI or WebUI. - */ - - // moduleConfig.telemetry.environment_measurement_enabled = 1; - // moduleConfig.telemetry.environment_screen_enabled = 1; - // moduleConfig.telemetry.environment_update_interval = 15; if (!(moduleConfig.telemetry.environment_measurement_enabled || moduleConfig.telemetry.environment_screen_enabled || ENVIRONMENTAL_TELEMETRY_MODULE_ENABLE)) { diff --git a/src/modules/Telemetry/Sensor/SHT31Sensor.cpp b/src/modules/Telemetry/Sensor/SHT31Sensor.cpp deleted file mode 100644 index 67a36933d..000000000 --- a/src/modules/Telemetry/Sensor/SHT31Sensor.cpp +++ /dev/null @@ -1,31 +0,0 @@ -#include "configuration.h" - -#if !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR && __has_include() - -#include "../mesh/generated/meshtastic/telemetry.pb.h" -#include "SHT31Sensor.h" -#include "TelemetrySensor.h" -#include - -SHT31Sensor::SHT31Sensor() : TelemetrySensor(meshtastic_TelemetrySensorType_SHT31, "SHT31") {} - -bool SHT31Sensor::initDevice(TwoWire *bus, ScanI2C::FoundDevice *dev) -{ - LOG_INFO("Init sensor: %s", sensorName); - sht31 = Adafruit_SHT31(bus); - status = sht31.begin(dev->address.address); - initI2CSensor(); - return status; -} - -bool SHT31Sensor::getMetrics(meshtastic_Telemetry *measurement) -{ - measurement->variant.environment_metrics.has_temperature = true; - measurement->variant.environment_metrics.has_relative_humidity = true; - measurement->variant.environment_metrics.temperature = sht31.readTemperature(); - measurement->variant.environment_metrics.relative_humidity = sht31.readHumidity(); - - return true; -} - -#endif \ No newline at end of file diff --git a/src/modules/Telemetry/Sensor/SHT31Sensor.h b/src/modules/Telemetry/Sensor/SHT31Sensor.h deleted file mode 100644 index ecb7d63a6..000000000 --- a/src/modules/Telemetry/Sensor/SHT31Sensor.h +++ /dev/null @@ -1,20 +0,0 @@ -#include "configuration.h" - -#if !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR && __has_include() - -#include "../mesh/generated/meshtastic/telemetry.pb.h" -#include "TelemetrySensor.h" -#include - -class SHT31Sensor : public TelemetrySensor -{ - private: - Adafruit_SHT31 sht31; - - public: - SHT31Sensor(); - virtual bool getMetrics(meshtastic_Telemetry *measurement) override; - virtual bool initDevice(TwoWire *bus, ScanI2C::FoundDevice *dev) override; -}; - -#endif \ No newline at end of file diff --git a/src/modules/Telemetry/Sensor/SHT4XSensor.cpp b/src/modules/Telemetry/Sensor/SHT4XSensor.cpp deleted file mode 100644 index b11795d97..000000000 --- a/src/modules/Telemetry/Sensor/SHT4XSensor.cpp +++ /dev/null @@ -1,48 +0,0 @@ -#include "configuration.h" - -#if !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR && __has_include() - -#include "../mesh/generated/meshtastic/telemetry.pb.h" -#include "SHT4XSensor.h" -#include "TelemetrySensor.h" -#include - -SHT4XSensor::SHT4XSensor() : TelemetrySensor(meshtastic_TelemetrySensorType_SHT4X, "SHT4X") {} - -bool SHT4XSensor::initDevice(TwoWire *bus, ScanI2C::FoundDevice *dev) -{ - LOG_INFO("Init sensor: %s", sensorName); - - uint32_t serialNumber = 0; - - status = sht4x.begin(bus); - if (!status) { - return status; - } - - serialNumber = sht4x.readSerial(); - if (serialNumber != 0) { - LOG_DEBUG("serialNumber : %x", serialNumber); - status = 1; - } else { - LOG_DEBUG("Error trying to execute readSerial(): "); - status = 0; - } - - initI2CSensor(); - return status; -} - -bool SHT4XSensor::getMetrics(meshtastic_Telemetry *measurement) -{ - measurement->variant.environment_metrics.has_temperature = true; - measurement->variant.environment_metrics.has_relative_humidity = true; - - sensors_event_t humidity, temp; - sht4x.getEvent(&humidity, &temp); - measurement->variant.environment_metrics.temperature = temp.temperature; - measurement->variant.environment_metrics.relative_humidity = humidity.relative_humidity; - return true; -} - -#endif \ No newline at end of file diff --git a/src/modules/Telemetry/Sensor/SHT4XSensor.h b/src/modules/Telemetry/Sensor/SHT4XSensor.h deleted file mode 100644 index 7311d2366..000000000 --- a/src/modules/Telemetry/Sensor/SHT4XSensor.h +++ /dev/null @@ -1,20 +0,0 @@ -#include "configuration.h" - -#if !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR && __has_include() - -#include "../mesh/generated/meshtastic/telemetry.pb.h" -#include "TelemetrySensor.h" -#include - -class SHT4XSensor : public TelemetrySensor -{ - private: - Adafruit_SHT4x sht4x = Adafruit_SHT4x(); - - public: - SHT4XSensor(); - virtual bool getMetrics(meshtastic_Telemetry *measurement) override; - virtual bool initDevice(TwoWire *bus, ScanI2C::FoundDevice *dev) override; -}; - -#endif \ No newline at end of file diff --git a/src/modules/Telemetry/Sensor/SHTC3Sensor.cpp b/src/modules/Telemetry/Sensor/SHTC3Sensor.cpp deleted file mode 100644 index fdab0b266..000000000 --- a/src/modules/Telemetry/Sensor/SHTC3Sensor.cpp +++ /dev/null @@ -1,35 +0,0 @@ -#include "configuration.h" - -#if !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR && __has_include() - -#include "../mesh/generated/meshtastic/telemetry.pb.h" -#include "SHTC3Sensor.h" -#include "TelemetrySensor.h" -#include - -SHTC3Sensor::SHTC3Sensor() : TelemetrySensor(meshtastic_TelemetrySensorType_SHTC3, "SHTC3") {} - -bool SHTC3Sensor::initDevice(TwoWire *bus, ScanI2C::FoundDevice *dev) -{ - LOG_INFO("Init sensor: %s", sensorName); - status = shtc3.begin(bus); - - initI2CSensor(); - return status; -} - -bool SHTC3Sensor::getMetrics(meshtastic_Telemetry *measurement) -{ - measurement->variant.environment_metrics.has_temperature = true; - measurement->variant.environment_metrics.has_relative_humidity = true; - - sensors_event_t humidity, temp; - shtc3.getEvent(&humidity, &temp); - - measurement->variant.environment_metrics.temperature = temp.temperature; - measurement->variant.environment_metrics.relative_humidity = humidity.relative_humidity; - - return true; -} - -#endif \ No newline at end of file diff --git a/src/modules/Telemetry/Sensor/SHTC3Sensor.h b/src/modules/Telemetry/Sensor/SHTC3Sensor.h deleted file mode 100644 index 51cee18f7..000000000 --- a/src/modules/Telemetry/Sensor/SHTC3Sensor.h +++ /dev/null @@ -1,20 +0,0 @@ -#include "configuration.h" - -#if !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR && __has_include() - -#include "../mesh/generated/meshtastic/telemetry.pb.h" -#include "TelemetrySensor.h" -#include - -class SHTC3Sensor : public TelemetrySensor -{ - private: - Adafruit_SHTC3 shtc3 = Adafruit_SHTC3(); - - public: - SHTC3Sensor(); - virtual bool getMetrics(meshtastic_Telemetry *measurement) override; - virtual bool initDevice(TwoWire *bus, ScanI2C::FoundDevice *dev) override; -}; - -#endif \ No newline at end of file diff --git a/src/modules/Telemetry/Sensor/SHTXXSensor.cpp b/src/modules/Telemetry/Sensor/SHTXXSensor.cpp new file mode 100644 index 000000000..92cac7f77 --- /dev/null +++ b/src/modules/Telemetry/Sensor/SHTXXSensor.cpp @@ -0,0 +1,145 @@ +#include "configuration.h" + +#if !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR && __has_include() + +#include "../mesh/generated/meshtastic/telemetry.pb.h" +#include "SHTXXSensor.h" +#include "TelemetrySensor.h" +#include + +SHTXXSensor::SHTXXSensor() : TelemetrySensor(meshtastic_TelemetrySensorType_SHTXX, "SHTXX") {} + +void SHTXXSensor::getSensorVariant(SHTSensor::SHTSensorType sensorType) +{ + switch (sensorType) { + case SHTSensor::SHTSensorType::SHT2X: + sensorVariant = "SHT2x"; + break; + + case SHTSensor::SHTSensorType::SHT3X: + case SHTSensor::SHTSensorType::SHT85: + sensorVariant = "SHT3x/SHT85"; + break; + + case SHTSensor::SHTSensorType::SHT3X_ALT: + sensorVariant = "SHT3x"; + break; + + case SHTSensor::SHTSensorType::SHTW1: + case SHTSensor::SHTSensorType::SHTW2: + case SHTSensor::SHTSensorType::SHTC1: + case SHTSensor::SHTSensorType::SHTC3: + sensorVariant = "SHTC1/SHTC3/SHTW1/SHTW2"; + break; + + case SHTSensor::SHTSensorType::SHT4X: + sensorVariant = "SHT4x"; + break; + + default: + sensorVariant = "Unknown"; + break; + } +} + +bool SHTXXSensor::initDevice(TwoWire *bus, ScanI2C::FoundDevice *dev) +{ + LOG_INFO("Init sensor: %s", sensorName); + + _bus = bus; + _address = dev->address.address; + + if (sht.init(*_bus)) { + LOG_INFO("%s: init(): success", sensorName); + getSensorVariant(sht.mSensorType); + LOG_INFO("%s Sensor detected: %s on 0x%x", sensorName, sensorVariant, _address); + status = 1; + } else { + LOG_ERROR("%s: init(): failed", sensorName); + } + + initI2CSensor(); + return status; +} + +/** + * Accuracy setting of measurement. + * Not all sensors support changing the sampling accuracy (only SHT3X and SHT4X) + * SHTAccuracy: + * - SHT_ACCURACY_HIGH: Highest repeatability at the cost of slower measurement + * - SHT_ACCURACY_MEDIUM: Balanced repeatability and speed of measurement + * - SHT_ACCURACY_LOW: Fastest measurement but lowest repeatability + */ +bool SHTXXSensor::setAccuracy(SHTSensor::SHTAccuracy newAccuracy) +{ + // Only SHT3X-family (including alternates) and SHT4X support changing accuracy + if (sht.mSensorType != SHTSensor::SHTSensorType::SHT3X && sht.mSensorType != SHTSensor::SHTSensorType::SHT3X_ALT && + sht.mSensorType != SHTSensor::SHTSensorType::SHT85 && sht.mSensorType != SHTSensor::SHTSensorType::SHT4X) { + LOG_WARN("%s doesn't support accuracy setting", sensorVariant); + return false; + } + LOG_INFO("%s: setting new accuracy setting", sensorVariant); + accuracy = newAccuracy; + return sht.setAccuracy(accuracy); +} + +bool SHTXXSensor::getMetrics(meshtastic_Telemetry *measurement) +{ + if (sht.readSample()) { + measurement->variant.environment_metrics.has_temperature = true; + measurement->variant.environment_metrics.has_relative_humidity = true; + measurement->variant.environment_metrics.temperature = sht.getTemperature(); + measurement->variant.environment_metrics.relative_humidity = sht.getHumidity(); + + LOG_INFO("%s (%s): Got: temp:%fdegC, hum:%f%%rh", sensorName, sensorVariant, + measurement->variant.environment_metrics.temperature, + measurement->variant.environment_metrics.relative_humidity); + + return true; + } else { + LOG_ERROR("%s (%s): read sample failed", sensorName, sensorVariant); + return false; + } +} + +AdminMessageHandleResult SHTXXSensor::handleAdminMessage(const meshtastic_MeshPacket &mp, meshtastic_AdminMessage *request, + meshtastic_AdminMessage *response) +{ + AdminMessageHandleResult result; + result = AdminMessageHandleResult::NOT_HANDLED; + + switch (request->which_payload_variant) { + case meshtastic_AdminMessage_sensor_config_tag: + if (!request->sensor_config.has_shtxx_config) { + result = AdminMessageHandleResult::NOT_HANDLED; + break; + } + + // Check for sensor accuracy setting + if (request->sensor_config.shtxx_config.has_set_accuracy) { + SHTSensor::SHTAccuracy newAccuracy; + if (request->sensor_config.shtxx_config.set_accuracy == 0) { + newAccuracy = SHTSensor::SHT_ACCURACY_LOW; + } else if (request->sensor_config.shtxx_config.set_accuracy == 1) { + newAccuracy = SHTSensor::SHT_ACCURACY_MEDIUM; + } else if (request->sensor_config.shtxx_config.set_accuracy == 2) { + newAccuracy = SHTSensor::SHT_ACCURACY_HIGH; + } else { + LOG_ERROR("%s: incorrect accuracy setting", sensorName); + result = AdminMessageHandleResult::HANDLED; + break; + } + this->setAccuracy(newAccuracy); + } + + result = AdminMessageHandleResult::HANDLED; + break; + + default: + result = AdminMessageHandleResult::NOT_HANDLED; + } + + return result; +} + +#endif \ No newline at end of file diff --git a/src/modules/Telemetry/Sensor/SHTXXSensor.h b/src/modules/Telemetry/Sensor/SHTXXSensor.h new file mode 100644 index 000000000..e354e113f --- /dev/null +++ b/src/modules/Telemetry/Sensor/SHTXXSensor.h @@ -0,0 +1,29 @@ +#include "configuration.h" + +#if !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR && __has_include() + +#include "../mesh/generated/meshtastic/telemetry.pb.h" +#include "TelemetrySensor.h" +#include + +class SHTXXSensor : public TelemetrySensor +{ + private: + SHTSensor sht; + TwoWire *_bus{}; + uint8_t _address{}; + SHTSensor::SHTAccuracy accuracy{}; + bool setAccuracy(SHTSensor::SHTAccuracy newAccuracy); + + public: + SHTXXSensor(); + virtual bool getMetrics(meshtastic_Telemetry *measurement) override; + virtual bool initDevice(TwoWire *bus, ScanI2C::FoundDevice *dev) override; + void getSensorVariant(SHTSensor::SHTSensorType); + const char *sensorVariant{}; + + AdminMessageHandleResult handleAdminMessage(const meshtastic_MeshPacket &mp, meshtastic_AdminMessage *request, + meshtastic_AdminMessage *response) override; +}; + +#endif \ No newline at end of file diff --git a/src/modules/TrafficManagementModule.cpp b/src/modules/TrafficManagementModule.cpp index 6936ef682..1ecb68c4b 100644 --- a/src/modules/TrafficManagementModule.cpp +++ b/src/modules/TrafficManagementModule.cpp @@ -7,6 +7,7 @@ #include "NodeDB.h" #include "Router.h" #include "TypeConversions.h" +#include "airtime.h" #include "concurrency/LockGuard.h" #include "configuration.h" #include "mesh-pb-constants.h" @@ -1001,7 +1002,11 @@ void TrafficManagementModule::alterReceived(meshtastic_MeshPacket &mp) const auto &cfg = moduleConfig.traffic_management; const bool isTelemetry = mp.decoded.portnum == meshtastic_PortNum_TELEMETRY_APP; const bool isPosition = mp.decoded.portnum == meshtastic_PortNum_POSITION_APP; - const bool shouldExhaust = (isTelemetry && cfg.exhaust_hop_telemetry) || (isPosition && cfg.exhaust_hop_position); + // Only exhaust telemetry hops when channel is actually congested, mirroring the same + // airtime checks that gate self-generated telemetry in the telemetry modules. + const bool channelBusy = airTime && (!airTime->isTxAllowedChannelUtil(true) || !airTime->isTxAllowedAirUtil()); + const bool shouldExhaust = + ((channelBusy && isTelemetry && cfg.exhaust_hop_telemetry) || (isPosition && cfg.exhaust_hop_position)); if (!shouldExhaust || !isBroadcast(mp.to)) return; diff --git a/src/mqtt/MQTT.cpp b/src/mqtt/MQTT.cpp index c916f86c4..15762c93d 100644 --- a/src/mqtt/MQTT.cpp +++ b/src/mqtt/MQTT.cpp @@ -321,8 +321,8 @@ bool connectPubSub(const PubSubConfig &config, PubSubClient &pubSub, Client &cli pubSub.setClient(client); pubSub.setServer(config.serverAddr.c_str(), config.serverPort); - LOG_INFO("Connecting directly to MQTT server %s, port: %d, username: %s, password: %s", config.serverAddr.c_str(), - config.serverPort, config.mqttUsername, config.mqttPassword); + LOG_INFO("Connecting directly to MQTT server %s, port: %d, username: %s, password: ***", config.serverAddr.c_str(), + config.serverPort, config.mqttUsername); // Generate node ID from nodenum for client identification std::string nodeId = nodeDB->getNodeId(); diff --git a/src/platform/esp32/main-esp32.cpp b/src/platform/esp32/main-esp32.cpp index d1b2031fe..2f39c11f5 100644 --- a/src/platform/esp32/main-esp32.cpp +++ b/src/platform/esp32/main-esp32.cpp @@ -239,7 +239,9 @@ void cpuDeepSleep(uint32_t msecToWake) #if SOC_RTCIO_HOLD_SUPPORTED && SOC_PM_SUPPORT_EXT_WAKEUP uint64_t gpioMask = (1ULL << (config.device.button_gpio ? config.device.button_gpio : BUTTON_PIN)); #endif - +#ifdef ALT_BUTTON_WAKE + gpioMask |= (1ULL << BUTTON_PIN_ALT); +#endif #ifdef BUTTON_NEED_PULLUP gpio_pullup_en((gpio_num_t)BUTTON_PIN); #endif diff --git a/src/platform/extra_variants/t_lora_pager/variant.cpp b/src/platform/extra_variants/t_lora_pager/variant.cpp index ea5773d30..19c8881ca 100644 --- a/src/platform/extra_variants/t_lora_pager/variant.cpp +++ b/src/platform/extra_variants/t_lora_pager/variant.cpp @@ -23,5 +23,6 @@ void lateInitVariant() cfg.i2s.bits = BIT_LENGTH_16BITS; cfg.i2s.rate = RATE_44K; board.begin(cfg); + board.setVolume(75); // 75% volume } #endif \ No newline at end of file diff --git a/src/platform/nrf52/main-nrf52.cpp b/src/platform/nrf52/main-nrf52.cpp index 73780b6eb..5cf3a4465 100644 --- a/src/platform/nrf52/main-nrf52.cpp +++ b/src/platform/nrf52/main-nrf52.cpp @@ -17,6 +17,7 @@ #include #include // #include +#include "HardwareRNG.h" #include "NodeDB.h" #include "PowerMon.h" #include "error.h" @@ -398,15 +399,14 @@ void nrf52Setup() #endif // Init random seed - union seedParts { - uint32_t seed32; - uint8_t seed8[4]; - } seed; - nRFCrypto.begin(); - nRFCrypto.Random.generate(seed.seed8, sizeof(seed.seed8)); - LOG_DEBUG("Set random seed %u", seed.seed32); - randomSeed(seed.seed32); - nRFCrypto.end(); + uint32_t seed = 0; + if (!HardwareRNG::seed(seed)) { + LOG_WARN("Hardware RNG seed unavailable, using PRNG fallback"); + // Use a hardware timer value as a fallback seed for better entropy + seed = micros(); + } + LOG_DEBUG("Set random seed %u", seed); + randomSeed(seed); // Set up nrfx watchdog. Do not enable the watchdog yet (we do that // the first time through the main loop), so that other threads can diff --git a/src/platform/portduino/PortduinoGlue.cpp b/src/platform/portduino/PortduinoGlue.cpp index 4bbdbee7a..9e0a1b2a5 100644 --- a/src/platform/portduino/PortduinoGlue.cpp +++ b/src/platform/portduino/PortduinoGlue.cpp @@ -1,4 +1,5 @@ #include "CryptoEngine.h" +#include "HardwareRNG.h" #include "PortduinoGPIO.h" #include "SPIChip.h" #include "mesh/RF95Interface.h" @@ -233,7 +234,9 @@ void portduinoSetup() std::cout << "Running in simulated mode." << std::endl; portduino_config.MaxNodes = 200; // Default to 200 nodes // Set the random seed equal to TCPPort to have a different seed per instance - randomSeed(TCPPort); + uint32_t seed = TCPPort; + HardwareRNG::seed(seed); + randomSeed(seed); return; } @@ -512,7 +515,9 @@ void portduinoSetup() #endif printf("MAC ADDRESS: %02X:%02X:%02X:%02X:%02X:%02X\n", dmac[0], dmac[1], dmac[2], dmac[3], dmac[4], dmac[5]); // Rather important to set this, if not running simulated. - randomSeed(time(NULL)); + uint32_t seed = static_cast(time(NULL)); + HardwareRNG::seed(seed); + randomSeed(seed); std::string defaultGpioChipName = gpioChipName + std::to_string(portduino_config.lora_default_gpiochip); diff --git a/src/platform/rp2xx0/main-rp2xx0.cpp b/src/platform/rp2xx0/main-rp2xx0.cpp index 6c73e385a..e59b0a9cd 100644 --- a/src/platform/rp2xx0/main-rp2xx0.cpp +++ b/src/platform/rp2xx0/main-rp2xx0.cpp @@ -1,3 +1,4 @@ +#include "HardwareRNG.h" #include "configuration.h" #include "hardware/xosc.h" #include @@ -98,10 +99,12 @@ void getMacAddr(uint8_t *dmac) void rp2040Setup() { - /* Sets a random seed to make sure we get different random numbers on each boot. - Taken from CPU cycle counter and ROSC oscillator, so should be pretty random. - */ - randomSeed(rp2040.hwrand32()); + /* Sets a random seed to make sure we get different random numbers on each boot. */ + uint32_t seed = 0; + if (!HardwareRNG::seed(seed)) { + seed = rp2040.hwrand32(); + } + randomSeed(seed); #ifdef RP2040_SLOW_CLOCK uint f_pll_sys = frequency_count_khz(CLOCKS_FC0_SRC_VALUE_PLL_SYS_CLKSRC_PRIMARY); diff --git a/src/platform/stm32wl/hardfault_handler.s b/src/platform/stm32wl/hardfault_handler.s new file mode 100644 index 000000000..ab76096fa --- /dev/null +++ b/src/platform/stm32wl/hardfault_handler.s @@ -0,0 +1,11 @@ +.globl HardFault_Handler +.syntax unified +.thumb + +.type HardFault_Handler, %function +HardFault_Handler: +tst lr, #4 +ite eq +mrseq r0, msp +mrsne r0, psp +b HardFault_Handler_C \ No newline at end of file diff --git a/src/platform/stm32wl/main-stm32wl.cpp b/src/platform/stm32wl/main-stm32wl.cpp index e841f8f29..93080f840 100644 --- a/src/platform/stm32wl/main-stm32wl.cpp +++ b/src/platform/stm32wl/main-stm32wl.cpp @@ -1,5 +1,6 @@ #include "RTC.h" #include "configuration.h" +#include #include #include @@ -53,4 +54,99 @@ extern "C" void __wrap__tzset_unlocked_r(struct _reent *reent_ptr) { return; } -#endif \ No newline at end of file +#endif + +// Taken from https://interrupt.memfault.com/blog/cortex-m-hardfault-debug +typedef struct __attribute__((packed)) ContextStateFrame { + uint32_t r0; + uint32_t r1; + uint32_t r2; + uint32_t r3; + uint32_t r12; + uint32_t lr; + uint32_t return_address; + uint32_t xpsr; +} sContextStateFrame; + +// NOTE: If you are using CMSIS, the registers can also be +// accessed through CoreDebug->DHCSR & CoreDebug_DHCSR_C_DEBUGEN_Msk +#define HALT_IF_DEBUGGING() \ + do { \ + if ((*(volatile uint32_t *)0xE000EDF0) & (1 << 0)) { \ + __asm("bkpt 1"); \ + } \ + } while (0) + +static char hardfault_message_buffer[256]; + +// printf directly using srcwrapper's debug UART function. +static void debug_printf(const char *format, ...) +{ + va_list args; + va_start(args, format); + int length = vsnprintf(hardfault_message_buffer, sizeof(hardfault_message_buffer), format, args); + va_end(args); + + if (length < 0) + return; + uart_debug_write((uint8_t *)hardfault_message_buffer, min((unsigned int)length, sizeof(hardfault_message_buffer) - 1)); +} + +// N picked by guessing +#define DOT_TIME 1200000 +static void dot() +{ + digitalWrite(LED_POWER, LED_STATE_ON); + for (volatile int i = 0; i < DOT_TIME; i++) { /* busy wait */ + } + digitalWrite(LED_POWER, LED_STATE_OFF); + for (volatile int i = 0; i < DOT_TIME; i++) { /* busy wait */ + } +} + +static void dash() +{ + digitalWrite(LED_POWER, LED_STATE_ON); + for (volatile int i = 0; i < (DOT_TIME * 3); i++) { /* busy wait */ + } + digitalWrite(LED_POWER, LED_STATE_OFF); + for (volatile int i = 0; i < DOT_TIME; i++) { /* busy wait */ + } +} + +static void space() +{ + for (volatile int i = 0; i < (DOT_TIME * 3); i++) { /* busy wait */ + } +} + +// Disable optimizations for this function so "frame" argument +// does not get optimized away +extern "C" __attribute__((optimize("O0"))) void HardFault_Handler_C(sContextStateFrame *frame) +{ + debug_printf("HardFault!\r\n"); + debug_printf("r0: %08x\r\n", frame->r0); + debug_printf("r1: %08x\r\n", frame->r1); + debug_printf("r2: %08x\r\n", frame->r2); + debug_printf("r3: %08x\r\n", frame->r3); + debug_printf("r12: %08x\r\n", frame->r12); + debug_printf("lr: %08x\r\n", frame->lr); + debug_printf("pc[return address]: %08x\r\n", frame->return_address); + debug_printf("xpsr: %08x\r\n", frame->xpsr); + + HALT_IF_DEBUGGING(); + + // blink SOS forever + while (1) { + dot(); + dot(); + dot(); + dash(); + dash(); + dash(); + dot(); + dot(); + dot(); + space(); + } +} \ No newline at end of file diff --git a/test/test_radio/test_main.cpp b/test/test_radio/test_main.cpp index 49eaabe5b..a7d3d32d2 100644 --- a/test/test_radio/test_main.cpp +++ b/test/test_radio/test_main.cpp @@ -14,6 +14,23 @@ class MockMeshService : public MeshService static MockMeshService *mockMeshService; +// Test shim to expose protected radio parameters set by applyModemConfig() +class TestableRadioInterface : public RadioInterface +{ + public: + TestableRadioInterface() : RadioInterface() {} + uint8_t getCr() const { return cr; } + uint8_t getSf() const { return sf; } + float getBw() const { return bw; } + + // Override reconfigure to call the base which invokes applyModemConfig() + bool reconfigure() override { return RadioInterface::reconfigure(); } + + // Stubs for pure virtual methods required by RadioInterface + uint32_t getPacketTime(uint32_t, bool) override { return 0; } + ErrorCode send(meshtastic_MeshPacket *p) override { return ERRNO_OK; } +}; + static void test_bwCodeToKHz_specialMappings() { TEST_ASSERT_FLOAT_WITHIN(0.0001f, 31.25f, bwCodeToKHz(31)); @@ -100,13 +117,87 @@ static void test_clampConfigLora_validPresetUnchanged() TEST_ASSERT_EQUAL(meshtastic_Config_LoRaConfig_ModemPreset_MEDIUM_FAST, cfg.modem_preset); } +// ----------------------------------------------------------------------- +// applyModemConfig() coding rate tests (via reconfigure) +// ----------------------------------------------------------------------- + +static TestableRadioInterface *testRadio; + +// After fresh flash: coding_rate=0, use_preset=true, modem_preset=LONG_FAST +// CR should come from the preset (5 for LONG_FAST), not from the zero default. +static void test_applyModemConfig_freshFlashCodingRateNotZero() +{ + config.lora = meshtastic_Config_LoRaConfig_init_zero; + config.lora.region = meshtastic_Config_LoRaConfig_RegionCode_US; + config.lora.use_preset = true; + config.lora.modem_preset = meshtastic_Config_LoRaConfig_ModemPreset_LONG_FAST; + // coding_rate is 0 (default after init_zero, same as fresh flash) + + testRadio->reconfigure(); + + // LONG_FAST preset has cr=5; must never be 0 + TEST_ASSERT_EQUAL_UINT8(5, testRadio->getCr()); + TEST_ASSERT_EQUAL_UINT8(11, testRadio->getSf()); + TEST_ASSERT_FLOAT_WITHIN(0.01f, 250.0f, testRadio->getBw()); +} + +// When coding_rate matches the preset exactly, should still use the preset value +static void test_applyModemConfig_codingRateMatchesPreset() +{ + config.lora = meshtastic_Config_LoRaConfig_init_zero; + config.lora.region = meshtastic_Config_LoRaConfig_RegionCode_US; + config.lora.use_preset = true; + config.lora.modem_preset = meshtastic_Config_LoRaConfig_ModemPreset_LONG_SLOW; + config.lora.coding_rate = 8; // LONG_SLOW default is cr=8 + + testRadio->reconfigure(); + + TEST_ASSERT_EQUAL_UINT8(8, testRadio->getCr()); +} + +// Custom CR higher than preset should be used +static void test_applyModemConfig_customCodingRateHigherThanPreset() +{ + config.lora = meshtastic_Config_LoRaConfig_init_zero; + config.lora.region = meshtastic_Config_LoRaConfig_RegionCode_US; + config.lora.use_preset = true; + config.lora.modem_preset = meshtastic_Config_LoRaConfig_ModemPreset_LONG_FAST; + config.lora.coding_rate = 7; // LONG_FAST preset has cr=5, 7 > 5 + + testRadio->reconfigure(); + + TEST_ASSERT_EQUAL_UINT8(7, testRadio->getCr()); +} + +// Custom CR lower than preset: preset wins (higher is more robust) +static void test_applyModemConfig_customCodingRateLowerThanPreset() +{ + config.lora = meshtastic_Config_LoRaConfig_init_zero; + config.lora.region = meshtastic_Config_LoRaConfig_RegionCode_US; + config.lora.use_preset = true; + config.lora.modem_preset = meshtastic_Config_LoRaConfig_ModemPreset_LONG_SLOW; + config.lora.coding_rate = 5; // LONG_SLOW preset has cr=8, 5 < 8 + + testRadio->reconfigure(); + + TEST_ASSERT_EQUAL_UINT8(8, testRadio->getCr()); +} + void setUp(void) { mockMeshService = new MockMeshService(); service = mockMeshService; + + // RadioInterface computes slotTimeMsec during construction and expects myRegion to be valid. + config.lora.region = meshtastic_Config_LoRaConfig_RegionCode_US; + initRegion(); + + testRadio = new TestableRadioInterface(); } void tearDown(void) { + delete testRadio; + testRadio = nullptr; service = nullptr; delete mockMeshService; mockMeshService = nullptr; @@ -128,6 +219,10 @@ void setup() RUN_TEST(test_validateConfigLora_rejectsInvalidPresetForRegion); RUN_TEST(test_clampConfigLora_invalidPresetClampedToDefault); RUN_TEST(test_clampConfigLora_validPresetUnchanged); + RUN_TEST(test_applyModemConfig_freshFlashCodingRateNotZero); + RUN_TEST(test_applyModemConfig_codingRateMatchesPreset); + RUN_TEST(test_applyModemConfig_customCodingRateHigherThanPreset); + RUN_TEST(test_applyModemConfig_customCodingRateLowerThanPreset); exit(UNITY_END()); } diff --git a/variants/esp32/betafpv_2400_tx_micro/platformio.ini b/variants/esp32/betafpv_2400_tx_micro/platformio.ini index 068d71011..c2e89b333 100644 --- a/variants/esp32/betafpv_2400_tx_micro/platformio.ini +++ b/variants/esp32/betafpv_2400_tx_micro/platformio.ini @@ -13,7 +13,3 @@ board_build.f_cpu = 240000000L upload_protocol = esptool ;upload_port = /dev/ttyUSB0 upload_speed = 460800 -lib_deps = - ${esp32_base.lib_deps} - # renovate: datasource=custom.pio depName=NeoPixel packageName=adafruit/library/Adafruit NeoPixel - adafruit/Adafruit NeoPixel@1.15.4 diff --git a/variants/esp32/esp32-common.ini b/variants/esp32/esp32-common.ini index 36fde673e..e406f963e 100644 --- a/variants/esp32/esp32-common.ini +++ b/variants/esp32/esp32-common.ini @@ -5,7 +5,7 @@ custom_esp32_kind = custom_mtjson_part = platform = # TODO renovate - https://github.com/pioarduino/platform-espressif32/releases/download/55.03.37/platform-espressif32.zip + https://github.com/pioarduino/platform-espressif32/releases/download/55.03.38/platform-espressif32.zip ; https://github.com/pioarduino/platform-espressif32.git#develop extra_scripts = @@ -36,7 +36,6 @@ build_flags = -Wall -Wextra -Isrc/platform/esp32 - -include mbedtls/error.h -std=gnu++17 -DLOG_LOCAL_LEVEL=ESP_LOG_DEBUG -DCORE_DEBUG_LEVEL=ARDUHAL_LOG_LEVEL_DEBUG @@ -58,8 +57,8 @@ lib_deps = ${environmental_base.lib_deps} ${environmental_extra.lib_deps} ${radiolib_base.lib_deps} - # TODO renovate - https://github.com/meshtastic/esp32_https_server/archive/e42e0bbca3eaa59672bfb42cda8e53a6f9a2266e.zip + # renovate: datasource=git-refs depName=meshtastic-esp32_https_server packageName=https://github.com/meshtastic/esp32_https_server gitBranch=master + https://github.com/meshtastic/esp32_https_server/archive/0c71f380390ad483ff134ad938e07f6cf1226c5b.zip # renovate: datasource=custom.pio depName=NimBLE-Arduino packageName=h2zero/library/NimBLE-Arduino h2zero/NimBLE-Arduino@1.4.3 # TODO renovate diff --git a/variants/esp32/nano-g1-explorer/platformio.ini b/variants/esp32/nano-g1-explorer/platformio.ini index 16ecb99cc..b27ebf28e 100644 --- a/variants/esp32/nano-g1-explorer/platformio.ini +++ b/variants/esp32/nano-g1-explorer/platformio.ini @@ -9,7 +9,7 @@ custom_meshtastic_display_name = Nano G1 Explorer custom_meshtastic_tags = B&Q extends = esp32_base -board = ttgo-t-beam +board = ttgo-tbeam build_flags = ${esp32_base.build_flags} -D NANO_G1_EXPLORER diff --git a/variants/esp32/nano-g1/platformio.ini b/variants/esp32/nano-g1/platformio.ini index 724e008c7..b2e392dbd 100644 --- a/variants/esp32/nano-g1/platformio.ini +++ b/variants/esp32/nano-g1/platformio.ini @@ -9,7 +9,7 @@ custom_meshtastic_display_name = Nano G1 custom_meshtastic_tags = B&Q extends = esp32_base -board = ttgo-t-beam +board = ttgo-tbeam build_flags = ${esp32_base.build_flags} -D NANO_G1 diff --git a/variants/esp32/station-g1/platformio.ini b/variants/esp32/station-g1/platformio.ini index b1f3e15f3..5a7f33485 100644 --- a/variants/esp32/station-g1/platformio.ini +++ b/variants/esp32/station-g1/platformio.ini @@ -9,10 +9,7 @@ custom_meshtastic_display_name = Station G1 custom_meshtastic_tags = B&Q extends = esp32_base -board = ttgo-t-beam -build_unflags = - ${esp32_common.build_unflags} - -DBOARD_HAS_PSRAM +board = ttgo-tbeam build_flags = ${esp32_base.build_flags} -D STATION_G1 diff --git a/variants/esp32/tbeam/platformio.ini b/variants/esp32/tbeam/platformio.ini index 26c8e9cd3..c9e6cce1f 100644 --- a/variants/esp32/tbeam/platformio.ini +++ b/variants/esp32/tbeam/platformio.ini @@ -10,14 +10,12 @@ custom_meshtastic_images = tbeam.svg custom_meshtastic_tags = LilyGo extends = esp32_base -board = ttgo-t-beam +board = ttgo-tbeam board_check = true build_flags = ${esp32_base.build_flags} -D TBEAM_V10 -I variants/esp32/tbeam - -DBOARD_HAS_PSRAM - -mfix-esp32-psram-cache-issue -ULED_BUILTIN upload_speed = 921600 diff --git a/variants/esp32/tbeam_v07/platformio.ini b/variants/esp32/tbeam_v07/platformio.ini index e2763fdec..1809ba56c 100644 --- a/variants/esp32/tbeam_v07/platformio.ini +++ b/variants/esp32/tbeam_v07/platformio.ini @@ -9,7 +9,7 @@ custom_meshtastic_tags = LilyGo board_level = extra extends = esp32_base -board = ttgo-t-beam +board = ttgo-tbeam build_flags = ${esp32_base.build_flags} -D TBEAM_V07 diff --git a/variants/esp32c3/heltec_hru_3601/platformio.ini b/variants/esp32c3/heltec_hru_3601/platformio.ini index aa62fb4fc..5eb1c9977 100644 --- a/variants/esp32c3/heltec_hru_3601/platformio.ini +++ b/variants/esp32c3/heltec_hru_3601/platformio.ini @@ -5,6 +5,3 @@ build_flags = ${esp32c3_base.build_flags} -D HELTEC_HRU_3601 -I variants/esp32c3/heltec_hru_3601 -lib_deps = ${esp32c3_base.lib_deps} - # renovate: datasource=custom.pio depName=NeoPixel packageName=adafruit/library/Adafruit NeoPixel - adafruit/Adafruit NeoPixel@1.15.4 diff --git a/variants/esp32c6/m5stack_unitc6l/platformio.ini b/variants/esp32c6/m5stack_unitc6l/platformio.ini index 1b4631656..43e5391ee 100644 --- a/variants/esp32c6/m5stack_unitc6l/platformio.ini +++ b/variants/esp32c6/m5stack_unitc6l/platformio.ini @@ -21,6 +21,8 @@ lib_deps = ${esp32c6_base.lib_deps} # renovate: datasource=custom.pio depName=NeoPixel packageName=adafruit/library/Adafruit NeoPixel adafruit/Adafruit NeoPixel@1.15.4 + # renovate: datasource=custom.pio depName=NimBLE-Arduino packageName=h2zero/library/NimBLE-Arduino + h2zero/NimBLE-Arduino@2.3.7 build_flags = ${esp32c6_base.build_flags} -D M5STACK_UNITC6L diff --git a/variants/esp32p4/esp32p4.ini b/variants/esp32p4/esp32p4.ini index d7f9530f2..c8caf8b05 100644 --- a/variants/esp32p4/esp32p4.ini +++ b/variants/esp32p4/esp32p4.ini @@ -8,26 +8,60 @@ build_unflags= build_flags = ${esp32_common.build_flags} - -DHAS_BLUETOOTH=0 - -DHAS_WIFI=0 - -DMESHTASTIC_EXCLUDE_BLUETOOTH=1 - -DMESHTASTIC_EXCLUDE_WIFI=1 -DMESHTASTIC_EXCLUDE_MQTT=1 -DMESHTASTIC_EXCLUDE_PAXCOUNTER=1 build_src_filter = - ${esp32_common.build_src_filter} - - - - - - - - - - + ${esp32_common.build_src_filter} - - - - - - - monitor_speed = 460800 monitor_filters = esp32_c3_exception_decoder +; Override esp32_common component pruning: keep esp_hosted + esp_wifi_remote for P4 hosted BT +custom_component_remove = + espressif/esp_modem + espressif/esp-dsp + espressif/esp32-camera + espressif/libsodium + espressif/esp-modbus + espressif/qrcode + espressif/esp_insights + espressif/esp_diag_data_store + espressif/esp_diagnostics + espressif/esp_rainmaker + espressif/rmaker_common + espressif/network_provisioning + chmorgan/esp-libhelix-mp3 + espressif/esp-tflite-micro + espressif/esp-sr + espressif/esp_matter + espressif/esp-zboss-lib + espressif/esp-zigbee-lib + espressif/mqtt + custom_sdkconfig = ${esp32_common.custom_sdkconfig} CONFIG_ARDUINO_SELECTIVE_SD_MMC=y - CONFIG_BT_ENABLED=n - CONFIG_BT_NIMBLE_ENABLED=n + CONFIG_BT_ENABLED=y + CONFIG_BT_NIMBLE_ENABLED=y CONFIG_BT_NIMBLE_EXT_ADV=n - ;CONFIG_ESP_SYSTEM_PANIC_PRINT_HALT=y ; remove for production version + CONFIG_ESP_WIFI_REMOTE_ENABLED=n + CONFIG_ESP_HOSTED_ENABLED=y + CONFIG_ESP_HOSTED_SDIO_HOST_INTERFACE=y + CONFIG_ESP_HOSTED_IDF_SLAVE_TARGET="esp32c6" + CONFIG_ESP_HOSTED_ENABLE_BT_NIMBLE=y + CONFIG_ESP_HOSTED_NIMBLE_HCI_VHCI=y + CONFIG_ESP_HOSTED_ENABLE_PEER_DATA_TRANSFER=y + CONFIG_ESP_HOSTED_MAX_CUSTOM_MSG_HANDLERS=3 + ; Prefer conservative reset behavior across P4 hosts + CONFIG_ESP_HOSTED_SLAVE_RESET_ON_EVERY_HOST_BOOTUP=n + CONFIG_ESP_HOSTED_SLAVE_RESET_ONLY_IF_NECESSARY=y + ; SOC_LCD (MUI / lovyanGFX) + CONFIG_SOC_LCD_I80_SUPPORTED=y + CONFIG_SOC_LCD_RGB_SUPPORTED=y + CONFIG_SOC_MIPI_DSI_SUPPORTED=y + CONFIG_ESP_SYSTEM_PANIC_PRINT_HALT=y ; remove for production version + ;CONFIG_ESP_SYSTEM_PANIC_PRINT_REBOOT=y; for production version ;CONFIG_ESP_SYSTEM_PANIC_GDBSTUB=y ; for target debugging lib_ignore = @@ -39,7 +73,6 @@ lib_ignore = esp32_idf5_https_server esp_driver_cam esp_http_server - esp_lcd ; Override lib_deps to exclude environmental_extras lib_deps = diff --git a/variants/esp32s3/ELECROW-ThinkNode-M5/variant.cpp b/variants/esp32s3/ELECROW-ThinkNode-M5/variant.cpp index 917341560..51a91bef0 100644 --- a/variants/esp32s3/ELECROW-ThinkNode-M5/variant.cpp +++ b/variants/esp32s3/ELECROW-ThinkNode-M5/variant.cpp @@ -9,11 +9,11 @@ void earlyInitVariant() io.pinMode(PCA_PIN_EINK_EN, OUTPUT); io.pinMode(PCA_PIN_POWER_EN, OUTPUT); io.pinMode(PCA_LED_POWER, OUTPUT); - io.pinMode(PCA_LED_USER, OUTPUT); + io.pinMode(PCA_LED_NOTIFICATION, OUTPUT); io.pinMode(PCA_LED_ENABLE, OUTPUT); io.digitalWrite(PCA_PIN_POWER_EN, HIGH); - io.digitalWrite(PCA_LED_USER, LOW); + io.digitalWrite(PCA_LED_NOTIFICATION, LOW); io.digitalWrite(PCA_LED_ENABLE, LOW); } diff --git a/variants/esp32s3/ELECROW-ThinkNode-M5/variant.h b/variants/esp32s3/ELECROW-ThinkNode-M5/variant.h index ff3541713..55bcd0dc7 100644 --- a/variants/esp32s3/ELECROW-ThinkNode-M5/variant.h +++ b/variants/esp32s3/ELECROW-ThinkNode-M5/variant.h @@ -8,9 +8,9 @@ // LED // Both of these are on the GPIO expander -#define PCA_LED_USER 1 // the Blue LED -#define PCA_LED_ENABLE 2 // the power supply to the LEDs, in an OR arrangement with VBUS power -#define PCA_LED_POWER 3 // the Red LED? Seems to have hardware logic to blink when USB is plugged in. +#define PCA_LED_NOTIFICATION 1 // the Blue LED +#define PCA_LED_ENABLE 2 // the power supply to the LEDs, in an OR arrangement with VBUS power +#define PCA_LED_POWER 3 // the Red LED? Seems to have hardware logic to blink when USB is plugged in. #define POWER_LED_HARDWARE_BLINKS_WHILE_CHARGING // USB_CHECK @@ -18,7 +18,7 @@ #define BATTERY_PIN 8 #define ADC_CHANNEL ADC_CHANNEL_7 -#define ADC_MULTIPLIER 2.11 // 2.0 + 10% for correction of display undervoltage. +#define ADC_MULTIPLIER 2.0 // 2.0 + 10% for correction of display undervoltage. #define PIN_BUZZER 9 @@ -86,6 +86,7 @@ #define BUTTON_PIN PIN_BUTTON1 #define BUTTON_PIN_ALT PIN_BUTTON2 +#define ALT_BUTTON_WAKE #define SERIAL_PRINT_PORT 0 #endif diff --git a/variants/esp32s3/elecrow_panel/platformio.ini b/variants/esp32s3/elecrow_panel/platformio.ini index 9d2d3f664..a707a832e 100644 --- a/variants/esp32s3/elecrow_panel/platformio.ini +++ b/variants/esp32s3/elecrow_panel/platformio.ini @@ -89,6 +89,7 @@ custom_meshtastic_images = crowpanel_2_4.svg, crowpanel_2_8.svg custom_meshtastic_tags = Elecrow custom_meshtastic_requires_dfu = true custom_meshtastic_partition_scheme = 16MB +custom_meshtastic_has_mui = true extends = crowpanel_small_esp32s3_base build_flags = @@ -124,6 +125,7 @@ custom_meshtastic_images = crowpanel_3_5.svg custom_meshtastic_tags = Elecrow custom_meshtastic_requires_dfu = true custom_meshtastic_partition_scheme = 16MB +custom_meshtastic_has_mui = true extends = crowpanel_small_esp32s3_base board_level = pr @@ -163,6 +165,7 @@ custom_meshtastic_images = crowpanel_5_0.svg, crowpanel_7_0.svg custom_meshtastic_tags = Elecrow custom_meshtastic_requires_dfu = true custom_meshtastic_partition_scheme = 16MB +custom_meshtastic_has_mui = true extends = crowpanel_large_esp32s3_base build_flags = diff --git a/variants/esp32s3/esp32-s3-pico/platformio.ini b/variants/esp32s3/esp32-s3-pico/platformio.ini index 07ca069f3..64f50f80e 100644 --- a/variants/esp32s3/esp32-s3-pico/platformio.ini +++ b/variants/esp32s3/esp32-s3-pico/platformio.ini @@ -24,5 +24,3 @@ build_flags = ${esp32s3_base.build_flags} lib_deps = ${esp32s3_base.lib_deps} # renovate: datasource=custom.pio depName=GxEPD2 packageName=zinggjm/library/GxEPD2 zinggjm/GxEPD2@1.6.8 - # renovate: datasource=custom.pio depName=NeoPixel packageName=adafruit/library/Adafruit NeoPixel - adafruit/Adafruit NeoPixel@1.15.4 diff --git a/variants/esp32s3/heltec_sensor_hub/platformio.ini b/variants/esp32s3/heltec_sensor_hub/platformio.ini index 013280db1..9a5384ccd 100644 --- a/variants/esp32s3/heltec_sensor_hub/platformio.ini +++ b/variants/esp32s3/heltec_sensor_hub/platformio.ini @@ -8,7 +8,3 @@ build_flags = -I variants/esp32s3/heltec_sensor_hub -D HELTEC_SENSOR_HUB -ULED_BUILTIN - -lib_deps = ${esp32s3_base.lib_deps} - # renovate: datasource=custom.pio depName=NeoPixel packageName=adafruit/library/Adafruit NeoPixel - adafruit/Adafruit NeoPixel@1.15.4 diff --git a/variants/esp32s3/heltec_v4/platformio.ini b/variants/esp32s3/heltec_v4/platformio.ini index cb795c65d..0336bf983 100644 --- a/variants/esp32s3/heltec_v4/platformio.ini +++ b/variants/esp32s3/heltec_v4/platformio.ini @@ -22,6 +22,7 @@ custom_meshtastic_images = heltec_v4.svg custom_meshtastic_tags = Heltec custom_meshtastic_requires_dfu = true custom_meshtastic_partition_scheme = 16MB +custom_meshtastic_has_mui = true extends = heltec_v4_base build_flags = diff --git a/variants/esp32s3/heltec_vision_master_e213/platformio.ini b/variants/esp32s3/heltec_vision_master_e213/platformio.ini index 80655af70..fb97fd983 100644 --- a/variants/esp32s3/heltec_vision_master_e213/platformio.ini +++ b/variants/esp32s3/heltec_vision_master_e213/platformio.ini @@ -9,6 +9,7 @@ custom_meshtastic_images = heltec-vision-master-e213.svg custom_meshtastic_tags = Heltec custom_meshtastic_requires_dfu = true custom_meshtastic_partition_scheme = 8MB +custom_meshtastic_has_ink_hud = true extends = esp32s3_base board = heltec_vision_master_e213 diff --git a/variants/esp32s3/heltec_vision_master_e290/platformio.ini b/variants/esp32s3/heltec_vision_master_e290/platformio.ini index 5affd24de..9fdb023de 100644 --- a/variants/esp32s3/heltec_vision_master_e290/platformio.ini +++ b/variants/esp32s3/heltec_vision_master_e290/platformio.ini @@ -10,6 +10,7 @@ custom_meshtastic_images = heltec-vision-master-e290.svg custom_meshtastic_tags = Heltec custom_meshtastic_requires_dfu = true custom_meshtastic_partition_scheme = 8MB +custom_meshtastic_has_ink_hud = true extends = esp32s3_base board = heltec_vision_master_e290 diff --git a/variants/esp32s3/heltec_vision_master_t190/platformio.ini b/variants/esp32s3/heltec_vision_master_t190/platformio.ini index 44e8b2f2d..be1ea192d 100644 --- a/variants/esp32s3/heltec_vision_master_t190/platformio.ini +++ b/variants/esp32s3/heltec_vision_master_t190/platformio.ini @@ -20,5 +20,5 @@ build_flags = lib_deps = ${esp32s3_base.lib_deps} # renovate: datasource=git-refs depName=meshtastic-st7789 packageName=https://github.com/meshtastic/st7789 gitBranch=main - https://github.com/meshtastic/st7789/archive/9ee76d6b18b9a8f45a2c5cae06b1134a587691eb.zip + https://github.com/meshtastic/st7789/archive/a787beea5c6c8f864ba6787eb432bbefc575e6ad.zip upload_speed = 921600 diff --git a/variants/esp32s3/heltec_wireless_paper/platformio.ini b/variants/esp32s3/heltec_wireless_paper/platformio.ini index ce4bed30e..acd619c48 100644 --- a/variants/esp32s3/heltec_wireless_paper/platformio.ini +++ b/variants/esp32s3/heltec_wireless_paper/platformio.ini @@ -9,6 +9,7 @@ custom_meshtastic_display_name = Heltec Wireless Paper custom_meshtastic_images = heltec-wireless-paper.svg custom_meshtastic_tags = Heltec custom_meshtastic_partition_scheme = 8MB +custom_meshtastic_has_ink_hud = true extends = esp32s3_base board = heltec_wifi_lora_32_V3 diff --git a/variants/esp32s3/m5stack_cardputer_adv/platformio.ini b/variants/esp32s3/m5stack_cardputer_adv/platformio.ini index e2411bc6e..7da039cd4 100644 --- a/variants/esp32s3/m5stack_cardputer_adv/platformio.ini +++ b/variants/esp32s3/m5stack_cardputer_adv/platformio.ini @@ -16,12 +16,10 @@ build_src_filter = lib_deps = ${esp32s3_base.lib_deps} # renovate: datasource=git-refs depName=meshtastic-st7789 packageName=https://github.com/meshtastic/st7789 gitBranch=main - https://github.com/meshtastic/st7789/archive/9ee76d6b18b9a8f45a2c5cae06b1134a587691eb.zip + https://github.com/meshtastic/st7789/archive/a787beea5c6c8f864ba6787eb432bbefc575e6ad.zip # renovate: datasource=github-tags depName=pschatzmann_arduino-audio-driver packageName=pschatzmann/arduino-audio-driver https://github.com/pschatzmann/arduino-audio-driver/archive/v0.2.1.zip # renovate: datasource=git-refs depName=ESP8266Audio packageName=https://github.com/meshtastic/ESP8266Audio gitBranch=meshtastic-2.0.0-dacfix https://github.com/meshtastic/ESP8266Audio/archive/343024632ee78d6216907b2353fc943a62422d80.zip # renovate: datasource=custom.pio depName=ESP8266SAM packageName=earlephilhower/library/ESP8266SAM earlephilhower/ESP8266SAM@1.1.0 - # renovate: datasource=custom.pio depName=NeoPixel packageName=adafruit/library/Adafruit NeoPixel - adafruit/Adafruit NeoPixel@1.15.4 diff --git a/variants/esp32s3/mesh-tab/platformio.ini b/variants/esp32s3/mesh-tab/platformio.ini index ecf5498b3..a153ba9fb 100644 --- a/variants/esp32s3/mesh-tab/platformio.ini +++ b/variants/esp32s3/mesh-tab/platformio.ini @@ -12,6 +12,7 @@ build_flags = ${esp32s3_base.build_flags} -D CONFIG_ARDUHAL_ESP_LOG -D CONFIG_ARDUHAL_LOG_COLORS=1 -D CONFIG_DISABLE_HAL_LOCKS=1 + -D MESHTASTIC_EXCLUDE_SCREEN=1 -D MESHTASTIC_EXCLUDE_CANNEDMESSAGES=1 -D MESHTASTIC_EXCLUDE_INPUTBROKER=1 -D MESHTASTIC_EXCLUDE_BLUETOOTH=1 @@ -31,7 +32,10 @@ build_flags = ${esp32s3_base.build_flags} -D HAS_SCREEN=0 -D HAS_TFT=1 -D USE_PIN_BUZZER - -D RAM_SIZE=1024 + -D MAP_TILES_GREY ; required for 2MB PSRAM + -D RAM_SIZE=1432 + -D STBI_ARENA_SIZE=450000 + -D LV_CACHE_DEF_SIZE=0 -D LGFX_DRIVER_TEMPLATE -D LGFX_DRIVER=LGFX_GENERIC -D GFX_DRIVER_INC=\"graphics/LGFX/LGFX_GENERIC.h\" diff --git a/variants/esp32s3/mini-epaper-s3/nicheGraphics.h b/variants/esp32s3/mini-epaper-s3/nicheGraphics.h index 86da4b8ce..0cbd6a192 100644 --- a/variants/esp32s3/mini-epaper-s3/nicheGraphics.h +++ b/variants/esp32s3/mini-epaper-s3/nicheGraphics.h @@ -98,7 +98,7 @@ void setupNicheGraphics() buttons->setTwoWayRockerPressHandlers( [inkhud]() { bool systemHandlingInput = false; - for (InkHUD::SystemApplet *sa : inkhud->systemApplets) { + for (const InkHUD::SystemApplet *sa : inkhud->systemApplets) { if (sa->handleInput) { systemHandlingInput = true; break; @@ -112,7 +112,7 @@ void setupNicheGraphics() }, [inkhud]() { bool systemHandlingInput = false; - for (InkHUD::SystemApplet *sa : inkhud->systemApplets) { + for (const InkHUD::SystemApplet *sa : inkhud->systemApplets) { if (sa->handleInput) { systemHandlingInput = true; break; diff --git a/variants/esp32s3/mini-epaper-s3/platformio.ini b/variants/esp32s3/mini-epaper-s3/platformio.ini index 5c3e64681..3e4802319 100644 --- a/variants/esp32s3/mini-epaper-s3/platformio.ini +++ b/variants/esp32s3/mini-epaper-s3/platformio.ini @@ -1,5 +1,5 @@ [env:mini-epaper-s3] -;custom_meshtastic_hw_model = +custom_meshtastic_hw_model = 125 custom_meshtastic_hw_model_slug = MINI_EPAPER_S3 custom_meshtastic_architecture = esp32-s3 custom_meshtastic_actively_supported = true @@ -8,6 +8,7 @@ custom_meshtastic_display_name = LILYGO Mini ePaper S3 E-Ink custom_meshtastic_images = mini-epaper-s3.svg custom_meshtastic_tags = LilyGo custom_meshtastic_requires_dfu = no +custom_meshtastic_has_mui = false extends = esp32s3_base board = mini-epaper-s3 diff --git a/variants/esp32s3/picomputer-s3/platformio.ini b/variants/esp32s3/picomputer-s3/platformio.ini index 82147f222..6f218a126 100644 --- a/variants/esp32s3/picomputer-s3/platformio.ini +++ b/variants/esp32s3/picomputer-s3/platformio.ini @@ -6,6 +6,7 @@ custom_meshtastic_actively_supported = true custom_meshtastic_support_level = 3 custom_meshtastic_display_name = Pi Computer S3 custom_meshtastic_partition_scheme = 8MB +custom_meshtastic_has_mui = true extends = esp32s3_base board = bpi_picow_esp32_s3 diff --git a/variants/esp32s3/rak3312/platformio.ini b/variants/esp32s3/rak3312/platformio.ini index 113c2f527..87e5b63ff 100644 --- a/variants/esp32s3/rak3312/platformio.ini +++ b/variants/esp32s3/rak3312/platformio.ini @@ -9,6 +9,7 @@ custom_meshtastic_images = rak_3312.svg custom_meshtastic_tags = RAK custom_meshtastic_requires_dfu = false custom_meshtastic_partition_scheme = 16MB +custom_meshtastic_has_mui = false extends = esp32s3_base board = wiscore_rak3312 diff --git a/variants/esp32s3/rak_wismesh_tap_v2/platformio.ini b/variants/esp32s3/rak_wismesh_tap_v2/platformio.ini index 96b1a067b..7847410ae 100644 --- a/variants/esp32s3/rak_wismesh_tap_v2/platformio.ini +++ b/variants/esp32s3/rak_wismesh_tap_v2/platformio.ini @@ -20,6 +20,7 @@ custom_meshtastic_display_name = RAK WisMesh Tap V2 custom_meshtastic_images = rak-wismesh-tap-v2.svg custom_meshtastic_tags = RAK custom_meshtastic_partition_scheme = 8MB +custom_meshtastic_has_mui = true extends = esp32s3_base board = wiscore_rak3312 @@ -43,6 +44,7 @@ extends = env:rak_wismesh_tap_v2 build_flags = ${env:rak_wismesh_tap_v2.build_flags} + -D MESHTASTIC_EXCLUDE_WEBSERVER=1 -D CONFIG_ARDUHAL_ESP_LOG -D CONFIG_ARDUHAL_LOG_COLORS=1 -D CONFIG_DISABLE_HAL_LOCKS=1 diff --git a/variants/esp32s3/seeed-sensecap-indicator/platformio.ini b/variants/esp32s3/seeed-sensecap-indicator/platformio.ini index 37686fbc7..158e704ec 100644 --- a/variants/esp32s3/seeed-sensecap-indicator/platformio.ini +++ b/variants/esp32s3/seeed-sensecap-indicator/platformio.ini @@ -9,7 +9,7 @@ custom_meshtastic_display_name = Seeed SenseCAP Indicator custom_meshtastic_images = seeed-sensecap-indicator.svg custom_meshtastic_tags = Seeed custom_meshtastic_partition_scheme = 8MB - = true +custom_meshtastic_has_mui = true extends = esp32s3_base platform_packages = diff --git a/variants/esp32s3/t-beam-1w/platformio.ini b/variants/esp32s3/t-beam-1w/platformio.ini index 9abf895db..b14f2fe3c 100644 --- a/variants/esp32s3/t-beam-1w/platformio.ini +++ b/variants/esp32s3/t-beam-1w/platformio.ini @@ -8,6 +8,7 @@ custom_meshtastic_support_level = 1 custom_meshtastic_display_name = LILYGO T-Beam 1W custom_meshtastic_images = tbeam-1w.svg custom_meshtastic_tags = LilyGo +custom_meshtastic_has_mui = false extends = esp32s3_base board = t-beam-1w diff --git a/variants/esp32s3/t-deck-pro/platformio.ini b/variants/esp32s3/t-deck-pro/platformio.ini index c5411da13..93ef8babf 100644 --- a/variants/esp32s3/t-deck-pro/platformio.ini +++ b/variants/esp32s3/t-deck-pro/platformio.ini @@ -9,6 +9,7 @@ custom_meshtastic_images = tdeck_pro.svg custom_meshtastic_tags = LilyGo custom_meshtastic_requires_dfu = true custom_meshtastic_partition_scheme = 16MB +custom_meshtastic_has_mui = false extends = esp32s3_base board = t-deck-pro diff --git a/variants/esp32s3/t-deck/platformio.ini b/variants/esp32s3/t-deck/platformio.ini index 7d79e934c..1b3599464 100644 --- a/variants/esp32s3/t-deck/platformio.ini +++ b/variants/esp32s3/t-deck/platformio.ini @@ -10,6 +10,7 @@ custom_meshtastic_images = t-deck.svg custom_meshtastic_tags = LilyGo custom_meshtastic_requires_dfu = true custom_meshtastic_partition_scheme = 16MB +custom_meshtastic_has_mui = true extends = esp32s3_base board = t-deck diff --git a/variants/esp32s3/t5s3_epaper/platformio.ini b/variants/esp32s3/t5s3_epaper/platformio.ini index 8f4a02a00..bad36706c 100644 --- a/variants/esp32s3/t5s3_epaper/platformio.ini +++ b/variants/esp32s3/t5s3_epaper/platformio.ini @@ -30,6 +30,8 @@ lib_deps = [env:t5s3_epaper_inkhud] extends = t5s3_epaper_base, inkhud +board_level = extra # inkhud port is incomplete +board_check = false build_flags = ${t5s3_epaper_base.build_flags} ${inkhud.build_flags} diff --git a/variants/esp32s3/tlora-pager/platformio.ini b/variants/esp32s3/tlora-pager/platformio.ini index dc96113b0..832f9d7d7 100644 --- a/variants/esp32s3/tlora-pager/platformio.ini +++ b/variants/esp32s3/tlora-pager/platformio.ini @@ -10,6 +10,7 @@ custom_meshtastic_images = lilygo-tlora-pager.svg custom_meshtastic_tags = LilyGo custom_meshtastic_requires_dfu = true custom_meshtastic_partition_scheme = 16MB +custom_meshtastic_has_mui = true extends = esp32s3_base board = t-deck-pro ; same as T-Deck Pro diff --git a/variants/esp32s3/tlora_t3s3_epaper/platformio.ini b/variants/esp32s3/tlora_t3s3_epaper/platformio.ini index f9d1ea7db..8f764bbe6 100644 --- a/variants/esp32s3/tlora_t3s3_epaper/platformio.ini +++ b/variants/esp32s3/tlora_t3s3_epaper/platformio.ini @@ -8,6 +8,7 @@ custom_meshtastic_display_name = LILYGO T-LoRa T3-S3 E-Ink custom_meshtastic_images = tlora-t3s3-epaper.svg custom_meshtastic_tags = LilyGo custom_meshtastic_requires_dfu = true +custom_meshtastic_has_ink_hud = true extends = esp32s3_base board = tlora-t3s3-v1 diff --git a/variants/esp32s3/unphone/platformio.ini b/variants/esp32s3/unphone/platformio.ini index b36c5df20..1a67836a3 100644 --- a/variants/esp32s3/unphone/platformio.ini +++ b/variants/esp32s3/unphone/platformio.ini @@ -39,8 +39,6 @@ lib_deps = ${esp32s3_base.lib_deps} lovyan03/LovyanGFX@1.2.19 # TODO renovate https://gitlab.com/hamishcunningham/unphonelibrary#meshtastic@9.0.0 https://gitlab.com/hamishcunningham/unphonelibrary/-/archive/meshtastic/unphonelibrary-meshtastic.zip - # renovate: datasource=custom.pio depName=NeoPixel packageName=adafruit/library/Adafruit NeoPixel - adafruit/Adafruit NeoPixel@1.15.4 [env:unphone-tft] board_level = extra diff --git a/variants/native/portduino.ini b/variants/native/portduino.ini index a247b0af1..86b1fe60a 100644 --- a/variants/native/portduino.ini +++ b/variants/native/portduino.ini @@ -34,8 +34,8 @@ lib_deps = adafruit/Adafruit seesaw Library@1.7.9 # renovate: datasource=git-refs depName=RAK12034-BMX160 packageName=https://github.com/RAKWireless/RAK12034-BMX160 gitBranch=main https://github.com/RAKWireless/RAK12034-BMX160/archive/dcead07ffa267d3c906e9ca4a1330ab989e957e2.zip - # renovate: datasource=custom.pio depName=Adafruit_BME680 packageName=adafruit/library/Adafruit BME680 Library - adafruit/Adafruit BME680 Library@2.0.6 + # renovate: datasource=github-tags depName=Adafruit_BME680 packageName=adafruit/Adafruit_BME680 + https://github.com/adafruit/Adafruit_BME680/archive/refs/tags/2.0.6.zip build_flags = ${arduino_base.build_flags} @@ -59,4 +59,5 @@ build_flags = lib_ignore = Adafruit NeoPixel Adafruit ST7735 and ST7789 Library + Adafruit SSD1306 SD diff --git a/variants/nrf52840/ELECROW-ThinkNode-M1/platformio.ini b/variants/nrf52840/ELECROW-ThinkNode-M1/platformio.ini index 2a6cea73e..c169de8f7 100644 --- a/variants/nrf52840/ELECROW-ThinkNode-M1/platformio.ini +++ b/variants/nrf52840/ELECROW-ThinkNode-M1/platformio.ini @@ -8,6 +8,7 @@ custom_meshtastic_support_level = 1 custom_meshtastic_display_name = ThinkNode M1 custom_meshtastic_images = thinknode_m1.svg custom_meshtastic_tags = Elecrow +custom_meshtastic_has_ink_hud = true extends = nrf52840_base board = ThinkNode-M1 diff --git a/variants/nrf52840/diy/nrf52_promicro_diy_tcxo/rfswitch.h b/variants/nrf52840/diy/nrf52_promicro_diy_tcxo/rfswitch.h index 71508c037..ac7ef57c4 100644 --- a/variants/nrf52840/diy/nrf52_promicro_diy_tcxo/rfswitch.h +++ b/variants/nrf52840/diy/nrf52_promicro_diy_tcxo/rfswitch.h @@ -12,9 +12,15 @@ static const uint32_t rfswitch_dio_pins[] = {RADIOLIB_LR11X0_DIO5, RADIOLIB_LR11 RADIOLIB_NC}; static const Module::RfSwitchMode_t rfswitch_table[] = { - // mode DIO5 DIO6 DIO7 - {LR11x0::MODE_STBY, {LOW, LOW, LOW}}, {LR11x0::MODE_RX, {LOW, HIGH, LOW}}, - {LR11x0::MODE_TX, {HIGH, HIGH, LOW}}, {LR11x0::MODE_TX_HP, {HIGH, LOW, LOW}}, - {LR11x0::MODE_TX_HF, {LOW, LOW, LOW}}, {LR11x0::MODE_GNSS, {LOW, LOW, HIGH}}, - {LR11x0::MODE_WIFI, {LOW, LOW, LOW}}, END_OF_MODE_TABLE, + // clang-format off + // mode DIO5 DIO6 DIO7 + {LR11x0::MODE_STBY, {LOW, LOW, LOW}}, + {LR11x0::MODE_RX, {LOW, HIGH, LOW}}, + {LR11x0::MODE_TX, {HIGH, HIGH, LOW}}, + {LR11x0::MODE_TX_HP, {HIGH, LOW, LOW}}, + {LR11x0::MODE_TX_HF, {LOW, LOW, LOW}}, + {LR11x0::MODE_GNSS, {LOW, LOW, HIGH}}, + {LR11x0::MODE_WIFI, {LOW, LOW, LOW}}, + END_OF_MODE_TABLE, + // clang-format on }; diff --git a/variants/nrf52840/heltec_mesh_node_t114/platformio.ini b/variants/nrf52840/heltec_mesh_node_t114/platformio.ini index 7cbc5f6a9..ef8bd4a17 100644 --- a/variants/nrf52840/heltec_mesh_node_t114/platformio.ini +++ b/variants/nrf52840/heltec_mesh_node_t114/platformio.ini @@ -23,4 +23,4 @@ build_src_filter = ${nrf52_base.build_src_filter} +<../variants/nrf52840/heltec_ lib_deps = ${nrf52840_base.lib_deps} # renovate: datasource=git-refs depName=meshtastic-st7789 packageName=https://github.com/meshtastic/st7789 gitBranch=main - https://github.com/meshtastic/st7789/archive/9ee76d6b18b9a8f45a2c5cae06b1134a587691eb.zip + https://github.com/meshtastic/st7789/archive/a787beea5c6c8f864ba6787eb432bbefc575e6ad.zip diff --git a/variants/nrf52840/heltec_mesh_pocket/platformio.ini b/variants/nrf52840/heltec_mesh_pocket/platformio.ini index 9fbcc890d..c9b599382 100644 --- a/variants/nrf52840/heltec_mesh_pocket/platformio.ini +++ b/variants/nrf52840/heltec_mesh_pocket/platformio.ini @@ -15,6 +15,7 @@ custom_meshtastic_display_name = Heltec Mesh Pocket custom_meshtastic_actively_supported = true custom_meshtastic_variant = 5000mAh custom_meshtastic_key = heltec_mesh_pocket +custom_meshtastic_has_ink_hud = true # add -DCFG_SYSVIEW if you want to use the Segger systemview tool for OS profiling. build_flags = ${nrf52840_base.build_flags} @@ -78,6 +79,7 @@ custom_meshtastic_display_name = Heltec Mesh Pocket custom_meshtastic_actively_supported = true custom_meshtastic_variant = 10000mAh custom_meshtastic_key = heltec_mesh_pocket +custom_meshtastic_has_ink_hud = true # add -DCFG_SYSVIEW if you want to use the Segger systemview tool for OS profiling. build_flags = ${nrf52840_base.build_flags} diff --git a/variants/nrf52840/heltec_mesh_solar/platformio.ini b/variants/nrf52840/heltec_mesh_solar/platformio.ini index 6935920cd..1b15c0758 100644 --- a/variants/nrf52840/heltec_mesh_solar/platformio.ini +++ b/variants/nrf52840/heltec_mesh_solar/platformio.ini @@ -132,4 +132,4 @@ build_flags = ${heltec_mesh_solar_base.build_flags} lib_deps = ${heltec_mesh_solar_base.lib_deps} # renovate: datasource=git-refs depName=meshtastic-st7789 packageName=https://github.com/meshtastic/st7789 gitBranch=main - https://github.com/meshtastic/st7789/archive/9ee76d6b18b9a8f45a2c5cae06b1134a587691eb.zip + https://github.com/meshtastic/st7789/archive/a787beea5c6c8f864ba6787eb432bbefc575e6ad.zip diff --git a/variants/nrf52840/seeed_wio_tracker_L1_eink/platformio.ini b/variants/nrf52840/seeed_wio_tracker_L1_eink/platformio.ini index d8fbaf8ff..26f4de565 100644 --- a/variants/nrf52840/seeed_wio_tracker_L1_eink/platformio.ini +++ b/variants/nrf52840/seeed_wio_tracker_L1_eink/platformio.ini @@ -7,6 +7,7 @@ custom_meshtastic_support_level = 1 custom_meshtastic_display_name = Seeed Wio Tracker L1 E-Ink custom_meshtastic_images = wio_tracker_l1_eink.svg custom_meshtastic_tags = Seeed +custom_meshtastic_has_ink_hud = true board = seeed_wio_tracker_L1 extends = nrf52840_base diff --git a/variants/nrf52840/t-echo-plus/platformio.ini b/variants/nrf52840/t-echo-plus/platformio.ini index 9ec9187e8..313eceadc 100644 --- a/variants/nrf52840/t-echo-plus/platformio.ini +++ b/variants/nrf52840/t-echo-plus/platformio.ini @@ -1,4 +1,15 @@ [env:t-echo-plus] +custom_meshtastic_hw_model = 33 +custom_meshtastic_hw_model_slug = T_ECHO_PLUS +custom_meshtastic_architecture = nrf52840 +custom_meshtastic_actively_supported = true +custom_meshtastic_support_level = 1 +custom_meshtastic_display_name = LILYGO T-Echo Plus +custom_meshtastic_images = t-echo_plus.svg +custom_meshtastic_tags = LilyGo +custom_meshtastic_requires_dfu = true +custom_meshtastic_has_ink_hud = true + extends = nrf52840_base board = t-echo board_level = pr diff --git a/variants/nrf52840/t-echo/platformio.ini b/variants/nrf52840/t-echo/platformio.ini index 89ce488ad..58ad029ae 100644 --- a/variants/nrf52840/t-echo/platformio.ini +++ b/variants/nrf52840/t-echo/platformio.ini @@ -8,6 +8,7 @@ custom_meshtastic_support_level = 1 custom_meshtastic_display_name = LILYGO T-Echo custom_meshtastic_images = t-echo.svg custom_meshtastic_tags = LilyGo +custom_meshtastic_has_ink_hud = true extends = nrf52840_base board = t-echo diff --git a/variants/nrf52840/wio-sdk-wm1110/platformio.ini b/variants/nrf52840/wio-sdk-wm1110/platformio.ini index 7c11ef6f6..9fac82289 100644 --- a/variants/nrf52840/wio-sdk-wm1110/platformio.ini +++ b/variants/nrf52840/wio-sdk-wm1110/platformio.ini @@ -9,6 +9,7 @@ extra_scripts = # Remove adafruit USB serial from the build (it is incompatible with using the ch340 serial chip on this board) build_unflags = + ${nrf52840_base.build_unflags} -Ofast -Og -ggdb3 diff --git a/version.properties b/version.properties index c25179ae2..8621dd9c9 100644 --- a/version.properties +++ b/version.properties @@ -1,4 +1,4 @@ [VERSION] major = 2 minor = 7 -build = 21 +build = 22