mirror of
https://github.com/meshtastic/firmware.git
synced 2025-12-15 23:32:34 +00:00
Compare commits
1 Commits
gps-reset-
...
double-tro
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ca6c83e07a |
@@ -1,7 +1,7 @@
|
||||
# trunk-ignore-all(terrascan/AC_DOCKER_0002): Known terrascan issue
|
||||
# trunk-ignore-all(hadolint/DL3008): Do not pin apt package versions
|
||||
# trunk-ignore-all(hadolint/DL3013): Do not pin pip package versions
|
||||
FROM mcr.microsoft.com/devcontainers/cpp:2-debian-12
|
||||
FROM mcr.microsoft.com/devcontainers/cpp:1-debian-12
|
||||
|
||||
USER root
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
"features": {
|
||||
"ghcr.io/devcontainers/features/python:1": {
|
||||
"installTools": true,
|
||||
"version": "3.13"
|
||||
"version": "latest"
|
||||
}
|
||||
},
|
||||
"customizations": {
|
||||
|
||||
56
.github/workflows/build_one_arch.yml
vendored
56
.github/workflows/build_one_arch.yml
vendored
@@ -88,6 +88,62 @@ jobs:
|
||||
if: ${{ !contains(github.ref_name, 'event/') && github.event_name != 'workflow_dispatch' || !contains(github.ref_name, 'event/') && inputs.arch == 'native' }}
|
||||
uses: ./.github/workflows/test_native.yml
|
||||
|
||||
docker-deb-amd64:
|
||||
if: ${{ github.event_name != 'workflow_dispatch' || inputs.arch == 'native' }}
|
||||
uses: ./.github/workflows/docker_build.yml
|
||||
with:
|
||||
distro: debian
|
||||
platform: linux/amd64
|
||||
runs-on: ubuntu-24.04
|
||||
push: false
|
||||
|
||||
docker-deb-amd64-tft:
|
||||
if: ${{ github.event_name != 'workflow_dispatch' || inputs.arch == 'native' }}
|
||||
uses: ./.github/workflows/docker_build.yml
|
||||
with:
|
||||
distro: debian
|
||||
platform: linux/amd64
|
||||
runs-on: ubuntu-24.04
|
||||
push: false
|
||||
pio_env: native-tft
|
||||
|
||||
docker-alp-amd64:
|
||||
if: ${{ github.event_name != 'workflow_dispatch' || inputs.arch == 'native' }}
|
||||
uses: ./.github/workflows/docker_build.yml
|
||||
with:
|
||||
distro: alpine
|
||||
platform: linux/amd64
|
||||
runs-on: ubuntu-24.04
|
||||
push: false
|
||||
|
||||
docker-alp-amd64-tft:
|
||||
if: ${{ github.event_name != 'workflow_dispatch' || inputs.arch == 'native' }}
|
||||
uses: ./.github/workflows/docker_build.yml
|
||||
with:
|
||||
distro: alpine
|
||||
platform: linux/amd64
|
||||
runs-on: ubuntu-24.04
|
||||
push: false
|
||||
pio_env: native-tft
|
||||
|
||||
docker-deb-arm64:
|
||||
if: ${{ github.event_name != 'workflow_dispatch' || inputs.arch == 'native' }}
|
||||
uses: ./.github/workflows/docker_build.yml
|
||||
with:
|
||||
distro: debian
|
||||
platform: linux/arm64
|
||||
runs-on: ubuntu-24.04-arm
|
||||
push: false
|
||||
|
||||
docker-deb-armv7:
|
||||
if: ${{ github.event_name != 'workflow_dispatch' || inputs.arch == 'native' }}
|
||||
uses: ./.github/workflows/docker_build.yml
|
||||
with:
|
||||
distro: debian
|
||||
platform: linux/arm/v7
|
||||
runs-on: ubuntu-24.04-arm
|
||||
push: false
|
||||
|
||||
gather-artifacts:
|
||||
permissions:
|
||||
contents: write
|
||||
|
||||
56
.github/workflows/build_one_target.yml
vendored
56
.github/workflows/build_one_target.yml
vendored
@@ -106,6 +106,62 @@ jobs:
|
||||
if: ${{ !contains(github.ref_name, 'event/') && github.event_name != 'workflow_dispatch' || !contains(github.ref_name, 'event/') && inputs.arch == 'native' && inputs.target != '' }}
|
||||
uses: ./.github/workflows/test_native.yml
|
||||
|
||||
docker-deb-amd64:
|
||||
if: ${{ inputs.target != '' && inputs.arch == 'native' }}
|
||||
uses: ./.github/workflows/docker_build.yml
|
||||
with:
|
||||
distro: debian
|
||||
platform: linux/amd64
|
||||
runs-on: ubuntu-24.04
|
||||
push: false
|
||||
|
||||
docker-deb-amd64-tft:
|
||||
if: ${{ inputs.target != '' && inputs.arch == 'native' }}
|
||||
uses: ./.github/workflows/docker_build.yml
|
||||
with:
|
||||
distro: debian
|
||||
platform: linux/amd64
|
||||
runs-on: ubuntu-24.04
|
||||
push: false
|
||||
pio_env: native-tft
|
||||
|
||||
docker-alp-amd64:
|
||||
if: ${{ inputs.target != '' && inputs.arch == 'native' }}
|
||||
uses: ./.github/workflows/docker_build.yml
|
||||
with:
|
||||
distro: alpine
|
||||
platform: linux/amd64
|
||||
runs-on: ubuntu-24.04
|
||||
push: false
|
||||
|
||||
docker-alp-amd64-tft:
|
||||
if: ${{ inputs.target != '' && inputs.arch == 'native' }}
|
||||
uses: ./.github/workflows/docker_build.yml
|
||||
with:
|
||||
distro: alpine
|
||||
platform: linux/amd64
|
||||
runs-on: ubuntu-24.04
|
||||
push: false
|
||||
pio_env: native-tft
|
||||
|
||||
docker-deb-arm64:
|
||||
if: ${{ inputs.target != '' && inputs.arch == 'native' }}
|
||||
uses: ./.github/workflows/docker_build.yml
|
||||
with:
|
||||
distro: debian
|
||||
platform: linux/arm64
|
||||
runs-on: ubuntu-24.04-arm
|
||||
push: false
|
||||
|
||||
docker-deb-armv7:
|
||||
if: ${{ inputs.target != '' && inputs.arch == 'native' }}
|
||||
uses: ./.github/workflows/docker_build.yml
|
||||
with:
|
||||
distro: debian
|
||||
platform: linux/arm/v7
|
||||
runs-on: ubuntu-24.04-arm
|
||||
push: false
|
||||
|
||||
gather-artifacts:
|
||||
permissions:
|
||||
contents: write
|
||||
|
||||
76
.github/workflows/main_matrix.yml
vendored
76
.github/workflows/main_matrix.yml
vendored
@@ -27,6 +27,7 @@ on:
|
||||
|
||||
jobs:
|
||||
setup:
|
||||
if: github.repository == 'meshtastic/firmware'
|
||||
strategy:
|
||||
fail-fast: true
|
||||
matrix:
|
||||
@@ -41,6 +42,10 @@ jobs:
|
||||
python-version: 3.x
|
||||
cache: pip
|
||||
- run: pip install -U platformio
|
||||
- name: Uncomment build epoch
|
||||
shell: bash
|
||||
run: |
|
||||
sed -i 's/#-DBUILD_EPOCH=$UNIX_TIME/-DBUILD_EPOCH=$UNIX_TIME/' platformio.ini
|
||||
- name: Generate matrix
|
||||
id: jsonStep
|
||||
run: |
|
||||
@@ -57,6 +62,7 @@ jobs:
|
||||
check: ${{ steps.jsonStep.outputs.check }}
|
||||
|
||||
version:
|
||||
if: github.repository == 'meshtastic/firmware'
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v5
|
||||
@@ -119,26 +125,60 @@ jobs:
|
||||
if: ${{ !contains(github.ref_name, 'event/') && github.repository == 'meshtastic/firmware' }}
|
||||
uses: ./.github/workflows/test_native.yml
|
||||
|
||||
docker:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
distro: [debian, alpine]
|
||||
platform: [linux/amd64, linux/arm64, linux/arm/v7]
|
||||
pio_env: [native, native-tft]
|
||||
exclude:
|
||||
- distro: alpine
|
||||
platform: linux/arm/v7
|
||||
- pio_env: native-tft
|
||||
platform: linux/arm64
|
||||
- pio_env: native-tft
|
||||
platform: linux/arm/v7
|
||||
docker-deb-amd64:
|
||||
if: github.repository == 'meshtastic/firmware'
|
||||
uses: ./.github/workflows/docker_build.yml
|
||||
with:
|
||||
distro: ${{ matrix.distro }}
|
||||
platform: ${{ matrix.platform }}
|
||||
runs-on: ${{ contains(matrix.platform, 'arm') && 'ubuntu-24.04-arm' || 'ubuntu-24.04' }}
|
||||
pio_env: ${{ matrix.pio_env }}
|
||||
distro: debian
|
||||
platform: linux/amd64
|
||||
runs-on: ubuntu-24.04
|
||||
push: false
|
||||
|
||||
docker-deb-amd64-tft:
|
||||
if: github.repository == 'meshtastic/firmware'
|
||||
uses: ./.github/workflows/docker_build.yml
|
||||
with:
|
||||
distro: debian
|
||||
platform: linux/amd64
|
||||
runs-on: ubuntu-24.04
|
||||
push: false
|
||||
pio_env: native-tft
|
||||
|
||||
docker-alp-amd64:
|
||||
if: github.repository == 'meshtastic/firmware'
|
||||
uses: ./.github/workflows/docker_build.yml
|
||||
with:
|
||||
distro: alpine
|
||||
platform: linux/amd64
|
||||
runs-on: ubuntu-24.04
|
||||
push: false
|
||||
|
||||
docker-alp-amd64-tft:
|
||||
if: github.repository == 'meshtastic/firmware'
|
||||
uses: ./.github/workflows/docker_build.yml
|
||||
with:
|
||||
distro: alpine
|
||||
platform: linux/amd64
|
||||
runs-on: ubuntu-24.04
|
||||
push: false
|
||||
pio_env: native-tft
|
||||
|
||||
docker-deb-arm64:
|
||||
if: github.repository == 'meshtastic/firmware'
|
||||
uses: ./.github/workflows/docker_build.yml
|
||||
with:
|
||||
distro: debian
|
||||
platform: linux/arm64
|
||||
runs-on: ubuntu-24.04-arm
|
||||
push: false
|
||||
|
||||
docker-deb-armv7:
|
||||
if: github.repository == 'meshtastic/firmware'
|
||||
uses: ./.github/workflows/docker_build.yml
|
||||
with:
|
||||
distro: debian
|
||||
platform: linux/arm/v7
|
||||
runs-on: ubuntu-24.04-arm
|
||||
push: false
|
||||
|
||||
gather-artifacts:
|
||||
|
||||
64
.github/workflows/merge_queue.yml
vendored
64
.github/workflows/merge_queue.yml
vendored
@@ -99,26 +99,54 @@ jobs:
|
||||
if: ${{ !contains(github.ref_name, 'event/') }}
|
||||
uses: ./.github/workflows/test_native.yml
|
||||
|
||||
docker:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
distro: [debian, alpine]
|
||||
platform: [linux/amd64, linux/arm64, linux/arm/v7]
|
||||
pio_env: [native, native-tft]
|
||||
exclude:
|
||||
- distro: alpine
|
||||
platform: linux/arm/v7
|
||||
- pio_env: native-tft
|
||||
platform: linux/arm64
|
||||
- pio_env: native-tft
|
||||
platform: linux/arm/v7
|
||||
docker-deb-amd64:
|
||||
uses: ./.github/workflows/docker_build.yml
|
||||
with:
|
||||
distro: ${{ matrix.distro }}
|
||||
platform: ${{ matrix.platform }}
|
||||
runs-on: ${{ contains(matrix.platform, 'arm') && 'ubuntu-24.04-arm' || 'ubuntu-24.04' }}
|
||||
pio_env: ${{ matrix.pio_env }}
|
||||
distro: debian
|
||||
platform: linux/amd64
|
||||
runs-on: ubuntu-24.04
|
||||
push: false
|
||||
|
||||
docker-deb-amd64-tft:
|
||||
uses: ./.github/workflows/docker_build.yml
|
||||
with:
|
||||
distro: debian
|
||||
platform: linux/amd64
|
||||
runs-on: ubuntu-24.04
|
||||
push: false
|
||||
pio_env: native-tft
|
||||
|
||||
docker-alp-amd64:
|
||||
uses: ./.github/workflows/docker_build.yml
|
||||
with:
|
||||
distro: alpine
|
||||
platform: linux/amd64
|
||||
runs-on: ubuntu-24.04
|
||||
push: false
|
||||
|
||||
docker-alp-amd64-tft:
|
||||
uses: ./.github/workflows/docker_build.yml
|
||||
with:
|
||||
distro: alpine
|
||||
platform: linux/amd64
|
||||
runs-on: ubuntu-24.04
|
||||
push: false
|
||||
pio_env: native-tft
|
||||
|
||||
docker-deb-arm64:
|
||||
uses: ./.github/workflows/docker_build.yml
|
||||
with:
|
||||
distro: debian
|
||||
platform: linux/arm64
|
||||
runs-on: ubuntu-24.04-arm
|
||||
push: false
|
||||
|
||||
docker-deb-armv7:
|
||||
uses: ./.github/workflows/docker_build.yml
|
||||
with:
|
||||
distro: debian
|
||||
platform: linux/arm/v7
|
||||
runs-on: ubuntu-24.04-arm
|
||||
push: false
|
||||
|
||||
gather-artifacts:
|
||||
|
||||
6
.github/workflows/stale_bot.yml
vendored
6
.github/workflows/stale_bot.yml
vendored
@@ -20,7 +20,5 @@ jobs:
|
||||
uses: actions/stale@v10.1.0
|
||||
with:
|
||||
days-before-stale: 45
|
||||
stale-issue-message: This issue has not had any comment or update in the last month. If it is still relevant, please post update comments. If no comments are made, this issue will be closed automagically in 7 days.
|
||||
close-issue-message: This issue has not had any comment since the last notice. It has been closed automatically. If this is incorrect, or the issue becomes relevant again, please request that it is reopened.
|
||||
exempt-issue-labels: pinned,3.0,triaged,backlog
|
||||
exempt-pr-labels: pinned,3.0,triaged,backlog
|
||||
exempt-issue-labels: pinned,3.0
|
||||
exempt-pr-labels: pinned,3.0
|
||||
|
||||
4
.github/workflows/tests.yml
vendored
4
.github/workflows/tests.yml
vendored
@@ -47,9 +47,9 @@ jobs:
|
||||
pio upgrade
|
||||
|
||||
- name: Setup Node
|
||||
uses: actions/setup-node@v6
|
||||
uses: actions/setup-node@v5
|
||||
with:
|
||||
node-version: 24
|
||||
node-version: 22
|
||||
|
||||
- name: Setup pnpm
|
||||
uses: pnpm/action-setup@v4
|
||||
|
||||
@@ -4,24 +4,24 @@ cli:
|
||||
plugins:
|
||||
sources:
|
||||
- id: trunk
|
||||
ref: v1.7.3
|
||||
ref: v1.7.2
|
||||
uri: https://github.com/trunk-io/plugins
|
||||
lint:
|
||||
enabled:
|
||||
- checkov@3.2.486
|
||||
- renovate@41.157.0
|
||||
- checkov@3.2.473
|
||||
- renovate@41.132.5
|
||||
- prettier@3.6.2
|
||||
- trufflehog@3.90.11
|
||||
- trufflehog@3.90.8
|
||||
- yamllint@1.37.1
|
||||
- bandit@1.8.6
|
||||
- trivy@0.67.2
|
||||
- trivy@0.67.0
|
||||
- taplo@0.10.0
|
||||
- ruff@0.14.1
|
||||
- isort@7.0.0
|
||||
- ruff@0.13.3
|
||||
- isort@6.1.0
|
||||
- markdownlint@0.45.0
|
||||
- oxipng@9.1.5
|
||||
- svgo@4.0.0
|
||||
- actionlint@1.7.8
|
||||
- actionlint@1.7.7
|
||||
- flake8@7.3.0
|
||||
- hadolint@2.14.0
|
||||
- shfmt@3.6.0
|
||||
|
||||
@@ -57,7 +57,7 @@ lib_deps =
|
||||
# renovate: datasource=git-refs depName=libpax packageName=https://github.com/dbinfrago/libpax gitBranch=master
|
||||
https://github.com/dbinfrago/libpax/archive/3cdc0371c375676a97967547f4065607d4c53fd1.zip
|
||||
# renovate: datasource=github-tags depName=XPowersLib packageName=lewisxhe/XPowersLib
|
||||
https://github.com/lewisxhe/XPowersLib/archive/v0.3.1.zip
|
||||
https://github.com/lewisxhe/XPowersLib/archive/v0.3.0.zip
|
||||
# renovate: datasource=git-refs depName=meshtastic-ESP32_Codec2 packageName=https://github.com/meshtastic/ESP32_Codec2 gitBranch=master
|
||||
https://github.com/meshtastic/ESP32_Codec2/archive/633326c78ac251c059ab3a8c430fcdf25b41672f.zip
|
||||
# renovate: datasource=custom.pio depName=rweather/Crypto packageName=rweather/library/Crypto
|
||||
|
||||
@@ -28,7 +28,7 @@ lib_deps =
|
||||
${environmental_extra.lib_deps}
|
||||
${radiolib_base.lib_deps}
|
||||
# renovate: datasource=custom.pio depName=XPowersLib packageName=lewisxhe/library/XPowersLib
|
||||
lewisxhe/XPowersLib@0.3.1
|
||||
lewisxhe/XPowersLib@0.3.0
|
||||
# renovate: datasource=git-refs depName=meshtastic-ESP32_Codec2 packageName=https://github.com/meshtastic/ESP32_Codec2 gitBranch=master
|
||||
https://github.com/meshtastic/ESP32_Codec2/archive/633326c78ac251c059ab3a8c430fcdf25b41672f.zip
|
||||
# renovate: datasource=custom.pio depName=rweather/Crypto packageName=rweather/library/Crypto
|
||||
|
||||
@@ -1,116 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Script to cancel all running GitHub Actions workflows
|
||||
# Requires GitHub CLI (gh) to be installed and authenticated
|
||||
|
||||
set -e
|
||||
|
||||
# Colors for output
|
||||
RED='\033[0;31m'
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[1;33m'
|
||||
NC='\033[0m' # No Color
|
||||
|
||||
# Function to print colored output
|
||||
print_status() {
|
||||
echo -e "${GREEN}[INFO]${NC} $1"
|
||||
}
|
||||
|
||||
print_warning() {
|
||||
echo -e "${YELLOW}[WARN]${NC} $1"
|
||||
}
|
||||
|
||||
print_error() {
|
||||
echo -e "${RED}[ERROR]${NC} $1"
|
||||
}
|
||||
|
||||
# Check if gh CLI is installed
|
||||
if ! command -v gh &> /dev/null; then
|
||||
print_error "GitHub CLI (gh) is not installed. Please install it first:"
|
||||
echo " brew install gh"
|
||||
echo " Or visit: https://cli.github.com/"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Check if authenticated
|
||||
if ! gh auth status &> /dev/null; then
|
||||
print_error "GitHub CLI is not authenticated. Please run:"
|
||||
echo " gh auth login"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Get repository info
|
||||
REPO=$(gh repo view --json owner,name -q '.owner.login + "/" + .name')
|
||||
if [[ -z "$REPO" ]]; then
|
||||
print_error "Could not determine repository. Make sure you're in a GitHub repository."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
print_status "Working with repository: $REPO"
|
||||
|
||||
# Get all active workflows (both queued and in-progress)
|
||||
print_status "Fetching active workflows (queued and in-progress)..."
|
||||
QUEUED_WORKFLOWS=$(gh run list --status queued --json databaseId,displayTitle,headBranch,status --limit 100)
|
||||
IN_PROGRESS_WORKFLOWS=$(gh run list --status in_progress --json databaseId,displayTitle,headBranch,status --limit 100)
|
||||
|
||||
# Combine both lists
|
||||
ALL_WORKFLOWS=$(echo "$QUEUED_WORKFLOWS $IN_PROGRESS_WORKFLOWS" | jq -s 'add | unique_by(.databaseId)')
|
||||
|
||||
if [[ "$ALL_WORKFLOWS" == "[]" ]]; then
|
||||
print_status "No active workflows found."
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Parse and display active workflows
|
||||
echo
|
||||
print_warning "Found active workflows:"
|
||||
echo "$ALL_WORKFLOWS" | jq -r '.[] | " - \(.displayTitle) (Branch: \(.headBranch), Status: \(.status), ID: \(.databaseId))"'
|
||||
|
||||
echo
|
||||
read -p "Do you want to cancel ALL these workflows? (y/N): " -n 1 -r
|
||||
echo
|
||||
|
||||
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
|
||||
print_status "Cancelled by user."
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Cancel each workflow
|
||||
print_status "Cancelling workflows..."
|
||||
CANCELLED_COUNT=0
|
||||
FAILED_COUNT=0
|
||||
|
||||
while IFS= read -r WORKFLOW_ID; do
|
||||
if [[ -n "$WORKFLOW_ID" ]]; then
|
||||
print_status "Cancelling workflow ID: $WORKFLOW_ID"
|
||||
if gh run cancel "$WORKFLOW_ID" 2>/dev/null; then
|
||||
((CANCELLED_COUNT++))
|
||||
else
|
||||
print_error "Failed to cancel workflow ID: $WORKFLOW_ID"
|
||||
((FAILED_COUNT++))
|
||||
fi
|
||||
fi
|
||||
done < <(echo "$ALL_WORKFLOWS" | jq -r '.[].databaseId')
|
||||
|
||||
echo
|
||||
print_status "Summary:"
|
||||
echo " - Cancelled: $CANCELLED_COUNT workflows"
|
||||
if [[ $FAILED_COUNT -gt 0 ]]; then
|
||||
echo " - Failed: $FAILED_COUNT workflows"
|
||||
fi
|
||||
|
||||
print_status "Done!"
|
||||
|
||||
# Optional: Show remaining active workflows
|
||||
echo
|
||||
print_status "Checking for any remaining active workflows..."
|
||||
REMAINING_QUEUED=$(gh run list --status queued --json databaseId --limit 10)
|
||||
REMAINING_IN_PROGRESS=$(gh run list --status in_progress --json databaseId --limit 10)
|
||||
REMAINING_ALL=$(echo "$REMAINING_QUEUED $REMAINING_IN_PROGRESS" | jq -s 'add | unique_by(.databaseId)')
|
||||
|
||||
if [[ "$REMAINING_ALL" == "[]" ]]; then
|
||||
print_status "All workflows successfully cancelled."
|
||||
else
|
||||
REMAINING_COUNT=$(echo "$REMAINING_ALL" | jq '. | length')
|
||||
print_warning "Still $REMAINING_COUNT workflows active (may take a moment to update status)"
|
||||
fi
|
||||
@@ -87,9 +87,6 @@
|
||||
</screenshots>
|
||||
|
||||
<releases>
|
||||
<release version="2.7.13" date="2025-10-11">
|
||||
<url type="details">https://github.com/meshtastic/firmware/releases?q=tag%3Av2.7.13</url>
|
||||
</release>
|
||||
<release version="2.7.12" date="2025-10-01">
|
||||
<url type="details">https://github.com/meshtastic/firmware/releases?q=tag%3Av2.7.12</url>
|
||||
</release>
|
||||
|
||||
@@ -1 +1 @@
|
||||
2.6.7
|
||||
2.6.6
|
||||
6
debian/changelog
vendored
6
debian/changelog
vendored
@@ -1,9 +1,3 @@
|
||||
meshtasticd (2.7.13.0) unstable; urgency=medium
|
||||
|
||||
* Version 2.7.13
|
||||
|
||||
-- GitHub Actions <github-actions[bot]@users.noreply.github.com> Sat, 11 Oct 2025 15:27:28 +0000
|
||||
|
||||
meshtasticd (2.7.12.0) unstable; urgency=medium
|
||||
|
||||
[ Austin Lane ]
|
||||
|
||||
@@ -120,7 +120,7 @@ lib_deps =
|
||||
[device-ui_base]
|
||||
lib_deps =
|
||||
# renovate: datasource=git-refs depName=meshtastic/device-ui packageName=https://github.com/meshtastic/device-ui gitBranch=master
|
||||
https://github.com/meshtastic/device-ui/archive/19b7855e9a1d9deff37391659ca7194e4ef57c43.zip
|
||||
https://github.com/meshtastic/device-ui/archive/6d8cc228298a1ecd9913aed757187e9527c1facc.zip
|
||||
|
||||
; Common libs for environmental measurements in telemetry module
|
||||
[environmental_base]
|
||||
@@ -164,7 +164,7 @@ lib_deps =
|
||||
# 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
|
||||
dfrobot/DFRobot_RTU@1.0.3
|
||||
# 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
|
||||
|
||||
Submodule protobufs updated: bf149bbdcc...a1b8c3d171
@@ -14,16 +14,16 @@ class NodeStatus : public Status
|
||||
CallbackObserver<NodeStatus, const NodeStatus *> statusObserver =
|
||||
CallbackObserver<NodeStatus, const NodeStatus *>(this, &NodeStatus::updateStatus);
|
||||
|
||||
uint16_t numOnline = 0;
|
||||
uint16_t numTotal = 0;
|
||||
uint8_t numOnline = 0;
|
||||
uint8_t numTotal = 0;
|
||||
|
||||
uint16_t lastNumTotal = 0;
|
||||
uint8_t lastNumTotal = 0;
|
||||
|
||||
public:
|
||||
bool forceUpdate = false;
|
||||
|
||||
NodeStatus() { statusType = STATUS_TYPE_NODE; }
|
||||
NodeStatus(uint16_t numOnline, uint16_t numTotal, bool forceUpdate = false) : Status()
|
||||
NodeStatus(uint8_t numOnline, uint8_t numTotal, bool forceUpdate = false) : Status()
|
||||
{
|
||||
this->forceUpdate = forceUpdate;
|
||||
this->numOnline = numOnline;
|
||||
@@ -34,11 +34,11 @@ class NodeStatus : public Status
|
||||
|
||||
void observe(Observable<const NodeStatus *> *source) { statusObserver.observe(source); }
|
||||
|
||||
uint16_t getNumOnline() const { return numOnline; }
|
||||
uint8_t getNumOnline() const { return numOnline; }
|
||||
|
||||
uint16_t getNumTotal() const { return numTotal; }
|
||||
uint8_t getNumTotal() const { return numTotal; }
|
||||
|
||||
uint16_t getLastNumTotal() const { return lastNumTotal; }
|
||||
uint8_t getLastNumTotal() const { return lastNumTotal; }
|
||||
|
||||
bool matches(const NodeStatus *newStatus) const
|
||||
{
|
||||
@@ -56,7 +56,7 @@ class NodeStatus : public Status
|
||||
numTotal = newStatus->getNumTotal();
|
||||
}
|
||||
if (isDirty || newStatus->forceUpdate) {
|
||||
LOG_DEBUG("Node status update: %u online, %u total", numOnline, numTotal);
|
||||
LOG_DEBUG("Node status update: %d online, %d total", numOnline, numTotal);
|
||||
onNewStatus.notifyObservers(this);
|
||||
}
|
||||
return 0;
|
||||
|
||||
@@ -562,7 +562,6 @@ class AnalogBatteryLevel : public HasBatteryLevel
|
||||
config.power.device_battery_ina_address) {
|
||||
if (!ina226Sensor.isInitialized())
|
||||
return ina226Sensor.runOnce() > 0;
|
||||
return ina226Sensor.isRunning();
|
||||
} else if (nodeTelemetrySensorsMap[meshtastic_TelemetrySensorType_INA260].first ==
|
||||
config.power.device_battery_ina_address) {
|
||||
if (!ina260Sensor.isInitialized())
|
||||
|
||||
@@ -126,9 +126,9 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#define TX_GAIN_LORA 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 10, 10, 9, 9, 8, 7
|
||||
#endif
|
||||
|
||||
#ifdef RAK13302
|
||||
#define NUM_PA_POINTS 22
|
||||
#define TX_GAIN_LORA 7, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 8
|
||||
#ifdef STATION_G2
|
||||
#define NUM_PA_POINTS 19
|
||||
#define TX_GAIN_LORA 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 19, 19, 18, 18
|
||||
#endif
|
||||
|
||||
// Default system gain to 0 if not defined
|
||||
|
||||
@@ -1,16 +0,0 @@
|
||||
#include "ScanI2CConsumer.h"
|
||||
#include <forward_list>
|
||||
|
||||
static std::forward_list<ScanI2CConsumer *> ScanI2CConsumers;
|
||||
|
||||
ScanI2CConsumer::ScanI2CConsumer()
|
||||
{
|
||||
ScanI2CConsumers.push_front(this);
|
||||
}
|
||||
|
||||
void ScanI2CCompleted(ScanI2C *i2cScanner)
|
||||
{
|
||||
for (ScanI2CConsumer *consumer : ScanI2CConsumers) {
|
||||
consumer->i2cScanFinished(i2cScanner);
|
||||
}
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "ScanI2C.h"
|
||||
#include <stddef.h>
|
||||
|
||||
class ScanI2CConsumer
|
||||
{
|
||||
public:
|
||||
ScanI2CConsumer();
|
||||
virtual void i2cScanFinished(ScanI2C *i2cScanner) = 0;
|
||||
};
|
||||
|
||||
void ScanI2CCompleted(ScanI2C *i2cScanner);
|
||||
@@ -378,8 +378,7 @@ void ScanI2CTwoWire::scanPort(I2CPort port, uint8_t *address, uint8_t asize)
|
||||
case SHT31_4x_ADDR: // same as OPT3001_ADDR_ALT
|
||||
case SHT31_4x_ADDR_ALT: // same as OPT3001_ADDR
|
||||
registerValue = getRegisterValue(ScanI2CTwoWire::RegisterLocation(addr, 0x89), 2);
|
||||
if (registerValue == 0x11a2 || registerValue == 0x11da || registerValue == 0x11f3 || registerValue == 0xe9c ||
|
||||
registerValue == 0xc8d) {
|
||||
if (registerValue == 0x11a2 || registerValue == 0x11da || registerValue == 0x11f3 || registerValue == 0xe9c || registerValue == 0xc8d) {
|
||||
type = SHT4X;
|
||||
logFoundDevice("SHT4X", (uint8_t)addr.address);
|
||||
} else if (getRegisterValue(ScanI2CTwoWire::RegisterLocation(addr, 0x7E), 2) == 0x5449) {
|
||||
@@ -581,7 +580,7 @@ void ScanI2CTwoWire::scanPort(I2CPort port)
|
||||
scanPort(port, nullptr, 0);
|
||||
}
|
||||
|
||||
TwoWire *ScanI2CTwoWire::fetchI2CBus(ScanI2C::DeviceAddress address)
|
||||
TwoWire *ScanI2CTwoWire::fetchI2CBus(ScanI2C::DeviceAddress address) const
|
||||
{
|
||||
if (address.port == ScanI2C::I2CPort::WIRE) {
|
||||
return &Wire;
|
||||
|
||||
@@ -23,12 +23,12 @@ class ScanI2CTwoWire : public ScanI2C
|
||||
|
||||
ScanI2C::FoundDevice find(ScanI2C::DeviceType) const override;
|
||||
|
||||
TwoWire *fetchI2CBus(ScanI2C::DeviceAddress) const;
|
||||
|
||||
bool exists(ScanI2C::DeviceType) const override;
|
||||
|
||||
size_t countDevices() const override;
|
||||
|
||||
static TwoWire *fetchI2CBus(ScanI2C::DeviceAddress);
|
||||
|
||||
protected:
|
||||
FoundDevice firstOfOrNONE(size_t, DeviceType[]) const override;
|
||||
|
||||
|
||||
@@ -240,9 +240,6 @@ GPS_RESPONSE GPS::getACK(const char *message, uint32_t waitMillis)
|
||||
buffer[bytesRead] = b;
|
||||
bytesRead++;
|
||||
if ((bytesRead == 767) || (b == '\r')) {
|
||||
#ifdef GPS_DEBUG
|
||||
LOG_DEBUG(debugmsg.c_str());
|
||||
#endif
|
||||
if (strnstr((char *)buffer, message, bytesRead) != nullptr) {
|
||||
#ifdef GPS_DEBUG
|
||||
LOG_DEBUG("Found: %s", message); // Log the found message
|
||||
@@ -250,6 +247,9 @@ GPS_RESPONSE GPS::getACK(const char *message, uint32_t waitMillis)
|
||||
return GNSS_RESPONSE_OK;
|
||||
} else {
|
||||
bytesRead = 0;
|
||||
#ifdef GPS_DEBUG
|
||||
LOG_DEBUG(debugmsg.c_str());
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -494,6 +494,17 @@ bool GPS::setup()
|
||||
if (!didSerialInit) {
|
||||
int msglen = 0;
|
||||
if (tx_gpio && gnssModel == GNSS_MODEL_UNKNOWN) {
|
||||
#ifdef TRACKER_T1000_E
|
||||
// add power up/down strategy, improve ag3335 detection success
|
||||
digitalWrite(PIN_GPS_EN, LOW);
|
||||
delay(500);
|
||||
digitalWrite(GPS_VRTC_EN, LOW);
|
||||
delay(1000);
|
||||
digitalWrite(GPS_VRTC_EN, HIGH);
|
||||
delay(500);
|
||||
digitalWrite(PIN_GPS_EN, HIGH);
|
||||
delay(1000);
|
||||
#endif
|
||||
if (probeTries < GPS_PROBETRIES) {
|
||||
gnssModel = probe(serialSpeeds[speedSelect]);
|
||||
if (gnssModel == GNSS_MODEL_UNKNOWN) {
|
||||
@@ -1275,24 +1286,6 @@ GnssModel_t GPS::probe(int serialSpeed)
|
||||
memset(&ublox_info, 0, sizeof(ublox_info));
|
||||
delay(100);
|
||||
|
||||
#if defined(PIN_GPS_RESET) && PIN_GPS_RESET != -1
|
||||
digitalWrite(PIN_GPS_RESET, GPS_RESET_MODE); // assert for 10ms
|
||||
delay(10);
|
||||
digitalWrite(PIN_GPS_RESET, !GPS_RESET_MODE);
|
||||
|
||||
// attempt to detect the chip based on boot messages
|
||||
std::vector<ChipInfo> passive_detect = {
|
||||
{"AG3335", "$PAIR021,AG3335", GNSS_MODEL_AG3335},
|
||||
{"AG3352", "$PAIR021,AG3352", GNSS_MODEL_AG3352},
|
||||
{"RYS3520", "$PAIR021,REYAX_RYS3520_V2", GNSS_MODEL_AG3352},
|
||||
{"UC6580", "UC6580", GNSS_MODEL_UC6580},
|
||||
// as L76K is sort of a last ditch effort, we won't attempt to detect it by startup messages for now.
|
||||
/*{"L76K", "SW=URANUS", GNSS_MODEL_MTK}*/};
|
||||
GnssModel_t detectedDriver = getProbeResponse(500, passive_detect, serialSpeed);
|
||||
if (detectedDriver != GNSS_MODEL_UNKNOWN) {
|
||||
return detectedDriver;
|
||||
}
|
||||
#endif
|
||||
// Close all NMEA sentences, valid for L76K, ATGM336H (and likely other AT6558 devices)
|
||||
_serial_gps->write("$PCAS03,0,0,0,0,0,0,0,0,0,0,,,0,0*02\r\n");
|
||||
delay(20);
|
||||
@@ -1491,12 +1484,12 @@ GnssModel_t GPS::getProbeResponse(unsigned long timeout, const std::vector<ChipI
|
||||
}
|
||||
|
||||
if (c == ',' || (responseLen >= 2 && response[responseLen - 2] == '\r' && response[responseLen - 1] == '\n')) {
|
||||
#ifdef GPS_DEBUG
|
||||
LOG_DEBUG(response);
|
||||
#endif
|
||||
// check if we can see our chips
|
||||
for (const auto &chipInfo : responseMap) {
|
||||
if (strstr(response, chipInfo.detectionString.c_str()) != nullptr) {
|
||||
#ifdef GPS_DEBUG
|
||||
LOG_DEBUG(response);
|
||||
#endif
|
||||
LOG_INFO("%s detected", chipInfo.chipName.c_str());
|
||||
delete[] response; // Cleanup before return
|
||||
return chipInfo.driver;
|
||||
@@ -1504,9 +1497,6 @@ GnssModel_t GPS::getProbeResponse(unsigned long timeout, const std::vector<ChipI
|
||||
}
|
||||
}
|
||||
if (responseLen >= 2 && response[responseLen - 2] == '\r' && response[responseLen - 1] == '\n') {
|
||||
#ifdef GPS_DEBUG
|
||||
LOG_DEBUG(response);
|
||||
#endif
|
||||
// Reset the response buffer for the next potential message
|
||||
responseLen = 0;
|
||||
response[0] = '\0';
|
||||
@@ -1593,6 +1583,8 @@ GPS *GPS::createGps()
|
||||
|
||||
#ifdef PIN_GPS_RESET
|
||||
pinMode(PIN_GPS_RESET, OUTPUT);
|
||||
digitalWrite(PIN_GPS_RESET, GPS_RESET_MODE); // assert for 10ms
|
||||
delay(10);
|
||||
digitalWrite(PIN_GPS_RESET, !GPS_RESET_MODE);
|
||||
#endif
|
||||
|
||||
|
||||
@@ -310,7 +310,7 @@ RTCSetResult perhapsSetRTC(RTCQuality q, struct tm &t)
|
||||
#ifdef BUILD_EPOCH
|
||||
if (tv.tv_sec < BUILD_EPOCH) {
|
||||
if (Throttle::isWithinTimespanMs(lastTimeValidationWarning, TIME_VALIDATION_WARNING_INTERVAL_MS) == false) {
|
||||
LOG_WARN("Ignore time (%lu) before build epoch (%lu)!", printableEpoch, BUILD_EPOCH);
|
||||
LOG_WARN("Ignore time (%ld) before build epoch (%ld)!", printableEpoch, BUILD_EPOCH);
|
||||
lastTimeValidationWarning = millis();
|
||||
}
|
||||
return RTCSetResultInvalidTime;
|
||||
@@ -319,7 +319,7 @@ RTCSetResult perhapsSetRTC(RTCQuality q, struct tm &t)
|
||||
// Calculate max allowed time safely to avoid overflow in logging
|
||||
uint64_t maxAllowedTime = (uint64_t)BUILD_EPOCH + FORTY_YEARS;
|
||||
uint32_t maxAllowedPrintable = (maxAllowedTime > UINT32_MAX) ? UINT32_MAX : (uint32_t)maxAllowedTime;
|
||||
LOG_WARN("Ignore time (%lu) too far in the future (build epoch: %lu, max allowed: %lu)!", printableEpoch,
|
||||
LOG_WARN("Ignore time (%ld) too far in the future (build epoch: %ld, max allowed: %ld)!", printableEpoch,
|
||||
(uint32_t)BUILD_EPOCH, maxAllowedPrintable);
|
||||
lastTimeValidationWarning = millis();
|
||||
}
|
||||
|
||||
@@ -1490,7 +1490,7 @@ int Screen::handleTextMessage(const meshtastic_MeshPacket *packet)
|
||||
strcpy(banner, "Alert Received");
|
||||
}
|
||||
screen->showSimpleBanner(banner, 3000);
|
||||
} else if (!channel.settings.has_module_settings || !channel.settings.module_settings.is_muted) {
|
||||
} else if (!channel.settings.mute) {
|
||||
if (longName && longName[0]) {
|
||||
#if defined(M5STACK_UNITC6L)
|
||||
strcpy(banner, "New Message");
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
#include "configuration.h"
|
||||
#if HAS_SCREEN
|
||||
#include "graphics/SharedUIDisplay.h"
|
||||
#include "RTC.h"
|
||||
#include "graphics/ScreenFonts.h"
|
||||
#include "graphics/SharedUIDisplay.h"
|
||||
#include "graphics/draw/UIRenderer.h"
|
||||
#include "main.h"
|
||||
#include "meshtastic/config.pb.h"
|
||||
@@ -425,4 +423,3 @@ std::string sanitizeString(const std::string &input)
|
||||
}
|
||||
|
||||
} // namespace graphics
|
||||
#endif
|
||||
@@ -1,6 +1,5 @@
|
||||
#include "configuration.h"
|
||||
#if HAS_SCREEN
|
||||
#include "VirtualKeyboard.h"
|
||||
#include "configuration.h"
|
||||
#include "graphics/Screen.h"
|
||||
#include "graphics/ScreenFonts.h"
|
||||
#include "graphics/SharedUIDisplay.h"
|
||||
@@ -737,4 +736,3 @@ bool VirtualKeyboard::isTimedOut() const
|
||||
}
|
||||
|
||||
} // namespace graphics
|
||||
#endif
|
||||
@@ -1,5 +1,3 @@
|
||||
#include "configuration.h"
|
||||
#if HAS_SCREEN
|
||||
#include "CompassRenderer.h"
|
||||
#include "NodeDB.h"
|
||||
#include "UIRenderer.h"
|
||||
@@ -137,4 +135,3 @@ uint16_t getCompassDiam(uint32_t displayWidth, uint32_t displayHeight)
|
||||
|
||||
} // namespace CompassRenderer
|
||||
} // namespace graphics
|
||||
#endif
|
||||
@@ -762,31 +762,6 @@ void menuHandler::nodeListMenu()
|
||||
screen->showOverlayBanner(bannerOptions);
|
||||
}
|
||||
|
||||
void menuHandler::nodeNameLengthMenu()
|
||||
{
|
||||
enum OptionsNumbers { Back, Long, Short };
|
||||
static const char *optionsArray[] = {"Back", "Long", "Short"};
|
||||
BannerOverlayOptions bannerOptions;
|
||||
bannerOptions.message = "Node Name Length";
|
||||
bannerOptions.optionsArrayPtr = optionsArray;
|
||||
bannerOptions.optionsCount = 3;
|
||||
bannerOptions.bannerCallback = [](int selected) -> void {
|
||||
if (selected == Long) {
|
||||
// Set names to long
|
||||
LOG_INFO("Setting names to long");
|
||||
config.display.use_long_node_name = true;
|
||||
} else if (selected == Short) {
|
||||
// Set names to short
|
||||
LOG_INFO("Setting names to short");
|
||||
config.display.use_long_node_name = false;
|
||||
} else if (selected == Back) {
|
||||
menuQueue = screen_options_menu;
|
||||
screen->runNow();
|
||||
}
|
||||
};
|
||||
screen->showOverlayBanner(bannerOptions);
|
||||
}
|
||||
|
||||
void menuHandler::resetNodeDBMenu()
|
||||
{
|
||||
static const char *optionsArray[] = {"Back", "Confirm"};
|
||||
@@ -1329,16 +1304,11 @@ void menuHandler::screenOptionsMenu()
|
||||
hasSupportBrightness = false;
|
||||
#endif
|
||||
|
||||
enum optionsNumbers { Back, NodeNameLength, Brightness, ScreenColor };
|
||||
static const char *optionsArray[5] = {"Back"};
|
||||
static int optionsEnumArray[5] = {Back};
|
||||
enum optionsNumbers { Back, Brightness, ScreenColor };
|
||||
static const char *optionsArray[4] = {"Back"};
|
||||
static int optionsEnumArray[4] = {Back};
|
||||
int options = 1;
|
||||
|
||||
#if defined(T_DECK) || defined(T_LORA_PAGER)
|
||||
optionsArray[options] = "Show Long/Short Name";
|
||||
optionsEnumArray[options++] = NodeNameLength;
|
||||
#endif
|
||||
|
||||
// Only show brightness for B&W displays
|
||||
if (hasSupportBrightness) {
|
||||
optionsArray[options] = "Brightness";
|
||||
@@ -1363,9 +1333,6 @@ void menuHandler::screenOptionsMenu()
|
||||
} else if (selected == ScreenColor) {
|
||||
menuHandler::menuQueue = menuHandler::tftcolormenupicker;
|
||||
screen->runNow();
|
||||
} else if (selected == NodeNameLength) {
|
||||
menuHandler::menuQueue = menuHandler::node_name_length_menu;
|
||||
screen->runNow();
|
||||
} else {
|
||||
menuQueue = system_base_menu;
|
||||
screen->runNow();
|
||||
@@ -1464,8 +1431,6 @@ void menuHandler::FrameToggles_menu()
|
||||
lora,
|
||||
clock,
|
||||
show_favorites,
|
||||
show_telemetry,
|
||||
show_power,
|
||||
enumEnd
|
||||
};
|
||||
static const char *optionsArray[enumEnd] = {"Finish"};
|
||||
@@ -1504,12 +1469,6 @@ void menuHandler::FrameToggles_menu()
|
||||
optionsArray[options] = screen->isFrameHidden("show_favorites") ? "Show Favorites" : "Hide Favorites";
|
||||
optionsEnumArray[options++] = show_favorites;
|
||||
|
||||
optionsArray[options] = moduleConfig.telemetry.environment_screen_enabled ? "Hide Telemetry" : "Show Telemetry";
|
||||
optionsEnumArray[options++] = show_telemetry;
|
||||
|
||||
optionsArray[options] = moduleConfig.telemetry.power_screen_enabled ? "Hide Power" : "Show Power";
|
||||
optionsEnumArray[options++] = show_power;
|
||||
|
||||
BannerOverlayOptions bannerOptions;
|
||||
bannerOptions.message = "Show/Hide Frames";
|
||||
bannerOptions.optionsArrayPtr = optionsArray;
|
||||
@@ -1564,14 +1523,6 @@ void menuHandler::FrameToggles_menu()
|
||||
screen->toggleFrameVisibility("show_favorites");
|
||||
menuHandler::menuQueue = menuHandler::FrameToggles;
|
||||
screen->runNow();
|
||||
} else if (selected == show_telemetry) {
|
||||
moduleConfig.telemetry.environment_screen_enabled = !moduleConfig.telemetry.environment_screen_enabled;
|
||||
menuHandler::menuQueue = menuHandler::FrameToggles;
|
||||
screen->runNow();
|
||||
} else if (selected == show_power) {
|
||||
moduleConfig.telemetry.power_screen_enabled = !moduleConfig.telemetry.power_screen_enabled;
|
||||
menuHandler::menuQueue = menuHandler::FrameToggles;
|
||||
screen->runNow();
|
||||
}
|
||||
};
|
||||
screen->showOverlayBanner(bannerOptions);
|
||||
@@ -1643,9 +1594,6 @@ void menuHandler::handleMenuSwitch(OLEDDisplay *display)
|
||||
case brightness_picker:
|
||||
BrightnessPickerMenu();
|
||||
break;
|
||||
case node_name_length_menu:
|
||||
nodeNameLengthMenu();
|
||||
break;
|
||||
case reboot_menu:
|
||||
rebootMenu();
|
||||
break;
|
||||
|
||||
@@ -43,7 +43,6 @@ class menuHandler
|
||||
key_verification_final_prompt,
|
||||
trace_route_menu,
|
||||
throttle_message,
|
||||
node_name_length_menu,
|
||||
FrameToggles
|
||||
};
|
||||
static screenMenus menuQueue;
|
||||
@@ -86,7 +85,6 @@ class menuHandler
|
||||
static void notificationsMenu();
|
||||
static void screenOptionsMenu();
|
||||
static void powerMenu();
|
||||
static void nodeNameLengthMenu();
|
||||
static void FrameToggles_menu();
|
||||
static void textMessageMenu();
|
||||
|
||||
|
||||
@@ -55,32 +55,26 @@ static int scrollIndex = 0;
|
||||
|
||||
const char *getSafeNodeName(meshtastic_NodeInfoLite *node)
|
||||
{
|
||||
const char *name = NULL;
|
||||
static char nodeName[16] = "?";
|
||||
if (config.display.use_long_node_name == true) {
|
||||
if (node->has_user && strlen(node->user.long_name) > 0) {
|
||||
name = node->user.long_name;
|
||||
if (node->has_user && strlen(node->user.short_name) > 0) {
|
||||
bool valid = true;
|
||||
const char *name = node->user.short_name;
|
||||
for (size_t i = 0; i < strlen(name); i++) {
|
||||
uint8_t c = (uint8_t)name[i];
|
||||
if (c < 32 || c > 126) {
|
||||
valid = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (valid) {
|
||||
strncpy(nodeName, name, sizeof(nodeName) - 1);
|
||||
nodeName[sizeof(nodeName) - 1] = '\0';
|
||||
} else {
|
||||
snprintf(nodeName, sizeof(nodeName), "(%04X)", (uint16_t)(node->num & 0xFFFF));
|
||||
}
|
||||
} else {
|
||||
if (node->has_user && strlen(node->user.short_name) > 0) {
|
||||
name = node->user.short_name;
|
||||
} else {
|
||||
snprintf(nodeName, sizeof(nodeName), "(%04X)", (uint16_t)(node->num & 0xFFFF));
|
||||
}
|
||||
}
|
||||
|
||||
// Use sanitizeString() function and copy directly into nodeName
|
||||
std::string sanitized_name = sanitizeString(name ? name : "");
|
||||
|
||||
if (!sanitized_name.empty()) {
|
||||
strncpy(nodeName, sanitized_name.c_str(), sizeof(nodeName) - 1);
|
||||
nodeName[sizeof(nodeName) - 1] = '\0';
|
||||
} else {
|
||||
snprintf(nodeName, sizeof(nodeName), "(%04X)", (uint16_t)(node->num & 0xFFFF));
|
||||
}
|
||||
|
||||
return nodeName;
|
||||
}
|
||||
|
||||
|
||||
@@ -563,7 +563,6 @@ void UIRenderer::drawDeviceFocused(OLEDDisplay *display, OLEDDisplayUiState *sta
|
||||
display->setTextAlignment(TEXT_ALIGN_LEFT);
|
||||
display->setFont(FONT_SMALL);
|
||||
int line = 1;
|
||||
meshtastic_NodeInfoLite *ourNode = nodeDB->getMeshNode(nodeDB->getNodeNum());
|
||||
|
||||
// === Header ===
|
||||
#if defined(M5STACK_UNITC6L)
|
||||
@@ -741,6 +740,7 @@ void UIRenderer::drawDeviceFocused(OLEDDisplay *display, OLEDDisplayUiState *sta
|
||||
int yOffset = (isHighResolution) ? 0 : 5;
|
||||
std::string longNameStr;
|
||||
|
||||
meshtastic_NodeInfoLite *ourNode = nodeDB->getMeshNode(nodeDB->getNodeNum());
|
||||
if (ourNode && ourNode->has_user && strlen(ourNode->user.long_name) > 0) {
|
||||
longNameStr = sanitizeString(ourNode->user.long_name);
|
||||
}
|
||||
@@ -1000,7 +1000,24 @@ void UIRenderer::drawCompassAndLocationScreen(OLEDDisplay *display, OLEDDisplayU
|
||||
const char *displayLine = ""; // Initialize to empty string by default
|
||||
meshtastic_NodeInfoLite *ourNode = nodeDB->getMeshNode(nodeDB->getNodeNum());
|
||||
|
||||
if (config.position.gps_mode != meshtastic_Config_PositionConfig_GpsMode_ENABLED) {
|
||||
bool usePhoneGPS = (ourNode && nodeDB->hasValidPosition(ourNode) &&
|
||||
config.position.gps_mode != meshtastic_Config_PositionConfig_GpsMode_ENABLED);
|
||||
|
||||
if (usePhoneGPS) {
|
||||
// Phone-provided GPS is active
|
||||
displayLine = "Phone GPS";
|
||||
int yOffset = (isHighResolution) ? 3 : 1;
|
||||
if (isHighResolution) {
|
||||
NodeListRenderer::drawScaledXBitmap16x16(x, getTextPositions(display)[line] + yOffset - 5, imgSatellite_width,
|
||||
imgSatellite_height, imgSatellite, display);
|
||||
} else {
|
||||
display->drawXbm(x + 1, getTextPositions(display)[line] + yOffset, imgSatellite_width, imgSatellite_height,
|
||||
imgSatellite);
|
||||
}
|
||||
int xOffset = (isHighResolution) ? 6 : 0;
|
||||
display->drawString(x + 11 + xOffset, getTextPositions(display)[line++], displayLine);
|
||||
} else if (config.position.gps_mode != meshtastic_Config_PositionConfig_GpsMode_ENABLED) {
|
||||
// GPS disabled / not present
|
||||
if (config.position.fixed_position) {
|
||||
displayLine = "Fixed GPS";
|
||||
} else {
|
||||
@@ -1091,7 +1108,9 @@ void UIRenderer::drawCompassAndLocationScreen(OLEDDisplay *display, OLEDDisplayU
|
||||
|
||||
// === Final Row: Altitude ===
|
||||
char altitudeLine[32] = {0};
|
||||
int32_t alt = geoCoord.getAltitude();
|
||||
int32_t alt = (strcmp(displayLine, "Phone GPS") == 0 && ourNode && nodeDB->hasValidPosition(ourNode))
|
||||
? ourNode->position.altitude
|
||||
: geoCoord.getAltitude();
|
||||
if (config.display.units == meshtastic_Config_DisplayConfig_DisplayUnits_IMPERIAL) {
|
||||
snprintf(altitudeLine, sizeof(altitudeLine), "Alt: %.0fft", alt * METERS_TO_FEET);
|
||||
} else {
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
#include "configuration.h"
|
||||
#if HAS_SCREEN
|
||||
#include "emotes.h"
|
||||
|
||||
namespace graphics
|
||||
@@ -18,8 +16,6 @@ const Emote emotes[] = {
|
||||
{"\U0001F642", Slightly_Smiling, Slightly_Smiling_width, Slightly_Smiling_height}, // 🙂 Slightly Smiling Face
|
||||
{"\U0001F609", Winking_Face, Winking_Face_width, Winking_Face_height}, // 😉 Winking Face
|
||||
{"\U0001F601", Grinning_Smiling_Eyes, Grinning_Smiling_Eyes_width, Grinning_Smiling_Eyes_height}, // 😁 Grinning Smiling Eyes
|
||||
{"\U0001F60D", Heart_eyes, Heart_eyes_width, Heart_eyes_height}, // 😍 Heart Eyes
|
||||
{"\U0001F970", heart_smile, heart_smile_width, heart_smile_height}, // 🥰 Smiling Face with Hearts
|
||||
|
||||
// --- Question/Alert ---
|
||||
{"\u2753", question, question_width, question_height}, // ❓ Question Mark
|
||||
@@ -32,15 +28,11 @@ const Emote emotes[] = {
|
||||
{"\U0001F605", haha, haha_width, haha_height}, // 😅 Smiling with Sweat
|
||||
{"\U0001F604", Grinning_SmilingEyes2, Grinning_SmilingEyes2_width,
|
||||
Grinning_SmilingEyes2_height}, // 😄 Grinning Face with Smiling Eyes
|
||||
{"\U0001F62D", Loudly_Crying_Face, Loudly_Crying_Face_width, Loudly_Crying_Face_height}, // 😭 Loudly Crying Face
|
||||
|
||||
// --- Gestures and People ---
|
||||
{"\U0001F44B", wave_icon, wave_icon_width, wave_icon_height}, // 👋 Waving Hand
|
||||
{"\u270C\uFE0F", peace_sign, peace_sign_width, peace_sign_height}, // ✌️ Victory Hand
|
||||
{"\U0001F596", vulcan_salute, vulcan_salute_width, vulcan_salute_height}, // 🖖 Vulcan Salute
|
||||
{"\U0001F64F", Praying, Praying_width, Praying_height}, // 🙏 Praying Hands
|
||||
{"\U0001F920", cowboy, cowboy_width, cowboy_height}, // 🤠 Cowboy Hat Face
|
||||
{"\U0001F3A7", deadmau5, deadmau5_width, deadmau5_height}, // 🎧 Headphones
|
||||
{"\U0001F44B", wave_icon, wave_icon_width, wave_icon_height}, // 👋 Waving Hand
|
||||
{"\U0001F920", cowboy, cowboy_width, cowboy_height}, // 🤠 Cowboy Hat Face
|
||||
{"\U0001F3A7", deadmau5, deadmau5_width, deadmau5_height}, // 🎧 Headphones
|
||||
|
||||
// --- Weather ---
|
||||
{"\u2600", sun, sun_width, sun_height}, // ☀ Sun (without variation selector)
|
||||
@@ -51,12 +43,8 @@ const Emote emotes[] = {
|
||||
|
||||
// --- Misc Faces ---
|
||||
{"\U0001F608", devil, devil_width, devil_height}, // 😈 Smiling Face with Horns
|
||||
{"\U0001F921", clown, clown_width, clown_height}, // 🤡 Clown Face
|
||||
{"\U0001F916", robo, robo_width, robo_height}, // 🤖 Robot Face
|
||||
|
||||
// --- Hearts (Multiple Unicode Aliases) ---
|
||||
{"\u2665", heart, heart_width, heart_height}, // ♥ Black Heart Suit
|
||||
{"\u2665\uFE0F", heart, heart_width, heart_height}, // ♥️ Black Heart Suit (emoji presentation)
|
||||
{"\u2764\uFE0F", heart, heart_width, heart_height}, // ❤️ Red Heart
|
||||
{"\U0001F9E1", heart, heart_width, heart_height}, // 🧡 Orange Heart
|
||||
{"\U00002763", heart, heart_width, heart_height}, // ❣ Heart Exclamation
|
||||
@@ -67,167 +55,223 @@ const Emote emotes[] = {
|
||||
{"\U0001F498", heart, heart_width, heart_height}, // 💘 Heart with Arrow
|
||||
|
||||
// --- Objects ---
|
||||
{"\U0001F4A9", poo, poo_width, poo_height}, // 💩 Pile of Poo
|
||||
{"\U0001F514", bell_icon, bell_icon_width, bell_icon_height}, // 🔔 Bell
|
||||
{"\U0001F36A", cookie, cookie_width, cookie_height}, // 🍪 Cookie
|
||||
{"\U0001F525", Fire, Fire_width, Fire_height}, // 🔥 Fire
|
||||
{"\u2728", Sparkles, Sparkles_width, Sparkles_height}, // ✨ Sparkles
|
||||
{"\U0001F573\uFE0F", hole, hole_width, hole_height}, // 🕳️ Hole
|
||||
{"\U0001F3B3", bowling, bowling_width, bowling_height} // 🎳 Bowling
|
||||
{"\U0001F4A9", poo, poo_width, poo_height}, // 💩 Pile of Poo
|
||||
{"\U0001F514", bell_icon, bell_icon_width, bell_icon_height} // 🔔 Bell
|
||||
#endif
|
||||
};
|
||||
|
||||
const int numEmotes = sizeof(emotes) / sizeof(emotes[0]);
|
||||
|
||||
#ifndef EXCLUDE_EMOJI
|
||||
const unsigned char thumbup[] PROGMEM = {0x00, 0x03, 0x80, 0x04, 0x80, 0x04, 0x40, 0x04, 0x20, 0x02, 0x18,
|
||||
0x02, 0x06, 0x3F, 0x06, 0x40, 0x06, 0x70, 0x06, 0x40, 0x06, 0x70,
|
||||
0x06, 0x40, 0x06, 0x30, 0x08, 0x20, 0xF0, 0x1F, 0x00, 0x00};
|
||||
const unsigned char thumbup[] PROGMEM = {
|
||||
0x00, 0x1C, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x80, 0x09, 0x00, 0x00,
|
||||
0xC0, 0x08, 0x00, 0x00, 0x40, 0x08, 0x00, 0x00, 0x20, 0x04, 0x00, 0x00, 0x10, 0x04, 0x00, 0x00, 0x18, 0x02, 0x00, 0x00,
|
||||
0x0C, 0xCE, 0x7F, 0x00, 0x04, 0x20, 0x80, 0x00, 0x02, 0x20, 0x80, 0x00, 0x02, 0x60, 0xC0, 0x00, 0x01, 0xF8, 0xFF, 0x01,
|
||||
0x01, 0x08, 0x00, 0x01, 0x01, 0x08, 0x00, 0x01, 0x01, 0xF8, 0xFF, 0x00, 0x01, 0x10, 0x80, 0x00, 0x01, 0x18, 0x80, 0x00,
|
||||
0x02, 0x30, 0xC0, 0x00, 0x06, 0xE0, 0x3F, 0x00, 0x0C, 0x20, 0x30, 0x00, 0x38, 0x20, 0x10, 0x00, 0xE0, 0xCF, 0x1F, 0x00,
|
||||
};
|
||||
|
||||
const unsigned char thumbdown[] PROGMEM = {0xF0, 0x1F, 0x08, 0x20, 0x06, 0x30, 0x06, 0x40, 0x06, 0x70, 0x06,
|
||||
0x40, 0x06, 0x70, 0x06, 0x40, 0x06, 0x3F, 0x18, 0x02, 0x20, 0x02,
|
||||
0x40, 0x04, 0x80, 0x04, 0x80, 0x04, 0x00, 0x03, 0x00, 0x00};
|
||||
const unsigned char thumbdown[] PROGMEM = {
|
||||
0xE0, 0xCF, 0x1F, 0x00, 0x38, 0x20, 0x10, 0x00, 0x0C, 0x20, 0x30, 0x00, 0x06, 0xE0, 0x3F, 0x00, 0x02, 0x30, 0xC0, 0x00,
|
||||
0x01, 0x18, 0x80, 0x00, 0x01, 0x10, 0x80, 0x00, 0x01, 0xF8, 0xFF, 0x00, 0x01, 0x08, 0x00, 0x01, 0x01, 0x08, 0x00, 0x01,
|
||||
0x01, 0xF8, 0xFF, 0x01, 0x02, 0x60, 0xC0, 0x00, 0x02, 0x20, 0x80, 0x00, 0x04, 0x20, 0x80, 0x00, 0x0C, 0xCE, 0x7F, 0x00,
|
||||
0x18, 0x02, 0x00, 0x00, 0x10, 0x04, 0x00, 0x00, 0x20, 0x04, 0x00, 0x00, 0x40, 0x08, 0x00, 0x00, 0xC0, 0x08, 0x00, 0x00,
|
||||
0x80, 0x09, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x1C, 0x00, 0x00,
|
||||
};
|
||||
|
||||
const unsigned char Smiling_Eyes[] PROGMEM = {0x00, 0x00, 0xE0, 0x07, 0x18, 0x18, 0x04, 0x20, 0x24, 0x24, 0x52,
|
||||
0x4A, 0x02, 0x40, 0x02, 0x40, 0x22, 0x44, 0x22, 0x44, 0xC2, 0x43,
|
||||
0x04, 0x20, 0x04, 0x20, 0x18, 0x18, 0xE0, 0x07, 0x00, 0x00};
|
||||
const unsigned char Smiling_Eyes[] PROGMEM = {
|
||||
0x00, 0xf8, 0x03, 0xc0, 0x00, 0xfe, 0x0f, 0xc0, 0x80, 0xff, 0x3f, 0xc0, 0xc0, 0xff, 0xff, 0xc0, 0xe0, 0xff, 0xff, 0xc1,
|
||||
0xf0, 0xff, 0xff, 0xc3, 0xf8, 0xff, 0xff, 0xc7, 0xf8, 0xff, 0xff, 0xcf, 0xfc, 0xff, 0xff, 0xcf, 0xfc, 0xff, 0xff, 0xcf,
|
||||
0x7e, 0xf8, 0xc3, 0xdf, 0x3e, 0xf0, 0x81, 0xdf, 0xbf, 0xf7, 0xbd, 0xff, 0xff, 0xff, 0xff, 0xff, 0x9f, 0xff, 0x3f, 0xff,
|
||||
0x6f, 0xff, 0xdf, 0xfe, 0x6f, 0xff, 0xdf, 0xfe, 0x9f, 0xff, 0x3f, 0xff, 0xfe, 0xff, 0xff, 0xdf, 0x7e, 0xff, 0xdf, 0xdf,
|
||||
0x7c, 0xff, 0xdf, 0xcf, 0xfc, 0xfe, 0xef, 0xcf, 0xf8, 0xf9, 0xf7, 0xc7, 0xf8, 0x03, 0xf8, 0xc7, 0xf0, 0xff, 0xff, 0xc3,
|
||||
0xe0, 0xff, 0xff, 0xc1, 0xc0, 0xff, 0xff, 0xc0, 0x80, 0xff, 0x3f, 0xc0, 0x00, 0xfe, 0x0f, 0xc0, 0x00, 0xf8, 0x07, 0xc0};
|
||||
|
||||
const unsigned char Grinning[] PROGMEM = {0x00, 0x00, 0xE0, 0x07, 0x18, 0x18, 0x04, 0x20, 0x44, 0x22, 0x42,
|
||||
0x42, 0x02, 0x40, 0x02, 0x40, 0xF2, 0x4F, 0x12, 0x48, 0x22, 0x44,
|
||||
0xC4, 0x23, 0x04, 0x20, 0x18, 0x18, 0xE0, 0x07, 0x00, 0x00};
|
||||
const unsigned char Grinning[] PROGMEM = {
|
||||
0x00, 0xf8, 0x03, 0xc0, 0x00, 0xfe, 0x0f, 0xc0, 0x80, 0xff, 0x3f, 0xc0, 0xc0, 0xff, 0xff, 0xc0, 0xe0, 0xff, 0xff, 0xc1,
|
||||
0xf0, 0xff, 0xff, 0xc3, 0xf8, 0xff, 0xff, 0xc7, 0xf8, 0xff, 0xff, 0xcf, 0xfc, 0xf9, 0xf3, 0xcf, 0xfc, 0xf0, 0xe1, 0xcf,
|
||||
0xfe, 0xf0, 0xe1, 0xdf, 0xfe, 0xf0, 0xe1, 0xdf, 0xff, 0xf0, 0xe1, 0xff, 0xff, 0xf9, 0xf3, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0x00, 0x80, 0xff, 0xbe, 0xff, 0xbf, 0xdf, 0x7e, 0x00, 0xc0, 0xdf,
|
||||
0x7c, 0x00, 0xc0, 0xcf, 0xfc, 0x00, 0xe0, 0xcf, 0xf8, 0x01, 0xf0, 0xc7, 0xf8, 0x03, 0xf8, 0xc7, 0xf0, 0xff, 0xff, 0xc3,
|
||||
0xe0, 0xff, 0xff, 0xc1, 0xc0, 0xff, 0xff, 0xc0, 0x80, 0xff, 0x3f, 0xc0, 0x00, 0xfe, 0x0f, 0xc0, 0x00, 0xf8, 0x03, 0xc0};
|
||||
|
||||
const unsigned char Slightly_Smiling[] PROGMEM = {0x00, 0x00, 0xE0, 0x07, 0x18, 0x18, 0x04, 0x20, 0x44, 0x22, 0x42,
|
||||
0x42, 0x02, 0x40, 0x02, 0x40, 0x12, 0x48, 0x12, 0x48, 0x22, 0x44,
|
||||
0xC4, 0x23, 0x04, 0x20, 0x18, 0x18, 0xE0, 0x07, 0x00, 0x00};
|
||||
const unsigned char Slightly_Smiling[] PROGMEM = {
|
||||
0x00, 0xf8, 0x03, 0xc0, 0x00, 0xfe, 0x0f, 0xc0, 0x80, 0xff, 0x3f, 0xc0, 0xc0, 0xff, 0xff, 0xc0, 0xe0, 0xff, 0xff, 0xc1,
|
||||
0xf0, 0xff, 0xff, 0xc3, 0xf8, 0xff, 0xff, 0xc7, 0xf8, 0xff, 0xff, 0xcf, 0xfc, 0xf9, 0xf3, 0xcf, 0xfc, 0xf0, 0xe1, 0xcf,
|
||||
0xfe, 0xf0, 0xe1, 0xdf, 0xfe, 0xf0, 0xe1, 0xdf, 0xff, 0xf0, 0xe1, 0xff, 0xff, 0xf9, 0xf3, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xdf, 0x7e, 0xff, 0xdf, 0xdf,
|
||||
0x7c, 0xff, 0xdf, 0xcf, 0xfc, 0xfe, 0xef, 0xcf, 0xf8, 0xf9, 0xf7, 0xc7, 0xf8, 0x03, 0xf8, 0xc7, 0xf0, 0xff, 0xff, 0xc3,
|
||||
0xe0, 0xff, 0xff, 0xc1, 0xc0, 0xff, 0xff, 0xc0, 0x80, 0xff, 0x3f, 0xc0, 0x00, 0xfe, 0x0f, 0xc0, 0x00, 0xf8, 0x03, 0xc0};
|
||||
|
||||
const unsigned char Winking_Face[] PROGMEM = {0x00, 0x00, 0xE0, 0x07, 0x18, 0x18, 0x04, 0x20, 0x44, 0x20, 0x42,
|
||||
0x46, 0x02, 0x40, 0x02, 0x40, 0x12, 0x48, 0x12, 0x48, 0x22, 0x44,
|
||||
0xC4, 0x23, 0x04, 0x20, 0x18, 0x18, 0xE0, 0x07, 0x00, 0x00};
|
||||
const unsigned char Winking_Face[] PROGMEM = {
|
||||
0x00, 0xf8, 0x03, 0xc0, 0x00, 0xfe, 0x0f, 0xc0, 0x80, 0xff, 0x3f, 0xc0, 0xc0, 0xff, 0xff, 0xc0, 0xe0, 0xff, 0xff, 0xc1,
|
||||
0xf0, 0xf0, 0xff, 0xc3, 0x78, 0xef, 0xc3, 0xc7, 0xb8, 0xdf, 0xbd, 0xcf, 0xfc, 0xf9, 0x7f, 0xcf, 0xfc, 0xf0, 0xff, 0xcf,
|
||||
0xfe, 0xf0, 0xc3, 0xdf, 0xfe, 0xf0, 0x81, 0xdf, 0xff, 0xf0, 0xbf, 0xff, 0xff, 0xf9, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xdf, 0x7e, 0xff, 0xdf, 0xdf,
|
||||
0x7c, 0xff, 0xdf, 0xcf, 0xfc, 0xfe, 0xef, 0xcf, 0xf8, 0xf9, 0xf7, 0xc7, 0xf8, 0x03, 0xf8, 0xc7, 0xf0, 0xff, 0xff, 0xc3,
|
||||
0xe0, 0xff, 0xff, 0xc1, 0xc0, 0xff, 0xff, 0xc0, 0x80, 0xff, 0x3f, 0xc0, 0x00, 0xfe, 0x0f, 0xc0, 0x00, 0xf8, 0x07, 0xc0};
|
||||
|
||||
const unsigned char Grinning_Smiling_Eyes[] PROGMEM = {0x00, 0x00, 0xE0, 0x07, 0x18, 0x18, 0x04, 0x20, 0x24, 0x24, 0x52,
|
||||
0x4A, 0x02, 0x40, 0xFA, 0x5F, 0x0A, 0x50, 0x0A, 0x50, 0x12, 0x48,
|
||||
0x24, 0x24, 0xC4, 0x23, 0x18, 0x18, 0xE0, 0x07, 0x00, 0x00};
|
||||
const unsigned char Grinning_Smiling_Eyes[] PROGMEM = {
|
||||
0x00, 0xf8, 0x03, 0xc0, 0x00, 0xfe, 0x0f, 0xc0, 0x80, 0xff, 0x3f, 0xc0, 0xc0, 0xff, 0xff, 0xc0, 0xe0, 0xff, 0xff, 0xc1,
|
||||
0xf0, 0xff, 0xff, 0xc3, 0xf8, 0xff, 0xff, 0xc7, 0xf8, 0xff, 0xff, 0xcf, 0xfc, 0xf8, 0xe3, 0xcf, 0x7c, 0xf7, 0xdd, 0xcf,
|
||||
0xbe, 0xef, 0xbe, 0xdf, 0xbe, 0xef, 0xbe, 0xdf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x1f, 0x00, 0x00, 0xff, 0x5e, 0x55, 0x55, 0xdf, 0x5e, 0x55, 0x55, 0xdf,
|
||||
0x3c, 0x00, 0x80, 0xcf, 0x7c, 0x55, 0xd5, 0xcf, 0xf8, 0x54, 0xe5, 0xc7, 0xf8, 0x03, 0xf8, 0xc7, 0xf0, 0xff, 0xff, 0xc3,
|
||||
0xe0, 0xff, 0xff, 0xc1, 0xc0, 0xff, 0xff, 0xc0, 0x80, 0xff, 0x3f, 0xc0, 0x00, 0xfe, 0x0f, 0xc0, 0x00, 0xf8, 0x03, 0xc0};
|
||||
|
||||
const unsigned char heart_smile[] PROGMEM = {0x00, 0x00, 0x6C, 0x07, 0x7C, 0x18, 0x7C, 0x20, 0x38, 0x24, 0x52,
|
||||
0x0A, 0x02, 0xD8, 0x02, 0xF8, 0x22, 0xFC, 0x20, 0x74, 0xDB, 0x23,
|
||||
0x1F, 0x00, 0x1F, 0x20, 0x0E, 0x18, 0xE4, 0x07, 0x00, 0x00};
|
||||
const unsigned char question[] PROGMEM = {
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x3C, 0x00, 0x00, 0x80, 0xFF, 0x01, 0x00, 0xC0, 0xFF, 0x07, 0x00, 0xE0, 0xFF, 0x07, 0x00,
|
||||
0xE0, 0xC3, 0x0F, 0x00, 0xF0, 0x81, 0x0F, 0x00, 0xF0, 0x01, 0x0F, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x80, 0x0F, 0x00,
|
||||
0x00, 0xC0, 0x0F, 0x00, 0x00, 0xE0, 0x07, 0x00, 0x00, 0xF0, 0x03, 0x00, 0x00, 0xF8, 0x01, 0x00, 0x00, 0x7C, 0x00, 0x00,
|
||||
0x00, 0x3C, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x3E, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
};
|
||||
|
||||
const unsigned char Heart_eyes[] PROGMEM = {0x00, 0x00, 0xE0, 0x07, 0x18, 0x18, 0x04, 0x20, 0x54, 0x2A, 0xFA,
|
||||
0x5F, 0x72, 0x4E, 0x22, 0x44, 0x02, 0x40, 0x12, 0x48, 0x12, 0x48,
|
||||
0x24, 0x24, 0xC4, 0x23, 0x18, 0x18, 0xE0, 0x07, 0x00, 0x00};
|
||||
const unsigned char bang[] PROGMEM = {
|
||||
0xFF, 0x0F, 0xFC, 0x3F, 0xFF, 0x0F, 0xFC, 0x3F, 0xFF, 0x0F, 0xFC, 0x3F, 0xFF, 0x07, 0xF8, 0x3F, 0xFF, 0x07, 0xF8, 0x3F,
|
||||
0xFE, 0x07, 0xF8, 0x1F, 0xFE, 0x07, 0xF8, 0x1F, 0xFE, 0x07, 0xF8, 0x1F, 0xFE, 0x07, 0xF8, 0x1F, 0xFE, 0x07, 0xF8, 0x1F,
|
||||
0xFE, 0x03, 0xF0, 0x1F, 0xFE, 0x03, 0xF0, 0x1F, 0xFC, 0x03, 0xF0, 0x0F, 0xFC, 0x03, 0xF0, 0x0F, 0xFC, 0x03, 0xF0, 0x0F,
|
||||
0xFC, 0x03, 0xF0, 0x0F, 0xFC, 0x03, 0xF0, 0x0F, 0xFC, 0x03, 0xF0, 0x0F, 0xFC, 0x01, 0xE0, 0x0F, 0xFC, 0x01, 0xE0, 0x0F,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0x00, 0xC0, 0x03, 0xFC, 0x03, 0xF0, 0x0F, 0xFE, 0x03, 0xF0, 0x1F,
|
||||
0xFE, 0x07, 0xF8, 0x1F, 0xFE, 0x07, 0xF8, 0x1F, 0xFE, 0x07, 0xF8, 0x1F, 0xFC, 0x03, 0xF0, 0x0F, 0xF8, 0x01, 0xE0, 0x07,
|
||||
};
|
||||
|
||||
const unsigned char question[] PROGMEM = {0xE0, 0x07, 0x10, 0x08, 0x08, 0x10, 0x88, 0x11, 0x48, 0x12, 0x48,
|
||||
0x12, 0x48, 0x12, 0x30, 0x11, 0x80, 0x08, 0x40, 0x04, 0x40, 0x02,
|
||||
0xC0, 0x03, 0x00, 0x00, 0xC0, 0x03, 0x40, 0x02, 0x80, 0x01};
|
||||
const unsigned char haha[] PROGMEM = {
|
||||
0x00, 0xf8, 0x03, 0xc0, 0x00, 0xfe, 0x0f, 0xc0, 0x80, 0xff, 0x3f, 0xc0, 0xc0, 0xff, 0x7f, 0xc0, 0xe0, 0xf9, 0xf3, 0xc0,
|
||||
0xf0, 0xfe, 0xef, 0xc1, 0x38, 0xff, 0x9f, 0xc3, 0xd8, 0xff, 0x7f, 0xc3, 0xfc, 0xf8, 0xe3, 0xc7, 0x7c, 0xf7, 0xdd, 0xcf,
|
||||
0xbe, 0xef, 0xbe, 0xcf, 0xfe, 0xff, 0xff, 0xcf, 0xef, 0xff, 0xff, 0xde, 0xe7, 0xff, 0xff, 0xdc, 0xeb, 0xff, 0xff, 0xda,
|
||||
0xed, 0xff, 0xff, 0xd6, 0xee, 0xff, 0xff, 0xce, 0x36, 0x00, 0x80, 0xcd, 0xb8, 0xff, 0xbf, 0xc3, 0x7e, 0x00, 0xc0, 0xdf,
|
||||
0x7c, 0x00, 0xc0, 0xcf, 0xfc, 0x00, 0xe0, 0xcf, 0xf8, 0x01, 0xf0, 0xc7, 0xf8, 0x03, 0xf8, 0xc7, 0xf0, 0xff, 0xff, 0xc3,
|
||||
0xe0, 0xff, 0xff, 0xc1, 0xc0, 0xff, 0xff, 0xc0, 0x80, 0xff, 0x3f, 0xc0, 0x00, 0xfe, 0x0f, 0xc0, 0x00, 0xf8, 0x03, 0xc0};
|
||||
|
||||
const unsigned char bang[] PROGMEM = {0x30, 0x0C, 0x48, 0x12, 0x48, 0x12, 0x48, 0x12, 0x48, 0x12, 0x48,
|
||||
0x12, 0x48, 0x12, 0x48, 0x12, 0x48, 0x12, 0x48, 0x12, 0x30, 0x0C,
|
||||
0x00, 0x00, 0x30, 0x0C, 0x48, 0x12, 0x30, 0x0C, 0x00, 0x00};
|
||||
const unsigned char ROFL[] PROGMEM = {
|
||||
0x00, 0x00, 0x00, 0xc0, 0x00, 0xfc, 0x07, 0xc0, 0x00, 0xff, 0x1f, 0xc0, 0x80, 0xff, 0x7f, 0xc0, 0xc0, 0xff, 0xff, 0xc0,
|
||||
0xe0, 0x9f, 0xff, 0xc1, 0xf0, 0x9f, 0xff, 0xc0, 0xf8, 0x9f, 0x7f, 0xcb, 0xf8, 0x9f, 0xbf, 0xcb, 0xfc, 0x9f, 0xdf, 0xdb,
|
||||
0xfc, 0x1f, 0x08, 0xdc, 0xfe, 0x1f, 0xf8, 0xfe, 0xfe, 0xff, 0xff, 0xfe, 0x1e, 0xf0, 0x7f, 0xfe, 0x1e, 0xf0, 0xbf, 0xfe,
|
||||
0xfe, 0xf3, 0xdf, 0xfe, 0xfe, 0xf3, 0x6f, 0xfe, 0xfe, 0xf3, 0x37, 0xfe, 0xfe, 0xeb, 0x1b, 0xfe, 0xfc, 0xef, 0x0d, 0xde,
|
||||
0xfc, 0xe7, 0x06, 0xcf, 0xf8, 0x6b, 0x83, 0xcf, 0xf8, 0x0d, 0xc0, 0xc7, 0xf0, 0xed, 0xff, 0xc7, 0xe0, 0xee, 0xff, 0xc3,
|
||||
0xc0, 0xee, 0xff, 0xc1, 0x80, 0xee, 0xff, 0xc0, 0x00, 0xe6, 0x3f, 0xc0, 0x00, 0xf0, 0x0f, 0xc0, 0x00, 0x00, 0x00, 0xc0};
|
||||
|
||||
const unsigned char haha[] PROGMEM = {0x00, 0x00, 0xE0, 0x07, 0x18, 0x18, 0x04, 0x20, 0x24, 0x24, 0x52,
|
||||
0x4A, 0x0A, 0x50, 0x0E, 0x70, 0xF2, 0x4F, 0x12, 0x48, 0x32, 0x44,
|
||||
0xC4, 0x23, 0x04, 0x20, 0x18, 0x18, 0xE0, 0x07, 0x00, 0x00};
|
||||
const unsigned char Smiling_Closed_Eyes[] PROGMEM = {
|
||||
0x00, 0xf8, 0x03, 0xc0, 0x00, 0xfe, 0x0f, 0xc0, 0x80, 0xff, 0x3f, 0xc0, 0xc0, 0xff, 0xff, 0xc0, 0xe0, 0xff, 0xff, 0xc1,
|
||||
0xf0, 0xff, 0xff, 0xc3, 0xf8, 0xff, 0xff, 0xc7, 0xf8, 0xff, 0xff, 0xcf, 0x7c, 0xfe, 0xcf, 0xcf, 0xfc, 0xfc, 0xe7, 0xcf,
|
||||
0xfe, 0xf9, 0xf3, 0xdf, 0xfe, 0xf3, 0xf9, 0xdf, 0xff, 0xf9, 0xf3, 0xff, 0xff, 0xfc, 0xe7, 0xff, 0x7f, 0xfe, 0xcf, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0x00, 0x80, 0xff, 0xbe, 0xff, 0xbf, 0xdf, 0x7e, 0x00, 0xc0, 0xdf,
|
||||
0x7c, 0x00, 0xc0, 0xcf, 0xfc, 0x00, 0xe0, 0xcf, 0xf8, 0x01, 0xf0, 0xc7, 0xf8, 0x03, 0xf8, 0xc7, 0xf0, 0xff, 0xff, 0xc3,
|
||||
0xe0, 0xff, 0xff, 0xc1, 0xc0, 0xff, 0xff, 0xc0, 0x80, 0xff, 0x3f, 0xc0, 0x00, 0xfe, 0x0f, 0xc0, 0x00, 0xf8, 0x03, 0xc0};
|
||||
|
||||
const unsigned char ROFL[] PROGMEM = {0x00, 0x00, 0xE0, 0x07, 0x18, 0x18, 0x84, 0x21, 0x84, 0x20, 0x02,
|
||||
0x4C, 0x02, 0x4A, 0x1A, 0x49, 0x8A, 0x48, 0x42, 0x48, 0x22, 0x44,
|
||||
0xE4, 0x23, 0x04, 0x20, 0x18, 0x18, 0xE0, 0x07, 0x00, 0x00};
|
||||
const unsigned char Grinning_SmilingEyes2[] PROGMEM = {
|
||||
0x00, 0xf8, 0x03, 0xc0, 0x00, 0xfe, 0x0f, 0xc0, 0x80, 0xff, 0x3f, 0xc0, 0xc0, 0xff, 0x7f, 0xc0, 0xe0, 0xff, 0xff, 0xc0,
|
||||
0xf0, 0xff, 0xff, 0xc1, 0xf8, 0xff, 0xff, 0xc3, 0xf8, 0xff, 0xff, 0xc3, 0xfc, 0xf8, 0xe3, 0xc7, 0x7c, 0xf7, 0xdd, 0xc7,
|
||||
0xbe, 0xef, 0xbe, 0xcf, 0xfe, 0xff, 0xff, 0xcf, 0xff, 0xff, 0xff, 0xdf, 0xff, 0xff, 0xff, 0xdf, 0xff, 0xff, 0xff, 0xdf,
|
||||
0xff, 0xff, 0xff, 0xdf, 0xff, 0xff, 0xff, 0xdf, 0x3f, 0x00, 0x80, 0xdf, 0xbe, 0xff, 0xbf, 0xcf, 0x7e, 0x00, 0xc0, 0xcf,
|
||||
0x7c, 0x00, 0xc0, 0xc7, 0xfc, 0x00, 0xe0, 0xc7, 0xf8, 0x01, 0xf0, 0xc3, 0xf8, 0x03, 0xf8, 0xc3, 0xf0, 0xff, 0xff, 0xc1,
|
||||
0xe0, 0xff, 0xff, 0xc0, 0xc0, 0xff, 0x7f, 0xc0, 0x80, 0xff, 0x3f, 0xc0, 0x00, 0xfe, 0x0f, 0xc0, 0x00, 0xf8, 0x03, 0xc0};
|
||||
|
||||
const unsigned char Smiling_Closed_Eyes[] PROGMEM = {0x00, 0x00, 0xE0, 0x07, 0x18, 0x18, 0x04, 0x20, 0x24, 0x24, 0x42,
|
||||
0x42, 0x22, 0x44, 0x02, 0x40, 0xF2, 0x4F, 0x12, 0x48, 0x22, 0x44,
|
||||
0xC4, 0x23, 0x04, 0x20, 0x18, 0x18, 0xE0, 0x07, 0x00, 0x00};
|
||||
const unsigned char wave_icon[] PROGMEM = {
|
||||
0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x7f, 0xc0, 0x00, 0x00, 0xc0, 0xc1, 0x00, 0x00, 0x00, 0xc7,
|
||||
0x00, 0x00, 0x1e, 0xcc, 0x00, 0x00, 0x30, 0xc8, 0x00, 0x00, 0x60, 0xd8, 0x00, 0x08, 0xc0, 0xd0, 0x00, 0x1a, 0x81, 0xd1,
|
||||
0x00, 0x36, 0x03, 0xd3, 0x80, 0x6d, 0x06, 0xd2, 0x00, 0xdb, 0x0c, 0xc2, 0x80, 0xb6, 0x1d, 0xc0, 0x80, 0x6d, 0x1f, 0xc0,
|
||||
0x00, 0xdb, 0x3f, 0xc0, 0x00, 0xf6, 0x7f, 0xc0, 0x00, 0xfc, 0x7f, 0xc0, 0x08, 0xf8, 0x7f, 0xc0, 0x48, 0xf0, 0x7f, 0xc0,
|
||||
0x48, 0xe0, 0x7f, 0xc0, 0xc8, 0xc0, 0x3f, 0xc0, 0x98, 0x81, 0x1f, 0xc0, 0x10, 0x03, 0x00, 0xc0, 0x30, 0x0e, 0x00, 0xc0,
|
||||
0x20, 0x38, 0x00, 0xc0, 0xe0, 0x00, 0x00, 0xc0, 0x80, 0x07, 0x00, 0xc0, 0x00, 0x1e, 0x00, 0xc0, 0x00, 0x00, 0x00, 0xc0};
|
||||
|
||||
const unsigned char Grinning_SmilingEyes2[] PROGMEM = {0x00, 0x00, 0xE0, 0x07, 0x18, 0x18, 0x04, 0x20, 0x24, 0x24, 0x52,
|
||||
0x4A, 0x02, 0x40, 0x02, 0x40, 0xF2, 0x4F, 0x12, 0x48, 0x22, 0x44,
|
||||
0xC4, 0x23, 0x04, 0x20, 0x18, 0x18, 0xE0, 0x07, 0x00, 0x00};
|
||||
const unsigned char cowboy[] PROGMEM = {
|
||||
0x00, 0x0c, 0x0c, 0xc0, 0x00, 0x02, 0x10, 0xc0, 0x00, 0x01, 0x20, 0xc0, 0xbc, 0x00, 0x40, 0xcf, 0xc2, 0x01, 0xe0, 0xd0,
|
||||
0x01, 0x01, 0x20, 0xe0, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0xc0,
|
||||
0xc1, 0x3f, 0xff, 0xe0, 0xe1, 0xff, 0xff, 0xe1, 0xf2, 0xf3, 0xf3, 0xd3, 0xf4, 0xf1, 0xe3, 0xcb, 0xfc, 0xf1, 0xe3, 0xc7,
|
||||
0xf8, 0xf1, 0xe3, 0xc7, 0xf8, 0xf1, 0xe3, 0xc7, 0xf8, 0xfb, 0xf7, 0xc7, 0xf8, 0xff, 0xff, 0xc7, 0xf8, 0xff, 0xff, 0xc7,
|
||||
0x70, 0xf8, 0x8f, 0xc3, 0x70, 0x03, 0xb0, 0xc3, 0x70, 0xfe, 0xbf, 0xc3, 0x60, 0x00, 0x80, 0xc1, 0xc0, 0x00, 0xc0, 0xc0,
|
||||
0x80, 0x01, 0x60, 0xc0, 0x00, 0x07, 0x38, 0xc0, 0x00, 0xfe, 0x1f, 0xc0, 0x00, 0xf0, 0x03, 0xc0, 0x00, 0x00, 0x00, 0xc0};
|
||||
|
||||
const unsigned char Loudly_Crying_Face[] PROGMEM = {0x00, 0x00, 0xE0, 0x07, 0x18, 0x18, 0x04, 0x20, 0x34, 0x2C, 0x4A,
|
||||
0x52, 0x12, 0x48, 0x12, 0x48, 0x92, 0x49, 0x52, 0x4A, 0x52, 0x4A,
|
||||
0x54, 0x2A, 0x94, 0x29, 0x18, 0x18, 0xF0, 0x0F, 0x00, 0x00};
|
||||
const unsigned char deadmau5[] PROGMEM = {
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0x07, 0x00,
|
||||
0x00, 0xFC, 0x03, 0x00, 0x00, 0xFF, 0x3F, 0x00, 0x80, 0xFF, 0x0F, 0x00, 0xC0, 0xFF, 0xFF, 0x00, 0xE0, 0xFF, 0x3F, 0x00,
|
||||
0xE0, 0xFF, 0xFF, 0x01, 0xF0, 0xFF, 0x7F, 0x00, 0xF0, 0xFF, 0xFF, 0x03, 0xF8, 0xFF, 0xFF, 0x00, 0xF0, 0xFF, 0xFF, 0x07,
|
||||
0xFC, 0xFF, 0xFF, 0x00, 0xF0, 0xFF, 0xFF, 0x0F, 0xFC, 0xFF, 0xFF, 0x00, 0xF0, 0xFF, 0xFF, 0x0F, 0xFE, 0xFF, 0xFF, 0x00,
|
||||
0xF0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0xF0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0xE0, 0xFF, 0x3F, 0xFC,
|
||||
0x0F, 0xFF, 0x7F, 0x00, 0xC0, 0xFF, 0x1F, 0xF8, 0x0F, 0xFC, 0x3F, 0x00, 0x80, 0xFF, 0x0F, 0xF8, 0x1F, 0xFC, 0x1F, 0x00,
|
||||
0x00, 0xFF, 0x0F, 0xFC, 0x3F, 0xFC, 0x0F, 0x00, 0x00, 0xF8, 0x1F, 0xFF, 0xFF, 0xFE, 0x01, 0x00, 0x00, 0x00, 0xFC, 0xFF,
|
||||
0xFF, 0x07, 0x00, 0x00, 0x00, 0x00, 0xFC, 0xFF, 0xFF, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x04, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00,
|
||||
0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0xE0, 0x00, 0xC0, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x80, 0x07, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFC, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
};
|
||||
|
||||
const unsigned char wave_icon[] PROGMEM = {0x00, 0x00, 0xC0, 0x18, 0x30, 0x21, 0x48, 0x5A, 0x94, 0x64, 0x24,
|
||||
0x25, 0x4A, 0x24, 0x12, 0x44, 0x22, 0x44, 0x04, 0x40, 0x08, 0x40,
|
||||
0x12, 0x40, 0x22, 0x20, 0xC4, 0x10, 0x18, 0x0F, 0x00, 0x00};
|
||||
const unsigned char sun[] PROGMEM = {
|
||||
0x00, 0xC0, 0x00, 0x00, 0x00, 0xE0, 0x01, 0x00, 0x00, 0xE0, 0x01, 0x00, 0x00, 0xE0, 0x01, 0x00, 0x30, 0xC0, 0x00, 0x03,
|
||||
0x70, 0x00, 0x80, 0x03, 0xF0, 0x00, 0xC0, 0x03, 0xF0, 0xF8, 0xC7, 0x03, 0xE0, 0xFC, 0xCF, 0x01, 0x00, 0xFE, 0x1F, 0x00,
|
||||
0x00, 0xFF, 0x3F, 0x00, 0x80, 0xFF, 0x7F, 0x00, 0x80, 0xFF, 0x7F, 0x00, 0x8E, 0xFF, 0x7F, 0x1C, 0x9F, 0xFF, 0x7F, 0x3E,
|
||||
0x9F, 0xFF, 0x7F, 0x3E, 0x8E, 0xFF, 0x7F, 0x1C, 0x80, 0xFF, 0x7F, 0x00, 0x80, 0xFF, 0x7F, 0x00, 0x00, 0xFF, 0x3F, 0x00,
|
||||
0x00, 0xFE, 0x1F, 0x00, 0x00, 0xFC, 0x0F, 0x00, 0xC0, 0xF9, 0xE7, 0x00, 0xE0, 0x01, 0xE0, 0x01, 0xF0, 0x01, 0xE0, 0x03,
|
||||
0xF0, 0xC0, 0xC0, 0x03, 0x00, 0xE0, 0x01, 0x00, 0x00, 0xE0, 0x01, 0x00, 0x00, 0xE0, 0x01, 0x00, 0x00, 0xC0, 0x00, 0x00,
|
||||
};
|
||||
|
||||
const unsigned char cowboy[] PROGMEM = {0x70, 0x0E, 0x8F, 0xF1, 0x11, 0x88, 0x21, 0x84, 0xC2, 0x43, 0x1E,
|
||||
0x78, 0xE2, 0x47, 0x42, 0x42, 0x12, 0x48, 0x12, 0x48, 0x22, 0x44,
|
||||
0xC4, 0x23, 0x04, 0x20, 0x18, 0x18, 0xE0, 0x07, 0x00, 0x00};
|
||||
const unsigned char rain[] PROGMEM = {
|
||||
0xC0, 0x0F, 0xC0, 0x00, 0x40, 0x00, 0x80, 0x00, 0x20, 0x00, 0x80, 0x00, 0x20, 0x00, 0x80, 0x03, 0x38, 0x00,
|
||||
0x00, 0x0E, 0x0C, 0x00, 0x00, 0x18, 0x02, 0x00, 0x00, 0x10, 0x03, 0x00, 0x00, 0x30, 0x01, 0x00, 0x00, 0x20,
|
||||
0x01, 0x00, 0x00, 0x20, 0x01, 0x00, 0x00, 0x20, 0x01, 0x00, 0x00, 0x20, 0x03, 0x00, 0x00, 0x30, 0x02, 0x00,
|
||||
0x00, 0x10, 0x06, 0x00, 0x00, 0x08, 0xFC, 0xFF, 0xFF, 0x07, 0xF0, 0xFF, 0xFF, 0x01, 0x80, 0x00, 0x01, 0x00,
|
||||
0xC0, 0xC0, 0x81, 0x03, 0xA0, 0x60, 0xC1, 0x03, 0x90, 0x20, 0x41, 0x01, 0xF0, 0xE0, 0xC0, 0x01, 0x60, 0x4C,
|
||||
0x98, 0x00, 0x00, 0x0E, 0x1C, 0x00, 0x00, 0x0B, 0x12, 0x00, 0x00, 0x09, 0x1A, 0x00, 0x00, 0x06, 0x0E, 0x00,
|
||||
};
|
||||
|
||||
const unsigned char deadmau5[] PROGMEM = {0x00, 0x00, 0xE0, 0x07, 0x18, 0x18, 0xE4, 0x27, 0x12, 0x48, 0x0A,
|
||||
0x50, 0x0E, 0x70, 0x11, 0x88, 0x19, 0x98, 0x19, 0x98, 0x19, 0x98,
|
||||
0x19, 0x98, 0x19, 0x98, 0x11, 0x88, 0x0E, 0x70, 0x00, 0x00};
|
||||
const unsigned char cloud[] PROGMEM = {
|
||||
0x00, 0x80, 0x07, 0x00, 0x00, 0xE0, 0x1F, 0x00, 0x00, 0x70, 0x30, 0x00, 0x00, 0x10, 0x60, 0x00, 0x80, 0x1F, 0x40, 0x00,
|
||||
0xC0, 0x0F, 0xC0, 0x00, 0xC0, 0x00, 0x80, 0x00, 0x60, 0x00, 0x80, 0x00, 0x20, 0x00, 0x80, 0x00, 0x20, 0x00, 0x80, 0x01,
|
||||
0x20, 0x00, 0x00, 0x07, 0x38, 0x00, 0x00, 0x0C, 0x0C, 0x00, 0x00, 0x08, 0x06, 0x00, 0x00, 0x18, 0x02, 0x00, 0x00, 0x10,
|
||||
0x02, 0x00, 0x00, 0x30, 0x03, 0x00, 0x00, 0x20, 0x01, 0x00, 0x00, 0x20, 0x01, 0x00, 0x00, 0x20, 0x01, 0x00, 0x00, 0x20,
|
||||
0x01, 0x00, 0x00, 0x20, 0x01, 0x00, 0x00, 0x20, 0x01, 0x00, 0x00, 0x20, 0x01, 0x00, 0x00, 0x30, 0x03, 0x00, 0x00, 0x10,
|
||||
0x02, 0x00, 0x00, 0x10, 0x06, 0x00, 0x00, 0x18, 0x0C, 0x00, 0x00, 0x0C, 0xFC, 0xFF, 0xFF, 0x07, 0xF0, 0xFF, 0xFF, 0x03,
|
||||
};
|
||||
|
||||
const unsigned char sun[] PROGMEM = {0x00, 0x00, 0x80, 0x01, 0xEC, 0x37, 0xFC, 0x3F, 0xF8, 0x1F, 0xFC,
|
||||
0x3F, 0xFE, 0x7F, 0xFC, 0x3F, 0xFC, 0x3F, 0xFE, 0x7F, 0xFC, 0x3F,
|
||||
0xF8, 0x1F, 0xFC, 0x3F, 0xEC, 0x37, 0x80, 0x01, 0x00, 0x00};
|
||||
const unsigned char fog[] PROGMEM = {
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x78, 0x00, 0x3C, 0x00, 0xFE, 0x01, 0xFF, 0x00, 0x87, 0xC7, 0xC3, 0x01, 0x03, 0xFE, 0x80, 0x01,
|
||||
0x00, 0x38, 0x00, 0x00, 0xFC, 0x00, 0x7E, 0x00, 0xFF, 0x83, 0xFF, 0x01, 0x03, 0xFF, 0x81, 0x01, 0x00, 0x7C, 0x00, 0x00,
|
||||
0xF8, 0x00, 0x3E, 0x00, 0xFE, 0x01, 0xFF, 0x00, 0x87, 0xC7, 0xC3, 0x01, 0x03, 0xFE, 0x80, 0x01, 0x00, 0x38, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
};
|
||||
|
||||
const unsigned char rain[] PROGMEM = {0x00, 0x00, 0x00, 0x00, 0x00, 0x0E, 0x38, 0x1F, 0xFC, 0x3F, 0xFE,
|
||||
0x7F, 0xFE, 0x7F, 0xFE, 0x7F, 0xFC, 0x3F, 0x00, 0x00, 0x48, 0x12,
|
||||
0x48, 0x12, 0x24, 0x09, 0x24, 0x09, 0x00, 0x00, 0x00, 0x00};
|
||||
const unsigned char devil[] PROGMEM = {
|
||||
0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0xc0, 0x01, 0x00, 0x00, 0xe0, 0x03, 0x00, 0x00, 0xf0, 0x0f, 0xfc, 0x0f, 0xfc,
|
||||
0x3f, 0xff, 0x3f, 0xff, 0xfe, 0xff, 0xff, 0xdf, 0xfe, 0xff, 0xff, 0xdf, 0xfe, 0xff, 0xff, 0xdf, 0xfc, 0xff, 0xff, 0xcf,
|
||||
0xfc, 0xff, 0xff, 0xcf, 0xf8, 0xff, 0xff, 0xc7, 0xf0, 0xff, 0xff, 0xc3, 0xf0, 0xff, 0xff, 0xc3, 0xf0, 0xf1, 0xe3, 0xc3,
|
||||
0xf0, 0xe7, 0xf9, 0xc3, 0xf0, 0xe7, 0xf9, 0xc3, 0xf0, 0xe3, 0xf1, 0xc3, 0xf0, 0xe3, 0xf1, 0xc3, 0xf0, 0xe7, 0xf9, 0xc3,
|
||||
0xf0, 0xff, 0xff, 0xc3, 0xe0, 0xfd, 0xef, 0xc1, 0xe0, 0xf3, 0xf3, 0xc1, 0xc0, 0x07, 0xf8, 0xc0, 0x80, 0x1f, 0x7e, 0xc0,
|
||||
0x00, 0xff, 0x3f, 0xc0, 0x00, 0xfe, 0x0f, 0xc0, 0x00, 0xf8, 0x03, 0xc0, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0xc0};
|
||||
|
||||
const unsigned char cloud[] PROGMEM = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0E, 0x38, 0x1F, 0xFC,
|
||||
0x3F, 0xFE, 0x7F, 0xFE, 0x7F, 0xFE, 0x7F, 0xFC, 0x3F, 0xF8, 0x1F,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
|
||||
const unsigned char heart[] PROGMEM = {
|
||||
0x00, 0x00, 0x00, 0x00, 0xC0, 0x03, 0xF0, 0x00, 0xF8, 0x0F, 0xFC, 0x07, 0xFC, 0x1F, 0x06, 0x0E, 0xFE, 0x3F, 0x03, 0x18,
|
||||
0xFE, 0xFF, 0x7F, 0x10, 0xFF, 0xFF, 0xFF, 0x31, 0xFF, 0xFF, 0xFF, 0x33, 0xFF, 0xFF, 0xFF, 0x37, 0xFF, 0xFF, 0xFF, 0x37,
|
||||
0xFF, 0xFF, 0xFF, 0x3F, 0xFF, 0xFF, 0xFF, 0x3F, 0xFF, 0xFF, 0xFF, 0x3F, 0xFE, 0xFF, 0xFF, 0x1F, 0xFE, 0xFF, 0xFF, 0x1F,
|
||||
0xFC, 0xFF, 0xFF, 0x0F, 0xFC, 0xFF, 0xFF, 0x0F, 0xF8, 0xFF, 0xFF, 0x07, 0xF0, 0xFF, 0xFF, 0x03, 0xF0, 0xFF, 0xFF, 0x03,
|
||||
0xE0, 0xFF, 0xFF, 0x01, 0xC0, 0xFF, 0xFF, 0x00, 0x80, 0xFF, 0x7F, 0x00, 0x00, 0xFF, 0x3F, 0x00, 0x00, 0xFE, 0x1F, 0x00,
|
||||
0x00, 0xFC, 0x0F, 0x00, 0x00, 0xF8, 0x07, 0x00, 0x00, 0xF0, 0x03, 0x00, 0x00, 0xE0, 0x01, 0x00, 0x00, 0x80, 0x00, 0x00,
|
||||
};
|
||||
|
||||
const unsigned char fog[] PROGMEM = {0x00, 0x00, 0x00, 0x00, 0x88, 0x88, 0x54, 0x55, 0x22, 0x22, 0x00,
|
||||
0x00, 0x44, 0x44, 0xAA, 0x2A, 0x11, 0x11, 0x00, 0x00, 0x88, 0x88,
|
||||
0x54, 0x55, 0x22, 0x22, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
|
||||
const unsigned char poo[] PROGMEM = {
|
||||
0x00, 0x1c, 0x00, 0xc0, 0x00, 0x7c, 0x00, 0xc0, 0x00, 0xfc, 0x00, 0xc0, 0x00, 0x7c, 0x03, 0xc0, 0x00, 0xbe, 0x03, 0xc0,
|
||||
0x00, 0xdf, 0x0f, 0xc0, 0x80, 0xcf, 0x0f, 0xc0, 0xc0, 0xf1, 0x0f, 0xc0, 0x60, 0xfc, 0x0f, 0xc0, 0x30, 0xff, 0x07, 0xc0,
|
||||
0x90, 0xff, 0x3b, 0xc0, 0xc0, 0xff, 0x7d, 0xc0, 0xf8, 0xff, 0xfc, 0xc0, 0xf8, 0x3f, 0xf0, 0xc0, 0x78, 0x88, 0xc0, 0xc0,
|
||||
0x20, 0xe3, 0x18, 0xc0, 0x98, 0xe7, 0xbc, 0xc1, 0x9c, 0x64, 0xa4, 0xc3, 0x9e, 0x64, 0xa4, 0xc7, 0xbe, 0xe4, 0xa4, 0xc7,
|
||||
0xbc, 0x27, 0xbc, 0xc7, 0x38, 0x03, 0xd9, 0xc3, 0x00, 0xf0, 0x63, 0xc0, 0xf8, 0xfc, 0x3f, 0xcf, 0xfc, 0xff, 0x87, 0xdf,
|
||||
0xfe, 0xff, 0xe0, 0xdf, 0xfc, 0x1f, 0xfe, 0xdf, 0xf8, 0x07, 0xf8, 0xcf, 0xf0, 0x03, 0xe0, 0xc7, 0x00, 0x00, 0x00, 0xc0};
|
||||
|
||||
const unsigned char devil[] PROGMEM = {0x06, 0x60, 0xCA, 0x53, 0x32, 0x4C, 0x22, 0x44, 0x44, 0x22, 0x3A,
|
||||
0x5C, 0x32, 0x4C, 0x52, 0x4A, 0x72, 0x4E, 0x02, 0x40, 0x22, 0x44,
|
||||
0xC4, 0x23, 0x04, 0x20, 0x18, 0x18, 0xE0, 0x07, 0x00, 0x00};
|
||||
|
||||
const unsigned char heart[] PROGMEM = {0x00, 0x00, 0x00, 0x00, 0x3C, 0x3C, 0x7E, 0x7E, 0xFE, 0x7F, 0xFE,
|
||||
0x7F, 0xFE, 0x7F, 0xFE, 0x7F, 0xFC, 0x3F, 0xF8, 0x1F, 0xF8, 0x1F,
|
||||
0xF0, 0x0F, 0xE0, 0x07, 0xC0, 0x03, 0x80, 0x01, 0x00, 0x00};
|
||||
|
||||
const unsigned char poo[] PROGMEM = {0x00, 0x00, 0x80, 0x01, 0x40, 0x02, 0x20, 0x04, 0x10, 0x04, 0xF0,
|
||||
0x08, 0x10, 0x10, 0x48, 0x12, 0x08, 0x18, 0xE8, 0x21, 0x1C, 0x40,
|
||||
0x42, 0x42, 0x82, 0x41, 0x02, 0x30, 0xFC, 0x0F, 0x00, 0x00};
|
||||
|
||||
const unsigned char bell_icon[] PROGMEM = {0x00, 0x00, 0x80, 0x01, 0x80, 0x01, 0xE0, 0x07, 0xF0, 0x0F, 0xF0,
|
||||
0x0F, 0xF8, 0x1F, 0xF8, 0x1F, 0xF8, 0x1F, 0xF8, 0x1F, 0xFC, 0x3F,
|
||||
0xFC, 0x3F, 0xFE, 0x7F, 0xFE, 0x7F, 0x80, 0x01, 0x00, 0x00};
|
||||
|
||||
const unsigned char cookie[] PROGMEM = {0x00, 0x00, 0xE0, 0x07, 0x18, 0x18, 0x04, 0x20, 0x34, 0x22, 0x32,
|
||||
0x40, 0x02, 0x58, 0x82, 0x5B, 0x92, 0x43, 0x82, 0x43, 0x02, 0x40,
|
||||
0x64, 0x28, 0x64, 0x20, 0x18, 0x18, 0xE0, 0x07, 0x00, 0x00};
|
||||
|
||||
const unsigned char Fire[] PROGMEM = {0x30, 0x00, 0xF0, 0x00, 0xF8, 0x03, 0xF8, 0x07, 0xFC, 0x1F, 0xFC,
|
||||
0x1F, 0xFE, 0x3E, 0x7E, 0x3E, 0x3E, 0x7C, 0x1E, 0x78, 0x1E, 0x70,
|
||||
0x1C, 0x70, 0x1C, 0x70, 0x38, 0x38, 0x30, 0x38, 0x60, 0x0C};
|
||||
|
||||
const unsigned char peace_sign[] PROGMEM = {0xC0, 0x30, 0x40, 0x29, 0x40, 0x25, 0x40, 0x15, 0x40, 0x12, 0x38,
|
||||
0x0A, 0x54, 0x68, 0x54, 0x58, 0x54, 0x44, 0x3C, 0x22, 0x04, 0x22,
|
||||
0x04, 0x12, 0x08, 0x10, 0x10, 0x08, 0xE0, 0x07, 0x00, 0x00};
|
||||
|
||||
const unsigned char Praying[] PROGMEM = {0x00, 0x00, 0x40, 0x02, 0xA0, 0x05, 0x90, 0x09, 0x90, 0x09, 0x90,
|
||||
0x09, 0x98, 0x19, 0x94, 0x29, 0xA4, 0x25, 0xA4, 0x25, 0x84, 0x21,
|
||||
0x84, 0x21, 0x86, 0x61, 0x4E, 0x72, 0x7F, 0x7E, 0x3F, 0xFC};
|
||||
|
||||
const unsigned char Sparkles[] PROGMEM = {0x00, 0x00, 0x10, 0x00, 0x38, 0x04, 0x10, 0x04, 0x00, 0x0E, 0x00,
|
||||
0x1F, 0x80, 0x3F, 0xE0, 0xFF, 0x80, 0x3F, 0x10, 0x1F, 0x10, 0x0E,
|
||||
0x38, 0x04, 0xFE, 0x04, 0x38, 0x00, 0x10, 0x00, 0x10, 0x00};
|
||||
|
||||
const unsigned char clown[] PROGMEM = {0x00, 0x00, 0xEE, 0x77, 0x1A, 0x58, 0x06, 0x60, 0x24, 0x24, 0x72,
|
||||
0x4E, 0x22, 0x44, 0x82, 0x41, 0x82, 0x41, 0x1A, 0x58, 0xF2, 0x4F,
|
||||
0x14, 0x28, 0xE4, 0x27, 0x18, 0x18, 0xE0, 0x07, 0x00, 0x00};
|
||||
|
||||
const unsigned char robo[] PROGMEM = {0x80, 0x01, 0xC0, 0x03, 0x80, 0x01, 0xFC, 0x3F, 0x04, 0x20, 0x74,
|
||||
0x2E, 0x52, 0x4A, 0x72, 0x4E, 0x02, 0x40, 0x02, 0x40, 0xA2, 0x4A,
|
||||
0x52, 0x45, 0x04, 0x20, 0x04, 0x20, 0xFC, 0x3F, 0x00, 0x00};
|
||||
|
||||
const unsigned char hole[] PROGMEM = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0x0F, 0x3C, 0x3C,
|
||||
0x06, 0x60, 0x0C, 0x30, 0xF0, 0x0F, 0x00, 0x00, 0x00, 0x00};
|
||||
|
||||
const unsigned char bowling[] PROGMEM = {0x00, 0x38, 0x00, 0x44, 0x00, 0x44, 0x00, 0x44, 0x00, 0x28, 0x00,
|
||||
0x38, 0x00, 0x28, 0x78, 0x44, 0x84, 0x82, 0x22, 0x83, 0x52, 0x83,
|
||||
0x02, 0x83, 0x02, 0x45, 0x84, 0x44, 0x78, 0x38, 0x00, 0x00};
|
||||
|
||||
const unsigned char vulcan_salute[] PROGMEM = {0x08, 0x02, 0x16, 0x0D, 0x15, 0x15, 0x15, 0x15, 0xA9, 0x12, 0x4A,
|
||||
0x0A, 0x02, 0x38, 0x04, 0x48, 0x04, 0x44, 0x04, 0x22, 0x04, 0x22,
|
||||
0x04, 0x12, 0x08, 0x10, 0x10, 0x08, 0xE0, 0x07, 0x00, 0x00};
|
||||
const unsigned char bell_icon[] PROGMEM = {
|
||||
0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b11110000,
|
||||
0b00000011, 0b00000000, 0b00000000, 0b11111100, 0b00001111, 0b00000000, 0b00000000, 0b00001111, 0b00111100, 0b00000000,
|
||||
0b00000000, 0b00000011, 0b00110000, 0b00000000, 0b10000000, 0b00000001, 0b01100000, 0b00000000, 0b11000000, 0b00000000,
|
||||
0b11000000, 0b00000000, 0b11000000, 0b00000000, 0b11000000, 0b00000000, 0b11000000, 0b00000000, 0b11000000, 0b00000000,
|
||||
0b11000000, 0b00000000, 0b11000000, 0b00000000, 0b11000000, 0b00000000, 0b11000000, 0b00000000, 0b11000000, 0b00000000,
|
||||
0b11000000, 0b00000000, 0b11000000, 0b00000000, 0b11000000, 0b00000000, 0b11000000, 0b00000000, 0b11000000, 0b00000000,
|
||||
0b11000000, 0b00000000, 0b11000000, 0b00000000, 0b01000000, 0b00000000, 0b10000000, 0b00000000, 0b01100000, 0b00000000,
|
||||
0b10000000, 0b00000001, 0b01110000, 0b00000000, 0b10000000, 0b00000011, 0b00110000, 0b00000000, 0b00000000, 0b00000011,
|
||||
0b00011000, 0b00000000, 0b00000000, 0b00000110, 0b11110000, 0b11111111, 0b11111111, 0b00000011, 0b00000000, 0b00001100,
|
||||
0b00001100, 0b00000000, 0b00000000, 0b00011000, 0b00000110, 0b00000000, 0b00000000, 0b11111000, 0b00000111, 0b00000000,
|
||||
0b00000000, 0b11100000, 0b00000001, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000,
|
||||
0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000};
|
||||
#endif
|
||||
|
||||
} // namespace graphics
|
||||
#endif
|
||||
@@ -17,150 +17,98 @@ extern const int numEmotes;
|
||||
|
||||
#ifndef EXCLUDE_EMOJI
|
||||
// === Emote Bitmaps ===
|
||||
#define thumbs_height 16
|
||||
#define thumbs_width 16
|
||||
#define thumbs_height 25
|
||||
#define thumbs_width 25
|
||||
extern const unsigned char thumbup[] PROGMEM;
|
||||
extern const unsigned char thumbdown[] PROGMEM;
|
||||
|
||||
#define Smiling_Eyes_height 16
|
||||
#define Smiling_Eyes_width 16
|
||||
#define Smiling_Eyes_height 30
|
||||
#define Smiling_Eyes_width 30
|
||||
extern const unsigned char Smiling_Eyes[] PROGMEM;
|
||||
|
||||
#define Grinning_height 16
|
||||
#define Grinning_width 16
|
||||
#define Grinning_height 30
|
||||
#define Grinning_width 30
|
||||
extern const unsigned char Grinning[] PROGMEM;
|
||||
|
||||
#define Slightly_Smiling_height 16
|
||||
#define Slightly_Smiling_width 16
|
||||
#define Slightly_Smiling_height 30
|
||||
#define Slightly_Smiling_width 30
|
||||
extern const unsigned char Slightly_Smiling[] PROGMEM;
|
||||
|
||||
#define Winking_Face_height 16
|
||||
#define Winking_Face_width 16
|
||||
#define Winking_Face_height 30
|
||||
#define Winking_Face_width 30
|
||||
extern const unsigned char Winking_Face[] PROGMEM;
|
||||
|
||||
#define Grinning_Smiling_Eyes_height 16
|
||||
#define Grinning_Smiling_Eyes_width 16
|
||||
#define Grinning_Smiling_Eyes_height 30
|
||||
#define Grinning_Smiling_Eyes_width 30
|
||||
extern const unsigned char Grinning_Smiling_Eyes[] PROGMEM;
|
||||
|
||||
#define heart_smile_height 16
|
||||
#define heart_smile_width 16
|
||||
extern const unsigned char heart_smile[] PROGMEM;
|
||||
|
||||
#define Heart_eyes_height 16
|
||||
#define Heart_eyes_width 16
|
||||
extern const unsigned char Heart_eyes[] PROGMEM;
|
||||
|
||||
#define question_height 16
|
||||
#define question_width 16
|
||||
#define question_height 25
|
||||
#define question_width 25
|
||||
extern const unsigned char question[] PROGMEM;
|
||||
|
||||
#define bang_height 16
|
||||
#define bang_width 16
|
||||
#define bang_height 30
|
||||
#define bang_width 30
|
||||
extern const unsigned char bang[] PROGMEM;
|
||||
|
||||
#define haha_height 16
|
||||
#define haha_width 16
|
||||
#define haha_height 30
|
||||
#define haha_width 30
|
||||
extern const unsigned char haha[] PROGMEM;
|
||||
|
||||
#define ROFL_height 16
|
||||
#define ROFL_width 16
|
||||
#define ROFL_height 30
|
||||
#define ROFL_width 30
|
||||
extern const unsigned char ROFL[] PROGMEM;
|
||||
|
||||
#define Smiling_Closed_Eyes_height 16
|
||||
#define Smiling_Closed_Eyes_width 16
|
||||
#define Smiling_Closed_Eyes_height 30
|
||||
#define Smiling_Closed_Eyes_width 30
|
||||
extern const unsigned char Smiling_Closed_Eyes[] PROGMEM;
|
||||
|
||||
#define Grinning_SmilingEyes2_height 16
|
||||
#define Grinning_SmilingEyes2_width 16
|
||||
#define Grinning_SmilingEyes2_height 30
|
||||
#define Grinning_SmilingEyes2_width 30
|
||||
extern const unsigned char Grinning_SmilingEyes2[] PROGMEM;
|
||||
|
||||
#define Loudly_Crying_Face_height 16
|
||||
#define Loudly_Crying_Face_width 16
|
||||
extern const unsigned char Loudly_Crying_Face[] PROGMEM;
|
||||
|
||||
#define wave_icon_height 16
|
||||
#define wave_icon_width 16
|
||||
#define wave_icon_height 30
|
||||
#define wave_icon_width 30
|
||||
extern const unsigned char wave_icon[] PROGMEM;
|
||||
|
||||
#define cowboy_height 16
|
||||
#define cowboy_width 16
|
||||
#define cowboy_height 30
|
||||
#define cowboy_width 30
|
||||
extern const unsigned char cowboy[] PROGMEM;
|
||||
|
||||
#define deadmau5_height 16
|
||||
#define deadmau5_width 16
|
||||
#define deadmau5_height 30
|
||||
#define deadmau5_width 60
|
||||
extern const unsigned char deadmau5[] PROGMEM;
|
||||
|
||||
#define sun_height 16
|
||||
#define sun_width 16
|
||||
#define sun_height 30
|
||||
#define sun_width 30
|
||||
extern const unsigned char sun[] PROGMEM;
|
||||
|
||||
#define rain_height 16
|
||||
#define rain_width 16
|
||||
#define rain_height 30
|
||||
#define rain_width 30
|
||||
extern const unsigned char rain[] PROGMEM;
|
||||
|
||||
#define cloud_height 16
|
||||
#define cloud_width 16
|
||||
#define cloud_height 30
|
||||
#define cloud_width 30
|
||||
extern const unsigned char cloud[] PROGMEM;
|
||||
|
||||
#define fog_height 16
|
||||
#define fog_width 16
|
||||
#define fog_height 25
|
||||
#define fog_width 25
|
||||
extern const unsigned char fog[] PROGMEM;
|
||||
|
||||
#define devil_height 16
|
||||
#define devil_width 16
|
||||
#define devil_height 30
|
||||
#define devil_width 30
|
||||
extern const unsigned char devil[] PROGMEM;
|
||||
|
||||
#define heart_height 16
|
||||
#define heart_width 16
|
||||
#define heart_height 30
|
||||
#define heart_width 30
|
||||
extern const unsigned char heart[] PROGMEM;
|
||||
|
||||
#define poo_height 16
|
||||
#define poo_width 16
|
||||
#define poo_height 30
|
||||
#define poo_width 30
|
||||
extern const unsigned char poo[] PROGMEM;
|
||||
|
||||
#define bell_icon_width 16
|
||||
#define bell_icon_height 16
|
||||
#define bell_icon_width 30
|
||||
#define bell_icon_height 30
|
||||
extern const unsigned char bell_icon[] PROGMEM;
|
||||
|
||||
#define cookie_width 16
|
||||
#define cookie_height 16
|
||||
extern const unsigned char cookie[] PROGMEM;
|
||||
|
||||
#define Fire_width 16
|
||||
#define Fire_height 16
|
||||
extern const unsigned char Fire[] PROGMEM;
|
||||
|
||||
#define peace_sign_width 16
|
||||
#define peace_sign_height 16
|
||||
extern const unsigned char peace_sign[] PROGMEM;
|
||||
|
||||
#define Praying_width 16
|
||||
#define Praying_height 16
|
||||
extern const unsigned char Praying[] PROGMEM;
|
||||
|
||||
#define Sparkles_width 16
|
||||
#define Sparkles_height 16
|
||||
extern const unsigned char Sparkles[] PROGMEM;
|
||||
|
||||
#define clown_width 16
|
||||
#define clown_height 16
|
||||
extern const unsigned char clown[] PROGMEM;
|
||||
|
||||
#define robo_width 16
|
||||
#define robo_height 16
|
||||
extern const unsigned char robo[] PROGMEM;
|
||||
|
||||
#define hole_width 16
|
||||
#define hole_height 16
|
||||
extern const unsigned char hole[] PROGMEM;
|
||||
|
||||
#define bowling_width 16
|
||||
#define bowling_height 16
|
||||
extern const unsigned char bowling[] PROGMEM;
|
||||
|
||||
#define vulcan_salute_width 16
|
||||
#define vulcan_salute_height 16
|
||||
extern const unsigned char vulcan_salute[] PROGMEM;
|
||||
#endif // EXCLUDE_EMOJI
|
||||
|
||||
} // namespace graphics
|
||||
} // namespace graphics
|
||||
|
||||
@@ -13,147 +13,45 @@ void InkHUD::MapApplet::onRender()
|
||||
return;
|
||||
}
|
||||
|
||||
// Helper: draw rounded rectangle centered at x,y
|
||||
auto fillRoundedRect = [&](int16_t cx, int16_t cy, int16_t w, int16_t h, int16_t r, uint16_t color) {
|
||||
int16_t x = cx - (w / 2);
|
||||
int16_t y = cy - (h / 2);
|
||||
|
||||
// center rects
|
||||
fillRect(x + r, y, w - 2 * r, h, color);
|
||||
fillRect(x, y + r, r, h - 2 * r, color);
|
||||
fillRect(x + w - r, y + r, r, h - 2 * r, color);
|
||||
|
||||
// corners
|
||||
fillCircle(x + r, y + r, r, color);
|
||||
fillCircle(x + w - r - 1, y + r, r, color);
|
||||
fillCircle(x + r, y + h - r - 1, r, color);
|
||||
fillCircle(x + w - r - 1, y + h - r - 1, r, color);
|
||||
};
|
||||
|
||||
// Find center of map
|
||||
// - latitude and longitude
|
||||
// - will be placed at X(0.5), Y(0.5)
|
||||
getMapCenter(&latCenter, &lngCenter);
|
||||
|
||||
// Calculate North+East distance of each node to map center
|
||||
// - which nodes to use controlled by virtual shouldDrawNode method
|
||||
calculateAllMarkers();
|
||||
|
||||
// Set the region shown on the map
|
||||
// - default: fit all nodes, plus padding
|
||||
// - maybe overriden by derived applet
|
||||
// - getMapSize *sets* passed parameters (C-style)
|
||||
getMapSize(&widthMeters, &heightMeters);
|
||||
|
||||
// Set the metersToPx conversion value
|
||||
calculateMapScale();
|
||||
|
||||
// Draw all markers first
|
||||
// Special marker for own node
|
||||
meshtastic_NodeInfoLite *ourNode = nodeDB->getMeshNode(nodeDB->getNodeNum());
|
||||
if (ourNode && nodeDB->hasValidPosition(ourNode))
|
||||
drawLabeledMarker(ourNode);
|
||||
|
||||
// Draw all markers
|
||||
for (Marker m : markers) {
|
||||
int16_t x = X(0.5) + (m.eastMeters * metersToPx);
|
||||
int16_t y = Y(0.5) - (m.northMeters * metersToPx);
|
||||
|
||||
// Add white halo outline first
|
||||
constexpr int outlinePad = 1;
|
||||
int boxSize = 11;
|
||||
int radius = 2; // rounded corner radius
|
||||
// Cross Size
|
||||
constexpr uint16_t csMin = 5;
|
||||
constexpr uint16_t csMax = 12;
|
||||
|
||||
// White halo background
|
||||
fillRoundedRect(x, y, boxSize + (outlinePad * 2), boxSize + (outlinePad * 2), radius + 1, WHITE);
|
||||
|
||||
// Draw inner box
|
||||
fillRoundedRect(x, y, boxSize, boxSize, radius, BLACK);
|
||||
|
||||
// Text inside
|
||||
setFont(fontSmall);
|
||||
setTextColor(WHITE);
|
||||
|
||||
// Draw actual marker on top
|
||||
if (m.hasHopsAway && m.hopsAway > config.lora.hop_limit) {
|
||||
printAt(x + 1, y + 1, "X", CENTER, MIDDLE);
|
||||
} else if (!m.hasHopsAway) {
|
||||
printAt(x + 1, y + 1, "?", CENTER, MIDDLE);
|
||||
} else {
|
||||
char hopStr[4];
|
||||
snprintf(hopStr, sizeof(hopStr), "%d", m.hopsAway);
|
||||
printAt(x, y + 1, hopStr, CENTER, MIDDLE);
|
||||
}
|
||||
|
||||
// Restore default font and color
|
||||
setFont(fontSmall);
|
||||
setTextColor(BLACK);
|
||||
}
|
||||
|
||||
// Dual map scale bars
|
||||
int16_t horizPx = width() * 0.25f;
|
||||
int16_t vertPx = height() * 0.25f;
|
||||
float horizMeters = horizPx / metersToPx;
|
||||
float vertMeters = vertPx / metersToPx;
|
||||
|
||||
auto formatDistance = [&](float meters, char *out, size_t len) {
|
||||
if (config.display.units == meshtastic_Config_DisplayConfig_DisplayUnits_IMPERIAL) {
|
||||
float feet = meters * 3.28084f;
|
||||
if (feet < 528)
|
||||
snprintf(out, len, "%.0f ft", feet);
|
||||
else {
|
||||
float miles = feet / 5280.0f;
|
||||
snprintf(out, len, miles < 10 ? "%.1f mi" : "%.0f mi", miles);
|
||||
}
|
||||
} else {
|
||||
if (meters >= 1000)
|
||||
snprintf(out, len, "%.1f km", meters / 1000.0f);
|
||||
else
|
||||
snprintf(out, len, "%.0f m", meters);
|
||||
}
|
||||
};
|
||||
|
||||
// Horizontal scale bar
|
||||
int16_t horizBarY = height() - 2;
|
||||
int16_t horizBarX = 1;
|
||||
drawLine(horizBarX, horizBarY, horizBarX + horizPx, horizBarY, BLACK);
|
||||
drawLine(horizBarX, horizBarY - 3, horizBarX, horizBarY + 3, BLACK);
|
||||
drawLine(horizBarX + horizPx, horizBarY - 3, horizBarX + horizPx, horizBarY + 3, BLACK);
|
||||
|
||||
char horizLabel[32];
|
||||
formatDistance(horizMeters, horizLabel, sizeof(horizLabel));
|
||||
int16_t horizLabelW = getTextWidth(horizLabel);
|
||||
int16_t horizLabelH = getFont().lineHeight();
|
||||
int16_t horizLabelX = horizBarX + horizPx + 4;
|
||||
int16_t horizLabelY = horizBarY - horizLabelH + 1;
|
||||
fillRect(horizLabelX - 2, horizLabelY - 1, horizLabelW + 4, horizLabelH + 2, WHITE);
|
||||
printAt(horizLabelX, horizBarY, horizLabel, LEFT, BOTTOM);
|
||||
|
||||
// Vertical scale bar
|
||||
int16_t vertBarX = 1;
|
||||
int16_t vertBarBottom = horizBarY;
|
||||
int16_t vertBarTop = vertBarBottom - vertPx;
|
||||
drawLine(vertBarX, vertBarBottom, vertBarX, vertBarTop, BLACK);
|
||||
drawLine(vertBarX - 3, vertBarBottom, vertBarX + 3, vertBarBottom, BLACK);
|
||||
drawLine(vertBarX - 3, vertBarTop, vertBarX + 3, vertBarTop, BLACK);
|
||||
|
||||
char vertTopLabel[32];
|
||||
formatDistance(vertMeters, vertTopLabel, sizeof(vertTopLabel));
|
||||
int16_t topLabelY = vertBarTop - getFont().lineHeight() - 2;
|
||||
int16_t topLabelW = getTextWidth(vertTopLabel);
|
||||
int16_t topLabelH = getFont().lineHeight();
|
||||
fillRect(vertBarX - 2, topLabelY - 1, topLabelW + 6, topLabelH + 2, WHITE);
|
||||
printAt(vertBarX + (topLabelW / 2) + 1, topLabelY + (topLabelH / 2), vertTopLabel, CENTER, MIDDLE);
|
||||
|
||||
char vertBottomLabel[32];
|
||||
formatDistance(vertMeters, vertBottomLabel, sizeof(vertBottomLabel));
|
||||
int16_t bottomLabelY = vertBarBottom + 4;
|
||||
int16_t bottomLabelW = getTextWidth(vertBottomLabel);
|
||||
int16_t bottomLabelH = getFont().lineHeight();
|
||||
fillRect(vertBarX - 2, bottomLabelY - 1, bottomLabelW + 6, bottomLabelH + 2, WHITE);
|
||||
printAt(vertBarX + (bottomLabelW / 2) + 1, bottomLabelY + (bottomLabelH / 2), vertBottomLabel, CENTER, MIDDLE);
|
||||
|
||||
// Draw our node LAST with full white fill + outline
|
||||
meshtastic_NodeInfoLite *ourNode = nodeDB->getMeshNode(nodeDB->getNodeNum());
|
||||
if (ourNode && nodeDB->hasValidPosition(ourNode)) {
|
||||
Marker self = calculateMarker(ourNode->position.latitude_i * 1e-7, ourNode->position.longitude_i * 1e-7, false, 0);
|
||||
|
||||
int16_t centerX = X(0.5) + (self.eastMeters * metersToPx);
|
||||
int16_t centerY = Y(0.5) - (self.northMeters * metersToPx);
|
||||
|
||||
// White fill background + halo
|
||||
fillCircle(centerX, centerY, 8, WHITE); // big white base
|
||||
drawCircle(centerX, centerY, 8, WHITE); // crisp edge
|
||||
|
||||
// Black bullseye on top
|
||||
drawCircle(centerX, centerY, 6, BLACK);
|
||||
fillCircle(centerX, centerY, 2, BLACK);
|
||||
|
||||
// Crosshairs
|
||||
drawLine(centerX - 8, centerY, centerX + 8, centerY, BLACK);
|
||||
drawLine(centerX, centerY - 8, centerX, centerY + 8, BLACK);
|
||||
// Too many hops away
|
||||
if (m.hasHopsAway && m.hopsAway > config.lora.hop_limit) // Too many mops
|
||||
printAt(x, y, "!", CENTER, MIDDLE);
|
||||
else if (!m.hasHopsAway) // Unknown hops
|
||||
drawCross(x, y, csMin);
|
||||
else // The fewer hops, the larger the cross
|
||||
drawCross(x, y, map(m.hopsAway, 0, config.lora.hop_limit, csMax, csMin));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -165,129 +63,116 @@ void InkHUD::MapApplet::onRender()
|
||||
|
||||
void InkHUD::MapApplet::getMapCenter(float *lat, float *lng)
|
||||
{
|
||||
// If we have a valid position for our own node, use that as the anchor
|
||||
meshtastic_NodeInfoLite *ourNode = nodeDB->getMeshNode(nodeDB->getNodeNum());
|
||||
if (ourNode && nodeDB->hasValidPosition(ourNode)) {
|
||||
*lat = ourNode->position.latitude_i * 1e-7;
|
||||
*lng = ourNode->position.longitude_i * 1e-7;
|
||||
} else {
|
||||
// Find mean lat long coords
|
||||
// ============================
|
||||
// - assigning X, Y and Z values to position on Earth's surface in 3D space, relative to center of planet
|
||||
// - averages the x, y and z coords
|
||||
// - uses tan to find angles for lat / long degrees
|
||||
// - longitude: triangle formed by x and y (on plane of the equator)
|
||||
// - latitude: triangle formed by z (north south),
|
||||
// and the line along plane of equator which stretches from earth's axis to where point xyz intersects planet's
|
||||
// surface
|
||||
// Find mean lat long coords
|
||||
// ============================
|
||||
// - assigning X, Y and Z values to position on Earth's surface in 3D space, relative to center of planet
|
||||
// - averages the x, y and z coords
|
||||
// - uses tan to find angles for lat / long degrees
|
||||
// - longitude: triangle formed by x and y (on plane of the equator)
|
||||
// - latitude: triangle formed by z (north south),
|
||||
// and the line along plane of equator which stretches from earth's axis to where point xyz intersects planet's surface
|
||||
|
||||
// Working totals, averaged after nodeDB processed
|
||||
uint32_t positionCount = 0;
|
||||
float xAvg = 0;
|
||||
float yAvg = 0;
|
||||
float zAvg = 0;
|
||||
// Working totals, averaged after nodeDB processed
|
||||
uint32_t positionCount = 0;
|
||||
float xAvg = 0;
|
||||
float yAvg = 0;
|
||||
float zAvg = 0;
|
||||
|
||||
// For each node in db
|
||||
for (uint32_t i = 0; i < nodeDB->getNumMeshNodes(); i++) {
|
||||
meshtastic_NodeInfoLite *node = nodeDB->getMeshNodeByIndex(i);
|
||||
// For each node in db
|
||||
for (uint32_t i = 0; i < nodeDB->getNumMeshNodes(); i++) {
|
||||
meshtastic_NodeInfoLite *node = nodeDB->getMeshNodeByIndex(i);
|
||||
|
||||
// Skip if no position
|
||||
if (!nodeDB->hasValidPosition(node))
|
||||
continue;
|
||||
// Skip if no position
|
||||
if (!nodeDB->hasValidPosition(node))
|
||||
continue;
|
||||
|
||||
// Skip if derived applet doesn't want to show this node on the map
|
||||
if (!shouldDrawNode(node))
|
||||
continue;
|
||||
// Skip if derived applet doesn't want to show this node on the map
|
||||
if (!shouldDrawNode(node))
|
||||
continue;
|
||||
|
||||
// Latitude and Longitude of node, in radians
|
||||
float latRad = node->position.latitude_i * (1e-7) * DEG_TO_RAD;
|
||||
float lngRad = node->position.longitude_i * (1e-7) * DEG_TO_RAD;
|
||||
// Latitude and Longitude of node, in radians
|
||||
float latRad = node->position.latitude_i * (1e-7) * DEG_TO_RAD;
|
||||
float lngRad = node->position.longitude_i * (1e-7) * DEG_TO_RAD;
|
||||
|
||||
// Convert to cartesian points, with center of earth at 0, 0, 0
|
||||
// Exact distance from center is irrelevant, as we're only interested in the vector
|
||||
float x = cos(latRad) * cos(lngRad);
|
||||
float y = cos(latRad) * sin(lngRad);
|
||||
float z = sin(latRad);
|
||||
// Convert to cartesian points, with center of earth at 0, 0, 0
|
||||
// Exact distance from center is irrelevant, as we're only interested in the vector
|
||||
float x = cos(latRad) * cos(lngRad);
|
||||
float y = cos(latRad) * sin(lngRad);
|
||||
float z = sin(latRad);
|
||||
|
||||
// To find mean values shortly
|
||||
xAvg += x;
|
||||
yAvg += y;
|
||||
zAvg += z;
|
||||
positionCount++;
|
||||
}
|
||||
|
||||
// All NodeDB processed, find mean values
|
||||
xAvg /= positionCount;
|
||||
yAvg /= positionCount;
|
||||
zAvg /= positionCount;
|
||||
|
||||
// Longitude from cartesian coords
|
||||
// (Angle from 3D coords describing a point of globe's surface)
|
||||
/*
|
||||
UK
|
||||
/-------\
|
||||
(Top View) /- -\
|
||||
/- (You) -\
|
||||
/- . -\
|
||||
/- . X -\
|
||||
Asia - ... - USA
|
||||
\- Y -/
|
||||
\- -/
|
||||
\- -/
|
||||
\- -/
|
||||
\- -----/
|
||||
Pacific
|
||||
|
||||
*/
|
||||
|
||||
*lng = atan2(yAvg, xAvg) * RAD_TO_DEG;
|
||||
|
||||
// Latitude from cartesian coords
|
||||
// (Angle from 3D coords describing a point on the globe's surface)
|
||||
// As latitude increases, distance from the Earth's north-south axis out to our surface point decreases.
|
||||
// Means we need to first find the hypotenuse which becomes base of our triangle in the second step
|
||||
/*
|
||||
UK North
|
||||
/-------\ (Front View) /-------\
|
||||
(Top View) /- -\ /- -\
|
||||
/- (You) -\ /-(You) -\
|
||||
/- /. -\ /- . -\
|
||||
/- √X²+Y²/ . X -\ /- Z . -\
|
||||
Asia - /... - USA - ..... -
|
||||
\- Y -/ \- √X²+Y² -/
|
||||
\- -/ \- -/
|
||||
\- -/ \- -/
|
||||
\- -/ \- -/
|
||||
\- -----/ \- -----/
|
||||
Pacific South
|
||||
*/
|
||||
|
||||
float hypotenuse = sqrt((xAvg * xAvg) + (yAvg * yAvg)); // Distance from globe's north-south axis to surface intersect
|
||||
*lat = atan2(zAvg, hypotenuse) * RAD_TO_DEG;
|
||||
// To find mean values shortly
|
||||
xAvg += x;
|
||||
yAvg += y;
|
||||
zAvg += z;
|
||||
positionCount++;
|
||||
}
|
||||
|
||||
// Use either our node position, or the mean fallback as the center
|
||||
latCenter = *lat;
|
||||
lngCenter = *lng;
|
||||
// All NodeDB processed, find mean values
|
||||
xAvg /= positionCount;
|
||||
yAvg /= positionCount;
|
||||
zAvg /= positionCount;
|
||||
|
||||
// Longitude from cartesian coords
|
||||
// (Angle from 3D coords describing a point of globe's surface)
|
||||
/*
|
||||
UK
|
||||
/-------\
|
||||
(Top View) /- -\
|
||||
/- (You) -\
|
||||
/- . -\
|
||||
/- . X -\
|
||||
Asia - ... - USA
|
||||
\- Y -/
|
||||
\- -/
|
||||
\- -/
|
||||
\- -/
|
||||
\- -----/
|
||||
Pacific
|
||||
|
||||
*/
|
||||
|
||||
*lng = atan2(yAvg, xAvg) * RAD_TO_DEG;
|
||||
|
||||
// Latitude from cartesian coords
|
||||
// (Angle from 3D coords describing a point on the globe's surface)
|
||||
// As latitude increases, distance from the Earth's north-south axis out to our surface point decreases.
|
||||
// Means we need to first find the hypotenuse which becomes base of our triangle in the second step
|
||||
/*
|
||||
UK North
|
||||
/-------\ (Front View) /-------\
|
||||
(Top View) /- -\ /- -\
|
||||
/- (You) -\ /-(You) -\
|
||||
/- /. -\ /- . -\
|
||||
/- √X²+Y²/ . X -\ /- Z . -\
|
||||
Asia - /... - USA - ..... -
|
||||
\- Y -/ \- √X²+Y² -/
|
||||
\- -/ \- -/
|
||||
\- -/ \- -/
|
||||
\- -/ \- -/
|
||||
\- -----/ \- -----/
|
||||
Pacific South
|
||||
*/
|
||||
|
||||
float hypotenuse = sqrt((xAvg * xAvg) + (yAvg * yAvg)); // Distance from globe's north-south axis to surface intersect
|
||||
*lat = atan2(zAvg, hypotenuse) * RAD_TO_DEG;
|
||||
|
||||
// ----------------------------------------------
|
||||
// This has given us either:
|
||||
// - our actual position (preferred), or
|
||||
// - a mean position (fallback if we had no fix)
|
||||
//
|
||||
// What we actually want is to place our center so that our outermost nodes
|
||||
// end up on the border of our map. The only real use of our "center" is to give
|
||||
// us a reference frame: which direction is east, and which is west.
|
||||
// This has given us the "mean position"
|
||||
// This will be a position *somewhere* near the center of our nodes.
|
||||
// What we actually want is to place our center so that our outermost nodes end up on the border of our map.
|
||||
// The only real use of our "mean position" is to give us a reference frame:
|
||||
// which direction is east, and which is west.
|
||||
//------------------------------------------------
|
||||
|
||||
// Find furthest nodes from our center
|
||||
// Find furthest nodes from "mean lat long"
|
||||
// ========================================
|
||||
|
||||
float northernmost = latCenter;
|
||||
float southernmost = latCenter;
|
||||
float easternmost = lngCenter;
|
||||
float westernmost = lngCenter;
|
||||
|
||||
for (size_t i = 0; i < nodeDB->getNumMeshNodes(); i++) {
|
||||
for (uint8_t i = 0; i < nodeDB->getNumMeshNodes(); i++) {
|
||||
meshtastic_NodeInfoLite *node = nodeDB->getMeshNodeByIndex(i);
|
||||
|
||||
// Skip if no position
|
||||
@@ -299,14 +184,14 @@ void InkHUD::MapApplet::getMapCenter(float *lat, float *lng)
|
||||
continue;
|
||||
|
||||
// Check for a new top or bottom latitude
|
||||
float latNode = node->position.latitude_i * 1e-7;
|
||||
northernmost = max(northernmost, latNode);
|
||||
southernmost = min(southernmost, latNode);
|
||||
float lat = node->position.latitude_i * 1e-7;
|
||||
northernmost = max(northernmost, lat);
|
||||
southernmost = min(southernmost, lat);
|
||||
|
||||
// Longitude is trickier
|
||||
float lngNode = node->position.longitude_i * 1e-7;
|
||||
float degEastward = fmod(((lngNode - lngCenter) + 360), 360); // Degrees traveled east from lngCenter to reach node
|
||||
float degWestward = abs(fmod(((lngNode - lngCenter) - 360), 360)); // Degrees traveled west from lngCenter to reach node
|
||||
float lng = node->position.longitude_i * 1e-7;
|
||||
float degEastward = fmod(((lng - lngCenter) + 360), 360); // Degrees traveled east from lngCenter to reach node
|
||||
float degWestward = abs(fmod(((lng - lngCenter) - 360), 360)); // Degrees traveled west from lngCenter to reach node
|
||||
if (degEastward < degWestward)
|
||||
easternmost = max(easternmost, lngCenter + degEastward);
|
||||
else
|
||||
@@ -365,6 +250,7 @@ InkHUD::MapApplet::Marker InkHUD::MapApplet::calculateMarker(float lat, float ln
|
||||
m.hopsAway = hopsAway;
|
||||
return m;
|
||||
}
|
||||
|
||||
// Draw a marker on the map for a node, with a shortname label, and backing box
|
||||
void InkHUD::MapApplet::drawLabeledMarker(meshtastic_NodeInfoLite *node)
|
||||
{
|
||||
@@ -438,18 +324,6 @@ void InkHUD::MapApplet::drawLabeledMarker(meshtastic_NodeInfoLite *node)
|
||||
textX = labelX + paddingW;
|
||||
}
|
||||
|
||||
// Prevent overlap with scale bars and their labels
|
||||
// Define a "safe zone" in the bottom-left where the scale bars and text are drawn
|
||||
constexpr int16_t safeZoneHeight = 28; // adjust based on your label font height
|
||||
constexpr int16_t safeZoneWidth = 60; // adjust based on horizontal label width zone
|
||||
bool overlapsScale = (labelY + labelH > height() - safeZoneHeight) && (labelX < safeZoneWidth);
|
||||
|
||||
// If it overlaps, shift label upward slightly above the safe zone
|
||||
if (overlapsScale) {
|
||||
labelY = height() - safeZoneHeight - labelH - 2;
|
||||
textY = labelY + (labelH / 2);
|
||||
}
|
||||
|
||||
// Backing box
|
||||
fillRect(labelX, labelY, labelW, labelH, WHITE);
|
||||
drawRect(labelX, labelY, labelW, labelH, BLACK);
|
||||
@@ -474,8 +348,8 @@ void InkHUD::MapApplet::drawLabeledMarker(meshtastic_NodeInfoLite *node)
|
||||
// Need at least two, to draw a sensible map
|
||||
bool InkHUD::MapApplet::enoughMarkers()
|
||||
{
|
||||
size_t count = 0;
|
||||
for (size_t i = 0; i < nodeDB->getNumMeshNodes(); i++) {
|
||||
uint8_t count = 0;
|
||||
for (uint8_t i = 0; i < nodeDB->getNumMeshNodes(); i++) {
|
||||
meshtastic_NodeInfoLite *node = nodeDB->getMeshNodeByIndex(i);
|
||||
|
||||
// Count nodes
|
||||
|
||||
@@ -127,11 +127,6 @@ void InkHUD::NodeListApplet::onRender()
|
||||
// Y value (top) of the current card. Increases as we draw.
|
||||
uint16_t cardTopY = headerDivY + padDivH;
|
||||
|
||||
// Clean up deleted nodes before drawing
|
||||
cards.erase(
|
||||
std::remove_if(cards.begin(), cards.end(), [](const CardInfo &c) { return nodeDB->getMeshNode(c.nodeNum) == nullptr; }),
|
||||
cards.end());
|
||||
|
||||
// -- Each node in list --
|
||||
for (auto card = cards.begin(); card != cards.end(); ++card) {
|
||||
|
||||
@@ -146,11 +141,6 @@ void InkHUD::NodeListApplet::onRender()
|
||||
|
||||
meshtastic_NodeInfoLite *node = nodeDB->getMeshNode(nodeNum);
|
||||
|
||||
// Skip deleted nodes
|
||||
if (!node) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// -- Shortname --
|
||||
// Parse special chars in the short name
|
||||
// Use "?" if unknown
|
||||
@@ -198,7 +188,7 @@ void InkHUD::NodeListApplet::onRender()
|
||||
drawSignalIndicator(signalX, signalY, signalW, signalH, signal);
|
||||
}
|
||||
// Otherwise, print "hops away" info, if available
|
||||
else if (hopsAway != CardInfo::HOPS_UNKNOWN && node) {
|
||||
else if (hopsAway != CardInfo::HOPS_UNKNOWN) {
|
||||
std::string hopString = to_string(node->hops_away);
|
||||
hopString += " Hop";
|
||||
if (node->hops_away != 1)
|
||||
|
||||
@@ -709,7 +709,7 @@ void InkHUD::MenuApplet::drawSystemInfoPanel(int16_t left, int16_t top, uint16_t
|
||||
// Voltage
|
||||
float voltage = powerStatus->getBatteryVoltageMv() / 1000.0;
|
||||
char voltageStr[6]; // "XX.XV"
|
||||
sprintf(voltageStr, "%.2fV", voltage);
|
||||
sprintf(voltageStr, "%.1fV", voltage);
|
||||
printAt(colC[0], labelT, "Bat", CENTER, TOP);
|
||||
printAt(colC[0], valT, voltageStr, CENTER, TOP);
|
||||
|
||||
|
||||
45
src/main.cpp
45
src/main.cpp
@@ -23,7 +23,6 @@
|
||||
#include "power.h"
|
||||
|
||||
#if !MESHTASTIC_EXCLUDE_I2C
|
||||
#include "detect/ScanI2CConsumer.h"
|
||||
#include "detect/ScanI2CTwoWire.h"
|
||||
#include <Wire.h>
|
||||
#endif
|
||||
@@ -436,12 +435,6 @@ void setup()
|
||||
|
||||
LOG_INFO("\n\n//\\ E S H T /\\ S T / C\n");
|
||||
|
||||
#if defined(DEBUG_MUTE) && defined(DEBUG_PORT)
|
||||
DEBUG_PORT.printf("\r\n\r\n//\\ E S H T /\\ S T / C\r\n");
|
||||
DEBUG_PORT.printf("Version %s for %s from %s\r\n", optstr(APP_VERSION), optstr(APP_ENV), optstr(APP_REPO));
|
||||
DEBUG_PORT.printf("Debug mute is enabled, there will be no serial output.\r\n");
|
||||
#endif
|
||||
|
||||
initDeepSleep();
|
||||
|
||||
#if defined(MODEM_POWER_EN)
|
||||
@@ -725,21 +718,46 @@ void setup()
|
||||
LOG_DEBUG("acc_info = %i", acc_info.type);
|
||||
#endif
|
||||
|
||||
scannerToSensorsMap(i2cScanner, ScanI2C::DeviceType::BME_680, meshtastic_TelemetrySensorType_BME680);
|
||||
scannerToSensorsMap(i2cScanner, ScanI2C::DeviceType::BME_280, meshtastic_TelemetrySensorType_BME280);
|
||||
scannerToSensorsMap(i2cScanner, ScanI2C::DeviceType::BMP_280, meshtastic_TelemetrySensorType_BMP280);
|
||||
scannerToSensorsMap(i2cScanner, ScanI2C::DeviceType::BMP_3XX, meshtastic_TelemetrySensorType_BMP3XX);
|
||||
scannerToSensorsMap(i2cScanner, ScanI2C::DeviceType::BMP_085, meshtastic_TelemetrySensorType_BMP085);
|
||||
scannerToSensorsMap(i2cScanner, ScanI2C::DeviceType::INA260, meshtastic_TelemetrySensorType_INA260);
|
||||
scannerToSensorsMap(i2cScanner, ScanI2C::DeviceType::INA226, meshtastic_TelemetrySensorType_INA226);
|
||||
scannerToSensorsMap(i2cScanner, ScanI2C::DeviceType::INA219, meshtastic_TelemetrySensorType_INA219);
|
||||
scannerToSensorsMap(i2cScanner, ScanI2C::DeviceType::INA3221, meshtastic_TelemetrySensorType_INA3221);
|
||||
scannerToSensorsMap(i2cScanner, ScanI2C::DeviceType::MAX17048, meshtastic_TelemetrySensorType_MAX17048);
|
||||
scannerToSensorsMap(i2cScanner, ScanI2C::DeviceType::MCP9808, meshtastic_TelemetrySensorType_MCP9808);
|
||||
scannerToSensorsMap(i2cScanner, ScanI2C::DeviceType::SHT31, meshtastic_TelemetrySensorType_SHT31);
|
||||
scannerToSensorsMap(i2cScanner, ScanI2C::DeviceType::SHTC3, meshtastic_TelemetrySensorType_SHTC3);
|
||||
scannerToSensorsMap(i2cScanner, ScanI2C::DeviceType::LPS22HB, meshtastic_TelemetrySensorType_LPS22);
|
||||
scannerToSensorsMap(i2cScanner, ScanI2C::DeviceType::QMC6310, meshtastic_TelemetrySensorType_QMC6310);
|
||||
scannerToSensorsMap(i2cScanner, ScanI2C::DeviceType::QMI8658, meshtastic_TelemetrySensorType_QMI8658);
|
||||
scannerToSensorsMap(i2cScanner, ScanI2C::DeviceType::QMC5883L, meshtastic_TelemetrySensorType_QMC5883L);
|
||||
scannerToSensorsMap(i2cScanner, ScanI2C::DeviceType::HMC5883L, meshtastic_TelemetrySensorType_QMC5883L);
|
||||
scannerToSensorsMap(i2cScanner, ScanI2C::DeviceType::PMSA0031, meshtastic_TelemetrySensorType_PMSA003I);
|
||||
scannerToSensorsMap(i2cScanner, ScanI2C::DeviceType::RCWL9620, meshtastic_TelemetrySensorType_RCWL9620);
|
||||
scannerToSensorsMap(i2cScanner, ScanI2C::DeviceType::VEML7700, meshtastic_TelemetrySensorType_VEML7700);
|
||||
scannerToSensorsMap(i2cScanner, ScanI2C::DeviceType::TSL2591, meshtastic_TelemetrySensorType_TSL25911FN);
|
||||
scannerToSensorsMap(i2cScanner, ScanI2C::DeviceType::OPT3001, meshtastic_TelemetrySensorType_OPT3001);
|
||||
scannerToSensorsMap(i2cScanner, ScanI2C::DeviceType::MLX90632, meshtastic_TelemetrySensorType_MLX90632);
|
||||
scannerToSensorsMap(i2cScanner, ScanI2C::DeviceType::MLX90614, meshtastic_TelemetrySensorType_MLX90614);
|
||||
scannerToSensorsMap(i2cScanner, ScanI2C::DeviceType::SHT4X, meshtastic_TelemetrySensorType_SHT4X);
|
||||
scannerToSensorsMap(i2cScanner, ScanI2C::DeviceType::AHT10, meshtastic_TelemetrySensorType_AHT10);
|
||||
scannerToSensorsMap(i2cScanner, ScanI2C::DeviceType::DFROBOT_LARK, meshtastic_TelemetrySensorType_DFROBOT_LARK);
|
||||
scannerToSensorsMap(i2cScanner, ScanI2C::DeviceType::ICM20948, meshtastic_TelemetrySensorType_ICM20948);
|
||||
scannerToSensorsMap(i2cScanner, ScanI2C::DeviceType::MAX30102, meshtastic_TelemetrySensorType_MAX30102);
|
||||
scannerToSensorsMap(i2cScanner, ScanI2C::DeviceType::CGRADSENS, meshtastic_TelemetrySensorType_RADSENS);
|
||||
scannerToSensorsMap(i2cScanner, ScanI2C::DeviceType::DFROBOT_RAIN, meshtastic_TelemetrySensorType_DFROBOT_RAIN);
|
||||
scannerToSensorsMap(i2cScanner, ScanI2C::DeviceType::LTR390UV, meshtastic_TelemetrySensorType_LTR390UV);
|
||||
scannerToSensorsMap(i2cScanner, ScanI2C::DeviceType::DPS310, meshtastic_TelemetrySensorType_DPS310);
|
||||
scannerToSensorsMap(i2cScanner, ScanI2C::DeviceType::RAK12035, meshtastic_TelemetrySensorType_RAK12035);
|
||||
scannerToSensorsMap(i2cScanner, ScanI2C::DeviceType::PCT2075, meshtastic_TelemetrySensorType_PCT2075);
|
||||
scannerToSensorsMap(i2cScanner, ScanI2C::DeviceType::SCD4X, meshtastic_TelemetrySensorType_SCD4X);
|
||||
scannerToSensorsMap(i2cScanner, ScanI2C::DeviceType::TSL2561, meshtastic_TelemetrySensorType_TSL2561);
|
||||
|
||||
i2cScanner.reset();
|
||||
#endif
|
||||
|
||||
#ifdef HAS_SDCARD
|
||||
@@ -847,14 +865,7 @@ void setup()
|
||||
SPI.begin();
|
||||
}
|
||||
#elif !defined(ARCH_ESP32) // ARCH_RP2040
|
||||
#if defined(RAK3401) || defined(RAK13302)
|
||||
pinMode(WB_IO2, OUTPUT);
|
||||
digitalWrite(WB_IO2, HIGH);
|
||||
SPI1.setPins(LORA_MISO, LORA_SCK, LORA_MOSI);
|
||||
SPI1.begin();
|
||||
#else
|
||||
SPI.begin();
|
||||
#endif
|
||||
#else
|
||||
// ESP32
|
||||
#if defined(HW_SPI1_DEVICE)
|
||||
@@ -953,12 +964,6 @@ void setup()
|
||||
// Now that the mesh service is created, create any modules
|
||||
setupModules();
|
||||
|
||||
#if !MESHTASTIC_EXCLUDE_I2C
|
||||
// Inform modules about I2C devices
|
||||
ScanI2CCompleted(i2cScanner.get());
|
||||
i2cScanner.reset();
|
||||
#endif
|
||||
|
||||
// warn the user about a low entropy key
|
||||
if (nodeDB->keyIsLowEntropy && !nodeDB->hasWarned) {
|
||||
LOG_WARN(LOW_ENTROPY_WARNING);
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
#ifdef USERPREFS_RINGTONE_NAG_SECS
|
||||
#define default_ringtone_nag_secs USERPREFS_RINGTONE_NAG_SECS
|
||||
#else
|
||||
#define default_ringtone_nag_secs 15
|
||||
#define default_ringtone_nag_secs 60
|
||||
#endif
|
||||
|
||||
#define default_mqtt_address "mqtt.meshtastic.org"
|
||||
@@ -46,15 +46,12 @@ class Default
|
||||
static uint32_t getConfiguredOrDefaultMs(uint32_t configuredInterval);
|
||||
static uint32_t getConfiguredOrDefaultMs(uint32_t configuredInterval, uint32_t defaultInterval);
|
||||
static uint32_t getConfiguredOrDefault(uint32_t configured, uint32_t defaultValue);
|
||||
// Note: numOnlineNodes uses uint32_t to match the public API and allow flexibility,
|
||||
// even though internal node counts use uint16_t (max 65535 nodes)
|
||||
static uint32_t getConfiguredOrDefaultMsScaled(uint32_t configured, uint32_t defaultValue, uint32_t numOnlineNodes);
|
||||
static uint8_t getConfiguredOrDefaultHopLimit(uint8_t configured);
|
||||
static uint32_t getConfiguredOrMinimumValue(uint32_t configured, uint32_t minValue);
|
||||
|
||||
private:
|
||||
// Note: Kept as uint32_t to match the public API parameter type
|
||||
static float congestionScalingCoefficient(uint32_t numOnlineNodes)
|
||||
static float congestionScalingCoefficient(int numOnlineNodes)
|
||||
{
|
||||
// Increase frequency of broadcasts for small networks regardless of preset
|
||||
if (numOnlineNodes <= 10) {
|
||||
@@ -87,4 +84,4 @@ class Default
|
||||
return 1.0 + (nodesOverForty * throttlingFactor); // Each number of online node scales by 0.075 (default)
|
||||
}
|
||||
}
|
||||
};
|
||||
};
|
||||
@@ -218,7 +218,6 @@ template <typename T> void LR11x0Interface<T>::addReceiveMetadata(meshtastic_Mes
|
||||
// LOG_DEBUG("PacketStatus %x", lora.getPacketStatus());
|
||||
mp->rx_snr = lora.getSNR();
|
||||
mp->rx_rssi = lround(lora.getRSSI());
|
||||
LOG_DEBUG("Corrected frequency offset: %f", lora.getFrequencyError());
|
||||
}
|
||||
|
||||
/** We override to turn on transmitter power as needed.
|
||||
|
||||
@@ -1,253 +0,0 @@
|
||||
#include "PacketCache.h"
|
||||
#include "Router.h"
|
||||
|
||||
PacketCache packetCache{};
|
||||
|
||||
/**
|
||||
* Allocate a new cache entry and copy the packet header and payload into it
|
||||
*/
|
||||
PacketCacheEntry *PacketCache::cache(const meshtastic_MeshPacket *p, bool preserveMetadata)
|
||||
{
|
||||
size_t payload_size =
|
||||
(p->which_payload_variant == meshtastic_MeshPacket_encrypted_tag) ? p->encrypted.size : p->decoded.payload.size;
|
||||
PacketCacheEntry *e = (PacketCacheEntry *)malloc(sizeof(PacketCacheEntry) + payload_size +
|
||||
(preserveMetadata ? sizeof(PacketCacheMetadata) : 0));
|
||||
if (!e) {
|
||||
LOG_ERROR("Unable to allocate memory for packet cache entry");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
*e = {};
|
||||
e->header.from = p->from;
|
||||
e->header.to = p->to;
|
||||
e->header.id = p->id;
|
||||
e->header.channel = p->channel;
|
||||
e->header.next_hop = p->next_hop;
|
||||
e->header.relay_node = p->relay_node;
|
||||
e->header.flags = (p->hop_limit & PACKET_FLAGS_HOP_LIMIT_MASK) | (p->want_ack ? PACKET_FLAGS_WANT_ACK_MASK : 0) |
|
||||
(p->via_mqtt ? PACKET_FLAGS_VIA_MQTT_MASK : 0) |
|
||||
((p->hop_start << PACKET_FLAGS_HOP_START_SHIFT) & PACKET_FLAGS_HOP_START_MASK);
|
||||
|
||||
PacketCacheMetadata m{};
|
||||
if (preserveMetadata) {
|
||||
e->has_metadata = true;
|
||||
m.rx_rssi = (uint8_t)(p->rx_rssi + 200);
|
||||
m.rx_snr = (uint8_t)((p->rx_snr + 30.0f) / 0.25f);
|
||||
m.rx_time = p->rx_time;
|
||||
m.transport_mechanism = p->transport_mechanism;
|
||||
m.priority = p->priority;
|
||||
}
|
||||
if (p->which_payload_variant == meshtastic_MeshPacket_encrypted_tag) {
|
||||
e->encrypted = true;
|
||||
e->payload_len = p->encrypted.size;
|
||||
memcpy(((unsigned char *)e) + sizeof(PacketCacheEntry), p->encrypted.bytes, p->encrypted.size);
|
||||
} else if (p->which_payload_variant == meshtastic_MeshPacket_decoded_tag) {
|
||||
e->encrypted = false;
|
||||
if (preserveMetadata) {
|
||||
m.portnum = p->decoded.portnum;
|
||||
m.want_response = p->decoded.want_response;
|
||||
m.emoji = p->decoded.emoji;
|
||||
m.bitfield = p->decoded.bitfield;
|
||||
if (p->decoded.reply_id)
|
||||
m.reply_id = p->decoded.reply_id;
|
||||
else if (p->decoded.request_id)
|
||||
m.request_id = p->decoded.request_id;
|
||||
}
|
||||
e->payload_len = p->decoded.payload.size;
|
||||
memcpy(((unsigned char *)e) + sizeof(PacketCacheEntry), p->decoded.payload.bytes, p->decoded.payload.size);
|
||||
} else {
|
||||
LOG_ERROR("Unable to cache packet with unknown payload type %d", p->which_payload_variant);
|
||||
free(e);
|
||||
return NULL;
|
||||
}
|
||||
if (preserveMetadata)
|
||||
memcpy(((unsigned char *)e) + sizeof(PacketCacheEntry) + e->payload_len, &m, sizeof(m));
|
||||
|
||||
size += sizeof(PacketCacheEntry) + e->payload_len + (e->has_metadata ? sizeof(PacketCacheMetadata) : 0);
|
||||
insert(e);
|
||||
return e;
|
||||
};
|
||||
|
||||
/**
|
||||
* Dump a list of packets into the provided buffer
|
||||
*/
|
||||
void PacketCache::dump(void *dest, const PacketCacheEntry **entries, size_t num_entries)
|
||||
{
|
||||
unsigned char *pos = (unsigned char *)dest;
|
||||
for (size_t i = 0; i < num_entries; i++) {
|
||||
size_t entry_len =
|
||||
sizeof(PacketCacheEntry) + entries[i]->payload_len + (entries[i]->has_metadata ? sizeof(PacketCacheMetadata) : 0);
|
||||
memcpy(pos, entries[i], entry_len);
|
||||
pos += entry_len;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate the length of buffer needed to dump the specified entries
|
||||
*/
|
||||
size_t PacketCache::dumpSize(const PacketCacheEntry **entries, size_t num_entries)
|
||||
{
|
||||
size_t total_size = 0;
|
||||
for (size_t i = 0; i < num_entries; i++) {
|
||||
total_size += sizeof(PacketCacheEntry) + entries[i]->payload_len;
|
||||
if (entries[i]->has_metadata)
|
||||
total_size += sizeof(PacketCacheMetadata);
|
||||
}
|
||||
return total_size;
|
||||
}
|
||||
|
||||
/**
|
||||
* Find a packet in the cache
|
||||
*/
|
||||
PacketCacheEntry *PacketCache::find(NodeNum from, PacketId id)
|
||||
{
|
||||
uint16_t h = PACKET_HASH(from, id);
|
||||
PacketCacheEntry *e = buckets[PACKET_CACHE_BUCKET(h)];
|
||||
while (e) {
|
||||
if (e->header.from == from && e->header.id == id)
|
||||
return e;
|
||||
e = e->next;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Find a packet in the cache by its hash
|
||||
*/
|
||||
PacketCacheEntry *PacketCache::find(PacketHash h)
|
||||
{
|
||||
PacketCacheEntry *e = buckets[PACKET_CACHE_BUCKET(h)];
|
||||
while (e) {
|
||||
if (PACKET_HASH(e->header.from, e->header.id) == h)
|
||||
return e;
|
||||
e = e->next;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Load a list of packets from the provided buffer
|
||||
*/
|
||||
bool PacketCache::load(void *src, PacketCacheEntry **entries, size_t num_entries)
|
||||
{
|
||||
memset(entries, 0, sizeof(PacketCacheEntry *) * num_entries);
|
||||
unsigned char *pos = (unsigned char *)src;
|
||||
for (size_t i = 0; i < num_entries; i++) {
|
||||
PacketCacheEntry e{};
|
||||
memcpy(&e, pos, sizeof(PacketCacheEntry));
|
||||
size_t entry_len = sizeof(PacketCacheEntry) + e.payload_len + (e.has_metadata ? sizeof(PacketCacheMetadata) : 0);
|
||||
entries[i] = (PacketCacheEntry *)malloc(entry_len);
|
||||
size += entry_len;
|
||||
if (!entries[i]) {
|
||||
LOG_ERROR("Unable to allocate memory for packet cache entry");
|
||||
for (size_t j = 0; j < i; j++) {
|
||||
size -= sizeof(PacketCacheEntry) + entries[j]->payload_len +
|
||||
(entries[j]->has_metadata ? sizeof(PacketCacheMetadata) : 0);
|
||||
free(entries[j]);
|
||||
entries[j] = NULL;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
memcpy(entries[i], pos, entry_len);
|
||||
pos += entry_len;
|
||||
}
|
||||
for (size_t i = 0; i < num_entries; i++)
|
||||
insert(entries[i]);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy the cached packet into the provided MeshPacket structure
|
||||
*/
|
||||
void PacketCache::rehydrate(const PacketCacheEntry *e, meshtastic_MeshPacket *p)
|
||||
{
|
||||
if (!e || !p)
|
||||
return;
|
||||
|
||||
*p = {};
|
||||
p->from = e->header.from;
|
||||
p->to = e->header.to;
|
||||
p->id = e->header.id;
|
||||
p->channel = e->header.channel;
|
||||
p->next_hop = e->header.next_hop;
|
||||
p->relay_node = e->header.relay_node;
|
||||
p->hop_limit = e->header.flags & PACKET_FLAGS_HOP_LIMIT_MASK;
|
||||
p->want_ack = !!(e->header.flags & PACKET_FLAGS_WANT_ACK_MASK);
|
||||
p->via_mqtt = !!(e->header.flags & PACKET_FLAGS_VIA_MQTT_MASK);
|
||||
p->hop_start = (e->header.flags & PACKET_FLAGS_HOP_START_MASK) >> PACKET_FLAGS_HOP_START_SHIFT;
|
||||
p->which_payload_variant = e->encrypted ? meshtastic_MeshPacket_encrypted_tag : meshtastic_MeshPacket_decoded_tag;
|
||||
|
||||
unsigned char *payload = ((unsigned char *)e) + sizeof(PacketCacheEntry);
|
||||
PacketCacheMetadata m{};
|
||||
if (e->has_metadata) {
|
||||
memcpy(&m, (payload + e->payload_len), sizeof(m));
|
||||
p->rx_rssi = ((int)m.rx_rssi) - 200;
|
||||
p->rx_snr = ((float)m.rx_snr * 0.25f) - 30.0f;
|
||||
p->rx_time = m.rx_time;
|
||||
p->transport_mechanism = (meshtastic_MeshPacket_TransportMechanism)m.transport_mechanism;
|
||||
p->priority = (meshtastic_MeshPacket_Priority)m.priority;
|
||||
}
|
||||
if (e->encrypted) {
|
||||
memcpy(p->encrypted.bytes, payload, e->payload_len);
|
||||
p->encrypted.size = e->payload_len;
|
||||
} else {
|
||||
memcpy(p->decoded.payload.bytes, payload, e->payload_len);
|
||||
p->decoded.payload.size = e->payload_len;
|
||||
if (e->has_metadata) {
|
||||
// Decrypted-only metadata
|
||||
p->decoded.portnum = (meshtastic_PortNum)m.portnum;
|
||||
p->decoded.want_response = m.want_response;
|
||||
p->decoded.emoji = m.emoji;
|
||||
p->decoded.bitfield = m.bitfield;
|
||||
if (m.reply_id)
|
||||
p->decoded.reply_id = m.reply_id;
|
||||
else if (m.request_id)
|
||||
p->decoded.request_id = m.request_id;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Release a cache entry
|
||||
*/
|
||||
void PacketCache::release(PacketCacheEntry *e)
|
||||
{
|
||||
if (!e)
|
||||
return;
|
||||
remove(e);
|
||||
size -= sizeof(PacketCacheEntry) + e->payload_len + (e->has_metadata ? sizeof(PacketCacheMetadata) : 0);
|
||||
free(e);
|
||||
}
|
||||
|
||||
/**
|
||||
* Insert a new entry into the hash table
|
||||
*/
|
||||
void PacketCache::insert(PacketCacheEntry *e)
|
||||
{
|
||||
assert(e);
|
||||
PacketHash h = PACKET_HASH(e->header.from, e->header.id);
|
||||
PacketCacheEntry **target = &buckets[PACKET_CACHE_BUCKET(h)];
|
||||
e->next = *target;
|
||||
*target = e;
|
||||
num_entries++;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove an entry from the hash table
|
||||
*/
|
||||
void PacketCache::remove(PacketCacheEntry *e)
|
||||
{
|
||||
assert(e);
|
||||
PacketHash h = PACKET_HASH(e->header.from, e->header.id);
|
||||
PacketCacheEntry **target = &buckets[PACKET_CACHE_BUCKET(h)];
|
||||
while (*target) {
|
||||
if (*target == e) {
|
||||
*target = e->next;
|
||||
e->next = NULL;
|
||||
num_entries--;
|
||||
break;
|
||||
} else {
|
||||
target = &(*target)->next;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,75 +0,0 @@
|
||||
#pragma once
|
||||
#include "RadioInterface.h"
|
||||
|
||||
#define PACKET_HASH(a, b) ((((a ^ b) >> 16) ^ (a ^ b)) & 0xFFFF) // 16 bit fold of packet (from, id) tuple
|
||||
typedef uint16_t PacketHash;
|
||||
|
||||
#define PACKET_CACHE_BUCKETS 64 // Number of hash table buckets
|
||||
#define PACKET_CACHE_BUCKET(h) (((h >> 12) ^ (h >> 6) ^ h) & 0x3F) // Fold hash down to 6-bit bucket index
|
||||
|
||||
typedef struct PacketCacheEntry {
|
||||
PacketCacheEntry *next;
|
||||
PacketHeader header;
|
||||
uint16_t payload_len = 0;
|
||||
union {
|
||||
uint16_t bitfield;
|
||||
struct {
|
||||
uint8_t encrypted : 1; // Payload is encrypted
|
||||
uint8_t has_metadata : 1; // Payload includes PacketCacheMetadata
|
||||
uint8_t : 6; // Reserved for future use
|
||||
uint8_t : 8; // Reserved for future use
|
||||
};
|
||||
};
|
||||
} PacketCacheEntry;
|
||||
|
||||
typedef struct PacketCacheMetadata {
|
||||
PacketCacheMetadata() : _bitfield(0), reply_id(0), _bitfield2(0) {}
|
||||
union {
|
||||
uint32_t _bitfield;
|
||||
struct {
|
||||
uint16_t portnum : 9; // meshtastic_MeshPacket::decoded::portnum
|
||||
uint16_t want_response : 1; // meshtastic_MeshPacket::decoded::want_response
|
||||
uint16_t emoji : 1; // meshtastic_MeshPacket::decoded::emoji
|
||||
uint16_t bitfield : 5; // meshtastic_MeshPacket::decoded::bitfield (truncated)
|
||||
uint8_t rx_rssi : 8; // meshtastic_MeshPacket::rx_rssi (map via actual RSSI + 200)
|
||||
uint8_t rx_snr : 8; // meshtastic_MeshPacket::rx_snr (map via (p->rx_snr + 30.0f) / 0.25f)
|
||||
};
|
||||
};
|
||||
union {
|
||||
uint32_t reply_id; // meshtastic_MeshPacket::decoded.reply_id
|
||||
uint32_t request_id; // meshtastic_MeshPacket::decoded.request_id
|
||||
};
|
||||
uint32_t rx_time = 0; // meshtastic_MeshPacket::rx_time
|
||||
uint8_t transport_mechanism = 0; // meshtastic_MeshPacket::transport_mechanism
|
||||
struct {
|
||||
uint8_t _bitfield2;
|
||||
union {
|
||||
uint8_t priority : 7; // meshtastic_MeshPacket::priority
|
||||
uint8_t reserved : 1; // Reserved for future use
|
||||
};
|
||||
};
|
||||
} PacketCacheMetadata;
|
||||
|
||||
class PacketCache
|
||||
{
|
||||
public:
|
||||
PacketCacheEntry *cache(const meshtastic_MeshPacket *p, bool preserveMetadata);
|
||||
static void dump(void *dest, const PacketCacheEntry **entries, size_t num_entries);
|
||||
size_t dumpSize(const PacketCacheEntry **entries, size_t num_entries);
|
||||
PacketCacheEntry *find(NodeNum from, PacketId id);
|
||||
PacketCacheEntry *find(PacketHash h);
|
||||
bool load(void *src, PacketCacheEntry **entries, size_t num_entries);
|
||||
size_t getNumEntries() { return num_entries; }
|
||||
size_t getSize() { return size; }
|
||||
void rehydrate(const PacketCacheEntry *e, meshtastic_MeshPacket *p);
|
||||
void release(PacketCacheEntry *e);
|
||||
|
||||
private:
|
||||
PacketCacheEntry *buckets[PACKET_CACHE_BUCKETS]{};
|
||||
size_t num_entries = 0;
|
||||
size_t size = 0;
|
||||
void insert(PacketCacheEntry *e);
|
||||
void remove(PacketCacheEntry *e);
|
||||
};
|
||||
|
||||
extern PacketCache packetCache;
|
||||
@@ -15,7 +15,6 @@
|
||||
#include "Router.h"
|
||||
#include "SPILock.h"
|
||||
#include "TypeConversions.h"
|
||||
#include "concurrency/LockGuard.h"
|
||||
#include "main.h"
|
||||
#include "xmodem.h"
|
||||
|
||||
@@ -57,9 +56,6 @@ void PhoneAPI::handleStartConfig()
|
||||
#endif
|
||||
}
|
||||
|
||||
// Allow subclasses to prepare for high-throughput config traffic
|
||||
onConfigStart();
|
||||
|
||||
// even if we were already connected - restart our state machine
|
||||
if (config_nonce == SPECIAL_NONCE_ONLY_NODES) {
|
||||
// If client only wants node info, jump directly to sending nodes
|
||||
@@ -74,13 +70,8 @@ void PhoneAPI::handleStartConfig()
|
||||
spiLock->unlock();
|
||||
LOG_DEBUG("Got %d files in manifest", filesManifest.size());
|
||||
|
||||
LOG_INFO("Start API client config millis=%u", millis());
|
||||
// Protect against concurrent BLE callbacks: they run in NimBLE's FreeRTOS task and also touch nodeInfoQueue.
|
||||
{
|
||||
concurrency::LockGuard guard(&nodeInfoMutex);
|
||||
nodeInfoForPhone = {};
|
||||
nodeInfoQueue.clear();
|
||||
}
|
||||
LOG_INFO("Start API client config");
|
||||
nodeInfoForPhone.num = 0; // Don't keep returning old nodeinfos
|
||||
resetReadIndex();
|
||||
}
|
||||
|
||||
@@ -102,12 +93,7 @@ void PhoneAPI::close()
|
||||
onConnectionChanged(false);
|
||||
fromRadioScratch = {};
|
||||
toRadioScratch = {};
|
||||
// Clear cached node info under lock because NimBLE callbacks can still be draining it.
|
||||
{
|
||||
concurrency::LockGuard guard(&nodeInfoMutex);
|
||||
nodeInfoForPhone = {};
|
||||
nodeInfoQueue.clear();
|
||||
}
|
||||
nodeInfoForPhone = {};
|
||||
packetForPhone = NULL;
|
||||
filesManifest.clear();
|
||||
fromRadioNum = 0;
|
||||
@@ -162,10 +148,6 @@ bool PhoneAPI::handleToRadio(const uint8_t *buf, size_t bufLength)
|
||||
#if !MESHTASTIC_EXCLUDE_MQTT
|
||||
case meshtastic_ToRadio_mqttClientProxyMessage_tag:
|
||||
LOG_DEBUG("Got MqttClientProxy message");
|
||||
if (state != STATE_SEND_PACKETS) {
|
||||
LOG_WARN("Ignore MqttClientProxy message while completing config handshake");
|
||||
break;
|
||||
}
|
||||
if (mqtt && moduleConfig.mqtt.proxy_to_client_enabled && moduleConfig.mqtt.enabled &&
|
||||
(channels.anyMqttEnabled() || moduleConfig.mqtt.map_reporting_enabled)) {
|
||||
mqtt->onClientProxyReceive(toRadioScratch.mqttClientProxyMessage);
|
||||
@@ -257,20 +239,13 @@ size_t PhoneAPI::getFromRadio(uint8_t *buf)
|
||||
LOG_DEBUG("Send My NodeInfo");
|
||||
auto us = nodeDB->readNextMeshNode(readIndex);
|
||||
if (us) {
|
||||
auto info = TypeConversions::ConvertToNodeInfo(us);
|
||||
info.has_hops_away = false;
|
||||
info.is_favorite = true;
|
||||
{
|
||||
concurrency::LockGuard guard(&nodeInfoMutex);
|
||||
nodeInfoForPhone = info;
|
||||
}
|
||||
nodeInfoForPhone = TypeConversions::ConvertToNodeInfo(us);
|
||||
nodeInfoForPhone.has_hops_away = false;
|
||||
nodeInfoForPhone.is_favorite = true;
|
||||
fromRadioScratch.which_payload_variant = meshtastic_FromRadio_node_info_tag;
|
||||
fromRadioScratch.node_info = info;
|
||||
fromRadioScratch.node_info = nodeInfoForPhone;
|
||||
// Should allow us to resume sending NodeInfo in STATE_SEND_OTHER_NODEINFOS
|
||||
{
|
||||
concurrency::LockGuard guard(&nodeInfoMutex);
|
||||
nodeInfoForPhone.num = 0;
|
||||
}
|
||||
nodeInfoForPhone.num = 0;
|
||||
}
|
||||
if (config_nonce == SPECIAL_NONCE_ONLY_NODES) {
|
||||
// If client only wants node info, jump directly to sending nodes
|
||||
@@ -456,44 +431,17 @@ size_t PhoneAPI::getFromRadio(uint8_t *buf)
|
||||
break;
|
||||
|
||||
case STATE_SEND_OTHER_NODEINFOS: {
|
||||
if (readIndex == 2) { // readIndex==2 will be true for the first non-us node
|
||||
LOG_INFO("Start sending nodeinfos millis=%u", millis());
|
||||
}
|
||||
|
||||
meshtastic_NodeInfo infoToSend = {};
|
||||
{
|
||||
concurrency::LockGuard guard(&nodeInfoMutex);
|
||||
if (nodeInfoForPhone.num == 0 && !nodeInfoQueue.empty()) {
|
||||
// Serve the next cached node without re-reading from the DB iterator.
|
||||
nodeInfoForPhone = nodeInfoQueue.front();
|
||||
nodeInfoQueue.pop_front();
|
||||
}
|
||||
infoToSend = nodeInfoForPhone;
|
||||
if (infoToSend.num != 0)
|
||||
nodeInfoForPhone = {};
|
||||
}
|
||||
|
||||
if (infoToSend.num != 0) {
|
||||
if (nodeInfoForPhone.num != 0) {
|
||||
// Just in case we stored a different user.id in the past, but should never happen going forward
|
||||
sprintf(infoToSend.user.id, "!%08x", infoToSend.num);
|
||||
|
||||
// Logging this really slows down sending nodes on initial connection because the serial console is so slow, so only
|
||||
// uncomment if you really need to:
|
||||
// LOG_INFO("nodeinfo: num=0x%x, lastseen=%u, id=%s, name=%s", nodeInfoForPhone.num, nodeInfoForPhone.last_heard,
|
||||
// nodeInfoForPhone.user.id, nodeInfoForPhone.user.long_name);
|
||||
|
||||
// Occasional progress logging. (readIndex==2 will be true for the first non-us node)
|
||||
if (readIndex == 2 || readIndex % 20 == 0) {
|
||||
LOG_DEBUG("nodeinfo: %d/%d", readIndex, nodeDB->getNumMeshNodes());
|
||||
}
|
||||
|
||||
sprintf(nodeInfoForPhone.user.id, "!%08x", nodeInfoForPhone.num);
|
||||
LOG_INFO("nodeinfo: num=0x%x, lastseen=%u, id=%s, name=%s", nodeInfoForPhone.num, nodeInfoForPhone.last_heard,
|
||||
nodeInfoForPhone.user.id, nodeInfoForPhone.user.long_name);
|
||||
fromRadioScratch.which_payload_variant = meshtastic_FromRadio_node_info_tag;
|
||||
fromRadioScratch.node_info = infoToSend;
|
||||
prefetchNodeInfos();
|
||||
fromRadioScratch.node_info = nodeInfoForPhone;
|
||||
// Stay in current state until done sending nodeinfos
|
||||
nodeInfoForPhone.num = 0; // We just consumed a nodeinfo, will need a new one next time
|
||||
} else {
|
||||
LOG_DEBUG("Done sending %d of %d nodeinfos millis=%u", readIndex, nodeDB->getNumMeshNodes(), millis());
|
||||
concurrency::LockGuard guard(&nodeInfoMutex);
|
||||
nodeInfoQueue.clear();
|
||||
LOG_DEBUG("Done sending nodeinfo");
|
||||
state = STATE_SEND_FILEMANIFEST;
|
||||
// Go ahead and send that ID right now
|
||||
return getFromRadio(buf);
|
||||
@@ -573,15 +521,11 @@ size_t PhoneAPI::getFromRadio(uint8_t *buf)
|
||||
|
||||
void PhoneAPI::sendConfigComplete()
|
||||
{
|
||||
LOG_INFO("Config Send Complete millis=%u", millis());
|
||||
LOG_INFO("Config Send Complete");
|
||||
fromRadioScratch.which_payload_variant = meshtastic_FromRadio_config_complete_id_tag;
|
||||
fromRadioScratch.config_complete_id = config_nonce;
|
||||
config_nonce = 0;
|
||||
state = STATE_SEND_PACKETS;
|
||||
|
||||
// Allow subclasses to know we've entered steady-state so they can lower power consumption
|
||||
onConfigComplete();
|
||||
|
||||
pauseBluetoothLogging = false;
|
||||
}
|
||||
|
||||
@@ -601,33 +545,6 @@ void PhoneAPI::releaseQueueStatusPhonePacket()
|
||||
}
|
||||
}
|
||||
|
||||
void PhoneAPI::prefetchNodeInfos()
|
||||
{
|
||||
bool added = false;
|
||||
// Keep the queue topped up so BLE reads stay responsive even if DB fetches take a moment.
|
||||
{
|
||||
concurrency::LockGuard guard(&nodeInfoMutex);
|
||||
while (nodeInfoQueue.size() < kNodePrefetchDepth) {
|
||||
auto nextNode = nodeDB->readNextMeshNode(readIndex);
|
||||
if (!nextNode)
|
||||
break;
|
||||
|
||||
auto info = TypeConversions::ConvertToNodeInfo(nextNode);
|
||||
bool isUs = info.num == nodeDB->getNodeNum();
|
||||
info.hops_away = isUs ? 0 : info.hops_away;
|
||||
info.last_heard = isUs ? getValidTime(RTCQualityFromNet) : info.last_heard;
|
||||
info.snr = isUs ? 0 : info.snr;
|
||||
info.via_mqtt = isUs ? false : info.via_mqtt;
|
||||
info.is_favorite = info.is_favorite || isUs;
|
||||
nodeInfoQueue.push_back(info);
|
||||
added = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (added)
|
||||
onNowHasData(0);
|
||||
}
|
||||
|
||||
void PhoneAPI::releaseMqttClientProxyPhonePacket()
|
||||
{
|
||||
if (mqttClientProxyMessageForPhone) {
|
||||
@@ -663,17 +580,22 @@ bool PhoneAPI::available()
|
||||
case STATE_SEND_COMPLETE_ID:
|
||||
return true;
|
||||
|
||||
case STATE_SEND_OTHER_NODEINFOS: {
|
||||
concurrency::LockGuard guard(&nodeInfoMutex);
|
||||
if (nodeInfoQueue.empty()) {
|
||||
// Drop the lock before prefetching; prefetchNodeInfos() will re-acquire it.
|
||||
goto PREFETCH_NODEINFO;
|
||||
case STATE_SEND_OTHER_NODEINFOS:
|
||||
if (nodeInfoForPhone.num == 0) {
|
||||
auto nextNode = nodeDB->readNextMeshNode(readIndex);
|
||||
if (nextNode) {
|
||||
nodeInfoForPhone = TypeConversions::ConvertToNodeInfo(nextNode);
|
||||
bool isUs = nodeInfoForPhone.num == nodeDB->getNodeNum();
|
||||
nodeInfoForPhone.hops_away = isUs ? 0 : nodeInfoForPhone.hops_away;
|
||||
nodeInfoForPhone.last_heard = isUs ? getValidTime(RTCQualityFromNet) : nodeInfoForPhone.last_heard;
|
||||
nodeInfoForPhone.snr = isUs ? 0 : nodeInfoForPhone.snr;
|
||||
nodeInfoForPhone.via_mqtt = isUs ? false : nodeInfoForPhone.via_mqtt;
|
||||
nodeInfoForPhone.is_favorite = nodeInfoForPhone.is_favorite || isUs; // Our node is always a favorite
|
||||
|
||||
onNowHasData(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
return true; // Always say we have something, because we might need to advance our state machine
|
||||
PREFETCH_NODEINFO:
|
||||
prefetchNodeInfos();
|
||||
return true;
|
||||
case STATE_SEND_PACKETS: {
|
||||
if (!queueStatusPacketForPhone)
|
||||
queueStatusPacketForPhone = service->getQueueStatusForPhone();
|
||||
|
||||
@@ -1,10 +1,8 @@
|
||||
#pragma once
|
||||
|
||||
#include "Observer.h"
|
||||
#include "concurrency/Lock.h"
|
||||
#include "mesh-pb-constants.h"
|
||||
#include "meshtastic/portnums.pb.h"
|
||||
#include <deque>
|
||||
#include <iterator>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
@@ -81,12 +79,6 @@ class PhoneAPI
|
||||
|
||||
/// We temporarily keep the nodeInfo here between the call to available and getFromRadio
|
||||
meshtastic_NodeInfo nodeInfoForPhone = meshtastic_NodeInfo_init_default;
|
||||
// Prefetched node info entries ready for immediate transmission to the phone.
|
||||
std::deque<meshtastic_NodeInfo> nodeInfoQueue;
|
||||
// Tunable size of the node info cache so we can keep BLE reads non-blocking.
|
||||
static constexpr size_t kNodePrefetchDepth = 4;
|
||||
// Protect nodeInfoForPhone + nodeInfoQueue because NimBLE callbacks run in a separate FreeRTOS task.
|
||||
concurrency::Lock nodeInfoMutex;
|
||||
|
||||
meshtastic_ToRadio toRadioScratch = {
|
||||
0}; // this is a static scratch object, any data must be copied elsewhere before returning
|
||||
@@ -136,7 +128,6 @@ class PhoneAPI
|
||||
bool available();
|
||||
|
||||
bool isConnected() { return state != STATE_SEND_NOTHING; }
|
||||
bool isSendingPackets() { return state == STATE_SEND_PACKETS; }
|
||||
|
||||
protected:
|
||||
/// Our fromradio packet while it is being assembled
|
||||
@@ -159,11 +150,6 @@ class PhoneAPI
|
||||
*/
|
||||
virtual void onNowHasData(uint32_t fromRadioNum) {}
|
||||
|
||||
/// Subclasses can use these lifecycle hooks for transport-specific behavior around config/steady-state
|
||||
/// (i.e. BLE connection params)
|
||||
virtual void onConfigStart() {}
|
||||
virtual void onConfigComplete() {}
|
||||
|
||||
/// begin a new connection
|
||||
void handleStartConfig();
|
||||
|
||||
@@ -172,8 +158,6 @@ class PhoneAPI
|
||||
|
||||
void releaseQueueStatusPhonePacket();
|
||||
|
||||
void prefetchNodeInfos();
|
||||
|
||||
void releaseMqttClientProxyPhonePacket();
|
||||
|
||||
void releaseClientNotification();
|
||||
|
||||
@@ -13,7 +13,7 @@ template <class T> class ProtobufModule : protected SinglePortModule
|
||||
const pb_msgdesc_t *fields;
|
||||
|
||||
public:
|
||||
uint16_t numOnlineNodes = 0;
|
||||
uint8_t numOnlineNodes = 0;
|
||||
/** Constructor
|
||||
* name is for debugging output
|
||||
*/
|
||||
|
||||
@@ -272,10 +272,10 @@ uint32_t RadioInterface::getTxDelayMsec()
|
||||
uint8_t RadioInterface::getCWsize(float snr)
|
||||
{
|
||||
// The minimum value for a LoRa SNR
|
||||
const int32_t SNR_MIN = -20;
|
||||
const uint32_t SNR_MIN = -20;
|
||||
|
||||
// The maximum value for a LoRa SNR
|
||||
const int32_t SNR_MAX = 10;
|
||||
const uint32_t SNR_MAX = 10;
|
||||
|
||||
return map(snr, SNR_MIN, SNR_MAX, CWmin, CWmax);
|
||||
}
|
||||
@@ -647,24 +647,23 @@ void RadioInterface::limitPower(int8_t loraMaxPower)
|
||||
}
|
||||
|
||||
#ifndef NUM_PA_POINTS
|
||||
if (TX_GAIN_LORA > 0 && !devicestate.owner.is_licensed) {
|
||||
if (TX_GAIN_LORA > 0) {
|
||||
LOG_INFO("Requested Tx power: %d dBm; Device LoRa Tx gain: %d dB", power, TX_GAIN_LORA);
|
||||
power -= TX_GAIN_LORA;
|
||||
}
|
||||
#else
|
||||
if (!devicestate.owner.is_licensed) {
|
||||
// we have an array of PA gain values. Find the highest power setting that works.
|
||||
const uint16_t tx_gain[NUM_PA_POINTS] = {TX_GAIN_LORA};
|
||||
for (int radio_dbm = 0; radio_dbm < NUM_PA_POINTS; radio_dbm++) {
|
||||
if (((radio_dbm + tx_gain[radio_dbm]) > power) ||
|
||||
((radio_dbm == (NUM_PA_POINTS - 1)) && ((radio_dbm + tx_gain[radio_dbm]) <= power))) {
|
||||
// we've exceeded the power limit, or hit the max we can do
|
||||
LOG_INFO("Requested Tx power: %d dBm; Device LoRa Tx gain: %d dB", power, tx_gain[radio_dbm]);
|
||||
power -= tx_gain[radio_dbm];
|
||||
break;
|
||||
}
|
||||
// we have an array of PA gain values. Find the highest power setting that works.
|
||||
const uint16_t tx_gain[NUM_PA_POINTS] = {TX_GAIN_LORA};
|
||||
for (int radio_dbm = 0; radio_dbm < NUM_PA_POINTS; radio_dbm++) {
|
||||
if (((radio_dbm + tx_gain[radio_dbm]) > power) ||
|
||||
((radio_dbm == (NUM_PA_POINTS - 1)) && ((radio_dbm + tx_gain[radio_dbm]) <= power))) {
|
||||
// we've exceeded the power limit, or hit the max we can do
|
||||
LOG_INFO("Requested Tx power: %d dBm; Device LoRa Tx gain: %d dB", power, tx_gain[radio_dbm]);
|
||||
power -= tx_gain[radio_dbm];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
if (power > loraMaxPower) // Clamp power to maximum defined level
|
||||
power = loraMaxPower;
|
||||
|
||||
@@ -289,7 +289,12 @@ void RadioLibInterface::onNotify(uint32_t notification)
|
||||
// actual transmission as short as possible
|
||||
txp = txQueue.dequeue();
|
||||
assert(txp);
|
||||
startSend(txp);
|
||||
bool sent = startSend(txp);
|
||||
if (sent) {
|
||||
// Packet has been sent, count it toward our TX airtime utilization.
|
||||
uint32_t xmitMsec = getPacketTime(txp);
|
||||
airTime->logAirtime(TX_LOG, xmitMsec);
|
||||
}
|
||||
LOG_DEBUG("%d packets remain in the TX queue", txQueue.getMaxLen() - txQueue.getFree());
|
||||
}
|
||||
}
|
||||
@@ -408,10 +413,6 @@ void RadioLibInterface::completeSending()
|
||||
sendingPacket = NULL;
|
||||
|
||||
if (p) {
|
||||
// Packet has been sent, count it toward our TX airtime utilization.
|
||||
uint32_t xmitMsec = getPacketTime(p);
|
||||
airTime->logAirtime(TX_LOG, xmitMsec);
|
||||
|
||||
txGood++;
|
||||
if (!isFromUs(p))
|
||||
txRelay++;
|
||||
|
||||
@@ -35,15 +35,6 @@
|
||||
(MAX_RX_TOPHONE + MAX_RX_FROMRADIO + 2 * MAX_TX_QUEUE + \
|
||||
2) // max number of packets which can be in flight (either queued from reception or queued for sending)
|
||||
|
||||
static MemoryDynamic<meshtastic_MeshPacket> dynamicPool;
|
||||
Allocator<meshtastic_MeshPacket> &packetPool = dynamicPool;
|
||||
#elif defined(ARCH_STM32WL)
|
||||
// On STM32 there isn't enough heap left over for the rest of the firmware if we allocate this statically.
|
||||
// For now, make it dynamic again.
|
||||
#define MAX_PACKETS \
|
||||
(MAX_RX_TOPHONE + MAX_RX_FROMRADIO + 2 * MAX_TX_QUEUE + \
|
||||
2) // max number of packets which can be in flight (either queued from reception or queued for sending)
|
||||
|
||||
static MemoryDynamic<meshtastic_MeshPacket> dynamicPool;
|
||||
Allocator<meshtastic_MeshPacket> &packetPool = dynamicPool;
|
||||
#else
|
||||
|
||||
@@ -266,7 +266,6 @@ template <typename T> void SX126xInterface<T>::addReceiveMetadata(meshtastic_Mes
|
||||
// LOG_DEBUG("PacketStatus %x", lora.getPacketStatus());
|
||||
mp->rx_snr = lora.getSNR();
|
||||
mp->rx_rssi = lround(lora.getRSSI());
|
||||
LOG_DEBUG("Corrected frequency offset: %f", lora.getFrequencyError());
|
||||
}
|
||||
|
||||
/** We override to turn on transmitter power as needed.
|
||||
|
||||
@@ -204,7 +204,6 @@ template <typename T> void SX128xInterface<T>::addReceiveMetadata(meshtastic_Mes
|
||||
// LOG_DEBUG("PacketStatus %x", lora.getPacketStatus());
|
||||
mp->rx_snr = lora.getSNR();
|
||||
mp->rx_rssi = lround(lora.getRSSI());
|
||||
LOG_DEBUG("Corrected frequency offset: %f", lora.getFrequencyError());
|
||||
}
|
||||
|
||||
/** We override to turn on transmitter power as needed.
|
||||
|
||||
@@ -55,7 +55,7 @@ extern const pb_msgdesc_t meshtastic_ChannelSet_msg;
|
||||
|
||||
/* Maximum encoded size of messages (where known) */
|
||||
#define MESHTASTIC_MESHTASTIC_APPONLY_PB_H_MAX_SIZE meshtastic_ChannelSet_size
|
||||
#define meshtastic_ChannelSet_size 679
|
||||
#define meshtastic_ChannelSet_size 695
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
|
||||
@@ -34,9 +34,9 @@ typedef enum _meshtastic_Channel_Role {
|
||||
typedef struct _meshtastic_ModuleSettings {
|
||||
/* Bits of precision for the location sent in position packets. */
|
||||
uint32_t position_precision;
|
||||
/* Controls whether or not the client / device should mute the current channel
|
||||
/* Controls whether or not the phone / clients should mute the current channel
|
||||
Useful for noisy public channels you don't necessarily want to disable */
|
||||
bool is_muted;
|
||||
bool is_client_muted;
|
||||
} meshtastic_ModuleSettings;
|
||||
|
||||
typedef PB_BYTES_ARRAY_T(32) meshtastic_ChannelSettings_psk_t;
|
||||
@@ -97,6 +97,8 @@ typedef struct _meshtastic_ChannelSettings {
|
||||
/* Per-channel module settings. */
|
||||
bool has_module_settings;
|
||||
meshtastic_ModuleSettings module_settings;
|
||||
/* Whether or not we should receive notifactions / alerts through this channel */
|
||||
bool mute;
|
||||
} meshtastic_ChannelSettings;
|
||||
|
||||
/* A pair of a channel number, mode and the (sharable) settings for that channel */
|
||||
@@ -128,16 +130,16 @@ extern "C" {
|
||||
|
||||
|
||||
/* Initializer values for message structs */
|
||||
#define meshtastic_ChannelSettings_init_default {0, {0, {0}}, "", 0, 0, 0, false, meshtastic_ModuleSettings_init_default}
|
||||
#define meshtastic_ChannelSettings_init_default {0, {0, {0}}, "", 0, 0, 0, false, meshtastic_ModuleSettings_init_default, 0}
|
||||
#define meshtastic_ModuleSettings_init_default {0, 0}
|
||||
#define meshtastic_Channel_init_default {0, false, meshtastic_ChannelSettings_init_default, _meshtastic_Channel_Role_MIN}
|
||||
#define meshtastic_ChannelSettings_init_zero {0, {0, {0}}, "", 0, 0, 0, false, meshtastic_ModuleSettings_init_zero}
|
||||
#define meshtastic_ChannelSettings_init_zero {0, {0, {0}}, "", 0, 0, 0, false, meshtastic_ModuleSettings_init_zero, 0}
|
||||
#define meshtastic_ModuleSettings_init_zero {0, 0}
|
||||
#define meshtastic_Channel_init_zero {0, false, meshtastic_ChannelSettings_init_zero, _meshtastic_Channel_Role_MIN}
|
||||
|
||||
/* Field tags (for use in manual encoding/decoding) */
|
||||
#define meshtastic_ModuleSettings_position_precision_tag 1
|
||||
#define meshtastic_ModuleSettings_is_muted_tag 2
|
||||
#define meshtastic_ModuleSettings_is_client_muted_tag 2
|
||||
#define meshtastic_ChannelSettings_channel_num_tag 1
|
||||
#define meshtastic_ChannelSettings_psk_tag 2
|
||||
#define meshtastic_ChannelSettings_name_tag 3
|
||||
@@ -145,6 +147,7 @@ extern "C" {
|
||||
#define meshtastic_ChannelSettings_uplink_enabled_tag 5
|
||||
#define meshtastic_ChannelSettings_downlink_enabled_tag 6
|
||||
#define meshtastic_ChannelSettings_module_settings_tag 7
|
||||
#define meshtastic_ChannelSettings_mute_tag 8
|
||||
#define meshtastic_Channel_index_tag 1
|
||||
#define meshtastic_Channel_settings_tag 2
|
||||
#define meshtastic_Channel_role_tag 3
|
||||
@@ -157,14 +160,15 @@ X(a, STATIC, SINGULAR, STRING, name, 3) \
|
||||
X(a, STATIC, SINGULAR, FIXED32, id, 4) \
|
||||
X(a, STATIC, SINGULAR, BOOL, uplink_enabled, 5) \
|
||||
X(a, STATIC, SINGULAR, BOOL, downlink_enabled, 6) \
|
||||
X(a, STATIC, OPTIONAL, MESSAGE, module_settings, 7)
|
||||
X(a, STATIC, OPTIONAL, MESSAGE, module_settings, 7) \
|
||||
X(a, STATIC, SINGULAR, BOOL, mute, 8)
|
||||
#define meshtastic_ChannelSettings_CALLBACK NULL
|
||||
#define meshtastic_ChannelSettings_DEFAULT NULL
|
||||
#define meshtastic_ChannelSettings_module_settings_MSGTYPE meshtastic_ModuleSettings
|
||||
|
||||
#define meshtastic_ModuleSettings_FIELDLIST(X, a) \
|
||||
X(a, STATIC, SINGULAR, UINT32, position_precision, 1) \
|
||||
X(a, STATIC, SINGULAR, BOOL, is_muted, 2)
|
||||
X(a, STATIC, SINGULAR, BOOL, is_client_muted, 2)
|
||||
#define meshtastic_ModuleSettings_CALLBACK NULL
|
||||
#define meshtastic_ModuleSettings_DEFAULT NULL
|
||||
|
||||
@@ -187,8 +191,8 @@ extern const pb_msgdesc_t meshtastic_Channel_msg;
|
||||
|
||||
/* Maximum encoded size of messages (where known) */
|
||||
#define MESHTASTIC_MESHTASTIC_CHANNEL_PB_H_MAX_SIZE meshtastic_Channel_size
|
||||
#define meshtastic_ChannelSettings_size 72
|
||||
#define meshtastic_Channel_size 87
|
||||
#define meshtastic_ChannelSettings_size 74
|
||||
#define meshtastic_Channel_size 89
|
||||
#define meshtastic_ModuleSettings_size 8
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
@@ -360,8 +360,8 @@ extern const pb_msgdesc_t meshtastic_BackupPreferences_msg;
|
||||
/* Maximum encoded size of messages (where known) */
|
||||
/* meshtastic_NodeDatabase_size depends on runtime parameters */
|
||||
#define MESHTASTIC_MESHTASTIC_DEVICEONLY_PB_H_MAX_SIZE meshtastic_BackupPreferences_size
|
||||
#define meshtastic_BackupPreferences_size 2277
|
||||
#define meshtastic_ChannelFile_size 718
|
||||
#define meshtastic_BackupPreferences_size 2293
|
||||
#define meshtastic_ChannelFile_size 734
|
||||
#define meshtastic_DeviceState_size 1737
|
||||
#define meshtastic_NodeInfoLite_size 196
|
||||
#define meshtastic_PositionLite_size 28
|
||||
|
||||
@@ -282,8 +282,6 @@ typedef enum _meshtastic_HardwareModel {
|
||||
meshtastic_HardwareModel_HELTEC_WIRELESS_TRACKER_V2 = 113,
|
||||
/* LilyGo T-Watch Ultra */
|
||||
meshtastic_HardwareModel_T_WATCH_ULTRA = 114,
|
||||
/* Elecrow ThinkNode M3 */
|
||||
meshtastic_HardwareModel_THINKNODE_M3 = 115,
|
||||
/* ------------------------------------------------------------------------------------------------------------------------------------------
|
||||
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.
|
||||
------------------------------------------------------------------------------------------------------------------------------------------ */
|
||||
|
||||
@@ -101,9 +101,7 @@ typedef enum _meshtastic_TelemetrySensorType {
|
||||
/* SEN5X PM SENSORS */
|
||||
meshtastic_TelemetrySensorType_SEN5X = 43,
|
||||
/* TSL2561 light sensor */
|
||||
meshtastic_TelemetrySensorType_TSL2561 = 44,
|
||||
/* BH1750 light sensor */
|
||||
meshtastic_TelemetrySensorType_BH1750 = 45
|
||||
meshtastic_TelemetrySensorType_TSL2561 = 44
|
||||
} meshtastic_TelemetrySensorType;
|
||||
|
||||
/* Struct definitions */
|
||||
@@ -440,8 +438,8 @@ extern "C" {
|
||||
|
||||
/* Helper constants for enums */
|
||||
#define _meshtastic_TelemetrySensorType_MIN meshtastic_TelemetrySensorType_SENSOR_UNSET
|
||||
#define _meshtastic_TelemetrySensorType_MAX meshtastic_TelemetrySensorType_BH1750
|
||||
#define _meshtastic_TelemetrySensorType_ARRAYSIZE ((meshtastic_TelemetrySensorType)(meshtastic_TelemetrySensorType_BH1750+1))
|
||||
#define _meshtastic_TelemetrySensorType_MAX meshtastic_TelemetrySensorType_TSL2561
|
||||
#define _meshtastic_TelemetrySensorType_ARRAYSIZE ((meshtastic_TelemetrySensorType)(meshtastic_TelemetrySensorType_TSL2561+1))
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -95,12 +95,10 @@ static void onNetworkConnected()
|
||||
#ifdef ARCH_ESP32
|
||||
MDNS.addServiceTxt("meshtastic", "tcp", "shortname", String(owner.short_name));
|
||||
MDNS.addServiceTxt("meshtastic", "tcp", "id", String(nodeDB->getNodeId().c_str()));
|
||||
MDNS.addServiceTxt("meshtastic", "tcp", "pio_env", optstr(APP_ENV));
|
||||
// ESP32 prints obtained IP address in WiFiEvent
|
||||
#elif defined(ARCH_RP2040)
|
||||
MDNS.addServiceTxt("meshtastic", "shortname", owner.short_name);
|
||||
MDNS.addServiceTxt("meshtastic", "id", nodeDB->getNodeId().c_str());
|
||||
MDNS.addServiceTxt("meshtastic", "pio_env", optstr(APP_ENV));
|
||||
LOG_INFO("Obtained IP address: %s", WiFi.localIP().toString().c_str());
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -255,7 +255,7 @@ void CannedMessageModule::updateDestinationSelectionList()
|
||||
|
||||
for (size_t i = 0; i < numMeshNodes; ++i) {
|
||||
meshtastic_NodeInfoLite *node = nodeDB->getMeshNodeByIndex(i);
|
||||
if (!node || node->num == myNodeNum || !node->has_user || node->user.public_key.size != 32)
|
||||
if (!node || node->num == myNodeNum)
|
||||
continue;
|
||||
|
||||
const String &nodeName = node->user.long_name;
|
||||
@@ -976,8 +976,6 @@ void CannedMessageModule::sendText(NodeNum dest, ChannelIndex channel, const cha
|
||||
LOG_INFO("Proactively adding %x as favorite node", p->to);
|
||||
nodeDB->set_favorite(true, p->to);
|
||||
screen->setFrames(graphics::Screen::FOCUS_PRESERVE);
|
||||
p->pki_encrypted = true;
|
||||
p->channel = 0;
|
||||
}
|
||||
|
||||
// Send to mesh and phone (even if no phone connected, to track ACKs)
|
||||
|
||||
@@ -94,8 +94,8 @@ int32_t ExternalNotificationModule::runOnce()
|
||||
// audioThread->isPlaying() also handles actually playing the RTTTL, needs to be called in loop
|
||||
isRtttlPlaying = isRtttlPlaying || audioThread->isPlaying();
|
||||
#endif
|
||||
if ((nagCycleCutoff <= millis())) {
|
||||
// Turn off external notification immediately when timeout is reached, regardless of song state
|
||||
if ((nagCycleCutoff < millis()) && !isRtttlPlaying) {
|
||||
// let the song finish if we reach timeout
|
||||
nagCycleCutoff = UINT32_MAX;
|
||||
LOG_INFO("Turning off external notification: ");
|
||||
for (int i = 0; i < 3; i++) {
|
||||
@@ -103,6 +103,7 @@ int32_t ExternalNotificationModule::runOnce()
|
||||
externalTurnedOn[i] = 0;
|
||||
LOG_INFO("%d ", i);
|
||||
}
|
||||
LOG_INFO("");
|
||||
#ifdef HAS_I2S
|
||||
// GPIO0 is used as mclk for I2S audio and set to OUTPUT by the sound library
|
||||
// T-Deck uses GPIO0 as trackball button, so restore the mode
|
||||
@@ -509,8 +510,7 @@ ProcessMessage ExternalNotificationModule::handleReceived(const meshtastic_MeshP
|
||||
}
|
||||
}
|
||||
|
||||
if (moduleConfig.external_notification.alert_message &&
|
||||
(!ch.settings.has_module_settings || !ch.settings.module_settings.is_muted)) {
|
||||
if (moduleConfig.external_notification.alert_message && !ch.settings.mute) {
|
||||
LOG_INFO("externalNotificationModule - Notification Module");
|
||||
isNagging = true;
|
||||
setExternalState(0, true);
|
||||
@@ -521,8 +521,7 @@ ProcessMessage ExternalNotificationModule::handleReceived(const meshtastic_MeshP
|
||||
}
|
||||
}
|
||||
|
||||
if (moduleConfig.external_notification.alert_message_vibra &&
|
||||
(!ch.settings.has_module_settings || !ch.settings.module_settings.is_muted)) {
|
||||
if (moduleConfig.external_notification.alert_message_vibra && !ch.settings.mute) {
|
||||
LOG_INFO("externalNotificationModule - Notification Module (Vibra)");
|
||||
isNagging = true;
|
||||
setExternalState(1, true);
|
||||
@@ -533,8 +532,7 @@ ProcessMessage ExternalNotificationModule::handleReceived(const meshtastic_MeshP
|
||||
}
|
||||
}
|
||||
|
||||
if (moduleConfig.external_notification.alert_message_buzzer &&
|
||||
(!ch.settings.has_module_settings || !ch.settings.module_settings.is_muted)) {
|
||||
if (moduleConfig.external_notification.alert_message_buzzer && !ch.settings.mute) {
|
||||
LOG_INFO("externalNotificationModule - Notification Module (Buzzer)");
|
||||
if (config.device.buzzer_mode != meshtastic_Config_DeviceConfig_BuzzerMode_DIRECT_MSG_ONLY ||
|
||||
(!isBroadcast(mp.to) && isToUs(&mp))) {
|
||||
|
||||
@@ -159,7 +159,6 @@ ProcessMessage RangeTestModuleRadio::handleReceived(const meshtastic_MeshPacket
|
||||
LOG_DEBUG("---- Received Packet:");
|
||||
LOG_DEBUG("mp.from %d", mp.from);
|
||||
LOG_DEBUG("mp.rx_snr %f", mp.rx_snr);
|
||||
LOG_DEBUG("mp.rx_rssi %f", mp.rx_rssi);
|
||||
LOG_DEBUG("mp.hop_limit %d", mp.hop_limit);
|
||||
LOG_DEBUG("---- Node Information of Received Packet (mp.from):");
|
||||
LOG_DEBUG("n->user.long_name %s", n->user.long_name);
|
||||
@@ -235,8 +234,8 @@ bool RangeTestModuleRadio::appendFile(const meshtastic_MeshPacket &mp)
|
||||
}
|
||||
|
||||
// Print the CSV header
|
||||
if (fileToWrite.println("time,from,sender name,sender lat,sender long,rx lat,rx long,rx elevation,rx "
|
||||
"snr,distance,hop limit,payload,rx rssi")) {
|
||||
if (fileToWrite.println(
|
||||
"time,from,sender name,sender lat,sender long,rx lat,rx long,rx elevation,rx snr,distance,hop limit,payload")) {
|
||||
LOG_INFO("File was written");
|
||||
} else {
|
||||
LOG_ERROR("File write failed");
|
||||
@@ -298,8 +297,6 @@ bool RangeTestModuleRadio::appendFile(const meshtastic_MeshPacket &mp)
|
||||
|
||||
// TODO: If quotes are found in the payload, it has to be escaped.
|
||||
fileToAppend.printf("\"%s\"\n", p.payload.bytes);
|
||||
fileToAppend.printf("%i,", mp.rx_rssi); // RX RSSI
|
||||
|
||||
fileToAppend.flush();
|
||||
fileToAppend.close();
|
||||
|
||||
|
||||
@@ -26,8 +26,7 @@ int32_t DeviceTelemetryModule::runOnce()
|
||||
Default::getConfiguredOrDefaultMsScaled(moduleConfig.telemetry.device_update_interval,
|
||||
default_telemetry_broadcast_interval_secs, numOnlineNodes))) &&
|
||||
airTime->isTxAllowedChannelUtil(!isImpoliteRole) && airTime->isTxAllowedAirUtil() &&
|
||||
config.device.role != meshtastic_Config_DeviceConfig_Role_CLIENT_HIDDEN &&
|
||||
moduleConfig.telemetry.device_telemetry_enabled) {
|
||||
config.device.role != meshtastic_Config_DeviceConfig_Role_CLIENT_HIDDEN) {
|
||||
sendTelemetry();
|
||||
lastSentToMesh = uptimeLastMs;
|
||||
} else if (service->isToPhoneQueueEmpty()) {
|
||||
|
||||
@@ -35,103 +35,175 @@ extern void drawCommonHeader(OLEDDisplay *display, int16_t x, int16_t y, const c
|
||||
}
|
||||
#if __has_include(<Adafruit_AHTX0.h>)
|
||||
#include "Sensor/AHT10.h"
|
||||
AHT10Sensor aht10Sensor;
|
||||
#else
|
||||
NullSensor aht10Sensor;
|
||||
#endif
|
||||
|
||||
#if __has_include(<Adafruit_BME280.h>)
|
||||
#include "Sensor/BME280Sensor.h"
|
||||
BME280Sensor bme280Sensor;
|
||||
#else
|
||||
NullSensor bmp280Sensor;
|
||||
#endif
|
||||
|
||||
#if __has_include(<Adafruit_BMP085.h>)
|
||||
#include "Sensor/BMP085Sensor.h"
|
||||
BMP085Sensor bmp085Sensor;
|
||||
#else
|
||||
NullSensor bmp085Sensor;
|
||||
#endif
|
||||
|
||||
#if __has_include(<Adafruit_BMP280.h>)
|
||||
#include "Sensor/BMP280Sensor.h"
|
||||
BMP280Sensor bmp280Sensor;
|
||||
#else
|
||||
NullSensor bme280Sensor;
|
||||
#endif
|
||||
|
||||
#if __has_include(<Adafruit_LTR390.h>)
|
||||
#include "Sensor/LTR390UVSensor.h"
|
||||
LTR390UVSensor ltr390uvSensor;
|
||||
#else
|
||||
NullSensor ltr390uvSensor;
|
||||
#endif
|
||||
|
||||
#if __has_include(<bsec2.h>)
|
||||
#include "Sensor/BME680Sensor.h"
|
||||
BME680Sensor bme680Sensor;
|
||||
#else
|
||||
NullSensor bme680Sensor;
|
||||
#endif
|
||||
|
||||
#if __has_include(<Adafruit_DPS310.h>)
|
||||
#include "Sensor/DPS310Sensor.h"
|
||||
DPS310Sensor dps310Sensor;
|
||||
#else
|
||||
NullSensor dps310Sensor;
|
||||
#endif
|
||||
|
||||
#if __has_include(<Adafruit_MCP9808.h>)
|
||||
#include "Sensor/MCP9808Sensor.h"
|
||||
MCP9808Sensor mcp9808Sensor;
|
||||
#else
|
||||
NullSensor mcp9808Sensor;
|
||||
#endif
|
||||
|
||||
#if __has_include(<Adafruit_SHT31.h>)
|
||||
#include "Sensor/SHT31Sensor.h"
|
||||
SHT31Sensor sht31Sensor;
|
||||
#else
|
||||
NullSensor sht31Sensor;
|
||||
#endif
|
||||
|
||||
#if __has_include(<Adafruit_LPS2X.h>)
|
||||
#include "Sensor/LPS22HBSensor.h"
|
||||
LPS22HBSensor lps22hbSensor;
|
||||
#else
|
||||
NullSensor lps22hbSensor;
|
||||
#endif
|
||||
|
||||
#if __has_include(<Adafruit_SHTC3.h>)
|
||||
#include "Sensor/SHTC3Sensor.h"
|
||||
SHTC3Sensor shtc3Sensor;
|
||||
#else
|
||||
NullSensor shtc3Sensor;
|
||||
#endif
|
||||
|
||||
#if __has_include("RAK12035_SoilMoisture.h") && defined(RAK_4631) && RAK_4631 == 1
|
||||
#include "Sensor/RAK12035Sensor.h"
|
||||
RAK12035Sensor rak12035Sensor;
|
||||
#else
|
||||
NullSensor rak12035Sensor;
|
||||
#endif
|
||||
|
||||
#if __has_include(<Adafruit_VEML7700.h>)
|
||||
#include "Sensor/VEML7700Sensor.h"
|
||||
VEML7700Sensor veml7700Sensor;
|
||||
#else
|
||||
NullSensor veml7700Sensor;
|
||||
#endif
|
||||
|
||||
#if __has_include(<Adafruit_TSL2591.h>)
|
||||
#include "Sensor/TSL2591Sensor.h"
|
||||
TSL2591Sensor tsl2591Sensor;
|
||||
#else
|
||||
NullSensor tsl2591Sensor;
|
||||
#endif
|
||||
|
||||
#if __has_include(<ClosedCube_OPT3001.h>)
|
||||
#include "Sensor/OPT3001Sensor.h"
|
||||
OPT3001Sensor opt3001Sensor;
|
||||
#else
|
||||
NullSensor opt3001Sensor;
|
||||
#endif
|
||||
|
||||
#if __has_include(<Adafruit_SHT4x.h>)
|
||||
#include "Sensor/SHT4XSensor.h"
|
||||
SHT4XSensor sht4xSensor;
|
||||
#else
|
||||
NullSensor sht4xSensor;
|
||||
#endif
|
||||
|
||||
#if __has_include(<SparkFun_MLX90632_Arduino_Library.h>)
|
||||
#include "Sensor/MLX90632Sensor.h"
|
||||
MLX90632Sensor mlx90632Sensor;
|
||||
#else
|
||||
NullSensor mlx90632Sensor;
|
||||
#endif
|
||||
|
||||
#if __has_include(<DFRobot_LarkWeatherStation.h>)
|
||||
#include "Sensor/DFRobotLarkSensor.h"
|
||||
DFRobotLarkSensor dfRobotLarkSensor;
|
||||
#else
|
||||
NullSensor dfRobotLarkSensor;
|
||||
#endif
|
||||
|
||||
#if __has_include(<DFRobot_RainfallSensor.h>)
|
||||
#include "Sensor/DFRobotGravitySensor.h"
|
||||
DFRobotGravitySensor dfRobotGravitySensor;
|
||||
#else
|
||||
NullSensor dfRobotGravitySensor;
|
||||
#endif
|
||||
|
||||
#if __has_include(<SparkFun_Qwiic_Scale_NAU7802_Arduino_Library.h>)
|
||||
#include "Sensor/NAU7802Sensor.h"
|
||||
NAU7802Sensor nau7802Sensor;
|
||||
#else
|
||||
NullSensor nau7802Sensor;
|
||||
#endif
|
||||
|
||||
#if __has_include(<Adafruit_BMP3XX.h>)
|
||||
#include "Sensor/BMP3XXSensor.h"
|
||||
BMP3XXSensor bmp3xxSensor;
|
||||
#else
|
||||
NullSensor bmp3xxSensor;
|
||||
#endif
|
||||
|
||||
#if __has_include(<Adafruit_PCT2075.h>)
|
||||
#include "Sensor/PCT2075Sensor.h"
|
||||
PCT2075Sensor pct2075Sensor;
|
||||
#else
|
||||
NullSensor pct2075Sensor;
|
||||
#endif
|
||||
|
||||
RCWL9620Sensor rcwl9620Sensor;
|
||||
CGRadSensSensor cgRadSens;
|
||||
|
||||
#endif
|
||||
#ifdef T1000X_SENSOR_EN
|
||||
#include "Sensor/T1000xSensor.h"
|
||||
T1000xSensor t1000xSensor;
|
||||
#endif
|
||||
|
||||
#ifdef SENSECAP_INDICATOR
|
||||
#include "Sensor/IndicatorSensor.h"
|
||||
IndicatorSensor indicatorSensor;
|
||||
#endif
|
||||
|
||||
#if __has_include(<Adafruit_TSL2561_U.h>)
|
||||
#include "Sensor/TSL2561Sensor.h"
|
||||
TSL2561Sensor tsl2561Sensor;
|
||||
#else
|
||||
NullSensor tsl2561Sensor;
|
||||
#endif
|
||||
|
||||
#define FAILED_STATE_SENSOR_READ_MULTIPLIER 10
|
||||
@@ -140,132 +212,6 @@ extern void drawCommonHeader(OLEDDisplay *display, int16_t x, int16_t y, const c
|
||||
#include "graphics/ScreenFonts.h"
|
||||
#include <Throttle.h>
|
||||
|
||||
#include <forward_list>
|
||||
|
||||
static std::forward_list<TelemetrySensor *> sensors;
|
||||
|
||||
template <typename T> void addSensor(ScanI2C *i2cScanner, ScanI2C::DeviceType type)
|
||||
{
|
||||
ScanI2C::FoundDevice dev = i2cScanner->find(type);
|
||||
if (dev.type != ScanI2C::DeviceType::NONE || type == ScanI2C::DeviceType::NONE) {
|
||||
TelemetrySensor *sensor = new T();
|
||||
#if WIRE_INTERFACES_COUNT > 1
|
||||
TwoWire *bus = ScanI2CTwoWire::fetchI2CBus(dev.address);
|
||||
if (dev.address.port != ScanI2C::I2CPort::WIRE1 && sensor->onlyWire1()) {
|
||||
// This sensor only works on Wire (Wire1 is not supported)
|
||||
delete sensor;
|
||||
return;
|
||||
}
|
||||
#else
|
||||
TwoWire *bus = &Wire;
|
||||
#endif
|
||||
if (sensor->initDevice(bus, &dev)) {
|
||||
sensors.push_front(sensor);
|
||||
return;
|
||||
}
|
||||
// destroy sensor
|
||||
delete sensor;
|
||||
}
|
||||
}
|
||||
|
||||
void EnvironmentTelemetryModule::i2cScanFinished(ScanI2C *i2cScanner)
|
||||
{
|
||||
if (!moduleConfig.telemetry.environment_measurement_enabled && !ENVIRONMENTAL_TELEMETRY_MODULE_ENABLE) {
|
||||
return;
|
||||
}
|
||||
LOG_INFO("Environment Telemetry adding I2C devices...");
|
||||
|
||||
// order by priority of metrics/values (low top, high bottom)
|
||||
|
||||
#if !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR
|
||||
#ifdef T1000X_SENSOR_EN
|
||||
// Not a real I2C device
|
||||
addSensor<T1000xSensor>(i2cScanner, ScanI2C::DeviceType::NONE);
|
||||
#else
|
||||
#ifdef SENSECAP_INDICATOR
|
||||
// Not a real I2C device, uses UART
|
||||
addSensor<IndicatorSensor>(i2cScanner, ScanI2C::DeviceType::NONE);
|
||||
#endif
|
||||
addSensor<RCWL9620Sensor>(i2cScanner, ScanI2C::DeviceType::RCWL9620);
|
||||
addSensor<CGRadSensSensor>(i2cScanner, ScanI2C::DeviceType::CGRADSENS);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR && !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR_EXTERNAL
|
||||
#if __has_include(<DFRobot_LarkWeatherStation.h>)
|
||||
addSensor<DFRobotLarkSensor>(i2cScanner, ScanI2C::DeviceType::DFROBOT_LARK);
|
||||
#endif
|
||||
#if __has_include(<DFRobot_RainfallSensor.h>)
|
||||
addSensor<DFRobotGravitySensor>(i2cScanner, ScanI2C::DeviceType::DFROBOT_RAIN);
|
||||
#endif
|
||||
#if __has_include(<Adafruit_AHTX0.h>)
|
||||
addSensor<AHT10Sensor>(i2cScanner, ScanI2C::DeviceType::AHT10);
|
||||
#endif
|
||||
#if __has_include(<Adafruit_BMP085.h>)
|
||||
addSensor<BMP085Sensor>(i2cScanner, ScanI2C::DeviceType::BMP_085);
|
||||
#endif
|
||||
#if __has_include(<Adafruit_BME280.h>)
|
||||
addSensor<BME280Sensor>(i2cScanner, ScanI2C::DeviceType::BME_280);
|
||||
#endif
|
||||
#if __has_include(<Adafruit_LTR390.h>)
|
||||
addSensor<LTR390UVSensor>(i2cScanner, ScanI2C::DeviceType::LTR390UV);
|
||||
#endif
|
||||
#if __has_include(<bsec2.h>)
|
||||
addSensor<BME680Sensor>(i2cScanner, ScanI2C::DeviceType::BME_680);
|
||||
#endif
|
||||
#if __has_include(<Adafruit_BMP280.h>)
|
||||
addSensor<BMP280Sensor>(i2cScanner, ScanI2C::DeviceType::BMP_280);
|
||||
#endif
|
||||
#if __has_include(<Adafruit_DPS310.h>)
|
||||
addSensor<DPS310Sensor>(i2cScanner, ScanI2C::DeviceType::DPS310);
|
||||
#endif
|
||||
#if __has_include(<Adafruit_MCP9808.h>)
|
||||
addSensor<MCP9808Sensor>(i2cScanner, ScanI2C::DeviceType::MCP9808);
|
||||
#endif
|
||||
#if __has_include(<Adafruit_SHT31.h>)
|
||||
addSensor<SHT31Sensor>(i2cScanner, ScanI2C::DeviceType::SHT31);
|
||||
#endif
|
||||
#if __has_include(<Adafruit_LPS2X.h>)
|
||||
addSensor<LPS22HBSensor>(i2cScanner, ScanI2C::DeviceType::LPS22HB);
|
||||
#endif
|
||||
#if __has_include(<Adafruit_SHTC3.h>)
|
||||
addSensor<SHTC3Sensor>(i2cScanner, ScanI2C::DeviceType::SHTC3);
|
||||
#endif
|
||||
#if __has_include("RAK12035_SoilMoisture.h") && defined(RAK_4631) && RAK_4631 == 1
|
||||
addSensor<RAK12035Sensor>(i2cScanner, ScanI2C::DeviceType::RAK12035);
|
||||
#endif
|
||||
#if __has_include(<Adafruit_VEML7700.h>)
|
||||
addSensor<VEML7700Sensor>(i2cScanner, ScanI2C::DeviceType::VEML7700);
|
||||
#endif
|
||||
#if __has_include(<Adafruit_TSL2591.h>)
|
||||
addSensor<TSL2591Sensor>(i2cScanner, ScanI2C::DeviceType::TSL2591);
|
||||
#endif
|
||||
#if __has_include(<ClosedCube_OPT3001.h>)
|
||||
addSensor<OPT3001Sensor>(i2cScanner, ScanI2C::DeviceType::OPT3001);
|
||||
#endif
|
||||
#if __has_include(<Adafruit_SHT4x.h>)
|
||||
addSensor<SHT4XSensor>(i2cScanner, ScanI2C::DeviceType::SHT4X);
|
||||
#endif
|
||||
#if __has_include(<SparkFun_MLX90632_Arduino_Library.h>)
|
||||
addSensor<MLX90632Sensor>(i2cScanner, ScanI2C::DeviceType::MLX90632);
|
||||
#endif
|
||||
|
||||
#if __has_include(<Adafruit_BMP3XX.h>)
|
||||
addSensor<BMP3XXSensor>(i2cScanner, ScanI2C::DeviceType::BMP_3XX);
|
||||
#endif
|
||||
#if __has_include(<Adafruit_PCT2075.h>)
|
||||
addSensor<PCT2075Sensor>(i2cScanner, ScanI2C::DeviceType::PCT2075);
|
||||
#endif
|
||||
#if __has_include(<Adafruit_TSL2561_U.h>)
|
||||
addSensor<TSL2561Sensor>(i2cScanner, ScanI2C::DeviceType::TSL2561);
|
||||
#endif
|
||||
#if __has_include(<SparkFun_Qwiic_Scale_NAU7802_Arduino_Library.h>)
|
||||
addSensor<NAU7802Sensor>(i2cScanner, ScanI2C::DeviceType::NAU7802);
|
||||
#endif
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
int32_t EnvironmentTelemetryModule::runOnce()
|
||||
{
|
||||
if (sleepOnNextExecution == true) {
|
||||
@@ -298,27 +244,81 @@ int32_t EnvironmentTelemetryModule::runOnce()
|
||||
|
||||
if (moduleConfig.telemetry.environment_measurement_enabled || ENVIRONMENTAL_TELEMETRY_MODULE_ENABLE) {
|
||||
LOG_INFO("Environment Telemetry: init");
|
||||
|
||||
// check if we have at least one sensor
|
||||
if (!sensors.empty()) {
|
||||
result = DEFAULT_SENSOR_MINIMUM_WAIT_TIME_BETWEEN_READS;
|
||||
}
|
||||
|
||||
#ifdef SENSECAP_INDICATOR
|
||||
result = indicatorSensor.runOnce();
|
||||
#endif
|
||||
#ifdef T1000X_SENSOR_EN
|
||||
result = t1000xSensor.runOnce();
|
||||
#elif !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR_EXTERNAL
|
||||
if (dfRobotLarkSensor.hasSensor())
|
||||
result = dfRobotLarkSensor.runOnce();
|
||||
if (dfRobotGravitySensor.hasSensor())
|
||||
result = dfRobotGravitySensor.runOnce();
|
||||
if (bmp085Sensor.hasSensor())
|
||||
result = bmp085Sensor.runOnce();
|
||||
#if __has_include(<Adafruit_BME280.h>)
|
||||
if (bmp280Sensor.hasSensor())
|
||||
result = bmp280Sensor.runOnce();
|
||||
#endif
|
||||
if (bme280Sensor.hasSensor())
|
||||
result = bme280Sensor.runOnce();
|
||||
if (ltr390uvSensor.hasSensor())
|
||||
result = ltr390uvSensor.runOnce();
|
||||
if (bmp3xxSensor.hasSensor())
|
||||
result = bmp3xxSensor.runOnce();
|
||||
if (bme680Sensor.hasSensor())
|
||||
result = bme680Sensor.runOnce();
|
||||
if (dps310Sensor.hasSensor())
|
||||
result = dps310Sensor.runOnce();
|
||||
if (mcp9808Sensor.hasSensor())
|
||||
result = mcp9808Sensor.runOnce();
|
||||
if (shtc3Sensor.hasSensor())
|
||||
result = shtc3Sensor.runOnce();
|
||||
if (lps22hbSensor.hasSensor())
|
||||
result = lps22hbSensor.runOnce();
|
||||
if (sht31Sensor.hasSensor())
|
||||
result = sht31Sensor.runOnce();
|
||||
if (sht4xSensor.hasSensor())
|
||||
result = sht4xSensor.runOnce();
|
||||
if (ina219Sensor.hasSensor())
|
||||
result = ina219Sensor.runOnce();
|
||||
if (ina260Sensor.hasSensor())
|
||||
result = ina260Sensor.runOnce();
|
||||
if (ina3221Sensor.hasSensor())
|
||||
result = ina3221Sensor.runOnce();
|
||||
if (veml7700Sensor.hasSensor())
|
||||
result = veml7700Sensor.runOnce();
|
||||
if (tsl2591Sensor.hasSensor())
|
||||
result = tsl2591Sensor.runOnce();
|
||||
if (opt3001Sensor.hasSensor())
|
||||
result = opt3001Sensor.runOnce();
|
||||
if (rcwl9620Sensor.hasSensor())
|
||||
result = rcwl9620Sensor.runOnce();
|
||||
if (aht10Sensor.hasSensor())
|
||||
result = aht10Sensor.runOnce();
|
||||
if (mlx90632Sensor.hasSensor())
|
||||
result = mlx90632Sensor.runOnce();
|
||||
if (nau7802Sensor.hasSensor())
|
||||
result = nau7802Sensor.runOnce();
|
||||
if (max17048Sensor.hasSensor())
|
||||
result = max17048Sensor.runOnce();
|
||||
if (cgRadSens.hasSensor())
|
||||
result = cgRadSens.runOnce();
|
||||
if (tsl2561Sensor.hasSensor())
|
||||
result = tsl2561Sensor.runOnce();
|
||||
if (pct2075Sensor.hasSensor())
|
||||
result = pct2075Sensor.runOnce();
|
||||
// this only works on the wismesh hub with the solar option. This is not an I2C sensor, so we don't need the
|
||||
// sensormap here.
|
||||
#ifdef HAS_RAKPROT
|
||||
|
||||
result = rak9154Sensor.runOnce();
|
||||
#endif
|
||||
#if __has_include("RAK12035_SoilMoisture.h") && defined(RAK_4631) && RAK_4631 == 1
|
||||
if (rak12035Sensor.hasSensor()) {
|
||||
result = rak12035Sensor.runOnce();
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
// it's possible to have this module enabled, only for displaying values on the screen.
|
||||
@@ -328,13 +328,11 @@ int32_t EnvironmentTelemetryModule::runOnce()
|
||||
// if we somehow got to a second run of this module with measurement disabled, then just wait forever
|
||||
if (!moduleConfig.telemetry.environment_measurement_enabled && !ENVIRONMENTAL_TELEMETRY_MODULE_ENABLE) {
|
||||
return disable();
|
||||
}
|
||||
|
||||
for (TelemetrySensor *sensor : sensors) {
|
||||
uint32_t delay = sensor->runOnce();
|
||||
if (delay < result) {
|
||||
result = delay;
|
||||
}
|
||||
} else {
|
||||
#if !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR_EXTERNAL
|
||||
if (bme680Sensor.hasSensor())
|
||||
result = bme680Sensor.runTrigger();
|
||||
#endif
|
||||
}
|
||||
|
||||
if (((lastSentToMesh == 0) ||
|
||||
@@ -361,7 +359,6 @@ bool EnvironmentTelemetryModule::wantUIFrame()
|
||||
return moduleConfig.telemetry.environment_screen_enabled;
|
||||
}
|
||||
|
||||
#if HAS_SCREEN
|
||||
void EnvironmentTelemetryModule::drawFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y)
|
||||
{
|
||||
// === Setup display ===
|
||||
@@ -511,7 +508,6 @@ void EnvironmentTelemetryModule::drawFrame(OLEDDisplay *display, OLEDDisplayUiSt
|
||||
currentY += rowHeight;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
bool EnvironmentTelemetryModule::handleReceivedProtobuf(const meshtastic_MeshPacket &mp, meshtastic_Telemetry *t)
|
||||
{
|
||||
@@ -554,12 +550,72 @@ bool EnvironmentTelemetryModule::getEnvironmentTelemetry(meshtastic_Telemetry *m
|
||||
m->which_variant = meshtastic_Telemetry_environment_metrics_tag;
|
||||
m->variant.environment_metrics = meshtastic_EnvironmentMetrics_init_zero;
|
||||
|
||||
for (TelemetrySensor *sensor : sensors) {
|
||||
valid = valid && sensor->getMetrics(m);
|
||||
#ifdef SENSECAP_INDICATOR
|
||||
valid = valid && indicatorSensor.getMetrics(m);
|
||||
hasSensor = true;
|
||||
#endif
|
||||
#ifdef T1000X_SENSOR_EN // add by WayenWeng
|
||||
valid = valid && t1000xSensor.getMetrics(m);
|
||||
hasSensor = true;
|
||||
#else
|
||||
if (dfRobotLarkSensor.hasSensor()) {
|
||||
valid = valid && dfRobotLarkSensor.getMetrics(m);
|
||||
hasSensor = true;
|
||||
}
|
||||
if (dfRobotGravitySensor.hasSensor()) {
|
||||
valid = valid && dfRobotGravitySensor.getMetrics(m);
|
||||
hasSensor = true;
|
||||
}
|
||||
if (sht31Sensor.hasSensor()) {
|
||||
valid = valid && sht31Sensor.getMetrics(m);
|
||||
hasSensor = true;
|
||||
}
|
||||
if (sht4xSensor.hasSensor()) {
|
||||
valid = valid && sht4xSensor.getMetrics(m);
|
||||
hasSensor = true;
|
||||
}
|
||||
if (lps22hbSensor.hasSensor()) {
|
||||
valid = valid && lps22hbSensor.getMetrics(m);
|
||||
hasSensor = true;
|
||||
}
|
||||
if (shtc3Sensor.hasSensor()) {
|
||||
valid = valid && shtc3Sensor.getMetrics(m);
|
||||
hasSensor = true;
|
||||
}
|
||||
if (bmp085Sensor.hasSensor()) {
|
||||
valid = valid && bmp085Sensor.getMetrics(m);
|
||||
hasSensor = true;
|
||||
}
|
||||
#if __has_include(<Adafruit_BME280.h>)
|
||||
if (bmp280Sensor.hasSensor()) {
|
||||
valid = valid && bmp280Sensor.getMetrics(m);
|
||||
hasSensor = true;
|
||||
}
|
||||
#endif
|
||||
if (bme280Sensor.hasSensor()) {
|
||||
valid = valid && bme280Sensor.getMetrics(m);
|
||||
hasSensor = true;
|
||||
}
|
||||
if (ltr390uvSensor.hasSensor()) {
|
||||
valid = valid && ltr390uvSensor.getMetrics(m);
|
||||
hasSensor = true;
|
||||
}
|
||||
if (bmp3xxSensor.hasSensor()) {
|
||||
valid = valid && bmp3xxSensor.getMetrics(m);
|
||||
hasSensor = true;
|
||||
}
|
||||
if (bme680Sensor.hasSensor()) {
|
||||
valid = valid && bme680Sensor.getMetrics(m);
|
||||
hasSensor = true;
|
||||
}
|
||||
if (dps310Sensor.hasSensor()) {
|
||||
valid = valid && dps310Sensor.getMetrics(m);
|
||||
hasSensor = true;
|
||||
}
|
||||
if (mcp9808Sensor.hasSensor()) {
|
||||
valid = valid && mcp9808Sensor.getMetrics(m);
|
||||
hasSensor = true;
|
||||
}
|
||||
|
||||
#ifndef T1000X_SENSOR_EN
|
||||
if (ina219Sensor.hasSensor()) {
|
||||
valid = valid && ina219Sensor.getMetrics(m);
|
||||
hasSensor = true;
|
||||
@@ -572,14 +628,78 @@ bool EnvironmentTelemetryModule::getEnvironmentTelemetry(meshtastic_Telemetry *m
|
||||
valid = valid && ina3221Sensor.getMetrics(m);
|
||||
hasSensor = true;
|
||||
}
|
||||
if (veml7700Sensor.hasSensor()) {
|
||||
valid = valid && veml7700Sensor.getMetrics(m);
|
||||
hasSensor = true;
|
||||
}
|
||||
if (tsl2591Sensor.hasSensor()) {
|
||||
valid = valid && tsl2591Sensor.getMetrics(m);
|
||||
hasSensor = true;
|
||||
}
|
||||
if (opt3001Sensor.hasSensor()) {
|
||||
valid = valid && opt3001Sensor.getMetrics(m);
|
||||
hasSensor = true;
|
||||
}
|
||||
if (mlx90632Sensor.hasSensor()) {
|
||||
valid = valid && mlx90632Sensor.getMetrics(m);
|
||||
hasSensor = true;
|
||||
}
|
||||
if (rcwl9620Sensor.hasSensor()) {
|
||||
valid = valid && rcwl9620Sensor.getMetrics(m);
|
||||
hasSensor = true;
|
||||
}
|
||||
if (nau7802Sensor.hasSensor()) {
|
||||
valid = valid && nau7802Sensor.getMetrics(m);
|
||||
hasSensor = true;
|
||||
}
|
||||
if (tsl2561Sensor.hasSensor()) {
|
||||
valid = valid && tsl2561Sensor.getMetrics(m);
|
||||
hasSensor = true;
|
||||
}
|
||||
if (aht10Sensor.hasSensor()) {
|
||||
if (!bmp280Sensor.hasSensor() && !bmp3xxSensor.hasSensor()) {
|
||||
valid = valid && aht10Sensor.getMetrics(m);
|
||||
hasSensor = true;
|
||||
} else if (bmp280Sensor.hasSensor()) {
|
||||
// prefer bmp280 temp if both sensors are present, fetch only humidity
|
||||
meshtastic_Telemetry m_ahtx = meshtastic_Telemetry_init_zero;
|
||||
LOG_INFO("AHTX0+BMP280 module detected: using temp from BMP280 and humy from AHTX0");
|
||||
aht10Sensor.getMetrics(&m_ahtx);
|
||||
m->variant.environment_metrics.relative_humidity = m_ahtx.variant.environment_metrics.relative_humidity;
|
||||
m->variant.environment_metrics.has_relative_humidity = m_ahtx.variant.environment_metrics.has_relative_humidity;
|
||||
} else {
|
||||
// prefer bmp3xx temp if both sensors are present, fetch only humidity
|
||||
meshtastic_Telemetry m_ahtx = meshtastic_Telemetry_init_zero;
|
||||
LOG_INFO("AHTX0+BMP3XX module detected: using temp from BMP3XX and humy from AHTX0");
|
||||
aht10Sensor.getMetrics(&m_ahtx);
|
||||
m->variant.environment_metrics.relative_humidity = m_ahtx.variant.environment_metrics.relative_humidity;
|
||||
m->variant.environment_metrics.has_relative_humidity = m_ahtx.variant.environment_metrics.has_relative_humidity;
|
||||
}
|
||||
}
|
||||
if (max17048Sensor.hasSensor()) {
|
||||
valid = valid && max17048Sensor.getMetrics(m);
|
||||
hasSensor = true;
|
||||
}
|
||||
#endif
|
||||
if (cgRadSens.hasSensor()) {
|
||||
valid = valid && cgRadSens.getMetrics(m);
|
||||
hasSensor = true;
|
||||
}
|
||||
if (pct2075Sensor.hasSensor()) {
|
||||
valid = valid && pct2075Sensor.getMetrics(m);
|
||||
hasSensor = true;
|
||||
}
|
||||
#ifdef HAS_RAKPROT
|
||||
valid = valid && rak9154Sensor.getMetrics(m);
|
||||
hasSensor = true;
|
||||
#endif
|
||||
#if __has_include("RAK12035_SoilMoisture.h") && defined(RAK_4631) && \
|
||||
RAK_4631 == \
|
||||
1 // Not really needed, but may as well just skip at a lower level it if no library or not a RAK_4631
|
||||
if (rak12035Sensor.hasSensor()) {
|
||||
valid = valid && rak12035Sensor.getMetrics(m);
|
||||
hasSensor = true;
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
return valid && hasSensor;
|
||||
}
|
||||
@@ -617,8 +737,11 @@ bool EnvironmentTelemetryModule::sendTelemetry(NodeNum dest, bool phoneOnly)
|
||||
meshtastic_Telemetry m = meshtastic_Telemetry_init_zero;
|
||||
m.which_variant = meshtastic_Telemetry_environment_metrics_tag;
|
||||
m.time = getTime();
|
||||
|
||||
#ifdef T1000X_SENSOR_EN
|
||||
if (t1000xSensor.getMetrics(&m)) {
|
||||
#else
|
||||
if (getEnvironmentTelemetry(&m)) {
|
||||
#endif
|
||||
LOG_INFO("Send: barometric_pressure=%f, current=%f, gas_resistance=%f, relative_humidity=%f, temperature=%f",
|
||||
m.variant.environment_metrics.barometric_pressure, m.variant.environment_metrics.current,
|
||||
m.variant.environment_metrics.gas_resistance, m.variant.environment_metrics.relative_humidity,
|
||||
@@ -680,13 +803,71 @@ AdminMessageHandleResult EnvironmentTelemetryModule::handleAdminMessageForModule
|
||||
{
|
||||
AdminMessageHandleResult result = AdminMessageHandleResult::NOT_HANDLED;
|
||||
#if !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR_EXTERNAL
|
||||
|
||||
for (TelemetrySensor *sensor : sensors) {
|
||||
result = sensor->handleAdminMessage(mp, request, response);
|
||||
if (dfRobotLarkSensor.hasSensor()) {
|
||||
result = dfRobotLarkSensor.handleAdminMessage(mp, request, response);
|
||||
if (result != AdminMessageHandleResult::NOT_HANDLED)
|
||||
return result;
|
||||
}
|
||||
if (dfRobotGravitySensor.hasSensor()) {
|
||||
result = dfRobotGravitySensor.handleAdminMessage(mp, request, response);
|
||||
if (result != AdminMessageHandleResult::NOT_HANDLED)
|
||||
return result;
|
||||
}
|
||||
if (sht31Sensor.hasSensor()) {
|
||||
result = sht31Sensor.handleAdminMessage(mp, request, response);
|
||||
if (result != AdminMessageHandleResult::NOT_HANDLED)
|
||||
return result;
|
||||
}
|
||||
if (lps22hbSensor.hasSensor()) {
|
||||
result = lps22hbSensor.handleAdminMessage(mp, request, response);
|
||||
if (result != AdminMessageHandleResult::NOT_HANDLED)
|
||||
return result;
|
||||
}
|
||||
if (shtc3Sensor.hasSensor()) {
|
||||
result = shtc3Sensor.handleAdminMessage(mp, request, response);
|
||||
if (result != AdminMessageHandleResult::NOT_HANDLED)
|
||||
return result;
|
||||
}
|
||||
if (bmp085Sensor.hasSensor()) {
|
||||
result = bmp085Sensor.handleAdminMessage(mp, request, response);
|
||||
if (result != AdminMessageHandleResult::NOT_HANDLED)
|
||||
return result;
|
||||
}
|
||||
if (bmp280Sensor.hasSensor()) {
|
||||
result = bmp280Sensor.handleAdminMessage(mp, request, response);
|
||||
if (result != AdminMessageHandleResult::NOT_HANDLED)
|
||||
return result;
|
||||
}
|
||||
if (bme280Sensor.hasSensor()) {
|
||||
result = bme280Sensor.handleAdminMessage(mp, request, response);
|
||||
if (result != AdminMessageHandleResult::NOT_HANDLED)
|
||||
return result;
|
||||
}
|
||||
if (ltr390uvSensor.hasSensor()) {
|
||||
result = ltr390uvSensor.handleAdminMessage(mp, request, response);
|
||||
if (result != AdminMessageHandleResult::NOT_HANDLED)
|
||||
return result;
|
||||
}
|
||||
if (bmp3xxSensor.hasSensor()) {
|
||||
result = bmp3xxSensor.handleAdminMessage(mp, request, response);
|
||||
if (result != AdminMessageHandleResult::NOT_HANDLED)
|
||||
return result;
|
||||
}
|
||||
if (bme680Sensor.hasSensor()) {
|
||||
result = bme680Sensor.handleAdminMessage(mp, request, response);
|
||||
if (result != AdminMessageHandleResult::NOT_HANDLED)
|
||||
return result;
|
||||
}
|
||||
if (dps310Sensor.hasSensor()) {
|
||||
result = dps310Sensor.handleAdminMessage(mp, request, response);
|
||||
if (result != AdminMessageHandleResult::NOT_HANDLED)
|
||||
return result;
|
||||
}
|
||||
if (mcp9808Sensor.hasSensor()) {
|
||||
result = mcp9808Sensor.handleAdminMessage(mp, request, response);
|
||||
if (result != AdminMessageHandleResult::NOT_HANDLED)
|
||||
return result;
|
||||
}
|
||||
|
||||
if (ina219Sensor.hasSensor()) {
|
||||
result = ina219Sensor.handleAdminMessage(mp, request, response);
|
||||
if (result != AdminMessageHandleResult::NOT_HANDLED)
|
||||
@@ -702,11 +883,60 @@ AdminMessageHandleResult EnvironmentTelemetryModule::handleAdminMessageForModule
|
||||
if (result != AdminMessageHandleResult::NOT_HANDLED)
|
||||
return result;
|
||||
}
|
||||
if (veml7700Sensor.hasSensor()) {
|
||||
result = veml7700Sensor.handleAdminMessage(mp, request, response);
|
||||
if (result != AdminMessageHandleResult::NOT_HANDLED)
|
||||
return result;
|
||||
}
|
||||
if (tsl2591Sensor.hasSensor()) {
|
||||
result = tsl2591Sensor.handleAdminMessage(mp, request, response);
|
||||
if (result != AdminMessageHandleResult::NOT_HANDLED)
|
||||
return result;
|
||||
}
|
||||
if (opt3001Sensor.hasSensor()) {
|
||||
result = opt3001Sensor.handleAdminMessage(mp, request, response);
|
||||
if (result != AdminMessageHandleResult::NOT_HANDLED)
|
||||
return result;
|
||||
}
|
||||
if (mlx90632Sensor.hasSensor()) {
|
||||
result = mlx90632Sensor.handleAdminMessage(mp, request, response);
|
||||
if (result != AdminMessageHandleResult::NOT_HANDLED)
|
||||
return result;
|
||||
}
|
||||
if (rcwl9620Sensor.hasSensor()) {
|
||||
result = rcwl9620Sensor.handleAdminMessage(mp, request, response);
|
||||
if (result != AdminMessageHandleResult::NOT_HANDLED)
|
||||
return result;
|
||||
}
|
||||
if (nau7802Sensor.hasSensor()) {
|
||||
result = nau7802Sensor.handleAdminMessage(mp, request, response);
|
||||
if (result != AdminMessageHandleResult::NOT_HANDLED)
|
||||
return result;
|
||||
}
|
||||
if (aht10Sensor.hasSensor()) {
|
||||
result = aht10Sensor.handleAdminMessage(mp, request, response);
|
||||
if (result != AdminMessageHandleResult::NOT_HANDLED)
|
||||
return result;
|
||||
}
|
||||
if (max17048Sensor.hasSensor()) {
|
||||
result = max17048Sensor.handleAdminMessage(mp, request, response);
|
||||
if (result != AdminMessageHandleResult::NOT_HANDLED)
|
||||
return result;
|
||||
}
|
||||
if (cgRadSens.hasSensor()) {
|
||||
result = cgRadSens.handleAdminMessage(mp, request, response);
|
||||
if (result != AdminMessageHandleResult::NOT_HANDLED)
|
||||
return result;
|
||||
}
|
||||
#if __has_include("RAK12035_SoilMoisture.h") && defined(RAK_4631) && \
|
||||
RAK_4631 == \
|
||||
1 // Not really needed, but may as well just skip it at a lower level if no library or not a RAK_4631
|
||||
if (rak12035Sensor.hasSensor()) {
|
||||
result = rak12035Sensor.handleAdminMessage(mp, request, response);
|
||||
if (result != AdminMessageHandleResult::NOT_HANDLED)
|
||||
return result;
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -11,13 +11,10 @@
|
||||
#include "../mesh/generated/meshtastic/telemetry.pb.h"
|
||||
#include "NodeDB.h"
|
||||
#include "ProtobufModule.h"
|
||||
#include "detect/ScanI2CConsumer.h"
|
||||
#include <OLEDDisplay.h>
|
||||
#include <OLEDDisplayUi.h>
|
||||
|
||||
class EnvironmentTelemetryModule : private concurrency::OSThread,
|
||||
public ScanI2CConsumer,
|
||||
public ProtobufModule<meshtastic_Telemetry>
|
||||
class EnvironmentTelemetryModule : private concurrency::OSThread, public ProtobufModule<meshtastic_Telemetry>
|
||||
{
|
||||
CallbackObserver<EnvironmentTelemetryModule, const meshtastic::Status *> nodeStatusObserver =
|
||||
CallbackObserver<EnvironmentTelemetryModule, const meshtastic::Status *>(this,
|
||||
@@ -25,7 +22,7 @@ class EnvironmentTelemetryModule : private concurrency::OSThread,
|
||||
|
||||
public:
|
||||
EnvironmentTelemetryModule()
|
||||
: concurrency::OSThread("EnvironmentTelemetry"), ScanI2CConsumer(),
|
||||
: concurrency::OSThread("EnvironmentTelemetry"),
|
||||
ProtobufModule("EnvironmentTelemetry", meshtastic_PortNum_TELEMETRY_APP, &meshtastic_Telemetry_msg)
|
||||
{
|
||||
lastMeasurementPacket = nullptr;
|
||||
@@ -59,8 +56,6 @@ class EnvironmentTelemetryModule : private concurrency::OSThread,
|
||||
meshtastic_AdminMessage *request,
|
||||
meshtastic_AdminMessage *response) override;
|
||||
|
||||
void i2cScanFinished(ScanI2C *i2cScanner);
|
||||
|
||||
private:
|
||||
bool firstTime = 1;
|
||||
meshtastic_MeshPacket *lastMeasurementPacket;
|
||||
|
||||
@@ -108,7 +108,6 @@ bool PowerTelemetryModule::wantUIFrame()
|
||||
return moduleConfig.telemetry.power_screen_enabled;
|
||||
}
|
||||
|
||||
#if HAS_SCREEN
|
||||
void PowerTelemetryModule::drawFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y)
|
||||
{
|
||||
display->clear();
|
||||
@@ -166,7 +165,6 @@ void PowerTelemetryModule::drawFrame(OLEDDisplay *display, OLEDDisplayUiState *s
|
||||
drawLine("Ch3", m.ch3_voltage, m.ch3_current);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
bool PowerTelemetryModule::handleReceivedProtobuf(const meshtastic_MeshPacket &mp, meshtastic_Telemetry *t)
|
||||
{
|
||||
|
||||
@@ -15,16 +15,20 @@
|
||||
|
||||
AHT10Sensor::AHT10Sensor() : TelemetrySensor(meshtastic_TelemetrySensorType_AHT10, "AHT10") {}
|
||||
|
||||
bool AHT10Sensor::initDevice(TwoWire *bus, ScanI2C::FoundDevice *dev)
|
||||
int32_t AHT10Sensor::runOnce()
|
||||
{
|
||||
LOG_INFO("Init sensor: %s", sensorName);
|
||||
if (!hasSensor()) {
|
||||
return DEFAULT_SENSOR_MINIMUM_WAIT_TIME_BETWEEN_READS;
|
||||
}
|
||||
aht10 = Adafruit_AHTX0();
|
||||
status = aht10.begin(bus, 0, dev->address.address);
|
||||
status = aht10.begin(nodeTelemetrySensorsMap[sensorType].second, 0, nodeTelemetrySensorsMap[sensorType].first);
|
||||
|
||||
initI2CSensor();
|
||||
return status;
|
||||
return initI2CSensor();
|
||||
}
|
||||
|
||||
void AHT10Sensor::setup() {}
|
||||
|
||||
bool AHT10Sensor::getMetrics(meshtastic_Telemetry *measurement)
|
||||
{
|
||||
LOG_DEBUG("AHT10 getMetrics");
|
||||
@@ -32,16 +36,11 @@ bool AHT10Sensor::getMetrics(meshtastic_Telemetry *measurement)
|
||||
sensors_event_t humidity, temp;
|
||||
aht10.getEvent(&humidity, &temp);
|
||||
|
||||
// prefer other sensors like bmp280, bmp3xx
|
||||
if (!measurement->variant.environment_metrics.has_temperature) {
|
||||
measurement->variant.environment_metrics.has_temperature = true;
|
||||
measurement->variant.environment_metrics.temperature = temp.temperature;
|
||||
}
|
||||
measurement->variant.environment_metrics.has_temperature = true;
|
||||
measurement->variant.environment_metrics.has_relative_humidity = true;
|
||||
|
||||
if (!measurement->variant.environment_metrics.has_relative_humidity) {
|
||||
measurement->variant.environment_metrics.has_relative_humidity = true;
|
||||
measurement->variant.environment_metrics.relative_humidity = humidity.relative_humidity;
|
||||
}
|
||||
measurement->variant.environment_metrics.temperature = temp.temperature;
|
||||
measurement->variant.environment_metrics.relative_humidity = humidity.relative_humidity;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -15,10 +15,13 @@ class AHT10Sensor : public TelemetrySensor
|
||||
private:
|
||||
Adafruit_AHTX0 aht10;
|
||||
|
||||
protected:
|
||||
virtual void setup() override;
|
||||
|
||||
public:
|
||||
AHT10Sensor();
|
||||
virtual int32_t runOnce() override;
|
||||
virtual bool getMetrics(meshtastic_Telemetry *measurement) override;
|
||||
virtual bool initDevice(TwoWire *bus, ScanI2C::FoundDevice *dev) override;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -10,13 +10,13 @@
|
||||
|
||||
BME280Sensor::BME280Sensor() : TelemetrySensor(meshtastic_TelemetrySensorType_BME280, "BME280") {}
|
||||
|
||||
bool BME280Sensor::initDevice(TwoWire *bus, ScanI2C::FoundDevice *dev)
|
||||
int32_t BME280Sensor::runOnce()
|
||||
{
|
||||
LOG_INFO("Init sensor: %s", sensorName);
|
||||
status = bme280.begin(dev->address.address, bus);
|
||||
if (!status) {
|
||||
return status;
|
||||
if (!hasSensor()) {
|
||||
return DEFAULT_SENSOR_MINIMUM_WAIT_TIME_BETWEEN_READS;
|
||||
}
|
||||
status = bme280.begin(nodeTelemetrySensorsMap[sensorType].first, nodeTelemetrySensorsMap[sensorType].second);
|
||||
|
||||
bme280.setSampling(Adafruit_BME280::MODE_FORCED,
|
||||
Adafruit_BME280::SAMPLING_X1, // Temp. oversampling
|
||||
@@ -24,10 +24,11 @@ bool BME280Sensor::initDevice(TwoWire *bus, ScanI2C::FoundDevice *dev)
|
||||
Adafruit_BME280::SAMPLING_X1, // Humidity oversampling
|
||||
Adafruit_BME280::FILTER_OFF, Adafruit_BME280::STANDBY_MS_1000);
|
||||
|
||||
initI2CSensor();
|
||||
return status;
|
||||
return initI2CSensor();
|
||||
}
|
||||
|
||||
void BME280Sensor::setup() {}
|
||||
|
||||
bool BME280Sensor::getMetrics(meshtastic_Telemetry *measurement)
|
||||
{
|
||||
measurement->variant.environment_metrics.has_temperature = true;
|
||||
|
||||
@@ -11,10 +11,13 @@ class BME280Sensor : public TelemetrySensor
|
||||
private:
|
||||
Adafruit_BME280 bme280;
|
||||
|
||||
protected:
|
||||
virtual void setup() override;
|
||||
|
||||
public:
|
||||
BME280Sensor();
|
||||
virtual int32_t runOnce() override;
|
||||
virtual bool getMetrics(meshtastic_Telemetry *measurement) override;
|
||||
virtual bool initDevice(TwoWire *bus, ScanI2C::FoundDevice *dev) override;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -10,7 +10,7 @@
|
||||
|
||||
BME680Sensor::BME680Sensor() : TelemetrySensor(meshtastic_TelemetrySensorType_BME680, "BME680") {}
|
||||
|
||||
int32_t BME680Sensor::runOnce()
|
||||
int32_t BME680Sensor::runTrigger()
|
||||
{
|
||||
if (!bme680.run()) {
|
||||
checkStatus("runTrigger");
|
||||
@@ -18,10 +18,13 @@ int32_t BME680Sensor::runOnce()
|
||||
return 35;
|
||||
}
|
||||
|
||||
bool BME680Sensor::initDevice(TwoWire *bus, ScanI2C::FoundDevice *dev)
|
||||
int32_t BME680Sensor::runOnce()
|
||||
{
|
||||
status = 0;
|
||||
if (!bme680.begin(dev->address.address, *bus))
|
||||
|
||||
if (!hasSensor()) {
|
||||
return DEFAULT_SENSOR_MINIMUM_WAIT_TIME_BETWEEN_READS;
|
||||
}
|
||||
if (!bme680.begin(nodeTelemetrySensorsMap[sensorType].first, *nodeTelemetrySensorsMap[sensorType].second))
|
||||
checkStatus("begin");
|
||||
|
||||
if (bme680.status == BSEC_OK) {
|
||||
@@ -37,15 +40,17 @@ bool BME680Sensor::initDevice(TwoWire *bus, ScanI2C::FoundDevice *dev)
|
||||
}
|
||||
LOG_INFO("Init sensor: %s with the BSEC Library version %d.%d.%d.%d ", sensorName, bme680.version.major,
|
||||
bme680.version.minor, bme680.version.major_bugfix, bme680.version.minor_bugfix);
|
||||
} else {
|
||||
status = 0;
|
||||
}
|
||||
|
||||
if (status == 0)
|
||||
LOG_DEBUG("BME680Sensor::runOnce: bme680.status %d", bme680.status);
|
||||
|
||||
initI2CSensor();
|
||||
return status;
|
||||
return initI2CSensor();
|
||||
}
|
||||
|
||||
void BME680Sensor::setup() {}
|
||||
|
||||
bool BME680Sensor::getMetrics(meshtastic_Telemetry *measurement)
|
||||
{
|
||||
if (bme680.getData(BSEC_OUTPUT_RAW_PRESSURE).signal == 0)
|
||||
|
||||
@@ -18,6 +18,7 @@ class BME680Sensor : public TelemetrySensor
|
||||
Bsec2 bme680;
|
||||
|
||||
protected:
|
||||
virtual void setup() override;
|
||||
const char *bsecConfigFileName = "/prefs/bsec.dat";
|
||||
uint8_t bsecState[BSEC_MAX_STATE_BLOB_SIZE] = {0};
|
||||
uint8_t accuracy = 0;
|
||||
@@ -37,9 +38,9 @@ class BME680Sensor : public TelemetrySensor
|
||||
|
||||
public:
|
||||
BME680Sensor();
|
||||
int32_t runTrigger();
|
||||
virtual int32_t runOnce() override;
|
||||
virtual bool getMetrics(meshtastic_Telemetry *measurement) override;
|
||||
virtual bool initDevice(TwoWire *bus, ScanI2C::FoundDevice *dev) override;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -10,17 +10,20 @@
|
||||
|
||||
BMP085Sensor::BMP085Sensor() : TelemetrySensor(meshtastic_TelemetrySensorType_BMP085, "BMP085") {}
|
||||
|
||||
bool BMP085Sensor::initDevice(TwoWire *bus, ScanI2C::FoundDevice *dev)
|
||||
int32_t BMP085Sensor::runOnce()
|
||||
{
|
||||
LOG_INFO("Init sensor: %s", sensorName);
|
||||
|
||||
if (!hasSensor()) {
|
||||
return DEFAULT_SENSOR_MINIMUM_WAIT_TIME_BETWEEN_READS;
|
||||
}
|
||||
bmp085 = Adafruit_BMP085();
|
||||
status = bmp085.begin(dev->address.address, bus);
|
||||
status = bmp085.begin(nodeTelemetrySensorsMap[sensorType].first, nodeTelemetrySensorsMap[sensorType].second);
|
||||
|
||||
initI2CSensor();
|
||||
return status;
|
||||
return initI2CSensor();
|
||||
}
|
||||
|
||||
void BMP085Sensor::setup() {}
|
||||
|
||||
bool BMP085Sensor::getMetrics(meshtastic_Telemetry *measurement)
|
||||
{
|
||||
measurement->variant.environment_metrics.has_temperature = true;
|
||||
|
||||
@@ -11,10 +11,13 @@ class BMP085Sensor : public TelemetrySensor
|
||||
private:
|
||||
Adafruit_BMP085 bmp085;
|
||||
|
||||
protected:
|
||||
virtual void setup() override;
|
||||
|
||||
public:
|
||||
BMP085Sensor();
|
||||
virtual int32_t runOnce() override;
|
||||
virtual bool getMetrics(meshtastic_Telemetry *measurement) override;
|
||||
virtual bool initDevice(TwoWire *bus, ScanI2C::FoundDevice *dev) override;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -10,25 +10,25 @@
|
||||
|
||||
BMP280Sensor::BMP280Sensor() : TelemetrySensor(meshtastic_TelemetrySensorType_BMP280, "BMP280") {}
|
||||
|
||||
bool BMP280Sensor::initDevice(TwoWire *bus, ScanI2C::FoundDevice *dev)
|
||||
int32_t BMP280Sensor::runOnce()
|
||||
{
|
||||
LOG_INFO("Init sensor: %s", sensorName);
|
||||
|
||||
bmp280 = Adafruit_BMP280(bus);
|
||||
status = bmp280.begin(dev->address.address);
|
||||
if (!status) {
|
||||
return status;
|
||||
if (!hasSensor()) {
|
||||
return DEFAULT_SENSOR_MINIMUM_WAIT_TIME_BETWEEN_READS;
|
||||
}
|
||||
bmp280 = Adafruit_BMP280(nodeTelemetrySensorsMap[sensorType].second);
|
||||
status = bmp280.begin(nodeTelemetrySensorsMap[sensorType].first);
|
||||
|
||||
bmp280.setSampling(Adafruit_BMP280::MODE_FORCED,
|
||||
Adafruit_BMP280::SAMPLING_X1, // Temp. oversampling
|
||||
Adafruit_BMP280::SAMPLING_X1, // Pressure oversampling
|
||||
Adafruit_BMP280::FILTER_OFF, Adafruit_BMP280::STANDBY_MS_1000);
|
||||
|
||||
initI2CSensor();
|
||||
return status;
|
||||
return initI2CSensor();
|
||||
}
|
||||
|
||||
void BMP280Sensor::setup() {}
|
||||
|
||||
bool BMP280Sensor::getMetrics(meshtastic_Telemetry *measurement)
|
||||
{
|
||||
measurement->variant.environment_metrics.has_temperature = true;
|
||||
|
||||
@@ -11,10 +11,13 @@ class BMP280Sensor : public TelemetrySensor
|
||||
private:
|
||||
Adafruit_BMP280 bmp280;
|
||||
|
||||
protected:
|
||||
virtual void setup() override;
|
||||
|
||||
public:
|
||||
BMP280Sensor();
|
||||
virtual int32_t runOnce() override;
|
||||
virtual bool getMetrics(meshtastic_Telemetry *measurement) override;
|
||||
virtual bool initDevice(TwoWire *bus, ScanI2C::FoundDevice *dev) override;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -6,18 +6,20 @@
|
||||
|
||||
BMP3XXSensor::BMP3XXSensor() : TelemetrySensor(meshtastic_TelemetrySensorType_BMP3XX, "BMP3XX") {}
|
||||
|
||||
bool BMP3XXSensor::initDevice(TwoWire *bus, ScanI2C::FoundDevice *dev)
|
||||
void BMP3XXSensor::setup() {}
|
||||
|
||||
int32_t BMP3XXSensor::runOnce()
|
||||
{
|
||||
LOG_INFO("Init sensor: %s", sensorName);
|
||||
if (!hasSensor()) {
|
||||
return DEFAULT_SENSOR_MINIMUM_WAIT_TIME_BETWEEN_READS;
|
||||
}
|
||||
|
||||
// Get a singleton instance and initialise the bmp3xx
|
||||
if (bmp3xx == nullptr) {
|
||||
bmp3xx = BMP3XXSingleton::GetInstance();
|
||||
}
|
||||
status = bmp3xx->begin_I2C(dev->address.address, bus);
|
||||
if (!status) {
|
||||
return status;
|
||||
}
|
||||
status = bmp3xx->begin_I2C(nodeTelemetrySensorsMap[sensorType].first, nodeTelemetrySensorsMap[sensorType].second);
|
||||
|
||||
// set up oversampling and filter initialization
|
||||
bmp3xx->setTemperatureOversampling(BMP3_OVERSAMPLING_4X);
|
||||
@@ -29,8 +31,7 @@ bool BMP3XXSensor::initDevice(TwoWire *bus, ScanI2C::FoundDevice *dev)
|
||||
for (int i = 0; i < 3; i++) {
|
||||
bmp3xx->performReading();
|
||||
}
|
||||
initI2CSensor();
|
||||
return status;
|
||||
return initI2CSensor();
|
||||
}
|
||||
|
||||
bool BMP3XXSensor::getMetrics(meshtastic_Telemetry *measurement)
|
||||
|
||||
@@ -43,11 +43,12 @@ class BMP3XXSensor : public TelemetrySensor
|
||||
{
|
||||
protected:
|
||||
BMP3XXSingleton *bmp3xx = nullptr;
|
||||
virtual void setup() override;
|
||||
|
||||
public:
|
||||
BMP3XXSensor();
|
||||
virtual int32_t runOnce() override;
|
||||
virtual bool getMetrics(meshtastic_Telemetry *measurement) override;
|
||||
virtual bool initDevice(TwoWire *bus, ScanI2C::FoundDevice *dev) override;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -14,16 +14,22 @@
|
||||
|
||||
CGRadSensSensor::CGRadSensSensor() : TelemetrySensor(meshtastic_TelemetrySensorType_RADSENS, "RadSens") {}
|
||||
|
||||
bool CGRadSensSensor::initDevice(TwoWire *bus, ScanI2C::FoundDevice *dev)
|
||||
int32_t CGRadSensSensor::runOnce()
|
||||
{
|
||||
// Initialize the sensor following the same pattern as RCWL9620Sensor
|
||||
LOG_INFO("Init sensor: %s", sensorName);
|
||||
if (!hasSensor()) {
|
||||
return DEFAULT_SENSOR_MINIMUM_WAIT_TIME_BETWEEN_READS;
|
||||
}
|
||||
|
||||
status = true;
|
||||
begin(bus, dev->address.address);
|
||||
initI2CSensor();
|
||||
return status;
|
||||
begin(nodeTelemetrySensorsMap[sensorType].second, nodeTelemetrySensorsMap[sensorType].first);
|
||||
|
||||
return initI2CSensor();
|
||||
}
|
||||
|
||||
void CGRadSensSensor::setup() {}
|
||||
|
||||
void CGRadSensSensor::begin(TwoWire *wire, uint8_t addr)
|
||||
{
|
||||
// Store the Wire and address to the sensor following the same pattern as RCWL9620Sensor
|
||||
|
||||
@@ -17,13 +17,14 @@ class CGRadSensSensor : public TelemetrySensor
|
||||
TwoWire *_wire = &Wire;
|
||||
|
||||
protected:
|
||||
virtual void setup() override;
|
||||
void begin(TwoWire *wire = &Wire, uint8_t addr = 0x66);
|
||||
float getStaticRadiation();
|
||||
|
||||
public:
|
||||
CGRadSensSensor();
|
||||
virtual int32_t runOnce() override;
|
||||
virtual bool getMetrics(meshtastic_Telemetry *measurement) override;
|
||||
virtual bool initDevice(TwoWire *bus, ScanI2C::FoundDevice *dev) override;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -10,39 +10,31 @@
|
||||
|
||||
DFRobotGravitySensor::DFRobotGravitySensor() : TelemetrySensor(meshtastic_TelemetrySensorType_DFROBOT_RAIN, "DFROBOT_RAIN") {}
|
||||
|
||||
DFRobotGravitySensor::~DFRobotGravitySensor()
|
||||
{
|
||||
if (gravity) {
|
||||
delete gravity;
|
||||
gravity = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
bool DFRobotGravitySensor::initDevice(TwoWire *bus, ScanI2C::FoundDevice *dev)
|
||||
int32_t DFRobotGravitySensor::runOnce()
|
||||
{
|
||||
LOG_INFO("Init sensor: %s", sensorName);
|
||||
if (!hasSensor()) {
|
||||
return DEFAULT_SENSOR_MINIMUM_WAIT_TIME_BETWEEN_READS;
|
||||
}
|
||||
|
||||
gravity = new DFRobot_RainfallSensor_I2C(bus);
|
||||
status = gravity->begin();
|
||||
gravity = DFRobot_RainfallSensor_I2C(nodeTelemetrySensorsMap[sensorType].second);
|
||||
status = gravity.begin();
|
||||
|
||||
LOG_DEBUG("%s VID: %x, PID: %x, Version: %s", sensorName, gravity->vid, gravity->pid, gravity->getFirmwareVersion().c_str());
|
||||
return initI2CSensor();
|
||||
}
|
||||
|
||||
initI2CSensor();
|
||||
return status;
|
||||
void DFRobotGravitySensor::setup()
|
||||
{
|
||||
LOG_DEBUG("%s VID: %x, PID: %x, Version: %s", sensorName, gravity.vid, gravity.pid, gravity.getFirmwareVersion().c_str());
|
||||
}
|
||||
|
||||
bool DFRobotGravitySensor::getMetrics(meshtastic_Telemetry *measurement)
|
||||
{
|
||||
if (!gravity) {
|
||||
LOG_ERROR("DFRobotGravitySensor not initialized");
|
||||
return false;
|
||||
}
|
||||
|
||||
measurement->variant.environment_metrics.has_rainfall_1h = true;
|
||||
measurement->variant.environment_metrics.has_rainfall_24h = true;
|
||||
|
||||
measurement->variant.environment_metrics.rainfall_1h = gravity->getRainfall(1);
|
||||
measurement->variant.environment_metrics.rainfall_24h = gravity->getRainfall(24);
|
||||
measurement->variant.environment_metrics.rainfall_1h = gravity.getRainfall(1);
|
||||
measurement->variant.environment_metrics.rainfall_24h = gravity.getRainfall(24);
|
||||
|
||||
LOG_INFO("Rain 1h: %f mm", measurement->variant.environment_metrics.rainfall_1h);
|
||||
LOG_INFO("Rain 24h: %f mm", measurement->variant.environment_metrics.rainfall_24h);
|
||||
|
||||
@@ -14,13 +14,15 @@
|
||||
class DFRobotGravitySensor : public TelemetrySensor
|
||||
{
|
||||
private:
|
||||
DFRobot_RainfallSensor_I2C *gravity = nullptr;
|
||||
DFRobot_RainfallSensor_I2C gravity = DFRobot_RainfallSensor_I2C(nodeTelemetrySensorsMap[sensorType].second);
|
||||
|
||||
protected:
|
||||
virtual void setup() override;
|
||||
|
||||
public:
|
||||
DFRobotGravitySensor();
|
||||
~DFRobotGravitySensor();
|
||||
virtual int32_t runOnce() override;
|
||||
virtual bool getMetrics(meshtastic_Telemetry *measurement) override;
|
||||
virtual bool initDevice(TwoWire *bus, ScanI2C::FoundDevice *dev) override;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -11,10 +11,14 @@
|
||||
|
||||
DFRobotLarkSensor::DFRobotLarkSensor() : TelemetrySensor(meshtastic_TelemetrySensorType_DFROBOT_LARK, "DFROBOT_LARK") {}
|
||||
|
||||
bool DFRobotLarkSensor::initDevice(TwoWire *bus, ScanI2C::FoundDevice *dev)
|
||||
int32_t DFRobotLarkSensor::runOnce()
|
||||
{
|
||||
LOG_INFO("Init sensor: %s", sensorName);
|
||||
lark = DFRobot_LarkWeatherStation_I2C(dev->address.address, bus);
|
||||
if (!hasSensor()) {
|
||||
return DEFAULT_SENSOR_MINIMUM_WAIT_TIME_BETWEEN_READS;
|
||||
}
|
||||
|
||||
lark = DFRobot_LarkWeatherStation_I2C(nodeTelemetrySensorsMap[sensorType].first, nodeTelemetrySensorsMap[sensorType].second);
|
||||
|
||||
if (lark.begin() == 0) // DFRobotLarkSensor init
|
||||
{
|
||||
@@ -24,10 +28,11 @@ bool DFRobotLarkSensor::initDevice(TwoWire *bus, ScanI2C::FoundDevice *dev)
|
||||
LOG_ERROR("DFRobotLarkSensor Init Failed");
|
||||
status = false;
|
||||
}
|
||||
initI2CSensor();
|
||||
return status;
|
||||
return initI2CSensor();
|
||||
}
|
||||
|
||||
void DFRobotLarkSensor::setup() {}
|
||||
|
||||
bool DFRobotLarkSensor::getMetrics(meshtastic_Telemetry *measurement)
|
||||
{
|
||||
measurement->variant.environment_metrics.has_temperature = true;
|
||||
|
||||
@@ -16,10 +16,13 @@ class DFRobotLarkSensor : public TelemetrySensor
|
||||
private:
|
||||
DFRobot_LarkWeatherStation_I2C lark = DFRobot_LarkWeatherStation_I2C();
|
||||
|
||||
protected:
|
||||
virtual void setup() override;
|
||||
|
||||
public:
|
||||
DFRobotLarkSensor();
|
||||
virtual int32_t runOnce() override;
|
||||
virtual bool getMetrics(meshtastic_Telemetry *measurement) override;
|
||||
virtual bool initDevice(TwoWire *bus, ScanI2C::FoundDevice *dev) override;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -9,22 +9,23 @@
|
||||
|
||||
DPS310Sensor::DPS310Sensor() : TelemetrySensor(meshtastic_TelemetrySensorType_DPS310, "DPS310") {}
|
||||
|
||||
bool DPS310Sensor::initDevice(TwoWire *bus, ScanI2C::FoundDevice *dev)
|
||||
int32_t DPS310Sensor::runOnce()
|
||||
{
|
||||
LOG_INFO("Init sensor: %s", sensorName);
|
||||
status = dps310.begin_I2C(dev->address.address, bus);
|
||||
if (!status) {
|
||||
return status;
|
||||
if (!hasSensor()) {
|
||||
return DEFAULT_SENSOR_MINIMUM_WAIT_TIME_BETWEEN_READS;
|
||||
}
|
||||
status = dps310.begin_I2C(nodeTelemetrySensorsMap[sensorType].first, nodeTelemetrySensorsMap[sensorType].second);
|
||||
|
||||
dps310.configurePressure(DPS310_1HZ, DPS310_4SAMPLES);
|
||||
dps310.configureTemperature(DPS310_1HZ, DPS310_4SAMPLES);
|
||||
dps310.setMode(DPS310_CONT_PRESTEMP);
|
||||
|
||||
initI2CSensor();
|
||||
return status;
|
||||
return initI2CSensor();
|
||||
}
|
||||
|
||||
void DPS310Sensor::setup() {}
|
||||
|
||||
bool DPS310Sensor::getMetrics(meshtastic_Telemetry *measurement)
|
||||
{
|
||||
sensors_event_t temp, press;
|
||||
|
||||
@@ -11,10 +11,13 @@ class DPS310Sensor : public TelemetrySensor
|
||||
private:
|
||||
Adafruit_DPS310 dps310;
|
||||
|
||||
protected:
|
||||
virtual void setup() override;
|
||||
|
||||
public:
|
||||
DPS310Sensor();
|
||||
virtual int32_t runOnce() override;
|
||||
virtual bool getMetrics(meshtastic_Telemetry *measurement) override;
|
||||
virtual bool initDevice(TwoWire *bus, ScanI2C::FoundDevice *dev) override;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -61,11 +61,11 @@ static int cmd_send(uint8_t cmd, const char *p_data, uint8_t len)
|
||||
return -1;
|
||||
}
|
||||
|
||||
bool IndicatorSensor::initDevice(TwoWire *bus, ScanI2C::FoundDevice *dev)
|
||||
int32_t IndicatorSensor::runOnce()
|
||||
{
|
||||
LOG_INFO("%s: init", sensorName);
|
||||
setup();
|
||||
return true;
|
||||
return 2 * DEFAULT_SENSOR_MINIMUM_WAIT_TIME_BETWEEN_READS; // give it some time to start up
|
||||
}
|
||||
|
||||
void IndicatorSensor::setup()
|
||||
|
||||
@@ -7,13 +7,13 @@
|
||||
|
||||
class IndicatorSensor : public TelemetrySensor
|
||||
{
|
||||
protected:
|
||||
virtual void setup() override;
|
||||
|
||||
public:
|
||||
IndicatorSensor();
|
||||
virtual int32_t runOnce() override;
|
||||
virtual bool getMetrics(meshtastic_Telemetry *measurement) override;
|
||||
virtual bool initDevice(TwoWire *bus, ScanI2C::FoundDevice *dev) override;
|
||||
|
||||
private:
|
||||
void setup();
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -10,17 +10,19 @@
|
||||
|
||||
LPS22HBSensor::LPS22HBSensor() : TelemetrySensor(meshtastic_TelemetrySensorType_LPS22, "LPS22HB") {}
|
||||
|
||||
bool LPS22HBSensor::initDevice(TwoWire *bus, ScanI2C::FoundDevice *dev)
|
||||
int32_t LPS22HBSensor::runOnce()
|
||||
{
|
||||
LOG_INFO("Init sensor: %s", sensorName);
|
||||
status = lps22hb.begin_I2C(dev->address.address, bus);
|
||||
if (!status) {
|
||||
return status;
|
||||
if (!hasSensor()) {
|
||||
return DEFAULT_SENSOR_MINIMUM_WAIT_TIME_BETWEEN_READS;
|
||||
}
|
||||
lps22hb.setDataRate(LPS22_RATE_10_HZ);
|
||||
status = lps22hb.begin_I2C(nodeTelemetrySensorsMap[sensorType].first, nodeTelemetrySensorsMap[sensorType].second);
|
||||
return initI2CSensor();
|
||||
}
|
||||
|
||||
initI2CSensor();
|
||||
return status;
|
||||
void LPS22HBSensor::setup()
|
||||
{
|
||||
lps22hb.setDataRate(LPS22_RATE_10_HZ);
|
||||
}
|
||||
|
||||
bool LPS22HBSensor::getMetrics(meshtastic_Telemetry *measurement)
|
||||
|
||||
@@ -12,10 +12,13 @@ class LPS22HBSensor : public TelemetrySensor
|
||||
private:
|
||||
Adafruit_LPS22 lps22hb;
|
||||
|
||||
protected:
|
||||
virtual void setup() override;
|
||||
|
||||
public:
|
||||
LPS22HBSensor();
|
||||
virtual int32_t runOnce() override;
|
||||
virtual bool getMetrics(meshtastic_Telemetry *measurement) override;
|
||||
virtual bool initDevice(TwoWire *bus, ScanI2C::FoundDevice *dev) override;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -9,23 +9,23 @@
|
||||
|
||||
LTR390UVSensor::LTR390UVSensor() : TelemetrySensor(meshtastic_TelemetrySensorType_LTR390UV, "LTR390UV") {}
|
||||
|
||||
bool LTR390UVSensor::initDevice(TwoWire *bus, ScanI2C::FoundDevice *dev)
|
||||
int32_t LTR390UVSensor::runOnce()
|
||||
{
|
||||
LOG_INFO("Init sensor: %s", sensorName);
|
||||
|
||||
status = ltr390uv.begin(bus);
|
||||
if (!status) {
|
||||
return status;
|
||||
if (!hasSensor()) {
|
||||
return DEFAULT_SENSOR_MINIMUM_WAIT_TIME_BETWEEN_READS;
|
||||
}
|
||||
|
||||
status = ltr390uv.begin(nodeTelemetrySensorsMap[sensorType].second);
|
||||
ltr390uv.setMode(LTR390_MODE_UVS);
|
||||
ltr390uv.setGain(LTR390_GAIN_18); // Datasheet default
|
||||
ltr390uv.setResolution(LTR390_RESOLUTION_20BIT); // Datasheet default
|
||||
|
||||
initI2CSensor();
|
||||
return status;
|
||||
return initI2CSensor();
|
||||
}
|
||||
|
||||
void LTR390UVSensor::setup() {}
|
||||
|
||||
bool LTR390UVSensor::getMetrics(meshtastic_Telemetry *measurement)
|
||||
{
|
||||
LOG_DEBUG("LTR390UV getMetrics");
|
||||
|
||||
@@ -13,10 +13,13 @@ class LTR390UVSensor : public TelemetrySensor
|
||||
float lastLuxReading = 0;
|
||||
float lastUVReading = 0;
|
||||
|
||||
protected:
|
||||
virtual void setup() override;
|
||||
|
||||
public:
|
||||
LTR390UVSensor();
|
||||
virtual int32_t runOnce() override;
|
||||
virtual bool getMetrics(meshtastic_Telemetry *measurement) override;
|
||||
virtual bool initDevice(TwoWire *bus, ScanI2C::FoundDevice *dev) override;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -9,17 +9,19 @@
|
||||
|
||||
MCP9808Sensor::MCP9808Sensor() : TelemetrySensor(meshtastic_TelemetrySensorType_MCP9808, "MCP9808") {}
|
||||
|
||||
bool MCP9808Sensor::initDevice(TwoWire *bus, ScanI2C::FoundDevice *dev)
|
||||
int32_t MCP9808Sensor::runOnce()
|
||||
{
|
||||
LOG_INFO("Init sensor: %s", sensorName);
|
||||
status = mcp9808.begin(dev->address.address, bus);
|
||||
if (!status) {
|
||||
return status;
|
||||
if (!hasSensor()) {
|
||||
return DEFAULT_SENSOR_MINIMUM_WAIT_TIME_BETWEEN_READS;
|
||||
}
|
||||
mcp9808.setResolution(2);
|
||||
status = mcp9808.begin(nodeTelemetrySensorsMap[sensorType].first, nodeTelemetrySensorsMap[sensorType].second);
|
||||
return initI2CSensor();
|
||||
}
|
||||
|
||||
initI2CSensor();
|
||||
return status;
|
||||
void MCP9808Sensor::setup()
|
||||
{
|
||||
mcp9808.setResolution(2);
|
||||
}
|
||||
|
||||
bool MCP9808Sensor::getMetrics(meshtastic_Telemetry *measurement)
|
||||
|
||||
@@ -11,10 +11,13 @@ class MCP9808Sensor : public TelemetrySensor
|
||||
private:
|
||||
Adafruit_MCP9808 mcp9808;
|
||||
|
||||
protected:
|
||||
virtual void setup() override;
|
||||
|
||||
public:
|
||||
MCP9808Sensor();
|
||||
virtual int32_t runOnce() override;
|
||||
virtual bool getMetrics(meshtastic_Telemetry *measurement) override;
|
||||
virtual bool initDevice(TwoWire *bus, ScanI2C::FoundDevice *dev) override;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -8,12 +8,16 @@
|
||||
|
||||
MLX90632Sensor::MLX90632Sensor() : TelemetrySensor(meshtastic_TelemetrySensorType_MLX90632, "MLX90632") {}
|
||||
|
||||
bool MLX90632Sensor::initDevice(TwoWire *bus, ScanI2C::FoundDevice *dev)
|
||||
int32_t MLX90632Sensor::runOnce()
|
||||
{
|
||||
LOG_INFO("Init sensor: %s", sensorName);
|
||||
if (!hasSensor()) {
|
||||
return DEFAULT_SENSOR_MINIMUM_WAIT_TIME_BETWEEN_READS;
|
||||
}
|
||||
|
||||
MLX90632::status returnError;
|
||||
if (mlx.begin(dev->address.address, *bus, returnError) == true) // MLX90632 init
|
||||
if (mlx.begin(nodeTelemetrySensorsMap[sensorType].first, *nodeTelemetrySensorsMap[sensorType].second, returnError) ==
|
||||
true) // MLX90632 init
|
||||
{
|
||||
LOG_DEBUG("MLX90632 Init Succeed");
|
||||
status = true;
|
||||
@@ -21,10 +25,11 @@ bool MLX90632Sensor::initDevice(TwoWire *bus, ScanI2C::FoundDevice *dev)
|
||||
LOG_ERROR("MLX90632 Init Failed");
|
||||
status = false;
|
||||
}
|
||||
initI2CSensor();
|
||||
return status;
|
||||
return initI2CSensor();
|
||||
}
|
||||
|
||||
void MLX90632Sensor::setup() {}
|
||||
|
||||
bool MLX90632Sensor::getMetrics(meshtastic_Telemetry *measurement)
|
||||
{
|
||||
measurement->variant.environment_metrics.has_temperature = true;
|
||||
|
||||
@@ -11,10 +11,13 @@ class MLX90632Sensor : public TelemetrySensor
|
||||
private:
|
||||
MLX90632 mlx = MLX90632();
|
||||
|
||||
protected:
|
||||
virtual void setup() override;
|
||||
|
||||
public:
|
||||
MLX90632Sensor();
|
||||
virtual int32_t runOnce() override;
|
||||
virtual bool getMetrics(meshtastic_Telemetry *measurement) override;
|
||||
virtual bool initDevice(TwoWire *bus, ScanI2C::FoundDevice *dev) override;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -16,23 +16,24 @@ meshtastic_Nau7802Config nau7802config = meshtastic_Nau7802Config_init_zero;
|
||||
|
||||
NAU7802Sensor::NAU7802Sensor() : TelemetrySensor(meshtastic_TelemetrySensorType_NAU7802, "NAU7802") {}
|
||||
|
||||
bool NAU7802Sensor::initDevice(TwoWire *bus, ScanI2C::FoundDevice *dev)
|
||||
int32_t NAU7802Sensor::runOnce()
|
||||
{
|
||||
LOG_INFO("Init sensor: %s", sensorName);
|
||||
status = nau7802.begin(*bus);
|
||||
if (!status) {
|
||||
return status;
|
||||
if (!hasSensor()) {
|
||||
return DEFAULT_SENSOR_MINIMUM_WAIT_TIME_BETWEEN_READS;
|
||||
}
|
||||
status = nau7802.begin(*nodeTelemetrySensorsMap[sensorType].second);
|
||||
nau7802.setSampleRate(NAU7802_SPS_320);
|
||||
if (!loadCalibrationData()) {
|
||||
LOG_ERROR("Failed to load calibration data");
|
||||
}
|
||||
nau7802.calibrateAFE();
|
||||
LOG_INFO("Offset: %d, Calibration factor: %.2f", nau7802.getZeroOffset(), nau7802.getCalibrationFactor());
|
||||
initI2CSensor();
|
||||
return status;
|
||||
return initI2CSensor();
|
||||
}
|
||||
|
||||
void NAU7802Sensor::setup() {}
|
||||
|
||||
bool NAU7802Sensor::getMetrics(meshtastic_Telemetry *measurement)
|
||||
{
|
||||
LOG_DEBUG("NAU7802 getMetrics");
|
||||
|
||||
@@ -13,14 +13,15 @@ class NAU7802Sensor : public TelemetrySensor
|
||||
NAU7802 nau7802;
|
||||
|
||||
protected:
|
||||
virtual void setup() override;
|
||||
const char *nau7802ConfigFileName = "/prefs/nau7802.dat";
|
||||
bool saveCalibrationData();
|
||||
bool loadCalibrationData();
|
||||
|
||||
public:
|
||||
NAU7802Sensor();
|
||||
virtual int32_t runOnce() override;
|
||||
virtual bool getMetrics(meshtastic_Telemetry *measurement) override;
|
||||
virtual bool initDevice(TwoWire *bus, ScanI2C::FoundDevice *dev) override;
|
||||
void tare();
|
||||
void calibrate(float weight);
|
||||
AdminMessageHandleResult handleAdminMessage(const meshtastic_MeshPacket &mp, meshtastic_AdminMessage *request,
|
||||
|
||||
@@ -9,15 +9,20 @@
|
||||
|
||||
OPT3001Sensor::OPT3001Sensor() : TelemetrySensor(meshtastic_TelemetrySensorType_OPT3001, "OPT3001") {}
|
||||
|
||||
bool OPT3001Sensor::initDevice(TwoWire *bus, ScanI2C::FoundDevice *dev)
|
||||
int32_t OPT3001Sensor::runOnce()
|
||||
{
|
||||
LOG_INFO("Init sensor: %s", sensorName);
|
||||
auto errorCode = opt3001.begin(dev->address.address);
|
||||
status = errorCode == NO_ERROR;
|
||||
if (!status) {
|
||||
return status;
|
||||
if (!hasSensor()) {
|
||||
return DEFAULT_SENSOR_MINIMUM_WAIT_TIME_BETWEEN_READS;
|
||||
}
|
||||
auto errorCode = opt3001.begin(nodeTelemetrySensorsMap[sensorType].first);
|
||||
status = errorCode == NO_ERROR;
|
||||
|
||||
return initI2CSensor();
|
||||
}
|
||||
|
||||
void OPT3001Sensor::setup()
|
||||
{
|
||||
OPT3001_Config newConfig;
|
||||
|
||||
newConfig.RangeNumber = 0b1100;
|
||||
@@ -29,10 +34,6 @@ bool OPT3001Sensor::initDevice(TwoWire *bus, ScanI2C::FoundDevice *dev)
|
||||
if (errorConfig != NO_ERROR) {
|
||||
LOG_ERROR("OPT3001 configuration error #%d", errorConfig);
|
||||
}
|
||||
status = errorConfig == NO_ERROR;
|
||||
|
||||
initI2CSensor();
|
||||
return status;
|
||||
}
|
||||
|
||||
bool OPT3001Sensor::getMetrics(meshtastic_Telemetry *measurement)
|
||||
|
||||
@@ -12,13 +12,13 @@ class OPT3001Sensor : public TelemetrySensor
|
||||
private:
|
||||
ClosedCube_OPT3001 opt3001;
|
||||
|
||||
protected:
|
||||
virtual void setup() override;
|
||||
|
||||
public:
|
||||
OPT3001Sensor();
|
||||
#if WIRE_INTERFACES_COUNT > 1
|
||||
virtual bool onlyWire1() { return true; }
|
||||
#endif
|
||||
virtual int32_t runOnce() override;
|
||||
virtual bool getMetrics(meshtastic_Telemetry *measurement) override;
|
||||
virtual bool initDevice(TwoWire *bus, ScanI2C::FoundDevice *dev) override;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -9,18 +9,24 @@
|
||||
|
||||
PCT2075Sensor::PCT2075Sensor() : TelemetrySensor(meshtastic_TelemetrySensorType_PCT2075, "PCT2075") {}
|
||||
|
||||
bool PCT2075Sensor::initDevice(TwoWire *bus, ScanI2C::FoundDevice *dev)
|
||||
int32_t PCT2075Sensor::runOnce()
|
||||
{
|
||||
LOG_INFO("Init sensor: %s", sensorName);
|
||||
status = pct2075.begin(dev->address.address, bus);
|
||||
if (!hasSensor()) {
|
||||
return DEFAULT_SENSOR_MINIMUM_WAIT_TIME_BETWEEN_READS;
|
||||
}
|
||||
|
||||
initI2CSensor();
|
||||
return status;
|
||||
status = pct2075.begin(nodeTelemetrySensorsMap[sensorType].first, nodeTelemetrySensorsMap[sensorType].second);
|
||||
|
||||
return initI2CSensor();
|
||||
}
|
||||
|
||||
void PCT2075Sensor::setup() {}
|
||||
|
||||
bool PCT2075Sensor::getMetrics(meshtastic_Telemetry *measurement)
|
||||
{
|
||||
measurement->variant.environment_metrics.has_temperature = true;
|
||||
|
||||
measurement->variant.environment_metrics.temperature = pct2075.getTemperature();
|
||||
|
||||
return true;
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user