Merge branch 'master' into ch341

This commit is contained in:
Jonathan Bennett 2024-11-28 12:05:40 -06:00 committed by GitHub
commit 3f970d2edf
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
313 changed files with 7557 additions and 3745 deletions

View File

@ -51,6 +51,7 @@ runs:
file: build.tar
target: build.tar
token: ${{ inputs.github_token }}
version: tags/v2.5.3
- name: Unpack web ui
if: inputs.include-web-ui == 'true'

View File

@ -7,6 +7,8 @@ on:
required: true
type: string
permissions: read-all
jobs:
build-esp32:
runs-on: ubuntu-latest
@ -24,6 +26,7 @@ jobs:
./arch/esp32/esp32s2.ini
./arch/esp32/esp32s3.ini
./arch/esp32/esp32c3.ini
./arch/esp32/esp32c6.ini
build-script-path: bin/build-esp32.sh
ota-firmware-source: firmware.bin
ota-firmware-target: release/bleota.bin

View File

@ -26,10 +26,12 @@ jobs:
./arch/esp32/esp32s2.ini
./arch/esp32/esp32s3.ini
./arch/esp32/esp32c3.ini
./arch/esp32/esp32c6.ini
build-script-path: bin/build-esp32.sh
ota-firmware-source: firmware-c3.bin
ota-firmware-target: release/bleota-c3.bin
artifact-paths: |
release/*.bin
release/*.elf
include-web-ui: true
arch: esp32c3

View File

@ -33,4 +33,5 @@ jobs:
artifact-paths: |
release/*.bin
release/*.elf
include-web-ui: true
arch: esp32c6

View File

@ -7,6 +7,8 @@ on:
required: true
type: string
permissions: read-all
jobs:
build-esp32-s3:
runs-on: ubuntu-latest
@ -24,6 +26,7 @@ jobs:
./arch/esp32/esp32s2.ini
./arch/esp32/esp32s3.ini
./arch/esp32/esp32c3.ini
./arch/esp32/esp32c6.ini
build-script-path: bin/build-esp32.sh
ota-firmware-source: firmware-s3.bin
ota-firmware-target: release/bleota-s3.bin

View File

@ -13,8 +13,8 @@ jobs:
- name: Install libbluetooth
shell: bash
run: |
apt-get update -y --fix-missing
apt-get install -y libbluetooth-dev libgpiod-dev libyaml-cpp-dev openssl libssl-dev libulfius-dev liborcania-dev
sudo apt-get update -y --fix-missing
sudo apt-get install -y libbluetooth-dev libgpiod-dev libyaml-cpp-dev openssl libssl-dev libulfius-dev liborcania-dev
- name: Checkout code
uses: actions/checkout@v4

View File

@ -13,8 +13,8 @@ jobs:
- name: Install libbluetooth
shell: bash
run: |
apt-get update -y --fix-missing
apt-get install -y libbluetooth-dev libgpiod-dev libyaml-cpp-dev openssl libssl-dev libulfius-dev liborcania-dev
sudo apt-get update -y --fix-missing
sudo apt-get install -y libbluetooth-dev libgpiod-dev libyaml-cpp-dev openssl libssl-dev libulfius-dev liborcania-dev
- name: Checkout code
uses: actions/checkout@v4

View File

@ -203,6 +203,7 @@ jobs:
./device-*.sh
./device-*.bat
./littlefs-*.bin
./littlefswebui-*.bin
./bleota*bin
./Meshtastic_nRF52_factory_erase*.uf2
retention-days: 30
@ -245,7 +246,8 @@ jobs:
if: ${{ github.event_name == 'workflow_dispatch' }}
outputs:
upload_url: ${{ steps.create_release.outputs.upload_url }}
needs: [
needs:
[
gather-artifacts,
package-raspbian,
package-raspbian-armv7l,

View File

@ -50,11 +50,18 @@ jobs:
mkdir -p .debpkg/usr/share/doc/meshtasticd/web
mkdir -p .debpkg/usr/sbin
mkdir -p .debpkg/etc/meshtasticd
mkdir -p .debpkg/etc/meshtasticd/config.d
mkdir -p .debpkg/etc/meshtasticd/available.d
mkdir -p .debpkg/usr/lib/systemd/system/
tar -xf build.tar -C .debpkg/usr/share/doc/meshtasticd/web
gunzip .debpkg/usr/share/doc/meshtasticd/web/*.gz
shopt -s dotglob nullglob
if [ -d .debpkg/usr/share/doc/meshtasticd/web/build ]; then mv .debpkg/usr/share/doc/meshtasticd/web/build/* .debpkg/usr/share/doc/meshtasticd/web/; fi
if [ -d .debpkg/usr/share/doc/meshtasticd/web/build ]; then rmdir .debpkg/usr/share/doc/meshtasticd/web/build; fi
if [ -d .debpkg/usr/share/doc/meshtasticd/web/.DS_Store]; then rm -f .debpkg/usr/share/doc/meshtasticd/web/.DS_Store; fi
gunzip .debpkg/usr/share/doc/meshtasticd/web/ -r
cp release/meshtasticd_linux_x86_64 .debpkg/usr/sbin/meshtasticd
cp bin/config-dist.yaml .debpkg/etc/meshtasticd/config.yaml
cp bin/config.d/* .debpkg/etc/meshtasticd/available.d/
chmod +x .debpkg/usr/sbin/meshtasticd
cp bin/meshtasticd.service .debpkg/usr/lib/systemd/system/meshtasticd.service
echo "/etc/meshtasticd/config.yaml" > .debpkg/DEBIAN/conffiles

View File

@ -50,11 +50,18 @@ jobs:
mkdir -p .debpkg/usr/share/doc/meshtasticd/web
mkdir -p .debpkg/usr/sbin
mkdir -p .debpkg/etc/meshtasticd
mkdir -p .debpkg/etc/meshtasticd/config.d
mkdir -p .debpkg/etc/meshtasticd/available.d
mkdir -p .debpkg/usr/lib/systemd/system/
tar -xf build.tar -C .debpkg/usr/share/doc/meshtasticd/web
gunzip .debpkg/usr/share/doc/meshtasticd/web/*.gz
shopt -s dotglob nullglob
if [ -d .debpkg/usr/share/doc/meshtasticd/web/build ]; then mv .debpkg/usr/share/doc/meshtasticd/web/build/* .debpkg/usr/share/doc/meshtasticd/web/; fi
if [ -d .debpkg/usr/share/doc/meshtasticd/web/build ]; then rmdir .debpkg/usr/share/doc/meshtasticd/web/build; fi
if [ -d .debpkg/usr/share/doc/meshtasticd/web/.DS_Store]; then rm -f .debpkg/usr/share/doc/meshtasticd/web/.DS_Store; fi
gunzip .debpkg/usr/share/doc/meshtasticd/web/ -r
cp release/meshtasticd_linux_aarch64 .debpkg/usr/sbin/meshtasticd
cp bin/config-dist.yaml .debpkg/etc/meshtasticd/config.yaml
cp bin/config.d/* .debpkg/etc/meshtasticd/available.d/
chmod +x .debpkg/usr/sbin/meshtasticd
cp bin/meshtasticd.service .debpkg/usr/lib/systemd/system/meshtasticd.service
echo "/etc/meshtasticd/config.yaml" > .debpkg/DEBIAN/conffiles

View File

@ -50,11 +50,18 @@ jobs:
mkdir -p .debpkg/usr/share/doc/meshtasticd/web
mkdir -p .debpkg/usr/sbin
mkdir -p .debpkg/etc/meshtasticd
mkdir -p .debpkg/etc/meshtasticd/config.d
mkdir -p .debpkg/etc/meshtasticd/available.d
mkdir -p .debpkg/usr/lib/systemd/system/
tar -xf build.tar -C .debpkg/usr/share/doc/meshtasticd/web
gunzip .debpkg/usr/share/doc/meshtasticd/web/*.gz
shopt -s dotglob nullglob
if [ -d .debpkg/usr/share/doc/meshtasticd/web/build ]; then mv .debpkg/usr/share/doc/meshtasticd/web/build/* .debpkg/usr/share/doc/meshtasticd/web/; fi
if [ -d .debpkg/usr/share/doc/meshtasticd/web/build ]; then rmdir .debpkg/usr/share/doc/meshtasticd/web/build; fi
if [ -d .debpkg/usr/share/doc/meshtasticd/web/.DS_Store]; then rm -f .debpkg/usr/share/doc/meshtasticd/web/.DS_Store; fi
gunzip .debpkg/usr/share/doc/meshtasticd/web/ -r
cp release/meshtasticd_linux_armv7l .debpkg/usr/sbin/meshtasticd
cp bin/config-dist.yaml .debpkg/etc/meshtasticd/config.yaml
cp bin/config.d/* .debpkg/etc/meshtasticd/available.d/
chmod +x .debpkg/usr/sbin/meshtasticd
cp bin/meshtasticd.service .debpkg/usr/lib/systemd/system/meshtasticd.service
echo "/etc/meshtasticd/config.yaml" > .debpkg/DEBIAN/conffiles

22
.github/workflows/stale_bot.yml vendored Normal file
View File

@ -0,0 +1,22 @@
name: process stale Issues and PR's
on:
schedule:
- cron: 0 6 * * *
workflow_dispatch: {}
permissions:
issues: write
pull-requests: write
actions: write
jobs:
stale_issues:
name: Close Stale Issues
runs-on: ubuntu-latest
steps:
- name: Stale PR+Issues
uses: actions/stale@v9.0.0
with:
exempt-issue-labels: pinned,3.0
exempt-pr-labels: pinned,3.0

43
.github/workflows/trunk_format_pr.yml vendored Normal file
View File

@ -0,0 +1,43 @@
name: Run Trunk Fmt on PR Comment
on:
issue_comment:
types: [created]
jobs:
trunk-fmt:
if: github.event.issue.pull_request != null && contains(github.event.comment.body, 'trunk fmt')
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
ref: ${{github.event.pull_request.head.ref}}
repository: ${{github.event.pull_request.head.repo.full_name}}
- name: Install trunk
run: curl https://get.trunk.io -fsSL | bash
- name: Run Trunk Fmt
run: trunk fmt
- name: Commit and push changes
run: |
git config --global user.name "github-actions[bot]"
git config --global user.email "github-actions[bot]@users.noreply.github.com"
git add .
git commit -m "Add firmware version ${{ steps.version.outputs.version }}"
git push
- name: Comment on PR
uses: actions/github-script@v7
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
script: |
github.issues.createComment({
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
body: '`trunk fmt` has been run on this PR.'
})

View File

@ -1,34 +1,34 @@
version: 0.1
cli:
version: 1.22.6
version: 1.22.8
plugins:
sources:
- id: trunk
ref: v1.6.3
ref: v1.6.4
uri: https://github.com/trunk-io/plugins
lint:
enabled:
- trufflehog@3.82.6
- trufflehog@3.83.6
- yamllint@1.35.1
- bandit@1.7.10
- checkov@3.2.256
- terrascan@1.19.1
- trivy@0.55.2
- checkov@3.2.287
- terrascan@1.19.9
- trivy@0.56.2
#- trufflehog@3.63.2-rc0
- taplo@0.9.3
- ruff@0.6.8
- ruff@0.7.3
- isort@5.13.2
- markdownlint@0.42.0
- oxipng@9.1.2
- svgo@3.3.2
- actionlint@1.7.3
- actionlint@1.7.4
- flake8@7.1.1
- hadolint@2.12.0
- shfmt@3.6.0
- shellcheck@0.10.0
- black@24.8.0
- black@24.10.0
- git-diff-check
- gitleaks@8.20.0
- gitleaks@8.21.1
- clang-format@16.0.3
- prettier@3.3.3
ignore:

4
CODE_OF_CONDUCT.md Normal file
View File

@ -0,0 +1,4 @@
# Contributor Covenant Code of Conduct
The Meshtastic Firmware project is subject to the code of conduct for the parent project, which can be found here:
https://meshtastic.org/docs/legal/conduct/

View File

@ -31,7 +31,7 @@ build_flags =
-DCONFIG_BT_NIMBLE_ENABLED
-DCONFIG_NIMBLE_CPP_LOG_LEVEL=2
-DCONFIG_BT_NIMBLE_MAX_CCCDS=20
-DCONFIG_BT_NIMBLE_HOST_TASK_STACK_SIZE=5120
-DCONFIG_BT_NIMBLE_HOST_TASK_STACK_SIZE=8192
-DESP_OPENSSL_SUPPRESS_LEGACY_WARNING
-DSERIAL_BUFFER_SIZE=4096
-DLIBPAX_ARDUINO
@ -43,9 +43,10 @@ lib_deps =
${arduino_base.lib_deps}
${networking_base.lib_deps}
${environmental_base.lib_deps}
${radiolib_base.lib_deps}
https://github.com/meshtastic/esp32_https_server.git#23665b3adc080a311dcbb586ed5941b5f94d6ea2
h2zero/NimBLE-Arduino@^1.4.2
https://github.com/dbSuS/libpax.git#7bcd3fcab75037505be9b122ab2b24cc5176b587
https://github.com/dbinfrago/libpax.git#3cdc0371c375676a97967547f4065607d4c53fd1
lewisxhe/XPowersLib@^0.2.6
https://github.com/meshtastic/ESP32_Codec2.git#633326c78ac251c059ab3a8c430fcdf25b41672f
rweather/Crypto@^0.4.0

View File

@ -23,6 +23,7 @@ lib_deps =
${arduino_base.lib_deps}
${networking_base.lib_deps}
${environmental_base.lib_deps}
${radiolib_base.lib_deps}
lewisxhe/XPowersLib@^0.2.6
https://github.com/meshtastic/ESP32_Codec2.git#633326c78ac251c059ab3a8c430fcdf25b41672f
rweather/Crypto@^0.4.0

View File

@ -14,13 +14,18 @@ build_flags =
-Wno-unused-variable
-Isrc/platform/nrf52
-DLFS_NO_ASSERT ; Disable LFS assertions , see https://github.com/meshtastic/firmware/pull/3818
-DMESHTASTIC_EXCLUDE_AUDIO=1
-DMESHTASTIC_EXCLUDE_PAXCOUNTER=1
-DMAX_NUM_NODES=80
build_src_filter =
${arduino_base.build_src_filter} -<platform/esp32/> -<platform/stm32wl> -<nimble/> -<mesh/wifi/> -<mesh/api/> -<mesh/http/> -<modules/esp32> -<platform/rp2xx0> -<mesh/eth/> -<mesh/raspihttp>
lib_deps=
${arduino_base.lib_deps}
${radiolib_base.lib_deps}
rweather/Crypto@^0.4.0
lib_ignore =
BluetoothOTA
BluetoothOTA
lvgl

View File

@ -1,6 +1,6 @@
; The Portduino based sim environment on top of any host OS, all hardware will be simulated
[portduino_base]
platform = https://github.com/meshtastic/platform-native.git#6b3796d697481c8f6e3f4aa5c111bd9979f29e64
platform = https://github.com/meshtastic/platform-native.git#bcd02436cfca91f7d28ad0f7dab977c6aaa781af
framework = arduino
build_src_filter =
@ -23,8 +23,9 @@ build_src_filter =
lib_deps =
${env.lib_deps}
${networking_base.lib_deps}
${radiolib_base.lib_deps}
rweather/Crypto@^0.4.0
lovyan03/LovyanGFX@^1.1.16
https://github.com/lovyan03/LovyanGFX.git#1401c28a47646fe00538d487adcb2eb3c72de805
build_flags =
${arduino_base.build_flags}
@ -32,6 +33,7 @@ build_flags =
-Isrc/platform/portduino
-DRADIOLIB_EEPROM_UNSUPPORTED
-DPORTDUINO_LINUX_HARDWARE
-lstdc++fs
-lbluetooth
-lgpiod
-lyaml-cpp

View File

@ -1,8 +1,8 @@
; Common settings for rp2040 Processor based targets
[rp2040_base]
platform = https://github.com/maxgerhardt/platform-raspberrypi.git#v1.2.0-gcc12
platform = https://github.com/maxgerhardt/platform-raspberrypi.git#19e30129fb1428b823be585c787dcb4ac0d9014c ; For arduino-pico 4.2.1
extends = arduino_base
platform_packages = framework-arduinopico@https://github.com/earlephilhower/arduino-pico.git#4.0.3
platform_packages = framework-arduinopico@https://github.com/earlephilhower/arduino-pico.git#996c3bfab9758f12c07aa20cc6d352e630c16987 ; 4.2.1 with fix for sporadic hangs
board_build.core = earlephilhower
board_build.filesystem_size = 0.5m
@ -22,4 +22,5 @@ lib_ignore =
lib_deps =
${arduino_base.lib_deps}
${environmental_base.lib_deps}
${radiolib_base.lib_deps}
rweather/Crypto

View File

@ -1,8 +1,8 @@
; Common settings for rp2040 Processor based targets
[rp2350_base]
platform = https://github.com/maxgerhardt/platform-raspberrypi.git#9e55f6db5c56b9867c69fe473f388beea4546672
platform = https://github.com/maxgerhardt/platform-raspberrypi.git#19e30129fb1428b823be585c787dcb4ac0d9014c ; For arduino-pico 4.2.1
extends = arduino_base
platform_packages = framework-arduinopico@https://github.com/earlephilhower/arduino-pico.git#a6ab6e1f95bc1428d667d55ea7173c0744acc03c ; 4.0.2+
platform_packages = framework-arduinopico@https://github.com/earlephilhower/arduino-pico.git#96c3bfab9758f12c07aa20cc6d352e630c16987 ; 4.2.1 with fix for sporadic hangs
board_build.core = earlephilhower
board_build.filesystem_size = 0.5m
@ -16,8 +16,10 @@ build_src_filter =
lib_ignore =
BluetoothOTA
lvgl
lib_deps =
${arduino_base.lib_deps}
${environmental_base.lib_deps}
${radiolib_base.lib_deps}
rweather/Crypto

View File

@ -30,8 +30,9 @@ upload_protocol = stlink
lib_deps =
${env.lib_deps}
charlesbaynham/OSFS@^1.2.3
jgromes/RadioLib@7.0.2
https://github.com/caveman99/Crypto.git#f61ae26a53f7a2d0ba5511625b8bf8eff3a35d5e
lib_ignore =
mathertel/OneButton@~2.6.1
mathertel/OneButton@2.6.1
Wire

33
bin/base64_to_hex.py Normal file
View File

@ -0,0 +1,33 @@
import sys
import base64
def base64_to_hex_string(b64_string):
try:
# Decode the Base64 string to raw bytes
decoded_bytes = base64.b64decode(b64_string)
except Exception as e:
raise ValueError(f"Invalid Base64 input: {e}")
# Check if the decoded result is exactly 32 bytes
if len(decoded_bytes) != 32:
raise ValueError("Decoded Base64 input must be exactly 32 bytes.")
# Convert each byte to its hex representation
hex_values = [f"0x{byte:02x}" for byte in decoded_bytes]
# Join the formatted hex values with commas
formatted_output = "{ " + ", ".join(hex_values) + " };"
return formatted_output
if __name__ == "__main__":
# Check if a Base64 string was provided in command line arguments
if len(sys.argv) != 2:
print("Usage: python script.py <base64-string>")
sys.exit(1)
b64_string = sys.argv[1]
try:
formatted_hex = base64_to_hex_string(b64_string)
print(formatted_hex)
except ValueError as e:
print(e)

View File

@ -35,6 +35,11 @@ cp $SRCBIN $OUTDIR/$basename-update.bin
echo "Building Filesystem for ESP32 targets"
pio run --environment $1 -t buildfs
cp .pio/build/$1/littlefs.bin $OUTDIR/littlefswebui-$VERSION.bin
# Remove webserver files from the filesystem and rebuild
ls -l data/static # Diagnostic list of files
rm -rf data/static
pio run --environment $1 -t buildfs
cp .pio/build/$1/littlefs.bin $OUTDIR/littlefs-$VERSION.bin
cp bin/device-install.* $OUTDIR
cp bin/device-update.* $OUTDIR

View File

@ -27,5 +27,4 @@ rm -r $OUTDIR/* || true
platformio pkg update --environment native || platformioFailed
pio run --environment native || platformioFailed
cp .pio/build/native/program "$OUTDIR/meshtasticd_linux_$(uname -m)"
cp bin/device-install.* $OUTDIR
cp bin/device-update.* $OUTDIR
cp bin/native-install.* $OUTDIR

View File

@ -1,15 +1,11 @@
### Many device configs have been moved to /etc/meshtasticd/available.d
### To activate, simply copy or link the appropriate file into /etc/meshtasticd/config.d
### Define your devices here using Broadcom pin numbering
### Uncomment the block that corresponds to your hardware
### Including the "Module:" line!
---
Lora:
# Module: sx1262 # Waveshare SX126X XXXM
# DIO2_AS_RF_SWITCH: true
# CS: 21
# IRQ: 16
# Busy: 20
# Reset: 18
# SX126X_ANT_SW: 6
# Module: sx1262 # Waveshare SX1302 LISTEN ONLY AT THIS TIME!
# CS: 7
@ -20,6 +16,7 @@ Lora:
# CS: 0
# IRQ: 10
# Busy: 11
# DIO2_AS_RF_SWITCH: true
# spidev: spidev0.1
# Module: RF95 # Adafruit RFM9x
@ -84,17 +81,6 @@ I2C:
Display:
### Waveshare 2.8inch RPi LCD
# Panel: ST7789
# CS: 8
# DC: 22 # Data/Command pin
# Backlight: 18
# Width: 240
# Height: 320
# Reset: 27
# Rotate: true
# Invert: true
### Waveshare 1.44inch LCD HAT
# Panel: ST7735S
# CS: 8 #Chip Select
@ -114,6 +100,29 @@ Display:
# Height: 320
# Rotate: true
### SHCHV 3.5 RPi TFT+Touchscreen
# Panel: ILI9486
# spidev: spidev0.0
# BusFrequency: 30000000
# DC: 24
# Reset: 25
# Width: 320
# Height: 480
# OffsetRotate: 2
### TZT 2.0 Inch TFT Display ST7789V 240RGBx320
# Panel: ST7789
# spidev: spidev0.0
# # CS: 8 # can be freely chosen
# BusFrequency: 80000000
# DC: 24 # can be freely chosen
# Width: 320
# Height: 240
# Reset: 25 # can be freely chosen
# Rotate: true
# OffsetRotate: 1
# Invert: true
### You can also specify the spi device for the display to use
# spidev: spidev0.0
@ -128,10 +137,6 @@ Touchscreen:
# IRQ: 24
# I2CAddr: 0x38
# Module: XPT2046 # Waveshare 2.8inch
# CS: 7
# IRQ: 17
### You can also specify the spi device for the touchscreen to use
# spidev: spidev0.0
@ -154,4 +159,5 @@ Webserver:
General:
MaxNodes: 200
MaxMessageQueue: 100
MaxMessageQueue: 100
ConfigDirectory: /etc/meshtasticd/config.d/

View File

@ -0,0 +1,18 @@
Display:
### Waveshare 2.8inch RPi LCD
Panel: ST7789
CS: 8
DC: 22 # Data/Command pin
Backlight: 18
Width: 240
Height: 320
Reset: 27
Rotate: true
Invert: true
Touchscreen:
### Note, at least for now, the touchscreen must have a CS pin defined, even if you let Linux manage the CS switching.
Module: XPT2046 # Waveshare 2.8inch
CS: 7
IRQ: 17

View File

@ -0,0 +1,9 @@
Lora:
Module: sx1262
CS: 21
IRQ: 16
Busy: 20
Reset: 18
TXen: 13
RXen: 12
DIO3_TCXO_VOLTAGE: true

View File

@ -0,0 +1,8 @@
Lora:
Module: sx1262 # Waveshare SX126X XXXM
DIO2_AS_RF_SWITCH: true
CS: 21
IRQ: 16
Busy: 20
Reset: 18
SX126X_ANT_SW: 6

View File

@ -1,16 +1,26 @@
@ECHO OFF
set PYTHON=python
set WEB_APP=0
:: Determine the correct esptool command to use
where esptool >nul 2>&1
if %ERRORLEVEL% EQU 0 (
set "ESPTOOL_CMD=esptool"
) else (
set "ESPTOOL_CMD=%PYTHON% -m esptool"
)
goto GETOPTS
:HELP
echo Usage: %~nx0 [-h] [-p ESPTOOL_PORT] [-P PYTHON] [-f FILENAME^|FILENAME]
echo Usage: %~nx0 [-h] [-p ESPTOOL_PORT] [-P PYTHON] [-f FILENAME^|FILENAME] [--web]
echo Flash image file to device, but first erasing and writing system information
echo.
echo -h Display this help and exit
echo -p ESPTOOL_PORT Set the environment variable for ESPTOOL_PORT. If not set, ESPTOOL iterates all ports (Dangerrous).
echo -P PYTHON Specify alternate python interpreter to use to invoke esptool. (Default: %PYTHON%)
echo -f FILENAME The .bin file to flash. Custom to your device type and region.
echo --web Flash WEB APP.
goto EOF
:GETOPTS
@ -19,37 +29,44 @@ if /I "%1"=="--help" goto HELP
if /I "%1"=="-F" set "FILENAME=%2" & SHIFT
if /I "%1"=="-p" set ESPTOOL_PORT=%2 & SHIFT
if /I "%1"=="-P" set PYTHON=%2 & SHIFT
if /I "%1"=="--web" set WEB_APP=1 & SHIFT
SHIFT
IF NOT "__%1__"=="____" goto GETOPTS
IF "__%FILENAME%__" == "____" (
echo "Missing FILENAME"
goto HELP
goto HELP
)
IF EXIST %FILENAME% IF x%FILENAME:update=%==x%FILENAME% (
echo Trying to flash update %FILENAME%, but first erasing and writing system information"
%PYTHON% -m esptool --baud 115200 erase_flash
%PYTHON% -m esptool --baud 115200 write_flash 0x00 %FILENAME%
%ESPTOOL_CMD% --baud 115200 erase_flash
%ESPTOOL_CMD% --baud 115200 write_flash 0x00 %FILENAME%
@REM Account for S3 and C3 board's different OTA partition
IF x%FILENAME:s3=%==x%FILENAME% IF x%FILENAME:v3=%==x%FILENAME% IF x%FILENAME:t-deck=%==x%FILENAME% IF x%FILENAME:wireless-paper=%==x%FILENAME% IF x%FILENAME:wireless-tracker=%==x%FILENAME% IF x%FILENAME:station-g2=%==x%FILENAME% IF x%FILENAME:unphone=%==x%FILENAME% (
IF x%FILENAME:esp32c3=%==x%FILENAME% (
%PYTHON% -m esptool --baud 115200 write_flash 0x260000 bleota.bin
%ESPTOOL_CMD% --baud 115200 write_flash 0x260000 bleota.bin
) else (
%PYTHON% -m esptool --baud 115200 write_flash 0x260000 bleota-c3.bin
%ESPTOOL_CMD% --baud 115200 write_flash 0x260000 bleota-c3.bin
)
) else (
%PYTHON% -m esptool --baud 115200 write_flash 0x260000 bleota-s3.bin
) else (
%ESPTOOL_CMD% --baud 115200 write_flash 0x260000 bleota-s3.bin
)
for %%f in (littlefs-*.bin) do (
%PYTHON% -m esptool --baud 115200 write_flash 0x300000 %%f
IF %WEB_APP%==1 (
for %%f in (littlefswebui-*.bin) do (
%ESPTOOL_CMD% --baud 115200 write_flash 0x300000 %%f
)
) else (
for %%f in (littlefs-*.bin) do (
%ESPTOOL_CMD% --baud 115200 write_flash 0x300000 %%f
)
)
) else (
echo "Invalid file: %FILENAME%"
goto HELP
goto HELP
) else (
echo "Invalid file: %FILENAME%"
goto HELP
goto HELP
)
:EOF

View File

@ -1,22 +1,45 @@
#!/bin/sh
PYTHON=${PYTHON:-$(which python3 python | head -n 1)}
WEB_APP=false
# Determine the correct esptool command to use
if "$PYTHON" -m esptool version >/dev/null 2>&1; then
ESPTOOL_CMD="$PYTHON -m esptool"
elif command -v esptool >/dev/null 2>&1; then
ESPTOOL_CMD="esptool"
elif command -v esptool.py >/dev/null 2>&1; then
ESPTOOL_CMD="esptool.py"
else
echo "Error: esptool not found"
exit 1
fi
set -e
# Usage info
show_help() {
cat <<EOF
Usage: $(basename $0) [-h] [-p ESPTOOL_PORT] [-P PYTHON] [-f FILENAME|FILENAME]
Usage: $(basename $0) [-h] [-p ESPTOOL_PORT] [-P PYTHON] [-f FILENAME|FILENAME] [--web]
Flash image file to device, but first erasing and writing system information"
-h Display this help and exit
-p ESPTOOL_PORT Set the environment variable for ESPTOOL_PORT. If not set, ESPTOOL iterates all ports (Dangerous).
-P PYTHON Specify alternate python interpreter to use to invoke esptool. (Default: "$PYTHON")
-f FILENAME The .bin file to flash. Custom to your device type and region.
--web Flash WEB APP.
EOF
}
# Preprocess long options like --web
for arg in "$@"; do
case "$arg" in
--web)
WEB_APP=true
shift # Remove this argument from the list
;;
esac
done
while getopts ":hp:P:f:" opt; do
case "${opt}" in
@ -49,19 +72,23 @@ shift "$((OPTIND - 1))"
if [ -f "${FILENAME}" ] && [ -n "${FILENAME##*"update"*}" ]; then
echo "Trying to flash ${FILENAME}, but first erasing and writing system information"
"$PYTHON" -m esptool erase_flash
"$PYTHON" -m esptool write_flash 0x00 ${FILENAME}
$ESPTOOL_CMD erase_flash
$ESPTOOL_CMD write_flash 0x00 ${FILENAME}
# Account for S3 board's different OTA partition
if [ -n "${FILENAME##*"s3"*}" ] && [ -n "${FILENAME##*"-v3"*}" ] && [ -n "${FILENAME##*"t-deck"*}" ] && [ -n "${FILENAME##*"wireless-paper"*}" ] && [ -n "${FILENAME##*"wireless-tracker"*}" ] && [ -n "${FILENAME##*"station-g2"*}" ] && [ -n "${FILENAME##*"unphone"*}" ]; then
if [ -n "${FILENAME##*"esp32c3"*}" ]; then
"$PYTHON" -m esptool write_flash 0x260000 bleota.bin
$ESPTOOL_CMD write_flash 0x260000 bleota.bin
else
"$PYTHON" -m esptool write_flash 0x260000 bleota-c3.bin
$ESPTOOL_CMD write_flash 0x260000 bleota-c3.bin
fi
else
"$PYTHON" -m esptool write_flash 0x260000 bleota-s3.bin
$ESPTOOL_CMD write_flash 0x260000 bleota-s3.bin
fi
if [ "$WEB_APP" = true ]; then
$ESPTOOL_CMD write_flash 0x300000 littlefswebui-*.bin
else
$ESPTOOL_CMD write_flash 0x300000 littlefs-*.bin
fi
"$PYTHON" -m esptool write_flash 0x300000 littlefs-*.bin
else
show_help

View File

@ -2,6 +2,14 @@
set PYTHON=python
:: Determine the correct esptool command to use
where esptool >nul 2>&1
if %ERRORLEVEL% EQU 0 (
set "ESPTOOL_CMD=esptool"
) else (
set "ESPTOOL_CMD=%PYTHON% -m esptool"
)
goto GETOPTS
:HELP
echo Usage: %~nx0 [-h] [-p ESPTOOL_PORT] [-P PYTHON] [-f FILENAME^|FILENAME]
@ -24,17 +32,17 @@ IF NOT "__%1__"=="____" goto GETOPTS
IF "__%FILENAME%__" == "____" (
echo "Missing FILENAME"
goto HELP
goto HELP
)
IF EXIST %FILENAME% IF NOT x%FILENAME:update=%==x%FILENAME% (
echo Trying to flash update %FILENAME%
%PYTHON% -m esptool --baud 115200 write_flash 0x10000 %FILENAME%
%ESPTOOL_CMD% --baud 115200 write_flash 0x10000 %FILENAME%
) else (
echo "Invalid file: %FILENAME%"
goto HELP
goto HELP
) else (
echo "Invalid file: %FILENAME%"
goto HELP
goto HELP
)
:EOF

View File

@ -2,6 +2,18 @@
PYTHON=${PYTHON:-$(which python3 python|head -n 1)}
# Determine the correct esptool command to use
if "$PYTHON" -m esptool version >/dev/null 2>&1; then
ESPTOOL_CMD="$PYTHON -m esptool"
elif command -v esptool >/dev/null 2>&1; then
ESPTOOL_CMD="esptool"
elif command -v esptool.py >/dev/null 2>&1; then
ESPTOOL_CMD="esptool.py"
else
echo "Error: esptool not found"
exit 1
fi
# Usage info
show_help() {
cat << EOF
@ -9,7 +21,7 @@ Usage: $(basename $0) [-h] [-p ESPTOOL_PORT] [-P PYTHON] [-f FILENAME|FILENAME]
Flash image file to device, leave existing system intact."
-h Display this help and exit
-p ESPTOOL_PORT Set the environment variable for ESPTOOL_PORT. If not set, ESPTOOL iterates all ports (Dangerrous).
-p ESPTOOL_PORT Set the environment variable for ESPTOOL_PORT. If not set, ESPTOOL iterates all ports (Dangerous).
-P PYTHON Specify alternate python interpreter to use to invoke esptool. (Default: "$PYTHON")
-f FILENAME The *update.bin file to flash. Custom to your device type.
@ -30,7 +42,7 @@ while getopts ":hp:P:f:" opt; do
f) FILENAME=${OPTARG}
;;
*)
echo "Invalid flag."
echo "Invalid flag."
show_help >&2
exit 1
;;
@ -45,7 +57,7 @@ shift "$((OPTIND-1))"
if [ -f "${FILENAME}" ] && [ -z "${FILENAME##*"update"*}" ]; then
printf "Trying to flash update ${FILENAME}"
$PYTHON -m esptool --baud 115200 write_flash 0x10000 ${FILENAME}
$ESPTOOL_CMD --baud 115200 write_flash 0x10000 ${FILENAME}
else
show_help
echo "Invalid file: ${FILENAME}"

View File

@ -1,12 +1,16 @@
[Unit]
Description=Meshtastic Native Daemon
After=network-online.target
StartLimitInterval=200
StartLimitBurst=5
[Service]
User=root
Group=root
Type=simple
ExecStart=/usr/sbin/meshtasticd
Restart=always
RestartSec=3
[Install]
WantedBy=multi-user.target
WantedBy=multi-user.target

View File

@ -1,7 +1,7 @@
#!/usr/bin/env bash
cp "release/meshtasticd_linux_$(uname -m)" /usr/sbin/meshtasticd
mkdir /etc/meshtasticd
mkdir -p /etc/meshtasticd
if [[ -f "/etc/meshtasticd/config.yaml" ]]; then
cp bin/config-dist.yaml /etc/meshtasticd/config-upgrade.yaml
else

View File

@ -88,12 +88,13 @@ Import("projenv")
prefsLoc = projenv["PROJECT_DIR"] + "/version.properties"
verObj = readProps(prefsLoc)
print("Using meshtastic platformio-custom.py, firmware version " + verObj["long"])
print("Using meshtastic platformio-custom.py, firmware version " + verObj["long"] + " on " + env.get("PIOENV"))
# General options that are passed to the C and C++ compilers
projenv.Append(
CCFLAGS=[
"-DAPP_VERSION=" + verObj["long"],
"-DAPP_VERSION_SHORT=" + verObj["short"],
"-DAPP_ENV=" + env.get("PIOENV"),
]
)

View File

@ -28,6 +28,8 @@
"flash_size": "8MB",
"maximum_ram_size": 327680,
"maximum_size": 8388608,
"use_1200bps_touch": true,
"wait_for_upload_port": true,
"require_upload_port": true,
"speed": 921600
},

41
boards/icarus.json Normal file
View File

@ -0,0 +1,41 @@
{
"build": {
"arduino": {
"ldscript": "esp32s3_out.ld",
"memory_type": "qio_opi"
},
"core": "esp32",
"extra_flags": [
"-DBOARD_HAS_PSRAM",
"-DARDUINO_USB_CDC_ON_BOOT=1",
"-DARDUINO_USB_MODE=0",
"-DARDUINO_RUNNING_CORE=1",
"-DARDUINO_EVENT_RUNNING_CORE=0"
],
"f_cpu": "240000000L",
"f_flash": "80000000L",
"flash_mode": "qio",
"hwids": [["0x2886", "0x0059"]],
"mcu": "esp32s3",
"variant": "icarus"
},
"connectivity": ["wifi", "bluetooth", "lora"],
"debug": {
"default_tool": "esp-builtin",
"onboard_tools": ["esp-builtin"],
"openocd_target": "esp32s3.cfg"
},
"frameworks": ["arduino", "espidf"],
"name": "icarus",
"upload": {
"flash_size": "8MB",
"maximum_ram_size": 8388608,
"maximum_size": 8388608,
"use_1200bps_touch": true,
"wait_for_upload_port": true,
"require_upload_port": true,
"speed": 921600
},
"url": "https://icarus.azlan.works",
"vendor": "Muhammad Shah"
}

46
boards/unphone.json Normal file
View File

@ -0,0 +1,46 @@
{
"build": {
"arduino": {
"ldscript": "esp32s3_out.ld",
"memory_type": "qio_opi",
"partitions": "default_8MB.csv"
},
"core": "esp32",
"extra_flags": [
"-DBOARD_HAS_PSRAM",
"-DUNPHONE_SPIN=9",
"-DARDUINO_USB_CDC_ON_BOOT=1",
"-DARDUINO_USB_MODE=0",
"-DARDUINO_RUNNING_CORE=1",
"-DARDUINO_EVENT_RUNNING_CORE=1"
],
"f_cpu": "240000000L",
"f_flash": "80000000L",
"flash_mode": "qio",
"hwids": [
["0x16D0", "0x1178"],
["0x303a", "0x1001"]
],
"mcu": "esp32s3",
"variant": "unphone"
},
"connectivity": ["wifi", "bluetooth", "lora"],
"debug": {
"default_tool": "esp-builtin",
"onboard_tools": ["esp-builtin"],
"openocd_target": "esp32s3.cfg"
},
"frameworks": ["arduino", "espidf"],
"name": "unPhone",
"upload": {
"flash_size": "8MB",
"maximum_ram_size": 327680,
"maximum_size": 8323072,
"use_1200bps_touch": true,
"wait_for_upload_port": true,
"require_upload_port": true,
"speed": 921600
},
"url": "https://unphone.net/",
"vendor": "University of Sheffield"
}

View File

@ -29,138 +29,134 @@ default_envs = tbeam
;default_envs = rak4631
;default_envs = rak4631_eth_gw
;default_envs = rak2560
;default_envs = rak10701
;default_envs = rak_wismeshtap
;default_envs = wio-e5
;default_envs = radiomaster_900_bandit_nano
;default_envs = radiomaster_900_bandit_micro
;default_envs = radiomaster_900_bandit
;default_envs = heltec_capsule_sensor_v3
;default_envs = heltec_vision_master_t190
;default_envs = heltec_vision_master_e213
;default_envs = heltec_vision_master_e290
;default_envs = heltec_mesh_node_t114
extra_configs =
arch/*/*.ini
variants/*/platformio.ini
arch/*/*.ini
variants/*/platformio.ini
description = Meshtastic
[env]
test_build_src = true
extra_scripts = bin/platformio-custom.py
; note: we add src to our include search path so that lmic_project_config can override
; note: TINYGPS_OPTION_NO_CUSTOM_FIELDS is VERY important. We don't use custom fields and somewhere in that pile
; of code is a heap corruption bug!
; FIXME: fix lib/BluetoothOTA dependency back on src/ so we can remove -Isrc
; The Radiolib stuff will speed up building considerably. Exclud all the stuff we dont need.
build_flags = -Wno-missing-field-initializers
-Wno-format
-Isrc -Isrc/mesh -Isrc/mesh/generated -Isrc/gps -Isrc/buzz -Wl,-Map,.pio/build/output.map
-DUSE_THREAD_NAMES
-DTINYGPS_OPTION_NO_CUSTOM_FIELDS
-DPB_ENABLE_MALLOC=1
-DRADIOLIB_EXCLUDE_CC1101=1
-DRADIOLIB_EXCLUDE_NRF24=1
-DRADIOLIB_EXCLUDE_RF69=1
-DRADIOLIB_EXCLUDE_SX1231=1
-DRADIOLIB_EXCLUDE_SX1233=1
-DRADIOLIB_EXCLUDE_SI443X=1
-DRADIOLIB_EXCLUDE_RFM2X=1
-DRADIOLIB_EXCLUDE_AFSK=1
-DRADIOLIB_EXCLUDE_BELL=1
-DRADIOLIB_EXCLUDE_HELLSCHREIBER=1
-DRADIOLIB_EXCLUDE_MORSE=1
-DRADIOLIB_EXCLUDE_RTTY=1
-DRADIOLIB_EXCLUDE_SSTV=1
-DRADIOLIB_EXCLUDE_AX25=1
-DRADIOLIB_EXCLUDE_DIRECT_RECEIVE=1
-DRADIOLIB_EXCLUDE_BELL=1
-DRADIOLIB_EXCLUDE_PAGER=1
-DRADIOLIB_EXCLUDE_FSK4=1
-DRADIOLIB_EXCLUDE_APRS=1
-DRADIOLIB_EXCLUDE_LORAWAN=1
-DMESHTASTIC_EXCLUDE_DROPZONE=1
-DMESHTASTIC_EXCLUDE_REMOTEHARDWARE=1
#-DBUILD_EPOCH=$UNIX_TIME
;-D OLED_PL
-Wno-format
-Isrc -Isrc/mesh -Isrc/mesh/generated -Isrc/gps -Isrc/buzz -Wl,-Map,.pio/build/output.map
-DUSE_THREAD_NAMES
-DTINYGPS_OPTION_NO_CUSTOM_FIELDS
-DPB_ENABLE_MALLOC=1
-DRADIOLIB_EXCLUDE_CC1101=1
-DRADIOLIB_EXCLUDE_NRF24=1
-DRADIOLIB_EXCLUDE_RF69=1
-DRADIOLIB_EXCLUDE_SX1231=1
-DRADIOLIB_EXCLUDE_SX1233=1
-DRADIOLIB_EXCLUDE_SI443X=1
-DRADIOLIB_EXCLUDE_RFM2X=1
-DRADIOLIB_EXCLUDE_AFSK=1
-DRADIOLIB_EXCLUDE_BELL=1
-DRADIOLIB_EXCLUDE_HELLSCHREIBER=1
-DRADIOLIB_EXCLUDE_MORSE=1
-DRADIOLIB_EXCLUDE_RTTY=1
-DRADIOLIB_EXCLUDE_SSTV=1
-DRADIOLIB_EXCLUDE_AX25=1
-DRADIOLIB_EXCLUDE_DIRECT_RECEIVE=1
-DRADIOLIB_EXCLUDE_BELL=1
-DRADIOLIB_EXCLUDE_PAGER=1
-DRADIOLIB_EXCLUDE_FSK4=1
-DRADIOLIB_EXCLUDE_APRS=1
-DRADIOLIB_EXCLUDE_LORAWAN=1
-DMESHTASTIC_EXCLUDE_DROPZONE=1
-DMESHTASTIC_EXCLUDE_REMOTEHARDWARE=1
-DMESHTASTIC_EXCLUDE_POWERSTRESS=1 ; exclude power stress test module from main firmware
#-DBUILD_EPOCH=$UNIX_TIME
;-D OLED_PL
monitor_speed = 115200
monitor_filters = direct
lib_deps =
jgromes/RadioLib@~7.0.2
https://github.com/meshtastic/esp8266-oled-ssd1306.git#e16cee124fe26490cb14880c679321ad8ac89c95 ; ESP8266_SSD1306
mathertel/OneButton@~2.6.1 ; OneButton library for non-blocking button debounce
https://github.com/meshtastic/arduino-fsm.git#7db3702bf0cfe97b783d6c72595e3f38e0b19159
https://github.com/meshtastic/TinyGPSPlus.git#71a82db35f3b973440044c476d4bcdc673b104f4
https://github.com/meshtastic/ArduinoThread.git#1ae8778c85d0a2a729f989e0b1e7d7c4dc84eef0
nanopb/Nanopb@^0.4.9
erriez/ErriezCRC32@^1.0.1
https://github.com/meshtastic/esp8266-oled-ssd1306.git#e16cee124fe26490cb14880c679321ad8ac89c95
mathertel/OneButton@2.6.1
https://github.com/meshtastic/arduino-fsm.git#7db3702bf0cfe97b783d6c72595e3f38e0b19159
https://github.com/meshtastic/TinyGPSPlus.git#71a82db35f3b973440044c476d4bcdc673b104f4
https://github.com/meshtastic/ArduinoThread.git#1ae8778c85d0a2a729f989e0b1e7d7c4dc84eef0
nanopb/Nanopb@0.4.9
erriez/ErriezCRC32@1.0.1
; Used for the code analysis in PIO Home / Inspect
check_tool = cppcheck
check_skip_packages = yes
check_flags =
-DAPP_VERSION=1.0.0
--suppressions-list=suppressions.txt
--inline-suppr
-DAPP_VERSION=1.0.0
--suppressions-list=suppressions.txt
--inline-suppr
; Common settings for conventional (non Portduino) Arduino targets
[arduino_base]
framework = arduino
lib_deps =
${env.lib_deps}
end2endzone/NonBlockingRTTTL@^1.3.0
https://github.com/meshtastic/SparkFun_ATECCX08a_Arduino_Library.git#5cf62b36c6f30bc72a07bdb2c11fc9a22d1e31da
${env.lib_deps}
end2endzone/NonBlockingRTTTL@1.3.0
build_flags = ${env.build_flags} -Os
build_src_filter = ${env.build_src_filter} -<platform/portduino/>
; Common libs for communicating over TCP/IP networks such as MQTT
[networking_base]
lib_deps =
knolleary/PubSubClient@^2.8
arduino-libraries/NTPClient@^3.1.0
arcao/Syslog@^2.0.0
knolleary/PubSubClient@2.8
arduino-libraries/NTPClient@3.1.0
arcao/Syslog@2.0.0
[radiolib_base]
lib_deps =
jgromes/RadioLib@7.1.0
; Common libs for environmental measurements in telemetry module
; (not included in native / portduino)
[environmental_base]
lib_deps =
adafruit/Adafruit BusIO@^1.16.1
adafruit/Adafruit Unified Sensor@^1.1.11
adafruit/Adafruit BMP280 Library@^2.6.8
adafruit/Adafruit BMP085 Library@^1.2.4
adafruit/Adafruit BME280 Library@^2.2.2
adafruit/Adafruit BMP3XX Library@^2.1.5
adafruit/Adafruit MCP9808 Library@^2.0.0
adafruit/Adafruit INA260 Library@^1.5.0
adafruit/Adafruit INA219@^1.2.0
adafruit/Adafruit MAX1704X@^1.0.3
adafruit/Adafruit SHTC3 Library@^1.0.0
adafruit/Adafruit LPS2X@^2.0.4
adafruit/Adafruit SHT31 Library@^2.2.2
adafruit/Adafruit PM25 AQI Sensor@^1.1.1
adafruit/Adafruit MPU6050@^2.2.4
adafruit/Adafruit LIS3DH@^1.3.0
adafruit/Adafruit AHTX0@^2.0.5
adafruit/Adafruit LSM6DS@^4.7.2
adafruit/Adafruit VEML7700 Library@^2.1.6
adafruit/Adafruit SHT4x Library@^1.0.4
adafruit/Adafruit TSL2591 Library@^1.4.5
sparkfun/SparkFun Qwiic Scale NAU7802 Arduino Library@^1.0.5
sparkfun/SparkFun 9DoF IMU Breakout - ICM 20948 - Arduino Library@^1.2.13
ClosedCube OPT3001@^1.1.2
emotibit/EmotiBit MLX90632@^1.0.8
dfrobot/DFRobot_RTU@^1.0.3
sparkfun/SparkFun MAX3010x Pulse and Proximity Sensor Library@^1.1.2
adafruit/Adafruit MLX90614 Library@^2.1.5
https://github.com/boschsensortec/Bosch-BSEC2-Library#v1.7.2502
boschsensortec/BME68x Sensor Library@^1.1.40407
https://github.com/KodinLanewave/INA3221@^1.0.1
lewisxhe/SensorLib@0.2.0
mprograms/QMC5883LCompass@^1.2.0
https://github.com/meshtastic/DFRobot_LarkWeatherStation#4de3a9cadef0f6a5220a8a906cf9775b02b0040d
https://github.com/gjelsoe/STK8xxx-Accelerometer.git#v0.1.1
adafruit/Adafruit BusIO@1.16.2
adafruit/Adafruit Unified Sensor@1.1.14
adafruit/Adafruit BMP280 Library@2.6.8
adafruit/Adafruit BMP085 Library@1.2.4
adafruit/Adafruit BME280 Library@2.2.4
adafruit/Adafruit BMP3XX Library@2.1.5
adafruit/Adafruit MCP9808 Library@2.0.2
adafruit/Adafruit INA260 Library@1.5.2
adafruit/Adafruit INA219@1.2.3
adafruit/Adafruit MAX1704X@1.0.3
adafruit/Adafruit SHTC3 Library@1.0.1
adafruit/Adafruit LPS2X@2.0.6
adafruit/Adafruit SHT31 Library@2.2.2
adafruit/Adafruit PM25 AQI Sensor@1.1.1
adafruit/Adafruit MPU6050@2.2.6
adafruit/Adafruit LIS3DH@1.3.0
adafruit/Adafruit AHTX0@2.0.5
adafruit/Adafruit LSM6DS@4.7.3
adafruit/Adafruit VEML7700 Library@2.1.6
adafruit/Adafruit SHT4x Library@1.0.5
adafruit/Adafruit TSL2591 Library@1.4.5
sparkfun/SparkFun Qwiic Scale NAU7802 Arduino Library@1.0.6
sparkfun/SparkFun 9DoF IMU Breakout - ICM 20948 - Arduino Library@1.2.13
ClosedCube OPT3001@1.1.2
emotibit/EmotiBit MLX90632@1.0.8
sparkfun/SparkFun MAX3010x Pulse and Proximity Sensor Library@1.1.2
adafruit/Adafruit MLX90614 Library@2.1.5
https://github.com/boschsensortec/Bosch-BSEC2-Library#v1.7.2502
boschsensortec/BME68x Sensor Library@1.1.40407
https://github.com/KodinLanewave/INA3221@1.0.1
mprograms/QMC5883LCompass@1.2.3
dfrobot/DFRobot_RTU@1.0.3
https://github.com/meshtastic/DFRobot_LarkWeatherStation#4de3a9cadef0f6a5220a8a906cf9775b02b0040d

@ -1 +1 @@
Subproject commit 49ebc4783275f108a9f8723ca52a6edf0a954c55
Subproject commit 02e6576efaa2f691be9504b8c1c6261703f7a277

View File

@ -1 +0,0 @@
curfirmwareversion.xml

View File

@ -21,7 +21,7 @@ namespace concurrency
class AmbientLightingThread : public concurrency::OSThread
{
public:
explicit AmbientLightingThread(ScanI2C::DeviceType type) : OSThread("AmbientLightingThread")
explicit AmbientLightingThread(ScanI2C::DeviceType type) : OSThread("AmbientLighting")
{
notifyDeepSleepObserver.observe(&notifyDeepSleep); // Let us know when shutdown() is issued.
@ -42,18 +42,18 @@ class AmbientLightingThread : public concurrency::OSThread
#ifdef HAS_NCP5623
_type = type;
if (_type == ScanI2C::DeviceType::NONE) {
LOG_DEBUG("AmbientLightingThread disabling due to no RGB leds found on I2C bus\n");
LOG_DEBUG("AmbientLighting Disable due to no RGB leds found on I2C bus");
disable();
return;
}
#endif
#if defined(HAS_NCP5623) || defined(RGBLED_RED) || defined(HAS_NEOPIXEL) || defined(UNPHONE)
if (!moduleConfig.ambient_lighting.led_state) {
LOG_DEBUG("AmbientLightingThread disabling due to moduleConfig.ambient_lighting.led_state OFF\n");
LOG_DEBUG("AmbientLighting Disable due to moduleConfig.ambient_lighting.led_state OFF");
disable();
return;
}
LOG_DEBUG("AmbientLightingThread initializing\n");
LOG_DEBUG("AmbientLighting init");
#ifdef HAS_NCP5623
if (_type == ScanI2C::NCP5623) {
rgb.begin();
@ -106,27 +106,27 @@ class AmbientLightingThread : public concurrency::OSThread
rgb.setRed(0);
rgb.setGreen(0);
rgb.setBlue(0);
LOG_INFO("Turn Off NCP5623 Ambient lighting.\n");
LOG_INFO("OFF: NCP5623 Ambient lighting");
#endif
#ifdef HAS_NEOPIXEL
pixels.clear();
pixels.show();
LOG_INFO("Turn Off NeoPixel Ambient lighting.\n");
LOG_INFO("OFF: NeoPixel Ambient lighting");
#endif
#ifdef RGBLED_CA
analogWrite(RGBLED_RED, 255 - 0);
analogWrite(RGBLED_GREEN, 255 - 0);
analogWrite(RGBLED_BLUE, 255 - 0);
LOG_INFO("Turn Off Ambient lighting RGB Common Anode.\n");
LOG_INFO("OFF: Ambient light RGB Common Anode");
#elif defined(RGBLED_RED)
analogWrite(RGBLED_RED, 0);
analogWrite(RGBLED_GREEN, 0);
analogWrite(RGBLED_BLUE, 0);
LOG_INFO("Turn Off Ambient lighting RGB Common Cathode.\n");
LOG_INFO("OFF: Ambient light RGB Common Cathode");
#endif
#ifdef UNPHONE
unphone.rgb(0, 0, 0);
LOG_INFO("Turn Off unPhone Ambient lighting.\n");
LOG_INFO("OFF: unPhone Ambient lighting");
#endif
return 0;
}
@ -138,9 +138,8 @@ class AmbientLightingThread : public concurrency::OSThread
rgb.setRed(moduleConfig.ambient_lighting.red);
rgb.setGreen(moduleConfig.ambient_lighting.green);
rgb.setBlue(moduleConfig.ambient_lighting.blue);
LOG_DEBUG("Initializing NCP5623 Ambient lighting w/ current=%d, red=%d, green=%d, blue=%d\n",
moduleConfig.ambient_lighting.current, moduleConfig.ambient_lighting.red, moduleConfig.ambient_lighting.green,
moduleConfig.ambient_lighting.blue);
LOG_DEBUG("Init NCP5623 Ambient light w/ current=%d, red=%d, green=%d, blue=%d", moduleConfig.ambient_lighting.current,
moduleConfig.ambient_lighting.red, moduleConfig.ambient_lighting.green, moduleConfig.ambient_lighting.blue);
#endif
#ifdef HAS_NEOPIXEL
pixels.fill(pixels.Color(moduleConfig.ambient_lighting.red, moduleConfig.ambient_lighting.green,
@ -158,7 +157,7 @@ class AmbientLightingThread : public concurrency::OSThread
#endif
#endif
pixels.show();
LOG_DEBUG("Initializing NeoPixel Ambient lighting w/ brightness(current)=%d, red=%d, green=%d, blue=%d\n",
LOG_DEBUG("Init NeoPixel Ambient light w/ brightness(current)=%d, red=%d, green=%d, blue=%d",
moduleConfig.ambient_lighting.current, moduleConfig.ambient_lighting.red, moduleConfig.ambient_lighting.green,
moduleConfig.ambient_lighting.blue);
#endif
@ -166,21 +165,21 @@ class AmbientLightingThread : public concurrency::OSThread
analogWrite(RGBLED_RED, 255 - moduleConfig.ambient_lighting.red);
analogWrite(RGBLED_GREEN, 255 - moduleConfig.ambient_lighting.green);
analogWrite(RGBLED_BLUE, 255 - moduleConfig.ambient_lighting.blue);
LOG_DEBUG("Initializing Ambient lighting RGB Common Anode w/ red=%d, green=%d, blue=%d\n",
moduleConfig.ambient_lighting.red, moduleConfig.ambient_lighting.green, moduleConfig.ambient_lighting.blue);
LOG_DEBUG("Init Ambient light RGB Common Anode w/ red=%d, green=%d, blue=%d", moduleConfig.ambient_lighting.red,
moduleConfig.ambient_lighting.green, moduleConfig.ambient_lighting.blue);
#elif defined(RGBLED_RED)
analogWrite(RGBLED_RED, moduleConfig.ambient_lighting.red);
analogWrite(RGBLED_GREEN, moduleConfig.ambient_lighting.green);
analogWrite(RGBLED_BLUE, moduleConfig.ambient_lighting.blue);
LOG_DEBUG("Initializing Ambient lighting RGB Common Cathode w/ red=%d, green=%d, blue=%d\n",
moduleConfig.ambient_lighting.red, moduleConfig.ambient_lighting.green, moduleConfig.ambient_lighting.blue);
LOG_DEBUG("Init Ambient light RGB Common Cathode w/ red=%d, green=%d, blue=%d", moduleConfig.ambient_lighting.red,
moduleConfig.ambient_lighting.green, moduleConfig.ambient_lighting.blue);
#endif
#ifdef UNPHONE
unphone.rgb(moduleConfig.ambient_lighting.red, moduleConfig.ambient_lighting.green, moduleConfig.ambient_lighting.blue);
LOG_DEBUG("Initializing unPhone Ambient lighting w/ red=%d, green=%d, blue=%d\n", moduleConfig.ambient_lighting.red,
LOG_DEBUG("Init unPhone Ambient light w/ red=%d, green=%d, blue=%d", moduleConfig.ambient_lighting.red,
moduleConfig.ambient_lighting.green, moduleConfig.ambient_lighting.blue);
#endif
}
};
} // namespace concurrency
} // namespace concurrency

View File

@ -16,7 +16,7 @@
class AudioThread : public concurrency::OSThread
{
public:
AudioThread() : OSThread("AudioThread") { initOutput(); }
AudioThread() : OSThread("Audio") { initOutput(); }
void beginRttl(const void *data, uint32_t len)
{
@ -64,7 +64,7 @@ class AudioThread : public concurrency::OSThread
void initOutput()
{
audioOut = new AudioOutputI2S(1, AudioOutputI2S::EXTERNAL_I2S);
audioOut->SetPinout(DAC_I2S_BCK, DAC_I2S_WS, DAC_I2S_DOUT);
audioOut->SetPinout(DAC_I2S_BCK, DAC_I2S_WS, DAC_I2S_DOUT, DAC_I2S_MCLK);
audioOut->SetGain(0.2);
};

View File

@ -1,4 +1,5 @@
#include "ButtonThread.h"
#include "../userPrefs.h"
#include "configuration.h"
#if !MESHTASTIC_EXCLUDE_GPS
#include "GPS.h"
@ -26,20 +27,25 @@ using namespace concurrency;
ButtonThread *buttonThread; // Declared extern in header
volatile ButtonThread::ButtonEventType ButtonThread::btnEvent = ButtonThread::BUTTON_EVENT_NONE;
#if defined(BUTTON_PIN) || defined(ARCH_PORTDUINO)
#if defined(BUTTON_PIN) || defined(ARCH_PORTDUINO) || defined(USERPREFS_BUTTON_PIN)
OneButton ButtonThread::userButton; // Get reference to static member
#endif
ButtonThread::ButtonThread() : OSThread("Button")
{
#if defined(BUTTON_PIN) || defined(ARCH_PORTDUINO)
#if defined(BUTTON_PIN) || defined(ARCH_PORTDUINO) || defined(USERPREFS_BUTTON_PIN)
#if defined(ARCH_PORTDUINO)
if (settingsMap.count(user) != 0 && settingsMap[user] != RADIOLIB_NC) {
this->userButton = OneButton(settingsMap[user], true, true);
LOG_DEBUG("Using GPIO%02d for button\n", settingsMap[user]);
LOG_DEBUG("Use GPIO%02d for button", settingsMap[user]);
}
#elif defined(BUTTON_PIN)
int pin = config.device.button_gpio ? config.device.button_gpio : BUTTON_PIN; // Resolved button pin
#if !defined(USERPREFS_BUTTON_PIN)
int pin = config.device.button_gpio ? config.device.button_gpio : BUTTON_PIN; // Resolved button pin
#endif
#ifdef USERPREFS_BUTTON_PIN
int pin = config.device.button_gpio ? config.device.button_gpio : USERPREFS_BUTTON_PIN; // Resolved button pin
#endif
#if defined(HELTEC_CAPSULE_SENSOR_V3)
this->userButton = OneButton(pin, false, false);
#elif defined(BUTTON_ACTIVE_LOW)
@ -47,7 +53,7 @@ ButtonThread::ButtonThread() : OSThread("Button")
#else
this->userButton = OneButton(pin, true, true);
#endif
LOG_DEBUG("Using GPIO%02d for button\n", pin);
LOG_DEBUG("Use GPIO%02d for button", pin);
#endif
#ifdef INPUT_PULLUP_SENSE
@ -59,7 +65,7 @@ ButtonThread::ButtonThread() : OSThread("Button")
#endif
#endif
#if defined(BUTTON_PIN) || defined(ARCH_PORTDUINO)
#if defined(BUTTON_PIN) || defined(ARCH_PORTDUINO) || defined(USERPREFS_BUTTON_PIN)
userButton.attachClick(userButtonPressed);
userButton.setClickMs(BUTTON_CLICK_MS);
userButton.setPressMs(BUTTON_LONGPRESS_MS);
@ -102,7 +108,7 @@ int32_t ButtonThread::runOnce()
// If the button is pressed we suppress CPU sleep until release
canSleep = true; // Assume we should not keep the board awake
#if defined(BUTTON_PIN)
#if defined(BUTTON_PIN) || defined(USERPREFS_BUTTON_PIN)
userButton.tick();
canSleep &= userButton.isIdle();
#elif defined(ARCH_PORTDUINO)
@ -123,14 +129,19 @@ int32_t ButtonThread::runOnce()
if (btnEvent != BUTTON_EVENT_NONE) {
switch (btnEvent) {
case BUTTON_EVENT_PRESSED: {
LOG_BUTTON("press!\n");
LOG_BUTTON("press!");
// If a nag notification is running, stop it and prevent other actions
if (moduleConfig.external_notification.enabled && (externalNotificationModule->nagCycleCutoff != UINT32_MAX)) {
externalNotificationModule->stopNow();
return 50;
}
#ifdef BUTTON_PIN
#if !defined(USERPREFS_BUTTON_PIN)
if (((config.device.button_gpio ? config.device.button_gpio : BUTTON_PIN) !=
#endif
#if defined(USERPREFS_BUTTON_PIN)
if (((config.device.button_gpio ? config.device.button_gpio : USERPREFS_BUTTON_PIN) !=
#endif
moduleConfig.canned_message.inputbroker_pin_press) ||
!(moduleConfig.canned_message.updown1_enabled || moduleConfig.canned_message.rotary1_enabled) ||
!moduleConfig.canned_message.enabled) {
@ -148,7 +159,7 @@ int32_t ButtonThread::runOnce()
}
case BUTTON_EVENT_DOUBLE_PRESSED: {
LOG_BUTTON("Double press!\n");
LOG_BUTTON("Double press!");
service->refreshLocalMeshNode();
auto sentPosition = service->trySendPosition(NODENUM_BROADCAST, true);
if (screen) {
@ -162,7 +173,7 @@ int32_t ButtonThread::runOnce()
}
case BUTTON_EVENT_MULTI_PRESSED: {
LOG_BUTTON("Mulitipress! %hux\n", multipressClickCount);
LOG_BUTTON("Mulitipress! %hux", multipressClickCount);
switch (multipressClickCount) {
#if HAS_GPS
// 3 clicks: toggle GPS
@ -189,7 +200,7 @@ int32_t ButtonThread::runOnce()
} // end multipress event
case BUTTON_EVENT_LONG_PRESSED: {
LOG_BUTTON("Long press!\n");
LOG_BUTTON("Long press!");
powerFSM.trigger(EVENT_PRESS);
if (screen) {
screen->startAlert("Shutting down...");
@ -201,7 +212,7 @@ int32_t ButtonThread::runOnce()
// Do actual shutdown when button released, otherwise the button release
// may wake the board immediatedly.
case BUTTON_EVENT_LONG_RELEASED: {
LOG_INFO("Shutdown from long press\n");
LOG_INFO("Shutdown from long press");
playShutdownMelody();
delay(3000);
power->shutdown();
@ -210,7 +221,7 @@ int32_t ButtonThread::runOnce()
#ifdef BUTTON_PIN_TOUCH
case BUTTON_EVENT_TOUCH_LONG_PRESSED: {
LOG_BUTTON("Touch press!\n");
LOG_BUTTON("Touch press!");
if (screen) {
// Wake if asleep
if (powerFSM.getState() == &stateDARK)
@ -244,7 +255,12 @@ void ButtonThread::attachButtonInterrupts()
#elif defined(BUTTON_PIN)
// Interrupt for user button, during normal use. Improves responsiveness.
attachInterrupt(
#if !defined(USERPREFS_BUTTON_PIN)
config.device.button_gpio ? config.device.button_gpio : BUTTON_PIN,
#endif
#if defined(USERPREFS_BUTTON_PIN)
config.device.button_gpio ? config.device.button_gpio : USERPREFS_BUTTON_PIN,
#endif
[]() {
ButtonThread::userButton.tick();
runASAP = true;
@ -273,8 +289,13 @@ void ButtonThread::detachButtonInterrupts()
if (settingsMap.count(user) != 0 && settingsMap[user] != RADIOLIB_NC)
detachInterrupt(settingsMap[user]);
#elif defined(BUTTON_PIN)
#if !defined(USERPREFS_BUTTON_PIN)
detachInterrupt(config.device.button_gpio ? config.device.button_gpio : BUTTON_PIN);
#endif
#if defined(USERPREFS_BUTTON_PIN)
detachInterrupt(config.device.button_gpio ? config.device.button_gpio : USERPREFS_BUTTON_PIN);
#endif
#endif
#ifdef BUTTON_PIN_ALT
detachInterrupt(BUTTON_PIN_ALT);
@ -315,7 +336,7 @@ void ButtonThread::userButtonMultiPressed(void *callerThread)
// Non-static method, runs during callback. Grabs info while still valid
void ButtonThread::storeClickCount()
{
#ifdef BUTTON_PIN
#if defined(BUTTON_PIN) || defined(USERPREFS_BUTTON_PIN)
multipressClickCount = userButton.getNumberClicks();
#endif
}

View File

@ -38,7 +38,7 @@ class ButtonThread : public concurrency::OSThread
void storeClickCount();
private:
#if defined(BUTTON_PIN) || defined(ARCH_PORTDUINO)
#if defined(BUTTON_PIN) || defined(ARCH_PORTDUINO) || defined(USERPREFS_BUTTON_PIN)
static OneButton userButton; // Static - accessed from an interrupt
#endif
#ifdef BUTTON_PIN_ALT

View File

@ -53,7 +53,7 @@ bool lfs_assert_failed =
extern "C" void lfs_assert(const char *reason)
{
LOG_ERROR("LFS assert: %s\n", reason);
LOG_ERROR("LFS assert: %s", reason);
lfs_assert_failed = true;
}
@ -75,19 +75,19 @@ bool copyFile(const char *from, const char *to)
r = OSFS::getFile(from, cbuffer);
if (r == notfound) {
LOG_ERROR("Failed to open source file %s\n", from);
LOG_ERROR("Failed to open source file %s", from);
return false;
} else if (r == noerr) {
r = OSFS::newFile(to, cbuffer, true);
if (r == noerr) {
return true;
} else {
LOG_ERROR("OSFS Error %d\n", r);
LOG_ERROR("OSFS Error %d", r);
return false;
}
} else {
LOG_ERROR("OSFS Error %d\n", r);
LOG_ERROR("OSFS Error %d", r);
return false;
}
return true;
@ -97,13 +97,13 @@ bool copyFile(const char *from, const char *to)
File f1 = FSCom.open(from, FILE_O_READ);
if (!f1) {
LOG_ERROR("Failed to open source file %s\n", from);
LOG_ERROR("Failed to open source file %s", from);
return false;
}
File f2 = FSCom.open(to, FILE_O_WRITE);
if (!f2) {
LOG_ERROR("Failed to open destination file %s\n", to);
LOG_ERROR("Failed to open destination file %s", to);
return false;
}
@ -231,7 +231,7 @@ void listDir(const char *dirname, uint8_t levels, bool del)
#ifdef ARCH_ESP32
listDir(file.path(), levels - 1, del);
if (del) {
LOG_DEBUG("Removing %s\n", file.path());
LOG_DEBUG("Remove %s", file.path());
strncpy(buffer, file.path(), sizeof(buffer));
file.close();
FSCom.rmdir(buffer);
@ -241,7 +241,7 @@ void listDir(const char *dirname, uint8_t levels, bool del)
#elif (defined(ARCH_RP2040) || defined(ARCH_PORTDUINO))
listDir(file.name(), levels - 1, del);
if (del) {
LOG_DEBUG("Removing %s\n", file.name());
LOG_DEBUG("Remove %s", file.name());
strncpy(buffer, file.name(), sizeof(buffer));
file.close();
FSCom.rmdir(buffer);
@ -249,7 +249,7 @@ void listDir(const char *dirname, uint8_t levels, bool del)
file.close();
}
#else
LOG_DEBUG(" %s (directory)\n", file.name());
LOG_DEBUG(" %s (directory)", file.name());
listDir(file.name(), levels - 1, del);
file.close();
#endif
@ -257,26 +257,26 @@ void listDir(const char *dirname, uint8_t levels, bool del)
} else {
#ifdef ARCH_ESP32
if (del) {
LOG_DEBUG("Deleting %s\n", file.path());
LOG_DEBUG("Delete %s", file.path());
strncpy(buffer, file.path(), sizeof(buffer));
file.close();
FSCom.remove(buffer);
} else {
LOG_DEBUG(" %s (%i Bytes)\n", file.path(), file.size());
LOG_DEBUG(" %s (%i Bytes)", file.path(), file.size());
file.close();
}
#elif (defined(ARCH_RP2040) || defined(ARCH_PORTDUINO))
if (del) {
LOG_DEBUG("Deleting %s\n", file.name());
LOG_DEBUG("Delete %s", file.name());
strncpy(buffer, file.name(), sizeof(buffer));
file.close();
FSCom.remove(buffer);
} else {
LOG_DEBUG(" %s (%i Bytes)\n", file.name(), file.size());
LOG_DEBUG(" %s (%i Bytes)", file.name(), file.size());
file.close();
}
#else
LOG_DEBUG(" %s (%i Bytes)\n", file.name(), file.size());
LOG_DEBUG(" %s (%i Bytes)", file.name(), file.size());
file.close();
#endif
}
@ -284,7 +284,7 @@ void listDir(const char *dirname, uint8_t levels, bool del)
}
#ifdef ARCH_ESP32
if (del) {
LOG_DEBUG("Removing %s\n", root.path());
LOG_DEBUG("Remove %s", root.path());
strncpy(buffer, root.path(), sizeof(buffer));
root.close();
FSCom.rmdir(buffer);
@ -293,7 +293,7 @@ void listDir(const char *dirname, uint8_t levels, bool del)
}
#elif (defined(ARCH_RP2040) || defined(ARCH_PORTDUINO))
if (del) {
LOG_DEBUG("Removing %s\n", root.name());
LOG_DEBUG("Remove %s", root.name());
strncpy(buffer, root.name(), sizeof(buffer));
root.close();
FSCom.rmdir(buffer);
@ -329,13 +329,13 @@ void fsInit()
{
#ifdef FSCom
if (!FSBegin()) {
LOG_ERROR("Filesystem mount Failed.\n");
LOG_ERROR("Filesystem mount failed");
// assert(0); This auto-formats the partition, so no need to fail here.
}
#if defined(ARCH_ESP32)
LOG_DEBUG("Filesystem files (%d/%d Bytes):\n", FSCom.usedBytes(), FSCom.totalBytes());
LOG_DEBUG("Filesystem files (%d/%d Bytes):", FSCom.usedBytes(), FSCom.totalBytes());
#else
LOG_DEBUG("Filesystem files:\n");
LOG_DEBUG("Filesystem files:");
#endif
listDir("/", 10);
#endif
@ -350,28 +350,28 @@ void setupSDCard()
SDHandler.begin(SPI_SCK, SPI_MISO, SPI_MOSI);
if (!SD.begin(SDCARD_CS, SDHandler)) {
LOG_DEBUG("No SD_MMC card detected\n");
LOG_DEBUG("No SD_MMC card detected");
return;
}
uint8_t cardType = SD.cardType();
if (cardType == CARD_NONE) {
LOG_DEBUG("No SD_MMC card attached\n");
LOG_DEBUG("No SD_MMC card attached");
return;
}
LOG_DEBUG("SD_MMC Card Type: ");
if (cardType == CARD_MMC) {
LOG_DEBUG("MMC\n");
LOG_DEBUG("MMC");
} else if (cardType == CARD_SD) {
LOG_DEBUG("SDSC\n");
LOG_DEBUG("SDSC");
} else if (cardType == CARD_SDHC) {
LOG_DEBUG("SDHC\n");
LOG_DEBUG("SDHC");
} else {
LOG_DEBUG("UNKNOWN\n");
LOG_DEBUG("UNKNOWN");
}
uint64_t cardSize = SD.cardSize() / (1024 * 1024);
LOG_DEBUG("SD Card Size: %lu MB\n", (uint32_t)cardSize);
LOG_DEBUG("Total space: %lu MB\n", (uint32_t)(SD.totalBytes() / (1024 * 1024)));
LOG_DEBUG("Used space: %lu MB\n", (uint32_t)(SD.usedBytes() / (1024 * 1024)));
LOG_DEBUG("SD Card Size: %lu MB", (uint32_t)cardSize);
LOG_DEBUG("Total space: %lu MB", (uint32_t)(SD.totalBytes() / (1024 * 1024)));
LOG_DEBUG("Used space: %lu MB", (uint32_t)(SD.usedBytes() / (1024 * 1024)));
#endif
}

View File

@ -50,9 +50,6 @@ class GPSStatus : public Status
int32_t getLatitude() const
{
if (config.position.fixed_position) {
#ifdef GPS_EXTRAVERBOSE
LOG_WARN("Using fixed latitude\n");
#endif
meshtastic_NodeInfoLite *node = nodeDB->getMeshNode(nodeDB->getNodeNum());
return node->position.latitude_i;
} else {
@ -63,9 +60,6 @@ class GPSStatus : public Status
int32_t getLongitude() const
{
if (config.position.fixed_position) {
#ifdef GPS_EXTRAVERBOSE
LOG_WARN("Using fixed longitude\n");
#endif
meshtastic_NodeInfoLite *node = nodeDB->getMeshNode(nodeDB->getNodeNum());
return node->position.longitude_i;
} else {
@ -76,9 +70,6 @@ class GPSStatus : public Status
int32_t getAltitude() const
{
if (config.position.fixed_position) {
#ifdef GPS_EXTRAVERBOSE
LOG_WARN("Using fixed altitude\n");
#endif
meshtastic_NodeInfoLite *node = nodeDB->getMeshNode(nodeDB->getNodeNum());
return node->position.altitude;
} else {
@ -94,8 +85,8 @@ class GPSStatus : public Status
bool matches(const GPSStatus *newStatus) const
{
#ifdef GPS_EXTRAVERBOSE
LOG_DEBUG("GPSStatus.match() new pos@%x to old pos@%x\n", newStatus->p.timestamp, p.timestamp);
#ifdef GPS_DEBUG
LOG_DEBUG("GPSStatus.match() new pos@%x to old pos@%x", newStatus->p.timestamp, p.timestamp);
#endif
return (newStatus->hasLock != hasLock || newStatus->isConnected != isConnected ||
newStatus->isPowerSaving != isPowerSaving || newStatus->p.latitude_i != p.latitude_i ||
@ -112,7 +103,7 @@ class GPSStatus : public Status
if (isDirty && p.timestamp && (newStatus->p.timestamp == p.timestamp)) {
// We can NEVER be in two locations at the same time! (also PR #886)
LOG_ERROR("BUG: Positional timestamp unchanged from prev solution\n");
LOG_ERROR("BUG: Positional timestamp unchanged from prev solution");
}
initialized = true;
@ -124,11 +115,11 @@ class GPSStatus : public Status
if (isDirty) {
if (hasLock) {
// In debug logs, identify position by @timestamp:stage (stage 3 = notify)
LOG_DEBUG("New GPS pos@%x:3 lat=%f lon=%f alt=%d pdop=%.2f track=%.2f speed=%.2f sats=%d\n", p.timestamp,
LOG_DEBUG("New GPS pos@%x:3 lat=%f lon=%f alt=%d pdop=%.2f track=%.2f speed=%.2f sats=%d", p.timestamp,
p.latitude_i * 1e-7, p.longitude_i * 1e-7, p.altitude, p.PDOP * 1e-2, p.ground_track * 1e-5,
p.ground_speed * 1e-2, p.sats_in_view);
} else {
LOG_DEBUG("No GPS lock\n");
LOG_DEBUG("No GPS lock");
}
onNewStatus.notifyObservers(this);
}

View File

@ -12,7 +12,6 @@ void GpioVirtPin::set(bool value)
void GpioHwPin::set(bool value)
{
// if (num == 3) LOG_DEBUG("Setting pin %d to %d\n", num, value);
pinMode(num, OUTPUT);
digitalWrite(num, value);
}
@ -66,7 +65,7 @@ GpioBinaryTransformer::GpioBinaryTransformer(GpioVirtPin *inPin1, GpioVirtPin *i
assert(!inPin2->dependentPin); // We only allow one dependent pin
inPin2->dependentPin = this;
// Don't update at construction time, because various GpioPins might be global constructor based not yet initied because
// Don't update at construction time, because various GpioPins might be global constructor based not yet initiated because
// order of operations for global constructors is not defined.
// update();
}
@ -88,7 +87,6 @@ void GpioBinaryTransformer::update()
newValue = (GpioVirtPin::PinState)(p1 && p2);
break;
case Or:
// LOG_DEBUG("Doing GPIO OR\n");
newValue = (GpioVirtPin::PinState)(p1 || p2);
break;
case Xor:
@ -101,4 +99,4 @@ void GpioBinaryTransformer::update()
set(newValue);
}
GpioSplitter::GpioSplitter(GpioPin *outPin1, GpioPin *outPin2) : outPin1(outPin1), outPin2(outPin2) {}
GpioSplitter::GpioSplitter(GpioPin *outPin1, GpioPin *outPin2) : outPin1(outPin1), outPin2(outPin2) {}

View File

@ -56,7 +56,7 @@ class NodeStatus : public Status
numTotal = newStatus->getNumTotal();
}
if (isDirty || newStatus->forceUpdate) {
LOG_DEBUG("Node status update: %d online, %d total\n", numOnline, numTotal);
LOG_DEBUG("Node status update: %d online, %d total", numOnline, numTotal);
onNewStatus.notifyObservers(this);
}
return 0;

View File

@ -154,9 +154,16 @@ static void adcEnable()
#ifdef ADC_CTRL // enable adc voltage divider when we need to read
#ifdef ADC_USE_PULLUP
pinMode(ADC_CTRL, INPUT_PULLUP);
#else
#ifdef HELTEC_V3
pinMode(ADC_CTRL, INPUT);
uint8_t adc_ctl_enable_value = !(digitalRead(ADC_CTRL));
pinMode(ADC_CTRL, OUTPUT);
digitalWrite(ADC_CTRL, adc_ctl_enable_value);
#else
pinMode(ADC_CTRL, OUTPUT);
digitalWrite(ADC_CTRL, ADC_CTRL_ENABLED);
#endif
#endif
delay(10);
#endif
@ -167,10 +174,14 @@ static void adcDisable()
#ifdef ADC_CTRL // disable adc voltage divider when we need to read
#ifdef ADC_USE_PULLUP
pinMode(ADC_CTRL, INPUT_PULLDOWN);
#else
#ifdef HELTEC_V3
pinMode(ADC_CTRL, ANALOG);
#else
digitalWrite(ADC_CTRL, !ADC_CTRL_ENABLED);
#endif
#endif
#endif
}
#endif
@ -240,7 +251,6 @@ class AnalogBatteryLevel : public HasBatteryLevel
#if HAS_TELEMETRY && !defined(ARCH_PORTDUINO) && !defined(ARCH_STM32WL) && !defined(HAS_PMU) && \
!MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR
if (hasINA()) {
LOG_DEBUG("Using INA on I2C addr 0x%x for device battery voltage\n", config.power.device_battery_ina_address);
return getINAVoltage();
}
#endif
@ -260,7 +270,7 @@ class AnalogBatteryLevel : public HasBatteryLevel
config.power.adc_multiplier_override > 0 ? config.power.adc_multiplier_override : ADC_MULTIPLIER;
// Do not call analogRead() often.
const uint32_t min_read_interval = 5000;
if (!Throttle::isWithinTimespanMs(last_read_time_ms, min_read_interval)) {
if (!initial_read_done || !Throttle::isWithinTimespanMs(last_read_time_ms, min_read_interval)) {
last_read_time_ms = millis();
uint32_t raw = 0;
@ -290,7 +300,7 @@ class AnalogBatteryLevel : public HasBatteryLevel
last_read_value += (scaled - last_read_value) * 0.5; // Virtual LPF
}
// LOG_DEBUG("battery gpio %d raw val=%u scaled=%u filtered=%u\n", BATTERY_PIN, raw, (uint32_t)(scaled), (uint32_t)
// LOG_DEBUG("battery gpio %d raw val=%u scaled=%u filtered=%u", BATTERY_PIN, raw, (uint32_t)(scaled), (uint32_t)
// (last_read_value));
}
return last_read_value;
@ -335,7 +345,7 @@ class AnalogBatteryLevel : public HasBatteryLevel
raw += adc_buf;
raw_c++; // Count valid samples
} else {
LOG_DEBUG("An attempt to sample ADC2 failed\n");
LOG_DEBUG("An attempt to sample ADC2 failed");
}
}
@ -360,7 +370,12 @@ class AnalogBatteryLevel : public HasBatteryLevel
/**
* return true if there is a battery installed in this unit
*/
// if we have a integrated device with a battery, we can assume that the battery is always connected
#ifdef BATTERY_IMMUTABLE
virtual bool isBatteryConnect() override { return true; }
#else
virtual bool isBatteryConnect() override { return getBatteryPercent() != -1; }
#endif
/// If we see a battery voltage higher than physics allows - assume charger is pumping
/// in power
@ -495,7 +510,7 @@ bool Power::analogInit()
#endif
#ifdef BATTERY_PIN
LOG_DEBUG("Using analog input %d for battery level\n", BATTERY_PIN);
LOG_DEBUG("Use analog input %d for battery level", BATTERY_PIN);
// disable any internal pullups
pinMode(BATTERY_PIN, INPUT);
@ -526,18 +541,18 @@ bool Power::analogInit()
esp_adc_cal_value_t val_type = esp_adc_cal_characterize(unit, atten, width, DEFAULT_VREF, adc_characs);
// show ADC characterization base
if (val_type == ESP_ADC_CAL_VAL_EFUSE_TP) {
LOG_INFO("ADCmod: ADC characterization based on Two Point values stored in eFuse\n");
LOG_INFO("ADC config based on Two Point values stored in eFuse");
} else if (val_type == ESP_ADC_CAL_VAL_EFUSE_VREF) {
LOG_INFO("ADCmod: ADC characterization based on reference voltage stored in eFuse\n");
LOG_INFO("ADC config based on reference voltage stored in eFuse");
}
#ifdef CONFIG_IDF_TARGET_ESP32S3
// ESP32S3
else if (val_type == ESP_ADC_CAL_VAL_EFUSE_TP_FIT) {
LOG_INFO("ADCmod: ADC Characterization based on Two Point values and fitting curve coefficients stored in eFuse\n");
LOG_INFO("ADC config based on Two Point values and fitting curve coefficients stored in eFuse");
}
#endif
else {
LOG_INFO("ADCmod: ADC characterization based on default reference voltage\n");
LOG_INFO("ADC config based on default reference voltage");
}
#endif // ARCH_ESP32
@ -586,7 +601,7 @@ bool Power::setup()
void Power::shutdown()
{
LOG_INFO("Shutting down\n");
LOG_INFO("Shutting down");
#if defined(ARCH_NRF52) || defined(ARCH_ESP32) || defined(ARCH_RP2040)
#ifdef PIN_LED1
@ -598,7 +613,7 @@ void Power::shutdown()
#ifdef PIN_LED3
ledOff(PIN_LED3);
#endif
doDeepSleep(DELAY_FOREVER, false);
doDeepSleep(DELAY_FOREVER, false, false);
#endif
}
@ -624,7 +639,7 @@ void Power::readPowerStatus()
batteryChargePercent = batteryLevel->getBatteryPercent();
} else {
// If the AXP192 returns a percentage less than 0, the feature is either not supported or there is an error
// In that case, we compute an estimate of the charge percent based on open circuite voltage table defined
// In that case, we compute an estimate of the charge percent based on open circuit voltage table defined
// in power.h
batteryChargePercent = clamp((int)(((batteryVoltageMv - (OCV[NUM_OCV_POINTS - 1] * NUM_CELLS)) * 1e2) /
((OCV[0] * NUM_CELLS) - (OCV[NUM_OCV_POINTS - 1] * NUM_CELLS))),
@ -641,7 +656,7 @@ void Power::readPowerStatus()
// changes.
nrfx_power_usb_state_t nrf_usb_state = nrfx_power_usbstatus_get();
// LOG_DEBUG("NRF Power %d\n", nrf_usb_state);
// LOG_DEBUG("NRF Power %d", nrf_usb_state);
// If changed to DISCONNECTED
if (nrf_usb_state == NRFX_POWER_USB_STATE_DISCONNECTED)
@ -654,22 +669,22 @@ void Power::readPowerStatus()
// Notify any status instances that are observing us
const PowerStatus powerStatus2 = PowerStatus(hasBattery, usbPowered, isCharging, batteryVoltageMv, batteryChargePercent);
LOG_DEBUG("Battery: usbPower=%d, isCharging=%d, batMv=%d, batPct=%d\n", powerStatus2.getHasUSB(),
powerStatus2.getIsCharging(), powerStatus2.getBatteryVoltageMv(), powerStatus2.getBatteryChargePercent());
LOG_DEBUG("Battery: usbPower=%d, isCharging=%d, batMv=%d, batPct=%d", powerStatus2.getHasUSB(), powerStatus2.getIsCharging(),
powerStatus2.getBatteryVoltageMv(), powerStatus2.getBatteryChargePercent());
newStatus.notifyObservers(&powerStatus2);
#ifdef DEBUG_HEAP
if (lastheap != memGet.getFreeHeap()) {
LOG_DEBUG("Threads running:");
std::string threadlist = "Threads running:";
int running = 0;
for (int i = 0; i < MAX_THREADS; i++) {
auto thread = concurrency::mainController.get(i);
if ((thread != nullptr) && (thread->enabled)) {
LOG_DEBUG(" %s", thread->ThreadName.c_str());
threadlist += vformat(" %s", thread->ThreadName.c_str());
running++;
}
}
LOG_DEBUG("\n");
LOG_DEBUG("Heap status: %d/%d bytes free (%d), running %d/%d threads\n", memGet.getFreeHeap(), memGet.getHeapSize(),
LOG_DEBUG(threadlist.c_str());
LOG_DEBUG("Heap status: %d/%d bytes free (%d), running %d/%d threads", memGet.getFreeHeap(), memGet.getHeapSize(),
memGet.getFreeHeap() - lastheap, running, concurrency::mainController.size(false));
lastheap = memGet.getFreeHeap();
}
@ -702,13 +717,13 @@ void Power::readPowerStatus()
if (batteryLevel && powerStatus2.getHasBattery() && !powerStatus2.getHasUSB()) {
if (batteryLevel->getBattVoltage() < OCV[NUM_OCV_POINTS - 1]) {
low_voltage_counter++;
LOG_DEBUG("Low voltage counter: %d/10\n", low_voltage_counter);
LOG_DEBUG("Low voltage counter: %d/10", low_voltage_counter);
if (low_voltage_counter > 10) {
#ifdef ARCH_NRF52
// We can't trigger deep sleep on NRF52, it's freezing the board
LOG_DEBUG("Low voltage detected, but not triggering deep sleep\n");
LOG_DEBUG("Low voltage detected, but not trigger deep sleep");
#else
LOG_INFO("Low voltage detected, triggering deep sleep\n");
LOG_INFO("Low voltage detected, trigger deep sleep");
powerFSM.trigger(EVENT_LOW_BATTERY);
#endif
}
@ -730,12 +745,12 @@ int32_t Power::runOnce()
PMU->getIrqStatus();
if (PMU->isVbusRemoveIrq()) {
LOG_INFO("USB unplugged\n");
LOG_INFO("USB unplugged");
powerFSM.trigger(EVENT_POWER_DISCONNECTED);
}
if (PMU->isVbusInsertIrq()) {
LOG_INFO("USB plugged In\n");
LOG_INFO("USB plugged In");
powerFSM.trigger(EVENT_POWER_CONNECTED);
}
@ -743,21 +758,21 @@ int32_t Power::runOnce()
Other things we could check if we cared...
if (PMU->isBatChagerStartIrq()) {
LOG_DEBUG("Battery start charging\n");
LOG_DEBUG("Battery start charging");
}
if (PMU->isBatChagerDoneIrq()) {
LOG_DEBUG("Battery fully charged\n");
LOG_DEBUG("Battery fully charged");
}
if (PMU->isBatInsertIrq()) {
LOG_DEBUG("Battery inserted\n");
LOG_DEBUG("Battery inserted");
}
if (PMU->isBatRemoveIrq()) {
LOG_DEBUG("Battery removed\n");
LOG_DEBUG("Battery removed");
}
*/
#ifndef T_WATCH_S3 // FIXME - why is this triggering on the T-Watch S3?
if (PMU->isPekeyLongPressIrq()) {
LOG_DEBUG("PEK long button press\n");
LOG_DEBUG("PEK long button press");
screen->setOn(false);
}
#endif
@ -800,22 +815,22 @@ bool Power::axpChipInit()
if (!PMU) {
PMU = new XPowersAXP2101(*w);
if (!PMU->init()) {
LOG_WARN("Failed to find AXP2101 power management\n");
LOG_WARN("No AXP2101 power management");
delete PMU;
PMU = NULL;
} else {
LOG_INFO("AXP2101 PMU init succeeded, using AXP2101 PMU\n");
LOG_INFO("AXP2101 PMU init succeeded");
}
}
if (!PMU) {
PMU = new XPowersAXP192(*w);
if (!PMU->init()) {
LOG_WARN("Failed to find AXP192 power management\n");
LOG_WARN("No AXP192 power management");
delete PMU;
PMU = NULL;
} else {
LOG_INFO("AXP192 PMU init succeeded, using AXP192 PMU\n");
LOG_INFO("AXP192 PMU init succeeded");
}
}
@ -972,51 +987,51 @@ bool Power::axpChipInit()
PMU->enableBattVoltageMeasure();
if (PMU->isChannelAvailable(XPOWERS_DCDC1)) {
LOG_DEBUG("DC1 : %s Voltage:%u mV \n", PMU->isPowerChannelEnable(XPOWERS_DCDC1) ? "+" : "-",
LOG_DEBUG("DC1 : %s Voltage:%u mV ", PMU->isPowerChannelEnable(XPOWERS_DCDC1) ? "+" : "-",
PMU->getPowerChannelVoltage(XPOWERS_DCDC1));
}
if (PMU->isChannelAvailable(XPOWERS_DCDC2)) {
LOG_DEBUG("DC2 : %s Voltage:%u mV \n", PMU->isPowerChannelEnable(XPOWERS_DCDC2) ? "+" : "-",
LOG_DEBUG("DC2 : %s Voltage:%u mV ", PMU->isPowerChannelEnable(XPOWERS_DCDC2) ? "+" : "-",
PMU->getPowerChannelVoltage(XPOWERS_DCDC2));
}
if (PMU->isChannelAvailable(XPOWERS_DCDC3)) {
LOG_DEBUG("DC3 : %s Voltage:%u mV \n", PMU->isPowerChannelEnable(XPOWERS_DCDC3) ? "+" : "-",
LOG_DEBUG("DC3 : %s Voltage:%u mV ", PMU->isPowerChannelEnable(XPOWERS_DCDC3) ? "+" : "-",
PMU->getPowerChannelVoltage(XPOWERS_DCDC3));
}
if (PMU->isChannelAvailable(XPOWERS_DCDC4)) {
LOG_DEBUG("DC4 : %s Voltage:%u mV \n", PMU->isPowerChannelEnable(XPOWERS_DCDC4) ? "+" : "-",
LOG_DEBUG("DC4 : %s Voltage:%u mV ", PMU->isPowerChannelEnable(XPOWERS_DCDC4) ? "+" : "-",
PMU->getPowerChannelVoltage(XPOWERS_DCDC4));
}
if (PMU->isChannelAvailable(XPOWERS_LDO2)) {
LOG_DEBUG("LDO2 : %s Voltage:%u mV \n", PMU->isPowerChannelEnable(XPOWERS_LDO2) ? "+" : "-",
LOG_DEBUG("LDO2 : %s Voltage:%u mV ", PMU->isPowerChannelEnable(XPOWERS_LDO2) ? "+" : "-",
PMU->getPowerChannelVoltage(XPOWERS_LDO2));
}
if (PMU->isChannelAvailable(XPOWERS_LDO3)) {
LOG_DEBUG("LDO3 : %s Voltage:%u mV \n", PMU->isPowerChannelEnable(XPOWERS_LDO3) ? "+" : "-",
LOG_DEBUG("LDO3 : %s Voltage:%u mV ", PMU->isPowerChannelEnable(XPOWERS_LDO3) ? "+" : "-",
PMU->getPowerChannelVoltage(XPOWERS_LDO3));
}
if (PMU->isChannelAvailable(XPOWERS_ALDO1)) {
LOG_DEBUG("ALDO1: %s Voltage:%u mV \n", PMU->isPowerChannelEnable(XPOWERS_ALDO1) ? "+" : "-",
LOG_DEBUG("ALDO1: %s Voltage:%u mV ", PMU->isPowerChannelEnable(XPOWERS_ALDO1) ? "+" : "-",
PMU->getPowerChannelVoltage(XPOWERS_ALDO1));
}
if (PMU->isChannelAvailable(XPOWERS_ALDO2)) {
LOG_DEBUG("ALDO2: %s Voltage:%u mV \n", PMU->isPowerChannelEnable(XPOWERS_ALDO2) ? "+" : "-",
LOG_DEBUG("ALDO2: %s Voltage:%u mV ", PMU->isPowerChannelEnable(XPOWERS_ALDO2) ? "+" : "-",
PMU->getPowerChannelVoltage(XPOWERS_ALDO2));
}
if (PMU->isChannelAvailable(XPOWERS_ALDO3)) {
LOG_DEBUG("ALDO3: %s Voltage:%u mV \n", PMU->isPowerChannelEnable(XPOWERS_ALDO3) ? "+" : "-",
LOG_DEBUG("ALDO3: %s Voltage:%u mV ", PMU->isPowerChannelEnable(XPOWERS_ALDO3) ? "+" : "-",
PMU->getPowerChannelVoltage(XPOWERS_ALDO3));
}
if (PMU->isChannelAvailable(XPOWERS_ALDO4)) {
LOG_DEBUG("ALDO4: %s Voltage:%u mV \n", PMU->isPowerChannelEnable(XPOWERS_ALDO4) ? "+" : "-",
LOG_DEBUG("ALDO4: %s Voltage:%u mV ", PMU->isPowerChannelEnable(XPOWERS_ALDO4) ? "+" : "-",
PMU->getPowerChannelVoltage(XPOWERS_ALDO4));
}
if (PMU->isChannelAvailable(XPOWERS_BLDO1)) {
LOG_DEBUG("BLDO1: %s Voltage:%u mV \n", PMU->isPowerChannelEnable(XPOWERS_BLDO1) ? "+" : "-",
LOG_DEBUG("BLDO1: %s Voltage:%u mV ", PMU->isPowerChannelEnable(XPOWERS_BLDO1) ? "+" : "-",
PMU->getPowerChannelVoltage(XPOWERS_BLDO1));
}
if (PMU->isChannelAvailable(XPOWERS_BLDO2)) {
LOG_DEBUG("BLDO2: %s Voltage:%u mV \n", PMU->isPowerChannelEnable(XPOWERS_BLDO2) ? "+" : "-",
LOG_DEBUG("BLDO2: %s Voltage:%u mV ", PMU->isPowerChannelEnable(XPOWERS_BLDO2) ? "+" : "-",
PMU->getPowerChannelVoltage(XPOWERS_BLDO2));
}
@ -1124,7 +1139,7 @@ LipoBatteryLevel lipoLevel;
bool Power::lipoInit()
{
bool result = lipoLevel.runOnce();
LOG_DEBUG("Power::lipoInit lipo sensor is %s\n", result ? "ready" : "not ready yet");
LOG_DEBUG("Power::lipoInit lipo sensor is %s", result ? "ready" : "not ready yet");
if (!result)
return false;
batteryLevel = &lipoLevel;

View File

@ -19,6 +19,10 @@
#include "sleep.h"
#include "target_specific.h"
#if HAS_WIFI && !defined(ARCH_PORTDUINO)
#include "mesh/wifi/WiFiAPClient.h"
#endif
#ifndef SLEEP_TIME
#define SLEEP_TIME 30
#endif
@ -53,16 +57,21 @@ static bool isPowered()
static void sdsEnter()
{
LOG_DEBUG("Enter state: SDS\n");
LOG_DEBUG("State: SDS");
// FIXME - make sure GPS and LORA radio are off first - because we want close to zero current draw
doDeepSleep(Default::getConfiguredOrDefaultMs(config.power.sds_secs), false);
doDeepSleep(Default::getConfiguredOrDefaultMs(config.power.sds_secs), false, false);
}
static void lowBattSDSEnter()
{
LOG_DEBUG("State: Lower batt SDS");
doDeepSleep(Default::getConfiguredOrDefaultMs(config.power.sds_secs), false, true);
}
extern Power *power;
static void shutdownEnter()
{
LOG_DEBUG("Enter state: SHUTDOWN\n");
LOG_DEBUG("State: SHUTDOWN");
power->shutdown();
}
@ -72,16 +81,16 @@ static uint32_t secsSlept;
static void lsEnter()
{
LOG_INFO("lsEnter begin, ls_secs=%u\n", config.power.ls_secs);
LOG_INFO("lsEnter begin, ls_secs=%u", config.power.ls_secs);
screen->setOn(false);
secsSlept = 0; // How long have we been sleeping this time
// LOG_INFO("lsEnter end\n");
// LOG_INFO("lsEnter end");
}
static void lsIdle()
{
// LOG_INFO("lsIdle begin ls_secs=%u\n", getPref_ls_secs());
// LOG_INFO("lsIdle begin ls_secs=%u", getPref_ls_secs());
#ifdef ARCH_ESP32
@ -105,7 +114,7 @@ static void lsIdle()
wakeCause2 = doLightSleep(100); // leave led on for 1ms
secsSlept += sleepTime;
// LOG_INFO("sleeping, flash led!\n");
// LOG_INFO("Sleep, flash led!");
break;
case ESP_SLEEP_WAKEUP_UART:
@ -137,7 +146,7 @@ static void lsIdle()
} else {
// Time to stop sleeping!
ledBlink.set(false);
LOG_INFO("Reached ls_secs, servicing loop()\n");
LOG_INFO("Reached ls_secs, service loop()");
powerFSM.trigger(EVENT_WAKE_TIMER);
}
#endif
@ -145,12 +154,12 @@ static void lsIdle()
static void lsExit()
{
LOG_INFO("Exit state: LS\n");
LOG_INFO("Exit state: LS");
}
static void nbEnter()
{
LOG_DEBUG("Enter state: NB\n");
LOG_DEBUG("State: NB");
screen->setOn(false);
#ifdef ARCH_ESP32
// Only ESP32 should turn off bluetooth
@ -168,7 +177,7 @@ static void darkEnter()
static void serialEnter()
{
LOG_DEBUG("Enter state: SERIAL\n");
LOG_DEBUG("State: SERIAL");
setBluetoothEnable(false);
screen->setOn(true);
screen->print("Serial connected\n");
@ -183,10 +192,10 @@ static void serialExit()
static void powerEnter()
{
// LOG_DEBUG("Enter state: POWER\n");
// LOG_DEBUG("State: POWER");
if (!isPowered()) {
// If we got here, we are in the wrong state - we should be in powered, let that state ahndle things
LOG_INFO("Loss of power in Powered\n");
// If we got here, we are in the wrong state - we should be in powered, let that state handle things
LOG_INFO("Loss of power in Powered");
powerFSM.trigger(EVENT_POWER_DISCONNECTED);
} else {
screen->setOn(true);
@ -205,7 +214,7 @@ static void powerIdle()
{
if (!isPowered()) {
// If we got here, we are in the wrong state
LOG_INFO("Loss of power in Powered\n");
LOG_INFO("Loss of power in Powered");
powerFSM.trigger(EVENT_POWER_DISCONNECTED);
}
}
@ -222,7 +231,7 @@ static void powerExit()
static void onEnter()
{
LOG_DEBUG("Enter state: ON\n");
LOG_DEBUG("State: ON");
screen->setOn(true);
setBluetoothEnable(true);
}
@ -230,7 +239,7 @@ static void onEnter()
static void onIdle()
{
if (isPowered()) {
// If we got here, we are in the wrong state - we should be in powered, let that state ahndle things
// If we got here, we are in the wrong state - we should be in powered, let that state handle things
powerFSM.trigger(EVENT_POWER_CONNECTED);
}
}
@ -242,11 +251,12 @@ static void screenPress()
static void bootEnter()
{
LOG_DEBUG("Enter state: BOOT\n");
LOG_DEBUG("State: BOOT");
}
State stateSHUTDOWN(shutdownEnter, NULL, NULL, "SHUTDOWN");
State stateSDS(sdsEnter, NULL, NULL, "SDS");
State stateLowBattSDS(lowBattSDSEnter, NULL, NULL, "SDS");
State stateLS(lsEnter, lsIdle, lsExit, "LS");
State stateNB(nbEnter, NULL, NULL, "NB");
State stateDARK(darkEnter, NULL, NULL, "DARK");
@ -264,7 +274,7 @@ void PowerFSM_setup()
config.device.role == meshtastic_Config_DeviceConfig_Role_SENSOR;
bool hasPower = isPowered();
LOG_INFO("PowerFSM init, USB power=%d\n", hasPower ? 1 : 0);
LOG_INFO("PowerFSM init, USB power=%d", hasPower ? 1 : 0);
powerFSM.add_timed_transition(&stateBOOT, hasPower ? &statePOWER : &stateON, 3 * 1000, NULL, "boot timeout");
// wake timer expired or a packet arrived
@ -291,12 +301,12 @@ void PowerFSM_setup()
"Press"); // Allow button to work while in serial API
// Handle critically low power battery by forcing deep sleep
powerFSM.add_transition(&stateBOOT, &stateSDS, EVENT_LOW_BATTERY, NULL, "LowBat");
powerFSM.add_transition(&stateLS, &stateSDS, EVENT_LOW_BATTERY, NULL, "LowBat");
powerFSM.add_transition(&stateNB, &stateSDS, EVENT_LOW_BATTERY, NULL, "LowBat");
powerFSM.add_transition(&stateDARK, &stateSDS, EVENT_LOW_BATTERY, NULL, "LowBat");
powerFSM.add_transition(&stateON, &stateSDS, EVENT_LOW_BATTERY, NULL, "LowBat");
powerFSM.add_transition(&stateSERIAL, &stateSDS, EVENT_LOW_BATTERY, NULL, "LowBat");
powerFSM.add_transition(&stateBOOT, &stateLowBattSDS, EVENT_LOW_BATTERY, NULL, "LowBat");
powerFSM.add_transition(&stateLS, &stateLowBattSDS, EVENT_LOW_BATTERY, NULL, "LowBat");
powerFSM.add_transition(&stateNB, &stateLowBattSDS, EVENT_LOW_BATTERY, NULL, "LowBat");
powerFSM.add_transition(&stateDARK, &stateLowBattSDS, EVENT_LOW_BATTERY, NULL, "LowBat");
powerFSM.add_transition(&stateON, &stateLowBattSDS, EVENT_LOW_BATTERY, NULL, "LowBat");
powerFSM.add_transition(&stateSERIAL, &stateLowBattSDS, EVENT_LOW_BATTERY, NULL, "LowBat");
// Handle being told to power off
powerFSM.add_transition(&stateBOOT, &stateSHUTDOWN, EVENT_SHUTDOWN, NULL, "Shutdown");
@ -371,9 +381,9 @@ void PowerFSM_setup()
// We never enter light-sleep or NB states on NRF52 (because the CPU uses so little power normally)
#ifdef ARCH_ESP32
// See: https://github.com/meshtastic/firmware/issues/1071
// Don't add power saving transitions if we are a power saving tracker or sensor. Sleep will be initiatiated through the
// modules
if ((isRouter || config.power.is_power_saving) && !isTrackerOrSensor) {
// Don't add power saving transitions if we are a power saving tracker or sensor or have Wifi enabled. Sleep will be initiated
// through the modules
if ((isRouter || config.power.is_power_saving) && !isWifiAvailable() && !isTrackerOrSensor) {
powerFSM.add_timed_transition(&stateNB, &stateLS,
Default::getConfiguredOrDefaultMs(config.power.min_wake_secs, default_min_wake_secs), NULL,
"Min wake timeout");

View File

@ -35,7 +35,7 @@ void PowerMon::emitLog(const char *reason)
{
#ifdef USE_POWERMON
// The nrf52 printf doesn't understand 64 bit ints, so if we ever reach that point this function will need to change.
LOG_INFO("S:PM:0x%08lx,%s\n", (uint32_t)states, reason);
LOG_INFO("S:PM:0x%08lx,%s", (uint32_t)states, reason);
#endif
}

View File

@ -91,7 +91,7 @@ class PowerStatus : public Status
isCharging = newStatus->isCharging;
}
if (isDirty) {
// LOG_DEBUG("Battery %dmV %d%%\n", batteryVoltageMv, batteryChargePercent);
// LOG_DEBUG("Battery %dmV %d%%", batteryVoltageMv, batteryChargePercent);
onNewStatus.notifyObservers(this);
}
return 0;

View File

@ -98,81 +98,75 @@ void RedirectablePrint::log_to_serial(const char *logLevel, const char *format,
{
size_t r = 0;
// Cope with 0 len format strings, but look for new line terminator
bool hasNewline = *format && format[strlen(format) - 1] == '\n';
#ifdef ARCH_PORTDUINO
bool color = !settingsMap[ascii_logs];
#else
bool color = true;
#endif
// If we are the first message on a report, include the header
if (!isContinuationMessage) {
// include the header
if (color) {
if (strcmp(logLevel, MESHTASTIC_LOG_LEVEL_DEBUG) == 0)
Print::write("\u001b[34m", 6);
if (strcmp(logLevel, MESHTASTIC_LOG_LEVEL_INFO) == 0)
Print::write("\u001b[32m", 6);
if (strcmp(logLevel, MESHTASTIC_LOG_LEVEL_WARN) == 0)
Print::write("\u001b[33m", 6);
if (strcmp(logLevel, MESHTASTIC_LOG_LEVEL_ERROR) == 0)
Print::write("\u001b[31m", 6);
if (strcmp(logLevel, MESHTASTIC_LOG_LEVEL_TRACE) == 0)
Print::write("\u001b[35m", 6);
}
uint32_t rtc_sec = getValidTime(RTCQuality::RTCQualityDevice, true); // display local time on logfile
if (rtc_sec > 0) {
long hms = rtc_sec % SEC_PER_DAY;
// hms += tz.tz_dsttime * SEC_PER_HOUR;
// hms -= tz.tz_minuteswest * SEC_PER_MIN;
// mod `hms` to ensure in positive range of [0...SEC_PER_DAY)
hms = (hms + SEC_PER_DAY) % SEC_PER_DAY;
// Tear apart hms into h:m:s
int hour = hms / SEC_PER_HOUR;
int min = (hms % SEC_PER_HOUR) / SEC_PER_MIN;
int sec = (hms % SEC_PER_HOUR) % SEC_PER_MIN; // or hms % SEC_PER_MIN
#ifdef ARCH_PORTDUINO
::printf("%s ", logLevel);
if (color) {
if (strcmp(logLevel, MESHTASTIC_LOG_LEVEL_DEBUG) == 0)
Print::write("\u001b[34m", 6);
if (strcmp(logLevel, MESHTASTIC_LOG_LEVEL_INFO) == 0)
Print::write("\u001b[32m", 6);
if (strcmp(logLevel, MESHTASTIC_LOG_LEVEL_WARN) == 0)
Print::write("\u001b[33m", 6);
if (strcmp(logLevel, MESHTASTIC_LOG_LEVEL_ERROR) == 0)
Print::write("\u001b[31m", 6);
if (strcmp(logLevel, MESHTASTIC_LOG_LEVEL_TRACE) == 0)
Print::write("\u001b[35m", 6);
::printf("\u001b[0m");
}
uint32_t rtc_sec = getValidTime(RTCQuality::RTCQualityDevice, true); // display local time on logfile
if (rtc_sec > 0) {
long hms = rtc_sec % SEC_PER_DAY;
// hms += tz.tz_dsttime * SEC_PER_HOUR;
// hms -= tz.tz_minuteswest * SEC_PER_MIN;
// mod `hms` to ensure in positive range of [0...SEC_PER_DAY)
hms = (hms + SEC_PER_DAY) % SEC_PER_DAY;
// Tear apart hms into h:m:s
int hour = hms / SEC_PER_HOUR;
int min = (hms % SEC_PER_HOUR) / SEC_PER_MIN;
int sec = (hms % SEC_PER_HOUR) % SEC_PER_MIN; // or hms % SEC_PER_MIN
#ifdef ARCH_PORTDUINO
::printf("%s ", logLevel);
if (color) {
::printf("\u001b[0m");
}
::printf("| %02d:%02d:%02d %u ", hour, min, sec, millis() / 1000);
::printf("| %02d:%02d:%02d %u ", hour, min, sec, millis() / 1000);
#else
printf("%s ", logLevel);
if (color) {
printf("\u001b[0m");
}
printf("| %02d:%02d:%02d %u ", hour, min, sec, millis() / 1000);
printf("%s ", logLevel);
if (color) {
printf("\u001b[0m");
}
printf("| %02d:%02d:%02d %u ", hour, min, sec, millis() / 1000);
#endif
} else {
} else {
#ifdef ARCH_PORTDUINO
::printf("%s ", logLevel);
if (color) {
::printf("\u001b[0m");
}
::printf("| ??:??:?? %u ", millis() / 1000);
::printf("%s ", logLevel);
if (color) {
::printf("\u001b[0m");
}
::printf("| ??:??:?? %u ", millis() / 1000);
#else
printf("%s ", logLevel);
if (color) {
printf("\u001b[0m");
}
printf("| ??:??:?? %u ", millis() / 1000);
printf("%s ", logLevel);
if (color) {
printf("\u001b[0m");
}
printf("| ??:??:?? %u ", millis() / 1000);
#endif
}
auto thread = concurrency::OSThread::currentThread;
if (thread) {
print("[");
// printf("%p ", thread);
// assert(thread->ThreadName.length());
print(thread->ThreadName);
print("] ");
}
}
auto thread = concurrency::OSThread::currentThread;
if (thread) {
print("[");
// printf("%p ", thread);
// assert(thread->ThreadName.length());
print(thread->ThreadName);
print("] ");
}
r += vprintf(logLevel, format, arg);
isContinuationMessage = !hasNewline;
}
void RedirectablePrint::log_to_syslog(const char *logLevel, const char *format, va_list arg)
@ -283,6 +277,14 @@ meshtastic_LogRecord_Level RedirectablePrint::getLogLevel(const char *logLevel)
void RedirectablePrint::log(const char *logLevel, const char *format, ...)
{
// append \n to format
size_t len = strlen(format);
char *newFormat = new char[len + 2];
strcpy(newFormat, format);
newFormat[len] = '\n';
newFormat[len + 1] = '\0';
#if ARCH_PORTDUINO
// level trace is special, two possible ways to handle it.
if (strcmp(logLevel, MESHTASTIC_LOG_LEVEL_TRACE) == 0) {
@ -295,17 +297,24 @@ void RedirectablePrint::log(const char *logLevel, const char *format, ...)
}
va_end(arg);
}
if (settingsMap[logoutputlevel] < level_trace && strcmp(logLevel, MESHTASTIC_LOG_LEVEL_TRACE) == 0)
if (settingsMap[logoutputlevel] < level_trace && strcmp(logLevel, MESHTASTIC_LOG_LEVEL_TRACE) == 0) {
delete[] newFormat;
return;
}
}
if (settingsMap[logoutputlevel] < level_debug && strcmp(logLevel, MESHTASTIC_LOG_LEVEL_DEBUG) == 0)
if (settingsMap[logoutputlevel] < level_debug && strcmp(logLevel, MESHTASTIC_LOG_LEVEL_DEBUG) == 0) {
delete[] newFormat;
return;
else if (settingsMap[logoutputlevel] < level_info && strcmp(logLevel, MESHTASTIC_LOG_LEVEL_INFO) == 0)
} else if (settingsMap[logoutputlevel] < level_info && strcmp(logLevel, MESHTASTIC_LOG_LEVEL_INFO) == 0) {
delete[] newFormat;
return;
else if (settingsMap[logoutputlevel] < level_warn && strcmp(logLevel, MESHTASTIC_LOG_LEVEL_WARN) == 0)
} else if (settingsMap[logoutputlevel] < level_warn && strcmp(logLevel, MESHTASTIC_LOG_LEVEL_WARN) == 0) {
delete[] newFormat;
return;
}
#endif
if (moduleConfig.serial.override_console_serial_port && strcmp(logLevel, MESHTASTIC_LOG_LEVEL_DEBUG) == 0) {
delete[] newFormat;
return;
}
@ -319,9 +328,9 @@ void RedirectablePrint::log(const char *logLevel, const char *format, ...)
va_list arg;
va_start(arg, format);
log_to_serial(logLevel, format, arg);
log_to_syslog(logLevel, format, arg);
log_to_ble(logLevel, format, arg);
log_to_serial(logLevel, newFormat, arg);
log_to_syslog(logLevel, newFormat, arg);
log_to_ble(logLevel, newFormat, arg);
va_end(arg);
#ifdef HAS_FREE_RTOS
@ -331,17 +340,18 @@ void RedirectablePrint::log(const char *logLevel, const char *format, ...)
#endif
}
delete[] newFormat;
return;
}
void RedirectablePrint::hexDump(const char *logLevel, unsigned char *buf, uint16_t len)
{
const char alphabet[17] = "0123456789abcdef";
log(logLevel, " +------------------------------------------------+ +----------------+\n");
log(logLevel, " |.0 .1 .2 .3 .4 .5 .6 .7 .8 .9 .a .b .c .d .e .f | | ASCII |\n");
log(logLevel, " +------------------------------------------------+ +----------------+");
log(logLevel, " |.0 .1 .2 .3 .4 .5 .6 .7 .8 .9 .a .b .c .d .e .f | | ASCII |");
for (uint16_t i = 0; i < len; i += 16) {
if (i % 128 == 0)
log(logLevel, " +------------------------------------------------+ +----------------+\n");
log(logLevel, " +------------------------------------------------+ +----------------+");
char s[] = "| | | |\n";
uint8_t ix = 1, iy = 52;
for (uint8_t j = 0; j < 16; j++) {
@ -363,7 +373,7 @@ void RedirectablePrint::hexDump(const char *logLevel, unsigned char *buf, uint16
log(logLevel, ".");
log(logLevel, s);
}
log(logLevel, " +------------------------------------------------+ +----------------+\n");
log(logLevel, " +------------------------------------------------+ +----------------+");
}
std::string RedirectablePrint::mt_sprintf(const std::string fmt_str, ...)

View File

@ -15,9 +15,6 @@ class RedirectablePrint : public Print
{
Print *dest;
/// Used to allow multiple logDebug messages to appear on a single log line
bool isContinuationMessage = false;
#ifdef HAS_FREE_RTOS
SemaphoreHandle_t inDebugPrint = nullptr;
StaticSemaphore_t _MutexStorageSpace;
@ -54,9 +51,9 @@ class RedirectablePrint : public Print
protected:
/// Subclasses can override if they need to change how we format over the serial port
virtual void log_to_serial(const char *logLevel, const char *format, va_list arg);
meshtastic_LogRecord_Level getLogLevel(const char *logLevel);
private:
void log_to_syslog(const char *logLevel, const char *format, va_list arg);
void log_to_ble(const char *logLevel, const char *format, va_list arg);
meshtastic_LogRecord_Level getLogLevel(const char *logLevel);
};

View File

@ -59,14 +59,14 @@ bool SafeFile::close()
// brief window of risk here ;-)
if (fullAtomic && FSCom.exists(filename.c_str()) && !FSCom.remove(filename.c_str())) {
LOG_ERROR("Can't remove old pref file\n");
LOG_ERROR("Can't remove old pref file");
return false;
}
String filenameTmp = filename;
filenameTmp += ".tmp";
if (!renameFile(filenameTmp.c_str(), filename.c_str())) {
LOG_ERROR("Error: can't rename new pref file\n");
LOG_ERROR("Error: can't rename new pref file");
return false;
}
@ -83,7 +83,7 @@ bool SafeFile::testReadback()
filenameTmp += ".tmp";
auto f2 = FSCom.open(filenameTmp.c_str(), FILE_O_READ);
if (!f2) {
LOG_ERROR("Can't open tmp file for readback\n");
LOG_ERROR("Can't open tmp file for readback");
return false;
}
@ -95,7 +95,7 @@ bool SafeFile::testReadback()
f2.close();
if (test_hash != hash) {
LOG_ERROR("Readback failed hash mismatch\n");
LOG_ERROR("Readback failed hash mismatch");
return false;
}

View File

@ -99,25 +99,7 @@ bool SerialConsole::handleToRadio(const uint8_t *buf, size_t len)
void SerialConsole::log_to_serial(const char *logLevel, const char *format, va_list arg)
{
if (usingProtobufs && config.security.debug_log_api_enabled) {
meshtastic_LogRecord_Level ll = meshtastic_LogRecord_Level_UNSET; // default to unset
switch (logLevel[0]) {
case 'D':
ll = meshtastic_LogRecord_Level_DEBUG;
break;
case 'I':
ll = meshtastic_LogRecord_Level_INFO;
break;
case 'W':
ll = meshtastic_LogRecord_Level_WARNING;
break;
case 'E':
ll = meshtastic_LogRecord_Level_ERROR;
break;
case 'C':
ll = meshtastic_LogRecord_Level_CRITICAL;
break;
}
meshtastic_LogRecord_Level ll = RedirectablePrint::getLogLevel(logLevel);
auto thread = concurrency::OSThread::currentThread;
emitLogRecord(ll, thread ? thread->ThreadName.c_str() : "", format, arg);
} else

View File

@ -13,17 +13,17 @@ void AirTime::logAirtime(reportTypes reportType, uint32_t airtime_ms)
{
if (reportType == TX_LOG) {
LOG_DEBUG("Packet transmitted : %ums\n", airtime_ms);
LOG_DEBUG("Packet TX: %ums", airtime_ms);
this->airtimes.periodTX[0] = this->airtimes.periodTX[0] + airtime_ms;
air_period_tx[0] = air_period_tx[0] + airtime_ms;
this->utilizationTX[this->getPeriodUtilHour()] = this->utilizationTX[this->getPeriodUtilHour()] + airtime_ms;
} else if (reportType == RX_LOG) {
LOG_DEBUG("Packet received : %ums\n", airtime_ms);
LOG_DEBUG("Packet RX: %ums", airtime_ms);
this->airtimes.periodRX[0] = this->airtimes.periodRX[0] + airtime_ms;
air_period_rx[0] = air_period_rx[0] + airtime_ms;
} else if (reportType == RX_ALL_LOG) {
LOG_DEBUG("Packet received (noise?) : %ums\n", airtime_ms);
LOG_DEBUG("Packet RX (noise?) : %ums", airtime_ms);
this->airtimes.periodRX_ALL[0] = this->airtimes.periodRX_ALL[0] + airtime_ms;
}
@ -50,7 +50,7 @@ void AirTime::airtimeRotatePeriod()
{
if (this->airtimes.lastPeriodIndex != this->currentPeriodIndex()) {
LOG_DEBUG("Rotating airtimes to a new period = %u\n", this->currentPeriodIndex());
LOG_DEBUG("Rotate airtimes to a new period = %u", this->currentPeriodIndex());
for (int i = PERIODS_TO_LOG - 2; i >= 0; --i) {
this->airtimes.periodTX[i + 1] = this->airtimes.periodTX[i];
@ -105,7 +105,6 @@ float AirTime::channelUtilizationPercent()
uint32_t sum = 0;
for (uint32_t i = 0; i < CHANNEL_UTILIZATION_PERIODS; i++) {
sum += this->channelUtilization[i];
// LOG_DEBUG("ChanUtilArray %u %u\n", i, this->channelUtilization[i]);
}
return (float(sum) / float(CHANNEL_UTILIZATION_PERIODS * 10 * 1000)) * 100;
@ -127,7 +126,7 @@ bool AirTime::isTxAllowedChannelUtil(bool polite)
if (channelUtilizationPercent() < percentage) {
return true;
} else {
LOG_WARN("Channel utilization is >%d percent. Skipping this opportunity to send.\n", percentage);
LOG_WARN("Ch. util >%d%%. Skip send", percentage);
return false;
}
}
@ -138,8 +137,7 @@ bool AirTime::isTxAllowedAirUtil()
if (utilizationTXPercent() < myRegion->dutyCycle * polite_duty_cycle_percent / 100) {
return true;
} else {
LOG_WARN("Tx air utilization is >%f percent. Skipping this opportunity to send.\n",
myRegion->dutyCycle * polite_duty_cycle_percent / 100);
LOG_WARN("TX air util. >%f%%. Skip send", myRegion->dutyCycle * polite_duty_cycle_percent / 100);
return false;
}
}
@ -208,14 +206,5 @@ int32_t AirTime::runOnce()
this->utilizationTX[utilPeriodTX] = 0;
}
}
/*
LOG_DEBUG("utilPeriodTX %d TX Airtime %3.2f%\n", utilPeriodTX, airTime->utilizationTXPercent());
for (uint32_t i = 0; i < MINUTES_IN_HOUR; i++) {
LOG_DEBUG(
"%d,", this->utilizationTX[i]
);
}
LOG_DEBUG("\n");
*/
return (1000 * 1);
}
}

View File

@ -55,6 +55,18 @@ void playBeep()
playTones(melody, sizeof(melody) / sizeof(ToneDuration));
}
void playGPSEnableBeep()
{
ToneDuration melody[] = {{NOTE_C3, DURATION_1_8}, {NOTE_FS3, DURATION_1_4}, {NOTE_CS4, DURATION_1_4}};
playTones(melody, sizeof(melody) / sizeof(ToneDuration));
}
void playGPSDisableBeep()
{
ToneDuration melody[] = {{NOTE_CS4, DURATION_1_8}, {NOTE_FS3, DURATION_1_4}, {NOTE_C3, DURATION_1_4}};
playTones(melody, sizeof(melody) / sizeof(ToneDuration));
}
void playStartMelody()
{
ToneDuration melody[] = {{NOTE_FS3, DURATION_1_8}, {NOTE_AS3, DURATION_1_8}, {NOTE_CS4, DURATION_1_4}};

View File

@ -3,3 +3,5 @@
void playBeep();
void playStartMelody();
void playShutdownMelody();
void playGPSEnableBeep();
void playGPSDisableBeep();

View File

@ -18,7 +18,7 @@ bool InterruptableDelay::delay(uint32_t msec)
// sem take will return false if we timed out (i.e. were not interrupted)
bool r = semaphore.take(msec);
// LOG_DEBUG("interrupt=%d\n", r);
// LOG_DEBUG("interrupt=%d", r);
return !r;
}

View File

@ -32,12 +32,12 @@ IRAM_ATTR bool NotifiedWorkerThread::notifyCommon(uint32_t v, bool overwrite)
notification = v;
if (debugNotification) {
LOG_DEBUG("setting notification %d\n", v);
LOG_DEBUG("Set notification %d", v);
}
return true;
} else {
if (debugNotification) {
LOG_DEBUG("dropping notification %d\n", v);
LOG_DEBUG("Drop notification %d", v);
}
return false;
}
@ -67,7 +67,7 @@ bool NotifiedWorkerThread::notifyLater(uint32_t delay, uint32_t v, bool overwrit
if (didIt) { // If we didn't already have something queued, override the delay to be larger
setIntervalFromNow(delay); // a new version of setInterval relative to the current time
if (debugNotification) {
LOG_DEBUG("delaying notification %u\n", delay);
LOG_DEBUG("Delay notification %u", delay);
}
}

View File

@ -62,15 +62,15 @@ bool OSThread::shouldRun(unsigned long time)
bool r = Thread::shouldRun(time);
if (showRun && r) {
LOG_DEBUG("Thread %s: run\n", ThreadName.c_str());
LOG_DEBUG("Thread %s: run", ThreadName.c_str());
}
if (showWaiting && enabled && !r) {
LOG_DEBUG("Thread %s: wait %lu\n", ThreadName.c_str(), interval);
LOG_DEBUG("Thread %s: wait %lu", ThreadName.c_str(), interval);
}
if (showDisabled && !enabled) {
LOG_DEBUG("Thread %s: disabled\n", ThreadName.c_str());
LOG_DEBUG("Thread %s: disabled", ThreadName.c_str());
}
return r;
@ -86,9 +86,9 @@ void OSThread::run()
#ifdef DEBUG_HEAP
auto newHeap = memGet.getFreeHeap();
if (newHeap < heap)
LOG_DEBUG("------ Thread %s leaked heap %d -> %d (%d) ------\n", ThreadName.c_str(), heap, newHeap, newHeap - heap);
LOG_DEBUG("------ Thread %s leaked heap %d -> %d (%d) ------", ThreadName.c_str(), heap, newHeap, newHeap - heap);
if (heap < newHeap)
LOG_DEBUG("++++++ Thread %s freed heap %d -> %d (%d) ++++++\n", ThreadName.c_str(), heap, newHeap, newHeap - heap);
LOG_DEBUG("++++++ Thread %s freed heap %d -> %d (%d) ++++++", ThreadName.c_str(), heap, newHeap, newHeap - heap);
#endif
runned();

View File

@ -114,6 +114,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#define CARDKB_ADDR 0x5F
#define TDECK_KB_ADDR 0x55
#define BBQ10_KB_ADDR 0x1F
#define MPR121_KB_ADDR 0x5A
// -----------------------------------------------------------------------------
// SENSOR
@ -135,6 +136,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#define LPS22HB_ADDR_ALT 0x5D
#define SHT31_4x_ADDR 0x44
#define PMSA0031_ADDR 0x12
#define QMA6100P_ADDR 0x12
#define AHT10_ADDR 0x38
#define RCWL9620_ADDR 0x57
#define VEML7700_ADDR 0x10
@ -146,13 +148,15 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#define NAU7802_ADDR 0x2A
#define MAX30102_ADDR 0x57
#define MLX90614_ADDR_DEF 0x5A
#define CGRADSENS_ADDR 0x66
// -----------------------------------------------------------------------------
// ACCELEROMETER
// -----------------------------------------------------------------------------
#define MPU6050_ADDR 0x68
#define STK8BXX_ADR 0x18
#define LIS3DH_ADR 0x18
#define STK8BXX_ADDR 0x18
#define LIS3DH_ADDR 0x18
#define LIS3DH_ADDR_ALT 0x19
#define BMA423_ADDR 0x19
#define LSM6DS3_ADDR 0x6A
#define BMX160_ADDR 0x69
@ -167,7 +171,6 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
// -----------------------------------------------------------------------------
// Security
// -----------------------------------------------------------------------------
#define ATECC608B_ADDR 0x35
// -----------------------------------------------------------------------------
// IO Expander
@ -205,6 +208,9 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#ifndef GPS_BAUDRATE
#define GPS_BAUDRATE 9600
#define GPS_BAUDRATE_FIXED 0
#else
#define GPS_BAUDRATE_FIXED 1
#endif
/* Step #2: follow with defines common to the architecture;
@ -355,4 +361,4 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#endif
#include "DebugConfiguration.h"
#include "RF95Configuration.h"
#include "RF95Configuration.h"

View File

@ -31,14 +31,14 @@ ScanI2C::FoundDevice ScanI2C::firstRTC() const
ScanI2C::FoundDevice ScanI2C::firstKeyboard() const
{
ScanI2C::DeviceType types[] = {CARDKB, TDECKKB, BBQ10KB, RAK14004};
return firstOfOrNONE(4, types);
ScanI2C::DeviceType types[] = {CARDKB, TDECKKB, BBQ10KB, RAK14004, MPR121KB};
return firstOfOrNONE(5, types);
}
ScanI2C::FoundDevice ScanI2C::firstAccelerometer() const
{
ScanI2C::DeviceType types[] = {MPU6050, LIS3DH, BMA423, LSM6DS3, BMX160, STK8BAXX, ICM20948};
return firstOfOrNONE(7, types);
ScanI2C::DeviceType types[] = {MPU6050, LIS3DH, BMA423, LSM6DS3, BMX160, STK8BAXX, ICM20948, QMA6100P};
return firstOfOrNONE(8, types);
}
ScanI2C::FoundDevice ScanI2C::find(ScanI2C::DeviceType) const

View File

@ -12,7 +12,6 @@ class ScanI2C
SCREEN_SH1106,
SCREEN_UNKNOWN, // has the same address as the two above but does not respond to the same commands
SCREEN_ST7567,
ATECC608B,
RTC_RV3028,
RTC_PCF8563,
CARDKB,
@ -39,6 +38,7 @@ class ScanI2C
QMC5883L,
HMC5883L,
PMSA0031,
QMA6100P,
MPU6050,
LIS3DH,
BMA423,
@ -61,7 +61,9 @@ class ScanI2C
STK8BAXX,
ICM20948,
MAX30102,
TPS65233
TPS65233,
MPR121KB,
CGRADSENS
} DeviceType;
// typedef uint8_t DeviceAddress;

View File

@ -7,7 +7,7 @@
#include "linux/LinuxHardwareI2C.h"
#endif
#if !defined(ARCH_PORTDUINO) && !defined(ARCH_STM32WL)
#include "main.h" // atecc
#include "meshUtils.h" // vformat
#endif
// AXP192 and AXP2101 have the same device address, we just need to identify it in Power.cpp
@ -71,52 +71,18 @@ ScanI2C::DeviceType ScanI2CTwoWire::probeOLED(ScanI2C::DeviceAddress addr) const
r &= 0x0f;
if (r == 0x08 || r == 0x00) {
LOG_INFO("sh1106 display found\n");
logFoundDevice("SH1106", (uint8_t)addr.address);
o_probe = SCREEN_SH1106; // SH1106
} else if (r == 0x03 || r == 0x04 || r == 0x06 || r == 0x07) {
LOG_INFO("ssd1306 display found\n");
logFoundDevice("SSD1306", (uint8_t)addr.address);
o_probe = SCREEN_SSD1306; // SSD1306
}
c++;
} while ((r != r_prev) && (c < 4));
LOG_DEBUG("0x%x subtype probed in %i tries \n", r, c);
LOG_DEBUG("0x%x subtype probed in %i tries ", r, c);
return o_probe;
}
void ScanI2CTwoWire::printATECCInfo() const
{
#if !defined(ARCH_PORTDUINO) && !defined(ARCH_STM32WL)
atecc.readConfigZone(false);
LOG_DEBUG("ATECC608B Serial Number: ");
for (int i = 0; i < 9; i++) {
LOG_DEBUG("%02x", atecc.serialNumber[i]);
}
LOG_DEBUG(", Rev Number: ");
for (int i = 0; i < 4; i++) {
LOG_DEBUG("%02x", atecc.revisionNumber[i]);
}
LOG_DEBUG("\n");
LOG_DEBUG("ATECC608B Config %s", atecc.configLockStatus ? "Locked" : "Unlocked");
LOG_DEBUG(", Data %s", atecc.dataOTPLockStatus ? "Locked" : "Unlocked");
LOG_DEBUG(", Slot 0 %s\n", atecc.slot0LockStatus ? "Locked" : "Unlocked");
if (atecc.configLockStatus && atecc.dataOTPLockStatus && atecc.slot0LockStatus) {
if (atecc.generatePublicKey() == false) {
LOG_DEBUG("ATECC608B Error generating public key\n");
} else {
LOG_DEBUG("ATECC608B Public Key: ");
for (int i = 0; i < 64; i++) {
LOG_DEBUG("%02x", atecc.publicKey64Bytes[i]);
}
LOG_DEBUG("\n");
}
}
#endif
}
uint16_t ScanI2CTwoWire::getRegisterValue(const ScanI2CTwoWire::RegisterLocation &registerLocation,
ScanI2CTwoWire::ResponseWidth responseWidth) const
{
@ -128,7 +94,6 @@ uint16_t ScanI2CTwoWire::getRegisterValue(const ScanI2CTwoWire::RegisterLocation
i2cBus->endTransmission();
delay(20);
i2cBus->requestFrom(registerLocation.i2cAddress.address, responseWidth);
LOG_DEBUG("Wire.available() = %d\n", i2cBus->available());
if (i2cBus->available() == 2) {
// Read MSB, then LSB
value = (uint16_t)i2cBus->read() << 8;
@ -141,7 +106,7 @@ uint16_t ScanI2CTwoWire::getRegisterValue(const ScanI2CTwoWire::RegisterLocation
#define SCAN_SIMPLE_CASE(ADDR, T, ...) \
case ADDR: \
LOG_INFO(__VA_ARGS__); \
logFoundDevice(__VA_ARGS__); \
type = T; \
break;
@ -149,7 +114,7 @@ void ScanI2CTwoWire::scanPort(I2CPort port, uint8_t *address, uint8_t asize)
{
concurrency::LockGuard guard((concurrency::Lock *)&lock);
LOG_DEBUG("Scanning for I2C devices on port %d\n", port);
LOG_DEBUG("Scan for I2C devices on port %d", port);
uint8_t err;
@ -172,11 +137,20 @@ void ScanI2CTwoWire::scanPort(I2CPort port, uint8_t *address, uint8_t asize)
}
#endif
for (addr.address = 1; addr.address < 127; addr.address++) {
// We only need to scan 112 addresses, the rest is reserved for special purposes
// 0x00 General Call
// 0x01 CBUS addresses
// 0x02 Reserved for different bus formats
// 0x03 Reserved for future purposes
// 0x04-0x07 High Speed Master Code
// 0x78-0x7B 10-bit slave addressing
// 0x7C-0x7F Reserved for future purposes
for (addr.address = 8; addr.address < 120; addr.address++) {
if (asize != 0) {
if (!in_array(address, asize, addr.address))
if (!in_array(address, asize, (uint8_t)addr.address))
continue;
LOG_DEBUG("Scanning address 0x%x\n", addr.address);
LOG_DEBUG("Scan address 0x%x", (uint8_t)addr.address);
}
i2cBus->beginTransmission(addr.address);
#ifdef ARCH_PORTDUINO
@ -189,35 +163,16 @@ void ScanI2CTwoWire::scanPort(I2CPort port, uint8_t *address, uint8_t asize)
#endif
type = NONE;
if (err == 0) {
LOG_DEBUG("I2C device found at address 0x%x\n", addr.address);
switch (addr.address) {
case SSD1306_ADDRESS:
type = probeOLED(addr);
break;
#if !defined(ARCH_PORTDUINO) && !defined(ARCH_STM32WL)
case ATECC608B_ADDR:
#ifdef RP2040_SLOW_CLOCK
if (atecc.begin(addr.address, Wire, Serial2) == true)
#else
if (atecc.begin(addr.address) == true)
#endif
{
LOG_INFO("ATECC608B initialized\n");
} else {
LOG_WARN("ATECC608B initialization failed\n");
}
printATECCInfo();
break;
#endif
#ifdef RV3028_RTC
case RV3028_RTC:
// foundDevices[addr] = RTC_RV3028;
type = RTC_RV3028;
LOG_INFO("RV3028 RTC found\n");
logFoundDevice("RV3028", (uint8_t)addr.address);
rtc.initI2C(*i2cBus);
rtc.writeToRegister(0x35, 0x07); // no Clkout
rtc.writeToRegister(0x37, 0xB4);
@ -225,7 +180,7 @@ void ScanI2CTwoWire::scanPort(I2CPort port, uint8_t *address, uint8_t asize)
#endif
#ifdef PCF8563_RTC
SCAN_SIMPLE_CASE(PCF8563_RTC, RTC_PCF8563, "PCF8563 RTC found\n")
SCAN_SIMPLE_CASE(PCF8563_RTC, RTC_PCF8563, "PCF8563", (uint8_t)addr.address)
#endif
case CARDKB_ADDR:
@ -233,49 +188,50 @@ void ScanI2CTwoWire::scanPort(I2CPort port, uint8_t *address, uint8_t asize)
registerValue = getRegisterValue(ScanI2CTwoWire::RegisterLocation(addr, 0x04), 1);
if (registerValue == 0x02) {
// KEYPAD_VERSION
LOG_INFO("RAK14004 found\n");
logFoundDevice("RAK14004", (uint8_t)addr.address);
type = RAK14004;
} else {
LOG_INFO("m5 cardKB found\n");
logFoundDevice("M5 cardKB", (uint8_t)addr.address);
type = CARDKB;
}
break;
SCAN_SIMPLE_CASE(TDECK_KB_ADDR, TDECKKB, "T-Deck keyboard found\n");
SCAN_SIMPLE_CASE(BBQ10_KB_ADDR, BBQ10KB, "BB Q10 keyboard found\n");
SCAN_SIMPLE_CASE(ST7567_ADDRESS, SCREEN_ST7567, "st7567 display found\n");
SCAN_SIMPLE_CASE(TDECK_KB_ADDR, TDECKKB, "T-Deck keyboard", (uint8_t)addr.address);
SCAN_SIMPLE_CASE(BBQ10_KB_ADDR, BBQ10KB, "BB Q10", (uint8_t)addr.address);
SCAN_SIMPLE_CASE(ST7567_ADDRESS, SCREEN_ST7567, "ST7567", (uint8_t)addr.address);
#ifdef HAS_NCP5623
SCAN_SIMPLE_CASE(NCP5623_ADDR, NCP5623, "NCP5623 RGB LED found\n");
SCAN_SIMPLE_CASE(NCP5623_ADDR, NCP5623, "NCP5623", (uint8_t)addr.address);
#endif
#ifdef HAS_PMU
SCAN_SIMPLE_CASE(XPOWERS_AXP192_AXP2101_ADDRESS, PMU_AXP192_AXP2101, "axp192/axp2101 PMU found\n")
SCAN_SIMPLE_CASE(XPOWERS_AXP192_AXP2101_ADDRESS, PMU_AXP192_AXP2101, "AXP192/AXP2101", (uint8_t)addr.address)
#endif
case BME_ADDR:
case BME_ADDR_ALTERNATE:
registerValue = getRegisterValue(ScanI2CTwoWire::RegisterLocation(addr, 0xD0), 1); // GET_ID
switch (registerValue) {
case 0x61:
LOG_INFO("BME-680 sensor found at address 0x%x\n", (uint8_t)addr.address);
logFoundDevice("BME680", (uint8_t)addr.address);
type = BME_680;
break;
case 0x60:
LOG_INFO("BME-280 sensor found at address 0x%x\n", (uint8_t)addr.address);
logFoundDevice("BME280", (uint8_t)addr.address);
type = BME_280;
break;
case 0x55:
LOG_INFO("BMP-085 or BMP-180 sensor found at address 0x%x\n", (uint8_t)addr.address);
logFoundDevice("BMP085/BMP180", (uint8_t)addr.address);
type = BMP_085;
break;
default:
registerValue = getRegisterValue(ScanI2CTwoWire::RegisterLocation(addr, 0x00), 1); // GET_ID
switch (registerValue) {
case 0x50: // BMP-388 should be 0x50
LOG_INFO("BMP-388 sensor found at address 0x%x\n", (uint8_t)addr.address);
logFoundDevice("BMP-388", (uint8_t)addr.address);
type = BMP_3XX;
break;
case 0x58: // BMP-280 should be 0x58
default:
LOG_INFO("BMP-280 sensor found at address 0x%x\n", (uint8_t)addr.address);
logFoundDevice("BMP-280", (uint8_t)addr.address);
type = BMP_280;
break;
}
@ -284,7 +240,7 @@ void ScanI2CTwoWire::scanPort(I2CPort port, uint8_t *address, uint8_t asize)
break;
#ifndef HAS_NCP5623
case AHT10_ADDR:
LOG_INFO("AHT10 sensor found at address 0x%x\n", (uint8_t)addr.address);
logFoundDevice("AHT10", (uint8_t)addr.address);
type = AHT10;
break;
#endif
@ -292,43 +248,59 @@ void ScanI2CTwoWire::scanPort(I2CPort port, uint8_t *address, uint8_t asize)
case INA_ADDR_ALTERNATE:
case INA_ADDR_WAVESHARE_UPS:
registerValue = getRegisterValue(ScanI2CTwoWire::RegisterLocation(addr, 0xFE), 2);
LOG_DEBUG("Register MFG_UID: 0x%x\n", registerValue);
LOG_DEBUG("Register MFG_UID: 0x%x", registerValue);
if (registerValue == 0x5449) {
LOG_INFO("INA260 sensor found at address 0x%x\n", (uint8_t)addr.address);
logFoundDevice("INA260", (uint8_t)addr.address);
type = INA260;
} else { // Assume INA219 if INA260 ID is not found
LOG_INFO("INA219 sensor found at address 0x%x\n", (uint8_t)addr.address);
logFoundDevice("INA219", (uint8_t)addr.address);
type = INA219;
}
break;
case INA3221_ADDR:
registerValue = getRegisterValue(ScanI2CTwoWire::RegisterLocation(addr, 0xFE), 2);
LOG_DEBUG("Register MFG_UID: 0x%x\n", registerValue);
LOG_DEBUG("Register MFG_UID FE: 0x%x", registerValue);
if (registerValue == 0x5449) {
LOG_INFO("INA3221 sensor found at address 0x%x\n", (uint8_t)addr.address);
logFoundDevice("INA3221", (uint8_t)addr.address);
type = INA3221;
} else {
LOG_INFO("DFRobot Lark weather station found at address 0x%x\n", (uint8_t)addr.address);
type = DFROBOT_LARK;
/* check the first 2 bytes of the 6 byte response register
LARK FW 1.0 should return:
RESPONSE_STATUS STATUS_SUCCESS (0x53)
RESPONSE_CMD CMD_GET_VERSION (0x05)
RESPONSE_LEN_L 0x02
RESPONSE_LEN_H 0x00
RESPONSE_PAYLOAD 0x01
RESPONSE_PAYLOAD+1 0x00
*/
registerValue = getRegisterValue(ScanI2CTwoWire::RegisterLocation(addr, 0x05), 2);
LOG_DEBUG("Register MFG_UID 05: 0x%x", registerValue);
if (registerValue == 0x5305) {
logFoundDevice("DFRobot Lark", (uint8_t)addr.address);
type = DFROBOT_LARK;
}
// else: probably a RAK12500/UBLOX GPS on I2C
}
break;
case MCP9808_ADDR:
// We need to check for STK8BAXX first, since register 0x07 is new data flag for the z-axis and can produce some
// weird result. and register 0x00 doesn't seems to be colliding with MCP9808 and LIS3DH chips.
{
#ifdef HAS_STK8XXX
// Check register 0x00 for 0x8700 response to ID STK8BA53 chip.
registerValue = getRegisterValue(ScanI2CTwoWire::RegisterLocation(addr, 0x00), 2);
if (registerValue == 0x8700) {
type = STK8BAXX;
LOG_INFO("STK8BAXX accelerometer found\n");
logFoundDevice("STK8BAXX", (uint8_t)addr.address);
break;
}
#endif
// Check register 0x07 for 0x0400 response to ID MCP9808 chip.
registerValue = getRegisterValue(ScanI2CTwoWire::RegisterLocation(addr, 0x07), 2);
if (registerValue == 0x0400) {
type = MCP9808;
LOG_INFO("MCP9808 sensor found\n");
logFoundDevice("MCP9808", (uint8_t)addr.address);
break;
}
@ -336,7 +308,7 @@ void ScanI2CTwoWire::scanPort(I2CPort port, uint8_t *address, uint8_t asize)
registerValue = getRegisterValue(ScanI2CTwoWire::RegisterLocation(addr, 0x0F), 2);
if (registerValue == 0x3300 || registerValue == 0x3333) { // RAK4631 WisBlock has LIS3DH register at 0x3333
type = LIS3DH;
LOG_INFO("LIS3DH accelerometer found\n");
logFoundDevice("LIS3DH", (uint8_t)addr.address);
}
break;
}
@ -344,95 +316,128 @@ void ScanI2CTwoWire::scanPort(I2CPort port, uint8_t *address, uint8_t asize)
registerValue = getRegisterValue(ScanI2CTwoWire::RegisterLocation(addr, 0x89), 2);
if (registerValue == 0x11a2 || registerValue == 0x11da || registerValue == 0xe9c) {
type = SHT4X;
LOG_INFO("SHT4X sensor found\n");
logFoundDevice("SHT4X", (uint8_t)addr.address);
} else if (getRegisterValue(ScanI2CTwoWire::RegisterLocation(addr, 0x7E), 2) == 0x5449) {
type = OPT3001;
LOG_INFO("OPT3001 light sensor found\n");
logFoundDevice("OPT3001", (uint8_t)addr.address);
} else {
type = SHT31;
LOG_INFO("SHT31 sensor found\n");
logFoundDevice("SHT31", (uint8_t)addr.address);
}
break;
SCAN_SIMPLE_CASE(SHTC3_ADDR, SHTC3, "SHTC3 sensor found\n")
SCAN_SIMPLE_CASE(SHTC3_ADDR, SHTC3, "SHTC3", (uint8_t)addr.address)
case RCWL9620_ADDR:
// get MAX30102 PARTID
registerValue = getRegisterValue(ScanI2CTwoWire::RegisterLocation(addr, 0xFF), 1);
if (registerValue == 0x15) {
type = MAX30102;
LOG_INFO("MAX30102 Health sensor found\n");
logFoundDevice("MAX30102", (uint8_t)addr.address);
break;
} else {
type = RCWL9620;
LOG_INFO("RCWL9620 sensor found\n");
logFoundDevice("RCWL9620", (uint8_t)addr.address);
}
break;
case LPS22HB_ADDR_ALT:
SCAN_SIMPLE_CASE(LPS22HB_ADDR, LPS22HB, "LPS22HB sensor found\n")
SCAN_SIMPLE_CASE(QMC6310_ADDR, QMC6310, "QMC6310 Highrate 3-Axis magnetic sensor found\n")
SCAN_SIMPLE_CASE(LPS22HB_ADDR, LPS22HB, "LPS22HB", (uint8_t)addr.address)
SCAN_SIMPLE_CASE(QMC6310_ADDR, QMC6310, "QMC6310", (uint8_t)addr.address)
case QMI8658_ADDR:
registerValue = getRegisterValue(ScanI2CTwoWire::RegisterLocation(addr, 0x0A), 1); // get ID
if (registerValue == 0xC0) {
type = BQ24295;
LOG_INFO("BQ24295 PMU found\n");
logFoundDevice("BQ24295", (uint8_t)addr.address);
break;
}
registerValue = getRegisterValue(ScanI2CTwoWire::RegisterLocation(addr, 0x0F), 1); // get ID
if (registerValue == 0x6A) {
type = LSM6DS3;
LOG_INFO("LSM6DS3 accelerometer found at address 0x%x\n", (uint8_t)addr.address);
logFoundDevice("LSM6DS3", (uint8_t)addr.address);
} else {
type = QMI8658;
LOG_INFO("QMI8658 Highrate 6-Axis inertial measurement sensor found\n");
logFoundDevice("QMI8658", (uint8_t)addr.address);
}
break;
SCAN_SIMPLE_CASE(QMC5883L_ADDR, QMC5883L, "QMC5883L Highrate 3-Axis magnetic sensor found\n")
SCAN_SIMPLE_CASE(HMC5883L_ADDR, HMC5883L, "HMC5883L 3-Axis digital compass found\n")
SCAN_SIMPLE_CASE(PMSA0031_ADDR, PMSA0031, "PMSA0031 air quality sensor found\n")
SCAN_SIMPLE_CASE(BMA423_ADDR, BMA423, "BMA423 accelerometer found\n");
SCAN_SIMPLE_CASE(LSM6DS3_ADDR, LSM6DS3, "LSM6DS3 accelerometer found at address 0x%x\n", (uint8_t)addr.address);
SCAN_SIMPLE_CASE(TCA9535_ADDR, TCA9535, "TCA9535 I2C expander found\n");
SCAN_SIMPLE_CASE(TCA9555_ADDR, TCA9555, "TCA9555 I2C expander found\n");
SCAN_SIMPLE_CASE(VEML7700_ADDR, VEML7700, "VEML7700 light sensor found\n");
SCAN_SIMPLE_CASE(TSL25911_ADDR, TSL2591, "TSL2591 light sensor found\n");
SCAN_SIMPLE_CASE(OPT3001_ADDR, OPT3001, "OPT3001 light sensor found\n");
SCAN_SIMPLE_CASE(MLX90632_ADDR, MLX90632, "MLX90632 IR temp sensor found\n");
SCAN_SIMPLE_CASE(NAU7802_ADDR, NAU7802, "NAU7802 based scale found\n");
SCAN_SIMPLE_CASE(FT6336U_ADDR, FT6336U, "FT6336U touchscreen found\n");
SCAN_SIMPLE_CASE(MAX1704X_ADDR, MAX17048, "MAX17048 lipo fuel gauge found\n");
#ifdef HAS_TPS65233
SCAN_SIMPLE_CASE(TPS65233_ADDR, TPS65233, "TPS65233 BIAS-T found\n");
SCAN_SIMPLE_CASE(QMC5883L_ADDR, QMC5883L, "QMC5883L", (uint8_t)addr.address)
SCAN_SIMPLE_CASE(HMC5883L_ADDR, HMC5883L, "HMC5883L", (uint8_t)addr.address)
#ifdef HAS_QMA6100P
SCAN_SIMPLE_CASE(QMA6100P_ADDR, QMA6100P, "QMA6100P", (uint8_t)addr.address)
#else
SCAN_SIMPLE_CASE(PMSA0031_ADDR, PMSA0031, "PMSA0031", (uint8_t)addr.address)
#endif
SCAN_SIMPLE_CASE(MLX90614_ADDR_DEF, MLX90614, "MLX90614 IR temp sensor found\n");
case BMA423_ADDR: // this can also be LIS3DH_ADDR_ALT
registerValue = getRegisterValue(ScanI2CTwoWire::RegisterLocation(addr, 0x0F), 2);
if (registerValue == 0x3300 || registerValue == 0x3333) { // RAK4631 WisBlock has LIS3DH register at 0x3333
type = LIS3DH;
logFoundDevice("LIS3DH", (uint8_t)addr.address);
} else {
type = BMA423;
logFoundDevice("BMA423", (uint8_t)addr.address);
}
break;
SCAN_SIMPLE_CASE(LSM6DS3_ADDR, LSM6DS3, "LSM6DS3", (uint8_t)addr.address);
SCAN_SIMPLE_CASE(TCA9535_ADDR, TCA9535, "TCA9535", (uint8_t)addr.address);
SCAN_SIMPLE_CASE(TCA9555_ADDR, TCA9555, "TCA9555", (uint8_t)addr.address);
SCAN_SIMPLE_CASE(VEML7700_ADDR, VEML7700, "VEML7700", (uint8_t)addr.address);
SCAN_SIMPLE_CASE(TSL25911_ADDR, TSL2591, "TSL2591", (uint8_t)addr.address);
SCAN_SIMPLE_CASE(OPT3001_ADDR, OPT3001, "OPT3001", (uint8_t)addr.address);
SCAN_SIMPLE_CASE(MLX90632_ADDR, MLX90632, "MLX90632", (uint8_t)addr.address);
SCAN_SIMPLE_CASE(NAU7802_ADDR, NAU7802, "NAU7802", (uint8_t)addr.address);
SCAN_SIMPLE_CASE(FT6336U_ADDR, FT6336U, "FT6336U", (uint8_t)addr.address);
SCAN_SIMPLE_CASE(MAX1704X_ADDR, MAX17048, "MAX17048", (uint8_t)addr.address);
#ifdef HAS_TPS65233
SCAN_SIMPLE_CASE(TPS65233_ADDR, TPS65233, "TPS65233", (uint8_t)addr.address);
#endif
case MLX90614_ADDR_DEF:
registerValue = getRegisterValue(ScanI2CTwoWire::RegisterLocation(addr, 0x0e), 1);
if (registerValue == 0x5a) {
type = MLX90614;
logFoundDevice("MLX90614", (uint8_t)addr.address);
} else {
type = MPR121KB;
logFoundDevice("MPR121KB", (uint8_t)addr.address);
}
break;
case ICM20948_ADDR: // same as BMX160_ADDR
case ICM20948_ADDR_ALT: // same as MPU6050_ADDR
registerValue = getRegisterValue(ScanI2CTwoWire::RegisterLocation(addr, 0x00), 1);
if (registerValue == 0xEA) {
type = ICM20948;
LOG_INFO("ICM20948 9-dof motion processor found\n");
logFoundDevice("ICM20948", (uint8_t)addr.address);
break;
} else if (addr.address == BMX160_ADDR) {
type = BMX160;
LOG_INFO("BMX160 accelerometer found\n");
logFoundDevice("BMX160", (uint8_t)addr.address);
break;
} else {
type = MPU6050;
LOG_INFO("MPU6050 accelerometer found\n");
logFoundDevice("MPU6050", (uint8_t)addr.address);
break;
}
break;
case CGRADSENS_ADDR:
// Register 0x00 of the RadSens sensor contains is product identifier 0x7D
registerValue = getRegisterValue(ScanI2CTwoWire::RegisterLocation(addr, 0x00), 1);
if (registerValue == 0x7D) {
type = CGRADSENS;
logFoundDevice("ClimateGuard RadSens", (uint8_t)addr.address);
break;
}
break;
default:
LOG_INFO("Device found at address 0x%x was not able to be enumerated\n", addr.address);
LOG_INFO("Device found at address 0x%x was not able to be enumerated", (uint8_t)addr.address);
}
} else if (err == 4) {
LOG_ERROR("Unknown error at address 0x%x\n", addr.address);
LOG_ERROR("Unknown error at address 0x%x", (uint8_t)addr.address);
}
// Check if a type was found for the enumerated device - save, if so
@ -465,4 +470,9 @@ size_t ScanI2CTwoWire::countDevices() const
{
return foundDevices.size();
}
void ScanI2CTwoWire::logFoundDevice(const char *device, uint8_t address)
{
LOG_INFO("%s found at address 0x%x", device, address);
}
#endif

View File

@ -53,10 +53,10 @@ class ScanI2CTwoWire : public ScanI2C
concurrency::Lock lock;
void printATECCInfo() const;
uint16_t getRegisterValue(const RegisterLocation &, ResponseWidth) const;
DeviceType probeOLED(ScanI2C::DeviceAddress) const;
static void logFoundDevice(const char *device, uint8_t address);
};
#endif

View File

@ -1,19 +0,0 @@
#if 0
// Turn off for now
uint32_t axpDebugRead()
{
axp.debugCharging();
LOG_DEBUG("vbus current %f\n", axp.getVbusCurrent());
LOG_DEBUG("charge current %f\n", axp.getBattChargeCurrent());
LOG_DEBUG("bat voltage %f\n", axp.getBattVoltage());
LOG_DEBUG("batt pct %d\n", axp.getBattPercentage());
LOG_DEBUG("is battery connected %d\n", axp.isBatteryConnect());
LOG_DEBUG("is USB connected %d\n", axp.isVBUSPlug());
LOG_DEBUG("is charging %d\n", axp.isChargeing());
return 30 * 1000;
}
Periodic axpDebugOutput(axpDebugRead);
axpDebugOutput.setup();
#endif

View File

@ -59,9 +59,9 @@ void scanEInkDevice(void)
d_writeCommand(0x20);
eink_found = (d_waitWhileBusy(150) > 0) ? true : false;
if (eink_found)
LOG_DEBUG("EInk display found\n");
LOG_DEBUG("EInk display found");
else
LOG_DEBUG("EInk display not found\n");
LOG_DEBUG("EInk display not found");
SPI1.end();
}
#endif

File diff suppressed because it is too large Load Diff

View File

@ -16,13 +16,6 @@
#define GPS_EN_ACTIVE 1
#endif
struct uBloxGnssModelInfo {
char swVersion[30];
char hwVersion[10];
uint8_t extensionNo;
char extension[10][30];
};
typedef enum {
GNSS_MODEL_ATGM336H,
GNSS_MODEL_MTK,
@ -34,6 +27,7 @@ typedef enum {
GNSS_MODEL_UC6580,
GNSS_MODEL_UNKNOWN,
GNSS_MODEL_MTK_L76B,
GNSS_MODEL_MTK_PA1616S,
GNSS_MODEL_AG3335,
GNSS_MODEL_AG3352
} GnssModel_t;
@ -53,9 +47,6 @@ enum GPSPowerState : uint8_t {
GPS_OFF // Powered off indefinitely
};
// Generate a string representation of DOP
const char *getDOPString(uint32_t dop);
/**
* A gps class that only reads from the GPS periodically and keeps the gps powered down except when reading
*
@ -63,101 +54,7 @@ const char *getDOPString(uint32_t dop);
*/
class GPS : private concurrency::OSThread
{
TinyGPSPlus reader;
uint8_t fixQual = 0; // fix quality from GPGGA
uint32_t lastChecksumFailCount = 0;
#ifndef TINYGPS_OPTION_NO_CUSTOM_FIELDS
// (20210908) TinyGps++ can only read the GPGSA "FIX TYPE" field
// via optional feature "custom fields", currently disabled (bug #525)
TinyGPSCustom gsafixtype; // custom extract fix type from GPGSA
TinyGPSCustom gsapdop; // custom extract PDOP from GPGSA
uint8_t fixType = 0; // fix type from GPGSA
#endif
private:
const int serialSpeeds[6] = {9600, 4800, 38400, 57600, 115200, 9600};
uint32_t lastWakeStartMsec = 0, lastSleepStartMsec = 0, lastFixStartMsec = 0;
uint32_t rx_gpio = 0;
uint32_t tx_gpio = 0;
int speedSelect = 0;
int probeTries = 2;
/**
* hasValidLocation - indicates that the position variables contain a complete
* GPS location, valid and fresh (< gps_update_interval + position_broadcast_secs)
*/
bool hasValidLocation = false; // default to false, until we complete our first read
bool isInPowersave = false;
bool shouldPublish = false; // If we've changed GPS state, this will force a publish the next loop()
bool hasGPS = false; // Do we have a GPS we are talking to
bool GPSInitFinished = false; // Init thread finished?
bool GPSInitStarted = false; // Init thread finished?
GPSPowerState powerState = GPS_OFF; // GPS_ACTIVE if we want a location right now
uint8_t numSatellites = 0;
CallbackObserver<GPS, void *> notifyDeepSleepObserver = CallbackObserver<GPS, void *>(this, &GPS::prepareDeepSleep);
public:
/** If !NULL we will use this serial port to construct our GPS */
#if defined(ARCH_RP2040)
static SerialUART *_serial_gps;
#else
static HardwareSerial *_serial_gps;
#endif
static uint8_t _message_PMREQ[];
static uint8_t _message_PMREQ_10[];
static const uint8_t _message_CFG_RXM_PSM[];
static const uint8_t _message_CFG_RXM_ECO[];
static const uint8_t _message_CFG_PM2[];
static const uint8_t _message_GNSS_7[];
static const uint8_t _message_GNSS_8[];
static const uint8_t _message_JAM_6_7[];
static const uint8_t _message_JAM_8[];
static const uint8_t _message_NAVX5[];
static const uint8_t _message_NAVX5_8[];
static const uint8_t _message_NMEA[];
static const uint8_t _message_DISABLE_TXT_INFO[];
static const uint8_t _message_1HZ[];
static const uint8_t _message_GLL[];
static const uint8_t _message_GSA[];
static const uint8_t _message_GSV[];
static const uint8_t _message_VTG[];
static const uint8_t _message_RMC[];
static const uint8_t _message_AID[];
static const uint8_t _message_GGA[];
static const uint8_t _message_PMS[];
static const uint8_t _message_SAVE[];
static const uint8_t _message_SAVE_10[];
// VALSET Commands for M10
static const uint8_t _message_VALSET_PM[];
static const uint8_t _message_VALSET_PM_RAM[];
static const uint8_t _message_VALSET_PM_BBR[];
static const uint8_t _message_VALSET_ITFM_RAM[];
static const uint8_t _message_VALSET_ITFM_BBR[];
static const uint8_t _message_VALSET_DISABLE_NMEA_RAM[];
static const uint8_t _message_VALSET_DISABLE_NMEA_BBR[];
static const uint8_t _message_VALSET_DISABLE_TXT_INFO_RAM[];
static const uint8_t _message_VALSET_DISABLE_TXT_INFO_BBR[];
static const uint8_t _message_VALSET_ENABLE_NMEA_RAM[];
static const uint8_t _message_VALSET_ENABLE_NMEA_BBR[];
static const uint8_t _message_VALSET_DISABLE_SBAS_RAM[];
static const uint8_t _message_VALSET_DISABLE_SBAS_BBR[];
// CASIC commands for ATGM336H
static const uint8_t _message_CAS_CFG_RST_FACTORY[];
static const uint8_t _message_CAS_CFG_NAVX_CONF[];
static const uint8_t _message_CAS_CFG_RATE_1HZ[];
const char *ACK_SUCCESS_MESSAGE = "Get ack success!\n";
meshtastic_Position p = meshtastic_Position_init_default;
/** This is normally bound to config.position.gps_en_gpio but some rare boards (like heltec tracker) need more advanced
@ -167,8 +64,6 @@ class GPS : private concurrency::OSThread
*/
GpioVirtPin *enablePin = NULL;
GPS() : concurrency::OSThread("GPS") {}
virtual ~GPS();
/** We will notify this observable anytime GPS state has changed meaningfully */
@ -205,21 +100,6 @@ class GPS : private concurrency::OSThread
// Empty the input buffer as quickly as possible
void clearBuffer();
// Create a ublox packet for editing in memory
uint8_t makeUBXPacket(uint8_t class_id, uint8_t msg_id, uint8_t payload_size, const uint8_t *msg);
uint8_t makeCASPacket(uint8_t class_id, uint8_t msg_id, uint8_t payload_size, const uint8_t *msg);
// scratch space for creating ublox packets
uint8_t UBXscratch[250] = {0};
int rebootsSeen = 0;
int getACK(uint8_t *buffer, uint16_t size, uint8_t requestedClass, uint8_t requestedID, uint32_t waitMillis);
GPS_RESPONSE getACK(uint8_t c, uint8_t i, uint32_t waitMillis);
GPS_RESPONSE getACK(const char *message, uint32_t waitMillis);
GPS_RESPONSE getACKCas(uint8_t class_id, uint8_t msg_id, uint32_t waitMillis);
virtual bool factoryReset();
// Creates an instance of the GPS class.
@ -232,20 +112,8 @@ class GPS : private concurrency::OSThread
// Let the GPS hardware save power between updates
void down();
protected:
/**
* Perform any processing that should be done only while the GPS is awake and looking for a fix.
* Override this method to check for new locations
*
* @return true if we've acquired a time
*/
/**
* Perform any processing that should be done only while the GPS is awake and looking for a fix.
* Override this method to check for new locations
*
* @return true if we've acquired a new location
*/
private:
GPS() : concurrency::OSThread("GPS") {}
/// Record that we have a GPS
void setConnected();
@ -272,15 +140,74 @@ class GPS : private concurrency::OSThread
*/
virtual bool lookForLocation();
private:
GnssModel_t gnssModel = GNSS_MODEL_UNKNOWN;
TinyGPSPlus reader;
uint8_t fixQual = 0; // fix quality from GPGGA
uint32_t lastChecksumFailCount = 0;
#ifndef TINYGPS_OPTION_NO_CUSTOM_FIELDS
// (20210908) TinyGps++ can only read the GPGSA "FIX TYPE" field
// via optional feature "custom fields", currently disabled (bug #525)
TinyGPSCustom gsafixtype; // custom extract fix type from GPGSA
TinyGPSCustom gsapdop; // custom extract PDOP from GPGSA
uint8_t fixType = 0; // fix type from GPGSA
#endif
uint32_t lastWakeStartMsec = 0, lastSleepStartMsec = 0, lastFixStartMsec = 0;
uint32_t rx_gpio = 0;
uint32_t tx_gpio = 0;
uint8_t speedSelect = 0;
uint8_t probeTries = 0;
/**
* hasValidLocation - indicates that the position variables contain a complete
* GPS location, valid and fresh (< gps_update_interval + position_broadcast_secs)
*/
bool hasValidLocation = false; // default to false, until we complete our first read
bool isInPowersave = false;
bool shouldPublish = false; // If we've changed GPS state, this will force a publish the next loop()
bool hasGPS = false; // Do we have a GPS we are talking to
bool GPSInitFinished = false; // Init thread finished?
bool GPSInitStarted = false; // Init thread finished?
GPSPowerState powerState = GPS_OFF; // GPS_ACTIVE if we want a location right now
uint8_t numSatellites = 0;
CallbackObserver<GPS, void *> notifyDeepSleepObserver = CallbackObserver<GPS, void *>(this, &GPS::prepareDeepSleep);
/** If !NULL we will use this serial port to construct our GPS */
#if defined(ARCH_RP2040)
static SerialUART *_serial_gps;
#else
static HardwareSerial *_serial_gps;
#endif
// Create a ublox packet for editing in memory
uint8_t makeUBXPacket(uint8_t class_id, uint8_t msg_id, uint8_t payload_size, const uint8_t *msg);
uint8_t makeCASPacket(uint8_t class_id, uint8_t msg_id, uint8_t payload_size, const uint8_t *msg);
// scratch space for creating ublox packets
uint8_t UBXscratch[250] = {0};
int rebootsSeen = 0;
int getACK(uint8_t *buffer, uint16_t size, uint8_t requestedClass, uint8_t requestedID, uint32_t waitMillis);
GPS_RESPONSE getACK(uint8_t c, uint8_t i, uint32_t waitMillis);
GPS_RESPONSE getACK(const char *message, uint32_t waitMillis);
GPS_RESPONSE getACKCas(uint8_t class_id, uint8_t msg_id, uint32_t waitMillis);
/// Prepare the GPS for the cpu entering deep sleep, expect to be gone for at least 100s of msecs
/// always returns 0 to indicate okay to sleep
int prepareDeepSleep(void *unused);
// Calculate checksum
void UBXChecksum(uint8_t *message, size_t length);
void CASChecksum(uint8_t *message, size_t length);
/** Set power with EN pin, if relevant
*/
void writePinEN(bool on);
@ -309,11 +236,6 @@ class GPS : private concurrency::OSThread
// delay counter to allow more sats before fixed position stops GPS thread
uint8_t fixeddelayCtr = 0;
const char *powerStateToString();
protected:
GnssModel_t gnssModel = GNSS_MODEL_UNKNOWN;
};
extern GPS *gps;

View File

@ -13,7 +13,7 @@ void GPSUpdateScheduling::informSearching()
void GPSUpdateScheduling::informGotLock()
{
searchEndedMs = millis();
LOG_DEBUG("Took %us to get lock\n", (searchEndedMs - searchStartedMs) / 1000);
LOG_DEBUG("Took %us to get lock", (searchEndedMs - searchStartedMs) / 1000);
updateLockTimePrediction();
}
@ -49,7 +49,7 @@ uint32_t GPSUpdateScheduling::msUntilNextSearch()
}
// How long have we already been searching?
// Used to abort a search in progress, if it runs unnaceptably long
// Used to abort a search in progress, if it runs unacceptably long
uint32_t GPSUpdateScheduling::elapsedSearchMs()
{
// If searching
@ -70,9 +70,9 @@ bool GPSUpdateScheduling::isUpdateDue()
// Have we been searching for a GPS position for too long?
bool GPSUpdateScheduling::searchedTooLong()
{
uint32_t maxSearchMs =
Default::getConfiguredOrDefaultMs(config.position.position_broadcast_secs, default_broadcast_interval_secs);
uint32_t minimumOrConfiguredSecs =
Default::getConfiguredOrMinimumValue(config.position.position_broadcast_secs, default_broadcast_interval_secs);
uint32_t maxSearchMs = Default::getConfiguredOrDefaultMs(minimumOrConfiguredSecs, default_broadcast_interval_secs);
// If broadcast interval set to max, no such thing as "too long"
if (maxSearchMs == UINT32_MAX)
return false;
@ -98,7 +98,7 @@ void GPSUpdateScheduling::updateLockTimePrediction()
// Ignore the first lock-time: likely to be long, will skew data
// Second locktime: likely stable. Use to intialize the smoothing filter
// Second locktime: likely stable. Use to initialize the smoothing filter
if (searchCount == 1)
predictedMsToGetLock = lockTime;
@ -106,13 +106,13 @@ void GPSUpdateScheduling::updateLockTimePrediction()
else if (searchCount > 1)
predictedMsToGetLock = (lockTime * weighting) + (predictedMsToGetLock * (1 - weighting));
searchCount++; // Only tracked so we can diregard initial lock-times
searchCount++; // Only tracked so we can disregard initial lock-times
LOG_DEBUG("Predicting %us to get next lock\n", predictedMsToGetLock / 1000);
LOG_DEBUG("Predict %us to get next lock", predictedMsToGetLock / 1000);
}
// How long do we expect to spend searching for a lock?
uint32_t GPSUpdateScheduling::predictedSearchDurationMs()
{
return GPSUpdateScheduling::predictedMsToGetLock;
}
}

View File

@ -574,3 +574,23 @@ const char *GeoCoord::degreesToBearing(unsigned int degrees)
else
return "N";
}
double GeoCoord::pow_neg(double base, double exponent)
{
if (exponent == 0) {
return 1;
} else if (exponent > 0) {
return pow(base, exponent);
}
return 1 / pow(base, -exponent);
}
double GeoCoord::toRadians(double deg)
{
return deg * PI / 180;
}
double GeoCoord::toDegrees(double r)
{
return r * 180 / PI;
}

View File

@ -13,28 +13,6 @@
#define OLC_CODE_LEN 11
#define DEG_CONVERT (180 / PI)
// Helper functions
// Raises a number to an exponent, handling negative exponents.
static inline double pow_neg(double base, double exponent)
{
if (exponent == 0) {
return 1;
} else if (exponent > 0) {
return pow(base, exponent);
}
return 1 / pow(base, -exponent);
}
static inline double toRadians(double deg)
{
return deg * PI / 180;
}
static inline double toDegrees(double r)
{
return r * 180 / PI;
}
// GeoCoord structs/classes
// A struct to hold the data for a DMS coordinate.
struct DMS {
@ -120,6 +98,11 @@ class GeoCoord
static unsigned int bearingToDegrees(const char *bearing);
static const char *degreesToBearing(unsigned int degrees);
// Raises a number to an exponent, handling negative exponents.
static double pow_neg(double base, double exponent);
static double toRadians(double deg);
static double toDegrees(double r);
// Point to point conversions
int32_t distanceTo(const GeoCoord &pointB);
int32_t bearingTo(const GeoCoord &pointB);
@ -162,4 +145,4 @@ class GeoCoord
// OLC getter
void getOLCCode(char *code) { strncpy(code, _olc.code, OLC_CODE_LEN + 1); } // +1 for null termination
};
};

View File

@ -23,7 +23,7 @@ uint32_t printWPL(char *buf, size_t bufsz, const meshtastic_PositionLite &pos, c
{
GeoCoord geoCoord(pos.latitude_i, pos.longitude_i, pos.altitude);
char type = isCaltopoMode ? 'P' : 'N';
uint32_t len = snprintf(buf, bufsz, "$G%cWPL,%02d%07.4f,%c,%03d%07.4f,%c,%s", type, geoCoord.getDMSLatDeg(),
uint32_t len = snprintf(buf, bufsz, "\r\n$G%cWPL,%02d%07.4f,%c,%03d%07.4f,%c,%s", type, geoCoord.getDMSLatDeg(),
(abs(geoCoord.getLatitude()) - geoCoord.getDMSLatDeg() * 1e+7) * 6e-6, geoCoord.getDMSLatCP(),
geoCoord.getDMSLonDeg(), (abs(geoCoord.getLongitude()) - geoCoord.getDMSLonDeg() * 1e+7) * 6e-6,
geoCoord.getDMSLonCP(), name);

View File

@ -46,7 +46,7 @@ void readFromRTC()
tv.tv_usec = 0;
uint32_t printableEpoch = tv.tv_sec; // Print lib only supports 32 bit but time_t can be 64 bit on some platforms
LOG_DEBUG("Read RTC time from RV3028 getTime as %02d-%02d-%02d %02d:%02d:%02d (%ld)\n", t.tm_year + 1900, t.tm_mon + 1,
LOG_DEBUG("Read RTC time from RV3028 getTime as %02d-%02d-%02d %02d:%02d:%02d (%ld)", t.tm_year + 1900, t.tm_mon + 1,
t.tm_mday, t.tm_hour, t.tm_min, t.tm_sec, printableEpoch);
timeStartMsec = now;
zeroOffsetSecs = tv.tv_sec;
@ -77,8 +77,8 @@ void readFromRTC()
tv.tv_usec = 0;
uint32_t printableEpoch = tv.tv_sec; // Print lib only supports 32 bit but time_t can be 64 bit on some platforms
LOG_DEBUG("Read RTC time from PCF8563 getDateTime as %02d-%02d-%02d %02d:%02d:%02d (%ld)\n", t.tm_year + 1900,
t.tm_mon + 1, t.tm_mday, t.tm_hour, t.tm_min, t.tm_sec, printableEpoch);
LOG_DEBUG("Read RTC time from PCF8563 getDateTime as %02d-%02d-%02d %02d:%02d:%02d (%ld)", t.tm_year + 1900, t.tm_mon + 1,
t.tm_mday, t.tm_hour, t.tm_min, t.tm_sec, printableEpoch);
timeStartMsec = now;
zeroOffsetSecs = tv.tv_sec;
if (currentQuality == RTCQualityNone) {
@ -89,7 +89,7 @@ void readFromRTC()
if (!gettimeofday(&tv, NULL)) {
uint32_t now = millis();
uint32_t printableEpoch = tv.tv_sec; // Print lib only supports 32 bit but time_t can be 64 bit on some platforms
LOG_DEBUG("Read RTC time as %ld\n", printableEpoch);
LOG_DEBUG("Read RTC time as %ld", printableEpoch);
timeStartMsec = now;
zeroOffsetSecs = tv.tv_sec;
}
@ -112,7 +112,7 @@ bool perhapsSetRTC(RTCQuality q, const struct timeval *tv, bool forceUpdate)
uint32_t printableEpoch = tv->tv_sec; // Print lib only supports 32 bit but time_t can be 64 bit on some platforms
#ifdef BUILD_EPOCH
if (tv->tv_sec < BUILD_EPOCH) {
LOG_WARN("Ignoring time (%ld) before build epoch (%ld)!\n", printableEpoch, BUILD_EPOCH);
LOG_WARN("Ignore time (%ld) before build epoch (%ld)!", printableEpoch, BUILD_EPOCH);
return false;
}
#endif
@ -120,21 +120,21 @@ bool perhapsSetRTC(RTCQuality q, const struct timeval *tv, bool forceUpdate)
bool shouldSet;
if (forceUpdate) {
shouldSet = true;
LOG_DEBUG("Overriding current RTC quality (%s) with incoming time of RTC quality of %s\n", RtcName(currentQuality),
LOG_DEBUG("Override current RTC quality (%s) with incoming time of RTC quality of %s", RtcName(currentQuality),
RtcName(q));
} else if (q > currentQuality) {
shouldSet = true;
LOG_DEBUG("Upgrading time to quality %s\n", RtcName(q));
LOG_DEBUG("Upgrade time to quality %s", RtcName(q));
} else if (q == RTCQualityGPS) {
shouldSet = true;
LOG_DEBUG("Reapplying GPS time: %ld secs\n", printableEpoch);
LOG_DEBUG("Reapply GPS time: %ld secs", printableEpoch);
} else if (q == RTCQualityNTP && !Throttle::isWithinTimespanMs(lastSetMsec, (12 * 60 * 60 * 1000UL))) {
// Every 12 hrs we will slam in a new NTP or Phone GPS / NTP time, to correct for local RTC clock drift
shouldSet = true;
LOG_DEBUG("Reapplying external time to correct clock drift %ld secs\n", printableEpoch);
LOG_DEBUG("Reapply external time to correct clock drift %ld secs", printableEpoch);
} else {
shouldSet = false;
LOG_DEBUG("Current RTC quality: %s. Ignoring time of RTC quality of %s\n", RtcName(currentQuality), RtcName(q));
LOG_DEBUG("Current RTC quality: %s. Ignore time of RTC quality of %s", RtcName(currentQuality), RtcName(q));
}
if (shouldSet) {
@ -158,7 +158,7 @@ bool perhapsSetRTC(RTCQuality q, const struct timeval *tv, bool forceUpdate)
#endif
tm *t = gmtime(&tv->tv_sec);
rtc.setTime(t->tm_year + 1900, t->tm_mon + 1, t->tm_wday, t->tm_mday, t->tm_hour, t->tm_min, t->tm_sec);
LOG_DEBUG("RV3028_RTC setTime %02d-%02d-%02d %02d:%02d:%02d (%ld)\n", t->tm_year + 1900, t->tm_mon + 1, t->tm_mday,
LOG_DEBUG("RV3028_RTC setTime %02d-%02d-%02d %02d:%02d:%02d (%ld)", t->tm_year + 1900, t->tm_mon + 1, t->tm_mday,
t->tm_hour, t->tm_min, t->tm_sec, printableEpoch);
}
#elif defined(PCF8563_RTC)
@ -172,8 +172,8 @@ bool perhapsSetRTC(RTCQuality q, const struct timeval *tv, bool forceUpdate)
#endif
tm *t = gmtime(&tv->tv_sec);
rtc.setDateTime(t->tm_year + 1900, t->tm_mon + 1, t->tm_mday, t->tm_hour, t->tm_min, t->tm_sec);
LOG_DEBUG("PCF8563_RTC setDateTime %02d-%02d-%02d %02d:%02d:%02d (%ld)\n", t->tm_year + 1900, t->tm_mon + 1,
t->tm_mday, t->tm_hour, t->tm_min, t->tm_sec, printableEpoch);
LOG_DEBUG("PCF8563_RTC setDateTime %02d-%02d-%02d %02d:%02d:%02d (%ld)", t->tm_year + 1900, t->tm_mon + 1, t->tm_mday,
t->tm_hour, t->tm_min, t->tm_sec, printableEpoch);
}
#elif defined(ARCH_ESP32)
settimeofday(tv, NULL);
@ -228,9 +228,9 @@ bool perhapsSetRTC(RTCQuality q, struct tm &t)
tv.tv_sec = res;
tv.tv_usec = 0; // time.centisecond() * (10 / 1000);
// LOG_DEBUG("Got time from GPS month=%d, year=%d, unixtime=%ld\n", t.tm_mon, t.tm_year, tv.tv_sec);
// LOG_DEBUG("Got time from GPS month=%d, year=%d, unixtime=%ld", t.tm_mon, t.tm_year, tv.tv_sec);
if (t.tm_year < 0 || t.tm_year >= 300) {
// LOG_DEBUG("Ignoring invalid GPS month=%d, year=%d, unixtime=%ld\n", t.tm_mon, t.tm_year, tv.tv_sec);
// LOG_DEBUG("Ignore invalid GPS month=%d, year=%d, unixtime=%ld", t.tm_mon, t.tm_year, tv.tv_sec);
return false;
} else {
return perhapsSetRTC(q, &tv);

View File

@ -21,7 +21,7 @@
// CFG-RST (0x06, 0x02)
// Factory reset
const uint8_t GPS::_message_CAS_CFG_RST_FACTORY[] = {
static const uint8_t _message_CAS_CFG_RST_FACTORY[] = {
0xFF, 0x03, // Fields to clear
0x01, // Reset Mode: Controlled Software reset
0x03 // Startup Mode: Factory
@ -30,7 +30,7 @@ const uint8_t GPS::_message_CAS_CFG_RST_FACTORY[] = {
// CFG_RATE (0x06, 0x01)
// 1HZ update rate, this should always be the case after
// factory reset but update it regardless
const uint8_t GPS::_message_CAS_CFG_RATE_1HZ[] = {
static const uint8_t _message_CAS_CFG_RATE_1HZ[] = {
0xE8, 0x03, // Update Rate: 0x03E8 = 1000ms
0x00, 0x00 // Reserved
};
@ -39,7 +39,7 @@ const uint8_t GPS::_message_CAS_CFG_RATE_1HZ[] = {
// Initial ATGM33H-5N configuration, Updates for Dynamic Mode, Fix Mode, and SV system
// Qwirk: The ATGM33H-5N-31 should only support GPS+BDS, however it will happily enable
// and use GPS+BDS+GLONASS iff the correct CFG_NAVX command is used.
const uint8_t GPS::_message_CAS_CFG_NAVX_CONF[] = {
static const uint8_t _message_CAS_CFG_NAVX_CONF[] = {
0x03, 0x01, 0x00, 0x00, // Update Mask: Dynamic Mode, Fix Mode, Nav Settings
0x03, // Dynamic Mode: Automotive
0x03, // Fix Mode: Auto 2D/3D
@ -60,4 +60,4 @@ const uint8_t GPS::_message_CAS_CFG_NAVX_CONF[] = {
0x00, 0x00, 0x00, 0x00, // Position Accuracy Max
0x00, 0x00, 0x00, 0x00, // Time Accuracy Max
0x00, 0x00, 0x00, 0x00 // Static Hold Threshold
};
};

View File

@ -1,20 +1,22 @@
const char *failMessage = "Unable to %s\n";
static const char *failMessage = "Unable to %s";
#define SEND_UBX_PACKET(TYPE, ID, DATA, ERRMSG, TIMEOUT) \
msglen = makeUBXPacket(TYPE, ID, sizeof(DATA), DATA); \
_serial_gps->write(UBXscratch, msglen); \
if (getACK(TYPE, ID, TIMEOUT) != GNSS_RESPONSE_OK) { \
LOG_WARN(failMessage, #ERRMSG); \
}
do { \
msglen = makeUBXPacket(TYPE, ID, sizeof(DATA), DATA); \
_serial_gps->write(UBXscratch, msglen); \
if (getACK(TYPE, ID, TIMEOUT) != GNSS_RESPONSE_OK) { \
LOG_WARN(failMessage, #ERRMSG); \
} \
} while (0)
// Power Management
uint8_t GPS::_message_PMREQ[] PROGMEM = {
static uint8_t _message_PMREQ[] PROGMEM = {
0x00, 0x00, 0x00, 0x00, // 4 bytes duration of request task (milliseconds)
0x02, 0x00, 0x00, 0x00 // Bitfield, set backup = 1
};
uint8_t GPS::_message_PMREQ_10[] PROGMEM = {
static uint8_t _message_PMREQ_10[] PROGMEM = {
0x00, // version (0 for this version)
0x00, 0x00, 0x00, // Reserved 1
0x00, 0x00, 0x00, 0x00, // 4 bytes duration of request task (milliseconds)
@ -22,18 +24,18 @@ uint8_t GPS::_message_PMREQ_10[] PROGMEM = {
0x08, 0x00, 0x00, 0x00 // wakeupSources Wake on uartrx
};
const uint8_t GPS::_message_CFG_RXM_PSM[] PROGMEM = {
static const uint8_t _message_CFG_RXM_PSM[] PROGMEM = {
0x08, // Reserved
0x01 // Power save mode
};
// only for Neo-6
const uint8_t GPS::_message_CFG_RXM_ECO[] PROGMEM = {
static const uint8_t _message_CFG_RXM_ECO[] PROGMEM = {
0x08, // Reserved
0x04 // eco mode
};
const uint8_t GPS::_message_CFG_PM2[] PROGMEM = {
static const uint8_t _message_CFG_PM2[] PROGMEM = {
0x01, // version
0x00, // Reserved 1, set to 0x06 by u-Center
0x00, // Reserved 2
@ -58,7 +60,7 @@ const uint8_t GPS::_message_CFG_PM2[] PROGMEM = {
// Constallation setup, none required for Neo-6
// For Neo-7 GPS & SBAS
const uint8_t GPS::_message_GNSS_7[] = {
static const uint8_t _message_GNSS_7[] = {
0x00, // msgVer (0 for this version)
0x00, // numTrkChHw (max number of hardware channels, read only, so it's always 0)
0xff, // numTrkChUse (max number of channels to use, 0xff = max available)
@ -76,7 +78,7 @@ const uint8_t GPS::_message_GNSS_7[] = {
// There is also a possibility that the module may be GPS-only.
// For M8 GPS, GLONASS, Galileo, SBAS, QZSS
const uint8_t GPS::_message_GNSS_8[] = {
static const uint8_t _message_GNSS_8[] = {
0x00, // msgVer (0 for this version)
0x00, // numTrkChHw (max number of hardware channels, read only, so it's always 0)
0xff, // numTrkChUse (max number of channels to use, 0xff = max available)
@ -90,7 +92,7 @@ const uint8_t GPS::_message_GNSS_8[] = {
};
/*
// For M8 GPS, GLONASS, BeiDou, SBAS, QZSS
const uint8_t GPS::_message_GNSS_8_B[] = {
static const uint8_t _message_GNSS_8_B[] = {
0x00, // msgVer (0 for this version)
0x00, // numTrkChHw (max number of hardware channels, read only, so it's always 0)
0xff, // numTrkChUse (max number of channels to use, 0xff = max available) read only for protocol >23
@ -105,7 +107,7 @@ const uint8_t GPS::_message_GNSS_8_B[] = {
*/
// For M8 we want to enable NMEA version 4.10 messages to allow for Galileo and or BeiDou
const uint8_t GPS::_message_NMEA[]{
static const uint8_t _message_NMEA[]{
0x00, // filter flags
0x41, // NMEA Version
0x00, // Max number of SVs to report per TaklerId
@ -121,13 +123,13 @@ const uint8_t GPS::_message_NMEA[]{
// Enable jamming/interference monitor
// For Neo-6, Max-7 and Neo-7
const uint8_t GPS::_message_JAM_6_7[] = {
static const uint8_t _message_JAM_6_7[] = {
0xf3, 0xac, 0x62, 0xad, // config1 bbThreshold = 3, cwThreshold = 15, enable = 1, reserved bits 0x16B156
0x1e, 0x03, 0x00, 0x00 // config2 antennaSetting Unknown = 0, reserved 3, = 0x00,0x00, reserved 2 = 0x31E
};
// For M8
const uint8_t GPS::_message_JAM_8[] = {
static const uint8_t _message_JAM_8[] = {
0xf3, 0xac, 0x62, 0xad, // config1 bbThreshold = 3, cwThreshold = 15, enable1 = 1, reserved bits 0x16B156
0x1e, 0x43, 0x00, 0x00 // config2 antennaSetting Unknown = 0, enable2 = 1, generalBits = 0x31E
};
@ -137,7 +139,7 @@ const uint8_t GPS::_message_JAM_8[] = {
// ToDo: check UBX-MON-VER for module type and protocol version
// For the Neo-6
const uint8_t GPS::_message_NAVX5[] = {
static const uint8_t _message_NAVX5[] = {
0x00, 0x00, // msgVer (0 for this version)
0x4c, 0x66, // mask1
0x00, 0x00, 0x00, 0x00, // Reserved 0
@ -166,7 +168,7 @@ const uint8_t GPS::_message_NAVX5[] = {
0x00, 0x00, 0x00, 0x00 // Reserved 4
};
// For the M8
const uint8_t GPS::_message_NAVX5_8[] = {
static const uint8_t _message_NAVX5_8[] = {
0x02, 0x00, // msgVer (2 for this version)
0x4c, 0x66, // mask1
0x00, 0x00, 0x00, 0x00, // mask2
@ -197,7 +199,7 @@ const uint8_t GPS::_message_NAVX5_8[] = {
// Additionally, for some new modules like the M9/M10, an update rate lower than 5Hz
// is recommended to avoid a known issue with satellites disappearing.
// The module defaults for M8, M9, M10 are the same as we use here so no update is necessary
const uint8_t GPS::_message_1HZ[] = {
static const uint8_t _message_1HZ[] = {
0xE8, 0x03, // Measurement Rate (1000ms for 1Hz)
0x01, 0x00, // Navigation rate, always 1 in GPS mode
0x01, 0x00 // Time reference
@ -205,7 +207,7 @@ const uint8_t GPS::_message_1HZ[] = {
// Disable GLL. GLL - Geographic position (latitude and longitude), which provides the current geographical
// coordinates.
const uint8_t GPS::_message_GLL[] = {
static const uint8_t _message_GLL[] = {
0xF0, 0x01, // NMEA ID for GLL
0x00, // Rate for DDC
0x00, // Rate for UART1
@ -217,7 +219,7 @@ const uint8_t GPS::_message_GLL[] = {
// Disable GSA. GSA - GPS DOP and active satellites, used for detailing the satellites used in the positioning and
// the DOP (Dilution of Precision)
const uint8_t GPS::_message_GSA[] = {
static const uint8_t _message_GSA[] = {
0xF0, 0x02, // NMEA ID for GSA
0x00, // Rate for DDC
0x00, // Rate for UART1
@ -228,7 +230,7 @@ const uint8_t GPS::_message_GSA[] = {
};
// Disable GSV. GSV - Satellites in view, details the number and location of satellites in view.
const uint8_t GPS::_message_GSV[] = {
static const uint8_t _message_GSV[] = {
0xF0, 0x03, // NMEA ID for GSV
0x00, // Rate for DDC
0x00, // Rate for UART1
@ -240,7 +242,7 @@ const uint8_t GPS::_message_GSV[] = {
// Disable VTG. VTG - Track made good and ground speed, which provides course and speed information relative to
// the ground.
const uint8_t GPS::_message_VTG[] = {
static const uint8_t _message_VTG[] = {
0xF0, 0x05, // NMEA ID for VTG
0x00, // Rate for DDC
0x00, // Rate for UART1
@ -251,7 +253,7 @@ const uint8_t GPS::_message_VTG[] = {
};
// Enable RMC. RMC - Recommended Minimum data, the essential gps pvt (position, velocity, time) data.
const uint8_t GPS::_message_RMC[] = {
static const uint8_t _message_RMC[] = {
0xF0, 0x04, // NMEA ID for RMC
0x00, // Rate for DDC
0x01, // Rate for UART1
@ -262,7 +264,7 @@ const uint8_t GPS::_message_RMC[] = {
};
// Enable GGA. GGA - Global Positioning System Fix Data, which provides 3D location and accuracy data.
const uint8_t GPS::_message_GGA[] = {
static const uint8_t _message_GGA[] = {
0xF0, 0x00, // NMEA ID for GGA
0x00, // Rate for DDC
0x01, // Rate for UART1
@ -274,7 +276,7 @@ const uint8_t GPS::_message_GGA[] = {
// Disable UBX-AID-ALPSRV as it may confuse TinyGPS. The Neo-6 seems to send this message
// whether the AID Autonomous is enabled or not
const uint8_t GPS::_message_AID[] = {
static const uint8_t _message_AID[] = {
0x0B, 0x32, // NMEA ID for UBX-AID-ALPSRV
0x00, // Rate for DDC
0x00, // Rate for UART1
@ -287,7 +289,7 @@ const uint8_t GPS::_message_AID[] = {
// Turn off TEXT INFO Messages for all but M10 series
// B5 62 06 02 0A 00 01 00 00 00 03 03 00 03 03 00 1F 20
const uint8_t GPS::_message_DISABLE_TXT_INFO[] = {
static const uint8_t _message_DISABLE_TXT_INFO[] = {
0x01, // Protocol ID for NMEA
0x00, 0x00, 0x00, // Reserved
0x03, // I2C
@ -310,7 +312,7 @@ const uint8_t GPS::_message_DISABLE_TXT_INFO[] = {
// and must be smaller than the period. It is only valid when the powerSetupValue is set to Interval; otherwise,
// it must be set to '0'.
// This command applies to M8 products
const uint8_t GPS::_message_PMS[] = {
static const uint8_t _message_PMS[] = {
0x00, // Version (0)
0x03, // Power setup value 3 = Agresssive 1Hz
0x00, 0x00, // period: not applicable, set to 0
@ -318,14 +320,14 @@ const uint8_t GPS::_message_PMS[] = {
0x00, 0x00 // reserved, generated by u-center
};
const uint8_t GPS::_message_SAVE[] = {
static const uint8_t _message_SAVE[] = {
0x00, 0x00, 0x00, 0x00, // clearMask: no sections cleared
0xFF, 0xFF, 0x00, 0x00, // saveMask: save all sections
0x00, 0x00, 0x00, 0x00, // loadMask: no sections loaded
0x17 // deviceMask: BBR, Flash, EEPROM, and SPI Flash
};
const uint8_t GPS::_message_SAVE_10[] = {
static const uint8_t _message_SAVE_10[] = {
0x00, 0x00, 0x00, 0x00, // clearMask: no sections cleared
0xFF, 0xFF, 0x00, 0x00, // saveMask: save all sections
0x00, 0x00, 0x00, 0x00, // loadMask: no sections loaded
@ -375,12 +377,12 @@ LIMITPEAKCURRENT L 1
// b5 62 06 8a 26 00 00 02 00 00 01 00 d0 20 02 02 00 d0 40 05 00 00 00 05 00 d0 30 01 00 08 00 d0 10 01 09 00 d0 10 01 10 00 d0
// 10 01 8c 03
*/
const uint8_t GPS::_message_VALSET_PM_RAM[] = {0x00, 0x01, 0x00, 0x00, 0x01, 0x00, 0xd0, 0x20, 0x02, 0x02, 0x00, 0xd0, 0x40,
0x05, 0x00, 0x00, 0x00, 0x05, 0x00, 0xd0, 0x30, 0x01, 0x00, 0x08, 0x00, 0xd0,
0x10, 0x01, 0x09, 0x00, 0xd0, 0x10, 0x01, 0x10, 0x00, 0xd0, 0x10, 0x01};
const uint8_t GPS::_message_VALSET_PM_BBR[] = {0x00, 0x02, 0x00, 0x00, 0x01, 0x00, 0xd0, 0x20, 0x02, 0x02, 0x00, 0xd0, 0x40,
0x05, 0x00, 0x00, 0x00, 0x05, 0x00, 0xd0, 0x30, 0x01, 0x00, 0x08, 0x00, 0xd0,
0x10, 0x01, 0x09, 0x00, 0xd0, 0x10, 0x01, 0x10, 0x00, 0xd0, 0x10, 0x01};
static const uint8_t _message_VALSET_PM_RAM[] = {0x00, 0x01, 0x00, 0x00, 0x01, 0x00, 0xd0, 0x20, 0x02, 0x02, 0x00, 0xd0, 0x40,
0x05, 0x00, 0x00, 0x00, 0x05, 0x00, 0xd0, 0x30, 0x01, 0x00, 0x08, 0x00, 0xd0,
0x10, 0x01, 0x09, 0x00, 0xd0, 0x10, 0x01, 0x10, 0x00, 0xd0, 0x10, 0x01};
static const uint8_t _message_VALSET_PM_BBR[] = {0x00, 0x02, 0x00, 0x00, 0x01, 0x00, 0xd0, 0x20, 0x02, 0x02, 0x00, 0xd0, 0x40,
0x05, 0x00, 0x00, 0x00, 0x05, 0x00, 0xd0, 0x30, 0x01, 0x00, 0x08, 0x00, 0xd0,
0x10, 0x01, 0x09, 0x00, 0xd0, 0x10, 0x01, 0x10, 0x00, 0xd0, 0x10, 0x01};
/*
CFG-ITFM replaced by 5 valset messages which can be combined into one for RAM and one for BBR
@ -394,10 +396,10 @@ CFG-ITFM replaced by 5 valset messages which can be combined into one for RAM an
b5 62 06 8a 0e 00 00 01 00 00 0d 00 41 10 01 13 00 41 10 01 63 c6
*/
const uint8_t GPS::_message_VALSET_ITFM_RAM[] = {0x00, 0x01, 0x00, 0x00, 0x0d, 0x00, 0x41,
0x10, 0x01, 0x13, 0x00, 0x41, 0x10, 0x01};
const uint8_t GPS::_message_VALSET_ITFM_BBR[] = {0x00, 0x02, 0x00, 0x00, 0x0d, 0x00, 0x41,
0x10, 0x01, 0x13, 0x00, 0x41, 0x10, 0x01};
static const uint8_t _message_VALSET_ITFM_RAM[] = {0x00, 0x01, 0x00, 0x00, 0x0d, 0x00, 0x41,
0x10, 0x01, 0x13, 0x00, 0x41, 0x10, 0x01};
static const uint8_t _message_VALSET_ITFM_BBR[] = {0x00, 0x02, 0x00, 0x00, 0x0d, 0x00, 0x41,
0x10, 0x01, 0x13, 0x00, 0x41, 0x10, 0x01};
// Turn off all NMEA messages:
// Ram layer config message:
@ -407,13 +409,13 @@ const uint8_t GPS::_message_VALSET_ITFM_BBR[] = {0x00, 0x02, 0x00, 0x00, 0x0d, 0
// BBR layer config message:
// b5 62 06 8a 13 00 00 02 00 00 ca 00 91 20 00 c5 00 91 20 00 b1 00 91 20 00 f8 4e
const uint8_t GPS::_message_VALSET_DISABLE_NMEA_RAM[] = {
static const uint8_t _message_VALSET_DISABLE_NMEA_RAM[] = {
/*0x00, 0x01, 0x00, 0x00, 0xca, 0x00, 0x91, 0x20, 0x00, 0xc5, 0x00, 0x91, 0x20, 0x00, 0xb1, 0x00, 0x91, 0x20, 0x00 */
0x00, 0x01, 0x00, 0x00, 0xc0, 0x00, 0x91, 0x20, 0x00, 0xca, 0x00, 0x91, 0x20, 0x00, 0xc5, 0x00, 0x91,
0x20, 0x00, 0xac, 0x00, 0x91, 0x20, 0x00, 0xb1, 0x00, 0x91, 0x20, 0x00, 0xbb, 0x00, 0x91, 0x20, 0x00};
const uint8_t GPS::_message_VALSET_DISABLE_NMEA_BBR[] = {0x00, 0x02, 0x00, 0x00, 0xca, 0x00, 0x91, 0x20, 0x00, 0xc5,
0x00, 0x91, 0x20, 0x00, 0xb1, 0x00, 0x91, 0x20, 0x00};
static const uint8_t _message_VALSET_DISABLE_NMEA_BBR[] = {0x00, 0x02, 0x00, 0x00, 0xca, 0x00, 0x91, 0x20, 0x00, 0xc5,
0x00, 0x91, 0x20, 0x00, 0xb1, 0x00, 0x91, 0x20, 0x00};
// Turn off text info messages:
// Ram layer config message:
@ -432,17 +434,17 @@ const uint8_t GPS::_message_VALSET_DISABLE_NMEA_BBR[] = {0x00, 0x02, 0x00, 0x00,
// b5 62 06 8a 0e 00 00 04 00 00 bb 00 91 20 01 ac 00 91 20 01 6d b6
// Doing this for the FLASH layer isn't really required since we save the config to flash later
const uint8_t GPS::_message_VALSET_DISABLE_TXT_INFO_RAM[] = {0x00, 0x01, 0x00, 0x00, 0x07, 0x00, 0x92, 0x20, 0x03};
const uint8_t GPS::_message_VALSET_DISABLE_TXT_INFO_BBR[] = {0x00, 0x02, 0x00, 0x00, 0x07, 0x00, 0x92, 0x20, 0x03};
static const uint8_t _message_VALSET_DISABLE_TXT_INFO_RAM[] = {0x00, 0x01, 0x00, 0x00, 0x07, 0x00, 0x92, 0x20, 0x03};
static const uint8_t _message_VALSET_DISABLE_TXT_INFO_BBR[] = {0x00, 0x02, 0x00, 0x00, 0x07, 0x00, 0x92, 0x20, 0x03};
const uint8_t GPS::_message_VALSET_ENABLE_NMEA_RAM[] = {0x00, 0x01, 0x00, 0x00, 0xbb, 0x00, 0x91,
0x20, 0x01, 0xac, 0x00, 0x91, 0x20, 0x01};
const uint8_t GPS::_message_VALSET_ENABLE_NMEA_BBR[] = {0x00, 0x02, 0x00, 0x00, 0xbb, 0x00, 0x91,
0x20, 0x01, 0xac, 0x00, 0x91, 0x20, 0x01};
const uint8_t GPS::_message_VALSET_DISABLE_SBAS_RAM[] = {0x00, 0x01, 0x00, 0x00, 0x20, 0x00, 0x31,
0x10, 0x00, 0x05, 0x00, 0x31, 0x10, 0x00};
const uint8_t GPS::_message_VALSET_DISABLE_SBAS_BBR[] = {0x00, 0x02, 0x00, 0x00, 0x20, 0x00, 0x31,
0x10, 0x00, 0x05, 0x00, 0x31, 0x10, 0x00};
static const uint8_t _message_VALSET_ENABLE_NMEA_RAM[] = {0x00, 0x01, 0x00, 0x00, 0xbb, 0x00, 0x91,
0x20, 0x01, 0xac, 0x00, 0x91, 0x20, 0x01};
static const uint8_t _message_VALSET_ENABLE_NMEA_BBR[] = {0x00, 0x02, 0x00, 0x00, 0xbb, 0x00, 0x91,
0x20, 0x01, 0xac, 0x00, 0x91, 0x20, 0x01};
static const uint8_t _message_VALSET_DISABLE_SBAS_RAM[] = {0x00, 0x01, 0x00, 0x00, 0x20, 0x00, 0x31,
0x10, 0x00, 0x05, 0x00, 0x31, 0x10, 0x00};
static const uint8_t _message_VALSET_DISABLE_SBAS_BBR[] = {0x00, 0x02, 0x00, 0x00, 0x20, 0x00, 0x31,
0x10, 0x00, 0x05, 0x00, 0x31, 0x10, 0x00};
/*
Operational issues with the M10:
@ -462,7 +464,7 @@ the PM config. Lets try without it.
PMREQ sort of works with SBAS, but the awake time is too short to re-acquire any SBAS sats.
The defination of "Got Fix" doesn't seem to include SBAS. Much more too this...
Even if it was, it can take minutes (up to 12.5),
even under good sat visability conditions to re-acquire the SBAS data.
even under good sat visibility conditions to re-acquire the SBAS data.
Another effect fo the quick transition to sleep is that no other sats will be acquired so the
sat count will tend to remain at what the initial fix was.
@ -475,4 +477,4 @@ b5 62 06 8a 0e 00 00 01 00 00 20 00 31 10 00 05 00 31 10 00 46 87
BBR layer config message:
b5 62 06 8a 0e 00 00 02 00 00 20 00 31 10 00 05 00 31 10 00 47 94
*/
*/

View File

@ -79,13 +79,13 @@ bool EInkDisplay::forceDisplay(uint32_t msecLimit)
}
// Trigger the refresh in GxEPD2
LOG_DEBUG("Updating E-Paper... ");
LOG_DEBUG("Update E-Paper");
adafruitDisplay->nextPage();
// End the update process
endUpdate();
LOG_DEBUG("done\n");
LOG_DEBUG("done");
return true;
}
@ -123,7 +123,7 @@ void EInkDisplay::setDetected(uint8_t detected)
// Connect to the display - variant specific
bool EInkDisplay::connect()
{
LOG_INFO("Doing EInk init\n");
LOG_INFO("Do EInk init");
#ifdef PIN_EINK_EN
// backlight power, HIGH is backlight on, LOW is off

View File

@ -119,7 +119,7 @@ void EInkDynamicDisplay::endOrDetach()
awaitRefresh();
else {
// Async begins
LOG_DEBUG("Async full-refresh begins (dropping frames)\n");
LOG_DEBUG("Async full-refresh begins (drop frames)");
notifyLater(intervalPollAsyncRefresh, DUE_POLL_ASYNCREFRESH, true); // Hand-off to NotifiedWorkerThread
}
}
@ -133,7 +133,7 @@ void EInkDynamicDisplay::endOrDetach()
if (previousRefresh == FULL || previousRefresh == FAST) { // If refresh wasn't skipped (on unspecified..)
LOG_WARN(
"GxEPD2 version has not been modified to support async refresh; using fallback behavior. Please update lib_deps in "
"variant's platformio.ini file\n");
"variant's platformio.ini file");
EInkDisplay::endUpdate();
}
#endif
@ -170,7 +170,7 @@ bool EInkDynamicDisplay::determineMode()
checkFastRequested();
if (refresh == UNSPECIFIED)
LOG_WARN("There was a flaw in the determineMode() logic.\n");
LOG_WARN("There was a flaw in the determineMode() logic");
// -- Decision has been reached --
applyRefreshMode();
@ -254,7 +254,7 @@ void EInkDynamicDisplay::checkRateLimiting()
if (Throttle::isWithinTimespanMs(previousRunMs, EINK_LIMIT_RATE_RESPONSIVE_SEC * 1000)) {
refresh = SKIPPED;
reason = EXCEEDED_RATELIMIT_FAST;
LOG_DEBUG("refresh=SKIPPED, reason=EXCEEDED_RATELIMIT_FAST, frameFlags=0x%x\n", frameFlags);
LOG_DEBUG("refresh=SKIPPED, reason=EXCEEDED_RATELIMIT_FAST, frameFlags=0x%x", frameFlags);
return;
}
}
@ -271,7 +271,7 @@ void EInkDynamicDisplay::checkCosmetic()
if (frameFlags & COSMETIC) {
refresh = FULL;
reason = FLAGGED_COSMETIC;
LOG_DEBUG("refresh=FULL, reason=FLAGGED_COSMETIC, frameFlags=0x%x\n", frameFlags);
LOG_DEBUG("refresh=FULL, reason=FLAGGED_COSMETIC, frameFlags=0x%x", frameFlags);
}
}
@ -286,7 +286,7 @@ void EInkDynamicDisplay::checkDemandingFast()
if (frameFlags & DEMAND_FAST) {
refresh = FAST;
reason = FLAGGED_DEMAND_FAST;
LOG_DEBUG("refresh=FAST, reason=FLAGGED_DEMAND_FAST, frameFlags=0x%x\n", frameFlags);
LOG_DEBUG("refresh=FAST, reason=FLAGGED_DEMAND_FAST, frameFlags=0x%x", frameFlags);
}
}
@ -306,7 +306,7 @@ void EInkDynamicDisplay::checkFrameMatchesPrevious()
if (frameFlags == BACKGROUND && fastRefreshCount > 0) {
refresh = FULL;
reason = REDRAW_WITH_FULL;
LOG_DEBUG("refresh=FULL, reason=REDRAW_WITH_FULL, frameFlags=0x%x\n", frameFlags);
LOG_DEBUG("refresh=FULL, reason=REDRAW_WITH_FULL, frameFlags=0x%x", frameFlags);
return;
}
#endif
@ -314,7 +314,7 @@ void EInkDynamicDisplay::checkFrameMatchesPrevious()
// Not redrawn, not COSMETIC, not DEMAND_FAST
refresh = SKIPPED;
reason = FRAME_MATCHED_PREVIOUS;
LOG_DEBUG("refresh=SKIPPED, reason=FRAME_MATCHED_PREVIOUS, frameFlags=0x%x\n", frameFlags);
LOG_DEBUG("refresh=SKIPPED, reason=FRAME_MATCHED_PREVIOUS, frameFlags=0x%x", frameFlags);
}
// Have too many fast-refreshes occured consecutively, since last full refresh?
@ -328,7 +328,7 @@ void EInkDynamicDisplay::checkConsecutiveFastRefreshes()
if (fastRefreshCount >= EINK_LIMIT_FASTREFRESH) {
refresh = FULL;
reason = EXCEEDED_LIMIT_FASTREFRESH;
LOG_DEBUG("refresh=FULL, reason=EXCEEDED_LIMIT_FASTREFRESH, frameFlags=0x%x\n", frameFlags);
LOG_DEBUG("refresh=FULL, reason=EXCEEDED_LIMIT_FASTREFRESH, frameFlags=0x%x", frameFlags);
}
}
@ -343,13 +343,13 @@ void EInkDynamicDisplay::checkFastRequested()
// If we want BACKGROUND to use fast. (FULL only when a limit is hit)
refresh = FAST;
reason = BACKGROUND_USES_FAST;
LOG_DEBUG("refresh=FAST, reason=BACKGROUND_USES_FAST, fastRefreshCount=%lu, frameFlags=0x%x\n", fastRefreshCount,
LOG_DEBUG("refresh=FAST, reason=BACKGROUND_USES_FAST, fastRefreshCount=%lu, frameFlags=0x%x", fastRefreshCount,
frameFlags);
#else
// If we do want to use FULL for BACKGROUND updates
refresh = FULL;
reason = FLAGGED_BACKGROUND;
LOG_DEBUG("refresh=FULL, reason=FLAGGED_BACKGROUND\n");
LOG_DEBUG("refresh=FULL, reason=FLAGGED_BACKGROUND");
#endif
}
@ -357,7 +357,7 @@ void EInkDynamicDisplay::checkFastRequested()
if (frameFlags & RESPONSIVE) {
refresh = FAST;
reason = NO_OBJECTIONS;
LOG_DEBUG("refresh=FAST, reason=NO_OBJECTIONS, fastRefreshCount=%lu, frameFlags=0x%x\n", fastRefreshCount, frameFlags);
LOG_DEBUG("refresh=FAST, reason=NO_OBJECTIONS, fastRefreshCount=%lu, frameFlags=0x%x", fastRefreshCount, frameFlags);
}
}
@ -438,7 +438,7 @@ void EInkDynamicDisplay::checkExcessiveGhosting()
if (ghostPixelCount > EINK_LIMIT_GHOSTING_PX) {
refresh = FULL;
reason = EXCEEDED_GHOSTINGLIMIT;
LOG_DEBUG("refresh=FULL, reason=EXCEEDED_GHOSTINGLIMIT, frameFlags=0x%x\n", frameFlags);
LOG_DEBUG("refresh=FULL, reason=EXCEEDED_GHOSTINGLIMIT, frameFlags=0x%x", frameFlags);
}
}
@ -469,7 +469,7 @@ void EInkDynamicDisplay::joinAsyncRefresh()
if (!asyncRefreshRunning)
return;
LOG_DEBUG("Joining an async refresh in progress\n");
LOG_DEBUG("Join an async refresh in progress");
// Continually poll the BUSY pin
while (adafruitDisplay->epd2.isBusy())
@ -479,7 +479,7 @@ void EInkDynamicDisplay::joinAsyncRefresh()
adafruitDisplay->endAsyncFull(); // Run the end of nextPage() code
EInkDisplay::endUpdate(); // Run base-class code to finish off update (NOT our derived class override)
asyncRefreshRunning = false; // Unset the flag
LOG_DEBUG("Refresh complete\n");
LOG_DEBUG("Refresh complete");
// Note: this code only works because of a modification to meshtastic/GxEPD2.
// It is only equipped to intercept calls to nextPage()
@ -503,7 +503,7 @@ void EInkDynamicDisplay::pollAsyncRefresh()
adafruitDisplay->endAsyncFull(); // Run the end of nextPage() code
EInkDisplay::endUpdate(); // Run base-class code to finish off update (NOT our derived class override)
asyncRefreshRunning = false; // Unset the flag
LOG_DEBUG("Async full-refresh complete\n");
LOG_DEBUG("Async full-refresh complete");
// Note: this code only works because of a modification to meshtastic/GxEPD2.
// It is only equipped to intercept calls to nextPage()

View File

@ -20,7 +20,6 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "Screen.h"
#include "../userPrefs.h"
#include "PowerMon.h"
#include "Throttle.h"
#include "configuration.h"
@ -101,9 +100,9 @@ std::vector<MeshModule *> moduleFrames;
static char ourId[5];
// vector where symbols (string) are displayed in bottom corner of display.
std::vector<std::string> functionSymbals;
// string displayed in bottom right corner of display. Created from elements in functionSymbals vector
std::string functionSymbalString = "";
std::vector<std::string> functionSymbol;
// string displayed in bottom right corner of display. Created from elements in functionSymbol vector
std::string functionSymbolString = "";
#if HAS_GPS
// GeoCoord object for the screen
@ -144,7 +143,7 @@ static bool haveGlyphs(const char *str)
}
}
LOG_DEBUG("haveGlyphs=%d\n", have);
LOG_DEBUG("haveGlyphs=%d", have);
return have;
}
@ -186,56 +185,6 @@ static void drawIconScreen(const char *upperMsg, OLEDDisplay *display, OLEDDispl
display->setTextAlignment(TEXT_ALIGN_LEFT); // Restore left align, just to be kind to any other unsuspecting code
}
static void drawOEMIconScreen(const char *upperMsg, OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y)
{
// draw an xbm image.
// Please note that everything that should be transitioned
// needs to be drawn relative to x and y
// draw centered icon left to right and centered above the one line of app text
display->drawXbm(x + (SCREEN_WIDTH - oemStore.oem_icon_width) / 2,
y + (SCREEN_HEIGHT - FONT_HEIGHT_MEDIUM - oemStore.oem_icon_height) / 2 + 2, oemStore.oem_icon_width,
oemStore.oem_icon_height, (const uint8_t *)oemStore.oem_icon_bits.bytes);
switch (oemStore.oem_font) {
case 0:
display->setFont(FONT_SMALL);
break;
case 2:
display->setFont(FONT_LARGE);
break;
default:
display->setFont(FONT_MEDIUM);
break;
}
display->setTextAlignment(TEXT_ALIGN_LEFT);
const char *title = oemStore.oem_text;
display->drawString(x + getStringCenteredX(title), y + SCREEN_HEIGHT - FONT_HEIGHT_MEDIUM, title);
display->setFont(FONT_SMALL);
// Draw region in upper left
if (upperMsg)
display->drawString(x + 0, y + 0, upperMsg);
// Draw version and shortname in upper right
char buf[25];
snprintf(buf, sizeof(buf), "%s\n%s", xstr(APP_VERSION_SHORT), haveGlyphs(owner.short_name) ? owner.short_name : "");
display->setTextAlignment(TEXT_ALIGN_RIGHT);
display->drawString(x + SCREEN_WIDTH, y + 0, buf);
screen->forceDisplay();
display->setTextAlignment(TEXT_ALIGN_LEFT); // Restore left align, just to be kind to any other unsuspecting code
}
static void drawOEMBootScreen(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y)
{
// Draw region in upper left
const char *region = myRegion ? myRegion->name : NULL;
drawOEMIconScreen(region, display, state, x, y);
}
void Screen::drawFrameText(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y, const char *message)
{
uint16_t x_offset = display->width() / 2;
@ -292,11 +241,11 @@ static void drawWelcomeScreen(OLEDDisplay *display, OLEDDisplayUiState *state, i
// draw overlay in bottom right corner of screen to show when notifications are muted or modifier key is active
static void drawFunctionOverlay(OLEDDisplay *display, OLEDDisplayUiState *state)
{
// LOG_DEBUG("Drawing function overlay\n");
if (functionSymbals.begin() != functionSymbals.end()) {
// LOG_DEBUG("Draw function overlay");
if (functionSymbol.begin() != functionSymbol.end()) {
char buf[64];
display->setFont(FONT_SMALL);
snprintf(buf, sizeof(buf), "%s", functionSymbalString.c_str());
snprintf(buf, sizeof(buf), "%s", functionSymbolString.c_str());
display->drawString(SCREEN_WIDTH - display->getStringWidth(buf), SCREEN_HEIGHT - FONT_HEIGHT_SMALL, buf);
}
}
@ -310,7 +259,7 @@ static void drawDeepSleepScreen(OLEDDisplay *display, OLEDDisplayUiState *state,
EINK_ADD_FRAMEFLAG(display, COSMETIC);
EINK_ADD_FRAMEFLAG(display, BLOCKING);
LOG_DEBUG("Drawing deep sleep screen\n");
LOG_DEBUG("Draw deep sleep screen");
// Display displayStr on the screen
drawIconScreen("Sleeping", display, state, x, y);
@ -319,7 +268,7 @@ static void drawDeepSleepScreen(OLEDDisplay *display, OLEDDisplayUiState *state,
/// Used on eink displays when screen updates are paused
static void drawScreensaverOverlay(OLEDDisplay *display, OLEDDisplayUiState *state)
{
LOG_DEBUG("Drawing screensaver overlay\n");
LOG_DEBUG("Draw screensaver overlay");
EINK_ADD_FRAMEFLAG(display, COSMETIC); // Take the opportunity for a full-refresh
@ -385,9 +334,9 @@ static void drawModuleFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int
} else {
// otherwise, just display the module frame that's aligned with the current frame
module_frame = state->currentFrame;
// LOG_DEBUG("Screen is not in transition. Frame: %d\n\n", module_frame);
// LOG_DEBUG("Screen is not in transition. Frame: %d", module_frame);
}
// LOG_DEBUG("Drawing Module Frame %d\n\n", module_frame);
// LOG_DEBUG("Draw Module Frame %d", module_frame);
MeshModule &pi = *moduleFrames.at(module_frame);
pi.drawFrame(display, state, x, y);
}
@ -446,7 +395,7 @@ static void drawBattery(OLEDDisplay *display, int16_t x, int16_t y, uint8_t *img
display->drawFastImage(x, y, 16, 8, imgBuffer);
}
#ifdef T_WATCH_S3
#if defined(DISPLAY_CLOCK_FRAME)
void Screen::drawWatchFaceToggleButton(OLEDDisplay *display, int16_t x, int16_t y, bool digitalMode, float scale)
{
@ -962,7 +911,7 @@ static void drawTextMessageFrame(OLEDDisplay *display, OLEDDisplayUiState *state
const meshtastic_MeshPacket &mp = devicestate.rx_text_message;
meshtastic_NodeInfoLite *node = nodeDB->getMeshNode(getFrom(&mp));
// LOG_DEBUG("drawing text message from 0x%x: %s\n", mp.from,
// LOG_DEBUG("Draw text message from 0x%x: %s", mp.from,
// mp.decoded.variant.data.decoded.bytes);
// Demo for drawStringMaxWidth:
@ -1008,55 +957,65 @@ static void drawTextMessageFrame(OLEDDisplay *display, OLEDDisplayUiState *state
display->setColor(WHITE);
#ifndef EXCLUDE_EMOJI
if (strcmp(reinterpret_cast<const char *>(mp.decoded.payload.bytes), "\U0001F44D") == 0) {
const char *msg = reinterpret_cast<const char *>(mp.decoded.payload.bytes);
if (strcmp(msg, "\U0001F44D") == 0) {
display->drawXbm(x + (SCREEN_WIDTH - thumbs_width) / 2,
y + (SCREEN_HEIGHT - FONT_HEIGHT_MEDIUM - thumbs_height) / 2 + 2 + 5, thumbs_width, thumbs_height,
thumbup);
} else if (strcmp(reinterpret_cast<const char *>(mp.decoded.payload.bytes), "\U0001F44E") == 0) {
} else if (strcmp(msg, "\U0001F44E") == 0) {
display->drawXbm(x + (SCREEN_WIDTH - thumbs_width) / 2,
y + (SCREEN_HEIGHT - FONT_HEIGHT_MEDIUM - thumbs_height) / 2 + 2 + 5, thumbs_width, thumbs_height,
thumbdown);
} else if (strcmp(reinterpret_cast<const char *>(mp.decoded.payload.bytes), "") == 0) {
} else if (strcmp(msg, "\U0001F60A") == 0 || strcmp(msg, "\U0001F600") == 0 || strcmp(msg, "\U0001F642") == 0 ||
strcmp(msg, "\U0001F609") == 0 ||
strcmp(msg, "\U0001F601") == 0) { // matches 5 different common smileys, so that the phone user doesn't have to
// remember which one is compatible
display->drawXbm(x + (SCREEN_WIDTH - smiley_width) / 2,
y + (SCREEN_HEIGHT - FONT_HEIGHT_MEDIUM - smiley_height) / 2 + 2 + 5, smiley_width, smiley_height,
smiley);
} else if (strcmp(msg, "") == 0) {
display->drawXbm(x + (SCREEN_WIDTH - question_width) / 2,
y + (SCREEN_HEIGHT - FONT_HEIGHT_MEDIUM - question_height) / 2 + 2 + 5, question_width, question_height,
question);
} else if (strcmp(reinterpret_cast<const char *>(mp.decoded.payload.bytes), "‼️") == 0) {
} else if (strcmp(msg, "‼️") == 0) {
display->drawXbm(x + (SCREEN_WIDTH - bang_width) / 2, y + (SCREEN_HEIGHT - FONT_HEIGHT_MEDIUM - bang_height) / 2 + 2 + 5,
bang_width, bang_height, bang);
} else if (strcmp(reinterpret_cast<const char *>(mp.decoded.payload.bytes), "\U0001F4A9") == 0) {
} else if (strcmp(msg, "\U0001F4A9") == 0) {
display->drawXbm(x + (SCREEN_WIDTH - poo_width) / 2, y + (SCREEN_HEIGHT - FONT_HEIGHT_MEDIUM - poo_height) / 2 + 2 + 5,
poo_width, poo_height, poo);
} else if (strcmp(reinterpret_cast<const char *>(mp.decoded.payload.bytes), "\xf0\x9f\xa4\xa3") == 0) {
} else if (strcmp(msg, "\U0001F923") == 0) {
display->drawXbm(x + (SCREEN_WIDTH - haha_width) / 2, y + (SCREEN_HEIGHT - FONT_HEIGHT_MEDIUM - haha_height) / 2 + 2 + 5,
haha_width, haha_height, haha);
} else if (strcmp(reinterpret_cast<const char *>(mp.decoded.payload.bytes), "\U0001F44B") == 0) {
} else if (strcmp(msg, "\U0001F44B") == 0) {
display->drawXbm(x + (SCREEN_WIDTH - wave_icon_width) / 2,
y + (SCREEN_HEIGHT - FONT_HEIGHT_MEDIUM - wave_icon_height) / 2 + 2 + 5, wave_icon_width,
wave_icon_height, wave_icon);
} else if (strcmp(reinterpret_cast<const char *>(mp.decoded.payload.bytes), "\U0001F920") == 0) {
} else if (strcmp(msg, "\U0001F920") == 0) {
display->drawXbm(x + (SCREEN_WIDTH - cowboy_width) / 2,
y + (SCREEN_HEIGHT - FONT_HEIGHT_MEDIUM - cowboy_height) / 2 + 2 + 5, cowboy_width, cowboy_height,
cowboy);
} else if (strcmp(reinterpret_cast<const char *>(mp.decoded.payload.bytes), "\U0001F42D") == 0) {
} else if (strcmp(msg, "\U0001F42D") == 0) {
display->drawXbm(x + (SCREEN_WIDTH - deadmau5_width) / 2,
y + (SCREEN_HEIGHT - FONT_HEIGHT_MEDIUM - deadmau5_height) / 2 + 2 + 5, deadmau5_width, deadmau5_height,
deadmau5);
} else if (strcmp(reinterpret_cast<const char *>(mp.decoded.payload.bytes), "\xE2\x98\x80\xEF\xB8\x8F") == 0) {
} else if (strcmp(msg, "\xE2\x98\x80\xEF\xB8\x8F") == 0) {
display->drawXbm(x + (SCREEN_WIDTH - sun_width) / 2, y + (SCREEN_HEIGHT - FONT_HEIGHT_MEDIUM - sun_height) / 2 + 2 + 5,
sun_width, sun_height, sun);
} else if (strcmp(reinterpret_cast<const char *>(mp.decoded.payload.bytes), "\u2614") == 0) {
} else if (strcmp(msg, "\u2614") == 0) {
display->drawXbm(x + (SCREEN_WIDTH - rain_width) / 2, y + (SCREEN_HEIGHT - FONT_HEIGHT_MEDIUM - rain_height) / 2 + 2 + 10,
rain_width, rain_height, rain);
} else if (strcmp(reinterpret_cast<const char *>(mp.decoded.payload.bytes), "☁️") == 0) {
} else if (strcmp(msg, "☁️") == 0) {
display->drawXbm(x + (SCREEN_WIDTH - cloud_width) / 2,
y + (SCREEN_HEIGHT - FONT_HEIGHT_MEDIUM - cloud_height) / 2 + 2 + 5, cloud_width, cloud_height, cloud);
} else if (strcmp(reinterpret_cast<const char *>(mp.decoded.payload.bytes), "🌫️") == 0) {
} else if (strcmp(msg, "🌫️") == 0) {
display->drawXbm(x + (SCREEN_WIDTH - fog_width) / 2, y + (SCREEN_HEIGHT - FONT_HEIGHT_MEDIUM - fog_height) / 2 + 2 + 5,
fog_width, fog_height, fog);
} else if (strcmp(reinterpret_cast<const char *>(mp.decoded.payload.bytes), "\xf0\x9f\x98\x88") == 0) {
} else if (strcmp(msg, "\U0001F608") == 0) {
display->drawXbm(x + (SCREEN_WIDTH - devil_width) / 2,
y + (SCREEN_HEIGHT - FONT_HEIGHT_MEDIUM - devil_height) / 2 + 2 + 5, devil_width, devil_height, devil);
} else if (strcmp(reinterpret_cast<const char *>(mp.decoded.payload.bytes), "♥️") == 0) {
} else if (strcmp(msg, "♥️") == 0 || strcmp(msg, "\U0001F9E1") == 0 || strcmp(msg, "\U00002763") == 0 ||
strcmp(msg, "\U00002764") == 0 || strcmp(msg, "\U0001F495") == 0 || strcmp(msg, "\U0001F496") == 0 ||
strcmp(msg, "\U0001F497") == 0 || strcmp(msg, "\U0001F496") == 0) {
display->drawXbm(x + (SCREEN_WIDTH - heart_width) / 2,
y + (SCREEN_HEIGHT - FONT_HEIGHT_MEDIUM - heart_height) / 2 + 2 + 5, heart_width, heart_height, heart);
} else {
@ -1460,7 +1419,7 @@ static void drawNodeInfo(OLEDDisplay *display, OLEDDisplayUiState *state, int16_
}
bool hasNodeHeading = false;
if (ourNode && (hasValidPosition(ourNode) || screen->hasHeading())) {
if (ourNode && (nodeDB->hasValidPosition(ourNode) || screen->hasHeading())) {
const meshtastic_PositionLite &op = ourNode->position;
float myHeading;
if (screen->hasHeading())
@ -1469,7 +1428,7 @@ static void drawNodeInfo(OLEDDisplay *display, OLEDDisplayUiState *state, int16_
myHeading = screen->estimatedHeading(DegD(op.latitude_i), DegD(op.longitude_i));
screen->drawCompassNorth(display, compassX, compassY, myHeading);
if (hasValidPosition(node)) {
if (nodeDB->hasValidPosition(node)) {
// display direction toward node
hasNodeHeading = true;
const meshtastic_PositionLite &p = node->position;
@ -1500,7 +1459,7 @@ static void drawNodeInfo(OLEDDisplay *display, OLEDDisplayUiState *state, int16_
if (!hasNodeHeading) {
// direction to node is unknown so display question mark
// Debug info for gps lock errors
// LOG_DEBUG("ourNode %d, ourPos %d, theirPos %d\n", !!ourNode, ourNode && hasValidPosition(ourNode),
// LOG_DEBUG("ourNode %d, ourPos %d, theirPos %d", !!ourNode, ourNode && hasValidPosition(ourNode),
// hasValidPosition(node));
display->drawString(compassX - FONT_HEIGHT_SMALL / 4, compassY - FONT_HEIGHT_SMALL / 2, "?");
}
@ -1549,7 +1508,7 @@ Screen::Screen(ScanI2C::DeviceAddress address, meshtastic_Config_DisplayConfig_O
(address.port == ScanI2C::I2CPort::WIRE1) ? HW_I2C::I2C_TWO : HW_I2C::I2C_ONE);
#elif ARCH_PORTDUINO
if (settingsMap[displayPanel] != no_screen) {
LOG_DEBUG("Making TFTDisplay!\n");
LOG_DEBUG("Make TFTDisplay!");
dispdev = new TFTDisplay(address.address, -1, -1, geometry,
(address.port == ScanI2C::I2CPort::WIRE1) ? HW_I2C::I2C_TWO : HW_I2C::I2C_ONE);
} else {
@ -1596,7 +1555,7 @@ void Screen::handleSetOn(bool on, FrameCallback einkScreensaver)
if (on != screenOn) {
if (on) {
LOG_INFO("Turning on screen\n");
LOG_INFO("Turn on screen");
powerMon->setState(meshtastic_PowerMon_State_Screen_On);
#ifdef T_WATCH_S3
PMU->enablePowerOutput(XPOWERS_ALDO2);
@ -1631,7 +1590,7 @@ void Screen::handleSetOn(bool on, FrameCallback einkScreensaver)
// eInkScreensaver parameter is usually NULL (default argument), default frame used instead
setScreensaverFrames(einkScreensaver);
#endif
LOG_INFO("Turning off screen\n");
LOG_INFO("Turn off screen");
dispdev->displayOff();
#ifdef USE_ST7789
SPI1.end();
@ -1699,9 +1658,6 @@ void Screen::setup()
// Set the utf8 conversion function
dispdev->setFontTableLookupFunction(customFontTableLookup);
if (strlen(oemStore.oem_text) > 0)
logo_timeout *= 2;
// Add frames.
EINK_ADD_FRAMEFLAG(dispdev, DEMAND_FAST);
alertFrames[0] = [this](OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y) -> void {
@ -1842,28 +1798,11 @@ int32_t Screen::runOnce()
// serialSinceMsec adjusts for additional serial wait time during nRF52 bootup
static bool showingBootScreen = true;
if (showingBootScreen && (millis() > (logo_timeout + serialSinceMsec))) {
LOG_INFO("Done with boot screen...\n");
LOG_INFO("Done with boot screen");
stopBootScreen();
showingBootScreen = false;
}
// If we have an OEM Boot screen, toggle after logo_timeout seconds
if (strlen(oemStore.oem_text) > 0) {
static bool showingOEMBootScreen = true;
if (showingOEMBootScreen && (millis() > ((logo_timeout / 2) + serialSinceMsec))) {
LOG_INFO("Switch to OEM screen...\n");
// Change frames.
static FrameCallback bootOEMFrames[] = {drawOEMBootScreen};
static const int bootOEMFrameCount = sizeof(bootOEMFrames) / sizeof(bootOEMFrames[0]);
ui->setFrames(bootOEMFrames, bootOEMFrameCount);
ui->update();
#ifndef USE_EINK
ui->update();
#endif
showingOEMBootScreen = false;
}
}
#ifndef DISABLE_WELCOME_UNSET
if (showingNormalScreen && config.lora.region == meshtastic_Config_LoRaConfig_RegionCode_UNSET) {
setWelcomeFrames();
@ -1917,7 +1856,7 @@ int32_t Screen::runOnce()
free(cmd.print_text);
break;
default:
LOG_ERROR("Invalid screen cmd\n");
LOG_ERROR("Invalid screen cmd");
}
}
@ -1955,12 +1894,12 @@ int32_t Screen::runOnce()
EINK_ADD_FRAMEFLAG(dispdev, COSMETIC);
#endif
LOG_DEBUG("LastScreenTransition exceeded %ums transitioning to next frame\n", (millis() - lastScreenTransition));
LOG_DEBUG("LastScreenTransition exceeded %ums transition to next frame", (millis() - lastScreenTransition));
handleOnPress();
}
}
// LOG_DEBUG("want fps %d, fixed=%d\n", targetFramerate,
// LOG_DEBUG("want fps %d, fixed=%d", targetFramerate,
// ui->getUiState()->frameState); If we are scrolling we need to be called
// soon, otherwise just 1 fps (to save CPU) We also ask to be called twice
// as fast as we really need so that any rounding errors still result with
@ -1991,7 +1930,7 @@ void Screen::drawDebugInfoWiFiTrampoline(OLEDDisplay *display, OLEDDisplayUiStat
void Screen::setSSLFrames()
{
if (address_found.address) {
// LOG_DEBUG("showing SSL frames\n");
// LOG_DEBUG("Show SSL frames");
static FrameCallback sslFrames[] = {drawSSLScreen};
ui->setFrames(sslFrames, 1);
ui->update();
@ -2003,7 +1942,7 @@ void Screen::setSSLFrames()
void Screen::setWelcomeFrames()
{
if (address_found.address) {
// LOG_DEBUG("showing Welcome frames\n");
// LOG_DEBUG("Show Welcome frames");
static FrameCallback frames[] = {drawWelcomeScreen};
setFrameImmediateDraw(frames);
}
@ -2069,7 +2008,7 @@ void Screen::setFrames(FrameFocus focus)
uint8_t originalPosition = ui->getUiState()->currentFrame;
FramesetInfo fsi; // Location of specific frames, for applying focus parameter
LOG_DEBUG("showing standard frames\n");
LOG_DEBUG("Show standard frames");
showingNormalScreen = true;
#ifdef USE_EINK
@ -2082,10 +2021,10 @@ void Screen::setFrames(FrameFocus focus)
#endif
moduleFrames = MeshModule::GetMeshModulesWithUIFrames();
LOG_DEBUG("Showing %d module frames\n", moduleFrames.size());
LOG_DEBUG("Show %d module frames", moduleFrames.size());
#ifdef DEBUG_PORT
int totalFrameCount = MAX_NUM_NODES + NUM_EXTRA_FRAMES + moduleFrames.size();
LOG_DEBUG("Total frame count: %d\n", totalFrameCount);
LOG_DEBUG("Total frame count: %d", totalFrameCount);
#endif
// We don't show the node info of our node (if we have it yet - we should)
@ -2119,7 +2058,7 @@ void Screen::setFrames(FrameFocus focus)
numframes++;
}
LOG_DEBUG("Added modules. numframes: %d\n", numframes);
LOG_DEBUG("Added modules. numframes: %d", numframes);
// If we have a critical fault, show it first
fsi.positions.fault = numframes;
@ -2128,7 +2067,7 @@ void Screen::setFrames(FrameFocus focus)
focus = FOCUS_FAULT; // Change our "focus" parameter, to ensure we show the fault frame
}
#ifdef T_WATCH_S3
#if defined(DISPLAY_CLOCK_FRAME)
normalFrames[numframes++] = screen->digitalWatchFace ? &Screen::drawDigitalClockFrame : &Screen::drawAnalogClockFrame;
#endif
@ -2164,7 +2103,7 @@ void Screen::setFrames(FrameFocus focus)
#endif
fsi.frameCount = numframes; // Total framecount is used to apply FOCUS_PRESERVE
LOG_DEBUG("Finished building frames. numframes: %d\n", numframes);
LOG_DEBUG("Finished build frames. numframes: %d", numframes);
ui->setFrames(normalFrames, numframes);
ui->enableAllIndicators();
@ -2245,13 +2184,13 @@ void Screen::dismissCurrentFrame()
bool dismissed = false;
if (currentFrame == framesetInfo.positions.textMessage && devicestate.has_rx_text_message) {
LOG_INFO("Dismissing Text Message\n");
LOG_INFO("Dismiss Text Message");
devicestate.has_rx_text_message = false;
dismissed = true;
}
else if (currentFrame == framesetInfo.positions.waypoint && devicestate.has_rx_waypoint) {
LOG_DEBUG("Dismissing Waypoint\n");
LOG_DEBUG("Dismiss Waypoint");
devicestate.has_rx_waypoint = false;
dismissed = true;
}
@ -2263,7 +2202,7 @@ void Screen::dismissCurrentFrame()
void Screen::handleStartFirmwareUpdateScreen()
{
LOG_DEBUG("showing firmware screen\n");
LOG_DEBUG("Show firmware screen");
showingNormalScreen = false;
EINK_ADD_FRAMEFLAG(dispdev, DEMAND_FAST); // E-Ink: Explicitly use fast-refresh for next frame
@ -2312,24 +2251,24 @@ void Screen::decreaseBrightness()
/* TO DO: add little popup in center of screen saying what brightness level it is set to*/
}
void Screen::setFunctionSymbal(std::string sym)
void Screen::setFunctionSymbol(std::string sym)
{
if (std::find(functionSymbals.begin(), functionSymbals.end(), sym) == functionSymbals.end()) {
functionSymbals.push_back(sym);
functionSymbalString = "";
for (auto symbol : functionSymbals) {
functionSymbalString = symbol + " " + functionSymbalString;
if (std::find(functionSymbol.begin(), functionSymbol.end(), sym) == functionSymbol.end()) {
functionSymbol.push_back(sym);
functionSymbolString = "";
for (auto symbol : functionSymbol) {
functionSymbolString = symbol + " " + functionSymbolString;
}
setFastFramerate();
}
}
void Screen::removeFunctionSymbal(std::string sym)
void Screen::removeFunctionSymbol(std::string sym)
{
functionSymbals.erase(std::remove(functionSymbals.begin(), functionSymbals.end(), sym), functionSymbals.end());
functionSymbalString = "";
for (auto symbol : functionSymbals) {
functionSymbalString = symbol + " " + functionSymbalString;
functionSymbol.erase(std::remove(functionSymbol.begin(), functionSymbol.end(), sym), functionSymbol.end());
functionSymbolString = "";
for (auto symbol : functionSymbol) {
functionSymbolString = symbol + " " + functionSymbolString;
}
setFastFramerate();
}
@ -2355,7 +2294,7 @@ void Screen::handlePrint(const char *text)
{
// the string passed into us probably has a newline, but that would confuse the logging system
// so strip it
LOG_DEBUG("Screen: %.*s\n", strlen(text) - 1, text);
LOG_DEBUG("Screen: %.*s", strlen(text) - 1, text);
if (!useDisplay || !showingNormalScreen)
return;
@ -2708,7 +2647,7 @@ void DebugInfo::drawFrameSettings(OLEDDisplay *display, OLEDDisplayUiState *stat
int Screen::handleStatusUpdate(const meshtastic::Status *arg)
{
// LOG_DEBUG("Screen got status update %d\n", arg->getStatusType());
// LOG_DEBUG("Screen got status update %d", arg->getStatusType());
switch (arg->getStatusType()) {
case STATUS_TYPE_NODE:
if (showingNormalScreen && nodeStatus->getLastNumTotal() != nodeStatus->getNumTotal()) {
@ -2744,7 +2683,7 @@ int Screen::handleUIFrameEvent(const UIFrameEvent *event)
if (event->action == UIFrameEvent::Action::REGENERATE_FRAMESET)
setFrames(FOCUS_MODULE);
// Regenerate the frameset, while attempting to maintain focus on the current frame
// Regenerate the frameset, while Attempt to maintain focus on the current frame
else if (event->action == UIFrameEvent::Action::REGENERATE_FRAMESET_BACKGROUND)
setFrames(FOCUS_PRESERVE);
@ -2759,7 +2698,7 @@ int Screen::handleUIFrameEvent(const UIFrameEvent *event)
int Screen::handleInputEvent(const InputEvent *event)
{
#ifdef T_WATCH_S3
#if defined(DISPLAY_CLOCK_FRAME)
// For the T-Watch, intercept touches to the 'toggle digital/analog watch face' button
uint8_t watchFaceFrame = error_code ? 1 : 0;
@ -2817,4 +2756,4 @@ int Screen::handleAdminMessage(const meshtastic_AdminMessage *arg)
} // namespace graphics
#else
graphics::Screen::Screen(ScanI2C::DeviceAddress, meshtastic_Config_DisplayConfig_OledType, OLEDDISPLAY_GEOMETRY) {}
#endif // HAS_SCREEN
#endif // HAS_SCREEN

View File

@ -1,5 +1,6 @@
#pragma once
#include "../userPrefs.h"
#include "configuration.h"
#include "detect/ScanI2C.h"
@ -24,8 +25,8 @@ class Screen
void startFirmwareUpdateScreen() {}
void increaseBrightness() {}
void decreaseBrightness() {}
void setFunctionSymbal(std::string) {}
void removeFunctionSymbal(std::string) {}
void setFunctionSymbol(std::string) {}
void removeFunctionSymbol(std::string) {}
void startAlert(const char *) {}
void endAlert() {}
};
@ -282,8 +283,8 @@ class Screen : public concurrency::OSThread
void increaseBrightness();
void decreaseBrightness();
void setFunctionSymbal(std::string sym);
void removeFunctionSymbal(std::string sym);
void setFunctionSymbol(std::string sym);
void removeFunctionSymbol(std::string sym);
/// Stops showing the boot screen.
void stopBootScreen() { enqueueCmd(ScreenCmd{.cmd = Cmd::STOP_BOOT_SCREEN}); }
@ -327,10 +328,15 @@ class Screen : public concurrency::OSThread
SKIPREST = false;
return (uint8_t)ch;
}
case 0xC3: {
SKIPREST = false;
return (uint8_t)(ch | 0xC0);
}
}
// We want to strip out prefix chars for two-byte char formats
if (ch == 0xC2)
if (ch == 0xC2 || ch == 0xC3)
return (uint8_t)0;
#if defined(OLED_PL)
@ -549,7 +555,7 @@ class Screen : public concurrency::OSThread
static void drawDebugInfoWiFiTrampoline(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y);
#ifdef T_WATCH_S3
#if defined(DISPLAY_CLOCK_FRAME)
static void drawAnalogClockFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y);
static void drawDigitalClockFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y);
@ -600,4 +606,4 @@ class Screen : public concurrency::OSThread
} // namespace graphics
#endif
#endif

View File

@ -27,14 +27,22 @@
#define FONT_SMALL ArialMT_Plain_10_RU
#else
#ifdef OLED_UA
#define FONT_SMALL ArialMT_Plain_10_UA
#define FONT_SMALL ArialMT_Plain_10_UA // Height: 13
#else
#define FONT_SMALL ArialMT_Plain_10 // Height: 13
#endif
#endif
#endif
#ifdef OLED_UA
#define FONT_MEDIUM ArialMT_Plain_16_UA // Height: 19
#else
#define FONT_MEDIUM ArialMT_Plain_16 // Height: 19
#define FONT_LARGE ArialMT_Plain_24 // Height: 28
#endif
#ifdef OLED_UA
#define FONT_LARGE ArialMT_Plain_24_UA // Height: 28
#else
#define FONT_LARGE ArialMT_Plain_24 // Height: 28
#endif
#endif
#define _fontHeight(font) ((font)[1] + 1) // height is position 1

View File

@ -380,7 +380,7 @@ class LGFX : public lgfx::LGFX_Device
_panel_instance->setBus(&_bus_instance); // set the bus on the panel.
auto cfg = _panel_instance->config(); // Gets a structure for display panel settings.
LOG_DEBUG("Height: %d, Width: %d \n", settingsMap[displayHeight], settingsMap[displayWidth]);
LOG_DEBUG("Height: %d, Width: %d ", settingsMap[displayHeight], settingsMap[displayWidth]);
cfg.pin_cs = settingsMap[displayCS]; // Pin number where CS is connected (-1 = disable)
cfg.pin_rst = settingsMap[displayReset];
cfg.panel_width = settingsMap[displayWidth]; // actual displayable width
@ -643,7 +643,7 @@ GpioPin *TFTDisplay::backlightEnable = NULL;
TFTDisplay::TFTDisplay(uint8_t address, int sda, int scl, OLEDDISPLAY_GEOMETRY geometry, HW_I2C i2cBus)
{
LOG_DEBUG("TFTDisplay!\n");
LOG_DEBUG("TFTDisplay!");
#ifdef TFT_BL
GpioPin *p = new GpioHwPin(TFT_BL);
@ -712,7 +712,7 @@ void TFTDisplay::sendCommand(uint8_t com)
// handle display on/off directly
switch (com) {
case DISPLAYON: {
// LOG_DEBUG("Display on\n");
// LOG_DEBUG("Display on");
backlightEnable->set(true);
#if ARCH_PORTDUINO
display(true);
@ -736,7 +736,7 @@ void TFTDisplay::sendCommand(uint8_t com)
break;
}
case DISPLAYOFF: {
// LOG_DEBUG("Display off\n");
// LOG_DEBUG("Display off");
backlightEnable->set(false);
#if ARCH_PORTDUINO
tft->clear();
@ -772,14 +772,14 @@ void TFTDisplay::setDisplayBrightness(uint8_t _brightness)
// todo
#else
tft->setBrightness(_brightness);
LOG_DEBUG("Brightness is set to value: %i \n", _brightness);
LOG_DEBUG("Brightness is set to value: %i ", _brightness);
#endif
}
void TFTDisplay::flipScreenVertically()
{
#if defined(T_WATCH_S3)
LOG_DEBUG("Flip TFT vertically\n"); // T-Watch S3 right-handed orientation
LOG_DEBUG("Flip TFT vertically"); // T-Watch S3 right-handed orientation
tft->setRotation(0);
#endif
}
@ -823,7 +823,7 @@ void TFTDisplay::setDetected(uint8_t detected)
bool TFTDisplay::connect()
{
concurrency::LockGuard g(spiLock);
LOG_INFO("Doing TFT init\n");
LOG_INFO("Do TFT init");
#ifdef RAK14014
tft = new TFT_eSPI;
#else
@ -831,7 +831,7 @@ bool TFTDisplay::connect()
#endif
backlightEnable->set(true);
LOG_INFO("Power to TFT Backlight\n");
LOG_INFO("Power to TFT Backlight");
#ifdef UNPHONE
unphone.backlight(true); // using unPhone library

File diff suppressed because it is too large Load Diff

View File

@ -8,4 +8,6 @@
#endif
extern const uint8_t ArialMT_Plain_10_UA[] PROGMEM;
extern const uint8_t ArialMT_Plain_16_UA[] PROGMEM;
extern const uint8_t ArialMT_Plain_24_UA[] PROGMEM;
#endif

View File

@ -14,7 +14,7 @@ const uint8_t imgUser[] PROGMEM = {0x3C, 0x42, 0x99, 0xA5, 0xA5, 0x99, 0x42, 0x3
const uint8_t imgPositionEmpty[] PROGMEM = {0x20, 0x30, 0x28, 0x24, 0x42, 0xFF};
const uint8_t imgPositionSolid[] PROGMEM = {0x20, 0x30, 0x38, 0x3C, 0x7E, 0xFF};
#ifdef T_WATCH_S3
#if defined(DISPLAY_CLOCK_FRAME)
const uint8_t bluetoothConnectedIcon[36] PROGMEM = {0xfe, 0x01, 0xff, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x00, 0xe3, 0x1f,
0xf3, 0x3f, 0x33, 0x30, 0x33, 0x33, 0x33, 0x33, 0x03, 0x33, 0xff, 0x33,
0xfe, 0x31, 0x00, 0x30, 0x30, 0x30, 0x30, 0x30, 0xf0, 0x3f, 0xe0, 0x1f};
@ -56,6 +56,16 @@ static unsigned char thumbdown[] PROGMEM = {
0x80, 0x09, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x1C, 0x00, 0x00,
};
#define smiley_height 30
#define smiley_width 30
static unsigned char smiley[] PROGMEM = {
0x00, 0xfe, 0x0f, 0x00, 0x80, 0x01, 0x30, 0x00, 0x40, 0x00, 0xc0, 0x00, 0x20, 0x00, 0x00, 0x01, 0x10, 0x00, 0x00, 0x02,
0x08, 0x00, 0x00, 0x04, 0x04, 0x00, 0x00, 0x08, 0x04, 0x00, 0x00, 0x10, 0x02, 0x0e, 0x0e, 0x10, 0x02, 0x09, 0x12, 0x10,
0x01, 0x09, 0x12, 0x20, 0x01, 0x0f, 0x1e, 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, 0x20, 0x81, 0x00, 0x20, 0x20,
0x82, 0x00, 0x20, 0x10, 0x02, 0x01, 0x10, 0x10, 0x04, 0x02, 0x08, 0x08, 0x04, 0xfc, 0x07, 0x08, 0x08, 0x00, 0x00, 0x04,
0x10, 0x00, 0x00, 0x02, 0x20, 0x00, 0x00, 0x01, 0x40, 0x00, 0xc0, 0x00, 0x80, 0x01, 0x30, 0x00, 0x00, 0xfe, 0x0f, 0x00};
#define question_height 25
#define question_width 25
static unsigned char question[] PROGMEM = {

View File

@ -233,7 +233,7 @@ void ExpressLRSFiveWay::sendAdhocPing()
// Contained as one method for easier remapping of buttons by user
void ExpressLRSFiveWay::shutdown()
{
LOG_INFO("Shutdown from long press\n");
LOG_INFO("Shutdown from long press");
powerFSM.trigger(EVENT_PRESS);
screen->startAlert("Shutting down...");
// Don't set alerting = true. We don't want to auto-dismiss this alert.

View File

@ -0,0 +1,430 @@
// Based on the BBQ10 Keyboard
#include "MPR121Keyboard.h"
#include "configuration.h"
#include <Arduino.h>
#define _MPR121_REG_KEY 0x5a
#define _MPR121_REG_TOUCH_STATUS 0x00
#define _MPR121_REG_ELECTRODE_FILTERED_DATA
#define _MPR121_REG_BASELINE_VALUE 0x1E
// Baseline filters
#define _MPR121_REG_MAX_HALF_DELTA_RISING 0x2B
#define _MPR121_REG_NOISE_HALF_DELTA_RISING 0x2C
#define _MPR121_REG_NOISE_COUNT_LIMIT_RISING 0x2D
#define _MPR121_REG_FILTER_DELAY_COUNT_RISING 0x2E
#define _MPR121_REG_MAX_HALF_DELTA_FALLING 0x2F
#define _MPR121_REG_NOISE_HALF_DELTA_FALLING 0x30
#define _MPR121_REG_NOISE_COUNT_LIMIT_FALLING 0x31
#define _MPR121_REG_FILTER_DELAY_COUNT_FALLING 0x32
#define _MPR121_REG_NOISE_HALF_DELTA_TOUCHED 0x33
#define _MPR121_REG_NOISE_COUNT_LIMIT_TOUCHED 0x34
#define _MPR121_REG_FILTER_DELAY_COUNT_TOUCHED 0x35
#define _MPR121_REG_TOUCH_THRESHOLD 0x41 // First input, +2 for subsequent
#define _MPR121_REG_RELEASE_THRESHOLD 0x42 // First input, +2 for subsequent
#define _MPR121_REG_DEBOUNCE 0x5B
#define _MPR121_REG_CONFIG1 0x5C
#define _MPR121_REG_CONFIG2 0x5D
#define _MPR121_REG_ELECTRODE_CONFIG 0x5E
#define _MPR121_REG_SOFT_RESET 0x80
#define _KEY_MASK 0x0FFF // Key mask for the first 12 bits
#define _NUM_KEYS 12
#define ECR_CALIBRATION_TRACK_FROM_ZERO (0 << 6)
#define ECR_CALIBRATION_LOCK (1 << 6)
#define ECR_CALIBRATION_TRACK_FROM_PARTIAL_FILTER (2 << 6) // Recommended Typical Mode
#define ECR_CALIBRATION_TRACK_FROM_FULL_FILTER (3 << 6)
#define ECR_PROXIMITY_DETECTION_OFF (0 << 0) // Not using proximity detection
#define ECR_TOUCH_DETECTION_12CH (12 << 0) // Using all 12 channels
#define MPR121_NONE 0x00
#define MPR121_REBOOT 0x90
#define MPR121_LEFT 0xb4
#define MPR121_UP 0xb5
#define MPR121_DOWN 0xb6
#define MPR121_RIGHT 0xb7
#define MPR121_ESC 0x1b
#define MPR121_BSP 0x08
#define MPR121_SELECT 0x0d
#define MPR121_FN_ON 0xf1
#define MPR121_FN_OFF 0xf2
#define LONG_PRESS_THRESHOLD 2000
#define MULTI_TAP_THRESHOLD 2000
uint8_t TapMod[12] = {1, 2, 1, 13, 7, 7, 7, 7, 7, 9, 7, 9}; // Num chars per key, Modulus for rotating through characters
unsigned char MPR121_TapMap[12][13] = {{MPR121_BSP},
{'0', ' '},
{MPR121_SELECT},
{'1', '.', ',', '?', '!', ':', ';', '-', '_', '\\', '/', '(', ')'},
{'2', 'a', 'b', 'c', 'A', 'B', 'C'},
{'3', 'd', 'e', 'f', 'D', 'E', 'F'},
{'4', 'g', 'h', 'i', 'G', 'H', 'I'},
{'5', 'j', 'k', 'l', 'J', 'K', 'L'},
{'6', 'm', 'n', 'o', 'M', 'N', 'O'},
{'7', 'p', 'q', 'r', 's', 'P', 'Q', 'R', 'S'},
{'8', 't', 'u', 'v', 'T', 'U', 'V'},
{'9', 'w', 'x', 'y', 'z', 'W', 'X', 'Y', 'Z'}};
unsigned char MPR121_LongPressMap[12] = {MPR121_ESC, ' ', MPR121_NONE, MPR121_NONE, MPR121_UP, MPR121_NONE,
MPR121_LEFT, MPR121_NONE, MPR121_RIGHT, MPR121_NONE, MPR121_DOWN, MPR121_NONE};
// Translation map from left to right, top to bottom layout to a more convenient layout to manufacture, matching the
// https://www.amazon.com.au/Capacitive-Sensitive-Sensitivity-Replacement-Traditional/dp/B0CTJD5KW9/ref=pd_ci_mcx_mh_mcx_views_0_title?th=1
/*uint8_t MPR121_KeyMap[12] = {
9, 6, 3, 0,
10, 7, 4, 1,
11, 8, 5, 2
};*/
// Rotated Layout
uint8_t MPR121_KeyMap[12] = {2, 5, 8, 11, 1, 4, 7, 10, 0, 3, 6, 9};
MPR121Keyboard::MPR121Keyboard() : m_wire(nullptr), m_addr(0), readCallback(nullptr), writeCallback(nullptr)
{
// LOG_DEBUG("MPR121 @ %02x\n", m_addr);
state = Init;
last_key = -1;
last_tap = 0L;
char_idx = 0;
queue = "";
}
void MPR121Keyboard::begin(uint8_t addr, TwoWire *wire)
{
m_addr = addr;
m_wire = wire;
m_wire->begin();
reset();
}
void MPR121Keyboard::begin(i2c_com_fptr_t r, i2c_com_fptr_t w, uint8_t addr)
{
m_addr = addr;
m_wire = nullptr;
writeCallback = w;
readCallback = r;
reset();
}
void MPR121Keyboard::reset()
{
LOG_DEBUG("MPR121 Reset");
// Trigger a MPR121 Soft Reset
if (m_wire) {
m_wire->beginTransmission(m_addr);
m_wire->write(_MPR121_REG_SOFT_RESET);
m_wire->endTransmission();
}
if (writeCallback) {
uint8_t data = 0;
writeCallback(m_addr, _MPR121_REG_SOFT_RESET, &data, 0);
}
delay(100);
// Reset Electrode Configuration to 0x00, Stop Mode
writeRegister(_MPR121_REG_ELECTRODE_CONFIG, 0x00);
delay(100);
LOG_DEBUG("MPR121 Configure");
// Set touch release thresholds
for (uint8_t i = 0; i < 12; i++) {
// Set touch threshold
writeRegister(_MPR121_REG_TOUCH_THRESHOLD + (i * 2), 15);
delay(20);
// Set release threshold
writeRegister(_MPR121_REG_RELEASE_THRESHOLD + (i * 2), 7);
delay(20);
}
// Configure filtering and baseline registers
writeRegister(_MPR121_REG_MAX_HALF_DELTA_RISING, 0x01);
delay(20);
writeRegister(_MPR121_REG_MAX_HALF_DELTA_FALLING, 0x01);
delay(20);
writeRegister(_MPR121_REG_NOISE_HALF_DELTA_RISING, 0x01);
delay(20);
writeRegister(_MPR121_REG_NOISE_HALF_DELTA_FALLING, 0x05);
delay(20);
writeRegister(_MPR121_REG_NOISE_HALF_DELTA_TOUCHED, 0x00);
delay(20);
writeRegister(_MPR121_REG_NOISE_COUNT_LIMIT_RISING, 0x0e);
delay(20);
writeRegister(_MPR121_REG_NOISE_COUNT_LIMIT_FALLING, 0x01);
delay(20);
writeRegister(_MPR121_REG_NOISE_COUNT_LIMIT_TOUCHED, 0x00);
delay(20);
writeRegister(_MPR121_REG_FILTER_DELAY_COUNT_RISING, 0x00);
delay(20);
writeRegister(_MPR121_REG_FILTER_DELAY_COUNT_FALLING, 0x00);
delay(20);
writeRegister(_MPR121_REG_FILTER_DELAY_COUNT_TOUCHED, 0x00);
delay(20);
// Set Debounce to 0x02
writeRegister(_MPR121_REG_DEBOUNCE, 0x00);
delay(20);
// Set Filter1 itterations and discharge current 6x and 16uA respectively (0x10)
writeRegister(_MPR121_REG_CONFIG1, 0x10);
delay(20);
// Set CDT to 0.5us, Filter2 itterations to 4x, and Sample interval = 0 (0x20)
writeRegister(_MPR121_REG_CONFIG2, 0x20);
delay(20);
// Enter run mode by Seting partial filter calibration tracking, disable proximity detection, enable 12 channels
writeRegister(_MPR121_REG_ELECTRODE_CONFIG,
ECR_CALIBRATION_TRACK_FROM_PARTIAL_FILTER | ECR_PROXIMITY_DETECTION_OFF | ECR_TOUCH_DETECTION_12CH);
delay(100);
LOG_DEBUG("MPR121 Run");
state = Idle;
}
void MPR121Keyboard::attachInterrupt(uint8_t pin, void (*func)(void)) const
{
pinMode(pin, INPUT_PULLUP);
::attachInterrupt(digitalPinToInterrupt(pin), func, RISING);
}
void MPR121Keyboard::detachInterrupt(uint8_t pin) const
{
::detachInterrupt(pin);
}
uint8_t MPR121Keyboard::status() const
{
return readRegister16(_MPR121_REG_KEY);
}
uint8_t MPR121Keyboard::keyCount() const
{
// Read the key register
uint16_t keyRegister = readRegister16(_MPR121_REG_KEY);
return keyCount(keyRegister);
}
uint8_t MPR121Keyboard::keyCount(uint16_t value) const
{
// Mask the first 12 bits
uint16_t buttonState = value & _KEY_MASK;
// Count how many bits are set to 1 (i.e., how many buttons are pressed)
uint8_t numButtonsPressed = 0;
for (uint8_t i = 0; i < 12; ++i) {
if (buttonState & (1 << i)) {
numButtonsPressed++;
}
}
return numButtonsPressed;
}
bool MPR121Keyboard::hasEvent()
{
return queue.length() > 0;
}
void MPR121Keyboard::queueEvent(char next)
{
if (next == MPR121_NONE) {
return;
}
queue.concat(next);
}
char MPR121Keyboard::dequeueEvent()
{
if (queue.length() < 1) {
return MPR121_NONE;
}
char next = queue.charAt(0);
queue.remove(0, 1);
return next;
}
void MPR121Keyboard::trigger()
{
// Intended to fire in response to an interrupt from the MPR121 or a longpress callback
// Only functional if not in Init state
if (state != Init) {
// Read the key register
uint16_t keyRegister = readRegister16(_MPR121_REG_KEY);
uint8_t keysPressed = keyCount(keyRegister);
if (keysPressed == 0) {
// No buttons pressed
if (state == Held)
released();
state = Idle;
return;
}
if (keysPressed == 1) {
// No buttons pressed
if (state == Held || state == HeldLong)
held(keyRegister);
if (state == Idle)
pressed(keyRegister);
return;
}
if (keysPressed > 1) {
// Multipress
state = Busy;
return;
}
} else {
reset();
}
}
void MPR121Keyboard::pressed(uint16_t keyRegister)
{
if (state == Init || state == Busy) {
return;
}
if (keyCount(keyRegister) != 1) {
LOG_DEBUG("Multipress");
return;
} else {
LOG_DEBUG("Pressed");
}
uint16_t buttonState = keyRegister & _KEY_MASK;
uint8_t next_pin = 0;
for (uint8_t i = 0; i < 12; ++i) {
if (buttonState & (1 << i)) {
next_pin = i;
}
}
uint8_t next_key = MPR121_KeyMap[next_pin];
LOG_DEBUG("MPR121 Pin: %i Key: %i", next_pin, next_key);
uint32_t now = millis();
int32_t tap_interval = now - last_tap;
if (tap_interval < 0) {
// long running, millis has overflowed.
last_tap = 0;
state = Busy;
return;
}
if (next_key != last_key || tap_interval > MULTI_TAP_THRESHOLD) {
char_idx = 0;
} else {
char_idx += 1;
}
last_key = next_key;
last_tap = now;
state = Held;
return;
}
void MPR121Keyboard::held(uint16_t keyRegister)
{
if (state == Init || state == Busy) {
return;
}
if (keyCount(keyRegister) != 1) {
return;
}
LOG_DEBUG("Held");
uint16_t buttonState = keyRegister & _KEY_MASK;
uint8_t next_key = 0;
for (uint8_t i = 0; i < 12; ++i) {
if (buttonState & (1 << i)) {
next_key = MPR121_KeyMap[i];
}
}
uint32_t now = millis();
int32_t held_interval = now - last_tap;
if (held_interval < 0 || next_key != last_key) {
// long running, millis has overflowed, or a key has been switched quickly...
last_tap = 0;
state = Busy;
return;
}
if (held_interval > LONG_PRESS_THRESHOLD) {
// Set state to heldlong, send a longpress, and reset the timer...
state = HeldLong; // heldlong will allow this function to still fire, but prevent a "release"
queueEvent(MPR121_LongPressMap[last_key]);
last_tap = now;
LOG_DEBUG("Long Press Key: %i Map: %i", last_key, MPR121_LongPressMap[last_key]);
}
return;
}
void MPR121Keyboard::released()
{
if (state != Held) {
return;
}
// would clear longpress callback... later.
if (last_key < 0 || last_key > _NUM_KEYS) { // reset to idle if last_key out of bounds
last_key = -1;
state = Idle;
return;
}
LOG_DEBUG("Released");
if (char_idx > 0 && TapMod[last_key] > 1) {
queueEvent(MPR121_BSP);
LOG_DEBUG("Multi Press, Backspace");
}
queueEvent(MPR121_TapMap[last_key][(char_idx % TapMod[last_key])]);
LOG_DEBUG("Key Press: %i Index:%i if %i Map: %i", last_key, char_idx, TapMod[last_key],
MPR121_TapMap[last_key][(char_idx % TapMod[last_key])]);
}
uint8_t MPR121Keyboard::readRegister8(uint8_t reg) const
{
if (m_wire) {
m_wire->beginTransmission(m_addr);
m_wire->write(reg);
m_wire->endTransmission();
m_wire->requestFrom(m_addr, (uint8_t)1);
if (m_wire->available() < 1)
return 0;
return m_wire->read();
}
if (readCallback) {
uint8_t data;
readCallback(m_addr, reg, &data, 1);
return data;
}
return 0;
}
uint16_t MPR121Keyboard::readRegister16(uint8_t reg) const
{
uint8_t data[2] = {0};
// uint8_t low = 0, high = 0;
if (m_wire) {
m_wire->beginTransmission(m_addr);
m_wire->write(reg);
m_wire->endTransmission();
m_wire->requestFrom(m_addr, (uint8_t)2);
if (m_wire->available() < 2)
return 0;
data[0] = m_wire->read();
data[1] = m_wire->read();
}
if (readCallback) {
readCallback(m_addr, reg, data, 2);
}
return (data[1] << 8) | data[0];
}
void MPR121Keyboard::writeRegister(uint8_t reg, uint8_t value)
{
uint8_t data[2];
data[0] = reg;
data[1] = value;
if (m_wire) {
m_wire->beginTransmission(m_addr);
m_wire->write(data, sizeof(uint8_t) * 2);
m_wire->endTransmission();
}
if (writeCallback) {
writeCallback(m_addr, data[0], &(data[1]), 1);
}
}

View File

@ -0,0 +1,56 @@
// Based on the BBQ10 Keyboard
#include "concurrency/NotifiedWorkerThread.h"
#include "configuration.h"
#include <Wire.h>
#include <main.h>
class MPR121Keyboard
{
public:
typedef uint8_t (*i2c_com_fptr_t)(uint8_t dev_addr, uint8_t reg_addr, uint8_t *data, uint8_t len);
enum MPR121States { Init = 0, Idle, Held, HeldLong, Busy };
MPR121States state;
int8_t last_key;
uint32_t last_tap;
uint8_t char_idx;
String queue;
MPR121Keyboard();
void begin(uint8_t addr = MPR121_KB_ADDR, TwoWire *wire = &Wire);
void begin(i2c_com_fptr_t r, i2c_com_fptr_t w, uint8_t addr = MPR121_KB_ADDR);
void reset(void);
void attachInterrupt(uint8_t pin, void (*func)(void)) const;
void detachInterrupt(uint8_t pin) const;
void trigger(void);
void pressed(uint16_t value);
void held(uint16_t value);
void released(void);
uint8_t status(void) const;
uint8_t keyCount(void) const;
uint8_t keyCount(uint16_t value) const;
bool hasEvent(void);
char dequeueEvent(void);
void queueEvent(char);
uint8_t readRegister8(uint8_t reg) const;
uint16_t readRegister16(uint8_t reg) const;
void writeRegister(uint8_t reg, uint8_t value);
private:
TwoWire *m_wire;
uint8_t m_addr;
i2c_com_fptr_t readCallback;
i2c_com_fptr_t writeCallback;
};

View File

@ -28,7 +28,7 @@ void RotaryEncoderInterruptBase::init(
this->rotaryLevelA = digitalRead(this->_pinA);
this->rotaryLevelB = digitalRead(this->_pinB);
LOG_INFO("Rotary initialized (%d, %d, %d)\n", this->_pinA, this->_pinB, pinPress);
LOG_INFO("Rotary initialized (%d, %d, %d)", this->_pinA, this->_pinB, pinPress);
}
int32_t RotaryEncoderInterruptBase::runOnce()
@ -38,13 +38,13 @@ int32_t RotaryEncoderInterruptBase::runOnce()
e.source = this->_originName;
if (this->action == ROTARY_ACTION_PRESSED) {
LOG_DEBUG("Rotary event Press\n");
LOG_DEBUG("Rotary event Press");
e.inputEvent = this->_eventPressed;
} else if (this->action == ROTARY_ACTION_CW) {
LOG_DEBUG("Rotary event CW\n");
LOG_DEBUG("Rotary event CW");
e.inputEvent = this->_eventCw;
} else if (this->action == ROTARY_ACTION_CCW) {
LOG_DEBUG("Rotary event CCW\n");
LOG_DEBUG("Rotary event CCW");
e.inputEvent = this->_eventCcw;
}

View File

@ -47,7 +47,7 @@ bool ScanAndSelectInput::init()
// Connect our class to the canned message module
inputBroker->registerSource(this);
LOG_INFO("Initialized 'Scan and Select' input for Canned Messages, using pin %d\n", pin);
LOG_INFO("Initialized 'Scan and Select' input for Canned Messages, using pin %d", pin);
return true; // Init succeded
}
@ -59,7 +59,7 @@ int32_t ScanAndSelectInput::runOnce()
// If: "no messages added" alert screen currently shown
if (alertingNoMessage) {
// Dismiss the alert screen several seconds after it appears
if (now > alertingSinceMs + durationAlertMs) {
if (!Throttle::isWithinTimespanMs(alertingSinceMs, durationAlertMs)) {
alertingNoMessage = false;
screen->endAlert();
}
@ -74,9 +74,9 @@ int32_t ScanAndSelectInput::runOnce()
// Existing press
else {
// Duration enough for long press
// Longer than shortpress window
// Long press not yet fired (prevent repeat firing while held)
if (!longPressFired && Throttle::isWithinTimespanMs(downSinceMs, durationLongMs)) {
if (!longPressFired && !Throttle::isWithinTimespanMs(downSinceMs, durationLongMs)) {
longPressFired = true;
longPress();
}
@ -91,7 +91,9 @@ int32_t ScanAndSelectInput::runOnce()
// Button newly released
// Long press event didn't already fire
if (held && !longPressFired) {
// Duration enough for short press
// Duration within shortpress window
// - longer than durationShortPress (debounce)
// - shorter than durationLongPress
if (!Throttle::isWithinTimespanMs(downSinceMs, durationShortMs)) {
shortPress();
}

View File

@ -52,7 +52,7 @@ int32_t SerialKeyboard::runOnce()
digitalWrite(KB_LOAD, HIGH);
digitalWrite(KB_CLK, LOW);
prevKeys = 0b1111111111111111;
LOG_DEBUG("Serial Keyboard setup\n");
LOG_DEBUG("Serial Keyboard setup");
}
if (INPUTBROKER_SERIAL_TYPE == 1) { // Chatter V1.0 & V2.0 keypads

View File

@ -1,6 +1,10 @@
#include "TouchScreenBase.h"
#include "main.h"
#if defined(RAK14014) && !defined(MESHTASTIC_EXCLUDE_CANNEDMESSAGES)
#include "modules/CannedMessageModule.h"
#endif
#ifndef TIME_LONG_PRESS
#define TIME_LONG_PRESS 400
#endif
@ -23,7 +27,7 @@ TouchScreenBase::TouchScreenBase(const char *name, uint16_t width, uint16_t heig
void TouchScreenBase::init(bool hasTouch)
{
if (hasTouch) {
LOG_INFO("TouchScreen initialized %d %d\n", TOUCH_THRESHOLD_X, TOUCH_THRESHOLD_Y);
LOG_INFO("TouchScreen initialized %d %d", TOUCH_THRESHOLD_X, TOUCH_THRESHOLD_Y);
this->setInterval(100);
} else {
disable();
@ -68,20 +72,20 @@ int32_t TouchScreenBase::runOnce()
if (adx > ady && adx > TOUCH_THRESHOLD_X) {
if (0 > dx) { // swipe right to left
e.touchEvent = static_cast<char>(TOUCH_ACTION_LEFT);
LOG_DEBUG("action SWIPE: right to left\n");
LOG_DEBUG("action SWIPE: right to left");
} else { // swipe left to right
e.touchEvent = static_cast<char>(TOUCH_ACTION_RIGHT);
LOG_DEBUG("action SWIPE: left to right\n");
LOG_DEBUG("action SWIPE: left to right");
}
}
// swipe vertical
else if (ady > adx && ady > TOUCH_THRESHOLD_Y) {
if (0 > dy) { // swipe bottom to top
e.touchEvent = static_cast<char>(TOUCH_ACTION_UP);
LOG_DEBUG("action SWIPE: bottom to top\n");
LOG_DEBUG("action SWIPE: bottom to top");
} else { // swipe top to bottom
e.touchEvent = static_cast<char>(TOUCH_ACTION_DOWN);
LOG_DEBUG("action SWIPE: top to bottom\n");
LOG_DEBUG("action SWIPE: top to bottom");
}
}
// tap
@ -90,7 +94,7 @@ int32_t TouchScreenBase::runOnce()
if (_tapped) {
_tapped = false;
e.touchEvent = static_cast<char>(TOUCH_ACTION_DOUBLE_TAP);
LOG_DEBUG("action DOUBLE TAP(%d/%d)\n", x, y);
LOG_DEBUG("action DOUBLE TAP(%d/%d)", x, y);
} else {
_tapped = true;
}
@ -102,19 +106,37 @@ int32_t TouchScreenBase::runOnce()
}
_touchedOld = touched;
#if defined RAK14014
// Speed up the processing speed of the keyboard in virtual keyboard mode
auto state = cannedMessageModule->getRunState();
if (state == CANNED_MESSAGE_RUN_STATE_FREETEXT) {
if (_tapped) {
_tapped = false;
e.touchEvent = static_cast<char>(TOUCH_ACTION_TAP);
LOG_DEBUG("action TAP(%d/%d)\n", _last_x, _last_y);
}
} else {
if (_tapped && (time_t(millis()) - _start) > TIME_LONG_PRESS - 50) {
_tapped = false;
e.touchEvent = static_cast<char>(TOUCH_ACTION_TAP);
LOG_DEBUG("action TAP(%d/%d)\n", _last_x, _last_y);
}
}
#else
// fire TAP event when no 2nd tap occured within time
if (_tapped && (time_t(millis()) - _start) > TIME_LONG_PRESS - 50) {
_tapped = false;
e.touchEvent = static_cast<char>(TOUCH_ACTION_TAP);
LOG_DEBUG("action TAP(%d/%d)\n", _last_x, _last_y);
LOG_DEBUG("action TAP(%d/%d)", _last_x, _last_y);
}
#endif
// fire LONG_PRESS event without the need for release
if (touched && (time_t(millis()) - _start) > TIME_LONG_PRESS) {
// tricky: prevent reoccurring events and another touch event when releasing
_start = millis() + 30000;
e.touchEvent = static_cast<char>(TOUCH_ACTION_LONG_PRESS);
LOG_DEBUG("action LONG PRESS(%d/%d)\n", _last_x, _last_y);
LOG_DEBUG("action LONG PRESS(%d/%d)", _last_x, _last_y);
}
if (e.touchEvent != TOUCH_ACTION_NONE) {

View File

@ -30,7 +30,7 @@ void TrackballInterruptBase::init(uint8_t pinDown, uint8_t pinUp, uint8_t pinLef
attachInterrupt(this->_pinLeft, onIntLeft, RISING);
attachInterrupt(this->_pinRight, onIntRight, RISING);
LOG_DEBUG("Trackball GPIO initialized (%d, %d, %d, %d, %d)\n", this->_pinUp, this->_pinDown, this->_pinLeft, this->_pinRight,
LOG_DEBUG("Trackball GPIO initialized (%d, %d, %d, %d, %d)", this->_pinUp, this->_pinDown, this->_pinLeft, this->_pinRight,
pinPress);
this->setInterval(100);
@ -42,19 +42,19 @@ int32_t TrackballInterruptBase::runOnce()
e.inputEvent = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_NONE;
if (this->action == TB_ACTION_PRESSED) {
// LOG_DEBUG("Trackball event Press\n");
// LOG_DEBUG("Trackball event Press");
e.inputEvent = this->_eventPressed;
} else if (this->action == TB_ACTION_UP) {
// LOG_DEBUG("Trackball event UP\n");
// LOG_DEBUG("Trackball event UP");
e.inputEvent = this->_eventUp;
} else if (this->action == TB_ACTION_DOWN) {
// LOG_DEBUG("Trackball event DOWN\n");
// LOG_DEBUG("Trackball event DOWN");
e.inputEvent = this->_eventDown;
} else if (this->action == TB_ACTION_LEFT) {
// LOG_DEBUG("Trackball event LEFT\n");
// LOG_DEBUG("Trackball event LEFT");
e.inputEvent = this->_eventLeft;
} else if (this->action == TB_ACTION_RIGHT) {
// LOG_DEBUG("Trackball event RIGHT\n");
// LOG_DEBUG("Trackball event RIGHT");
e.inputEvent = this->_eventRight;
}

View File

@ -23,7 +23,7 @@ void UpDownInterruptBase::init(uint8_t pinDown, uint8_t pinUp, uint8_t pinPress,
attachInterrupt(this->_pinDown, onIntDown, RISING);
attachInterrupt(this->_pinUp, onIntUp, RISING);
LOG_DEBUG("Up/down/press GPIO initialized (%d, %d, %d)\n", this->_pinUp, this->_pinDown, pinPress);
LOG_DEBUG("Up/down/press GPIO initialized (%d, %d, %d)", this->_pinUp, this->_pinDown, pinPress);
this->setInterval(100);
}
@ -34,13 +34,13 @@ int32_t UpDownInterruptBase::runOnce()
e.inputEvent = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_NONE;
if (this->action == UPDOWN_ACTION_PRESSED) {
LOG_DEBUG("GPIO event Press\n");
LOG_DEBUG("GPIO event Press");
e.inputEvent = this->_eventPressed;
} else if (this->action == UPDOWN_ACTION_UP) {
LOG_DEBUG("GPIO event Up\n");
LOG_DEBUG("GPIO event Up");
e.inputEvent = this->_eventUp;
} else if (this->action == UPDOWN_ACTION_DOWN) {
LOG_DEBUG("GPIO event Down\n");
LOG_DEBUG("GPIO event Down");
e.inputEvent = this->_eventDown;
}

View File

@ -9,11 +9,11 @@ CardKbI2cImpl::CardKbI2cImpl() : KbI2cBase("cardKB") {}
void CardKbI2cImpl::init()
{
#if !MESHTASTIC_EXCLUDE_I2C && !defined(ARCH_PORTDUINO)
#if !MESHTASTIC_EXCLUDE_I2C && !defined(ARCH_PORTDUINO) && !defined(I2C_NO_RESCAN)
if (cardkb_found.address == 0x00) {
LOG_DEBUG("Rescanning for I2C keyboard\n");
uint8_t i2caddr_scan[] = {CARDKB_ADDR, TDECK_KB_ADDR, BBQ10_KB_ADDR};
uint8_t i2caddr_asize = 3;
LOG_DEBUG("Rescan for I2C keyboard");
uint8_t i2caddr_scan[] = {CARDKB_ADDR, TDECK_KB_ADDR, BBQ10_KB_ADDR, MPR121_KB_ADDR};
uint8_t i2caddr_asize = 4;
auto i2cScanner = std::unique_ptr<ScanI2CTwoWire>(new ScanI2CTwoWire());
#if WIRE_INTERFACES_COUNT == 2
@ -39,15 +39,21 @@ void CardKbI2cImpl::init()
// assign an arbitrary value to distinguish from other models
kb_model = 0x11;
break;
case ScanI2C::DeviceType::MPR121KB:
// assign an arbitrary value to distinguish from other models
kb_model = 0x37;
break;
default:
// use this as default since it's also just zero
LOG_WARN("kb_info.type is unknown(0x%02x), setting kb_model=0x00\n", kb_info.type);
LOG_WARN("kb_info.type is unknown(0x%02x), setting kb_model=0x00", kb_info.type);
kb_model = 0x00;
}
}
if (cardkb_found.address == 0x00) {
disable();
return;
} else {
LOG_DEBUG("Keyboard Type: 0x%02x Model: 0x%02x Address: 0x%02x", kb_info.type, kb_model, cardkb_found.address);
}
}
#else

View File

@ -34,21 +34,27 @@ int32_t KbI2cBase::runOnce()
switch (cardkb_found.port) {
case ScanI2C::WIRE1:
#if WIRE_INTERFACES_COUNT == 2
LOG_DEBUG("Using I2C Bus 1 (the second one)\n");
LOG_DEBUG("Use I2C Bus 1 (the second one)");
i2cBus = &Wire1;
if (cardkb_found.address == BBQ10_KB_ADDR) {
Q10keyboard.begin(BBQ10_KB_ADDR, &Wire1);
Q10keyboard.setBacklight(0);
}
if (cardkb_found.address == MPR121_KB_ADDR) {
MPRkeyboard.begin(MPR121_KB_ADDR, &Wire1);
}
break;
#endif
case ScanI2C::WIRE:
LOG_DEBUG("Using I2C Bus 0 (the first one)\n");
LOG_DEBUG("Use I2C Bus 0 (the first one)");
i2cBus = &Wire;
if (cardkb_found.address == BBQ10_KB_ADDR) {
Q10keyboard.begin(BBQ10_KB_ADDR, &Wire);
Q10keyboard.setBacklight(0);
}
if (cardkb_found.address == MPR121_KB_ADDR) {
MPRkeyboard.begin(MPR121_KB_ADDR, &Wire);
}
break;
case ScanI2C::NO_I2C:
default:
@ -157,6 +163,69 @@ int32_t KbI2cBase::runOnce()
}
break;
}
case 0x37: { // MPR121
MPRkeyboard.trigger();
InputEvent e;
while (MPRkeyboard.hasEvent()) {
char nextEvent = MPRkeyboard.dequeueEvent();
e.inputEvent = ANYKEY;
e.kbchar = 0x00;
e.source = this->_originName;
switch (nextEvent) {
case 0x00: // MPR121_NONE
e.inputEvent = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_NONE;
e.kbchar = 0x00;
break;
case 0x90: // MPR121_REBOOT
e.inputEvent = ANYKEY;
e.kbchar = INPUT_BROKER_MSG_REBOOT;
break;
case 0xb4: // MPR121_LEFT
e.inputEvent = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_LEFT;
e.kbchar = 0x00;
break;
case 0xb5: // MPR121_UP
e.inputEvent = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_UP;
e.kbchar = 0x00;
break;
case 0xb6: // MPR121_DOWN
e.inputEvent = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_DOWN;
e.kbchar = 0x00;
break;
case 0xb7: // MPR121_RIGHT
e.inputEvent = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_RIGHT;
e.kbchar = 0x00;
break;
case 0x1b: // MPR121_ESC
e.inputEvent = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_CANCEL;
e.kbchar = 0x1b;
break;
case 0x08: // MPR121_BSP
e.inputEvent = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_BACK;
e.kbchar = 0x08;
break;
case 0x0d: // MPR121_SELECT
e.inputEvent = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_SELECT;
e.kbchar = 0x0d;
break;
default:
if (nextEvent > 127) {
e.inputEvent = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_NONE;
e.kbchar = 0x00;
break;
}
e.inputEvent = ANYKEY;
e.kbchar = nextEvent;
break;
}
if (e.inputEvent != meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_NONE) {
LOG_DEBUG("MP121 Notifying: %i Char: %i", e.inputEvent, e.kbchar);
this->notifyObservers(&e);
}
}
break;
}
case 0x02: {
// RAK14004
uint8_t rDataBuf[8] = {0};
@ -171,7 +240,7 @@ int32_t KbI2cBase::runOnce()
}
}
if (PrintDataBuf != 0) {
LOG_DEBUG("RAK14004 key 0x%x pressed\n", PrintDataBuf);
LOG_DEBUG("RAK14004 key 0x%x pressed", PrintDataBuf);
InputEvent e;
e.inputEvent = MATRIXKEY;
e.source = this->_originName;
@ -326,7 +395,7 @@ int32_t KbI2cBase::runOnce()
break;
}
default:
LOG_WARN("Unknown kb_model 0x%02x\n", kb_model);
LOG_WARN("Unknown kb_model 0x%02x", kb_model);
}
return 300;
}

Some files were not shown because too many files have changed in this diff Show More