mirror of
https://github.com/meshtastic/firmware.git
synced 2025-12-22 18:52:30 +00:00
Merge branch 'apollo' of github.com:meshtastic/firmware into apollo
This commit is contained in:
4
.github/ISSUE_TEMPLATE/Bug Report.yml
vendored
4
.github/ISSUE_TEMPLATE/Bug Report.yml
vendored
@@ -37,7 +37,9 @@ body:
|
||||
- T-Lora v1
|
||||
- T-Lora v1.3
|
||||
- T-Lora v2 1.6
|
||||
- T-Deck
|
||||
- T-Echo
|
||||
- T-Watch
|
||||
- Rak4631
|
||||
- Rak11200
|
||||
- Rak11310
|
||||
@@ -45,6 +47,8 @@ body:
|
||||
- Heltec v2
|
||||
- Heltec v2.1
|
||||
- Heltec V3
|
||||
- Heltec Wireless Paper
|
||||
- Heltec Wireless Tracker
|
||||
- Raspberry Pi Pico (W)
|
||||
- Relay v1
|
||||
- Relay v2
|
||||
|
||||
16
.github/workflows/build_esp32.yml
vendored
16
.github/workflows/build_esp32.yml
vendored
@@ -17,11 +17,11 @@ jobs:
|
||||
uses: ./.github/actions/setup-base
|
||||
|
||||
- name: Pull web ui
|
||||
uses: dsaltares/fetch-gh-release-asset@master
|
||||
uses: dsaltares/fetch-gh-release-asset@a40c8b4a0471f9ab81bdf73a010f74cc51476ad4
|
||||
with:
|
||||
repo: "meshtastic/web"
|
||||
file: "build.tar"
|
||||
target: "build.tar"
|
||||
repo: meshtastic/web
|
||||
file: build.tar
|
||||
target: build.tar
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Unpack web ui
|
||||
@@ -40,11 +40,11 @@ jobs:
|
||||
run: bin/build-esp32.sh ${{ inputs.board }}
|
||||
|
||||
- name: Pull OTA Firmware
|
||||
uses: dsaltares/fetch-gh-release-asset@master
|
||||
uses: dsaltares/fetch-gh-release-asset@a40c8b4a0471f9ab81bdf73a010f74cc51476ad4
|
||||
with:
|
||||
repo: "meshtastic/firmware-ota"
|
||||
file: "firmware.bin"
|
||||
target: "release/bleota.bin"
|
||||
repo: meshtastic/firmware-ota
|
||||
file: firmware.bin
|
||||
target: release/bleota.bin
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Get release version string
|
||||
|
||||
16
.github/workflows/build_esp32_s3.yml
vendored
16
.github/workflows/build_esp32_s3.yml
vendored
@@ -17,11 +17,11 @@ jobs:
|
||||
uses: ./.github/actions/setup-base
|
||||
|
||||
- name: Pull web ui
|
||||
uses: dsaltares/fetch-gh-release-asset@master
|
||||
uses: dsaltares/fetch-gh-release-asset@a40c8b4a0471f9ab81bdf73a010f74cc51476ad4
|
||||
with:
|
||||
repo: "meshtastic/web"
|
||||
file: "build.tar"
|
||||
target: "build.tar"
|
||||
repo: meshtastic/web
|
||||
file: build.tar
|
||||
target: build.tar
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Unpack web ui
|
||||
@@ -38,11 +38,11 @@ jobs:
|
||||
run: bin/build-esp32.sh ${{ inputs.board }}
|
||||
|
||||
- name: Pull OTA Firmware
|
||||
uses: dsaltares/fetch-gh-release-asset@master
|
||||
uses: dsaltares/fetch-gh-release-asset@a40c8b4a0471f9ab81bdf73a010f74cc51476ad4
|
||||
with:
|
||||
repo: "meshtastic/firmware-ota"
|
||||
file: "firmware-s3.bin"
|
||||
target: "release/bleota-s3.bin"
|
||||
repo: meshtastic/firmware-ota
|
||||
file: firmware-s3.bin
|
||||
target: release/bleota-s3.bin
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Get release version string
|
||||
|
||||
19
.github/workflows/main_matrix.yml
vendored
19
.github/workflows/main_matrix.yml
vendored
@@ -1,4 +1,7 @@
|
||||
name: CI
|
||||
#concurrency:
|
||||
# group: ${{ github.ref }}
|
||||
# cancel-in-progress: ${{ github.ref != 'refs/heads/master' }}
|
||||
on:
|
||||
# # Triggers the workflow on push but only for the master branch
|
||||
push:
|
||||
@@ -33,6 +36,8 @@ jobs:
|
||||
- board: m5stack-coreink
|
||||
- board: tbeam-s3-core
|
||||
- board: tlora-t3s3-v1
|
||||
- board: t-watch-s3
|
||||
- board: t-deck
|
||||
#- board: rak11310
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
@@ -44,7 +49,7 @@ jobs:
|
||||
|
||||
- name: Trunk Check
|
||||
if: ${{ github.event_name != 'workflow_dispatch' }}
|
||||
uses: trunk-io/trunk-action@v1
|
||||
uses: trunk-io/trunk-action@782e83f803ca6e369f035d64c6ba2768174ba61b
|
||||
|
||||
- name: Check ${{ matrix.board }}
|
||||
run: bin/check-all.sh ${{ matrix.board }}
|
||||
@@ -66,6 +71,7 @@ jobs:
|
||||
- board: heltec-v2_1
|
||||
- board: tbeam0_7
|
||||
- board: meshtastic-diy-v1
|
||||
- board: hydra
|
||||
- board: meshtastic-dr-dev
|
||||
- board: nano-g1
|
||||
- board: station-g1
|
||||
@@ -83,8 +89,12 @@ jobs:
|
||||
include:
|
||||
- board: heltec-v3
|
||||
- board: heltec-wsl-v3
|
||||
- board: heltec-wireless-tracker
|
||||
- board: heltec-wireless-paper
|
||||
- board: tbeam-s3-core
|
||||
- board: tlora-t3s3-v1
|
||||
- board: t-watch-s3
|
||||
- board: t-deck
|
||||
uses: ./.github/workflows/build_esp32_s3.yml
|
||||
with:
|
||||
board: ${{ matrix.board }}
|
||||
@@ -97,9 +107,11 @@ jobs:
|
||||
include:
|
||||
- board: rak4631
|
||||
- board: rak4631_eink
|
||||
- board: monteops_hw1
|
||||
- board: t-echo
|
||||
- board: pca10059_diy_eink
|
||||
- board: feather_diy
|
||||
- board: nano-g2-ultra
|
||||
uses: ./.github/workflows/build_nrf52.yml
|
||||
with:
|
||||
board: ${{ matrix.board }}
|
||||
@@ -247,8 +259,9 @@ jobs:
|
||||
retention-days: 30
|
||||
|
||||
- name: Create request artifacts
|
||||
continue-on-error: true # FIXME: Why are we getting 502, but things still work?
|
||||
if: ${{ github.event_name == 'pull_request_target' || github.event_name == 'pull_request' }}
|
||||
uses: gavv/pull-request-artifacts@v1.0.0
|
||||
uses: gavv/pull-request-artifacts@v1.1.0
|
||||
with:
|
||||
commit: ${{ (github.event.pull_request_target || github.event.pull_request).head.sha }}
|
||||
repo-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
@@ -306,7 +319,7 @@ jobs:
|
||||
with:
|
||||
draft: true
|
||||
prerelease: true
|
||||
release_name: Meshtastic Firmware ${{ steps.version.outputs.version }}
|
||||
release_name: Meshtastic Firmware ${{ steps.version.outputs.version }} Alpha
|
||||
tag_name: v${{ steps.version.outputs.version }}
|
||||
body: |
|
||||
Autogenerated by github action, developer should edit as required before publishing...
|
||||
|
||||
2
.github/workflows/nightly.yml
vendored
2
.github/workflows/nightly.yml
vendored
@@ -14,6 +14,6 @@ jobs:
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Trunk Check
|
||||
uses: trunk-io/trunk-action@v1
|
||||
uses: trunk-io/trunk-action@782e83f803ca6e369f035d64c6ba2768174ba61b
|
||||
with:
|
||||
trunk-token: ${{ secrets.TRUNK_TOKEN }}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
; Common settings for ESP targes, mixin with extends = esp32_base
|
||||
[esp32_base]
|
||||
extends = arduino_base
|
||||
platform = platformio/espressif32@^6.2.0
|
||||
platform = platformio/espressif32@^6.3.2
|
||||
|
||||
build_src_filter =
|
||||
${arduino_base.build_src_filter} -<platform/nrf52/> -<platform/stm32wl> -<platform/rp2040> -<platform/apollo3> -<mesh/eth/>
|
||||
@@ -28,6 +28,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
|
||||
-DESP_OPENSSL_SUPPRESS_LEGACY_WARNING
|
||||
;-DDEBUG_HEAP
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[nrf52_base]
|
||||
; Instead of the standard nordicnrf52 platform, we use our fork which has our added variant files
|
||||
platform = platformio/nordicnrf52@^9.6.0
|
||||
platform = platformio/nordicnrf52@^10.0.0
|
||||
extends = arduino_base
|
||||
|
||||
build_type = debug ; I'm debugging with ICE a lot now
|
||||
@@ -9,7 +9,7 @@ build_flags =
|
||||
-Isrc/platform/nrf52
|
||||
|
||||
build_src_filter =
|
||||
${arduino_base.build_src_filter} -<platform/esp32/> -<platform/stm32wl> -<nimble/> -<mesh/api/> -<mesh/http/> -<modules/esp32> -<mqtt/> -<platform/rp2040> -<platform/apollo3> -<mesh/eth/>
|
||||
${arduino_base.build_src_filter} -<platform/esp32/> -<platform/stm32wl> -<nimble/> -<mesh/api/> -<mesh/http/> -<modules/esp32> -<platform/rp2040> -<platform/apollo3> -<mesh/eth/>
|
||||
|
||||
lib_deps=
|
||||
${arduino_base.lib_deps}
|
||||
|
||||
@@ -12,7 +12,7 @@ build_flags =
|
||||
-D__PLAT_RP2040__
|
||||
# -D _POSIX_THREADS
|
||||
build_src_filter =
|
||||
${arduino_base.build_src_filter} -<platform/esp32/> -<nimble/> -<mesh/api/> -<mesh/http/> -<modules/esp32> -<mqtt/> -<platform/nrf52/> -<platform/apollo3> -<platform/stm32wl> -<mesh/eth/>
|
||||
${arduino_base.build_src_filter} -<platform/esp32/> -<nimble/> -<mesh/api/> -<mesh/http/> -<modules/esp32> -<platform/nrf52/> -<platform/apollo3> -<platform/stm32wl> -<mesh/eth/>
|
||||
|
||||
lib_ignore =
|
||||
BluetoothOTA
|
||||
|
||||
@@ -13,7 +13,7 @@ build_flags =
|
||||
-DVECT_TAB_OFFSET=0x08000000
|
||||
|
||||
build_src_filter =
|
||||
${arduino_base.build_src_filter} -<platform/esp32/> -<platform/apollo3> -<nimble/> -<mesh/api/> -<mesh/http/> -<modules/esp32> -<mesh/eth/> -<mqtt/> -<graphics> -<input> -<buzz> -<modules/Telemetry> -<platform/nrf52> -<platform/portduino> -<platform/rp2040>
|
||||
${arduino_base.build_src_filter} -<platform/esp32/> -<platform/apollo3> -<nimble/> -<mesh/api/> -<mesh/http/> -<modules/esp32> -<mesh/eth/> -<input> -<buzz> -<modules/Telemetry> -<platform/nrf52> -<platform/portduino> -<platform/rp2040>
|
||||
|
||||
board_upload.offset_address = 0x08000000
|
||||
upload_protocol = stlink
|
||||
|
||||
@@ -32,7 +32,7 @@ IF EXIST %FILENAME% IF x%FILENAME:update=%==x%FILENAME% (
|
||||
%PYTHON% -m esptool --baud 115200 write_flash 0x00 %FILENAME%
|
||||
|
||||
@REM Account for S3 board's different OTA partition
|
||||
IF x%FILENAME:s3=%==x%FILENAME% IF x%FILENAME:v3=%==x%FILENAME% (
|
||||
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% (
|
||||
%PYTHON% -m esptool --baud 115200 write_flash 0x260000 bleota.bin
|
||||
) else (
|
||||
%PYTHON% -m esptool --baud 115200 write_flash 0x260000 bleota-s3.bin
|
||||
|
||||
@@ -50,7 +50,7 @@ if [ -f "${FILENAME}" ] && [ ! -z "${FILENAME##*"update"*}" ]; then
|
||||
"$PYTHON" -m esptool erase_flash
|
||||
"$PYTHON" -m esptool write_flash 0x00 ${FILENAME}
|
||||
# Account for S3 board's different OTA partition
|
||||
if [ ! -z "${FILENAME##*"s3"*}" ] && [ ! -z "${FILENAME##*"-v3"*}" ]; then
|
||||
if [ ! -z "${FILENAME##*"s3"*}" ] && [ ! -z "${FILENAME##*"-v3"*}" ] && [ ! -z "${FILENAME##*"t-deck"*}" ] && [ ! -z "${FILENAME##*"wireless-paper"*}" ] && [ ! -z "${FILENAME##*"wireless-tracker"*}" ]; then
|
||||
"$PYTHON" -m esptool write_flash 0x260000 bleota.bin
|
||||
else
|
||||
"$PYTHON" -m esptool write_flash 0x260000 bleota-s3.bin
|
||||
|
||||
38
boards/heltec_wireless_tracker.json
Normal file
38
boards/heltec_wireless_tracker.json
Normal file
@@ -0,0 +1,38 @@
|
||||
{
|
||||
"build": {
|
||||
"arduino": {
|
||||
"ldscript": "esp32s3_out.ld",
|
||||
"partitions": "default_8MB.csv"
|
||||
},
|
||||
"core": "esp32",
|
||||
"extra_flags": [
|
||||
"-DHELTEC_WIRELESS_TRACKER",
|
||||
"-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": [["0x303A", "0x1001"]],
|
||||
"mcu": "esp32s3",
|
||||
"variant": "heltec_wireless_tracker"
|
||||
},
|
||||
"connectivity": ["wifi", "bluetooth", "lora"],
|
||||
"debug": {
|
||||
"openocd_target": "esp32s3.cfg"
|
||||
},
|
||||
"frameworks": ["arduino", "espidf"],
|
||||
"name": "Heltec Wireless Tracker",
|
||||
"upload": {
|
||||
"flash_size": "8MB",
|
||||
"maximum_ram_size": 327680,
|
||||
"maximum_size": 8388608,
|
||||
"wait_for_upload_port": true,
|
||||
"require_upload_port": true,
|
||||
"speed": 921600
|
||||
},
|
||||
"url": "https://heltec.org/project/wireless-tracker/",
|
||||
"vendor": "Heltec"
|
||||
}
|
||||
51
boards/nano-g2-ultra.json
Normal file
51
boards/nano-g2-ultra.json
Normal file
@@ -0,0 +1,51 @@
|
||||
{
|
||||
"build": {
|
||||
"arduino": {
|
||||
"ldscript": "nrf52840_s140_v6.ld"
|
||||
},
|
||||
"core": "nRF5",
|
||||
"cpu": "cortex-m4",
|
||||
"extra_flags": "-DARDUINO_NRF52840_FEATHER -DNRF52840_XXAA",
|
||||
"f_cpu": "64000000L",
|
||||
"hwids": [
|
||||
["0x239A", "0x8029"],
|
||||
["0x239A", "0x0029"],
|
||||
["0x239A", "0x002A"],
|
||||
["0x239A", "0x802A"]
|
||||
],
|
||||
"usb_product": "BQ nRF52840",
|
||||
"mcu": "nrf52840",
|
||||
"variant": "nano-g2-ultra",
|
||||
"bsp": {
|
||||
"name": "adafruit"
|
||||
},
|
||||
"softdevice": {
|
||||
"sd_flags": "-DS140",
|
||||
"sd_name": "s140",
|
||||
"sd_version": "6.1.1",
|
||||
"sd_fwid": "0x00B6"
|
||||
},
|
||||
"bootloader": {
|
||||
"settings_addr": "0xFF000"
|
||||
}
|
||||
},
|
||||
"connectivity": ["bluetooth"],
|
||||
"debug": {
|
||||
"jlink_device": "nRF52840_xxAA",
|
||||
"svd_path": "nrf52840.svd"
|
||||
},
|
||||
"frameworks": ["arduino"],
|
||||
"name": "BQ nRF52840",
|
||||
"upload": {
|
||||
"maximum_ram_size": 248832,
|
||||
"maximum_size": 815104,
|
||||
"speed": 115200,
|
||||
"protocol": "nrfutil",
|
||||
"protocols": ["jlink", "nrfjprog", "nrfutil", "stlink"],
|
||||
"use_1200bps_touch": true,
|
||||
"require_upload_port": true,
|
||||
"wait_for_upload_port": true
|
||||
},
|
||||
"url": "https://wiki.uniteng.com/en/meshtastic/nano-g2-ultra",
|
||||
"vendor": "BQ Consulting"
|
||||
}
|
||||
40
boards/t-deck.json
Normal file
40
boards/t-deck.json
Normal file
@@ -0,0 +1,40 @@
|
||||
{
|
||||
"build": {
|
||||
"arduino": {
|
||||
"ldscript": "esp32s3_out.ld"
|
||||
},
|
||||
"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": "dio",
|
||||
"hwids": [["0x303A", "0x1001"]],
|
||||
"mcu": "esp32s3",
|
||||
"variant": "t-deck"
|
||||
},
|
||||
"connectivity": ["wifi", "bluetooth", "lora"],
|
||||
"debug": {
|
||||
"default_tool": "esp-builtin",
|
||||
"onboard_tools": ["esp-builtin"],
|
||||
"openocd_target": "esp32s3.cfg"
|
||||
},
|
||||
"frameworks": ["arduino", "espidf"],
|
||||
"name": "Espressif Systems LilyGO T-Deck (16 MB FLASH, 8 MB PSRAM)",
|
||||
"upload": {
|
||||
"flash_size": "16MB",
|
||||
"maximum_ram_size": 327680,
|
||||
"maximum_size": 16777216,
|
||||
"use_1200bps_touch": true,
|
||||
"wait_for_upload_port": true,
|
||||
"require_upload_port": true,
|
||||
"speed": 921600
|
||||
},
|
||||
"url": "https://www.lilygo.cc/en-pl/products/t-deck",
|
||||
"vendor": "LilyGO"
|
||||
}
|
||||
@@ -7,7 +7,10 @@
|
||||
"cpu": "cortex-m4",
|
||||
"extra_flags": "-DARDUINO_NRF52840_TTGO_EINK -DNRF52840_XXAA",
|
||||
"f_cpu": "64000000L",
|
||||
"hwids": [["0x239A", "0x4405"]],
|
||||
"hwids": [
|
||||
["0x239A", "0x4405"],
|
||||
["0x239A", "0x002A"]
|
||||
],
|
||||
"usb_product": "TTGO_eink",
|
||||
"mcu": "nrf52840",
|
||||
"variant": "t-echo",
|
||||
|
||||
38
boards/t-watch-s3.json
Normal file
38
boards/t-watch-s3.json
Normal file
@@ -0,0 +1,38 @@
|
||||
{
|
||||
"build": {
|
||||
"arduino": {
|
||||
"ldscript": "esp32s3_out.ld"
|
||||
},
|
||||
"core": "esp32",
|
||||
"extra_flags": [
|
||||
"-DBOARD_HAS_PSRAM",
|
||||
"-DT_WATCH_S3",
|
||||
"-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": "dio",
|
||||
"hwids": [["0X303A", "0x1001"]],
|
||||
"mcu": "esp32s3",
|
||||
"variant": "t-watch-s3"
|
||||
},
|
||||
"connectivity": ["wifi"],
|
||||
"debug": {
|
||||
"openocd_target": "esp32s3.cfg"
|
||||
},
|
||||
"frameworks": ["arduino"],
|
||||
"name": "LilyGo T-Watch 2020 V3",
|
||||
"upload": {
|
||||
"flash_size": "8MB",
|
||||
"maximum_ram_size": 327680,
|
||||
"maximum_size": 8388608,
|
||||
"require_upload_port": true,
|
||||
"use_1200bps_touch": true,
|
||||
"wait_for_upload_port": true
|
||||
},
|
||||
"url": "http://www.lilygo.cn/",
|
||||
"vendor": "LilyGo"
|
||||
}
|
||||
57
boards/xiao_ble_sense.json
Normal file
57
boards/xiao_ble_sense.json
Normal file
@@ -0,0 +1,57 @@
|
||||
{
|
||||
"build": {
|
||||
"arduino": {
|
||||
"ldscript": "nrf52840_s140_v7.ld"
|
||||
},
|
||||
"core": "nRF5",
|
||||
"cpu": "cortex-m4",
|
||||
"extra_flags": "-DARDUINO_MDBT50Q_RX -DNRF52840_XXAA",
|
||||
"f_cpu": "64000000L",
|
||||
"hwids": [
|
||||
["0x239A", "0x810B"],
|
||||
["0x239A", "0x010B"],
|
||||
["0x239A", "0x810C"]
|
||||
],
|
||||
"usb_product": "XIAO-BOOT",
|
||||
"mcu": "nrf52840",
|
||||
"variant": "Seeed_XIAO_nRF52840_Sense",
|
||||
"bsp": {
|
||||
"name": "adafruit"
|
||||
},
|
||||
"softdevice": {
|
||||
"sd_flags": "-DS140",
|
||||
"sd_name": "s140",
|
||||
"sd_version": "7.3.0",
|
||||
"sd_fwid": "0x0123"
|
||||
},
|
||||
"bootloader": {
|
||||
"settings_addr": "0xFF000"
|
||||
}
|
||||
},
|
||||
"connectivity": ["bluetooth"],
|
||||
"debug": {
|
||||
"jlink_device": "nRF52840_xxAA",
|
||||
"svd_path": "nrf52840.svd"
|
||||
},
|
||||
"frameworks": ["arduino"],
|
||||
"name": "Seeed Xiao BLE Sense",
|
||||
"upload": {
|
||||
"maximum_ram_size": 248832,
|
||||
"maximum_size": 815104,
|
||||
"speed": 115200,
|
||||
"protocol": "nrfutil",
|
||||
"protocols": [
|
||||
"jlink",
|
||||
"nrfjprog",
|
||||
"nrfutil",
|
||||
"stlink",
|
||||
"cmsis-dap",
|
||||
"blackmagic"
|
||||
],
|
||||
"use_1200bps_touch": true,
|
||||
"require_upload_port": true,
|
||||
"wait_for_upload_port": true
|
||||
},
|
||||
"url": "https://www.seeedstudio.com/Seeed-XIAO-BLE-Sense-nRF52840-p-5253.html",
|
||||
"vendor": "Seeed Studio"
|
||||
}
|
||||
@@ -9,6 +9,7 @@
|
||||
;default_envs = heltec-v1
|
||||
;default_envs = heltec-v2_0
|
||||
;default_envs = heltec-v2_1
|
||||
;default_envs = heltec-wireless-tracker
|
||||
;default_envs = tlora-v1
|
||||
;default_envs = tlora_v1_3
|
||||
;default_envs = tlora-v2
|
||||
@@ -120,3 +121,4 @@ lib_deps =
|
||||
adafruit/Adafruit PM25 AQI Sensor@^1.0.6
|
||||
adafruit/Adafruit MPU6050@^2.2.4
|
||||
adafruit/Adafruit LIS3DH@^1.2.4
|
||||
https://github.com/lewisxhe/BMA423_Library@^0.0.1
|
||||
Submodule protobufs updated: e4396fd499...6f88374ec6
@@ -4,14 +4,39 @@
|
||||
#include "main.h"
|
||||
#include "power.h"
|
||||
|
||||
#if defined(HAS_TELEMETRY) && (HAS_TELEMETRY == 1)
|
||||
|
||||
#include <Adafruit_LIS3DH.h>
|
||||
#include <Adafruit_MPU6050.h>
|
||||
#include <Arduino.h>
|
||||
#include <Wire.h>
|
||||
#include <bma.h>
|
||||
|
||||
BMA423 bmaSensor;
|
||||
bool BMA_IRQ = false;
|
||||
|
||||
#define ACCELEROMETER_CHECK_INTERVAL_MS 100
|
||||
#define ACCELEROMETER_CLICK_THRESHOLD 40
|
||||
|
||||
uint16_t readRegister(uint8_t address, uint8_t reg, uint8_t *data, uint16_t len)
|
||||
{
|
||||
Wire.beginTransmission(address);
|
||||
Wire.write(reg);
|
||||
Wire.endTransmission();
|
||||
Wire.requestFrom((uint8_t)address, (uint8_t)len);
|
||||
uint8_t i = 0;
|
||||
while (Wire.available()) {
|
||||
data[i++] = Wire.read();
|
||||
}
|
||||
return 0; // Pass
|
||||
}
|
||||
|
||||
uint16_t writeRegister(uint8_t address, uint8_t reg, uint8_t *data, uint16_t len)
|
||||
{
|
||||
Wire.beginTransmission(address);
|
||||
Wire.write(reg);
|
||||
Wire.write(data, len);
|
||||
return (0 != Wire.endTransmission());
|
||||
}
|
||||
|
||||
namespace concurrency
|
||||
{
|
||||
class AccelerometerThread : public concurrency::OSThread
|
||||
@@ -31,10 +56,10 @@ class AccelerometerThread : public concurrency::OSThread
|
||||
return;
|
||||
}
|
||||
|
||||
accleremoter_type = type;
|
||||
acceleremoter_type = type;
|
||||
LOG_DEBUG("AccelerometerThread initializing\n");
|
||||
|
||||
if (accleremoter_type == ScanI2C::DeviceType::MPU6050 && mpu.begin(accelerometer_found.address)) {
|
||||
if (acceleremoter_type == ScanI2C::DeviceType::MPU6050 && mpu.begin(accelerometer_found.address)) {
|
||||
LOG_DEBUG("MPU6050 initializing\n");
|
||||
// setup motion detection
|
||||
mpu.setHighPassFilter(MPU6050_HIGHPASS_0_63_HZ);
|
||||
@@ -42,11 +67,60 @@ class AccelerometerThread : public concurrency::OSThread
|
||||
mpu.setMotionDetectionDuration(20);
|
||||
mpu.setInterruptPinLatch(true); // Keep it latched. Will turn off when reinitialized.
|
||||
mpu.setInterruptPinPolarity(true);
|
||||
} else if (accleremoter_type == ScanI2C::DeviceType::LIS3DH && lis.begin(accelerometer_found.address)) {
|
||||
} else if (acceleremoter_type == ScanI2C::DeviceType::LIS3DH && lis.begin(accelerometer_found.address)) {
|
||||
LOG_DEBUG("LIS3DH initializing\n");
|
||||
lis.setRange(LIS3DH_RANGE_2_G);
|
||||
// Adjust threshhold, higher numbers are less sensitive
|
||||
// Adjust threshold, higher numbers are less sensitive
|
||||
lis.setClick(config.device.double_tap_as_button_press ? 2 : 1, ACCELEROMETER_CLICK_THRESHOLD);
|
||||
} else if (acceleremoter_type == ScanI2C::DeviceType::BMA423 && bmaSensor.begin(readRegister, writeRegister, delay)) {
|
||||
LOG_DEBUG("BMA423 initializing\n");
|
||||
Acfg cfg;
|
||||
cfg.odr = BMA4_OUTPUT_DATA_RATE_100HZ;
|
||||
cfg.range = BMA4_ACCEL_RANGE_2G;
|
||||
cfg.bandwidth = BMA4_ACCEL_NORMAL_AVG4;
|
||||
cfg.perf_mode = BMA4_CONTINUOUS_MODE;
|
||||
bmaSensor.setAccelConfig(cfg);
|
||||
bmaSensor.enableAccel();
|
||||
|
||||
struct bma4_int_pin_config pin_config;
|
||||
pin_config.edge_ctrl = BMA4_LEVEL_TRIGGER;
|
||||
pin_config.lvl = BMA4_ACTIVE_HIGH;
|
||||
pin_config.od = BMA4_PUSH_PULL;
|
||||
pin_config.output_en = BMA4_OUTPUT_ENABLE;
|
||||
pin_config.input_en = BMA4_INPUT_DISABLE;
|
||||
// The correct trigger interrupt needs to be configured as needed
|
||||
bmaSensor.setINTPinConfig(pin_config, BMA4_INTR1_MAP);
|
||||
|
||||
#ifdef BMA423_INT
|
||||
pinMode(BMA4XX_INT, INPUT);
|
||||
attachInterrupt(
|
||||
BMA4XX_INT,
|
||||
[] {
|
||||
// Set interrupt to set irq value to true
|
||||
BMA_IRQ = true;
|
||||
},
|
||||
RISING); // Select the interrupt mode according to the actual circuit
|
||||
#endif
|
||||
|
||||
struct bma423_axes_remap remap_data;
|
||||
remap_data.x_axis = 0;
|
||||
remap_data.x_axis_sign = 1;
|
||||
remap_data.y_axis = 1;
|
||||
remap_data.y_axis_sign = 0;
|
||||
remap_data.z_axis = 2;
|
||||
remap_data.z_axis_sign = 1;
|
||||
// Need to raise the wrist function, need to set the correct axis
|
||||
bmaSensor.setRemapAxes(&remap_data);
|
||||
// sensor.enableFeature(BMA423_STEP_CNTR, true);
|
||||
bmaSensor.enableFeature(BMA423_TILT, true);
|
||||
bmaSensor.enableFeature(BMA423_WAKEUP, true);
|
||||
// sensor.resetStepCounter();
|
||||
|
||||
// Turn on feature interrupt
|
||||
bmaSensor.enableStepCountInterrupt();
|
||||
bmaSensor.enableTiltInterrupt();
|
||||
// It corresponds to isDoubleClick interrupt
|
||||
bmaSensor.enableWakeupInterrupt();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -55,9 +129,9 @@ class AccelerometerThread : public concurrency::OSThread
|
||||
{
|
||||
canSleep = true; // Assume we should not keep the board awake
|
||||
|
||||
if (accleremoter_type == ScanI2C::DeviceType::MPU6050 && mpu.getMotionInterruptStatus()) {
|
||||
if (acceleremoter_type == ScanI2C::DeviceType::MPU6050 && mpu.getMotionInterruptStatus()) {
|
||||
wakeScreen();
|
||||
} else if (accleremoter_type == ScanI2C::DeviceType::LIS3DH && lis.getClick() > 0) {
|
||||
} else if (acceleremoter_type == ScanI2C::DeviceType::LIS3DH && lis.getClick() > 0) {
|
||||
uint8_t click = lis.getClick();
|
||||
if (!config.device.double_tap_as_button_press) {
|
||||
wakeScreen();
|
||||
@@ -67,7 +141,13 @@ class AccelerometerThread : public concurrency::OSThread
|
||||
buttonPress();
|
||||
return 500;
|
||||
}
|
||||
} else if (acceleremoter_type == ScanI2C::DeviceType::BMA423 && bmaSensor.getINT()) {
|
||||
if (bmaSensor.isTilt() || bmaSensor.isDoubleClick()) {
|
||||
wakeScreen();
|
||||
return 500;
|
||||
}
|
||||
}
|
||||
|
||||
return ACCELEROMETER_CHECK_INTERVAL_MS;
|
||||
}
|
||||
|
||||
@@ -86,11 +166,9 @@ class AccelerometerThread : public concurrency::OSThread
|
||||
powerFSM.trigger(EVENT_PRESS);
|
||||
}
|
||||
|
||||
ScanI2C::DeviceType accleremoter_type;
|
||||
ScanI2C::DeviceType acceleremoter_type;
|
||||
Adafruit_MPU6050 mpu;
|
||||
Adafruit_LIS3DH lis;
|
||||
};
|
||||
|
||||
} // namespace concurrency
|
||||
|
||||
#endif
|
||||
@@ -4,6 +4,7 @@
|
||||
#include "concurrency/OSThread.h"
|
||||
#include "configuration.h"
|
||||
#include "graphics/Screen.h"
|
||||
#include "main.h"
|
||||
#include "power.h"
|
||||
#include <OneButton.h>
|
||||
|
||||
@@ -98,10 +99,10 @@ class ButtonThread : public concurrency::OSThread
|
||||
userButtonTouch.tick();
|
||||
canSleep &= userButtonTouch.isIdle();
|
||||
#endif
|
||||
// if (!canSleep) LOG_DEBUG("Supressing sleep!\n");
|
||||
// if (!canSleep) LOG_DEBUG("Suppressing sleep!\n");
|
||||
// else LOG_DEBUG("sleep ok\n");
|
||||
|
||||
return 5;
|
||||
return 50;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
@@ -8,6 +8,8 @@
|
||||
#ifdef SDCARD_USE_SPI1
|
||||
SPIClass SPI1(HSPI);
|
||||
#define SDHandler SPI1
|
||||
#else
|
||||
#define SDHandler SPI
|
||||
#endif
|
||||
|
||||
#endif // HAS_SDCARD
|
||||
|
||||
@@ -106,7 +106,7 @@ 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.pos_timestamp, p.pos_timestamp);
|
||||
LOG_DEBUG("GPSStatus.match() new pos@%x to old pos@%x\n", newStatus->p.timestamp, p.timestamp);
|
||||
#endif
|
||||
return (newStatus->hasLock != hasLock || newStatus->isConnected != isConnected ||
|
||||
newStatus->isPowerSaving != isPowerSaving || newStatus->p.latitude_i != p.latitude_i ||
|
||||
|
||||
@@ -5,7 +5,8 @@
|
||||
* Schedule a callback to run. The callback must _not_ block, though it is called from regular thread level (not ISR)
|
||||
*
|
||||
* NOTE! xTimerPend... seems to ignore the time passed in on ESP32 and on NRF52
|
||||
* The reason this didn't work is bcause xTimerPednFunctCall really isn't a timer function at all - it just means run the callback
|
||||
* The reason this didn't work is because xTimerPednFunctCall really isn't a timer function at all - it just means run the
|
||||
callback
|
||||
* from the timer thread the next time you have spare cycles.
|
||||
*
|
||||
* @return true if successful, false if the timer fifo is too full.
|
||||
|
||||
@@ -50,7 +50,7 @@ XPowersLibInterface *PMU = NULL;
|
||||
#else
|
||||
|
||||
// Copy of the base class defined in axp20x.h.
|
||||
// I'd rather not inlude axp20x.h as it brings Wire dependency.
|
||||
// I'd rather not include axp20x.h as it brings Wire dependency.
|
||||
class HasBatteryLevel
|
||||
{
|
||||
public:
|
||||
@@ -540,10 +540,12 @@ int32_t Power::runOnce()
|
||||
LOG_DEBUG("Battery removed\n");
|
||||
}
|
||||
*/
|
||||
#ifndef T_WATCH_S3 // FIXME - why is this triggering on the T-Watch S3?
|
||||
if (PMU->isPekeyLongPressIrq()) {
|
||||
LOG_DEBUG("PEK long button press\n");
|
||||
screen->setOn(false);
|
||||
}
|
||||
#endif
|
||||
|
||||
PMU->clearIrqStatus();
|
||||
}
|
||||
@@ -681,7 +683,8 @@ bool Power::axpChipInit()
|
||||
// GNSS VDD 3300mV
|
||||
PMU->setPowerChannelVoltage(XPOWERS_ALDO3, 3300);
|
||||
PMU->enablePowerOutput(XPOWERS_ALDO3);
|
||||
} else if (HW_VENDOR == meshtastic_HardwareModel_LILYGO_TBEAM_S3_CORE) {
|
||||
} else if (HW_VENDOR == meshtastic_HardwareModel_LILYGO_TBEAM_S3_CORE ||
|
||||
HW_VENDOR == meshtastic_HardwareModel_T_WATCH_S3) {
|
||||
// t-beam s3 core
|
||||
/**
|
||||
* gnss module power channel
|
||||
@@ -712,10 +715,16 @@ bool Power::axpChipInit()
|
||||
PMU->setPowerChannelVoltage(XPOWERS_ALDO1, 3300);
|
||||
PMU->enablePowerOutput(XPOWERS_ALDO1);
|
||||
|
||||
// sdcard power channle
|
||||
// sdcard power channel
|
||||
PMU->setPowerChannelVoltage(XPOWERS_BLDO1, 3300);
|
||||
PMU->enablePowerOutput(XPOWERS_BLDO1);
|
||||
|
||||
#ifdef T_WATCH_S3
|
||||
// DRV2605 power channel
|
||||
PMU->setPowerChannelVoltage(XPOWERS_BLDO2, 3300);
|
||||
PMU->enablePowerOutput(XPOWERS_BLDO2);
|
||||
#endif
|
||||
|
||||
// PMU->setPowerChannelVoltage(XPOWERS_DCDC4, 3300);
|
||||
// PMU->enablePowerOutput(XPOWERS_DCDC4);
|
||||
|
||||
|
||||
@@ -352,5 +352,5 @@ void PowerFSM_setup()
|
||||
"mesh timeout");
|
||||
#endif
|
||||
|
||||
powerFSM.run_machine(); // run one interation of the state machine, so we run our on enter tasks for the initial DARK state
|
||||
powerFSM.run_machine(); // run one iteration of the state machine, so we run our on enter tasks for the initial DARK state
|
||||
}
|
||||
@@ -17,9 +17,9 @@
|
||||
|
||||
Example analytics:
|
||||
|
||||
TX_LOG + RX_LOG = Total air time for a perticular meshtastic channel.
|
||||
TX_LOG + RX_LOG = Total air time for a particular meshtastic channel.
|
||||
|
||||
TX_LOG + RX_LOG = Total air time for a perticular meshtastic channel, including
|
||||
TX_LOG + RX_LOG = Total air time for a particular meshtastic channel, including
|
||||
other lora radios.
|
||||
|
||||
RX_ALL_LOG - RX_LOG = Other lora radios on our frequency channel.
|
||||
|
||||
@@ -15,4 +15,6 @@ enum class Cmd {
|
||||
PRINT,
|
||||
START_SHUTDOWN_SCREEN,
|
||||
START_REBOOT_SCREEN,
|
||||
SHOW_PREV_FRAME,
|
||||
SHOW_NEXT_FRAME
|
||||
};
|
||||
@@ -18,7 +18,7 @@ namespace concurrency
|
||||
*
|
||||
* Useful for they top level loop() delay call to keep the CPU powered down until our next scheduled event or some external event.
|
||||
*
|
||||
* This is implmented for FreeRTOS but should be easy to port to other operating systems.
|
||||
* This is implemented for FreeRTOS but should be easy to port to other operating systems.
|
||||
*/
|
||||
class InterruptableDelay
|
||||
{
|
||||
|
||||
@@ -98,8 +98,9 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
// Define if screen should be mirrored left to right
|
||||
// #define SCREEN_MIRROR
|
||||
|
||||
// The m5stack I2C Keyboard (also RAK14004)
|
||||
// I2C Keyboards (M5Stack, RAK14004, T-Deck)
|
||||
#define CARDKB_ADDR 0x5F
|
||||
#define TDECK_KB_ADDR 0x55
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// SENSOR
|
||||
@@ -123,6 +124,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
// -----------------------------------------------------------------------------
|
||||
#define MPU6050_ADDR 0x68
|
||||
#define LIS3DH_ADR 0x18
|
||||
#define BMA423_ADDR 0x19
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// LED
|
||||
@@ -172,6 +174,12 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#ifndef HAS_BUTTON
|
||||
#define HAS_BUTTON 0
|
||||
#endif
|
||||
#ifndef HAS_TRACKBALL
|
||||
#define HAS_TRACKBALL 0
|
||||
#endif
|
||||
#ifndef HAS_TOUCHSCREEN
|
||||
#define HAS_TOUCHSCREEN 0
|
||||
#endif
|
||||
#ifndef HAS_TELEMETRY
|
||||
#define HAS_TELEMETRY 0
|
||||
#endif
|
||||
|
||||
@@ -30,14 +30,14 @@ ScanI2C::FoundDevice ScanI2C::firstRTC() const
|
||||
|
||||
ScanI2C::FoundDevice ScanI2C::firstKeyboard() const
|
||||
{
|
||||
ScanI2C::DeviceType types[] = {CARDKB, RAK14004};
|
||||
return firstOfOrNONE(2, types);
|
||||
ScanI2C::DeviceType types[] = {CARDKB, TDECKKB, RAK14004};
|
||||
return firstOfOrNONE(3, types);
|
||||
}
|
||||
|
||||
ScanI2C::FoundDevice ScanI2C::firstAccelerometer() const
|
||||
{
|
||||
ScanI2C::DeviceType types[] = {MPU6050, LIS3DH};
|
||||
return firstOfOrNONE(2, types);
|
||||
ScanI2C::DeviceType types[] = {MPU6050, LIS3DH, BMA423};
|
||||
return firstOfOrNONE(3, types);
|
||||
}
|
||||
|
||||
ScanI2C::FoundDevice ScanI2C::find(ScanI2C::DeviceType) const
|
||||
|
||||
@@ -16,6 +16,7 @@ class ScanI2C
|
||||
RTC_RV3028,
|
||||
RTC_PCF8563,
|
||||
CARDKB,
|
||||
TDECKKB,
|
||||
RAK14004,
|
||||
PMU_AXP192_AXP2101,
|
||||
BME_680,
|
||||
@@ -33,7 +34,10 @@ class ScanI2C
|
||||
PMSA0031,
|
||||
MPU6050,
|
||||
LIS3DH,
|
||||
BMA423,
|
||||
#ifdef HAS_NCP5623
|
||||
NCP5623,
|
||||
#endif
|
||||
} DeviceType;
|
||||
|
||||
// typedef uint8_t DeviceAddress;
|
||||
|
||||
@@ -212,9 +212,11 @@ void ScanI2CTwoWire::scanPort(I2CPort port)
|
||||
}
|
||||
break;
|
||||
|
||||
SCAN_SIMPLE_CASE(ST7567_ADDRESS, SCREEN_ST7567, "st7567 display found\n")
|
||||
SCAN_SIMPLE_CASE(TDECK_KB_ADDR, TDECKKB, "T-Deck keyboard found\n");
|
||||
SCAN_SIMPLE_CASE(ST7567_ADDRESS, SCREEN_ST7567, "st7567 display found\n");
|
||||
#ifdef HAS_NCP5623
|
||||
SCAN_SIMPLE_CASE(NCP5623_ADDR, NCP5623, "NCP5623 RGB LED found\n");
|
||||
|
||||
#endif
|
||||
#ifdef HAS_PMU
|
||||
SCAN_SIMPLE_CASE(XPOWERS_AXP192_AXP2101_ADDRESS, PMU_AXP192_AXP2101, "axp192/axp2101 PMU found\n")
|
||||
#endif
|
||||
@@ -273,6 +275,7 @@ void ScanI2CTwoWire::scanPort(I2CPort port)
|
||||
|
||||
SCAN_SIMPLE_CASE(PMSA0031_ADDR, PMSA0031, "PMSA0031 air quality sensor found\n")
|
||||
SCAN_SIMPLE_CASE(MPU6050_ADDR, MPU6050, "MPU6050 accelerometer found\n");
|
||||
SCAN_SIMPLE_CASE(BMA423_ADDR, BMA423, "BMA423 accelerometer found\n");
|
||||
|
||||
default:
|
||||
LOG_INFO("Device found at address 0x%x was not able to be enumerated\n", addr.address);
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#include "../configuration.h"
|
||||
|
||||
#ifdef RAK4630
|
||||
#ifdef RAK_4631
|
||||
#include "../main.h"
|
||||
#include <SPI.h>
|
||||
|
||||
|
||||
455
src/gps/GPS.cpp
455
src/gps/GPS.cpp
@@ -4,6 +4,10 @@
|
||||
#include "configuration.h"
|
||||
#include "sleep.h"
|
||||
|
||||
#ifndef GPS_RESET_MODE
|
||||
#define GPS_RESET_MODE HIGH
|
||||
#endif
|
||||
|
||||
// If we have a serial GPS port it will not be null
|
||||
#ifdef GPS_SERIAL_NUM
|
||||
HardwareSerial _serial_gps_real(GPS_SERIAL_NUM);
|
||||
@@ -21,11 +25,29 @@ GPS *gps;
|
||||
/// only init that port once.
|
||||
static bool didSerialInit;
|
||||
|
||||
bool GPS::getACK(uint8_t c, uint8_t i)
|
||||
struct uBloxGnssModelInfo info;
|
||||
uint8_t uBloxProtocolVersion;
|
||||
|
||||
void GPS::UBXChecksum(byte *message, size_t length)
|
||||
{
|
||||
uint8_t CK_A = 0, CK_B = 0;
|
||||
|
||||
// Calculate the checksum, starting from the CLASS field (which is message[2])
|
||||
for (size_t i = 2; i < length - 2; i++) {
|
||||
CK_A = (CK_A + message[i]) & 0xFF;
|
||||
CK_B = (CK_B + CK_A) & 0xFF;
|
||||
}
|
||||
|
||||
// Place the calculated checksum values in the message
|
||||
message[length - 2] = CK_A;
|
||||
message[length - 1] = CK_B;
|
||||
}
|
||||
|
||||
bool GPS::getACK(uint8_t class_id, uint8_t msg_id)
|
||||
{
|
||||
uint8_t b;
|
||||
uint8_t ack = 0;
|
||||
const uint8_t ackP[2] = {c, i};
|
||||
const uint8_t ackP[2] = {class_id, msg_id};
|
||||
uint8_t buf[10] = {0xB5, 0x62, 0x05, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00};
|
||||
unsigned long startTime = millis();
|
||||
|
||||
@@ -42,17 +64,23 @@ bool GPS::getACK(uint8_t c, uint8_t i)
|
||||
|
||||
while (1) {
|
||||
if (ack > 9) {
|
||||
return true;
|
||||
// LOG_INFO("Got ACK for class %02X message %02X\n", class_id, msg_id);
|
||||
return true; // ACK received
|
||||
}
|
||||
if (millis() - startTime > 1000) {
|
||||
return false;
|
||||
if (millis() - startTime > 3000) {
|
||||
LOG_WARN("No response for class %02X message %02X\n", class_id, msg_id);
|
||||
return false; // No response received within 3 seconds
|
||||
}
|
||||
if (_serial_gps->available()) {
|
||||
b = _serial_gps->read();
|
||||
if (b == buf[ack]) {
|
||||
ack++;
|
||||
} else {
|
||||
ack = 0;
|
||||
ack = 0; // Reset the acknowledgement counter
|
||||
if (buf[3] == 0x00) { // UBX-ACK-NAK message
|
||||
LOG_WARN("Got NAK for class %02X message %02X\n", class_id, msg_id);
|
||||
return false; // NAK received
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -73,7 +101,7 @@ int GPS::getAck(uint8_t *buffer, uint16_t size, uint8_t requestedClass, uint8_t
|
||||
uint32_t startTime = millis();
|
||||
uint16_t needRead;
|
||||
|
||||
while (millis() - startTime < 800) {
|
||||
while (millis() - startTime < 1200) {
|
||||
while (_serial_gps->available()) {
|
||||
int c = _serial_gps->read();
|
||||
switch (ubxFrameCounter) {
|
||||
@@ -108,12 +136,12 @@ int GPS::getAck(uint8_t *buffer, uint16_t size, uint8_t requestedClass, uint8_t
|
||||
}
|
||||
break;
|
||||
case 4:
|
||||
// Payload lenght lsb
|
||||
// Payload length lsb
|
||||
needRead = c;
|
||||
ubxFrameCounter++;
|
||||
break;
|
||||
case 5:
|
||||
// Payload lenght msb
|
||||
// Payload length msb
|
||||
needRead |= (c << 8);
|
||||
ubxFrameCounter++;
|
||||
break;
|
||||
@@ -126,7 +154,7 @@ int GPS::getAck(uint8_t *buffer, uint16_t size, uint8_t requestedClass, uint8_t
|
||||
if (_serial_gps->readBytes(buffer, needRead) != needRead) {
|
||||
ubxFrameCounter = 0;
|
||||
} else {
|
||||
// return payload lenght
|
||||
// return payload length
|
||||
return needRead;
|
||||
}
|
||||
break;
|
||||
@@ -160,10 +188,14 @@ bool GPS::setupGPS()
|
||||
config.position.tx_gpio = GPS_TX_PIN;
|
||||
#endif
|
||||
|
||||
//#define BAUD_RATE 115200
|
||||
// ESP32 has a special set of parameters vs other arduino ports
|
||||
#if defined(ARCH_ESP32)
|
||||
if (config.position.rx_gpio)
|
||||
if (config.position.rx_gpio) {
|
||||
LOG_DEBUG("Using GPIO%d for GPS RX\n", config.position.rx_gpio);
|
||||
LOG_DEBUG("Using GPIO%d for GPS TX\n", config.position.tx_gpio);
|
||||
_serial_gps->begin(GPS_BAUDRATE, SERIAL_8N1, config.position.rx_gpio, config.position.tx_gpio);
|
||||
}
|
||||
#else
|
||||
_serial_gps->begin(GPS_BAUDRATE);
|
||||
#endif
|
||||
@@ -190,8 +222,131 @@ bool GPS::setupGPS()
|
||||
// Switch to Vehicle Mode, since SoftRF enables Aviation < 2g
|
||||
_serial_gps->write("$PCAS11,3*1E\r\n");
|
||||
delay(250);
|
||||
} else if (gnssModel == GNSS_MODEL_UC6850) {
|
||||
|
||||
// use GPS + GLONASS
|
||||
_serial_gps->write("$CFGSYS,h15\r\n");
|
||||
delay(250);
|
||||
} else if (gnssModel == GNSS_MODEL_UBLOX) {
|
||||
|
||||
// Configure GNSS system to GPS+SBAS+GLONASS (Module may restart after this command)
|
||||
// We need set it because by default it is GPS only, and we want to use GLONASS too
|
||||
// Also we need SBAS for better accuracy and extra features
|
||||
// ToDo: Dynamic configure GNSS systems depending of LoRa region
|
||||
byte _message_GNSS[36] = {
|
||||
0xb5, 0x62, // Sync message for UBX protocol
|
||||
0x06, 0x3e, // Message class and ID (UBX-CFG-GNSS)
|
||||
0x1c, 0x00, // Length of payload (28 bytes)
|
||||
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)
|
||||
0x03, // numConfigBlocks (number of GNSS systems), most modules support maximum 3 GNSS systems
|
||||
// GNSS config format: gnssId, resTrkCh, maxTrkCh, reserved1, flags
|
||||
0x00, 0x08, 0x10, 0x00, 0x01, 0x00, 0x01, 0x01, // GPS
|
||||
0x01, 0x01, 0x03, 0x00, 0x01, 0x00, 0x01, 0x01, // SBAS
|
||||
0x06, 0x08, 0x0e, 0x00, 0x01, 0x00, 0x01, 0x01, // GLONASS
|
||||
0x00, 0x00 // Checksum (to be calculated below)
|
||||
};
|
||||
|
||||
// Calculate the checksum and update the message.
|
||||
UBXChecksum(_message_GNSS, sizeof(_message_GNSS));
|
||||
|
||||
// Send the message to the module
|
||||
_serial_gps->write(_message_GNSS, sizeof(_message_GNSS));
|
||||
|
||||
if (!getACK(0x06, 0x3e)) {
|
||||
// It's not critical if the module doesn't acknowledge this configuration.
|
||||
// The module should operate adequately with its factory or previously saved settings.
|
||||
// It appears that there is a firmware bug in some GPS modules: When an attempt is made
|
||||
// to overwrite a saved state with identical values, no ACK/NAK is received, contrary to
|
||||
// what is specified in the Ublox documentation.
|
||||
// There is also a possibility that the module may be GPS-only.
|
||||
LOG_INFO("Unable to reconfigure GNSS - defaults maintained. Is this module GPS-only?\n");
|
||||
return true;
|
||||
} else {
|
||||
LOG_INFO("GNSS configured for GPS+SBAS+GLONASS. Pause for 0.75s before sending next command.\n");
|
||||
// Documentation say, we need wait atleast 0.5s after reconfiguration of GNSS module, before sending next commands
|
||||
delay(750);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Enable interference resistance, because we are using LoRa, WiFi and Bluetooth on same board,
|
||||
// and we need to reduce interference from them
|
||||
byte _message_JAM[16] = {
|
||||
0xB5, 0x62, // UBX protocol sync characters
|
||||
0x06, 0x39, // Message class and ID (UBX-CFG-ITFM)
|
||||
0x08, 0x00, // Length of payload (8 bytes)
|
||||
// bbThreshold (Broadband jamming detection threshold) is set to 0x3F (63 in decimal)
|
||||
// cwThreshold (CW jamming detection threshold) is set to 0x10 (16 in decimal)
|
||||
// algorithmBits (Reserved algorithm settings) is set to 0x16B156 as recommended
|
||||
// enable (Enable interference detection) is set to 1 (enabled)
|
||||
0x3F, 0x10, 0xB1, 0x56, // config: Interference config word
|
||||
// generalBits (General settings) is set to 0x31E as recommended
|
||||
// antSetting (Antenna setting, 0=unknown, 1=passive, 2=active) is set to 0 (unknown)
|
||||
// ToDo: Set to 1 (passive) or 2 (active) if known, for example from UBX-MON-HW, or from board info
|
||||
// enable2 (Set to 1 to scan auxiliary bands, u-blox 8 / u-blox M8 only, otherwise ignored) is set to 1
|
||||
// (enabled)
|
||||
0x1E, 0x03, 0x00, 0x01, // config2: Extra settings for jamming/interference monitor
|
||||
0x00, 0x00 // Checksum (calculated below)
|
||||
};
|
||||
|
||||
// Calculate the checksum and update the message.
|
||||
UBXChecksum(_message_JAM, sizeof(_message_JAM));
|
||||
|
||||
// Send the message to the module
|
||||
_serial_gps->write(_message_JAM, sizeof(_message_JAM));
|
||||
|
||||
if (!getACK(0x06, 0x39)) {
|
||||
LOG_WARN("Unable to enable interference resistance.\n");
|
||||
return true;
|
||||
}
|
||||
|
||||
// Configure navigation engine expert settings:
|
||||
byte _message_NAVX5[48] = {
|
||||
0xb5, 0x62, // UBX protocol sync characters
|
||||
0x06, 0x23, // Message class and ID (UBX-CFG-NAVX5)
|
||||
0x28, 0x00, // Length of payload (40 bytes)
|
||||
0x00, 0x00, // msgVer (0 for this version)
|
||||
// minMax flag = 1: apply min/max SVs settings
|
||||
// minCno flag = 1: apply minimum C/N0 setting
|
||||
// initial3dfix flag = 0: apply initial 3D fix settings
|
||||
// aop flag = 1: apply aopCfg (useAOP flag) settings (AssistNow Autonomous)
|
||||
0x1B, 0x00, // mask1 (First parameters bitmask)
|
||||
// adr flag = 0: apply ADR sensor fusion on/off setting (useAdr flag)
|
||||
// If firmware is not ADR/UDR, enabling this flag will fail configuration
|
||||
// ToDo: check this with UBX-MON-VER
|
||||
0x00, 0x00, 0x00, 0x00, // mask2 (Second parameters bitmask)
|
||||
0x00, 0x00, // Reserved
|
||||
0x03, // minSVs (Minimum number of satellites for navigation) = 3
|
||||
0x10, // maxSVs (Maximum number of satellites for navigation) = 16
|
||||
0x06, // minCNO (Minimum satellite signal level for navigation) = 6 dBHz
|
||||
0x00, // Reserved
|
||||
0x00, // iniFix3D (Initial fix must be 3D) = 0 (disabled)
|
||||
0x00, 0x00, // Reserved
|
||||
0x00, // ackAiding (Issue acknowledgements for assistance message input) = 0 (disabled)
|
||||
0x00, 0x00, // Reserved
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Reserved
|
||||
0x00, // Reserved
|
||||
0x01, // aopCfg (AssistNow Autonomous configuration) = 1 (enabled)
|
||||
0x00, 0x00, // Reserved
|
||||
0x00, 0x00, // Reserved
|
||||
0x00, 0x00, 0x00, 0x00, // Reserved
|
||||
0x00, 0x00, 0x00, // Reserved
|
||||
0x01, // useAdr (Enable/disable ADR sensor fusion) = 1 (enabled)
|
||||
0x00, 0x00 // Checksum (calculated below)
|
||||
};
|
||||
|
||||
// Calculate the checksum and update the message.
|
||||
UBXChecksum(_message_NAVX5, sizeof(_message_NAVX5));
|
||||
|
||||
// Send the message to the module
|
||||
_serial_gps->write(_message_NAVX5, sizeof(_message_NAVX5));
|
||||
|
||||
if (!getACK(0x06, 0x23)) {
|
||||
LOG_WARN("Unable to configure extra settings.\n");
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
tips: NMEA Only should not be set here, otherwise initializing Ublox gnss module again after
|
||||
setting will not output command messages in UART1, resulting in unrecognized module information
|
||||
@@ -208,57 +363,205 @@ bool GPS::setupGPS()
|
||||
|
||||
// ublox-M10S can be compatible with UBLOX traditional protocol, so the following sentence settings are also valid
|
||||
|
||||
// disable GGL
|
||||
byte _message_GGL[] = {0xB5, 0x62, 0x06, 0x01, 0x08, 0x00, 0xF0, 0x01,
|
||||
0x01, 0x00, 0x01, 0x01, 0x01, 0x01, 0x05, 0x3A};
|
||||
// Set GPS update rate to 1Hz
|
||||
// Lowering the update rate helps to save power.
|
||||
// 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.
|
||||
byte _message_1Hz[] = {
|
||||
0xB5, 0x62, // UBX protocol sync characters
|
||||
0x06, 0x08, // Message class and ID (UBX-CFG-RATE)
|
||||
0x06, 0x00, // Length of payload (6 bytes)
|
||||
0xE8, 0x03, // Measurement Rate (1000ms for 1Hz)
|
||||
0x01, 0x00, // Navigation rate, always 1 in GPS mode
|
||||
0x01, 0x00, // Time reference
|
||||
0x00, 0x00 // Placeholder for checksum, will be calculated next
|
||||
};
|
||||
|
||||
// Calculate the checksum and update the message.
|
||||
UBXChecksum(_message_1Hz, sizeof(_message_1Hz));
|
||||
|
||||
// Send the message to the module
|
||||
_serial_gps->write(_message_1Hz, sizeof(_message_1Hz));
|
||||
|
||||
if (!getACK(0x06, 0x08)) {
|
||||
LOG_WARN("Unable to set GPS update rate.\n");
|
||||
return true;
|
||||
}
|
||||
|
||||
// Disable GGL. GGL - Geographic position (latitude and longitude), which provides the current geographical
|
||||
// coordinates.
|
||||
byte _message_GGL[] = {
|
||||
0xB5, 0x62, // UBX sync characters
|
||||
0x06, 0x01, // Message class and ID (UBX-CFG-MSG)
|
||||
0x08, 0x00, // Length of payload (8 bytes)
|
||||
0xF0, 0x01, // NMEA ID for GLL
|
||||
0x01, // I/O Target 0=I/O, 1=UART1, 2=UART2, 3=USB, 4=SPI
|
||||
0x00, // Disable
|
||||
0x01, 0x01, 0x01, 0x01, // Reserved
|
||||
0x00, 0x00 // CK_A and CK_B (Checksum)
|
||||
};
|
||||
|
||||
// Calculate the checksum and update the message.
|
||||
UBXChecksum(_message_GGL, sizeof(_message_GGL));
|
||||
|
||||
// Send the message to the module
|
||||
_serial_gps->write(_message_GGL, sizeof(_message_GGL));
|
||||
|
||||
if (!getACK(0x06, 0x01)) {
|
||||
LOG_WARN("Unable to disable NMEA GGL.\n");
|
||||
return true;
|
||||
}
|
||||
|
||||
// disable GSA
|
||||
byte _message_GSA[] = {0xB5, 0x62, 0x06, 0x01, 0x08, 0x00, 0xF0, 0x02,
|
||||
0x01, 0x00, 0x01, 0x01, 0x01, 0x01, 0x06, 0x41};
|
||||
// Enable GSA. GSA - GPS DOP and active satellites, used for detailing the satellites used in the positioning and
|
||||
// the DOP (Dilution of Precision)
|
||||
byte _message_GSA[] = {
|
||||
0xB5, 0x62, // UBX sync characters
|
||||
0x06, 0x01, // Message class and ID (UBX-CFG-MSG)
|
||||
0x08, 0x00, // Length of payload (8 bytes)
|
||||
0xF0, 0x02, // NMEA ID for GSA
|
||||
0x01, // I/O Target 0=I/O, 1=UART1, 2=UART2, 3=USB, 4=SPI
|
||||
0x01, // Enable
|
||||
0x01, 0x01, 0x01, 0x01, // Reserved
|
||||
0x00, 0x00 // CK_A and CK_B (Checksum)
|
||||
};
|
||||
UBXChecksum(_message_GSA, sizeof(_message_GSA));
|
||||
_serial_gps->write(_message_GSA, sizeof(_message_GSA));
|
||||
if (!getACK(0x06, 0x01)) {
|
||||
LOG_WARN("Unable to disable NMEA GSA.\n");
|
||||
LOG_WARN("Unable to Enable NMEA GSA.\n");
|
||||
return true;
|
||||
}
|
||||
|
||||
// disable GSV
|
||||
byte _message_GSV[] = {0xB5, 0x62, 0x06, 0x01, 0x08, 0x00, 0xF0, 0x03,
|
||||
0x01, 0x00, 0x01, 0x01, 0x01, 0x01, 0x07, 0x48};
|
||||
// Disable GSV. GSV - Satellites in view, details the number and location of satellites in view.
|
||||
byte _message_GSV[] = {
|
||||
0xB5, 0x62, // UBX sync characters
|
||||
0x06, 0x01, // Message class and ID (UBX-CFG-MSG)
|
||||
0x08, 0x00, // Length of payload (8 bytes)
|
||||
0xF0, 0x03, // NMEA ID for GSV
|
||||
0x01, // I/O Target 0=I/O, 1=UART1, 2=UART2, 3=USB, 4=SPI
|
||||
0x00, // Disable
|
||||
0x01, 0x01, 0x01, 0x01, // Reserved
|
||||
0x00, 0x00 // CK_A and CK_B (Checksum)
|
||||
};
|
||||
UBXChecksum(_message_GSV, sizeof(_message_GSV));
|
||||
_serial_gps->write(_message_GSV, sizeof(_message_GSV));
|
||||
if (!getACK(0x06, 0x01)) {
|
||||
LOG_WARN("Unable to disable NMEA GSV.\n");
|
||||
return true;
|
||||
}
|
||||
|
||||
// disable VTG
|
||||
byte _message_VTG[] = {0xB5, 0x62, 0x06, 0x01, 0x08, 0x00, 0xF0, 0x05,
|
||||
0x01, 0x00, 0x01, 0x01, 0x01, 0x01, 0x09, 0x56};
|
||||
// Disable VTG. VTG - Track made good and ground speed, which provides course and speed information relative to
|
||||
// the ground.
|
||||
byte _message_VTG[] = {
|
||||
0xB5, 0x62, // UBX sync characters
|
||||
0x06, 0x01, // Message class and ID (UBX-CFG-MSG)
|
||||
0x08, 0x00, // Length of payload (8 bytes)
|
||||
0xF0, 0x05, // NMEA ID for VTG
|
||||
0x01, // I/O Target 0=I/O, 1=UART1, 2=UART2, 3=USB, 4=SPI
|
||||
0x00, // Disable
|
||||
0x01, 0x01, 0x01, 0x01, // Reserved
|
||||
0x00, 0x00 // CK_A and CK_B (Checksum)
|
||||
};
|
||||
UBXChecksum(_message_VTG, sizeof(_message_VTG));
|
||||
_serial_gps->write(_message_VTG, sizeof(_message_VTG));
|
||||
if (!getACK(0x06, 0x01)) {
|
||||
LOG_WARN("Unable to disable NMEA VTG.\n");
|
||||
return true;
|
||||
}
|
||||
|
||||
// enable RMC
|
||||
byte _message_RMC[] = {0xB5, 0x62, 0x06, 0x01, 0x08, 0x00, 0xF0, 0x04,
|
||||
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x09, 0x54};
|
||||
// Enable RMC. RMC - Recommended Minimum data, the essential gps pvt (position, velocity, time) data.
|
||||
byte _message_RMC[] = {
|
||||
0xB5, 0x62, // UBX sync characters
|
||||
0x06, 0x01, // Message class and ID (UBX-CFG-MSG)
|
||||
0x08, 0x00, // Length of payload (8 bytes)
|
||||
0xF0, 0x04, // NMEA ID for RMC
|
||||
0x01, // I/O Target 0=I/O, 1=UART1, 2=UART2, 3=USB, 4=SPI
|
||||
0x01, // Enable
|
||||
0x01, 0x01, 0x01, 0x01, // Reserved
|
||||
0x00, 0x00 // CK_A and CK_B (Checksum)
|
||||
};
|
||||
UBXChecksum(_message_RMC, sizeof(_message_RMC));
|
||||
_serial_gps->write(_message_RMC, sizeof(_message_RMC));
|
||||
if (!getACK(0x06, 0x01)) {
|
||||
LOG_WARN("Unable to enable NMEA RMC.\n");
|
||||
return true;
|
||||
}
|
||||
|
||||
// enable GGA
|
||||
byte _message_GGA[] = {0xB5, 0x62, 0x06, 0x01, 0x08, 0x00, 0xF0, 0x00,
|
||||
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x05, 0x38};
|
||||
// Enable GGA. GGA - Global Positioning System Fix Data, which provides 3D location and accuracy data.
|
||||
byte _message_GGA[] = {
|
||||
0xB5, 0x62, // UBX sync characters
|
||||
0x06, 0x01, // Message class and ID (UBX-CFG-MSG)
|
||||
0x08, 0x00, // Length of payload (8 bytes)
|
||||
0xF0, 0x00, // NMEA ID for GGA
|
||||
0x01, // I/O Target 0=I/O, 1=UART1, 2=UART2, 3=USB, 4=SPI
|
||||
0x01, // Enable
|
||||
0x01, 0x01, 0x01, 0x01, // Reserved
|
||||
0x00, 0x00 // CK_A and CK_B (Checksum)
|
||||
};
|
||||
UBXChecksum(_message_GGA, sizeof(_message_GGA));
|
||||
_serial_gps->write(_message_GGA, sizeof(_message_GGA));
|
||||
if (!getACK(0x06, 0x01)) {
|
||||
LOG_WARN("Unable to enable NMEA GGA.\n");
|
||||
return true;
|
||||
}
|
||||
|
||||
// The Power Management configuration allows the GPS module to operate in different power modes for optimized power
|
||||
// consumption.
|
||||
// The modes supported are:
|
||||
// 0x00 = Full power: The module operates at full power with no power saving.
|
||||
// 0x01 = Balanced: The module dynamically adjusts the tracking behavior to balance power consumption.
|
||||
// 0x02 = Interval: The module operates in a periodic mode, cycling between tracking and power saving states.
|
||||
// 0x03 = Aggressive with 1 Hz: The module operates in a power saving mode with a 1 Hz update rate.
|
||||
// 0x04 = Aggressive with 2 Hz: The module operates in a power saving mode with a 2 Hz update rate.
|
||||
// 0x05 = Aggressive with 4 Hz: The module operates in a power saving mode with a 4 Hz update rate.
|
||||
// The 'period' field specifies the position update and search period. It is only valid when the powerSetupValue is
|
||||
// set to Interval; otherwise, it must be set to '0'. The 'onTime' field specifies the duration of the ON phase 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'.
|
||||
byte UBX_CFG_PMS[14] = {
|
||||
0xB5, 0x62, // UBX sync characters
|
||||
0x06, 0x86, // Message class and ID (UBX-CFG-PMS)
|
||||
0x06, 0x00, // Length of payload (6 bytes)
|
||||
0x00, // Version (0)
|
||||
0x03, // Power setup value
|
||||
0x00, 0x00, // period: not applicable, set to 0
|
||||
0x00, 0x00, // onTime: not applicable, set to 0
|
||||
0x00, 0x00 // Placeholder for checksum, will be calculated next
|
||||
};
|
||||
|
||||
// Calculate the checksum and update the message
|
||||
UBXChecksum(UBX_CFG_PMS, sizeof(UBX_CFG_PMS));
|
||||
|
||||
// Send the message to the module
|
||||
_serial_gps->write(UBX_CFG_PMS, sizeof(UBX_CFG_PMS));
|
||||
if (!getACK(0x06, 0x86)) {
|
||||
LOG_WARN("Unable to enable powersaving for GPS.\n");
|
||||
return true;
|
||||
}
|
||||
|
||||
// We need save configuration to flash to make our config changes persistent
|
||||
byte _message_SAVE[21] = {
|
||||
0xB5, 0x62, // UBX protocol header
|
||||
0x06, 0x09, // UBX class ID (Configuration Input Messages), message ID (UBX-CFG-CFG)
|
||||
0x0D, 0x00, // Length of payload (13 bytes)
|
||||
0x00, 0x00, 0x00, 0x00, // clearMask: no sections cleared
|
||||
0xFF, 0xFF, 0x00, 0x00, // saveMask: save all sections
|
||||
0x00, 0x00, 0x00, 0x00, // loadMask: no sections loaded
|
||||
0x0F, // deviceMask: BBR, Flash, EEPROM, and SPI Flash
|
||||
0x00, 0x00 // Checksum (calculated below)
|
||||
};
|
||||
|
||||
// Calculate the checksum and update the message.
|
||||
UBXChecksum(_message_SAVE, sizeof(_message_SAVE));
|
||||
|
||||
// Send the message to the module
|
||||
_serial_gps->write(_message_SAVE, sizeof(_message_SAVE));
|
||||
|
||||
if (!getACK(0x06, 0x09)) {
|
||||
LOG_WARN("Unable to save GNSS module configuration.\n");
|
||||
return true;
|
||||
} else {
|
||||
LOG_INFO("GNSS module configuration saved!\n");
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -269,22 +572,21 @@ bool GPS::setupGPS()
|
||||
bool GPS::setup()
|
||||
{
|
||||
// Master power for the GPS
|
||||
|
||||
#if defined(HAS_PMU) || defined(PIN_GPS_EN)
|
||||
if (config.position.gps_enabled) {
|
||||
#ifdef PIN_GPS_EN
|
||||
digitalWrite(PIN_GPS_EN, 1);
|
||||
pinMode(PIN_GPS_EN, OUTPUT);
|
||||
#endif
|
||||
|
||||
#ifdef HAS_PMU
|
||||
if (config.position.gps_enabled) {
|
||||
setGPSPower(true);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef PIN_GPS_RESET
|
||||
digitalWrite(PIN_GPS_RESET, 1); // assert for 10ms
|
||||
digitalWrite(PIN_GPS_RESET, GPS_RESET_MODE); // assert for 10ms
|
||||
pinMode(PIN_GPS_RESET, OUTPUT);
|
||||
delay(10);
|
||||
digitalWrite(PIN_GPS_RESET, 0);
|
||||
digitalWrite(PIN_GPS_RESET, !GPS_RESET_MODE);
|
||||
#endif
|
||||
setAwake(true); // Wake GPS power before doing any init
|
||||
bool ok = setupGPS();
|
||||
@@ -384,7 +686,7 @@ void GPS::setAwake(bool on)
|
||||
}
|
||||
}
|
||||
|
||||
/** Get how long we should stay looking for each aquisition in msecs
|
||||
/** Get how long we should stay looking for each acquisition in msecs
|
||||
*/
|
||||
uint32_t GPS::getWakeTime() const
|
||||
{
|
||||
@@ -555,21 +857,17 @@ int GPS::prepareDeepSleep(void *unused)
|
||||
|
||||
GnssModel_t GPS::probe()
|
||||
{
|
||||
// return immediately if the model is set by the variant.h file
|
||||
#ifdef GPS_UBLOX
|
||||
return GNSS_MODEL_UBLOX;
|
||||
#elif defined(GPS_L76K)
|
||||
return GNSS_MODEL_MTK;
|
||||
#else
|
||||
// we use autodetect, only T-BEAM S3 for now...
|
||||
uint8_t buffer[256];
|
||||
/*
|
||||
* The GNSS module information variable is temporarily placed inside the function body,
|
||||
* if it needs to be used elsewhere, it can be moved to the outside
|
||||
* */
|
||||
struct uBloxGnssModelInfo info;
|
||||
|
||||
memset(&info, 0, sizeof(struct uBloxGnssModelInfo));
|
||||
// return immediately if the model is set by the variant.h file
|
||||
//#ifdef GPS_UBLOX (unless it's a ublox, because we might want to know the module info!
|
||||
// return GNSS_MODEL_UBLOX; think about removing this macro and return)
|
||||
#if defined(GPS_L76K)
|
||||
return GNSS_MODEL_MTK;
|
||||
#elif defined(GPS_UC6580)
|
||||
_serial_gps->updateBaudRate(115200);
|
||||
return GNSS_MODEL_UC6850;
|
||||
#else
|
||||
uint8_t buffer[384] = {0};
|
||||
|
||||
// Close all NMEA sentences , Only valid for MTK platform
|
||||
_serial_gps->write("$PCAS03,0,0,0,0,0,0,0,0,0,0,,,0,0*02\r\n");
|
||||
@@ -597,31 +895,37 @@ GnssModel_t GPS::probe()
|
||||
uint8_t cfg_rate[] = {0xB5, 0x62, 0x06, 0x08, 0x00, 0x00, 0x0E, 0x30};
|
||||
_serial_gps->write(cfg_rate, sizeof(cfg_rate));
|
||||
// Check that the returned response class and message ID are correct
|
||||
if (!getAck(buffer, 256, 0x06, 0x08)) {
|
||||
if (!getAck(buffer, 384, 0x06, 0x08)) {
|
||||
LOG_WARN("Failed to find UBlox & MTK GNSS Module\n");
|
||||
return GNSS_MODEL_UNKONW;
|
||||
return GNSS_MODEL_UNKNOWN;
|
||||
}
|
||||
|
||||
memset(buffer, 0, sizeof(buffer));
|
||||
byte _message_MONVER[8] = {
|
||||
0xB5, 0x62, // Sync message for UBX protocol
|
||||
0x0A, 0x04, // Message class and ID (UBX-MON-VER)
|
||||
0x00, 0x00, // Length of payload (we're asking for an answer, so no payload)
|
||||
0x00, 0x00 // Checksum
|
||||
};
|
||||
// Get Ublox gnss module hardware and software info
|
||||
uint8_t cfg_get_hw[] = {0xB5, 0x62, 0x0A, 0x04, 0x00, 0x00, 0x0E, 0x34};
|
||||
_serial_gps->write(cfg_get_hw, sizeof(cfg_get_hw));
|
||||
UBXChecksum(_message_MONVER, sizeof(_message_MONVER));
|
||||
_serial_gps->write(_message_MONVER, sizeof(_message_MONVER));
|
||||
|
||||
uint16_t len = getAck(buffer, 256, 0x0A, 0x04);
|
||||
uint16_t len = getAck(buffer, 384, 0x0A, 0x04);
|
||||
if (len) {
|
||||
|
||||
// LOG_DEBUG("monver reply size = %d\n", len);
|
||||
uint16_t position = 0;
|
||||
for (int i = 0; i < 30; i++) {
|
||||
info.swVersion[i] = buffer[position];
|
||||
position++;
|
||||
}
|
||||
for (int i = 0; i < 10; i++) {
|
||||
info.hwVersion[i] = buffer[position];
|
||||
info.hwVersion[i] = buffer[position - 1];
|
||||
position++;
|
||||
}
|
||||
|
||||
while (len >= position + 30) {
|
||||
for (int i = 0; i < 30; i++) {
|
||||
info.extension[info.extensionNo][i] = buffer[position];
|
||||
info.extension[info.extensionNo][i] = buffer[position - 1];
|
||||
position++;
|
||||
}
|
||||
info.extensionNo++;
|
||||
@@ -631,6 +935,7 @@ GnssModel_t GPS::probe()
|
||||
|
||||
LOG_DEBUG("Module Info : \n");
|
||||
LOG_DEBUG("Soft version: %s\n", info.swVersion);
|
||||
LOG_DEBUG("first char is %c\n", (char)info.swVersion[0]);
|
||||
LOG_DEBUG("Hard version: %s\n", info.hwVersion);
|
||||
LOG_DEBUG("Extensions:%d\n", info.extensionNo);
|
||||
for (int i = 0; i < info.extensionNo; i++) {
|
||||
@@ -641,18 +946,28 @@ GnssModel_t GPS::probe()
|
||||
|
||||
// tips: extensionNo field is 0 on some 6M GNSS modules
|
||||
for (int i = 0; i < info.extensionNo; ++i) {
|
||||
if (!strncmp(info.extension[i], "OD=", 3)) {
|
||||
strncpy((char *)buffer, &(info.extension[i][3]), sizeof(buffer));
|
||||
LOG_DEBUG("GetModel:%s\n", (char *)buffer);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!strncmp(info.extension[i], "MOD=", 4)) {
|
||||
strncpy((char *)buffer, &(info.extension[i][4]), sizeof(buffer));
|
||||
// LOG_DEBUG("GetModel:%s\n", (char *)buffer);
|
||||
if (strlen((char *)buffer)) {
|
||||
LOG_INFO("UBlox GNSS init succeeded, using UBlox %s GNSS Module\n", buffer);
|
||||
LOG_INFO("UBlox GNSS init succeeded, using UBlox %s GNSS Module\n", (char *)buffer);
|
||||
} else {
|
||||
LOG_INFO("UBlox GNSS init succeeded, using UBlox GNSS Module\n");
|
||||
}
|
||||
} else if (!strncmp(info.extension[i], "PROTVER=", 8)) {
|
||||
char *ptr = nullptr;
|
||||
memset(buffer, 0, sizeof(buffer));
|
||||
strncpy((char *)buffer, &(info.extension[i][8]), sizeof(buffer));
|
||||
LOG_DEBUG("Protocol Version:%s\n", (char *)buffer);
|
||||
if (strlen((char *)buffer)) {
|
||||
uBloxProtocolVersion = strtoul((char *)buffer, &ptr, 10);
|
||||
LOG_DEBUG("ProtVer=%d\n", uBloxProtocolVersion);
|
||||
} else {
|
||||
uBloxProtocolVersion = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return GNSS_MODEL_UBLOX;
|
||||
#endif
|
||||
@@ -675,8 +990,8 @@ GPS *createGps()
|
||||
LOG_DEBUG("Using MSL altitude model\n");
|
||||
#endif
|
||||
if (GPS::_serial_gps) {
|
||||
// Some boards might have only the TX line from the GPS connected, in that case, we can't configure it at all. Just
|
||||
// assume NMEA at 9600 baud.
|
||||
// Some boards might have only the TX line from the GPS connected, in that case, we can't configure it at all.
|
||||
// Just assume NMEA at 9600 baud.
|
||||
GPS *new_gps = new NMEAGPS();
|
||||
new_gps->setup();
|
||||
return new_gps;
|
||||
|
||||
@@ -14,7 +14,8 @@ struct uBloxGnssModelInfo {
|
||||
typedef enum {
|
||||
GNSS_MODEL_MTK,
|
||||
GNSS_MODEL_UBLOX,
|
||||
GNSS_MODEL_UNKONW,
|
||||
GNSS_MODEL_UC6850,
|
||||
GNSS_MODEL_UNKNOWN,
|
||||
} GnssModel_t;
|
||||
|
||||
// Generate a string representation of DOP
|
||||
@@ -139,6 +140,9 @@ class GPS : private concurrency::OSThread
|
||||
/// always returns 0 to indicate okay to sleep
|
||||
int prepareDeepSleep(void *unused);
|
||||
|
||||
// Calculate checksum
|
||||
void UBXChecksum(byte *message, size_t length);
|
||||
|
||||
/**
|
||||
* Switch the GPS into a mode where we are actively looking for a lock, or alternatively switch GPS into a low power mode
|
||||
*
|
||||
@@ -164,6 +168,7 @@ class GPS : private concurrency::OSThread
|
||||
virtual int32_t runOnce() override;
|
||||
|
||||
// Get GNSS model
|
||||
String getNMEA();
|
||||
GnssModel_t probe();
|
||||
|
||||
int getAck(uint8_t *buffer, uint16_t size, uint8_t requestedClass, uint8_t requestedID);
|
||||
@@ -172,7 +177,7 @@ class GPS : private concurrency::OSThread
|
||||
uint8_t fixeddelayCtr = 0;
|
||||
|
||||
protected:
|
||||
GnssModel_t gnssModel = GNSS_MODEL_UNKONW;
|
||||
GnssModel_t gnssModel = GNSS_MODEL_UNKNOWN;
|
||||
};
|
||||
|
||||
// Creates an instance of the GPS class.
|
||||
|
||||
@@ -12,7 +12,7 @@ GeoCoord::GeoCoord(int32_t lat, int32_t lon, int32_t alt) : _latitude(lat), _lon
|
||||
|
||||
GeoCoord::GeoCoord(float lat, float lon, int32_t alt) : _altitude(alt)
|
||||
{
|
||||
// Change decimial reprsentation to int32_t. I.e., 12.345 becomes 123450000
|
||||
// Change decimial representation to int32_t. I.e., 12.345 becomes 123450000
|
||||
_latitude = int32_t(lat * 1e+7);
|
||||
_longitude = int32_t(lon * 1e+7);
|
||||
GeoCoord::setCoords();
|
||||
@@ -20,7 +20,7 @@ GeoCoord::GeoCoord(float lat, float lon, int32_t alt) : _altitude(alt)
|
||||
|
||||
GeoCoord::GeoCoord(double lat, double lon, int32_t alt) : _altitude(alt)
|
||||
{
|
||||
// Change decimial reprsentation to int32_t. I.e., 12.345 becomes 123450000
|
||||
// Change decimial representation to int32_t. I.e., 12.345 becomes 123450000
|
||||
_latitude = int32_t(lat * 1e+7);
|
||||
_longitude = int32_t(lon * 1e+7);
|
||||
GeoCoord::setCoords();
|
||||
@@ -41,7 +41,7 @@ void GeoCoord::setCoords()
|
||||
|
||||
void GeoCoord::updateCoords(int32_t lat, int32_t lon, int32_t alt)
|
||||
{
|
||||
// If marked dirty or new coordiantes
|
||||
// If marked dirty or new coordinates
|
||||
if (_dirty || _latitude != lat || _longitude != lon || _altitude != alt) {
|
||||
_dirty = true;
|
||||
_latitude = lat;
|
||||
@@ -55,7 +55,7 @@ void GeoCoord::updateCoords(const double lat, const double lon, const int32_t al
|
||||
{
|
||||
int32_t iLat = lat * 1e+7;
|
||||
int32_t iLon = lon * 1e+7;
|
||||
// If marked dirty or new coordiantes
|
||||
// If marked dirty or new coordinates
|
||||
if (_dirty || _latitude != iLat || _longitude != iLon || _altitude != alt) {
|
||||
_dirty = true;
|
||||
_latitude = iLat;
|
||||
@@ -69,7 +69,7 @@ void GeoCoord::updateCoords(const float lat, const float lon, const int32_t alt)
|
||||
{
|
||||
int32_t iLat = lat * 1e+7;
|
||||
int32_t iLon = lon * 1e+7;
|
||||
// If marked dirty or new coordiantes
|
||||
// If marked dirty or new coordinates
|
||||
if (_dirty || _latitude != iLat || _longitude != iLon || _altitude != alt) {
|
||||
_dirty = true;
|
||||
_latitude = iLat;
|
||||
@@ -217,7 +217,7 @@ void GeoCoord::latLongToOSGR(const double lat, const double lon, OSGR &osgr)
|
||||
double eta2 = v / rho - 1;
|
||||
double mA = (1 + n + (5 / 4) * n * n + (5 / 4) * n * n * n) * (phi - phi0);
|
||||
double mB = (3 * n + 3 * n * n + (21 / 8) * n * n * n) * sin(phi - phi0) * cos(phi + phi0);
|
||||
// loss of precision in mC & mD due to floating point rounding can cause innaccuracy of northing by a few meters
|
||||
// loss of precision in mC & mD due to floating point rounding can cause inaccuracy of northing by a few meters
|
||||
double mC = (15 / 8 * n * n + 15 / 8 * n * n * n) * sin(2 * (phi - phi0)) * cos(2 * (phi + phi0));
|
||||
double mD = (35 / 24) * n * n * n * sin(3 * (phi - phi0)) * cos(3 * (phi + phi0));
|
||||
double m = b * f0 * (mA - mB + mC - mD);
|
||||
|
||||
@@ -65,7 +65,7 @@ struct MGRS {
|
||||
uint32_t northing;
|
||||
};
|
||||
|
||||
// A struct to hold the data for a OSGR coordiante
|
||||
// A struct to hold the data for a OSGR coordinate
|
||||
struct OSGR {
|
||||
char e100k;
|
||||
char n100k;
|
||||
|
||||
@@ -19,7 +19,7 @@ static uint64_t zeroOffsetSecs; // GPS based time in secs since 1970 - only upda
|
||||
|
||||
void readFromRTC()
|
||||
{
|
||||
struct timeval tv; /* btw settimeofday() is helpfull here too*/
|
||||
struct timeval tv; /* btw settimeofday() is helpful here too*/
|
||||
#ifdef RV3028_RTC
|
||||
if (rtc_found.address == RV3028_RTC) {
|
||||
uint32_t now = millis();
|
||||
|
||||
@@ -7,6 +7,10 @@
|
||||
#include "main.h"
|
||||
#include <SPI.h>
|
||||
|
||||
// #ifdef HELTEC_WIRELESS_PAPER
|
||||
// SPIClass *hspi = NULL;
|
||||
// #endif
|
||||
|
||||
#define COLORED GxEPD_BLACK
|
||||
#define UNCOLORED GxEPD_WHITE
|
||||
|
||||
@@ -41,6 +45,9 @@
|
||||
// 1.54 inch 200x200 - GxEPD2_154_M09
|
||||
#define TECHO_DISPLAY_MODEL GxEPD2_154_M09
|
||||
|
||||
#elif defined(HELTEC_WIRELESS_PAPER)
|
||||
//#define TECHO_DISPLAY_MODEL GxEPD2_213_T5D
|
||||
#define TECHO_DISPLAY_MODEL GxEPD2_213_BN
|
||||
#endif
|
||||
|
||||
GxEPD2_BW<TECHO_DISPLAY_MODEL, TECHO_DISPLAY_MODEL::HEIGHT> *adafruitDisplay;
|
||||
@@ -62,6 +69,10 @@ EInkDisplay::EInkDisplay(uint8_t address, int sda, int scl, OLEDDISPLAY_GEOMETRY
|
||||
|
||||
// GxEPD2_154_M09
|
||||
// setGeometry(GEOMETRY_RAWMODE, 200, 200);
|
||||
|
||||
#elif defined(HELTEC_WIRELESS_PAPER)
|
||||
// setGeometry(GEOMETRY_RAWMODE, 212, 104);
|
||||
setGeometry(GEOMETRY_RAWMODE, 250, 122);
|
||||
#elif defined(MAKERPYTHON)
|
||||
// GxEPD2_290_T5D
|
||||
setGeometry(GEOMETRY_RAWMODE, 296, 128);
|
||||
@@ -109,7 +120,7 @@ bool EInkDisplay::forceDisplay(uint32_t msecLimit)
|
||||
for (uint32_t y = 0; y < displayHeight; y++) {
|
||||
for (uint32_t x = 0; x < displayWidth; x++) {
|
||||
|
||||
// get src pixel in the page based ordering the OLED lib uses FIXME, super inefficent
|
||||
// get src pixel in the page based ordering the OLED lib uses FIXME, super inefficient
|
||||
auto b = buffer[x + (y / 8) * displayWidth];
|
||||
auto isset = b & (1 << (y & 7));
|
||||
adafruitDisplay->drawPixel(x, y, isset ? COLORED : UNCOLORED);
|
||||
@@ -218,6 +229,16 @@ bool EInkDisplay::connect()
|
||||
(void)adafruitDisplay;
|
||||
}
|
||||
}
|
||||
#elif defined(HELTEC_WIRELESS_PAPER)
|
||||
{
|
||||
auto lowLevel = new TECHO_DISPLAY_MODEL(PIN_EINK_CS, PIN_EINK_DC, PIN_EINK_RES, PIN_EINK_BUSY);
|
||||
adafruitDisplay = new GxEPD2_BW<TECHO_DISPLAY_MODEL, TECHO_DISPLAY_MODEL::HEIGHT>(*lowLevel);
|
||||
// hspi = new SPIClass(HSPI);
|
||||
// hspi->begin(PIN_EINK_SCLK, -1, PIN_EINK_MOSI, PIN_EINK_CS); // SCLK, MISO, MOSI, SS
|
||||
adafruitDisplay->init(115200, true, 10, false, SPI, SPISettings(6000000, MSBFIRST, SPI_MODE0));
|
||||
adafruitDisplay->setRotation(3);
|
||||
adafruitDisplay->setPartialWindow(0, 0, displayWidth, displayHeight);
|
||||
}
|
||||
#elif defined(PCA10059)
|
||||
{
|
||||
auto lowLevel = new TECHO_DISPLAY_MODEL(PIN_EINK_CS, PIN_EINK_DC, PIN_EINK_RES, PIN_EINK_BUSY);
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#include "main.h"
|
||||
|
||||
#ifdef RAK4630
|
||||
#ifdef HAS_NCP5623
|
||||
#include <NCP5623.h>
|
||||
extern NCP5623 rgb;
|
||||
|
||||
|
||||
@@ -31,6 +31,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#include "gps/GeoCoord.h"
|
||||
#include "gps/RTC.h"
|
||||
#include "graphics/images.h"
|
||||
#include "input/TouchScreenImpl1.h"
|
||||
#include "main.h"
|
||||
#include "mesh-pb-constants.h"
|
||||
#include "mesh/Channels.h"
|
||||
@@ -102,7 +103,7 @@ static uint16_t displayWidth, displayHeight;
|
||||
#define SCREEN_WIDTH displayWidth
|
||||
#define SCREEN_HEIGHT displayHeight
|
||||
|
||||
#if defined(USE_EINK) || defined(ILI9341_DRIVER) || defined(ST7735_CS)
|
||||
#if defined(USE_EINK) || defined(ILI9341_DRIVER) || defined(ST7735_CS) || defined(ST7789_CS)
|
||||
// The screen is bigger so use bigger fonts
|
||||
#define FONT_SMALL ArialMT_Plain_16 // Height: 19
|
||||
#define FONT_MEDIUM ArialMT_Plain_24 // Height: 28
|
||||
@@ -296,7 +297,7 @@ static void drawModuleFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int
|
||||
static void drawFrameBluetooth(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y)
|
||||
{
|
||||
int x_offset = display->width() / 2;
|
||||
int y_offset = display->height() == 64 ? 0 : 32;
|
||||
int y_offset = display->height() <= 80 ? 0 : 32;
|
||||
display->setTextAlignment(TEXT_ALIGN_CENTER);
|
||||
display->setFont(FONT_MEDIUM);
|
||||
display->drawString(x_offset + x, y_offset + y, "Bluetooth");
|
||||
@@ -320,18 +321,18 @@ static void drawFrameBluetooth(OLEDDisplay *display, OLEDDisplayUiState *state,
|
||||
|
||||
static void drawFrameShutdown(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y)
|
||||
{
|
||||
uint16_t x_offset = display->width() / 2;
|
||||
display->setTextAlignment(TEXT_ALIGN_CENTER);
|
||||
|
||||
display->setFont(FONT_MEDIUM);
|
||||
display->drawString(64 + x, 26 + y, "Shutting down...");
|
||||
display->drawString(x_offset + x, 26 + y, "Shutting down...");
|
||||
}
|
||||
|
||||
static void drawFrameReboot(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y)
|
||||
{
|
||||
uint16_t x_offset = display->width() / 2;
|
||||
display->setTextAlignment(TEXT_ALIGN_CENTER);
|
||||
|
||||
display->setFont(FONT_MEDIUM);
|
||||
display->drawString(64 + x, 26 + y, "Rebooting...");
|
||||
display->drawString(x_offset + x, 26 + y, "Rebooting...");
|
||||
}
|
||||
|
||||
static void drawFrameFirmware(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y)
|
||||
@@ -360,7 +361,7 @@ static void drawCriticalFaultFrame(OLEDDisplay *display, OLEDDisplayUiState *sta
|
||||
display->drawString(0 + x, FONT_HEIGHT_MEDIUM + y, "For help, please visit \nmeshtastic.org");
|
||||
}
|
||||
|
||||
// Ignore messages orginating from phone (from the current node 0x0) unless range test or store and forward module are enabled
|
||||
// Ignore messages originating from phone (from the current node 0x0) unless range test or store and forward module are enabled
|
||||
static bool shouldDrawMessage(const meshtastic_MeshPacket *packet)
|
||||
{
|
||||
return packet->from != 0 && !moduleConfig.range_test.enabled && !moduleConfig.store_forward.enabled;
|
||||
@@ -442,7 +443,7 @@ static void drawWaypointFrame(OLEDDisplay *display, OLEDDisplayUiState *state, i
|
||||
}
|
||||
}
|
||||
|
||||
/// Draw a series of fields in a column, wrapping to multiple colums if needed
|
||||
/// Draw a series of fields in a column, wrapping to multiple columns if needed
|
||||
static void drawColumns(OLEDDisplay *display, int16_t x, int16_t y, const char **fields)
|
||||
{
|
||||
// The coordinates define the left starting point of the text
|
||||
@@ -492,7 +493,7 @@ static void drawNodes(OLEDDisplay *display, int16_t x, int16_t y, NodeStatus *no
|
||||
{
|
||||
char usersString[20];
|
||||
snprintf(usersString, sizeof(usersString), "%d/%d", nodeStatus->getNumOnline(), nodeStatus->getNumTotal());
|
||||
#if defined(USE_EINK) || defined(ILI9341_DRIVER) || defined(ST7735_CS)
|
||||
#if defined(USE_EINK) || defined(ILI9341_DRIVER) || defined(ST7735_CS) || defined(ST7789_CS)
|
||||
display->drawFastImage(x, y + 3, 8, 8, imgUser);
|
||||
#else
|
||||
display->drawFastImage(x, y, 8, 8, imgUser);
|
||||
@@ -835,7 +836,11 @@ static void drawNodeInfo(OLEDDisplay *display, OLEDDisplayUiState *state, int16_
|
||||
}
|
||||
|
||||
static char distStr[20];
|
||||
strncpy(distStr, "? km", sizeof(distStr)); // might not have location data
|
||||
if (config.display.units == meshtastic_Config_DisplayConfig_DisplayUnits_IMPERIAL) {
|
||||
strncpy(distStr, "? mi", sizeof(distStr)); // might not have location data
|
||||
} else {
|
||||
strncpy(distStr, "? km", sizeof(distStr));
|
||||
}
|
||||
meshtastic_NodeInfoLite *ourNode = nodeDB.getMeshNode(nodeDB.getNodeNum());
|
||||
const char *fields[] = {username, distStr, signalStr, lastStr, NULL};
|
||||
int16_t compassX = 0, compassY = 0;
|
||||
@@ -944,6 +949,9 @@ void Screen::handleSetOn(bool on)
|
||||
if (on != screenOn) {
|
||||
if (on) {
|
||||
LOG_INFO("Turning on screen\n");
|
||||
#ifdef T_WATCH_S3
|
||||
PMU->enablePowerOutput(XPOWERS_ALDO2);
|
||||
#endif
|
||||
dispdev.displayOn();
|
||||
dispdev.displayOn();
|
||||
enabled = true;
|
||||
@@ -952,6 +960,9 @@ void Screen::handleSetOn(bool on)
|
||||
} else {
|
||||
LOG_INFO("Turning off screen\n");
|
||||
dispdev.displayOff();
|
||||
#ifdef T_WATCH_S3
|
||||
PMU->disablePowerOutput(XPOWERS_ALDO2);
|
||||
#endif
|
||||
enabled = false;
|
||||
}
|
||||
screenOn = on;
|
||||
@@ -1034,12 +1045,18 @@ void Screen::setup()
|
||||
#endif
|
||||
serialSinceMsec = millis();
|
||||
|
||||
#if HAS_TOUCHSCREEN
|
||||
touchScreenImpl1 = new TouchScreenImpl1(dispdev.getWidth(), dispdev.getHeight(), dispdev.getTouch);
|
||||
touchScreenImpl1->init();
|
||||
#endif
|
||||
|
||||
// Subscribe to status updates
|
||||
powerStatusObserver.observe(&powerStatus->onNewStatus);
|
||||
gpsStatusObserver.observe(&gpsStatus->onNewStatus);
|
||||
nodeStatusObserver.observe(&nodeStatus->onNewStatus);
|
||||
if (textMessageModule)
|
||||
textMessageObserver.observe(textMessageModule);
|
||||
inputObserver.observe(inputBroker);
|
||||
|
||||
// Modules can notify screen about refresh
|
||||
MeshModule::observeUIEvents(&uiFrameEventObserver);
|
||||
@@ -1117,6 +1134,12 @@ int32_t Screen::runOnce()
|
||||
handleOnPress();
|
||||
}
|
||||
break;
|
||||
case Cmd::SHOW_PREV_FRAME:
|
||||
handleShowPrevFrame();
|
||||
break;
|
||||
case Cmd::SHOW_NEXT_FRAME:
|
||||
handleShowNextFrame();
|
||||
break;
|
||||
case Cmd::START_BLUETOOTH_PIN_SCREEN:
|
||||
handleStartBluetoothPinScreen(cmd.bluetooth_pin);
|
||||
break;
|
||||
@@ -1410,6 +1433,28 @@ void Screen::handleOnPress()
|
||||
}
|
||||
}
|
||||
|
||||
void Screen::handleShowPrevFrame()
|
||||
{
|
||||
// If screen was off, just wake it, otherwise go back to previous frame
|
||||
// If we are in a transition, the press must have bounced, drop it.
|
||||
if (ui.getUiState()->frameState == FIXED) {
|
||||
ui.previousFrame();
|
||||
lastScreenTransition = millis();
|
||||
setFastFramerate();
|
||||
}
|
||||
}
|
||||
|
||||
void Screen::handleShowNextFrame()
|
||||
{
|
||||
// If screen was off, just wake it, otherwise advance to next frame
|
||||
// If we are in a transition, the press must have bounced, drop it.
|
||||
if (ui.getUiState()->frameState == FIXED) {
|
||||
ui.nextFrame();
|
||||
lastScreenTransition = millis();
|
||||
setFastFramerate();
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef SCREEN_TRANSITION_FRAMERATE
|
||||
#define SCREEN_TRANSITION_FRAMERATE 30 // fps
|
||||
#endif
|
||||
@@ -1482,7 +1527,7 @@ void DebugInfo::drawFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16
|
||||
#ifdef ARCH_ESP32
|
||||
if (millis() - storeForwardModule->lastHeartbeat >
|
||||
(storeForwardModule->heartbeatInterval * 1200)) { // no heartbeat, overlap a bit
|
||||
#if defined(USE_EINK) || defined(ILI9341_DRIVER) || defined(ST7735_CS)
|
||||
#if defined(USE_EINK) || defined(ILI9341_DRIVER) || defined(ST7735_CS) || defined(ST7789_CS)
|
||||
display->drawFastImage(x + SCREEN_WIDTH - 14 - display->getStringWidth(ourId), y + 3 + FONT_HEIGHT_SMALL, 12, 8,
|
||||
imgQuestionL1);
|
||||
display->drawFastImage(x + SCREEN_WIDTH - 14 - display->getStringWidth(ourId), y + 11 + FONT_HEIGHT_SMALL, 12, 8,
|
||||
@@ -1492,7 +1537,7 @@ void DebugInfo::drawFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16
|
||||
imgQuestion);
|
||||
#endif
|
||||
} else {
|
||||
#if defined(USE_EINK) || defined(ILI9341_DRIVER) || defined(ST7735_CS)
|
||||
#if defined(USE_EINK) || defined(ILI9341_DRIVER) || defined(ST7735_CS) || defined(ST7789_CS)
|
||||
display->drawFastImage(x + SCREEN_WIDTH - 18 - display->getStringWidth(ourId), y + 3 + FONT_HEIGHT_SMALL, 16, 8,
|
||||
imgSFL1);
|
||||
display->drawFastImage(x + SCREEN_WIDTH - 18 - display->getStringWidth(ourId), y + 11 + FONT_HEIGHT_SMALL, 16, 8,
|
||||
@@ -1504,7 +1549,7 @@ void DebugInfo::drawFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16
|
||||
}
|
||||
#endif
|
||||
} else {
|
||||
#if defined(USE_EINK) || defined(ILI9341_DRIVER) || defined(ST7735_CS)
|
||||
#if defined(USE_EINK) || defined(ILI9341_DRIVER) || defined(ST7735_CS) || defined(ST7789_CS)
|
||||
display->drawFastImage(x + SCREEN_WIDTH - 14 - display->getStringWidth(ourId), y + 3 + FONT_HEIGHT_SMALL, 12, 8,
|
||||
imgInfoL1);
|
||||
display->drawFastImage(x + SCREEN_WIDTH - 14 - display->getStringWidth(ourId), y + 11 + FONT_HEIGHT_SMALL, 12, 8,
|
||||
@@ -1789,7 +1834,7 @@ void DebugInfo::drawFrameSettings(OLEDDisplay *display, OLEDDisplayUiState *stat
|
||||
heartbeat = !heartbeat;
|
||||
#endif
|
||||
}
|
||||
// adjust Brightness cycle trough 1 to 254 as long as attachDuringLongPress is true
|
||||
// adjust Brightness cycle through 1 to 254 as long as attachDuringLongPress is true
|
||||
void Screen::adjustBrightness()
|
||||
{
|
||||
if (!useDisplay)
|
||||
@@ -1847,6 +1892,20 @@ int Screen::handleUIFrameEvent(const UIFrameEvent *event)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int Screen::handleInputEvent(const InputEvent *event)
|
||||
{
|
||||
if (showingNormalScreen && moduleFrames.size() == 0) {
|
||||
LOG_DEBUG("Screen::handleInputEvent from %s\n", event->source);
|
||||
if (event->inputEvent == static_cast<char>(meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_LEFT)) {
|
||||
showPrevFrame();
|
||||
} else if (event->inputEvent == static_cast<char>(meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_RIGHT)) {
|
||||
showNextFrame();
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
} // namespace graphics
|
||||
#else
|
||||
graphics::Screen::Screen(ScanI2C::DeviceAddress, meshtastic_Config_DisplayConfig_OledType, OLEDDISPLAY_GEOMETRY) {}
|
||||
|
||||
@@ -53,6 +53,7 @@ class Screen
|
||||
#include "commands.h"
|
||||
#include "concurrency/LockGuard.h"
|
||||
#include "concurrency/OSThread.h"
|
||||
#include "input/InputBroker.h"
|
||||
#include "mesh/MeshModule.h"
|
||||
#include "power.h"
|
||||
#include <string>
|
||||
@@ -118,6 +119,8 @@ class Screen : public concurrency::OSThread
|
||||
CallbackObserver<Screen, const meshtastic_MeshPacket *>(this, &Screen::handleTextMessage);
|
||||
CallbackObserver<Screen, const UIFrameEvent *> uiFrameEventObserver =
|
||||
CallbackObserver<Screen, const UIFrameEvent *>(this, &Screen::handleUIFrameEvent);
|
||||
CallbackObserver<Screen, const InputEvent *> inputObserver =
|
||||
CallbackObserver<Screen, const InputEvent *>(this, &Screen::handleInputEvent);
|
||||
|
||||
public:
|
||||
explicit Screen(ScanI2C::DeviceAddress, meshtastic_Config_DisplayConfig_OledType, OLEDDISPLAY_GEOMETRY);
|
||||
@@ -152,8 +155,10 @@ class Screen : public concurrency::OSThread
|
||||
|
||||
void blink();
|
||||
|
||||
/// Handles a button press.
|
||||
/// Handle button press, trackball or swipe action)
|
||||
void onPress() { enqueueCmd(ScreenCmd{.cmd = Cmd::ON_PRESS}); }
|
||||
void showPrevFrame() { enqueueCmd(ScreenCmd{.cmd = Cmd::SHOW_PREV_FRAME}); }
|
||||
void showNextFrame() { enqueueCmd(ScreenCmd{.cmd = Cmd::SHOW_NEXT_FRAME}); }
|
||||
|
||||
// Implementation to Adjust Brightness
|
||||
void adjustBrightness();
|
||||
@@ -301,9 +306,11 @@ class Screen : public concurrency::OSThread
|
||||
// Use this handle to set things like battery status, user count, GPS status, etc.
|
||||
DebugInfo *debug_info() { return &debugInfo; }
|
||||
|
||||
// Handle observer events
|
||||
int handleStatusUpdate(const meshtastic::Status *arg);
|
||||
int handleTextMessage(const meshtastic_MeshPacket *arg);
|
||||
int handleUIFrameEvent(const UIFrameEvent *arg);
|
||||
int handleInputEvent(const InputEvent *arg);
|
||||
|
||||
/// Used to force (super slow) eink displays to draw critical frames
|
||||
void forceDisplay();
|
||||
@@ -343,6 +350,8 @@ class Screen : public concurrency::OSThread
|
||||
// Implementations of various commands, called from doTask().
|
||||
void handleSetOn(bool on);
|
||||
void handleOnPress();
|
||||
void handleShowNextFrame();
|
||||
void handleShowPrevFrame();
|
||||
void handleStartBluetoothPinScreen(uint32_t pin);
|
||||
void handlePrint(const char *text);
|
||||
void handleStartFirmwareUpdateScreen();
|
||||
@@ -380,7 +389,7 @@ class Screen : public concurrency::OSThread
|
||||
SH1106Wire dispdev;
|
||||
#elif defined(USE_SSD1306)
|
||||
SSD1306Wire dispdev;
|
||||
#elif defined(ST7735_CS) || defined(ILI9341_DRIVER)
|
||||
#elif defined(ST7735_CS) || defined(ILI9341_DRIVER) || defined(ST7789_CS)
|
||||
TFTDisplay dispdev;
|
||||
#elif defined(USE_EINK)
|
||||
EInkDisplay dispdev;
|
||||
|
||||
@@ -1,12 +1,233 @@
|
||||
#include "configuration.h"
|
||||
|
||||
#if defined(ST7735_CS) || defined(ILI9341_DRIVER)
|
||||
#ifndef TFT_BACKLIGHT_ON
|
||||
#define TFT_BACKLIGHT_ON HIGH
|
||||
#endif
|
||||
|
||||
// convert 24-bit color to 16-bit (56K)
|
||||
#define COLOR565(r, g, b) (((r & 0xF8) << 8) | ((g & 0xFC) << 3) | ((b & 0xF8) >> 3))
|
||||
#define TFT_MESH COLOR565(0x67, 0xEA, 0x94)
|
||||
|
||||
#if defined(ST7735S)
|
||||
#include <LovyanGFX.hpp> // Graphics and font library for ST7735 driver chip
|
||||
|
||||
#if defined(ST7735_BACKLIGHT_EN) && !defined(TFT_BL)
|
||||
#define TFT_BL ST7735_BACKLIGHT_EN
|
||||
#endif
|
||||
|
||||
class LGFX : public lgfx::LGFX_Device
|
||||
{
|
||||
lgfx::Panel_ST7735S _panel_instance;
|
||||
lgfx::Bus_SPI _bus_instance;
|
||||
lgfx::Light_PWM _light_instance;
|
||||
|
||||
public:
|
||||
LGFX(void)
|
||||
{
|
||||
{
|
||||
auto cfg = _bus_instance.config();
|
||||
|
||||
// configure SPI
|
||||
cfg.spi_host = ST7735_SPI_HOST; // ESP32-S2,S3,C3 : SPI2_HOST or SPI3_HOST / ESP32 : VSPI_HOST or HSPI_HOST
|
||||
cfg.spi_mode = 0;
|
||||
cfg.freq_write = SPI_FREQUENCY; // SPI clock for transmission (up to 80MHz, rounded to the value obtained by dividing
|
||||
// 80MHz by an integer)
|
||||
cfg.freq_read = SPI_READ_FREQUENCY; // SPI clock when receiving
|
||||
cfg.spi_3wire = false; // Set to true if reception is done on the MOSI pin
|
||||
cfg.use_lock = true; // Set to true to use transaction locking
|
||||
cfg.dma_channel = SPI_DMA_CH_AUTO; // SPI_DMA_CH_AUTO; // Set DMA channel to use (0=not use DMA / 1=1ch / 2=ch /
|
||||
// SPI_DMA_CH_AUTO=auto setting)
|
||||
cfg.pin_sclk = ST7735_SCK; // Set SPI SCLK pin number
|
||||
cfg.pin_mosi = ST7735_SDA; // Set SPI MOSI pin number
|
||||
cfg.pin_miso = ST7735_MISO; // Set SPI MISO pin number (-1 = disable)
|
||||
cfg.pin_dc = ST7735_RS; // Set SPI DC pin number (-1 = disable)
|
||||
|
||||
_bus_instance.config(cfg); // applies the set value to the bus.
|
||||
_panel_instance.setBus(&_bus_instance); // set the bus on the panel.
|
||||
}
|
||||
|
||||
{ // Set the display panel control.
|
||||
auto cfg = _panel_instance.config(); // Gets a structure for display panel settings.
|
||||
|
||||
cfg.pin_cs = ST7735_CS; // Pin number where CS is connected (-1 = disable)
|
||||
cfg.pin_rst = ST7735_RESET; // Pin number where RST is connected (-1 = disable)
|
||||
cfg.pin_busy = ST7735_BUSY; // Pin number where BUSY is connected (-1 = disable)
|
||||
|
||||
// The following setting values are general initial values for each panel, so please comment out any
|
||||
// unknown items and try them.
|
||||
|
||||
cfg.panel_width = TFT_WIDTH; // actual displayable width
|
||||
cfg.panel_height = TFT_HEIGHT; // actual displayable height
|
||||
cfg.offset_x = TFT_OFFSET_X; // Panel offset amount in X direction
|
||||
cfg.offset_y = TFT_OFFSET_Y; // Panel offset amount in Y direction
|
||||
cfg.offset_rotation = 0; // Rotation direction value offset 0~7 (4~7 is upside down)
|
||||
cfg.dummy_read_pixel = 8; // Number of bits for dummy read before pixel readout
|
||||
cfg.dummy_read_bits = 1; // Number of bits for dummy read before non-pixel data read
|
||||
cfg.readable = true; // Set to true if data can be read
|
||||
cfg.invert = true; // Set to true if the light/darkness of the panel is reversed
|
||||
cfg.rgb_order = false; // Set to true if the panel's red and blue are swapped
|
||||
cfg.dlen_16bit =
|
||||
false; // Set to true for panels that transmit data length in 16-bit units with 16-bit parallel or SPI
|
||||
cfg.bus_shared = true; // If the bus is shared with the SD card, set to true (bus control with drawJpgFile etc.)
|
||||
|
||||
// Set the following only when the display is shifted with a driver with a variable number of pixels, such as the
|
||||
// ST7735 or ILI9163.
|
||||
cfg.memory_width = TFT_WIDTH; // Maximum width supported by the driver IC
|
||||
cfg.memory_height = TFT_HEIGHT; // Maximum height supported by the driver IC
|
||||
_panel_instance.config(cfg);
|
||||
}
|
||||
|
||||
// Set the backlight control
|
||||
{
|
||||
auto cfg = _light_instance.config(); // Gets a structure for backlight settings.
|
||||
|
||||
cfg.pin_bl = ST7735_BL; // Pin number to which the backlight is connected
|
||||
cfg.invert = true; // true to invert the brightness of the backlight
|
||||
// cfg.freq = 44100; // PWM frequency of backlight
|
||||
// cfg.pwm_channel = 1; // PWM channel number to use
|
||||
|
||||
_light_instance.config(cfg);
|
||||
_panel_instance.setLight(&_light_instance); // Set the backlight on the panel.
|
||||
}
|
||||
|
||||
setPanel(&_panel_instance);
|
||||
}
|
||||
};
|
||||
|
||||
static LGFX tft;
|
||||
|
||||
#elif defined(ST7789_CS)
|
||||
#include <LovyanGFX.hpp> // Graphics and font library for ST7735 driver chip
|
||||
|
||||
#if defined(ST7789_BACKLIGHT_EN) && !defined(TFT_BL)
|
||||
#define TFT_BL ST7789_BACKLIGHT_EN
|
||||
#endif
|
||||
|
||||
class LGFX : public lgfx::LGFX_Device
|
||||
{
|
||||
lgfx::Panel_ST7789 _panel_instance;
|
||||
lgfx::Bus_SPI _bus_instance;
|
||||
lgfx::Light_PWM _light_instance;
|
||||
#ifdef T_WATCH_S3
|
||||
lgfx::Touch_FT5x06 _touch_instance;
|
||||
#else
|
||||
lgfx::Touch_GT911 _touch_instance;
|
||||
#endif
|
||||
|
||||
public:
|
||||
LGFX(void)
|
||||
{
|
||||
{
|
||||
auto cfg = _bus_instance.config();
|
||||
|
||||
// SPI
|
||||
cfg.spi_host = ST7789_SPI_HOST;
|
||||
cfg.spi_mode = 0;
|
||||
cfg.freq_write = SPI_FREQUENCY; // SPI clock for transmission (up to 80MHz, rounded to the value obtained by dividing
|
||||
// 80MHz by an integer)
|
||||
cfg.freq_read = SPI_READ_FREQUENCY; // SPI clock when receiving
|
||||
cfg.spi_3wire = false; // Set to true if reception is done on the MOSI pin
|
||||
cfg.use_lock = true; // Set to true to use transaction locking
|
||||
cfg.dma_channel = SPI_DMA_CH_AUTO; // SPI_DMA_CH_AUTO; // Set DMA channel to use (0=not use DMA / 1=1ch / 2=ch /
|
||||
cfg.pin_sclk = ST7789_SCK; // Set SPI SCLK pin number
|
||||
cfg.pin_mosi = ST7789_SDA; // Set SPI MOSI pin number
|
||||
cfg.pin_miso = ST7789_MISO; // Set SPI MISO pin number (-1 = disable)
|
||||
cfg.pin_dc = ST7789_RS; // Set SPI DC pin number (-1 = disable)
|
||||
|
||||
_bus_instance.config(cfg); // applies the set value to the bus.
|
||||
_panel_instance.setBus(&_bus_instance); // set the bus on the panel.
|
||||
}
|
||||
|
||||
{ // Set the display panel control.
|
||||
auto cfg = _panel_instance.config(); // Gets a structure for display panel settings.
|
||||
|
||||
cfg.pin_cs = ST7789_CS; // Pin number where CS is connected (-1 = disable)
|
||||
cfg.pin_rst = -1; // Pin number where RST is connected (-1 = disable)
|
||||
cfg.pin_busy = -1; // Pin number where BUSY is connected (-1 = disable)
|
||||
|
||||
// The following setting values are general initial values for each panel, so please comment out any
|
||||
// unknown items and try them.
|
||||
|
||||
cfg.panel_width = TFT_WIDTH; // actual displayable width
|
||||
cfg.panel_height = TFT_HEIGHT; // actual displayable height
|
||||
cfg.offset_x = TFT_OFFSET_X; // Panel offset amount in X direction
|
||||
cfg.offset_y = TFT_OFFSET_Y; // Panel offset amount in Y direction
|
||||
cfg.offset_rotation = 0; // Rotation direction value offset 0~7 (4~7 is mirrored)
|
||||
cfg.dummy_read_pixel = 9; // Number of bits for dummy read before pixel readout
|
||||
cfg.dummy_read_bits = 1; // Number of bits for dummy read before non-pixel data read
|
||||
cfg.readable = true; // Set to true if data can be read
|
||||
cfg.invert = true; // Set to true if the light/darkness of the panel is reversed
|
||||
cfg.rgb_order = false; // Set to true if the panel's red and blue are swapped
|
||||
cfg.dlen_16bit =
|
||||
false; // Set to true for panels that transmit data length in 16-bit units with 16-bit parallel or SPI
|
||||
cfg.bus_shared = true; // If the bus is shared with the SD card, set to true (bus control with drawJpgFile etc.)
|
||||
|
||||
// Set the following only when the display is shifted with a driver with a variable number of pixels, such as the
|
||||
// ST7735 or ILI9163.
|
||||
// cfg.memory_width = TFT_WIDTH; // Maximum width supported by the driver IC
|
||||
// cfg.memory_height = TFT_HEIGHT; // Maximum height supported by the driver IC
|
||||
_panel_instance.config(cfg);
|
||||
}
|
||||
|
||||
// Set the backlight control. (delete if not necessary)
|
||||
{
|
||||
auto cfg = _light_instance.config(); // Gets a structure for backlight settings.
|
||||
|
||||
cfg.pin_bl = ST7789_BL; // Pin number to which the backlight is connected
|
||||
cfg.invert = false; // true to invert the brightness of the backlight
|
||||
// cfg.pwm_channel = 0;
|
||||
|
||||
_light_instance.config(cfg);
|
||||
_panel_instance.setLight(&_light_instance); // Set the backlight on the panel.
|
||||
}
|
||||
|
||||
// Configure settings for touch screen control.
|
||||
{
|
||||
auto cfg = _touch_instance.config();
|
||||
|
||||
cfg.pin_cs = -1;
|
||||
cfg.x_min = 0;
|
||||
cfg.x_max = TFT_HEIGHT - 1;
|
||||
cfg.y_min = 0;
|
||||
cfg.y_max = TFT_WIDTH - 1;
|
||||
cfg.pin_int = SCREEN_TOUCH_INT;
|
||||
cfg.bus_shared = true;
|
||||
cfg.offset_rotation = 0;
|
||||
// cfg.freq = 2500000;
|
||||
|
||||
// I2C
|
||||
cfg.i2c_port = TOUCH_I2C_PORT;
|
||||
cfg.i2c_addr = TOUCH_SLAVE_ADDRESS;
|
||||
#ifdef SCREEN_TOUCH_USE_I2C1
|
||||
cfg.pin_sda = I2C_SDA1;
|
||||
cfg.pin_scl = I2C_SCL1;
|
||||
#else
|
||||
cfg.pin_sda = I2C_SDA;
|
||||
cfg.pin_scl = I2C_SCL;
|
||||
#endif
|
||||
// cfg.freq = 400000;
|
||||
|
||||
_touch_instance.config(cfg);
|
||||
_panel_instance.setTouch(&_touch_instance);
|
||||
}
|
||||
|
||||
setPanel(&_panel_instance); // Sets the panel to use.
|
||||
}
|
||||
};
|
||||
|
||||
static LGFX tft;
|
||||
|
||||
#elif defined(ST7735_CS) || defined(ILI9341_DRIVER)
|
||||
#include <TFT_eSPI.h> // Graphics and font library for ILI9341 driver chip
|
||||
|
||||
static TFT_eSPI tft = TFT_eSPI(); // Invoke library, pins defined in User_Setup.h
|
||||
|
||||
#endif
|
||||
|
||||
#if defined(ST7735_CS) || defined(ST7789_CS) || defined(ILI9341_DRIVER)
|
||||
#include "SPILock.h"
|
||||
#include "TFTDisplay.h"
|
||||
#include <SPI.h>
|
||||
#include <TFT_eSPI.h> // Graphics and font library for ST7735 driver chip
|
||||
|
||||
static TFT_eSPI tft = TFT_eSPI(); // Invoke library, pins defined in User_Setup.h
|
||||
|
||||
TFTDisplay::TFTDisplay(uint8_t address, int sda, int scl, OLEDDISPLAY_GEOMETRY geometry, HW_I2C i2cBus)
|
||||
{
|
||||
@@ -30,7 +251,7 @@ void TFTDisplay::display(void)
|
||||
auto isset = buffer[x + (y / 8) * displayWidth] & (1 << (y & 7));
|
||||
auto dblbuf_isset = buffer_back[x + (y / 8) * displayWidth] & (1 << (y & 7));
|
||||
if (isset != dblbuf_isset) {
|
||||
tft.drawPixel(x, y, isset ? TFT_WHITE : TFT_BLACK);
|
||||
tft.drawPixel(x, y, isset ? TFT_MESH : TFT_BLACK);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -46,8 +267,55 @@ void TFTDisplay::display(void)
|
||||
// Send a command to the display (low level function)
|
||||
void TFTDisplay::sendCommand(uint8_t com)
|
||||
{
|
||||
(void)com;
|
||||
// Drop all commands to device (we just update the buffer)
|
||||
// handle display on/off directly
|
||||
switch (com) {
|
||||
case DISPLAYON: {
|
||||
#if defined(TFT_BL) && defined(TFT_BACKLIGHT_ON)
|
||||
digitalWrite(TFT_BL, TFT_BACKLIGHT_ON);
|
||||
#endif
|
||||
#ifdef VTFT_CTRL
|
||||
digitalWrite(VTFT_CTRL, LOW);
|
||||
#endif
|
||||
#ifndef M5STACK
|
||||
tft.setBrightness(128);
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
case DISPLAYOFF: {
|
||||
#if defined(TFT_BL) && defined(TFT_BACKLIGHT_ON)
|
||||
digitalWrite(TFT_BL, !TFT_BACKLIGHT_ON);
|
||||
#endif
|
||||
#ifdef VTFT_CTRL
|
||||
digitalWrite(VTFT_CTRL, HIGH);
|
||||
#endif
|
||||
#ifndef M5STACK
|
||||
tft.setBrightness(0);
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
// Drop all other commands to device (we just update the buffer)
|
||||
}
|
||||
|
||||
bool TFTDisplay::hasTouch(void)
|
||||
{
|
||||
#ifndef M5STACK
|
||||
return tft.touch() != nullptr;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
bool TFTDisplay::getTouch(int16_t *x, int16_t *y)
|
||||
{
|
||||
#ifndef M5STACK
|
||||
return tft.getTouch(x, y);
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
void TFTDisplay::setDetected(uint8_t detected)
|
||||
@@ -62,22 +330,19 @@ bool TFTDisplay::connect()
|
||||
LOG_INFO("Doing TFT init\n");
|
||||
|
||||
#ifdef TFT_BL
|
||||
digitalWrite(TFT_BL, HIGH);
|
||||
digitalWrite(TFT_BL, TFT_BACKLIGHT_ON);
|
||||
pinMode(TFT_BL, OUTPUT);
|
||||
#endif
|
||||
|
||||
#ifdef ST7735_BACKLIGHT_EN
|
||||
digitalWrite(ST7735_BACKLIGHT_EN, HIGH);
|
||||
pinMode(ST7735_BACKLIGHT_EN, OUTPUT);
|
||||
#endif
|
||||
tft.init();
|
||||
#ifdef M5STACK
|
||||
tft.setRotation(1); // M5Stack has the TFT in landscape
|
||||
#if defined(M5STACK) || defined(T_DECK)
|
||||
tft.setRotation(1); // M5Stack/T-Deck have the TFT in landscape
|
||||
#elif defined(T_WATCH_S3)
|
||||
tft.setRotation(0); // T-Watch S3 has the TFT in portrait
|
||||
#else
|
||||
tft.setRotation(3); // Orient horizontal and wide underneath the silkscreen name label
|
||||
#endif
|
||||
tft.fillScreen(TFT_BLACK);
|
||||
// tft.drawRect(0, 0, 40, 10, TFT_PURPLE); // wide rectangle in upper left
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -7,7 +7,6 @@
|
||||
*
|
||||
* Remaining TODO:
|
||||
* optimize display() to only draw changed pixels (see other OLED subclasses for examples)
|
||||
* implement displayOn/displayOff to turn off the TFT device (and backlight)
|
||||
* Use the fast NRF52 SPI API rather than the slow standard arduino version
|
||||
*
|
||||
* turn radio back on - currently with both on spi bus is fucked? or are we leaving chip select asserted?
|
||||
@@ -23,6 +22,10 @@ class TFTDisplay : public OLEDDisplay
|
||||
// Write the buffer to the display memory
|
||||
virtual void display(void) override;
|
||||
|
||||
// Touch screen (static handlers)
|
||||
static bool hasTouch(void);
|
||||
static bool getTouch(int16_t *x, int16_t *y);
|
||||
|
||||
/**
|
||||
* shim to make the abstraction happy
|
||||
*
|
||||
|
||||
@@ -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};
|
||||
|
||||
#if defined(USE_EINK) || defined(ILI9341_DRIVER) || defined(ST7735_CS)
|
||||
#if defined(USE_EINK) || defined(ILI9341_DRIVER) || defined(ST7735_CS) || defined(ST7789_CS)
|
||||
const uint8_t imgQuestionL1[] PROGMEM = {0xff, 0x01, 0x01, 0x32, 0x7b, 0x49, 0x49, 0x6f, 0x26, 0x01, 0x01, 0xff};
|
||||
const uint8_t imgQuestionL2[] PROGMEM = {0x0f, 0x08, 0x08, 0x08, 0x06, 0x0f, 0x0f, 0x06, 0x08, 0x08, 0x08, 0x0f};
|
||||
const uint8_t imgInfoL1[] PROGMEM = {0xff, 0x01, 0x01, 0x01, 0x1e, 0x7f, 0x1e, 0x01, 0x01, 0x01, 0x01, 0xff};
|
||||
|
||||
137
src/input/TouchScreenBase.cpp
Normal file
137
src/input/TouchScreenBase.cpp
Normal file
@@ -0,0 +1,137 @@
|
||||
#include "TouchScreenBase.h"
|
||||
#include "main.h"
|
||||
|
||||
#ifndef TIME_LONG_PRESS
|
||||
#define TIME_LONG_PRESS 400
|
||||
#endif
|
||||
|
||||
// move a minimum distance over the screen to detect a "swipe"
|
||||
#ifndef TOUCH_THRESHOLD_X
|
||||
#define TOUCH_THRESHOLD_X 30
|
||||
#endif
|
||||
|
||||
#ifndef TOUCH_THRESHOLD_Y
|
||||
#define TOUCH_THRESHOLD_Y 20
|
||||
#endif
|
||||
|
||||
TouchScreenBase::TouchScreenBase(const char *name, uint16_t width, uint16_t height)
|
||||
: concurrency::OSThread(name), _display_width(width), _display_height(height), _first_x(0), _last_x(0), _first_y(0),
|
||||
_last_y(0), _start(0), _tapped(false), _originName(name)
|
||||
{
|
||||
}
|
||||
|
||||
void TouchScreenBase::init(bool hasTouch)
|
||||
{
|
||||
if (hasTouch) {
|
||||
LOG_INFO("TouchScreen initialized %d %d\n", TOUCH_THRESHOLD_X, TOUCH_THRESHOLD_Y);
|
||||
this->setInterval(100);
|
||||
} else {
|
||||
disable();
|
||||
this->setInterval(UINT_MAX);
|
||||
}
|
||||
}
|
||||
|
||||
int32_t TouchScreenBase::runOnce()
|
||||
{
|
||||
TouchEvent e;
|
||||
e.touchEvent = static_cast<char>(TOUCH_ACTION_NONE);
|
||||
|
||||
// process touch events
|
||||
int16_t x, y;
|
||||
bool touched = getTouch(x, y);
|
||||
if (touched) {
|
||||
hapticFeedback();
|
||||
this->setInterval(20);
|
||||
_last_x = x;
|
||||
_last_y = y;
|
||||
}
|
||||
if (touched != _touchedOld) {
|
||||
if (touched) {
|
||||
_state = TOUCH_EVENT_OCCURRED;
|
||||
_start = millis();
|
||||
_first_x = x;
|
||||
_first_y = y;
|
||||
} else {
|
||||
_state = TOUCH_EVENT_CLEARED;
|
||||
time_t duration = millis() - _start;
|
||||
x = _last_x;
|
||||
y = _last_y;
|
||||
this->setInterval(50);
|
||||
|
||||
// compute distance
|
||||
int16_t dx = x - _first_x;
|
||||
int16_t dy = y - _first_y;
|
||||
uint16_t adx = abs(dx);
|
||||
uint16_t ady = abs(dy);
|
||||
|
||||
// swipe horizontal
|
||||
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");
|
||||
} else { // swipe left to right
|
||||
e.touchEvent = static_cast<char>(TOUCH_ACTION_RIGHT);
|
||||
LOG_DEBUG("action SWIPE: left to right\n");
|
||||
}
|
||||
}
|
||||
// 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");
|
||||
} else { // swipe top to bottom
|
||||
e.touchEvent = static_cast<char>(TOUCH_ACTION_DOWN);
|
||||
LOG_DEBUG("action SWIPE: top to bottom\n");
|
||||
}
|
||||
}
|
||||
// tap
|
||||
else {
|
||||
if (duration > 0 && duration < TIME_LONG_PRESS) {
|
||||
if (_tapped) {
|
||||
_tapped = false;
|
||||
e.touchEvent = static_cast<char>(TOUCH_ACTION_DOUBLE_TAP);
|
||||
LOG_DEBUG("action DOUBLE TAP(%d/%d)\n", x, y);
|
||||
} else {
|
||||
_tapped = true;
|
||||
}
|
||||
} else {
|
||||
_tapped = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
_touchedOld = touched;
|
||||
|
||||
// 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);
|
||||
}
|
||||
|
||||
// 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);
|
||||
}
|
||||
|
||||
if (e.touchEvent != TOUCH_ACTION_NONE) {
|
||||
e.source = this->_originName;
|
||||
e.x = _last_x;
|
||||
e.y = _last_y;
|
||||
onEvent(e);
|
||||
}
|
||||
|
||||
return interval;
|
||||
}
|
||||
|
||||
void TouchScreenBase::hapticFeedback()
|
||||
{
|
||||
#ifdef T_WATCH_S3
|
||||
drv.setWaveform(0, 75);
|
||||
drv.setWaveform(1, 0); // end waveform
|
||||
drv.go();
|
||||
#endif
|
||||
}
|
||||
55
src/input/TouchScreenBase.h
Normal file
55
src/input/TouchScreenBase.h
Normal file
@@ -0,0 +1,55 @@
|
||||
#pragma once
|
||||
|
||||
#include "InputBroker.h"
|
||||
#include "concurrency/OSThread.h"
|
||||
#include "mesh/NodeDB.h"
|
||||
|
||||
typedef struct _TouchEvent {
|
||||
const char *source;
|
||||
char touchEvent;
|
||||
uint16_t x;
|
||||
uint16_t y;
|
||||
} TouchEvent;
|
||||
|
||||
class TouchScreenBase : public Observable<const InputEvent *>, public concurrency::OSThread
|
||||
{
|
||||
public:
|
||||
explicit TouchScreenBase(const char *name, uint16_t width, uint16_t height);
|
||||
void init(bool hasTouch);
|
||||
|
||||
protected:
|
||||
enum TouchScreenBaseStateType { TOUCH_EVENT_OCCURRED, TOUCH_EVENT_CLEARED };
|
||||
|
||||
enum TouchScreenBaseEventType {
|
||||
TOUCH_ACTION_NONE,
|
||||
TOUCH_ACTION_UP,
|
||||
TOUCH_ACTION_DOWN,
|
||||
TOUCH_ACTION_LEFT,
|
||||
TOUCH_ACTION_RIGHT,
|
||||
TOUCH_ACTION_TAP,
|
||||
TOUCH_ACTION_DOUBLE_TAP,
|
||||
TOUCH_ACTION_LONG_PRESS
|
||||
};
|
||||
|
||||
virtual int32_t runOnce() override;
|
||||
|
||||
virtual bool getTouch(int16_t &x, int16_t &y) = 0;
|
||||
virtual void onEvent(const TouchEvent &event) = 0;
|
||||
|
||||
volatile TouchScreenBaseStateType _state = TOUCH_EVENT_CLEARED;
|
||||
volatile TouchScreenBaseEventType _action = TOUCH_ACTION_NONE;
|
||||
void hapticFeedback();
|
||||
|
||||
protected:
|
||||
uint16_t _display_width;
|
||||
uint16_t _display_height;
|
||||
|
||||
private:
|
||||
bool _touchedOld = false; // previous touch state
|
||||
int16_t _first_x, _last_x; // horizontal swipe direction
|
||||
int16_t _first_y, _last_y; // vertical swipe direction
|
||||
time_t _start; // for LONG_PRESS
|
||||
bool _tapped; // for DOUBLE_TAP
|
||||
|
||||
const char *_originName;
|
||||
};
|
||||
68
src/input/TouchScreenImpl1.cpp
Normal file
68
src/input/TouchScreenImpl1.cpp
Normal file
@@ -0,0 +1,68 @@
|
||||
#include "TouchScreenImpl1.h"
|
||||
#include "InputBroker.h"
|
||||
#include "configuration.h"
|
||||
|
||||
TouchScreenImpl1 *touchScreenImpl1;
|
||||
|
||||
TouchScreenImpl1::TouchScreenImpl1(uint16_t width, uint16_t height, bool (*getTouch)(int16_t *, int16_t *))
|
||||
: TouchScreenBase("touchscreen1", width, height), _getTouch(getTouch)
|
||||
{
|
||||
}
|
||||
|
||||
void TouchScreenImpl1::init()
|
||||
{
|
||||
#if !HAS_TOUCHSCREEN
|
||||
TouchScreenBase::init(false);
|
||||
return;
|
||||
#else
|
||||
TouchScreenBase::init(true);
|
||||
inputBroker->registerSource(this);
|
||||
#endif
|
||||
}
|
||||
|
||||
bool TouchScreenImpl1::getTouch(int16_t &x, int16_t &y)
|
||||
{
|
||||
return _getTouch(&x, &y);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief forward touchscreen event
|
||||
*
|
||||
* @param event
|
||||
*
|
||||
* The touchscreen events are translated to input events and reversed
|
||||
*/
|
||||
void TouchScreenImpl1::onEvent(const TouchEvent &event)
|
||||
{
|
||||
InputEvent e;
|
||||
e.source = event.source;
|
||||
switch (event.touchEvent) {
|
||||
case TOUCH_ACTION_LEFT: {
|
||||
e.inputEvent = static_cast<char>(meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_RIGHT);
|
||||
break;
|
||||
}
|
||||
case TOUCH_ACTION_RIGHT: {
|
||||
e.inputEvent = static_cast<char>(meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_LEFT);
|
||||
break;
|
||||
}
|
||||
case TOUCH_ACTION_UP: {
|
||||
e.inputEvent = static_cast<char>(meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_UP);
|
||||
break;
|
||||
}
|
||||
case TOUCH_ACTION_DOWN: {
|
||||
e.inputEvent = static_cast<char>(meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_DOWN);
|
||||
break;
|
||||
}
|
||||
case TOUCH_ACTION_DOUBLE_TAP: {
|
||||
e.inputEvent = static_cast<char>(meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_SELECT);
|
||||
break;
|
||||
}
|
||||
case TOUCH_ACTION_LONG_PRESS: {
|
||||
e.inputEvent = static_cast<char>(meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_CANCEL);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
return;
|
||||
}
|
||||
this->notifyObservers(&e);
|
||||
}
|
||||
17
src/input/TouchScreenImpl1.h
Normal file
17
src/input/TouchScreenImpl1.h
Normal file
@@ -0,0 +1,17 @@
|
||||
#pragma once
|
||||
#include "TouchScreenBase.h"
|
||||
|
||||
class TouchScreenImpl1 : public TouchScreenBase
|
||||
{
|
||||
public:
|
||||
TouchScreenImpl1(uint16_t width, uint16_t height, bool (*getTouch)(int16_t *, int16_t *));
|
||||
void init(void);
|
||||
|
||||
protected:
|
||||
virtual bool getTouch(int16_t &x, int16_t &y);
|
||||
virtual void onEvent(const TouchEvent &event);
|
||||
|
||||
bool (*_getTouch)(int16_t *, int16_t *);
|
||||
};
|
||||
|
||||
extern TouchScreenImpl1 *touchScreenImpl1;
|
||||
78
src/input/TrackballInterruptBase.cpp
Normal file
78
src/input/TrackballInterruptBase.cpp
Normal file
@@ -0,0 +1,78 @@
|
||||
#include "TrackballInterruptBase.h"
|
||||
#include "configuration.h"
|
||||
|
||||
TrackballInterruptBase::TrackballInterruptBase(const char *name)
|
||||
{
|
||||
this->_originName = name;
|
||||
}
|
||||
|
||||
void TrackballInterruptBase::init(uint8_t pinDown, uint8_t pinUp, uint8_t pinLeft, uint8_t pinRight, uint8_t pinPress,
|
||||
char eventDown, char eventUp, char eventLeft, char eventRight, char eventPressed,
|
||||
void (*onIntDown)(), void (*onIntUp)(), void (*onIntLeft)(), void (*onIntRight)(),
|
||||
void (*onIntPress)())
|
||||
{
|
||||
this->_pinDown = pinDown;
|
||||
this->_pinUp = pinUp;
|
||||
this->_pinLeft = pinLeft;
|
||||
this->_pinRight = pinRight;
|
||||
this->_eventDown = eventDown;
|
||||
this->_eventUp = eventUp;
|
||||
this->_eventLeft = eventLeft;
|
||||
this->_eventRight = eventRight;
|
||||
this->_eventPressed = eventPressed;
|
||||
|
||||
pinMode(pinPress, INPUT_PULLUP);
|
||||
pinMode(this->_pinDown, INPUT_PULLUP);
|
||||
pinMode(this->_pinUp, INPUT_PULLUP);
|
||||
pinMode(this->_pinLeft, INPUT_PULLUP);
|
||||
pinMode(this->_pinRight, INPUT_PULLUP);
|
||||
|
||||
attachInterrupt(pinPress, onIntPress, RISING);
|
||||
attachInterrupt(this->_pinDown, onIntDown, RISING);
|
||||
attachInterrupt(this->_pinUp, onIntUp, RISING);
|
||||
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,
|
||||
pinPress);
|
||||
}
|
||||
|
||||
void TrackballInterruptBase::intPressHandler()
|
||||
{
|
||||
InputEvent e;
|
||||
e.source = this->_originName;
|
||||
e.inputEvent = this->_eventPressed;
|
||||
this->notifyObservers(&e);
|
||||
}
|
||||
|
||||
void TrackballInterruptBase::intDownHandler()
|
||||
{
|
||||
InputEvent e;
|
||||
e.source = this->_originName;
|
||||
e.inputEvent = this->_eventDown;
|
||||
this->notifyObservers(&e);
|
||||
}
|
||||
|
||||
void TrackballInterruptBase::intUpHandler()
|
||||
{
|
||||
InputEvent e;
|
||||
e.source = this->_originName;
|
||||
e.inputEvent = this->_eventUp;
|
||||
this->notifyObservers(&e);
|
||||
}
|
||||
|
||||
void TrackballInterruptBase::intLeftHandler()
|
||||
{
|
||||
InputEvent e;
|
||||
e.source = this->_originName;
|
||||
e.inputEvent = this->_eventLeft;
|
||||
this->notifyObservers(&e);
|
||||
}
|
||||
|
||||
void TrackballInterruptBase::intRightHandler()
|
||||
{
|
||||
InputEvent e;
|
||||
e.source = this->_originName;
|
||||
e.inputEvent = this->_eventRight;
|
||||
this->notifyObservers(&e);
|
||||
}
|
||||
30
src/input/TrackballInterruptBase.h
Normal file
30
src/input/TrackballInterruptBase.h
Normal file
@@ -0,0 +1,30 @@
|
||||
#pragma once
|
||||
|
||||
#include "InputBroker.h"
|
||||
#include "mesh/NodeDB.h"
|
||||
|
||||
class TrackballInterruptBase : public Observable<const InputEvent *>
|
||||
{
|
||||
public:
|
||||
explicit TrackballInterruptBase(const char *name);
|
||||
void init(uint8_t pinDown, uint8_t pinUp, uint8_t pinLeft, uint8_t pinRight, uint8_t pinPress, char eventDown, char eventUp,
|
||||
char eventLeft, char eventRight, char eventPressed, void (*onIntDown)(), void (*onIntUp)(), void (*onIntLeft)(),
|
||||
void (*onIntRight)(), void (*onIntPress)());
|
||||
void intPressHandler();
|
||||
void intDownHandler();
|
||||
void intUpHandler();
|
||||
void intLeftHandler();
|
||||
void intRightHandler();
|
||||
|
||||
private:
|
||||
uint8_t _pinDown = 0;
|
||||
uint8_t _pinUp = 0;
|
||||
uint8_t _pinLeft = 0;
|
||||
uint8_t _pinRight = 0;
|
||||
char _eventDown = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_NONE;
|
||||
char _eventUp = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_NONE;
|
||||
char _eventLeft = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_NONE;
|
||||
char _eventRight = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_NONE;
|
||||
char _eventPressed = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_NONE;
|
||||
const char *_originName;
|
||||
};
|
||||
54
src/input/TrackballInterruptImpl1.cpp
Normal file
54
src/input/TrackballInterruptImpl1.cpp
Normal file
@@ -0,0 +1,54 @@
|
||||
#include "TrackballInterruptImpl1.h"
|
||||
#include "InputBroker.h"
|
||||
#include "configuration.h"
|
||||
|
||||
TrackballInterruptImpl1 *trackballInterruptImpl1;
|
||||
|
||||
TrackballInterruptImpl1::TrackballInterruptImpl1() : TrackballInterruptBase("trackball1") {}
|
||||
|
||||
void TrackballInterruptImpl1::init()
|
||||
{
|
||||
#if !HAS_TRACKBALL
|
||||
// Input device is disabled.
|
||||
return;
|
||||
#else
|
||||
uint8_t pinUp = TB_UP;
|
||||
uint8_t pinDown = TB_DOWN;
|
||||
uint8_t pinLeft = TB_LEFT;
|
||||
uint8_t pinRight = TB_RIGHT;
|
||||
uint8_t pinPress = TB_PRESS;
|
||||
|
||||
char eventDown = static_cast<char>(meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_DOWN);
|
||||
char eventUp = static_cast<char>(meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_UP);
|
||||
char eventLeft = static_cast<char>(meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_LEFT);
|
||||
char eventRight = static_cast<char>(meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_RIGHT);
|
||||
char eventPressed = static_cast<char>(meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_SELECT);
|
||||
|
||||
TrackballInterruptBase::init(pinDown, pinUp, pinLeft, pinRight, pinPress, eventDown, eventUp, eventLeft, eventRight,
|
||||
eventPressed, TrackballInterruptImpl1::handleIntDown, TrackballInterruptImpl1::handleIntUp,
|
||||
TrackballInterruptImpl1::handleIntLeft, TrackballInterruptImpl1::handleIntRight,
|
||||
TrackballInterruptImpl1::handleIntPressed);
|
||||
inputBroker->registerSource(this);
|
||||
#endif
|
||||
}
|
||||
|
||||
void TrackballInterruptImpl1::handleIntDown()
|
||||
{
|
||||
trackballInterruptImpl1->intDownHandler();
|
||||
}
|
||||
void TrackballInterruptImpl1::handleIntUp()
|
||||
{
|
||||
trackballInterruptImpl1->intUpHandler();
|
||||
}
|
||||
void TrackballInterruptImpl1::handleIntLeft()
|
||||
{
|
||||
trackballInterruptImpl1->intLeftHandler();
|
||||
}
|
||||
void TrackballInterruptImpl1::handleIntRight()
|
||||
{
|
||||
trackballInterruptImpl1->intRightHandler();
|
||||
}
|
||||
void TrackballInterruptImpl1::handleIntPressed()
|
||||
{
|
||||
trackballInterruptImpl1->intPressHandler();
|
||||
}
|
||||
16
src/input/TrackballInterruptImpl1.h
Normal file
16
src/input/TrackballInterruptImpl1.h
Normal file
@@ -0,0 +1,16 @@
|
||||
#pragma once
|
||||
#include "TrackballInterruptBase.h"
|
||||
|
||||
class TrackballInterruptImpl1 : public TrackballInterruptBase
|
||||
{
|
||||
public:
|
||||
TrackballInterruptImpl1();
|
||||
void init();
|
||||
static void handleIntDown();
|
||||
static void handleIntUp();
|
||||
static void handleIntLeft();
|
||||
static void handleIntRight();
|
||||
static void handleIntPressed();
|
||||
};
|
||||
|
||||
extern TrackballInterruptImpl1 *trackballInterruptImpl1;
|
||||
@@ -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("GPIO initialized (%d, %d, %d)\n", this->_pinDown, this->_pinUp, pinPress);
|
||||
LOG_DEBUG("Up/down/press GPIO initialized (%d, %d, %d)\n", this->_pinUp, this->_pinDown, pinPress);
|
||||
}
|
||||
|
||||
void UpDownInterruptBase::intPressHandler()
|
||||
|
||||
@@ -7,7 +7,7 @@ CardKbI2cImpl::CardKbI2cImpl() : KbI2cBase("cardKB") {}
|
||||
|
||||
void CardKbI2cImpl::init()
|
||||
{
|
||||
if (cardkb_found.address != CARDKB_ADDR) {
|
||||
if (cardkb_found.address != CARDKB_ADDR && cardkb_found.address != TDECK_KB_ADDR) {
|
||||
disable();
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -41,7 +41,7 @@ void write_to_14004(const TwoWire * i2cBus, uint8_t reg, uint8_t data)
|
||||
|
||||
int32_t KbI2cBase::runOnce()
|
||||
{
|
||||
if (cardkb_found.address != CARDKB_ADDR) {
|
||||
if (cardkb_found.address != CARDKB_ADDR && cardkb_found.address != TDECK_KB_ADDR) {
|
||||
// Input device is not detected.
|
||||
return INT32_MAX;
|
||||
}
|
||||
@@ -85,9 +85,9 @@ int32_t KbI2cBase::runOnce()
|
||||
e.kbchar = PrintDataBuf;
|
||||
this->notifyObservers(&e);
|
||||
}
|
||||
} else {
|
||||
// m5 cardkb
|
||||
i2cBus->requestFrom(CARDKB_ADDR, 1);
|
||||
} else if (kb_model == 0x00 || kb_model == 0x10) {
|
||||
// m5 cardkb and T-Deck
|
||||
i2cBus->requestFrom(kb_model == 0x00 ? CARDKB_ADDR : TDECK_KB_ADDR, 1);
|
||||
|
||||
while (i2cBus->available()) {
|
||||
char c = i2cBus->read();
|
||||
@@ -132,6 +132,8 @@ int32_t KbI2cBase::runOnce()
|
||||
this->notifyObservers(&e);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
LOG_WARN("Unknown kb_model 0x%02x\n", kb_model);
|
||||
}
|
||||
return 500;
|
||||
return 300;
|
||||
}
|
||||
|
||||
77
src/main.cpp
77
src/main.cpp
@@ -47,13 +47,12 @@ NRF52Bluetooth *nrf52Bluetooth;
|
||||
|
||||
#if HAS_WIFI
|
||||
#include "mesh/api/WiFiServerAPI.h"
|
||||
#include "mqtt/MQTT.h"
|
||||
#endif
|
||||
|
||||
#if HAS_ETHERNET
|
||||
#include "mesh/api/ethServerAPI.h"
|
||||
#include "mqtt/MQTT.h"
|
||||
#endif
|
||||
#include "mqtt/MQTT.h"
|
||||
|
||||
#include "LLCC68Interface.h"
|
||||
#include "RF95Interface.h"
|
||||
@@ -97,7 +96,7 @@ ScanI2C::DeviceAddress screen_found = ScanI2C::ADDRESS_NONE;
|
||||
|
||||
// The I2C address of the cardkb or RAK14004 (if found)
|
||||
ScanI2C::DeviceAddress cardkb_found = ScanI2C::ADDRESS_NONE;
|
||||
// 0x02 for RAK14004 and 0x00 for cardkb
|
||||
// 0x02 for RAK14004, 0x00 for cardkb, 0x10 for T-Deck
|
||||
uint8_t kb_model;
|
||||
|
||||
// The I2C address of the RTC Module (if found)
|
||||
@@ -111,6 +110,11 @@ ScanI2C::FoundDevice rgb_found = ScanI2C::FoundDevice(ScanI2C::DeviceType::NONE,
|
||||
ATECCX08A atecc;
|
||||
#endif
|
||||
|
||||
#ifdef T_WATCH_S3
|
||||
Adafruit_DRV2605 drv;
|
||||
#endif
|
||||
bool isVibrating = false;
|
||||
|
||||
bool eink_found = true;
|
||||
|
||||
uint32_t serialSinceMsec;
|
||||
@@ -170,7 +174,7 @@ SPISettings spiSettings(4000000, MSBFIRST, SPI_MODE0);
|
||||
RadioInterface *rIf = NULL;
|
||||
|
||||
/**
|
||||
* Some platforms (nrf52) might provide an alterate version that supresses calling delay from sleep.
|
||||
* Some platforms (nrf52) might provide an alterate version that suppresses calling delay from sleep.
|
||||
*/
|
||||
__attribute__((weak, noinline)) bool loopCanSleep()
|
||||
{
|
||||
@@ -215,6 +219,16 @@ void setup()
|
||||
digitalWrite(VEXT_ENABLE, 0); // turn on the display power
|
||||
#endif
|
||||
|
||||
#ifdef VGNSS_CTRL
|
||||
pinMode(VGNSS_CTRL, OUTPUT);
|
||||
digitalWrite(VGNSS_CTRL, LOW);
|
||||
#endif
|
||||
|
||||
#if defined(VTFT_CTRL)
|
||||
pinMode(VTFT_CTRL, OUTPUT);
|
||||
digitalWrite(VTFT_CTRL, LOW);
|
||||
#endif
|
||||
|
||||
#ifdef RESET_OLED
|
||||
pinMode(RESET_OLED, OUTPUT);
|
||||
digitalWrite(RESET_OLED, 1);
|
||||
@@ -241,6 +255,19 @@ void setup()
|
||||
|
||||
fsInit();
|
||||
|
||||
#if defined(_SEEED_XIAO_NRF52840_SENSE_H_)
|
||||
|
||||
pinMode(CHARGE_LED, INPUT); // sets to detect if charge LED is on or off to see if USB is plugged in
|
||||
|
||||
pinMode(HICHG, OUTPUT);
|
||||
digitalWrite(HICHG, LOW); // 100 mA charging current if set to LOW and 50mA (actually about 20mA) if set to HIGH
|
||||
|
||||
pinMode(BAT_READ, OUTPUT);
|
||||
digitalWrite(BAT_READ, LOW); // This is pin P0_14 = 14 and by pullling low to GND it provices path to read on pin 32 (P0,31)
|
||||
// PIN_VBAT the voltage from divider on XIAO board
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef I2C_SDA1
|
||||
Wire1.begin(I2C_SDA1, I2C_SCL1);
|
||||
#endif
|
||||
@@ -261,10 +288,11 @@ void setup()
|
||||
#endif
|
||||
|
||||
#ifdef RAK4630
|
||||
#ifdef PIN_3V3_EN
|
||||
// We need to enable 3.3V periphery in order to scan it
|
||||
pinMode(PIN_3V3_EN, OUTPUT);
|
||||
digitalWrite(PIN_3V3_EN, HIGH);
|
||||
|
||||
#endif
|
||||
#ifndef USE_EINK
|
||||
// RAK-12039 set pin for Air quality sensor
|
||||
pinMode(AQ_SET_PIN, OUTPUT);
|
||||
@@ -272,6 +300,15 @@ void setup()
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef T_DECK
|
||||
// enable keyboard
|
||||
pinMode(KB_POWERON, OUTPUT);
|
||||
digitalWrite(KB_POWERON, HIGH);
|
||||
// There needs to be a delay after power on, give LILYGO-KEYBOARD some startup time
|
||||
// otherwise keyboard and touch screen will not work
|
||||
delay(800);
|
||||
#endif
|
||||
|
||||
// Currently only the tbeam has a PMU
|
||||
// PMU initialization needs to be placed before i2c scanning
|
||||
power = new Power();
|
||||
@@ -344,8 +381,15 @@ void setup()
|
||||
kb_model = 0x02;
|
||||
break;
|
||||
case ScanI2C::DeviceType::CARDKB:
|
||||
kb_model = 0x00;
|
||||
break;
|
||||
case ScanI2C::DeviceType::TDECKKB:
|
||||
// assign an arbitrary value to distinguish from other models
|
||||
kb_model = 0x10;
|
||||
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);
|
||||
kb_model = 0x00;
|
||||
}
|
||||
}
|
||||
@@ -359,10 +403,11 @@ void setup()
|
||||
*/
|
||||
|
||||
// Only one supported RGB LED currently
|
||||
#ifdef HAS_NCP5623
|
||||
rgb_found = i2cScanner->find(ScanI2C::DeviceType::NCP5623);
|
||||
|
||||
// Start the RGB LED at 50%
|
||||
#ifdef RAK4630
|
||||
|
||||
if (rgb_found.type == ScanI2C::NCP5623) {
|
||||
rgb.begin();
|
||||
rgb.setCurrent(10);
|
||||
@@ -429,6 +474,11 @@ void setup()
|
||||
#ifdef ARCH_NRF52
|
||||
nrf52Setup();
|
||||
#endif
|
||||
|
||||
#ifdef ARCH_RP2040
|
||||
rp2040Setup();
|
||||
#endif
|
||||
|
||||
// We do this as early as possible because this loads preferences from flash
|
||||
// but we need to do this after main cpu iniot (esp32setup), because we need the random seed set
|
||||
nodeDB.init();
|
||||
@@ -461,10 +511,19 @@ void setup()
|
||||
|
||||
#if !defined(ARCH_PORTDUINO) && !defined(ARCH_STM32WL) && !defined(ARCH_APOLLO3)
|
||||
if (acc_info.type != ScanI2C::DeviceType::NONE) {
|
||||
config.display.wake_on_tap_or_motion = true;
|
||||
moduleConfig.external_notification.enabled = true;
|
||||
accelerometerThread = new AccelerometerThread(acc_info.type);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef T_WATCH_S3
|
||||
drv.begin();
|
||||
drv.selectLibrary(1);
|
||||
// I2C trigger by sending 'go' command
|
||||
drv.setMode(DRV2605_MODE_INTTRIG);
|
||||
#endif
|
||||
|
||||
// Init our SPI controller (must be before screen and lora)
|
||||
initSPI();
|
||||
#ifdef ARCH_RP2040
|
||||
@@ -520,7 +579,7 @@ void setup()
|
||||
|
||||
// Don't call screen setup until after nodedb is setup (because we need
|
||||
// the current region name)
|
||||
#if defined(ST7735_CS) || defined(USE_EINK) || defined(ILI9341_DRIVER)
|
||||
#if defined(ST7735_CS) || defined(USE_EINK) || defined(ILI9341_DRIVER) || defined(ST7789_CS)
|
||||
screen->setup();
|
||||
#else
|
||||
if (screen_found.port != ScanI2C::I2CPort::NO_I2C)
|
||||
@@ -657,9 +716,7 @@ void setup()
|
||||
}
|
||||
}
|
||||
|
||||
#if HAS_WIFI || HAS_ETHERNET
|
||||
mqttInit();
|
||||
#endif
|
||||
|
||||
#ifndef ARCH_PORTDUINO
|
||||
// Initialize Wifi
|
||||
@@ -704,7 +761,7 @@ uint32_t rebootAtMsec; // If not zero we will reboot at this time (used to reb
|
||||
uint32_t shutdownAtMsec; // If not zero we will shutdown at this time (used to shutdown from python or mobile client)
|
||||
|
||||
// If a thread does something that might need for it to be rescheduled ASAP it can set this flag
|
||||
// This will supress the current delay and instead try to run ASAP.
|
||||
// This will suppress the current delay and instead try to run ASAP.
|
||||
bool runASAP;
|
||||
|
||||
extern meshtastic_DeviceMetadata getDeviceMetadata()
|
||||
|
||||
10
src/main.h
10
src/main.h
@@ -38,6 +38,12 @@ extern bool isUSBPowered;
|
||||
extern ATECCX08A atecc;
|
||||
#endif
|
||||
|
||||
#ifdef T_WATCH_S3
|
||||
#include <Adafruit_DRV2605.h>
|
||||
extern Adafruit_DRV2605 drv;
|
||||
#endif
|
||||
extern bool isVibrating;
|
||||
|
||||
extern int TCPPort; // set by Portduino
|
||||
|
||||
// Global Screen singleton.
|
||||
@@ -59,10 +65,10 @@ extern uint32_t shutdownAtMsec;
|
||||
extern uint32_t serialSinceMsec;
|
||||
|
||||
// If a thread does something that might need for it to be rescheduled ASAP it can set this flag
|
||||
// This will supress the current delay and instead try to run ASAP.
|
||||
// This will suppress the current delay and instead try to run ASAP.
|
||||
extern bool runASAP;
|
||||
|
||||
void nrf52Setup(), esp32Setup(), nrf52Loop(), esp32Loop(), clearBonds();
|
||||
void nrf52Setup(), esp32Setup(), nrf52Loop(), esp32Loop(), rp2040Setup(), clearBonds();
|
||||
|
||||
meshtastic_DeviceMetadata getDeviceMetadata();
|
||||
|
||||
|
||||
@@ -20,7 +20,7 @@ class Channels
|
||||
/// The index of the primary channel
|
||||
ChannelIndex primaryIndex = 0;
|
||||
|
||||
/** The channel index that was requested for sending/receving. Note: if this channel is a secondary
|
||||
/** The channel index that was requested for sending/receiving. Note: if this channel is a secondary
|
||||
channel and does not have a PSK, we will use the PSK from the primary channel. If this channel is disabled
|
||||
no sending or receiving will be allowed */
|
||||
ChannelIndex activeChannelIndex = 0;
|
||||
|
||||
@@ -21,7 +21,12 @@ bool FloodingRouter::shouldFilterReceived(const meshtastic_MeshPacket *p)
|
||||
{
|
||||
if (wasSeenRecently(p)) { // Note: this will also add a recent packet record
|
||||
printPacket("Ignoring incoming msg, because we've already seen it", p);
|
||||
Router::cancelSending(p->from, p->id); // cancel rebroadcast of this message *if* there was already one
|
||||
if (config.device.role != meshtastic_Config_DeviceConfig_Role_ROUTER &&
|
||||
config.device.role != meshtastic_Config_DeviceConfig_Role_ROUTER_CLIENT &&
|
||||
config.device.role != meshtastic_Config_DeviceConfig_Role_REPEATER) {
|
||||
// cancel rebroadcast of this message *if* there was already one, unless we're a router/repeater!
|
||||
Router::cancelSending(p->from, p->id);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -48,7 +48,7 @@ class FloodingRouter : public Router, protected PacketHistory
|
||||
/**
|
||||
* Should this incoming filter be dropped?
|
||||
*
|
||||
* Called immedately on receiption, before any further processing.
|
||||
* Called immediately on reception, before any further processing.
|
||||
* @return true to abandon the packet
|
||||
*/
|
||||
virtual bool shouldFilterReceived(const meshtastic_MeshPacket *p) override;
|
||||
|
||||
@@ -18,7 +18,7 @@ meshtastic_MeshPacket *MeshModule::currentReply;
|
||||
|
||||
MeshModule::MeshModule(const char *_name) : name(_name)
|
||||
{
|
||||
// Can't trust static initalizer order, so we check each time
|
||||
// Can't trust static initializer order, so we check each time
|
||||
if (!modules)
|
||||
modules = new std::vector<MeshModule *>();
|
||||
|
||||
@@ -39,7 +39,7 @@ meshtastic_MeshPacket *MeshModule::allocAckNak(meshtastic_Routing_Error err, Nod
|
||||
c.error_reason = err;
|
||||
c.which_variant = meshtastic_Routing_error_reason_tag;
|
||||
|
||||
// Now that we have moded sendAckNak up one level into the class heirarchy we can no longer assume we are a RoutingPlugin
|
||||
// Now that we have moded sendAckNak up one level into the class hierarchy we can no longer assume we are a RoutingPlugin
|
||||
// So we manually call pb_encode_to_bytes and specify routing port number
|
||||
// auto p = allocDataProtobuf(c);
|
||||
meshtastic_MeshPacket *p = router->allocForSending();
|
||||
@@ -169,7 +169,7 @@ void MeshModule::callPlugins(const meshtastic_MeshPacket &mp, RxSource src)
|
||||
// Note: if the message started with the local node or a module asked to ignore the request, we don't want to send a
|
||||
// no response reply
|
||||
|
||||
// No one wanted to reply to this requst, tell the requster that happened
|
||||
// No one wanted to reply to this request, tell the requster that happened
|
||||
LOG_DEBUG("No one responded, send a nak\n");
|
||||
|
||||
// SECURITY NOTE! I considered sending back a different error code if we didn't find the psk (i.e. !isDecoded)
|
||||
|
||||
@@ -47,7 +47,7 @@ typedef struct _UIFrameEvent {
|
||||
* A key concept for this is that your module should use a particular "portnum" for each message type you want to receive
|
||||
* and handle.
|
||||
*
|
||||
* Interally we use modules to implement the core meshtastic text messaging and gps position sharing features. You
|
||||
* Internally we use modules to implement the core meshtastic text messaging and gps position sharing features. You
|
||||
* can use these classes as examples for how to write your own custom module. See here: (FIXME)
|
||||
*/
|
||||
class MeshModule
|
||||
|
||||
@@ -34,7 +34,7 @@ arbitrating to select a node number and keeping the current nodedb.
|
||||
|
||||
/* Broadcast when a newly powered mesh node wants to find a node num it can use
|
||||
|
||||
The algoritm is as follows:
|
||||
The algorithm is as follows:
|
||||
* when a node starts up, it broadcasts their user and the normal flow is for all other nodes to reply with their User as well (so
|
||||
the new node can build its node db)
|
||||
* If a node ever receives a User (not just the first broadcast) message where the sender node number equals our node number, that
|
||||
@@ -52,13 +52,18 @@ FIXME in the initial proof of concept we just skip the entire want/deny flow and
|
||||
|
||||
MeshService service;
|
||||
|
||||
static MemoryDynamic<meshtastic_MqttClientProxyMessage> staticMqttClientProxyMessagePool;
|
||||
|
||||
static MemoryDynamic<meshtastic_QueueStatus> staticQueueStatusPool;
|
||||
|
||||
Allocator<meshtastic_MqttClientProxyMessage> &mqttClientProxyMessagePool = staticMqttClientProxyMessagePool;
|
||||
|
||||
Allocator<meshtastic_QueueStatus> &queueStatusPool = staticQueueStatusPool;
|
||||
|
||||
#include "Router.h"
|
||||
|
||||
MeshService::MeshService() : toPhoneQueue(MAX_RX_TOPHONE), toPhoneQueueStatusQueue(MAX_RX_TOPHONE)
|
||||
MeshService::MeshService()
|
||||
: toPhoneQueue(MAX_RX_TOPHONE), toPhoneQueueStatusQueue(MAX_RX_TOPHONE), toPhoneMqttProxyQueue(MAX_RX_TOPHONE)
|
||||
{
|
||||
lastQueueStatus = {0, 0, 16, 0};
|
||||
}
|
||||
@@ -269,6 +274,20 @@ void MeshService::sendToPhone(meshtastic_MeshPacket *p)
|
||||
fromNum++;
|
||||
}
|
||||
|
||||
void MeshService::sendMqttMessageToClientProxy(meshtastic_MqttClientProxyMessage *m)
|
||||
{
|
||||
LOG_DEBUG("Sending mqtt message on topic '%s' to client for proxying to server\n", m->topic);
|
||||
if (toPhoneMqttProxyQueue.numFree() == 0) {
|
||||
LOG_WARN("MqttClientProxyMessagePool queue is full, discarding oldest\n");
|
||||
meshtastic_MqttClientProxyMessage *d = toPhoneMqttProxyQueue.dequeuePtr(0);
|
||||
if (d)
|
||||
releaseMqttClientProxyMessageToPool(d);
|
||||
}
|
||||
|
||||
assert(toPhoneMqttProxyQueue.enqueue(m, 0));
|
||||
fromNum++;
|
||||
}
|
||||
|
||||
meshtastic_NodeInfoLite *MeshService::refreshLocalMeshNode()
|
||||
{
|
||||
meshtastic_NodeInfoLite *node = nodeDB.getMeshNode(nodeDB.getNodeNum());
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
#endif
|
||||
|
||||
extern Allocator<meshtastic_QueueStatus> &queueStatusPool;
|
||||
extern Allocator<meshtastic_MqttClientProxyMessage> &mqttClientProxyMessagePool;
|
||||
|
||||
/**
|
||||
* Top level app for this service. keeps the mesh, the radio config and the queue of received packets.
|
||||
@@ -34,6 +35,9 @@ class MeshService
|
||||
// keep list of QueueStatus packets to be send to the phone
|
||||
PointerQueue<meshtastic_QueueStatus> toPhoneQueueStatusQueue;
|
||||
|
||||
// keep list of MqttClientProxyMessages to be send to the client for delivery
|
||||
PointerQueue<meshtastic_MqttClientProxyMessage> toPhoneMqttProxyQueue;
|
||||
|
||||
// This holds the last QueueStatus send
|
||||
meshtastic_QueueStatus lastQueueStatus;
|
||||
|
||||
@@ -67,9 +71,15 @@ class MeshService
|
||||
/// Return the next QueueStatus packet destined to the phone.
|
||||
meshtastic_QueueStatus *getQueueStatusForPhone() { return toPhoneQueueStatusQueue.dequeuePtr(0); }
|
||||
|
||||
/// Return the next MqttClientProxyMessage packet destined to the phone.
|
||||
meshtastic_MqttClientProxyMessage *getMqttClientProxyMessageForPhone() { return toPhoneMqttProxyQueue.dequeuePtr(0); }
|
||||
|
||||
// Release QueueStatus packet to pool
|
||||
void releaseQueueStatusToPool(meshtastic_QueueStatus *p) { queueStatusPool.release(p); }
|
||||
|
||||
// Release MqttClientProxyMessage packet to pool
|
||||
void releaseMqttClientProxyMessageToPool(meshtastic_MqttClientProxyMessage *p) { mqttClientProxyMessagePool.release(p); }
|
||||
|
||||
/**
|
||||
* Given a ToRadio buffer parse it and properly handle it (setup radio, owner or send packet into the mesh)
|
||||
* Called by PhoneAPI.handleToRadio. Note: p is a scratch buffer, this function is allowed to write to it but it can not keep
|
||||
@@ -103,11 +113,14 @@ class MeshService
|
||||
/// Send a packet to the phone
|
||||
void sendToPhone(meshtastic_MeshPacket *p);
|
||||
|
||||
/// Send an MQTT message to the phone for client proxying
|
||||
void sendMqttMessageToClientProxy(meshtastic_MqttClientProxyMessage *m);
|
||||
|
||||
bool isToPhoneQueueEmpty();
|
||||
|
||||
private:
|
||||
/// Called when our gps position has changed - updates nodedb and sends Location message out into the mesh
|
||||
/// returns 0 to allow futher processing
|
||||
/// returns 0 to allow further processing
|
||||
int onGPSChanged(const meshtastic::GPSStatus *arg);
|
||||
|
||||
/// Handle a packet that just arrived from the radio. This method does _ReliableRouternot_ free the provided packet. If it
|
||||
|
||||
@@ -13,7 +13,7 @@ typedef uint32_t PacketId; // A packet sequence number
|
||||
#define ERRNO_OK 0
|
||||
#define ERRNO_NO_INTERFACES 33
|
||||
#define ERRNO_UNKNOWN 32 // pick something that doesn't conflict with RH_ROUTER_ERROR_UNABLE_TO_DELIVER
|
||||
#define ERRNO_DISABLED 34 // the itnerface is disabled
|
||||
#define ERRNO_DISABLED 34 // the interface is disabled
|
||||
|
||||
/*
|
||||
* Source of a received message
|
||||
|
||||
@@ -138,7 +138,7 @@ bool NodeDB::factoryReset()
|
||||
// third, write everything to disk
|
||||
saveToDisk();
|
||||
#ifdef ARCH_ESP32
|
||||
// This will erase what's in NVS including ssl keys, persistant variables and ble pairing
|
||||
// This will erase what's in NVS including ssl keys, persistent variables and ble pairing
|
||||
nvs_flash_erase();
|
||||
#endif
|
||||
#ifdef ARCH_NRF52
|
||||
@@ -165,7 +165,8 @@ void NodeDB::installDefaultConfig()
|
||||
config.has_network = true;
|
||||
config.has_bluetooth = true;
|
||||
config.device.rebroadcast_mode = meshtastic_Config_DeviceConfig_RebroadcastMode_ALL;
|
||||
config.lora.sx126x_rx_boosted_gain = false;
|
||||
|
||||
config.lora.sx126x_rx_boosted_gain = true;
|
||||
config.lora.tx_enabled =
|
||||
true; // FIXME: maybe false in the future, and setting region to enable it. (unset region forces it off)
|
||||
config.lora.override_duty_cycle = false;
|
||||
@@ -184,7 +185,7 @@ void NodeDB::installDefaultConfig()
|
||||
// FIXME: Default to bluetooth capability of platform as default
|
||||
config.bluetooth.enabled = true;
|
||||
config.bluetooth.fixed_pin = defaultBLEPin;
|
||||
#if defined(ST7735_CS) || defined(USE_EINK) || defined(ILI9341_DRIVER)
|
||||
#if defined(ST7735_CS) || defined(USE_EINK) || defined(ILI9341_DRIVER) || defined(ST7789_CS)
|
||||
bool hasScreen = true;
|
||||
#else
|
||||
bool hasScreen = screen_found.port != ScanI2C::I2CPort::NO_I2C;
|
||||
@@ -195,6 +196,11 @@ void NodeDB::installDefaultConfig()
|
||||
config.position.position_flags =
|
||||
(meshtastic_Config_PositionConfig_PositionFlags_ALTITUDE | meshtastic_Config_PositionConfig_PositionFlags_ALTITUDE_MSL);
|
||||
|
||||
#ifdef T_WATCH_S3
|
||||
config.display.screen_on_secs = 30;
|
||||
config.display.wake_on_tap_or_motion = true;
|
||||
#endif
|
||||
|
||||
initConfigIntervals();
|
||||
}
|
||||
|
||||
@@ -233,6 +239,10 @@ void NodeDB::installDefaultModuleConfig()
|
||||
moduleConfig.external_notification.alert_message = true;
|
||||
moduleConfig.external_notification.output_ms = 1000;
|
||||
moduleConfig.external_notification.nag_timeout = 60;
|
||||
#endif
|
||||
#ifdef T_WATCH_S3
|
||||
// Don't worry about the other settings, we'll use the DRV2056 behavior for notifications
|
||||
moduleConfig.external_notification.enabled = true;
|
||||
#endif
|
||||
moduleConfig.has_canned_message = true;
|
||||
|
||||
@@ -911,7 +921,7 @@ void recordCriticalError(meshtastic_CriticalErrorCode code, uint32_t address, co
|
||||
error_code = code;
|
||||
error_address = address;
|
||||
|
||||
// Currently portuino is mostly used for simulation. Make sue the user notices something really bad happend
|
||||
// Currently portuino is mostly used for simulation. Make sure the user notices something really bad happened
|
||||
#ifdef ARCH_PORTDUINO
|
||||
LOG_ERROR("A critical failure occurred, portduino is exiting...");
|
||||
exit(2);
|
||||
|
||||
@@ -56,7 +56,7 @@ class NodeDB
|
||||
meshtastic_NodeInfoLite *updateGUIforNode = NULL; // if currently showing this node, we think you should update the GUI
|
||||
Observable<const meshtastic::NodeStatus *> newStatus;
|
||||
|
||||
/// don't do mesh based algoritm for node id assignment (initially)
|
||||
/// don't do mesh based algorithm for node id assignment (initially)
|
||||
/// instead just store in flash - possibly even in the initial alpha release do this hack
|
||||
NodeDB();
|
||||
|
||||
|
||||
@@ -18,6 +18,8 @@
|
||||
#error ToRadio is too big
|
||||
#endif
|
||||
|
||||
#include "mqtt/MQTT.h"
|
||||
|
||||
PhoneAPI::PhoneAPI()
|
||||
{
|
||||
lastContactMsec = millis();
|
||||
@@ -54,6 +56,7 @@ void PhoneAPI::close()
|
||||
unobserve(&xModem.packetReady);
|
||||
releasePhonePacket(); // Don't leak phone packets on shutdown
|
||||
releaseQueueStatusPhonePacket();
|
||||
releaseMqttClientProxyPhonePacket();
|
||||
|
||||
onConnectionChanged(false);
|
||||
}
|
||||
@@ -98,6 +101,12 @@ bool PhoneAPI::handleToRadio(const uint8_t *buf, size_t bufLength)
|
||||
LOG_INFO("Got xmodem packet\n");
|
||||
xModem.handlePacket(toRadioScratch.xmodemPacket);
|
||||
break;
|
||||
case meshtastic_ToRadio_mqttClientProxyMessage_tag:
|
||||
LOG_INFO("Got MqttClientProxy message\n");
|
||||
if (mqtt && moduleConfig.mqtt.proxy_to_client_enabled) {
|
||||
mqtt->onClientProxyReceive(toRadioScratch.mqttClientProxyMessage);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
// Ignore nop messages
|
||||
// LOG_DEBUG("Error: unexpected ToRadio variant\n");
|
||||
@@ -295,12 +304,16 @@ size_t PhoneAPI::getFromRadio(uint8_t *buf)
|
||||
break;
|
||||
|
||||
case STATE_SEND_PACKETS:
|
||||
// Do we have a message from the mesh?
|
||||
// Do we have a message from the mesh or packet from the local device?
|
||||
LOG_INFO("getFromRadio=STATE_SEND_PACKETS\n");
|
||||
if (queueStatusPacketForPhone) {
|
||||
fromRadioScratch.which_payload_variant = meshtastic_FromRadio_queueStatus_tag;
|
||||
fromRadioScratch.queueStatus = *queueStatusPacketForPhone;
|
||||
releaseQueueStatusPhonePacket();
|
||||
} else if (mqttClientProxyMessageForPhone) {
|
||||
fromRadioScratch.which_payload_variant = meshtastic_FromRadio_mqttClientProxyMessage_tag;
|
||||
fromRadioScratch.mqttClientProxyMessage = *mqttClientProxyMessageForPhone;
|
||||
releaseMqttClientProxyPhonePacket();
|
||||
} else if (xmodemPacketForPhone.control != meshtastic_XModem_Control_NUL) {
|
||||
fromRadioScratch.which_payload_variant = meshtastic_FromRadio_xmodemPacket_tag;
|
||||
fromRadioScratch.xmodemPacket = xmodemPacketForPhone;
|
||||
@@ -353,6 +366,14 @@ void PhoneAPI::releaseQueueStatusPhonePacket()
|
||||
}
|
||||
}
|
||||
|
||||
void PhoneAPI::releaseMqttClientProxyPhonePacket()
|
||||
{
|
||||
if (mqttClientProxyMessageForPhone) {
|
||||
service.releaseMqttClientProxyMessageToPool(mqttClientProxyMessageForPhone);
|
||||
mqttClientProxyMessageForPhone = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if we have data available to send to the phone
|
||||
*/
|
||||
@@ -381,7 +402,9 @@ bool PhoneAPI::available()
|
||||
case STATE_SEND_PACKETS: {
|
||||
if (!queueStatusPacketForPhone)
|
||||
queueStatusPacketForPhone = service.getQueueStatusForPhone();
|
||||
bool hasPacket = !!queueStatusPacketForPhone;
|
||||
if (!mqttClientProxyMessageForPhone)
|
||||
mqttClientProxyMessageForPhone = service.getMqttClientProxyMessageForPhone();
|
||||
bool hasPacket = !!queueStatusPacketForPhone || !!mqttClientProxyMessageForPhone;
|
||||
if (hasPacket)
|
||||
return true;
|
||||
|
||||
|
||||
@@ -50,6 +50,9 @@ class PhoneAPI
|
||||
// Keep QueueStatus packet just as packetForPhone
|
||||
meshtastic_QueueStatus *queueStatusPacketForPhone = NULL;
|
||||
|
||||
// Keep MqttClientProxyMessage packet just as packetForPhone
|
||||
meshtastic_MqttClientProxyMessage *mqttClientProxyMessageForPhone = NULL;
|
||||
|
||||
/// We temporarily keep the nodeInfo here between the call to available and getFromRadio
|
||||
meshtastic_NodeInfo nodeInfoForPhone = meshtastic_NodeInfo_init_default;
|
||||
|
||||
@@ -126,6 +129,8 @@ class PhoneAPI
|
||||
|
||||
void releaseQueueStatusPhonePacket();
|
||||
|
||||
void releaseMqttClientProxyPhonePacket();
|
||||
|
||||
/// begin a new connection
|
||||
void handleStartConfig();
|
||||
|
||||
|
||||
@@ -192,7 +192,7 @@ bool RF95Interface::isChannelActive()
|
||||
return false;
|
||||
}
|
||||
|
||||
/** Could we send right now (i.e. either not actively receving or transmitting)? */
|
||||
/** Could we send right now (i.e. either not actively receiving or transmitting)? */
|
||||
bool RF95Interface::isActivelyReceiving()
|
||||
{
|
||||
return lora->isReceiving();
|
||||
@@ -201,7 +201,7 @@ bool RF95Interface::isActivelyReceiving()
|
||||
bool RF95Interface::sleep()
|
||||
{
|
||||
// put chipset into sleep mode
|
||||
setStandby(); // First cancel any active receving/sending
|
||||
setStandby(); // First cancel any active receiving/sending
|
||||
lora->sleep();
|
||||
|
||||
return true;
|
||||
|
||||
@@ -196,8 +196,9 @@ uint32_t RadioInterface::getRetransmissionMsec(const meshtastic_MeshPacket *p)
|
||||
// LOG_DEBUG("Waiting for flooding message with airtime %d and slotTime is %d\n", packetAirtime, slotTimeMsec);
|
||||
float channelUtil = airTime->channelUtilizationPercent();
|
||||
uint8_t CWsize = map(channelUtil, 0, 100, CWmin, CWmax);
|
||||
// Assuming we pick max. of CWsize and there will be a receiver with SNR at half the range
|
||||
return 2 * packetAirtime + (pow(2, CWsize) + pow(2, int((CWmax + CWmin) / 2))) * slotTimeMsec + PROCESSING_TIME_MSEC;
|
||||
// Assuming we pick max. of CWsize and there will be a client with SNR at half the range
|
||||
return 2 * packetAirtime + (pow(2, CWsize) + 2 * CWmax + pow(2, int((CWmax + CWmin) / 2))) * slotTimeMsec +
|
||||
PROCESSING_TIME_MSEC;
|
||||
}
|
||||
|
||||
/** The delay to use when we want to send something */
|
||||
@@ -307,7 +308,7 @@ bool RadioInterface::init()
|
||||
preflightSleepObserver.observe(&preflightSleep);
|
||||
notifyDeepSleepObserver.observe(¬ifyDeepSleep);
|
||||
|
||||
// we now expect interfaces to operate in promiscous mode
|
||||
// we now expect interfaces to operate in promiscuous mode
|
||||
// radioIf.setThisAddress(nodeDB.getNodeNum()); // Note: we must do this here, because the nodenum isn't inited at constructor
|
||||
// time.
|
||||
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
|
||||
/**
|
||||
* This structure has to exactly match the wire layout when sent over the radio link. Used to keep compatibility
|
||||
* wtih the old radiohead implementation.
|
||||
* with the old radiohead implementation.
|
||||
*/
|
||||
typedef struct {
|
||||
NodeNum to, from; // can be 1 byte or four bytes
|
||||
@@ -75,7 +75,7 @@ class RadioInterface
|
||||
uint32_t lastTxStart = 0L;
|
||||
|
||||
/**
|
||||
* A temporary buffer used for sending/receving packets, sized to hold the biggest buffer we might need
|
||||
* A temporary buffer used for sending/receiving packets, sized to hold the biggest buffer we might need
|
||||
* */
|
||||
uint8_t radiobuf[MAX_RHPACKETLEN];
|
||||
|
||||
@@ -198,7 +198,7 @@ class RadioInterface
|
||||
virtual void saveFreq(float savedFreq);
|
||||
|
||||
/**
|
||||
* Save the chanel we selected for later reuse.
|
||||
* Save the channel we selected for later reuse.
|
||||
*/
|
||||
virtual void saveChannelNum(uint32_t savedChannelNum);
|
||||
|
||||
@@ -206,7 +206,7 @@ class RadioInterface
|
||||
/**
|
||||
* Convert our modemConfig enum into wf, sf, etc...
|
||||
*
|
||||
* These paramaters will be pull from the channelSettings global
|
||||
* These parameters will be pull from the channelSettings global
|
||||
*/
|
||||
void applyModemConfig();
|
||||
|
||||
|
||||
@@ -68,7 +68,7 @@ void INTERRUPT_ATTR RadioLibInterface::isrTxLevel0()
|
||||
*/
|
||||
RadioLibInterface *RadioLibInterface::instance;
|
||||
|
||||
/** Could we send right now (i.e. either not actively receving or transmitting)? */
|
||||
/** Could we send right now (i.e. either not actively receiving or transmitting)? */
|
||||
bool RadioLibInterface::canSendImmediately()
|
||||
{
|
||||
// We wait _if_ we are partially though receiving a packet (rather than just merely waiting for one).
|
||||
|
||||
@@ -12,9 +12,7 @@ extern "C" {
|
||||
#include "mesh/compression/unishox2.h"
|
||||
}
|
||||
|
||||
#if HAS_WIFI || HAS_ETHERNET
|
||||
#include "mqtt/MQTT.h"
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Router todo
|
||||
@@ -248,7 +246,6 @@ ErrorCode Router::send(meshtastic_MeshPacket *p)
|
||||
|
||||
bool shouldActuallyEncrypt = true;
|
||||
|
||||
#if HAS_WIFI || HAS_ETHERNET
|
||||
if (moduleConfig.mqtt.enabled) {
|
||||
// check if we should send decrypted packets to mqtt
|
||||
|
||||
@@ -272,7 +269,6 @@ ErrorCode Router::send(meshtastic_MeshPacket *p)
|
||||
if (mqtt && !shouldActuallyEncrypt)
|
||||
mqtt->onSend(*p, chIndex);
|
||||
}
|
||||
#endif
|
||||
|
||||
auto encodeResult = perhapsEncode(p);
|
||||
if (encodeResult != meshtastic_Routing_Error_NONE) {
|
||||
@@ -280,14 +276,12 @@ ErrorCode Router::send(meshtastic_MeshPacket *p)
|
||||
return encodeResult; // FIXME - this isn't a valid ErrorCode
|
||||
}
|
||||
|
||||
#if HAS_WIFI || HAS_ETHERNET
|
||||
if (moduleConfig.mqtt.enabled) {
|
||||
// the packet is now encrypted.
|
||||
// check if we should send encrypted packets to mqtt
|
||||
if (mqtt && shouldActuallyEncrypt)
|
||||
mqtt->onSend(*p, chIndex);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
assert(iface); // This should have been detected already in sendLocal (or we just received a packet from outside)
|
||||
@@ -405,7 +399,7 @@ meshtastic_Routing_Error perhapsEncode(meshtastic_MeshPacket *p)
|
||||
if (compressed_len >= p->decoded.payload.size) {
|
||||
|
||||
LOG_DEBUG("Not using compressing message.\n");
|
||||
// Set the uncompressed payload varient anyway. Shouldn't hurt?
|
||||
// Set the uncompressed payload variant anyway. Shouldn't hurt?
|
||||
// p->decoded.which_payloadVariant = Data_payload_tag;
|
||||
|
||||
// Otherwise we use the compressor
|
||||
|
||||
@@ -90,7 +90,7 @@ class Router : protected concurrency::OSThread
|
||||
*
|
||||
* FIXME, move this into the new RoutingModule and do the filtering there using the regular module logic
|
||||
*
|
||||
* Called immedately on receiption, before any further processing.
|
||||
* Called immediately on reception, before any further processing.
|
||||
* @return true to abandon the packet
|
||||
*/
|
||||
virtual bool shouldFilterReceived(const meshtastic_MeshPacket *p) { return false; }
|
||||
|
||||
@@ -70,12 +70,25 @@ template <typename T> bool SX126xInterface<T>::init()
|
||||
#endif
|
||||
|
||||
#if defined(SX126X_TXEN) && (SX126X_TXEN != RADIOLIB_NC)
|
||||
// lora.begin sets Dio2 as RF switch control, which is not true if we are manually controlling RX and TX
|
||||
// If SX126X_TXEN is connected to the MCU, we are manually controlling RX and TX.
|
||||
// But lora.begin (called above) sets Dio2 as RF switch control, which is not true here, so set it back to false.
|
||||
if (res == RADIOLIB_ERR_NONE) {
|
||||
LOG_DEBUG("SX126X_TX/RX EN pins defined. Setting RF Switch: RXEN=%i, TXEN=%i\n", SX126X_RXEN, SX126X_TXEN);
|
||||
LOG_DEBUG("SX126X_TXEN pin defined. Setting RF Switch: RXEN=%i, TXEN=%i\n", SX126X_RXEN, SX126X_TXEN);
|
||||
res = lora.setDio2AsRfSwitch(false);
|
||||
lora.setRfSwitchPins(SX126X_RXEN, SX126X_TXEN);
|
||||
}
|
||||
#elif defined(SX126X_RXEN) && (SX126X_RXEN != RADIOLIB_NC && defined(E22_TXEN_CONNECTED_TO_DIO2))
|
||||
// Otherwise, if SX126X_RXEN is connected to the MCU, and E22_TXEN_CONNECTED_TO_DIO2 is defined, we are letting the
|
||||
// E22 control RX and TX via DIO2. In this configuration, the E22's TXEN and DIO2 pins are connected to each other,
|
||||
// but not to the MCU.
|
||||
// However, we must still connect the E22's RXEN pin to the MCU, define SX126X_RXEN accordingly, and then call
|
||||
// setRfSwitchPins, otherwise RX sensitivity (observed via RSSI) is greatly diminished.
|
||||
LOG_DEBUG("SX126X_RXEN and E22_TXEN_CONNECTED_TO_DIO2 are defined; value of res: %d", res);
|
||||
if (res == RADIOLIB_ERR_NONE) {
|
||||
LOG_DEBUG("SX126X_TXEN is RADIOLIB_NC, but SX126X_RXEN and E22_TXEN_CONNECTED_TO_DIO2 are both defined; calling "
|
||||
"lora.setRfSwitchPins.");
|
||||
lora.setRfSwitchPins(SX126X_RXEN, SX126X_TXEN);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (config.lora.sx126x_rx_boosted_gain) {
|
||||
@@ -249,7 +262,7 @@ template <typename T> bool SX126xInterface<T>::isChannelActive()
|
||||
return false;
|
||||
}
|
||||
|
||||
/** Could we send right now (i.e. either not actively receving or transmitting)? */
|
||||
/** Could we send right now (i.e. either not actively receiving or transmitting)? */
|
||||
template <typename T> bool SX126xInterface<T>::isActivelyReceiving()
|
||||
{
|
||||
// The IRQ status will be cleared when we start our read operation. Check if we've started a header, but haven't yet
|
||||
|
||||
@@ -242,7 +242,7 @@ template <typename T> bool SX128xInterface<T>::isChannelActive()
|
||||
return false;
|
||||
}
|
||||
|
||||
/** Could we send right now (i.e. either not actively receving or transmitting)? */
|
||||
/** Could we send right now (i.e. either not actively receiving or transmitting)? */
|
||||
template <typename T> bool SX128xInterface<T>::isActivelyReceiving()
|
||||
{
|
||||
uint16_t irq = lora.getIrqStatus();
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
#include "Router.h"
|
||||
|
||||
/**
|
||||
* Most modules are only interested in sending/receving one particular portnum. This baseclass simplifies that common
|
||||
* Most modules are only interested in sending/receiving one particular portnum. This baseclass simplifies that common
|
||||
* case.
|
||||
*/
|
||||
class SinglePortModule : public MeshModule
|
||||
|
||||
@@ -57,7 +57,7 @@ uint8_t usx_code_94[94];
|
||||
uint8_t usx_vcodes[] = {0x00, 0x40, 0x60, 0x80, 0x90, 0xA0, 0xB0, 0xC0, 0xD0, 0xD8, 0xE0, 0xE4, 0xE8, 0xEC,
|
||||
0xEE, 0xF0, 0xF2, 0xF4, 0xF6, 0xF7, 0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF};
|
||||
|
||||
/// Length of each veritical code
|
||||
/// Length of each vertical code
|
||||
uint8_t usx_vcode_lens[] = {2, 3, 3, 4, 4, 4, 4, 4, 5, 5, 6, 6, 6, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8};
|
||||
|
||||
/// Vertical Codes and Set number for frequent sequences in sets USX_SYM and USX_NUM. First 3 bits indicate set (USX_SYM/USX_NUM)
|
||||
@@ -188,7 +188,7 @@ int append_switch_code(char *out, int olen, int ol, uint8_t state)
|
||||
return ol;
|
||||
}
|
||||
|
||||
/// Appends given horizontal and veritical code bits to out
|
||||
/// Appends given horizontal and vertical code bits to out
|
||||
int append_code(char *out, int olen, int ol, uint8_t code, uint8_t *state, const uint8_t usx_hcodes[],
|
||||
const uint8_t usx_hcode_lens[])
|
||||
{
|
||||
@@ -888,7 +888,7 @@ int read8bitCode(const char *in, int len, int bit_no)
|
||||
return code;
|
||||
}
|
||||
|
||||
/// The list of veritical codes is split into 5 sections. Used by readVCodeIdx()
|
||||
/// The list of vertical codes is split into 5 sections. Used by readVCodeIdx()
|
||||
#define SECTION_COUNT 5
|
||||
/// Used by readVCodeIdx() for finding the section under which the code read using read8bitCode() falls
|
||||
uint8_t usx_vsections[] = {0x7F, 0xBF, 0xDF, 0xEF, 0xFF};
|
||||
@@ -915,7 +915,7 @@ uint8_t usx_vcode_lookup[36] = {(1 << 5) + 0, (1 << 5) + 0, (2 << 5) + 1, (2
|
||||
/// compared to using a 256 uint8_t buffer to decode the next 8 bits read by read8bitCode() \n
|
||||
/// by splitting the list of vertical codes. \n
|
||||
/// Decoder is designed for using less memory, not speed. \n
|
||||
/// Returns the veritical code index or 99 if match could not be found. \n
|
||||
/// Returns the vertical code index or 99 if match could not be found. \n
|
||||
/// Also updates bit_no_p with how many ever bits used by the vertical code.
|
||||
int readVCodeIdx(const char *in, int len, int *bit_no_p)
|
||||
{
|
||||
|
||||
@@ -198,45 +198,45 @@
|
||||
2, 2, 2, 2, 0 \
|
||||
}
|
||||
|
||||
/// Default frequently occuring sequences. When composition of text is know beforehand, the other sequences in this section can be
|
||||
/// used to achieve more compression.
|
||||
/// Default frequently occurring sequences. When composition of text is know beforehand, the other sequences in this section can
|
||||
/// be used to achieve more compression.
|
||||
#define USX_FREQ_SEQ_DFLT \
|
||||
(const char *[]) \
|
||||
{ \
|
||||
"\": \"", "\": ", "</", "=\"", "\":\"", "://" \
|
||||
}
|
||||
/// Frequently occuring sequences in text content
|
||||
/// Frequently occurring sequences in text content
|
||||
#define USX_FREQ_SEQ_TXT \
|
||||
(const char *[]) \
|
||||
{ \
|
||||
" the ", " and ", "tion", " with", "ing", "ment" \
|
||||
}
|
||||
/// Frequently occuring sequences in URL content
|
||||
/// Frequently occurring sequences in URL content
|
||||
#define USX_FREQ_SEQ_URL \
|
||||
(const char *[]) \
|
||||
{ \
|
||||
"https://", "www.", ".com", "http://", ".org", ".net" \
|
||||
}
|
||||
/// Frequently occuring sequences in JSON content
|
||||
/// Frequently occurring sequences in JSON content
|
||||
#define USX_FREQ_SEQ_JSON \
|
||||
(const char *[]) \
|
||||
{ \
|
||||
"\": \"", "\": ", "\",", "}}}", "\":\"", "}}" \
|
||||
}
|
||||
/// Frequently occuring sequences in HTML content
|
||||
/// Frequently occurring sequences in HTML content
|
||||
#define USX_FREQ_SEQ_HTML \
|
||||
(const char *[]) \
|
||||
{ \
|
||||
"</", "=\"", "div", "href", "class", "<p>" \
|
||||
}
|
||||
/// Frequently occuring sequences in XML content
|
||||
/// Frequently occurring sequences in XML content
|
||||
#define USX_FREQ_SEQ_XML \
|
||||
(const char *[]) \
|
||||
{ \
|
||||
"</", "=\"", "\">", "<?xml version=\"1.0\"", "xmlns:", "://" \
|
||||
}
|
||||
|
||||
/// Commonly occuring templates (ISO Date/Time, ISO Date, US Phone number, ISO Time, Unused)
|
||||
/// Commonly occurring templates (ISO Date/Time, ISO Date, US Phone number, ISO Time, Unused)
|
||||
#define USX_TEMPLATES \
|
||||
(const char *[]) \
|
||||
{ \
|
||||
@@ -333,8 +333,8 @@ extern int unishox2_decompress_simple(const char *in, int len, char *out);
|
||||
* @param[in] olen length of 'out' buffer in bytes. Can be omitted if sufficient buffer is provided
|
||||
* @param[in] usx_hcodes Horizontal codes (array of bytes). See macro section for samples.
|
||||
* @param[in] usx_hcode_lens Length of each element in usx_hcodes array
|
||||
* @param[in] usx_freq_seq Frequently occuring sequences. See USX_FREQ_SEQ_* macros for samples
|
||||
* @param[in] usx_templates Templates of frequently occuring patterns. See USX_TEMPLATES macro.
|
||||
* @param[in] usx_freq_seq Frequently occurring sequences. See USX_FREQ_SEQ_* macros for samples
|
||||
* @param[in] usx_templates Templates of frequently occurring patterns. See USX_TEMPLATES macro.
|
||||
*/
|
||||
extern int unishox2_compress(const char *in, int len, UNISHOX_API_OUT_AND_LEN(char *out, int olen),
|
||||
const unsigned char usx_hcodes[], const unsigned char usx_hcode_lens[], const char *usx_freq_seq[],
|
||||
@@ -352,8 +352,8 @@ extern int unishox2_compress(const char *in, int len, UNISHOX_API_OUT_AND_LEN(ch
|
||||
* @param[in] olen length of 'out' buffer in bytes. Can be omitted if sufficient buffer is provided
|
||||
* @param[in] usx_hcodes Horizontal codes (array of bytes). See macro section for samples.
|
||||
* @param[in] usx_hcode_lens Length of each element in usx_hcodes array
|
||||
* @param[in] usx_freq_seq Frequently occuring sequences. See USX_FREQ_SEQ_* macros for samples
|
||||
* @param[in] usx_templates Templates of frequently occuring patterns. See USX_TEMPLATES macro.
|
||||
* @param[in] usx_freq_seq Frequently occurring sequences. See USX_FREQ_SEQ_* macros for samples
|
||||
* @param[in] usx_templates Templates of frequently occurring patterns. See USX_TEMPLATES macro.
|
||||
*/
|
||||
extern int unishox2_decompress(const char *in, int len, UNISHOX_API_OUT_AND_LEN(char *out, int olen),
|
||||
const unsigned char usx_hcodes[], const unsigned char usx_hcode_lens[], const char *usx_freq_seq[],
|
||||
@@ -373,7 +373,7 @@ extern int unishox2_compress_lines(const char *in, int len, UNISHOX_API_OUT_AND_
|
||||
const char *usx_freq_seq[], const char *usx_templates[], struct us_lnk_lst *prev_lines);
|
||||
/**
|
||||
* More Comprehensive API for de-compressing array of strings \n
|
||||
* This function is not be used in conjuction with unishox2_compress_lines()
|
||||
* This function is not be used in conjunction with unishox2_compress_lines()
|
||||
*
|
||||
* See unishox2_decompress() function for parameter definitions. \n
|
||||
* Typically an array is compressed using unishox2_compress_lines() and \n
|
||||
|
||||
@@ -68,7 +68,7 @@ static int32_t reconnectETH()
|
||||
}
|
||||
|
||||
// FIXME this is kinda yucky, instead we should just have an observable for 'wifireconnected'
|
||||
if (mqtt && !mqtt->connected()) {
|
||||
if (mqtt && !moduleConfig.mqtt.proxy_to_client_enabled && !mqtt->isConnectedDirectly()) {
|
||||
mqtt->reconnect();
|
||||
}
|
||||
}
|
||||
@@ -87,7 +87,6 @@ static int32_t reconnectETH()
|
||||
perhapsSetRTC(RTCQualityNTP, &tv);
|
||||
|
||||
ntp_renew = millis() + 43200 * 1000; // success, refresh every 12 hours
|
||||
|
||||
} else {
|
||||
LOG_ERROR("NTP Update failed\n");
|
||||
ntp_renew = millis() + 300 * 1000; // failure, retry every 5 minutes
|
||||
@@ -170,7 +169,6 @@ bool initEthernet()
|
||||
ethEvent = new Periodic("ethConnect", reconnectETH);
|
||||
|
||||
return true;
|
||||
|
||||
} else {
|
||||
LOG_INFO("Not using Ethernet\n");
|
||||
return false;
|
||||
|
||||
@@ -323,7 +323,7 @@ extern const pb_msgdesc_t meshtastic_NodeRemoteHardwarePin_msg;
|
||||
#define meshtastic_DeviceState_size 35056
|
||||
#define meshtastic_NodeInfoLite_size 151
|
||||
#define meshtastic_NodeRemoteHardwarePin_size 29
|
||||
#define meshtastic_OEMStore_size 3152
|
||||
#define meshtastic_OEMStore_size 3154
|
||||
#define meshtastic_PositionLite_size 28
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
@@ -163,7 +163,7 @@ extern const pb_msgdesc_t meshtastic_LocalModuleConfig_msg;
|
||||
|
||||
/* Maximum encoded size of messages (where known) */
|
||||
#define meshtastic_LocalConfig_size 461
|
||||
#define meshtastic_LocalModuleConfig_size 545
|
||||
#define meshtastic_LocalModuleConfig_size 547
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
|
||||
@@ -24,6 +24,9 @@ PB_BIND(meshtastic_Data, meshtastic_Data, 2)
|
||||
PB_BIND(meshtastic_Waypoint, meshtastic_Waypoint, AUTO)
|
||||
|
||||
|
||||
PB_BIND(meshtastic_MqttClientProxyMessage, meshtastic_MqttClientProxyMessage, 2)
|
||||
|
||||
|
||||
PB_BIND(meshtastic_MeshPacket, meshtastic_MeshPacket, 2)
|
||||
|
||||
|
||||
|
||||
@@ -59,6 +59,8 @@ typedef enum _meshtastic_HardwareModel {
|
||||
meshtastic_HardwareModel_TLORA_T3_S3 = 16,
|
||||
/* B&Q Consulting Nano G1 Explorer: https://wiki.uniteng.com/en/meshtastic/nano-g1-explorer */
|
||||
meshtastic_HardwareModel_NANO_G1_EXPLORER = 17,
|
||||
/* B&Q Consulting Nano G2 Ultra: https://wiki.uniteng.com/en/meshtastic/nano-g2-ultra */
|
||||
meshtastic_HardwareModel_NANO_G2_ULTRA = 18,
|
||||
/* B&Q Consulting Station Edition G1: https://uniteng.com/wiki/doku.php?id=meshtastic:station */
|
||||
meshtastic_HardwareModel_STATION_G1 = 25,
|
||||
/* RAK11310 (RP2040 + SX1262) */
|
||||
@@ -97,6 +99,14 @@ typedef enum _meshtastic_HardwareModel {
|
||||
meshtastic_HardwareModel_BETAFPV_900_NANO_TX = 46,
|
||||
/* Raspberry Pi Pico (W) with Waveshare SX1262 LoRa Node Module */
|
||||
meshtastic_HardwareModel_RPI_PICO = 47,
|
||||
/* Heltec Wireless Tracker with ESP32-S3 CPU, built-in GPS, and TFT */
|
||||
meshtastic_HardwareModel_HELTEC_WIRELESS_TRACKER = 48,
|
||||
/* Heltec Wireless Paper with ESP32-S3 CPU and E-Ink display */
|
||||
meshtastic_HardwareModel_HELTEC_WIRELESS_PAPER = 49,
|
||||
/* LilyGo T-Deck with ESP32-S3 CPU, Keyboard, and IPS display */
|
||||
meshtastic_HardwareModel_T_DECK = 50,
|
||||
/* LilyGo T-Watch S3 with ESP32-S3 CPU and IPS display */
|
||||
meshtastic_HardwareModel_T_WATCH_S3 = 51,
|
||||
/* ------------------------------------------------------------------------------------------------------------------------------------------
|
||||
Reserved ID For developing private Ports. These will show up in live traffic sparsely, so we can use a high number. Keep it within 8 bits.
|
||||
------------------------------------------------------------------------------------------------------------------------------------------ */
|
||||
@@ -220,9 +230,9 @@ typedef enum _meshtastic_Routing_Error {
|
||||
to make sure that critical packets are sent ASAP.
|
||||
In the case of meshtastic that means we want to send protocol acks as soon as possible
|
||||
(to prevent unneeded retransmissions), we want routing messages to be sent next,
|
||||
then messages marked as reliable and finally ‘background’ packets like periodic position updates.
|
||||
then messages marked as reliable and finally 'background' packets like periodic position updates.
|
||||
So I bit the bullet and implemented a new (internal - not sent over the air)
|
||||
field in MeshPacket called ‘priority’.
|
||||
field in MeshPacket called 'priority'.
|
||||
And the transmission queue in the router object is now a priority queue. */
|
||||
typedef enum _meshtastic_MeshPacket_Priority {
|
||||
/* Treated as Priority.DEFAULT */
|
||||
@@ -462,6 +472,22 @@ typedef struct _meshtastic_Waypoint {
|
||||
uint32_t icon;
|
||||
} meshtastic_Waypoint;
|
||||
|
||||
typedef PB_BYTES_ARRAY_T(435) meshtastic_MqttClientProxyMessage_data_t;
|
||||
/* This message will be proxied over the PhoneAPI for the client to deliver to the MQTT server */
|
||||
typedef struct _meshtastic_MqttClientProxyMessage {
|
||||
/* The MQTT topic this message will be sent /received on */
|
||||
char topic[60];
|
||||
pb_size_t which_payload_variant;
|
||||
union {
|
||||
/* Bytes */
|
||||
meshtastic_MqttClientProxyMessage_data_t data;
|
||||
/* Text */
|
||||
char text[435];
|
||||
} payload_variant;
|
||||
/* Whether the message should be retained (or not) */
|
||||
bool retained;
|
||||
} meshtastic_MqttClientProxyMessage;
|
||||
|
||||
typedef PB_BYTES_ARRAY_T(256) meshtastic_MeshPacket_encrypted_t;
|
||||
/* A packet envelope sent/received over the mesh
|
||||
only payload_variant is sent in the payload portion of the LORA packet.
|
||||
@@ -683,6 +709,8 @@ typedef struct _meshtastic_ToRadio {
|
||||
(Sending this message is optional for clients) */
|
||||
bool disconnect;
|
||||
meshtastic_XModem xmodemPacket;
|
||||
/* MQTT Client Proxy Message (for client / phone subscribed to MQTT sending to device) */
|
||||
meshtastic_MqttClientProxyMessage mqttClientProxyMessage;
|
||||
};
|
||||
} meshtastic_ToRadio;
|
||||
|
||||
@@ -780,6 +808,8 @@ typedef struct _meshtastic_FromRadio {
|
||||
meshtastic_XModem xmodemPacket;
|
||||
/* Device metadata message */
|
||||
meshtastic_DeviceMetadata metadata;
|
||||
/* MQTT Client Proxy Message (device sending to client / phone for publishing to MQTT) */
|
||||
meshtastic_MqttClientProxyMessage mqttClientProxyMessage;
|
||||
};
|
||||
} meshtastic_FromRadio;
|
||||
|
||||
@@ -836,6 +866,7 @@ extern "C" {
|
||||
#define meshtastic_Data_portnum_ENUMTYPE meshtastic_PortNum
|
||||
|
||||
|
||||
|
||||
#define meshtastic_MeshPacket_priority_ENUMTYPE meshtastic_MeshPacket_Priority
|
||||
#define meshtastic_MeshPacket_delayed_ENUMTYPE meshtastic_MeshPacket_Delayed
|
||||
|
||||
@@ -862,6 +893,7 @@ extern "C" {
|
||||
#define meshtastic_Routing_init_default {0, {meshtastic_RouteDiscovery_init_default}}
|
||||
#define meshtastic_Data_init_default {_meshtastic_PortNum_MIN, {0, {0}}, 0, 0, 0, 0, 0, 0}
|
||||
#define meshtastic_Waypoint_init_default {0, 0, 0, 0, 0, "", "", 0}
|
||||
#define meshtastic_MqttClientProxyMessage_init_default {"", 0, {{0, {0}}}, 0}
|
||||
#define meshtastic_MeshPacket_init_default {0, 0, 0, 0, {meshtastic_Data_init_default}, 0, 0, 0, 0, 0, _meshtastic_MeshPacket_Priority_MIN, 0, _meshtastic_MeshPacket_Delayed_MIN}
|
||||
#define meshtastic_NodeInfo_init_default {0, false, meshtastic_User_init_default, false, meshtastic_Position_init_default, 0, 0, false, meshtastic_DeviceMetrics_init_default, 0}
|
||||
#define meshtastic_MyNodeInfo_init_default {0, 0, 0, "", _meshtastic_CriticalErrorCode_MIN, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0, 0, 0, 0, 0, 0}, 0, {0, 0, 0, 0, 0, 0, 0, 0}, 0, 0, 0}
|
||||
@@ -879,6 +911,7 @@ extern "C" {
|
||||
#define meshtastic_Routing_init_zero {0, {meshtastic_RouteDiscovery_init_zero}}
|
||||
#define meshtastic_Data_init_zero {_meshtastic_PortNum_MIN, {0, {0}}, 0, 0, 0, 0, 0, 0}
|
||||
#define meshtastic_Waypoint_init_zero {0, 0, 0, 0, 0, "", "", 0}
|
||||
#define meshtastic_MqttClientProxyMessage_init_zero {"", 0, {{0, {0}}}, 0}
|
||||
#define meshtastic_MeshPacket_init_zero {0, 0, 0, 0, {meshtastic_Data_init_zero}, 0, 0, 0, 0, 0, _meshtastic_MeshPacket_Priority_MIN, 0, _meshtastic_MeshPacket_Delayed_MIN}
|
||||
#define meshtastic_NodeInfo_init_zero {0, false, meshtastic_User_init_zero, false, meshtastic_Position_init_zero, 0, 0, false, meshtastic_DeviceMetrics_init_zero, 0}
|
||||
#define meshtastic_MyNodeInfo_init_zero {0, 0, 0, "", _meshtastic_CriticalErrorCode_MIN, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0, 0, 0, 0, 0, 0}, 0, {0, 0, 0, 0, 0, 0, 0, 0}, 0, 0, 0}
|
||||
@@ -940,6 +973,10 @@ extern "C" {
|
||||
#define meshtastic_Waypoint_name_tag 6
|
||||
#define meshtastic_Waypoint_description_tag 7
|
||||
#define meshtastic_Waypoint_icon_tag 8
|
||||
#define meshtastic_MqttClientProxyMessage_topic_tag 1
|
||||
#define meshtastic_MqttClientProxyMessage_data_tag 2
|
||||
#define meshtastic_MqttClientProxyMessage_text_tag 3
|
||||
#define meshtastic_MqttClientProxyMessage_retained_tag 4
|
||||
#define meshtastic_MeshPacket_from_tag 1
|
||||
#define meshtastic_MeshPacket_to_tag 2
|
||||
#define meshtastic_MeshPacket_channel_tag 3
|
||||
@@ -988,6 +1025,7 @@ extern "C" {
|
||||
#define meshtastic_ToRadio_want_config_id_tag 3
|
||||
#define meshtastic_ToRadio_disconnect_tag 4
|
||||
#define meshtastic_ToRadio_xmodemPacket_tag 5
|
||||
#define meshtastic_ToRadio_mqttClientProxyMessage_tag 6
|
||||
#define meshtastic_Compressed_portnum_tag 1
|
||||
#define meshtastic_Compressed_data_tag 2
|
||||
#define meshtastic_Neighbor_node_id_tag 1
|
||||
@@ -1018,6 +1056,7 @@ extern "C" {
|
||||
#define meshtastic_FromRadio_queueStatus_tag 11
|
||||
#define meshtastic_FromRadio_xmodemPacket_tag 12
|
||||
#define meshtastic_FromRadio_metadata_tag 13
|
||||
#define meshtastic_FromRadio_mqttClientProxyMessage_tag 14
|
||||
|
||||
/* Struct field encoding specification for nanopb */
|
||||
#define meshtastic_Position_FIELDLIST(X, a) \
|
||||
@@ -1094,6 +1133,14 @@ X(a, STATIC, SINGULAR, FIXED32, icon, 8)
|
||||
#define meshtastic_Waypoint_CALLBACK NULL
|
||||
#define meshtastic_Waypoint_DEFAULT NULL
|
||||
|
||||
#define meshtastic_MqttClientProxyMessage_FIELDLIST(X, a) \
|
||||
X(a, STATIC, SINGULAR, STRING, topic, 1) \
|
||||
X(a, STATIC, ONEOF, BYTES, (payload_variant,data,payload_variant.data), 2) \
|
||||
X(a, STATIC, ONEOF, STRING, (payload_variant,text,payload_variant.text), 3) \
|
||||
X(a, STATIC, SINGULAR, BOOL, retained, 4)
|
||||
#define meshtastic_MqttClientProxyMessage_CALLBACK NULL
|
||||
#define meshtastic_MqttClientProxyMessage_DEFAULT NULL
|
||||
|
||||
#define meshtastic_MeshPacket_FIELDLIST(X, a) \
|
||||
X(a, STATIC, SINGULAR, FIXED32, from, 1) \
|
||||
X(a, STATIC, SINGULAR, FIXED32, to, 2) \
|
||||
@@ -1175,7 +1222,8 @@ X(a, STATIC, ONEOF, MESSAGE, (payload_variant,moduleConfig,moduleConfig),
|
||||
X(a, STATIC, ONEOF, MESSAGE, (payload_variant,channel,channel), 10) \
|
||||
X(a, STATIC, ONEOF, MESSAGE, (payload_variant,queueStatus,queueStatus), 11) \
|
||||
X(a, STATIC, ONEOF, MESSAGE, (payload_variant,xmodemPacket,xmodemPacket), 12) \
|
||||
X(a, STATIC, ONEOF, MESSAGE, (payload_variant,metadata,metadata), 13)
|
||||
X(a, STATIC, ONEOF, MESSAGE, (payload_variant,metadata,metadata), 13) \
|
||||
X(a, STATIC, ONEOF, MESSAGE, (payload_variant,mqttClientProxyMessage,mqttClientProxyMessage), 14)
|
||||
#define meshtastic_FromRadio_CALLBACK NULL
|
||||
#define meshtastic_FromRadio_DEFAULT NULL
|
||||
#define meshtastic_FromRadio_payload_variant_packet_MSGTYPE meshtastic_MeshPacket
|
||||
@@ -1188,16 +1236,19 @@ X(a, STATIC, ONEOF, MESSAGE, (payload_variant,metadata,metadata), 13)
|
||||
#define meshtastic_FromRadio_payload_variant_queueStatus_MSGTYPE meshtastic_QueueStatus
|
||||
#define meshtastic_FromRadio_payload_variant_xmodemPacket_MSGTYPE meshtastic_XModem
|
||||
#define meshtastic_FromRadio_payload_variant_metadata_MSGTYPE meshtastic_DeviceMetadata
|
||||
#define meshtastic_FromRadio_payload_variant_mqttClientProxyMessage_MSGTYPE meshtastic_MqttClientProxyMessage
|
||||
|
||||
#define meshtastic_ToRadio_FIELDLIST(X, a) \
|
||||
X(a, STATIC, ONEOF, MESSAGE, (payload_variant,packet,packet), 1) \
|
||||
X(a, STATIC, ONEOF, UINT32, (payload_variant,want_config_id,want_config_id), 3) \
|
||||
X(a, STATIC, ONEOF, BOOL, (payload_variant,disconnect,disconnect), 4) \
|
||||
X(a, STATIC, ONEOF, MESSAGE, (payload_variant,xmodemPacket,xmodemPacket), 5)
|
||||
X(a, STATIC, ONEOF, MESSAGE, (payload_variant,xmodemPacket,xmodemPacket), 5) \
|
||||
X(a, STATIC, ONEOF, MESSAGE, (payload_variant,mqttClientProxyMessage,mqttClientProxyMessage), 6)
|
||||
#define meshtastic_ToRadio_CALLBACK NULL
|
||||
#define meshtastic_ToRadio_DEFAULT NULL
|
||||
#define meshtastic_ToRadio_payload_variant_packet_MSGTYPE meshtastic_MeshPacket
|
||||
#define meshtastic_ToRadio_payload_variant_xmodemPacket_MSGTYPE meshtastic_XModem
|
||||
#define meshtastic_ToRadio_payload_variant_mqttClientProxyMessage_MSGTYPE meshtastic_MqttClientProxyMessage
|
||||
|
||||
#define meshtastic_Compressed_FIELDLIST(X, a) \
|
||||
X(a, STATIC, SINGULAR, UENUM, portnum, 1) \
|
||||
@@ -1239,6 +1290,7 @@ extern const pb_msgdesc_t meshtastic_RouteDiscovery_msg;
|
||||
extern const pb_msgdesc_t meshtastic_Routing_msg;
|
||||
extern const pb_msgdesc_t meshtastic_Data_msg;
|
||||
extern const pb_msgdesc_t meshtastic_Waypoint_msg;
|
||||
extern const pb_msgdesc_t meshtastic_MqttClientProxyMessage_msg;
|
||||
extern const pb_msgdesc_t meshtastic_MeshPacket_msg;
|
||||
extern const pb_msgdesc_t meshtastic_NodeInfo_msg;
|
||||
extern const pb_msgdesc_t meshtastic_MyNodeInfo_msg;
|
||||
@@ -1258,6 +1310,7 @@ extern const pb_msgdesc_t meshtastic_DeviceMetadata_msg;
|
||||
#define meshtastic_Routing_fields &meshtastic_Routing_msg
|
||||
#define meshtastic_Data_fields &meshtastic_Data_msg
|
||||
#define meshtastic_Waypoint_fields &meshtastic_Waypoint_msg
|
||||
#define meshtastic_MqttClientProxyMessage_fields &meshtastic_MqttClientProxyMessage_msg
|
||||
#define meshtastic_MeshPacket_fields &meshtastic_MeshPacket_msg
|
||||
#define meshtastic_NodeInfo_fields &meshtastic_NodeInfo_msg
|
||||
#define meshtastic_MyNodeInfo_fields &meshtastic_MyNodeInfo_msg
|
||||
@@ -1274,9 +1327,10 @@ extern const pb_msgdesc_t meshtastic_DeviceMetadata_msg;
|
||||
#define meshtastic_Compressed_size 243
|
||||
#define meshtastic_Data_size 270
|
||||
#define meshtastic_DeviceMetadata_size 46
|
||||
#define meshtastic_FromRadio_size 330
|
||||
#define meshtastic_FromRadio_size 510
|
||||
#define meshtastic_LogRecord_size 81
|
||||
#define meshtastic_MeshPacket_size 321
|
||||
#define meshtastic_MqttClientProxyMessage_size 501
|
||||
#define meshtastic_MyNodeInfo_size 179
|
||||
#define meshtastic_NeighborInfo_size 142
|
||||
#define meshtastic_Neighbor_size 11
|
||||
@@ -1285,7 +1339,7 @@ extern const pb_msgdesc_t meshtastic_DeviceMetadata_msg;
|
||||
#define meshtastic_QueueStatus_size 23
|
||||
#define meshtastic_RouteDiscovery_size 40
|
||||
#define meshtastic_Routing_size 42
|
||||
#define meshtastic_ToRadio_size 324
|
||||
#define meshtastic_ToRadio_size 504
|
||||
#define meshtastic_User_size 77
|
||||
#define meshtastic_Waypoint_size 165
|
||||
|
||||
|
||||
@@ -39,6 +39,9 @@ PB_BIND(meshtastic_ModuleConfig_TelemetryConfig, meshtastic_ModuleConfig_Telemet
|
||||
PB_BIND(meshtastic_ModuleConfig_CannedMessageConfig, meshtastic_ModuleConfig_CannedMessageConfig, AUTO)
|
||||
|
||||
|
||||
PB_BIND(meshtastic_ModuleConfig_AmbientLightingConfig, meshtastic_ModuleConfig_AmbientLightingConfig, AUTO)
|
||||
|
||||
|
||||
PB_BIND(meshtastic_RemoteHardwarePin, meshtastic_RemoteHardwarePin, AUTO)
|
||||
|
||||
|
||||
|
||||
@@ -112,6 +112,8 @@ typedef struct _meshtastic_ModuleConfig_MQTTConfig {
|
||||
/* The root topic to use for MQTT messages. Default is "msh".
|
||||
This is useful if you want to use a single MQTT server for multiple meshtastic networks and separate them via ACLs */
|
||||
char root[16];
|
||||
/* If true, we can use the connected phone / client to proxy messages to MQTT instead of a direct connection */
|
||||
bool proxy_to_client_enabled;
|
||||
} meshtastic_ModuleConfig_MQTTConfig;
|
||||
|
||||
/* NeighborInfoModule Config */
|
||||
@@ -279,6 +281,20 @@ typedef struct _meshtastic_ModuleConfig_CannedMessageConfig {
|
||||
bool send_bell;
|
||||
} meshtastic_ModuleConfig_CannedMessageConfig;
|
||||
|
||||
/* Ambient Lighting Module - Settings for control of onboard LEDs to allow users to adjust the brightness levels and respective color levels.
|
||||
Initially created for the RAK14001 RGB LED module. */
|
||||
typedef struct _meshtastic_ModuleConfig_AmbientLightingConfig {
|
||||
/* Sets LED to on or off. */
|
||||
bool led_state;
|
||||
/* Sets the overall current for the LED, firmware side range for the RAK14001 is 1-31, but users should be given a range of 0-100% */
|
||||
uint8_t current;
|
||||
uint8_t red; /* Red level */
|
||||
/* Sets the green level of the LED, firmware side values are 0-255, but users should be given a range of 0-100% */
|
||||
uint8_t green; /* Green level */
|
||||
/* Sets the blue level of the LED, firmware side values are 0-255, but users should be given a range of 0-100% */
|
||||
uint8_t blue; /* Blue level */
|
||||
} meshtastic_ModuleConfig_AmbientLightingConfig;
|
||||
|
||||
/* A GPIO pin definition for remote hardware module */
|
||||
typedef struct _meshtastic_RemoteHardwarePin {
|
||||
/* GPIO Pin number (must match Arduino) */
|
||||
@@ -324,6 +340,8 @@ typedef struct _meshtastic_ModuleConfig {
|
||||
meshtastic_ModuleConfig_RemoteHardwareConfig remote_hardware;
|
||||
/* TODO: REPLACE */
|
||||
meshtastic_ModuleConfig_NeighborInfoConfig neighbor_info;
|
||||
/* TODO: REPLACE */
|
||||
meshtastic_ModuleConfig_AmbientLightingConfig ambient_lighting;
|
||||
} payload_variant;
|
||||
} meshtastic_ModuleConfig;
|
||||
|
||||
@@ -370,12 +388,13 @@ extern "C" {
|
||||
#define meshtastic_ModuleConfig_CannedMessageConfig_inputbroker_event_ccw_ENUMTYPE meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar
|
||||
#define meshtastic_ModuleConfig_CannedMessageConfig_inputbroker_event_press_ENUMTYPE meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar
|
||||
|
||||
|
||||
#define meshtastic_RemoteHardwarePin_type_ENUMTYPE meshtastic_RemoteHardwarePinType
|
||||
|
||||
|
||||
/* Initializer values for message structs */
|
||||
#define meshtastic_ModuleConfig_init_default {0, {meshtastic_ModuleConfig_MQTTConfig_init_default}}
|
||||
#define meshtastic_ModuleConfig_MQTTConfig_init_default {0, "", "", "", 0, 0, 0, ""}
|
||||
#define meshtastic_ModuleConfig_MQTTConfig_init_default {0, "", "", "", 0, 0, 0, "", 0}
|
||||
#define meshtastic_ModuleConfig_RemoteHardwareConfig_init_default {0, 0, 0, {meshtastic_RemoteHardwarePin_init_default, meshtastic_RemoteHardwarePin_init_default, meshtastic_RemoteHardwarePin_init_default, meshtastic_RemoteHardwarePin_init_default}}
|
||||
#define meshtastic_ModuleConfig_NeighborInfoConfig_init_default {0, 0}
|
||||
#define meshtastic_ModuleConfig_AudioConfig_init_default {0, 0, _meshtastic_ModuleConfig_AudioConfig_Audio_Baud_MIN, 0, 0, 0, 0}
|
||||
@@ -385,9 +404,10 @@ extern "C" {
|
||||
#define meshtastic_ModuleConfig_RangeTestConfig_init_default {0, 0, 0}
|
||||
#define meshtastic_ModuleConfig_TelemetryConfig_init_default {0, 0, 0, 0, 0, 0, 0}
|
||||
#define meshtastic_ModuleConfig_CannedMessageConfig_init_default {0, 0, 0, 0, _meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_MIN, _meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_MIN, _meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_MIN, 0, 0, "", 0}
|
||||
#define meshtastic_ModuleConfig_AmbientLightingConfig_init_default {0, 0, 0, 0, 0}
|
||||
#define meshtastic_RemoteHardwarePin_init_default {0, "", _meshtastic_RemoteHardwarePinType_MIN}
|
||||
#define meshtastic_ModuleConfig_init_zero {0, {meshtastic_ModuleConfig_MQTTConfig_init_zero}}
|
||||
#define meshtastic_ModuleConfig_MQTTConfig_init_zero {0, "", "", "", 0, 0, 0, ""}
|
||||
#define meshtastic_ModuleConfig_MQTTConfig_init_zero {0, "", "", "", 0, 0, 0, "", 0}
|
||||
#define meshtastic_ModuleConfig_RemoteHardwareConfig_init_zero {0, 0, 0, {meshtastic_RemoteHardwarePin_init_zero, meshtastic_RemoteHardwarePin_init_zero, meshtastic_RemoteHardwarePin_init_zero, meshtastic_RemoteHardwarePin_init_zero}}
|
||||
#define meshtastic_ModuleConfig_NeighborInfoConfig_init_zero {0, 0}
|
||||
#define meshtastic_ModuleConfig_AudioConfig_init_zero {0, 0, _meshtastic_ModuleConfig_AudioConfig_Audio_Baud_MIN, 0, 0, 0, 0}
|
||||
@@ -397,6 +417,7 @@ extern "C" {
|
||||
#define meshtastic_ModuleConfig_RangeTestConfig_init_zero {0, 0, 0}
|
||||
#define meshtastic_ModuleConfig_TelemetryConfig_init_zero {0, 0, 0, 0, 0, 0, 0}
|
||||
#define meshtastic_ModuleConfig_CannedMessageConfig_init_zero {0, 0, 0, 0, _meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_MIN, _meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_MIN, _meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_MIN, 0, 0, "", 0}
|
||||
#define meshtastic_ModuleConfig_AmbientLightingConfig_init_zero {0, 0, 0, 0, 0}
|
||||
#define meshtastic_RemoteHardwarePin_init_zero {0, "", _meshtastic_RemoteHardwarePinType_MIN}
|
||||
|
||||
/* Field tags (for use in manual encoding/decoding) */
|
||||
@@ -408,6 +429,7 @@ extern "C" {
|
||||
#define meshtastic_ModuleConfig_MQTTConfig_json_enabled_tag 6
|
||||
#define meshtastic_ModuleConfig_MQTTConfig_tls_enabled_tag 7
|
||||
#define meshtastic_ModuleConfig_MQTTConfig_root_tag 8
|
||||
#define meshtastic_ModuleConfig_MQTTConfig_proxy_to_client_enabled_tag 9
|
||||
#define meshtastic_ModuleConfig_NeighborInfoConfig_enabled_tag 1
|
||||
#define meshtastic_ModuleConfig_NeighborInfoConfig_update_interval_tag 2
|
||||
#define meshtastic_ModuleConfig_AudioConfig_codec2_enabled_tag 1
|
||||
@@ -465,6 +487,11 @@ extern "C" {
|
||||
#define meshtastic_ModuleConfig_CannedMessageConfig_enabled_tag 9
|
||||
#define meshtastic_ModuleConfig_CannedMessageConfig_allow_input_source_tag 10
|
||||
#define meshtastic_ModuleConfig_CannedMessageConfig_send_bell_tag 11
|
||||
#define meshtastic_ModuleConfig_AmbientLightingConfig_led_state_tag 1
|
||||
#define meshtastic_ModuleConfig_AmbientLightingConfig_current_tag 2
|
||||
#define meshtastic_ModuleConfig_AmbientLightingConfig_red_tag 3
|
||||
#define meshtastic_ModuleConfig_AmbientLightingConfig_green_tag 4
|
||||
#define meshtastic_ModuleConfig_AmbientLightingConfig_blue_tag 5
|
||||
#define meshtastic_RemoteHardwarePin_gpio_pin_tag 1
|
||||
#define meshtastic_RemoteHardwarePin_name_tag 2
|
||||
#define meshtastic_RemoteHardwarePin_type_tag 3
|
||||
@@ -481,6 +508,7 @@ extern "C" {
|
||||
#define meshtastic_ModuleConfig_audio_tag 8
|
||||
#define meshtastic_ModuleConfig_remote_hardware_tag 9
|
||||
#define meshtastic_ModuleConfig_neighbor_info_tag 10
|
||||
#define meshtastic_ModuleConfig_ambient_lighting_tag 11
|
||||
|
||||
/* Struct field encoding specification for nanopb */
|
||||
#define meshtastic_ModuleConfig_FIELDLIST(X, a) \
|
||||
@@ -493,7 +521,8 @@ X(a, STATIC, ONEOF, MESSAGE, (payload_variant,telemetry,payload_variant.te
|
||||
X(a, STATIC, ONEOF, MESSAGE, (payload_variant,canned_message,payload_variant.canned_message), 7) \
|
||||
X(a, STATIC, ONEOF, MESSAGE, (payload_variant,audio,payload_variant.audio), 8) \
|
||||
X(a, STATIC, ONEOF, MESSAGE, (payload_variant,remote_hardware,payload_variant.remote_hardware), 9) \
|
||||
X(a, STATIC, ONEOF, MESSAGE, (payload_variant,neighbor_info,payload_variant.neighbor_info), 10)
|
||||
X(a, STATIC, ONEOF, MESSAGE, (payload_variant,neighbor_info,payload_variant.neighbor_info), 10) \
|
||||
X(a, STATIC, ONEOF, MESSAGE, (payload_variant,ambient_lighting,payload_variant.ambient_lighting), 11)
|
||||
#define meshtastic_ModuleConfig_CALLBACK NULL
|
||||
#define meshtastic_ModuleConfig_DEFAULT NULL
|
||||
#define meshtastic_ModuleConfig_payload_variant_mqtt_MSGTYPE meshtastic_ModuleConfig_MQTTConfig
|
||||
@@ -506,6 +535,7 @@ X(a, STATIC, ONEOF, MESSAGE, (payload_variant,neighbor_info,payload_varian
|
||||
#define meshtastic_ModuleConfig_payload_variant_audio_MSGTYPE meshtastic_ModuleConfig_AudioConfig
|
||||
#define meshtastic_ModuleConfig_payload_variant_remote_hardware_MSGTYPE meshtastic_ModuleConfig_RemoteHardwareConfig
|
||||
#define meshtastic_ModuleConfig_payload_variant_neighbor_info_MSGTYPE meshtastic_ModuleConfig_NeighborInfoConfig
|
||||
#define meshtastic_ModuleConfig_payload_variant_ambient_lighting_MSGTYPE meshtastic_ModuleConfig_AmbientLightingConfig
|
||||
|
||||
#define meshtastic_ModuleConfig_MQTTConfig_FIELDLIST(X, a) \
|
||||
X(a, STATIC, SINGULAR, BOOL, enabled, 1) \
|
||||
@@ -515,7 +545,8 @@ X(a, STATIC, SINGULAR, STRING, password, 4) \
|
||||
X(a, STATIC, SINGULAR, BOOL, encryption_enabled, 5) \
|
||||
X(a, STATIC, SINGULAR, BOOL, json_enabled, 6) \
|
||||
X(a, STATIC, SINGULAR, BOOL, tls_enabled, 7) \
|
||||
X(a, STATIC, SINGULAR, STRING, root, 8)
|
||||
X(a, STATIC, SINGULAR, STRING, root, 8) \
|
||||
X(a, STATIC, SINGULAR, BOOL, proxy_to_client_enabled, 9)
|
||||
#define meshtastic_ModuleConfig_MQTTConfig_CALLBACK NULL
|
||||
#define meshtastic_ModuleConfig_MQTTConfig_DEFAULT NULL
|
||||
|
||||
@@ -616,6 +647,15 @@ X(a, STATIC, SINGULAR, BOOL, send_bell, 11)
|
||||
#define meshtastic_ModuleConfig_CannedMessageConfig_CALLBACK NULL
|
||||
#define meshtastic_ModuleConfig_CannedMessageConfig_DEFAULT NULL
|
||||
|
||||
#define meshtastic_ModuleConfig_AmbientLightingConfig_FIELDLIST(X, a) \
|
||||
X(a, STATIC, SINGULAR, BOOL, led_state, 1) \
|
||||
X(a, STATIC, SINGULAR, UINT32, current, 2) \
|
||||
X(a, STATIC, SINGULAR, UINT32, red, 3) \
|
||||
X(a, STATIC, SINGULAR, UINT32, green, 4) \
|
||||
X(a, STATIC, SINGULAR, UINT32, blue, 5)
|
||||
#define meshtastic_ModuleConfig_AmbientLightingConfig_CALLBACK NULL
|
||||
#define meshtastic_ModuleConfig_AmbientLightingConfig_DEFAULT NULL
|
||||
|
||||
#define meshtastic_RemoteHardwarePin_FIELDLIST(X, a) \
|
||||
X(a, STATIC, SINGULAR, UINT32, gpio_pin, 1) \
|
||||
X(a, STATIC, SINGULAR, STRING, name, 2) \
|
||||
@@ -634,6 +674,7 @@ extern const pb_msgdesc_t meshtastic_ModuleConfig_StoreForwardConfig_msg;
|
||||
extern const pb_msgdesc_t meshtastic_ModuleConfig_RangeTestConfig_msg;
|
||||
extern const pb_msgdesc_t meshtastic_ModuleConfig_TelemetryConfig_msg;
|
||||
extern const pb_msgdesc_t meshtastic_ModuleConfig_CannedMessageConfig_msg;
|
||||
extern const pb_msgdesc_t meshtastic_ModuleConfig_AmbientLightingConfig_msg;
|
||||
extern const pb_msgdesc_t meshtastic_RemoteHardwarePin_msg;
|
||||
|
||||
/* Defines for backwards compatibility with code written before nanopb-0.4.0 */
|
||||
@@ -648,20 +689,22 @@ extern const pb_msgdesc_t meshtastic_RemoteHardwarePin_msg;
|
||||
#define meshtastic_ModuleConfig_RangeTestConfig_fields &meshtastic_ModuleConfig_RangeTestConfig_msg
|
||||
#define meshtastic_ModuleConfig_TelemetryConfig_fields &meshtastic_ModuleConfig_TelemetryConfig_msg
|
||||
#define meshtastic_ModuleConfig_CannedMessageConfig_fields &meshtastic_ModuleConfig_CannedMessageConfig_msg
|
||||
#define meshtastic_ModuleConfig_AmbientLightingConfig_fields &meshtastic_ModuleConfig_AmbientLightingConfig_msg
|
||||
#define meshtastic_RemoteHardwarePin_fields &meshtastic_RemoteHardwarePin_msg
|
||||
|
||||
/* Maximum encoded size of messages (where known) */
|
||||
#define meshtastic_ModuleConfig_AmbientLightingConfig_size 14
|
||||
#define meshtastic_ModuleConfig_AudioConfig_size 19
|
||||
#define meshtastic_ModuleConfig_CannedMessageConfig_size 49
|
||||
#define meshtastic_ModuleConfig_ExternalNotificationConfig_size 40
|
||||
#define meshtastic_ModuleConfig_MQTTConfig_size 220
|
||||
#define meshtastic_ModuleConfig_MQTTConfig_size 222
|
||||
#define meshtastic_ModuleConfig_NeighborInfoConfig_size 8
|
||||
#define meshtastic_ModuleConfig_RangeTestConfig_size 10
|
||||
#define meshtastic_ModuleConfig_RemoteHardwareConfig_size 96
|
||||
#define meshtastic_ModuleConfig_SerialConfig_size 28
|
||||
#define meshtastic_ModuleConfig_StoreForwardConfig_size 22
|
||||
#define meshtastic_ModuleConfig_TelemetryConfig_size 26
|
||||
#define meshtastic_ModuleConfig_size 223
|
||||
#define meshtastic_ModuleConfig_size 225
|
||||
#define meshtastic_RemoteHardwarePin_size 21
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
@@ -63,7 +63,7 @@ typedef struct _meshtastic_EnvironmentMetrics {
|
||||
float relative_humidity;
|
||||
/* Barometric pressure in hPA measured */
|
||||
float barometric_pressure;
|
||||
/* Gas resistance in mOhm measured */
|
||||
/* Gas resistance in MOhm measured */
|
||||
float gas_resistance;
|
||||
/* Voltage measured */
|
||||
float voltage;
|
||||
|
||||
@@ -165,7 +165,7 @@ void handleAPIv1FromRadio(HTTPRequest *req, HTTPResponse *res)
|
||||
|
||||
if (params->getQueryParameter("all", valueAll)) {
|
||||
|
||||
// If all is ture, return all the buffers we have available
|
||||
// If all is true, return all the buffers we have available
|
||||
// to us at this point in time.
|
||||
if (valueAll == "true") {
|
||||
while (len) {
|
||||
@@ -179,7 +179,7 @@ void handleAPIv1FromRadio(HTTPRequest *req, HTTPResponse *res)
|
||||
res->write(txBuf, len);
|
||||
}
|
||||
|
||||
// the param "all" was not spcified. Return just one protobuf
|
||||
// the param "all" was not specified. Return just one protobuf
|
||||
} else {
|
||||
len = webAPI.getFromRadio(txBuf);
|
||||
res->write(txBuf, len);
|
||||
@@ -460,7 +460,7 @@ void handleFormUpload(HTTPRequest *req, HTTPResponse *res)
|
||||
HTTPBodyParser *parser;
|
||||
std::string contentType = req->getHeader("Content-Type");
|
||||
|
||||
// The content type may have additional properties after a semicolon, for exampel:
|
||||
// The content type may have additional properties after a semicolon, for example:
|
||||
// Content-Type: text/html;charset=utf-8
|
||||
// Content-Type: multipart/form-data;boundary=------s0m3w31rdch4r4c73rs
|
||||
// As we're interested only in the actual mime _type_, we strip everything after the
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
#include "esp_task_wdt.h"
|
||||
#endif
|
||||
|
||||
// Persistant Data Storage
|
||||
// Persistent Data Storage
|
||||
#include <Preferences.h>
|
||||
Preferences prefs;
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@ size_t pb_encode_to_bytes(uint8_t *destbuf, size_t destbufsize, const pb_msgdesc
|
||||
if (!pb_encode(&stream, fields, src_struct)) {
|
||||
LOG_ERROR("Panic: can't encode protobuf reason='%s'\n", PB_GET_ERROR(&stream));
|
||||
assert(
|
||||
0); // If this asser fails it probably means you made a field too large for the max limits specified in mesh.options
|
||||
0); // If this assert fails it probably means you made a field too large for the max limits specified in mesh.options
|
||||
} else {
|
||||
return stream.bytes_written;
|
||||
}
|
||||
|
||||
@@ -16,9 +16,7 @@
|
||||
#include "unistd.h"
|
||||
#endif
|
||||
|
||||
#if HAS_WIFI || HAS_ETHERNET
|
||||
#include "mqtt/MQTT.h"
|
||||
#endif
|
||||
|
||||
#define DEFAULT_REBOOT_SECONDS 7
|
||||
|
||||
@@ -567,7 +565,7 @@ void AdminModule::handleGetDeviceConnectionStatus(const meshtastic_MeshPacket &r
|
||||
if (conn.wifi.status.is_connected) {
|
||||
conn.wifi.rssi = WiFi.RSSI();
|
||||
conn.wifi.status.ip_address = WiFi.localIP();
|
||||
conn.wifi.status.is_mqtt_connected = mqtt && mqtt->connected();
|
||||
conn.wifi.status.is_mqtt_connected = mqtt && mqtt->isConnectedDirectly();
|
||||
conn.wifi.status.is_syslog_connected = false; // FIXME wire this up
|
||||
}
|
||||
#endif
|
||||
@@ -578,7 +576,7 @@ void AdminModule::handleGetDeviceConnectionStatus(const meshtastic_MeshPacket &r
|
||||
if (Ethernet.linkStatus() == LinkON) {
|
||||
conn.ethernet.status.is_connected = true;
|
||||
conn.ethernet.status.ip_address = Ethernet.localIP();
|
||||
conn.ethernet.status.is_mqtt_connected = mqtt && mqtt->connected();
|
||||
conn.ethernet.status.is_mqtt_connected = mqtt && mqtt->isConnectedDirectly();
|
||||
conn.ethernet.status.is_syslog_connected = false; // FIXME wire this up
|
||||
} else {
|
||||
conn.ethernet.status.is_connected = false;
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
#include "FSCommon.h"
|
||||
#include "MeshService.h"
|
||||
#include "NodeDB.h"
|
||||
#include "PowerFSM.h" // neede for button bypass
|
||||
#include "PowerFSM.h" // needed for button bypass
|
||||
#include "detect/ScanI2C.h"
|
||||
#include "mesh/generated/meshtastic/cannedmessages.pb.h"
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
#include "graphics/fonts/OLEDDisplayFontsUA.h"
|
||||
#endif
|
||||
|
||||
#if defined(USE_EINK) || defined(ILI9341_DRIVER) || defined(ST7735_CS)
|
||||
#if defined(USE_EINK) || defined(ILI9341_DRIVER) || defined(ST7735_CS) || defined(ST7789_CS)
|
||||
// The screen is bigger so use bigger fonts
|
||||
#define FONT_SMALL ArialMT_Plain_16
|
||||
#define FONT_MEDIUM ArialMT_Plain_24
|
||||
@@ -123,8 +123,8 @@ int CannedMessageModule::splitConfiguredMessages()
|
||||
int CannedMessageModule::handleInputEvent(const InputEvent *event)
|
||||
{
|
||||
if ((strlen(moduleConfig.canned_message.allow_input_source) > 0) &&
|
||||
(strcmp(moduleConfig.canned_message.allow_input_source, event->source) != 0) &&
|
||||
(strcmp(moduleConfig.canned_message.allow_input_source, "_any") != 0)) {
|
||||
(strcasecmp(moduleConfig.canned_message.allow_input_source, event->source) != 0) &&
|
||||
(strcasecmp(moduleConfig.canned_message.allow_input_source, "_any") != 0)) {
|
||||
// Event source is not accepted.
|
||||
// Event only accepted if source matches the configured one, or
|
||||
// the configured one is "_any" (or if there is no configured
|
||||
@@ -164,13 +164,22 @@ int CannedMessageModule::handleInputEvent(const InputEvent *event)
|
||||
(event->inputEvent == static_cast<char>(meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_LEFT)) ||
|
||||
(event->inputEvent == static_cast<char>(meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_RIGHT))) {
|
||||
LOG_DEBUG("Canned message event (%x)\n", event->kbchar);
|
||||
if (this->runState == CANNED_MESSAGE_RUN_STATE_FREETEXT) {
|
||||
// tweak for left/right events generated via trackball/touch with empty kbchar
|
||||
if (!event->kbchar) {
|
||||
if (event->inputEvent == static_cast<char>(meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_LEFT)) {
|
||||
this->payload = 0xb4;
|
||||
this->destSelect = true;
|
||||
} else if (event->inputEvent == static_cast<char>(meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_RIGHT)) {
|
||||
this->payload = 0xb7;
|
||||
this->destSelect = true;
|
||||
}
|
||||
} else {
|
||||
// pass the pressed key
|
||||
this->payload = event->kbchar;
|
||||
}
|
||||
this->lastTouchMillis = millis();
|
||||
validEvent = true;
|
||||
}
|
||||
}
|
||||
if (event->inputEvent == static_cast<char>(ANYKEY)) {
|
||||
LOG_DEBUG("Canned message event any key pressed\n");
|
||||
// when inactive, this will switch to the freetext mode
|
||||
@@ -225,7 +234,7 @@ int32_t CannedMessageModule::runOnce()
|
||||
(this->runState == CANNED_MESSAGE_RUN_STATE_INACTIVE)) {
|
||||
return INT32_MAX;
|
||||
}
|
||||
LOG_DEBUG("Check status\n");
|
||||
// LOG_DEBUG("Check status\n");
|
||||
UIFrameEvent e = {false, true};
|
||||
if (this->runState == CANNED_MESSAGE_RUN_STATE_SENDING_ACTIVE) {
|
||||
// TODO: might have some feedback of sendig state
|
||||
@@ -300,8 +309,7 @@ int32_t CannedMessageModule::runOnce()
|
||||
this->runState = CANNED_MESSAGE_RUN_STATE_ACTIVE;
|
||||
LOG_DEBUG("MOVE DOWN (%d):%s\n", this->currentMessageIndex, this->getCurrentMessage());
|
||||
}
|
||||
} else if (this->runState == CANNED_MESSAGE_RUN_STATE_FREETEXT) {
|
||||
e.frameChanged = true;
|
||||
} else if (this->runState == CANNED_MESSAGE_RUN_STATE_FREETEXT || this->runState == CANNED_MESSAGE_RUN_STATE_ACTIVE) {
|
||||
switch (this->payload) {
|
||||
case 0xb4: // left
|
||||
if (this->destSelect) {
|
||||
@@ -347,6 +355,12 @@ int32_t CannedMessageModule::runOnce()
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (this->runState == CANNED_MESSAGE_RUN_STATE_FREETEXT) {
|
||||
e.frameChanged = true;
|
||||
switch (this->payload) {
|
||||
case 0x08: // backspace
|
||||
if (this->freetext.length() > 0) {
|
||||
if (this->cursor == this->freetext.length()) {
|
||||
@@ -365,6 +379,10 @@ int32_t CannedMessageModule::runOnce()
|
||||
this->destSelect = true;
|
||||
}
|
||||
break;
|
||||
case 0xb4: // left
|
||||
case 0xb7: // right
|
||||
// already handled above
|
||||
break;
|
||||
default:
|
||||
if (this->cursor == this->freetext.length()) {
|
||||
this->freetext += this->payload;
|
||||
@@ -379,6 +397,7 @@ int32_t CannedMessageModule::runOnce()
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
this->lastTouchMillis = millis();
|
||||
this->notifyObservers(&e);
|
||||
@@ -406,6 +425,11 @@ const char *CannedMessageModule::getNextMessage()
|
||||
{
|
||||
return this->messages[this->getNextIndex()];
|
||||
}
|
||||
const char *CannedMessageModule::getMessageByIndex(int index)
|
||||
{
|
||||
return (index >= 0 && index < this->messagesCount) ? this->messages[index] : "";
|
||||
}
|
||||
|
||||
const char *CannedMessageModule::getNodeName(NodeNum node)
|
||||
{
|
||||
if (node == NODENUM_BROADCAST) {
|
||||
@@ -482,12 +506,31 @@ void CannedMessageModule::drawFrame(OLEDDisplay *display, OLEDDisplayUiState *st
|
||||
display->setTextAlignment(TEXT_ALIGN_LEFT);
|
||||
display->setFont(FONT_SMALL);
|
||||
display->drawStringf(0 + x, 0 + y, buffer, "To: %s", cannedMessageModule->getNodeName(this->dest));
|
||||
int lines = (display->getHeight() / FONT_HEIGHT_SMALL) - 1;
|
||||
if (lines == 3) {
|
||||
// static (old) behavior for small displays
|
||||
display->drawString(0 + x, 0 + y + FONT_HEIGHT_SMALL, cannedMessageModule->getPrevMessage());
|
||||
display->fillRect(0 + x, 0 + y + FONT_HEIGHT_SMALL * 2, x + display->getWidth(), y + FONT_HEIGHT_SMALL);
|
||||
display->setColor(BLACK);
|
||||
display->drawString(0 + x, 0 + y + FONT_HEIGHT_SMALL * 2, cannedMessageModule->getCurrentMessage());
|
||||
display->setColor(WHITE);
|
||||
display->drawString(0 + x, 0 + y + FONT_HEIGHT_SMALL * 3, cannedMessageModule->getNextMessage());
|
||||
} else {
|
||||
// use entire display height for larger displays
|
||||
int topMsg = (messagesCount > lines && currentMessageIndex >= lines - 1) ? currentMessageIndex - lines + 2 : 0;
|
||||
for (int i = 0; i < std::min(messagesCount, lines); i++) {
|
||||
if (i == currentMessageIndex - topMsg) {
|
||||
display->fillRect(0 + x, 0 + y + FONT_HEIGHT_SMALL * (i + 1), x + display->getWidth(),
|
||||
y + FONT_HEIGHT_SMALL);
|
||||
display->setColor(BLACK);
|
||||
display->drawString(0 + x, 0 + y + FONT_HEIGHT_SMALL * (i + 1), cannedMessageModule->getCurrentMessage());
|
||||
display->setColor(WHITE);
|
||||
} else {
|
||||
display->drawString(0 + x, 0 + y + FONT_HEIGHT_SMALL * (i + 1),
|
||||
cannedMessageModule->getMessageByIndex(topMsg + i));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,6 +30,7 @@ class CannedMessageModule : public SinglePortModule, public Observable<const UIF
|
||||
const char *getCurrentMessage();
|
||||
const char *getPrevMessage();
|
||||
const char *getNextMessage();
|
||||
const char *getMessageByIndex(int index);
|
||||
const char *getNodeName(NodeNum node);
|
||||
bool shouldDraw();
|
||||
void eventUp();
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
|
||||
#include "main.h"
|
||||
|
||||
#ifdef RAK4630
|
||||
#ifdef HAS_NCP5623
|
||||
#include <graphics/RAKled.h>
|
||||
NCP5623 rgb;
|
||||
|
||||
@@ -84,7 +84,7 @@ int32_t ExternalNotificationModule::runOnce()
|
||||
millis()) {
|
||||
getExternal(2) ? setExternalOff(2) : setExternalOn(2);
|
||||
}
|
||||
#ifdef RAK4630
|
||||
#ifdef HAS_NCP5623
|
||||
if (rgb_found.type == ScanI2C::NCP5623) {
|
||||
green = (green + 50) % 255;
|
||||
red = abs(red - green) % 255;
|
||||
@@ -93,6 +93,10 @@ int32_t ExternalNotificationModule::runOnce()
|
||||
rgb.setColor(red, green, blue);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef T_WATCH_S3
|
||||
drv.go();
|
||||
#endif
|
||||
}
|
||||
|
||||
// now let the PWM buzzer play
|
||||
@@ -124,14 +128,18 @@ void ExternalNotificationModule::setExternalOn(uint8_t index)
|
||||
digitalWrite(moduleConfig.external_notification.output_buzzer, true);
|
||||
break;
|
||||
default:
|
||||
if (output > 0)
|
||||
digitalWrite(output, (moduleConfig.external_notification.active ? true : false));
|
||||
break;
|
||||
}
|
||||
#ifdef RAK4630
|
||||
#ifdef HAS_NCP5623
|
||||
if (rgb_found.type == ScanI2C::NCP5623) {
|
||||
rgb.setColor(red, green, blue);
|
||||
}
|
||||
#endif
|
||||
#ifdef T_WATCH_S3
|
||||
drv.go();
|
||||
#endif
|
||||
}
|
||||
|
||||
void ExternalNotificationModule::setExternalOff(uint8_t index)
|
||||
@@ -149,11 +157,12 @@ void ExternalNotificationModule::setExternalOff(uint8_t index)
|
||||
digitalWrite(moduleConfig.external_notification.output_buzzer, false);
|
||||
break;
|
||||
default:
|
||||
if (output > 0)
|
||||
digitalWrite(output, (moduleConfig.external_notification.active ? false : true));
|
||||
break;
|
||||
}
|
||||
|
||||
#ifdef RAK4630
|
||||
#ifdef HAS_NCP5623
|
||||
if (rgb_found.type == ScanI2C::NCP5623) {
|
||||
red = 0;
|
||||
green = 0;
|
||||
@@ -161,6 +170,9 @@ void ExternalNotificationModule::setExternalOff(uint8_t index)
|
||||
rgb.setColor(red, green, blue);
|
||||
}
|
||||
#endif
|
||||
#ifdef T_WATCH_S3
|
||||
drv.stop();
|
||||
#endif
|
||||
}
|
||||
|
||||
bool ExternalNotificationModule::getExternal(uint8_t index)
|
||||
@@ -174,6 +186,9 @@ void ExternalNotificationModule::stopNow()
|
||||
nagCycleCutoff = 1; // small value
|
||||
isNagging = false;
|
||||
setIntervalFromNow(0);
|
||||
#ifdef T_WATCH_S3
|
||||
drv.stop();
|
||||
#endif
|
||||
}
|
||||
|
||||
ExternalNotificationModule::ExternalNotificationModule()
|
||||
@@ -185,7 +200,6 @@ ExternalNotificationModule::ExternalNotificationModule()
|
||||
without having to configure it from the PythonAPI or WebUI.
|
||||
*/
|
||||
|
||||
// moduleConfig.external_notification.enabled = true;
|
||||
// moduleConfig.external_notification.alert_message = true;
|
||||
// moduleConfig.external_notification.alert_message_buzzer = true;
|
||||
// moduleConfig.external_notification.alert_message_vibra = true;
|
||||
@@ -213,8 +227,10 @@ ExternalNotificationModule::ExternalNotificationModule()
|
||||
: EXT_NOTIFICATION_MODULE_OUTPUT;
|
||||
|
||||
// Set the direction of a pin
|
||||
if (output > 0) {
|
||||
LOG_INFO("Using Pin %i in digital mode\n", output);
|
||||
pinMode(output, OUTPUT);
|
||||
}
|
||||
setExternalOff(0);
|
||||
externalTurnedOn[0] = 0;
|
||||
if (moduleConfig.external_notification.output_vibra) {
|
||||
@@ -235,7 +251,7 @@ ExternalNotificationModule::ExternalNotificationModule()
|
||||
LOG_INFO("Using Pin %i in PWM mode\n", config.device.buzzer_gpio);
|
||||
}
|
||||
}
|
||||
#ifdef RAK4630
|
||||
#ifdef HAS_NCP5623
|
||||
if (rgb_found.type == ScanI2C::NCP5623) {
|
||||
rgb.begin();
|
||||
rgb.setCurrent(10);
|
||||
@@ -250,7 +266,12 @@ ExternalNotificationModule::ExternalNotificationModule()
|
||||
ProcessMessage ExternalNotificationModule::handleReceived(const meshtastic_MeshPacket &mp)
|
||||
{
|
||||
if (moduleConfig.external_notification.enabled) {
|
||||
|
||||
#if T_WATCH_S3
|
||||
drv.setWaveform(0, 75);
|
||||
drv.setWaveform(1, 56);
|
||||
drv.setWaveform(2, 0);
|
||||
drv.go();
|
||||
#endif
|
||||
if (getFrom(&mp) != nodeDB.getNodeNum()) {
|
||||
|
||||
// Check if the message contains a bell character. Don't do this loop for every pin, just once.
|
||||
@@ -343,7 +364,6 @@ ProcessMessage ExternalNotificationModule::handleReceived(const meshtastic_MeshP
|
||||
}
|
||||
setIntervalFromNow(0); // run once so we know if we should do something
|
||||
}
|
||||
|
||||
} else {
|
||||
LOG_INFO("External Notification Module Disabled\n");
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#include "configuration.h"
|
||||
#include "input/InputBroker.h"
|
||||
#include "input/RotaryEncoderInterruptImpl1.h"
|
||||
#include "input/TrackballInterruptImpl1.h"
|
||||
#include "input/UpDownInterruptImpl1.h"
|
||||
#include "input/cardKbI2cImpl.h"
|
||||
#include "modules/AdminModule.h"
|
||||
@@ -24,7 +25,7 @@
|
||||
#include "modules/esp32/AudioModule.h"
|
||||
#include "modules/esp32/StoreForwardModule.h"
|
||||
#endif
|
||||
#if defined(ARCH_ESP32) || defined(ARCH_NRF52)
|
||||
#if defined(ARCH_ESP32) || defined(ARCH_NRF52) || defined(ARCH_RP2040)
|
||||
#include "modules/ExternalNotificationModule.h"
|
||||
#include "modules/RangeTestModule.h"
|
||||
#if (defined(ARCH_ESP32) || defined(ARCH_NRF52)) && !defined(CONFIG_IDF_TARGET_ESP32S2)
|
||||
@@ -60,6 +61,10 @@ void setupModules()
|
||||
cardKbI2cImpl = new CardKbI2cImpl();
|
||||
cardKbI2cImpl->init();
|
||||
#endif
|
||||
#if HAS_TRACKBALL
|
||||
trackballInterruptImpl1 = new TrackballInterruptImpl1();
|
||||
trackballInterruptImpl1->init();
|
||||
#endif
|
||||
#if HAS_SCREEN
|
||||
cannedMessageModule = new CannedMessageModule();
|
||||
#endif
|
||||
@@ -81,7 +86,7 @@ void setupModules()
|
||||
|
||||
storeForwardModule = new StoreForwardModule();
|
||||
#endif
|
||||
#if defined(ARCH_ESP32) || defined(ARCH_NRF52)
|
||||
#if defined(ARCH_ESP32) || defined(ARCH_NRF52) || defined(ARCH_RP2040)
|
||||
externalNotificationModule = new ExternalNotificationModule();
|
||||
new RangeTestModule();
|
||||
#endif
|
||||
|
||||
@@ -52,11 +52,22 @@ bool PositionModule::handleReceivedProtobuf(const meshtastic_MeshPacket &mp, mes
|
||||
|
||||
nodeDB.updatePosition(getFrom(&mp), p);
|
||||
|
||||
// Only respond to location requests on the channel where we broadcast location.
|
||||
if (channels.getByIndex(mp.channel).role == meshtastic_Channel_Role_PRIMARY) {
|
||||
ignoreRequest = false;
|
||||
} else {
|
||||
ignoreRequest = true;
|
||||
}
|
||||
|
||||
return false; // Let others look at this message also if they want
|
||||
}
|
||||
|
||||
meshtastic_MeshPacket *PositionModule::allocReply()
|
||||
{
|
||||
if (ignoreRequest) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
meshtastic_NodeInfoLite *node = service.refreshLocalMeshNode(); // should guarantee there is now a position
|
||||
assert(node->has_position);
|
||||
|
||||
|
||||
@@ -54,7 +54,7 @@ int32_t RangeTestModule::runOnce()
|
||||
if (moduleConfig.range_test.sender) {
|
||||
LOG_INFO("Initializing Range Test Module -- Sender\n");
|
||||
started = millis(); // make a note of when we started
|
||||
return (5000); // Sending first message 5 seconds after initilization.
|
||||
return (5000); // Sending first message 5 seconds after initialization.
|
||||
} else {
|
||||
LOG_INFO("Initializing Range Test Module -- Receiver\n");
|
||||
return disable();
|
||||
@@ -147,8 +147,8 @@ ProcessMessage RangeTestModuleRadio::handleReceived(const meshtastic_MeshPacket
|
||||
LOG_DEBUG("mp.from %d\n", mp.from);
|
||||
LOG_DEBUG("mp.rx_snr %f\n", mp.rx_snr);
|
||||
LOG_DEBUG("mp.hop_limit %d\n", mp.hop_limit);
|
||||
// LOG_DEBUG("mp.decoded.position.latitude_i %d\n", mp.decoded.position.latitude_i); // Depricated
|
||||
// LOG_DEBUG("mp.decoded.position.longitude_i %d\n", mp.decoded.position.longitude_i); // Depricated
|
||||
// LOG_DEBUG("mp.decoded.position.latitude_i %d\n", mp.decoded.position.latitude_i); // Deprecated
|
||||
// LOG_DEBUG("mp.decoded.position.longitude_i %d\n", mp.decoded.position.longitude_i); // Deprecated
|
||||
LOG_DEBUG("---- Node Information of Received Packet (mp.from):\n");
|
||||
LOG_DEBUG("n->user.long_name %s\n", n->user.long_name);
|
||||
LOG_DEBUG("n->user.short_name %s\n", n->user.short_name);
|
||||
@@ -186,8 +186,8 @@ bool RangeTestModuleRadio::appendFile(const meshtastic_MeshPacket &mp)
|
||||
LOG_DEBUG("mp.from %d\n", mp.from);
|
||||
LOG_DEBUG("mp.rx_snr %f\n", mp.rx_snr);
|
||||
LOG_DEBUG("mp.hop_limit %d\n", mp.hop_limit);
|
||||
// LOG_DEBUG("mp.decoded.position.latitude_i %d\n", mp.decoded.position.latitude_i); // Depricated
|
||||
// LOG_DEBUG("mp.decoded.position.longitude_i %d\n", mp.decoded.position.longitude_i); // Depricated
|
||||
// LOG_DEBUG("mp.decoded.position.latitude_i %d\n", mp.decoded.position.latitude_i); // Deprecated
|
||||
// LOG_DEBUG("mp.decoded.position.longitude_i %d\n", mp.decoded.position.longitude_i); // Deprecated
|
||||
LOG_DEBUG("---- Node Information of Received Packet (mp.from):\n");
|
||||
LOG_DEBUG("n->user.long_name %s\n", n->user.long_name);
|
||||
LOG_DEBUG("n->user.short_name %s\n", n->user.short_name);
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user