Merge branch 'master' into rsyslog-client

This commit is contained in:
Thomas Göttgens
2023-01-30 19:06:42 +01:00
335 changed files with 8406 additions and 8353 deletions

4
.gitattributes vendored Normal file
View File

@@ -0,0 +1,4 @@
* text=auto eol=lf
*.{cmd,[cC][mM][dD]} text eol=crlf
*.{bat,[bB][aA][tT]} text eol=crlf
*.{sh,[sS][hH]} text eol=lf

View File

@@ -1,5 +1,5 @@
name: 'Setup Build Base Composite Action' name: "Setup Build Base Composite Action"
description: 'Base build actions for Meshtastic Platform IO steps' description: "Base build actions for Meshtastic Platform IO steps"
runs: runs:
using: "composite" using: "composite"

View File

@@ -137,19 +137,26 @@ jobs:
release/device-*.bat release/device-*.bat
- name: Docker login - name: Docker login
if: ${{ github.event_name == 'workflow_dispatch' }}
uses: docker/login-action@v2 uses: docker/login-action@v2
with: with:
username: meshtastic username: meshtastic
password: ${{ secrets.DOCKER_TOKEN }} password: ${{ secrets.DOCKER_TOKEN }}
- name: Docker setup - name: Docker setup
if: ${{ github.event_name == 'workflow_dispatch' }}
uses: docker/setup-buildx-action@v2 uses: docker/setup-buildx-action@v2
- name: Docker build and push - name: Docker build and push tagged versions
if: ${{ github.event_name == 'workflow_dispatch' }} if: ${{ github.event_name == 'workflow_dispatch' }}
uses: docker/build-push-action@v3 uses: docker/build-push-action@v3
with:
context: .
file: ./Dockerfile
push: true
tags: meshtastic/device-simulator:${{ steps.version.outputs.version }}
- name: Docker build and push
if: github.ref == 'refs/heads/master'
uses: docker/build-push-action@v3
with: with:
context: . context: .
file: ./Dockerfile file: ./Dockerfile

View File

@@ -22,8 +22,8 @@ jobs:
- name: flawfinder_scan - name: flawfinder_scan
uses: david-a-wheeler/flawfinder@2.0.19 uses: david-a-wheeler/flawfinder@2.0.19
with: with:
arguments: '--sarif ./' arguments: "--sarif ./"
output: 'flawfinder_report.sarif' output: "flawfinder_report.sarif"
# step 3 # step 3
- name: save report as pipeline artifact - name: save report as pipeline artifact

View File

@@ -6,17 +6,15 @@ on:
branches: branches:
- master - master
schedule: schedule:
- cron: '0 1 * * 6' - cron: "0 1 * * 6"
jobs: jobs:
semgrep-full: semgrep-full:
runs-on: ubuntu-latest runs-on: ubuntu-latest
container: container:
image: returntocorp/semgrep image: returntocorp/semgrep
steps: steps:
# step 1 # step 1
- name: clone application source code - name: clone application source code
uses: actions/checkout@v3 uses: actions/checkout@v3

View File

@@ -1,17 +1,14 @@
--- ---
name: Semgrep Differential Scan name: Semgrep Differential Scan
on: on: pull_request
pull_request
jobs: jobs:
semgrep-diff: semgrep-diff:
runs-on: ubuntu-latest runs-on: ubuntu-latest
container: container:
image: returntocorp/semgrep image: returntocorp/semgrep
steps: steps:
# step 1 # step 1
- name: clone application source code - name: clone application source code
uses: actions/checkout@v3 uses: actions/checkout@v3

View File

@@ -8,16 +8,17 @@ plugins:
uri: https://github.com/trunk-io/plugins uri: https://github.com/trunk-io/plugins
lint: lint:
enabled: enabled:
- git-diff-check
- gitleaks@8.15.2
- clang-format@14.0.0
- prettier@2.8.3
disabled:
- shellcheck@0.9.0 - shellcheck@0.9.0
- shfmt@3.5.0 - shfmt@3.5.0
- oxipng@8.0.0 - oxipng@8.0.0
- actionlint@1.6.22 - actionlint@1.6.22
- git-diff-check
- gitleaks@8.15.2
- markdownlint@0.33.0 - markdownlint@0.33.0
- hadolint@2.12.0 - hadolint@2.12.0
- clang-format@14.0.0
- prettier@2.8.3
- svgo@3.0.2 - svgo@3.0.2
runtimes: runtimes:
enabled: enabled:

4
.vscode/tasks.json vendored
View File

@@ -4,9 +4,7 @@
{ {
"type": "PlatformIO", "type": "PlatformIO",
"task": "Build", "task": "Build",
"problemMatcher": [ "problemMatcher": ["$platformio"],
"$platformio"
],
"group": { "group": {
"kind": "build", "kind": "build",
"isDefault": true "isDefault": true

View File

@@ -22,9 +22,9 @@ def readProps(prefsLoc):
isDirty = subprocess.check_output( isDirty = subprocess.check_output(
['git', 'diff', 'HEAD']).decode("utf-8").strip() ['git', 'diff', 'HEAD']).decode("utf-8").strip()
suffix = sha suffix = sha
if isDirty: # if isDirty:
# short for 'dirty', we want to keep our verstrings source for protobuf reasons # # short for 'dirty', we want to keep our verstrings source for protobuf reasons
suffix = sha + "-d" # suffix = sha + "-d"
verObj['long'] = "{}.{}.{}.{}".format( verObj['long'] = "{}.{}.{}.{}".format(
version["major"], version["minor"], version["build"], suffix) version["major"], version["minor"], version["build"], suffix)
except: except:

View File

@@ -1 +1,5 @@
cd protobufs && ..\nanopb-0.4.7\generator-bin\protoc.exe --nanopb_out=-v:..\src\mesh\generated\meshtastic -I=..\protobufs meshtastic\*.proto cd protobufs && ..\nanopb-0.4.7\generator-bin\protoc.exe --nanopb_out=-v:..\src\mesh\generated -I=..\protobufs ..\protobufs\meshtastic\*.proto
@REM cd ../src/mesh/generated/meshtastic
@REM sed -i 's/#include "meshtastic/#include "./g' *
@REM sed -i 's/meshtastic_//g' *

View File

@@ -10,10 +10,10 @@ echo "prebuilt binaries for your computer into nanopb-0.4.7"
cd protobufs cd protobufs
../nanopb-0.4.7/generator-bin/protoc --nanopb_out=-v:../src/mesh/generated/ -I=../protobufs meshtastic/*.proto ../nanopb-0.4.7/generator-bin/protoc --nanopb_out=-v:../src/mesh/generated/ -I=../protobufs meshtastic/*.proto
cd ../src/mesh/generated/meshtastic # cd ../src/mesh/generated/meshtastic
sed -i 's/#include "meshtastic/#include "./g' * # sed -i 's/#include "meshtastic/#include "./g' -- *
sed -i 's/meshtastic_//g' * # sed -i 's/meshtastic_//g' -- *
#echo "Regenerating protobuf documentation - if you see an error message" #echo "Regenerating protobuf documentation - if you see an error message"
#echo "you can ignore it unless doing a new protobuf release to github." #echo "you can ignore it unless doing a new protobuf release to github."

View File

@@ -7,12 +7,7 @@
"cpu": "cortex-m4", "cpu": "cortex-m4",
"extra_flags": "-DARDUINO_NRF52840_TTGO_EINK -DNRF52840_XXAA", "extra_flags": "-DARDUINO_NRF52840_TTGO_EINK -DNRF52840_XXAA",
"f_cpu": "64000000L", "f_cpu": "64000000L",
"hwids": [ "hwids": [["0x239A", "0x4405"]],
[
"0x239A",
"0x4405"
]
],
"usb_product": "TTGO_eink", "usb_product": "TTGO_eink",
"mcu": "nrf52840", "mcu": "nrf52840",
"variant": "eink0.1", "variant": "eink0.1",
@@ -30,19 +25,13 @@
"settings_addr": "0xFF000" "settings_addr": "0xFF000"
} }
}, },
"connectivity": [ "connectivity": ["bluetooth"],
"bluetooth"
],
"debug": { "debug": {
"jlink_device": "nRF52840_xxAA", "jlink_device": "nRF52840_xxAA",
"onboard_tools": [ "onboard_tools": ["jlink"],
"jlink"
],
"svd_path": "nrf52840.svd" "svd_path": "nrf52840.svd"
}, },
"frameworks": [ "frameworks": ["arduino"],
"arduino"
],
"name": "TTGO eink (Adafruit BSP)", "name": "TTGO eink (Adafruit BSP)",
"upload": { "upload": {
"maximum_ram_size": 248832, "maximum_ram_size": 248832,
@@ -50,11 +39,7 @@
"require_upload_port": true, "require_upload_port": true,
"speed": 115200, "speed": 115200,
"protocol": "jlink", "protocol": "jlink",
"protocols": [ "protocols": ["jlink", "nrfjprog", "stlink"]
"jlink",
"nrfjprog",
"stlink"
]
}, },
"url": "FIXME", "url": "FIXME",
"vendor": "TTGO" "vendor": "TTGO"

View File

@@ -9,9 +9,7 @@
"product_line": "STM32WLE5xx" "product_line": "STM32WLE5xx"
}, },
"debug": { "debug": {
"default_tools": [ "default_tools": ["stlink"],
"stlink"
],
"jlink_device": "STM32WLE5CC", "jlink_device": "STM32WLE5CC",
"openocd_target": "stm32wlx", "openocd_target": "stm32wlx",
"svd_path": "STM32WLE5_CM4.svd" "svd_path": "STM32WLE5_CM4.svd"
@@ -22,9 +20,7 @@
"maximum_ram_size": 65536, "maximum_ram_size": 65536,
"maximum_size": 262144, "maximum_size": 262144,
"protocol": "cmsis-dap", "protocol": "cmsis-dap",
"protocols": [ "protocols": ["cmsis-dap"]
"cmsis-dap"
]
}, },
"url": "https://www.st.com/en/microcontrollers-microprocessors/stm32wl-series.html", "url": "https://www.st.com/en/microcontrollers-microprocessors/stm32wl-series.html",
"vendor": "ST" "vendor": "ST"

View File

@@ -19,16 +19,12 @@
"sd_fwid": "0x00B7" "sd_fwid": "0x00B7"
} }
}, },
"connectivity": [ "connectivity": ["bluetooth"],
"bluetooth"
],
"debug": { "debug": {
"jlink_device": "nRF52832_xxAA", "jlink_device": "nRF52832_xxAA",
"svd_path": "nrf52.svd" "svd_path": "nrf52.svd"
}, },
"frameworks": [ "frameworks": ["arduino"],
"arduino"
],
"name": "lora ISP4520", "name": "lora ISP4520",
"upload": { "upload": {
"maximum_ram_size": 65536, "maximum_ram_size": 65536,
@@ -36,12 +32,7 @@
"require_upload_port": true, "require_upload_port": true,
"speed": 115200, "speed": 115200,
"protocol": "nrfutil", "protocol": "nrfutil",
"protocols": [ "protocols": ["jlink", "nrfjprog", "nrfutil", "stlink"]
"jlink",
"nrfjprog",
"nrfutil",
"stlink"
]
}, },
"url": "", "url": "",
"vendor": "PsiSoft" "vendor": "PsiSoft"

View File

@@ -8,22 +8,10 @@
"extra_flags": "-DARDUINO_NRF52840_FEATHER -DNRF52840_XXAA", "extra_flags": "-DARDUINO_NRF52840_FEATHER -DNRF52840_XXAA",
"f_cpu": "64000000L", "f_cpu": "64000000L",
"hwids": [ "hwids": [
[ ["0x239A", "0x8029"],
"0x239A", ["0x239A", "0x0029"],
"0x8029" ["0x239A", "0x002A"],
], ["0x239A", "0x802A"]
[
"0x239A",
"0x0029"
],
[
"0x239A",
"0x002A"
],
[
"0x239A",
"0x802A"
]
], ],
"usb_product": "PCA10059", "usb_product": "PCA10059",
"mcu": "nrf52840", "mcu": "nrf52840",
@@ -41,28 +29,19 @@
"settings_addr": "0xFF000" "settings_addr": "0xFF000"
} }
}, },
"connectivity": [ "connectivity": ["bluetooth"],
"bluetooth"
],
"debug": { "debug": {
"jlink_device": "nRF52840_xxAA", "jlink_device": "nRF52840_xxAA",
"svd_path": "nrf52840.svd" "svd_path": "nrf52840.svd"
}, },
"frameworks": [ "frameworks": ["arduino"],
"arduino"
],
"name": "nRF52840 Dongle", "name": "nRF52840 Dongle",
"upload": { "upload": {
"maximum_ram_size": 248832, "maximum_ram_size": 248832,
"maximum_size": 815104, "maximum_size": 815104,
"speed": 115200, "speed": 115200,
"protocol": "nrfutil", "protocol": "nrfutil",
"protocols": [ "protocols": ["jlink", "nrfjprog", "nrfutil", "stlink"],
"jlink",
"nrfjprog",
"nrfutil",
"stlink"
],
"use_1200bps_touch": true, "use_1200bps_touch": true,
"require_upload_port": true, "require_upload_port": true,
"wait_for_upload_port": true "wait_for_upload_port": true

View File

@@ -44,4 +44,3 @@
"url": "https://meshtastic.org/", "url": "https://meshtastic.org/",
"vendor": "Nordic Semi" "vendor": "Nordic Semi"
} }

View File

@@ -7,12 +7,7 @@
"cpu": "cortex-m4", "cpu": "cortex-m4",
"extra_flags": "-DARDUINO_NRF52840_TTGO_EINK -DNRF52840_XXAA", "extra_flags": "-DARDUINO_NRF52840_TTGO_EINK -DNRF52840_XXAA",
"f_cpu": "64000000L", "f_cpu": "64000000L",
"hwids": [ "hwids": [["0x239A", "0x4405"]],
[
"0x239A",
"0x4405"
]
],
"usb_product": "TTGO_eink", "usb_product": "TTGO_eink",
"mcu": "nrf52840", "mcu": "nrf52840",
"variant": "t-echo", "variant": "t-echo",
@@ -30,31 +25,20 @@
"settings_addr": "0xFF000" "settings_addr": "0xFF000"
} }
}, },
"connectivity": [ "connectivity": ["bluetooth"],
"bluetooth"
],
"debug": { "debug": {
"jlink_device": "nRF52840_xxAA", "jlink_device": "nRF52840_xxAA",
"onboard_tools": [ "onboard_tools": ["jlink"],
"jlink"
],
"svd_path": "nrf52840.svd" "svd_path": "nrf52840.svd"
}, },
"frameworks": [ "frameworks": ["arduino"],
"arduino"
],
"name": "TTGO eink (Adafruit BSP)", "name": "TTGO eink (Adafruit BSP)",
"upload": { "upload": {
"maximum_ram_size": 248832, "maximum_ram_size": 248832,
"maximum_size": 815104, "maximum_size": 815104,
"speed": 115200, "speed": 115200,
"protocol": "nrfutil", "protocol": "nrfutil",
"protocols": [ "protocols": ["jlink", "nrfjprog", "nrfutil", "stlink"],
"jlink",
"nrfjprog",
"nrfutil",
"stlink"
],
"use_1200bps_touch": true, "use_1200bps_touch": true,
"require_upload_port": true, "require_upload_port": true,
"wait_for_upload_port": true "wait_for_upload_port": true

View File

@@ -15,24 +15,15 @@
"f_cpu": "240000000L", "f_cpu": "240000000L",
"f_flash": "80000000L", "f_flash": "80000000L",
"flash_mode": "dio", "flash_mode": "dio",
"hwids": [ "hwids": [["0X303A", "0x1001"]],
[
"0X303A",
"0x1001"
]
],
"mcu": "esp32s3", "mcu": "esp32s3",
"variant": "tbeam-s3-core" "variant": "tbeam-s3-core"
}, },
"connectivity": [ "connectivity": ["wifi"],
"wifi"
],
"debug": { "debug": {
"openocd_target": "esp32s3.cfg" "openocd_target": "esp32s3.cfg"
}, },
"frameworks": [ "frameworks": ["arduino"],
"arduino"
],
"name": "LilyGo TBeam-S3-Core", "name": "LilyGo TBeam-S3-Core",
"upload": { "upload": {
"flash_size": "8MB", "flash_size": "8MB",

View File

@@ -14,25 +14,15 @@
"f_cpu": "240000000L", "f_cpu": "240000000L",
"f_flash": "80000000L", "f_flash": "80000000L",
"flash_mode": "dio", "flash_mode": "dio",
"hwids": [ "hwids": [["0X303A", "0x1001"]],
[
"0X303A",
"0x1001"
]
],
"mcu": "esp32s3", "mcu": "esp32s3",
"variant": "tlora-t3s3-v1" "variant": "tlora-t3s3-v1"
}, },
"connectivity": [ "connectivity": ["wifi"],
"wifi"
],
"debug": { "debug": {
"openocd_target": "esp32s3.cfg" "openocd_target": "esp32s3.cfg"
}, },
"frameworks": [ "frameworks": ["arduino", "espidf"],
"arduino",
"espidf"
],
"name": "LilyGo TLora-T3S3-V1", "name": "LilyGo TLora-T3S3-V1",
"upload": { "upload": {
"flash_size": "4MB", "flash_size": "4MB",

View File

@@ -11,26 +11,14 @@
"mcu": "esp32", "mcu": "esp32",
"variant": "WisCore_RAK11200_Board" "variant": "WisCore_RAK11200_Board"
}, },
"connectivity": [ "connectivity": ["wifi", "bluetooth", "ethernet", "can"],
"wifi", "frameworks": ["arduino", "espidf"],
"bluetooth",
"ethernet",
"can"
],
"frameworks": [
"arduino",
"espidf"
],
"name": "WisCore RAK11200 Board", "name": "WisCore RAK11200 Board",
"upload": { "upload": {
"flash_size": "4MB", "flash_size": "4MB",
"maximum_ram_size": 327680, "maximum_ram_size": 327680,
"maximum_size": 4194304, "maximum_size": 4194304,
"protocols": [ "protocols": ["esptool", "espota", "ftdi"],
"esptool",
"espota",
"ftdi"
],
"require_upload_port": true, "require_upload_port": true,
"speed": 460800 "speed": 460800
}, },

View File

@@ -8,22 +8,10 @@
"extra_flags": "-DNRF52832_XXAA -DNRF52", "extra_flags": "-DNRF52832_XXAA -DNRF52",
"f_cpu": "64000000L", "f_cpu": "64000000L",
"hwids": [ "hwids": [
[ ["0x239A", "0x8029"],
"0x239A", ["0x239A", "0x0029"],
"0x8029" ["0x239A", "0x002A"],
], ["0x239A", "0x802A"]
[
"0x239A",
"0x0029"
],
[
"0x239A",
"0x002A"
],
[
"0x239A",
"0x802A"
]
], ],
"usb_product": "Feather nRF52832 Express", "usb_product": "Feather nRF52832 Express",
"mcu": "nrf52832", "mcu": "nrf52832",
@@ -41,17 +29,12 @@
"variant": "nrf52_adafruit_feather" "variant": "nrf52_adafruit_feather"
} }
}, },
"connectivity": [ "connectivity": ["bluetooth"],
"bluetooth"
],
"debug": { "debug": {
"jlink_device": "nRF52832_xxAA", "jlink_device": "nRF52832_xxAA",
"svd_path": "nrf52.svd" "svd_path": "nrf52.svd"
}, },
"frameworks": [ "frameworks": ["arduino", "zephyr"],
"arduino",
"zephyr"
],
"name": "Adafruit Bluefruit nRF52832 Feather", "name": "Adafruit Bluefruit nRF52832 Feather",
"upload": { "upload": {
"maximum_ram_size": 65536, "maximum_ram_size": 65536,
@@ -59,12 +42,7 @@
"require_upload_port": true, "require_upload_port": true,
"speed": 115200, "speed": 115200,
"protocol": "nrfutil", "protocol": "nrfutil",
"protocols": [ "protocols": ["jlink", "nrfjprog", "nrfutil", "stlink"]
"jlink",
"nrfjprog",
"nrfutil",
"stlink"
]
}, },
"url": "https://www.adafruit.com/product/3406", "url": "https://www.adafruit.com/product/3406",
"vendor": "Adafruit" "vendor": "Adafruit"

View File

@@ -8,22 +8,10 @@
"extra_flags": "-DARDUINO_NRF52840_FEATHER -DNRF52840_XXAA", "extra_flags": "-DARDUINO_NRF52840_FEATHER -DNRF52840_XXAA",
"f_cpu": "64000000L", "f_cpu": "64000000L",
"hwids": [ "hwids": [
[ ["0x239A", "0x8029"],
"0x239A", ["0x239A", "0x0029"],
"0x8029" ["0x239A", "0x002A"],
], ["0x239A", "0x802A"]
[
"0x239A",
"0x0029"
],
[
"0x239A",
"0x002A"
],
[
"0x239A",
"0x802A"
]
], ],
"usb_product": "WisCore RAK4631 Board", "usb_product": "WisCore RAK4631 Board",
"mcu": "nrf52840", "mcu": "nrf52840",
@@ -41,28 +29,19 @@
"settings_addr": "0xFF000" "settings_addr": "0xFF000"
} }
}, },
"connectivity": [ "connectivity": ["bluetooth"],
"bluetooth"
],
"debug": { "debug": {
"jlink_device": "nRF52840_xxAA", "jlink_device": "nRF52840_xxAA",
"svd_path": "nrf52840.svd" "svd_path": "nrf52840.svd"
}, },
"frameworks": [ "frameworks": ["arduino"],
"arduino"
],
"name": "WisCore RAK4631 Board", "name": "WisCore RAK4631 Board",
"upload": { "upload": {
"maximum_ram_size": 248832, "maximum_ram_size": 248832,
"maximum_size": 815104, "maximum_size": 815104,
"speed": 115200, "speed": 115200,
"protocol": "nrfutil", "protocol": "nrfutil",
"protocols": [ "protocols": ["jlink", "nrfjprog", "nrfutil", "stlink"],
"jlink",
"nrfjprog",
"nrfutil",
"stlink"
],
"use_1200bps_touch": true, "use_1200bps_touch": true,
"require_upload_port": true, "require_upload_port": true,
"wait_for_upload_port": true "wait_for_upload_port": true

View File

@@ -39,7 +39,7 @@ extra_scripts = bin/platformio-custom.py
; The Radiolib stuff will speed up building considerably. Exclud all the stuff we dont need. ; The Radiolib stuff will speed up building considerably. Exclud all the stuff we dont need.
build_flags = -Wno-missing-field-initializers build_flags = -Wno-missing-field-initializers
-Wno-format -Wno-format
-Isrc -Isrc/mesh -Isrc/gps -Isrc/buzz -Wl,-Map,.pio/build/output.map -Isrc -Isrc/mesh -Isrc/mesh/generated -Isrc/gps -Isrc/buzz -Wl,-Map,.pio/build/output.map
-DUSE_THREAD_NAMES -DUSE_THREAD_NAMES
-DTINYGPS_OPTION_NO_CUSTOM_FIELDS -DTINYGPS_OPTION_NO_CUSTOM_FIELDS
-DPB_ENABLE_MALLOC=1 -DPB_ENABLE_MALLOC=1
@@ -58,7 +58,7 @@ build_flags = -Wno-missing-field-initializers
monitor_speed = 115200 monitor_speed = 115200
lib_deps = lib_deps =
https://github.com/meshtastic/esp8266-oled-ssd1306.git#53580644255b48ebb7a737343c6b4e71c7e11cf2 ; ESP8266_SSD1306 https://github.com/meshtastic/esp8266-oled-ssd1306.git#da1ede4dfcd91074283b029080759fd744120909 ; ESP8266_SSD1306
mathertel/OneButton@^2.0.3 ; OneButton library for non-blocking button debounce mathertel/OneButton@^2.0.3 ; OneButton library for non-blocking button debounce
https://github.com/meshtastic/arduino-fsm.git#7db3702bf0cfe97b783d6c72595e3f38e0b19159 https://github.com/meshtastic/arduino-fsm.git#7db3702bf0cfe97b783d6c72595e3f38e0b19159
https://github.com/meshtastic/TinyGPSPlus.git#127ad674ef85f0201cb68a065879653ed94792c4 https://github.com/meshtastic/TinyGPSPlus.git#127ad674ef85f0201cb68a065879653ed94792c4
@@ -66,7 +66,7 @@ lib_deps =
nanopb/Nanopb@^0.4.6 nanopb/Nanopb@^0.4.6
erriez/ErriezCRC32@^1.0.1 erriez/ErriezCRC32@^1.0.1
; jgromes/RadioLib@^5.5.1 ; jgromes/RadioLib@^5.5.1
https://github.com/jgromes/RadioLib.git#395844922c5d88d5db0481a9c91479931172428d https://github.com/jgromes/RadioLib.git#1afa947030c5637f71f6563bc22aa75032e53a57
; Used for the code analysis in PIO Home / Inspect ; Used for the code analysis in PIO Home / Inspect
check_tool = cppcheck check_tool = cppcheck

View File

@@ -1,5 +1,5 @@
#include "configuration.h"
#include "BluetoothCommon.h" #include "BluetoothCommon.h"
#include "configuration.h"
// NRF52 wants these constants as byte arrays // NRF52 wants these constants as byte arrays
// Generated here https://yupana-engineering.com/online-uuid-to-c-array-converter - but in REVERSE BYTE ORDER // Generated here https://yupana-engineering.com/online-uuid-to-c-array-converter - but in REVERSE BYTE ORDER

View File

@@ -115,8 +115,7 @@ class ButtonThread : public concurrency::OSThread
{ {
// LOG_DEBUG("press!\n"); // LOG_DEBUG("press!\n");
#ifdef BUTTON_PIN #ifdef BUTTON_PIN
if ((BUTTON_PIN != moduleConfig.canned_message.inputbroker_pin_press) || if ((BUTTON_PIN != moduleConfig.canned_message.inputbroker_pin_press) || !moduleConfig.canned_message.enabled) {
!moduleConfig.canned_message.enabled) {
powerFSM.trigger(EVENT_PRESS); powerFSM.trigger(EVENT_PRESS);
} }
#endif #endif
@@ -163,13 +162,17 @@ class ButtonThread : public concurrency::OSThread
#if defined(USE_EINK) && defined(PIN_EINK_EN) #if defined(USE_EINK) && defined(PIN_EINK_EN)
digitalWrite(PIN_EINK_EN, digitalRead(PIN_EINK_EN) == LOW); digitalWrite(PIN_EINK_EN, digitalRead(PIN_EINK_EN) == LOW);
#endif #endif
#if defined(GPS_POWER_TOGGLE) screen->print("Sent ad-hoc ping\n");
if(config.position.gps_enabled) service.refreshMyNodeInfo();
{ service.sendNetworkPing(NODENUM_BROADCAST, true);
LOG_DEBUG("Flag set to false for gps power\n");
} }
else
static void userButtonMultiPressed()
{ {
#if defined(GPS_POWER_TOGGLE)
if (config.position.gps_enabled) {
LOG_DEBUG("Flag set to false for gps power\n");
} else {
LOG_DEBUG("Flag set to true to restore power\n"); LOG_DEBUG("Flag set to true to restore power\n");
} }
config.position.gps_enabled = !(config.position.gps_enabled); config.position.gps_enabled = !(config.position.gps_enabled);
@@ -177,13 +180,6 @@ class ButtonThread : public concurrency::OSThread
#endif #endif
} }
static void userButtonMultiPressed()
{
screen->print("Sent ad-hoc ping\n");
service.refreshMyNodeInfo();
service.sendNetworkPing(NODENUM_BROADCAST, true);
}
static void userButtonPressedLongStart() static void userButtonPressedLongStart()
{ {
if (millis() > 30 * 1000) { if (millis() > 30 * 1000) {

View File

@@ -1,17 +1,15 @@
#include "configuration.h"
#include "FSCommon.h" #include "FSCommon.h"
#include "configuration.h"
#ifdef HAS_SDCARD #ifdef HAS_SDCARD
#include <SPI.h>
#include <SD.h> #include <SD.h>
#include <SPI.h>
#ifdef SDCARD_USE_SPI1 #ifdef SDCARD_USE_SPI1
SPIClass SPI1(HSPI); SPIClass SPI1(HSPI);
#define SDHandler SPI1 #define SDHandler SPI1
#endif #endif
#endif // HAS_SDCARD #endif // HAS_SDCARD
bool copyFile(const char *from, const char *to) bool copyFile(const char *from, const char *to)
@@ -168,8 +166,7 @@ void rmDir(const char * dirname)
void fsInit() void fsInit()
{ {
#ifdef FSCom #ifdef FSCom
if (!FSBegin()) if (!FSBegin()) {
{
LOG_ERROR("Filesystem mount Failed.\n"); LOG_ERROR("Filesystem mount Failed.\n");
// assert(0); This auto-formats the partition, so no need to fail here. // assert(0); This auto-formats the partition, so no need to fail here.
} }
@@ -182,7 +179,6 @@ void fsInit()
#endif #endif
} }
void setupSDCard() void setupSDCard()
{ {
#ifdef HAS_SDCARD #ifdef HAS_SDCARD
@@ -214,6 +210,3 @@ void setupSDCard()
LOG_DEBUG("Used space: %llu MB\n", SD.usedBytes() / (1024 * 1024)); LOG_DEBUG("Used space: %llu MB\n", SD.usedBytes() / (1024 * 1024));
#endif #endif
} }

View File

@@ -22,13 +22,13 @@ class GPSStatus : public Status
bool isPowerSaving = false; // Are we in power saving state bool isPowerSaving = false; // Are we in power saving state
Position p = Position_init_default; meshtastic_Position p = meshtastic_Position_init_default;
public: public:
GPSStatus() { statusType = STATUS_TYPE_GPS; } GPSStatus() { statusType = STATUS_TYPE_GPS; }
// preferred method // preferred method
GPSStatus(bool hasLock, bool isConnected, bool isPowerSaving, const Position &pos) : Status() GPSStatus(bool hasLock, bool isConnected, bool isPowerSaving, const meshtastic_Position &pos) : Status()
{ {
this->hasLock = hasLock; this->hasLock = hasLock;
this->isConnected = isConnected; this->isConnected = isConnected;
@@ -55,7 +55,7 @@ class GPSStatus : public Status
#ifdef GPS_EXTRAVERBOSE #ifdef GPS_EXTRAVERBOSE
LOG_WARN("Using fixed latitude\n"); LOG_WARN("Using fixed latitude\n");
#endif #endif
NodeInfo *node = nodeDB.getNode(nodeDB.getNodeNum()); meshtastic_NodeInfo *node = nodeDB.getNode(nodeDB.getNodeNum());
return node->position.latitude_i; return node->position.latitude_i;
} else { } else {
return p.latitude_i; return p.latitude_i;
@@ -68,7 +68,7 @@ class GPSStatus : public Status
#ifdef GPS_EXTRAVERBOSE #ifdef GPS_EXTRAVERBOSE
LOG_WARN("Using fixed longitude\n"); LOG_WARN("Using fixed longitude\n");
#endif #endif
NodeInfo *node = nodeDB.getNode(nodeDB.getNodeNum()); meshtastic_NodeInfo *node = nodeDB.getNode(nodeDB.getNodeNum());
return node->position.longitude_i; return node->position.longitude_i;
} else { } else {
return p.longitude_i; return p.longitude_i;
@@ -81,29 +81,38 @@ class GPSStatus : public Status
#ifdef GPS_EXTRAVERBOSE #ifdef GPS_EXTRAVERBOSE
LOG_WARN("Using fixed altitude\n"); LOG_WARN("Using fixed altitude\n");
#endif #endif
NodeInfo *node = nodeDB.getNode(nodeDB.getNodeNum()); meshtastic_NodeInfo *node = nodeDB.getNode(nodeDB.getNodeNum());
return node->position.altitude; return node->position.altitude;
} else { } else {
return p.altitude; return p.altitude;
} }
} }
uint32_t getDOP() const { return p.PDOP; } uint32_t getDOP() const
{
return p.PDOP;
}
uint32_t getHeading() const { return p.ground_track; } uint32_t getHeading() const
{
return p.ground_track;
}
uint32_t getNumSatellites() const { return p.sats_in_view; } uint32_t getNumSatellites() const
{
return p.sats_in_view;
}
bool matches(const GPSStatus *newStatus) const bool matches(const GPSStatus *newStatus) const
{ {
#ifdef GPS_EXTRAVERBOSE #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.pos_timestamp, p.pos_timestamp);
#endif #endif
return (newStatus->hasLock != hasLock || newStatus->isConnected != isConnected || newStatus->isPowerSaving !=isPowerSaving || return (newStatus->hasLock != hasLock || newStatus->isConnected != isConnected ||
newStatus->p.latitude_i != p.latitude_i || newStatus->p.longitude_i != p.longitude_i || newStatus->isPowerSaving != isPowerSaving || newStatus->p.latitude_i != p.latitude_i ||
newStatus->p.altitude != p.altitude || newStatus->p.altitude_hae != p.altitude_hae || newStatus->p.longitude_i != p.longitude_i || newStatus->p.altitude != p.altitude ||
newStatus->p.PDOP != p.PDOP || newStatus->p.ground_track != p.ground_track || newStatus->p.altitude_hae != p.altitude_hae || newStatus->p.PDOP != p.PDOP ||
newStatus->p.ground_speed != p.ground_speed || newStatus->p.ground_track != p.ground_track || newStatus->p.ground_speed != p.ground_speed ||
newStatus->p.sats_in_view != p.sats_in_view); newStatus->p.sats_in_view != p.sats_in_view);
} }

View File

@@ -1,16 +1,18 @@
#pragma once #pragma once
#include <Arduino.h>
#include "Status.h" #include "Status.h"
#include "configuration.h" #include "configuration.h"
#include <Arduino.h>
namespace meshtastic { namespace meshtastic
{
/// Describes the state of the NodeDB system. /// Describes the state of the NodeDB system.
class NodeStatus : public Status class NodeStatus : public Status
{ {
private: private:
CallbackObserver<NodeStatus, const NodeStatus *> statusObserver = CallbackObserver<NodeStatus, const NodeStatus *>(this, &NodeStatus::updateStatus); CallbackObserver<NodeStatus, const NodeStatus *> statusObserver =
CallbackObserver<NodeStatus, const NodeStatus *>(this, &NodeStatus::updateStatus);
uint8_t numOnline = 0; uint8_t numOnline = 0;
uint8_t numTotal = 0; uint8_t numTotal = 0;
@@ -20,9 +22,7 @@ namespace meshtastic {
public: public:
bool forceUpdate = false; bool forceUpdate = false;
NodeStatus() { NodeStatus() { statusType = STATUS_TYPE_NODE; }
statusType = STATUS_TYPE_NODE;
}
NodeStatus(uint8_t numOnline, uint8_t numTotal, bool forceUpdate = false) : Status() NodeStatus(uint8_t numOnline, uint8_t numTotal, bool forceUpdate = false) : Status()
{ {
this->forceUpdate = forceUpdate; this->forceUpdate = forceUpdate;
@@ -32,34 +32,20 @@ namespace meshtastic {
NodeStatus(const NodeStatus &); NodeStatus(const NodeStatus &);
NodeStatus &operator=(const NodeStatus &); NodeStatus &operator=(const NodeStatus &);
void observe(Observable<const NodeStatus *> *source) void observe(Observable<const NodeStatus *> *source) { statusObserver.observe(source); }
{
statusObserver.observe(source);
}
uint8_t getNumOnline() const uint8_t getNumOnline() const { return numOnline; }
{
return numOnline;
}
uint8_t getNumTotal() const uint8_t getNumTotal() const { return numTotal; }
{
return numTotal;
}
uint8_t getLastNumTotal() const uint8_t getLastNumTotal() const { return lastNumTotal; }
{
return lastNumTotal;
}
bool matches(const NodeStatus *newStatus) const bool matches(const NodeStatus *newStatus) const
{ {
return ( return (newStatus->getNumOnline() != numOnline || newStatus->getNumTotal() != numTotal);
newStatus->getNumOnline() != numOnline ||
newStatus->getNumTotal() != numTotal
);
} }
int updateStatus(const NodeStatus *newStatus) { int updateStatus(const NodeStatus *newStatus)
{
// Only update the status if values have actually changed // Only update the status if values have actually changed
lastNumTotal = numTotal; lastNumTotal = numTotal;
bool isDirty; bool isDirty;
@@ -75,9 +61,8 @@ namespace meshtastic {
} }
return 0; return 0;
} }
}; };
} } // namespace meshtastic
extern meshtastic::NodeStatus *nodeStatus; extern meshtastic::NodeStatus *nodeStatus;

View File

@@ -1,5 +1,5 @@
#include "configuration.h"
#include "OSTimer.h" #include "OSTimer.h"
#include "configuration.h"
/** /**
* Schedule a callback to run. The callback must _not_ block, though it is called from regular thread level (not ISR) * Schedule a callback to run. The callback must _not_ block, though it is called from regular thread level (not ISR)

View File

@@ -1,3 +1,2 @@
#include "configuration.h"
#include "Observer.h" #include "Observer.h"
#include "configuration.h"

View File

@@ -1,16 +1,16 @@
#include "power.h" #include "power.h"
#include "NodeDB.h" #include "NodeDB.h"
#include "PowerFSM.h" #include "PowerFSM.h"
#include "buzz/buzz.h"
#include "configuration.h" #include "configuration.h"
#include "main.h" #include "main.h"
#include "sleep.h" #include "sleep.h"
#include "utils.h" #include "utils.h"
#include "buzz/buzz.h"
#ifdef HAS_PMU #ifdef HAS_PMU
#include "XPowersLibInterface.hpp"
#include "XPowersAXP2101.tpp"
#include "XPowersAXP192.tpp" #include "XPowersAXP192.tpp"
#include "XPowersAXP2101.tpp"
#include "XPowersLibInterface.hpp"
XPowersLibInterface *PMU = NULL; XPowersLibInterface *PMU = NULL;
#else #else
// Copy of the base class defined in axp20x.h. // Copy of the base class defined in axp20x.h.
@@ -108,15 +108,15 @@ class AnalogBatteryLevel : public HasBatteryLevel
#ifdef BATTERY_PIN #ifdef BATTERY_PIN
// Override variant or default ADC_MULTIPLIER if we have the override pref // Override variant or default ADC_MULTIPLIER if we have the override pref
float operativeAdcMultiplier = config.power.adc_multiplier_override > 0 float operativeAdcMultiplier =
? config.power.adc_multiplier_override config.power.adc_multiplier_override > 0 ? config.power.adc_multiplier_override : ADC_MULTIPLIER;
: ADC_MULTIPLIER;
// Do not call analogRead() often. // Do not call analogRead() often.
const uint32_t min_read_interval = 5000; const uint32_t min_read_interval = 5000;
if (millis() - last_read_time_ms > min_read_interval) { if (millis() - last_read_time_ms > min_read_interval) {
last_read_time_ms = millis(); last_read_time_ms = millis();
//Set the number of samples, it has an effect of increasing sensitivity, especially in complex electromagnetic environment. // Set the number of samples, it has an effect of increasing sensitivity, especially in complex electromagnetic
// environment.
uint32_t raw = 0; uint32_t raw = 0;
for (uint32_t i = 0; i < BATTERY_SENSE_SAMPLES; i++) { for (uint32_t i = 0; i < BATTERY_SENSE_SAMPLES; i++) {
raw += analogRead(BATTERY_PIN); raw += analogRead(BATTERY_PIN);
@@ -143,15 +143,24 @@ class AnalogBatteryLevel : public HasBatteryLevel
/** /**
* return true if there is a battery installed in this unit * return true if there is a battery installed in this unit
*/ */
virtual bool isBatteryConnect() override { return getBatteryPercent() != -1; } virtual bool isBatteryConnect() override
{
return getBatteryPercent() != -1;
}
/// If we see a battery voltage higher than physics allows - assume charger is pumping /// If we see a battery voltage higher than physics allows - assume charger is pumping
/// in power /// in power
virtual bool isVbusIn() override { return getBattVoltage() > chargingVolt; } virtual bool isVbusIn() override
{
return getBattVoltage() > chargingVolt;
}
/// Assume charging if we have a battery and external power is connected. /// Assume charging if we have a battery and external power is connected.
/// we can't be smart enough to say 'full'? /// we can't be smart enough to say 'full'?
virtual bool isCharging() override { return isBatteryConnect() && isVbusIn(); } virtual bool isCharging() override
{
return isBatteryConnect() && isVbusIn();
}
private: private:
/// If we see a battery voltage higher than physics allows - assume charger is pumping /// If we see a battery voltage higher than physics allows - assume charger is pumping
@@ -298,7 +307,8 @@ void Power::readPowerStatus()
} }
} }
LOG_DEBUG("\n"); LOG_DEBUG("\n");
LOG_DEBUG("Heap status: %d/%d bytes free (%d), running %d/%d threads\n", ESP.getFreeHeap(), ESP.getHeapSize(), ESP.getFreeHeap() - lastheap, running, concurrency::mainController.size(false)); LOG_DEBUG("Heap status: %d/%d bytes free (%d), running %d/%d threads\n", ESP.getFreeHeap(), ESP.getHeapSize(),
ESP.getFreeHeap() - lastheap, running, concurrency::mainController.size(false));
lastheap = ESP.getFreeHeap(); lastheap = ESP.getFreeHeap();
} }
#endif #endif
@@ -450,7 +460,6 @@ bool Power::axpChipInit()
PMU->setPowerChannelVoltage(XPOWERS_LDO2, 3300); PMU->setPowerChannelVoltage(XPOWERS_LDO2, 3300);
PMU->enablePowerOutput(XPOWERS_LDO2); PMU->enablePowerOutput(XPOWERS_LDO2);
// oled module power channel, // oled module power channel,
// disable it will cause abnormal communication between boot and AXP power supply, // disable it will cause abnormal communication between boot and AXP power supply,
// do not turn it off // do not turn it off
@@ -458,12 +467,10 @@ bool Power::axpChipInit()
// enable oled power // enable oled power
PMU->enablePowerOutput(XPOWERS_DCDC1); PMU->enablePowerOutput(XPOWERS_DCDC1);
// gnss module power channel - now turned on in setGpsPower // gnss module power channel - now turned on in setGpsPower
PMU->setPowerChannelVoltage(XPOWERS_LDO3, 3300); PMU->setPowerChannelVoltage(XPOWERS_LDO3, 3300);
// PMU->enablePowerOutput(XPOWERS_LDO3); // PMU->enablePowerOutput(XPOWERS_LDO3);
// protected oled power source // protected oled power source
PMU->setProtectedChannel(XPOWERS_DCDC1); PMU->setProtectedChannel(XPOWERS_DCDC1);
// protected esp32 power source // protected esp32 power source
@@ -537,7 +544,6 @@ bool Power::axpChipInit()
PMU->setChargeTargetVoltage(XPOWERS_AXP2101_CHG_VOL_4V2); PMU->setChargeTargetVoltage(XPOWERS_AXP2101_CHG_VOL_4V2);
} }
PMU->clearIrqStatus(); PMU->clearIrqStatus();
// TBeam1.1 /T-Beam S3-Core has no external TS detection, // TBeam1.1 /T-Beam S3-Core has no external TS detection,
@@ -550,40 +556,52 @@ bool Power::axpChipInit()
LOG_DEBUG("=======================================================================\n"); LOG_DEBUG("=======================================================================\n");
if (PMU->isChannelAvailable(XPOWERS_DCDC1)) { if (PMU->isChannelAvailable(XPOWERS_DCDC1)) {
LOG_DEBUG("DC1 : %s Voltage:%u mV \n", PMU->isPowerChannelEnable(XPOWERS_DCDC1) ? "+" : "-", PMU->getPowerChannelVoltage(XPOWERS_DCDC1)); LOG_DEBUG("DC1 : %s Voltage:%u mV \n", PMU->isPowerChannelEnable(XPOWERS_DCDC1) ? "+" : "-",
PMU->getPowerChannelVoltage(XPOWERS_DCDC1));
} }
if (PMU->isChannelAvailable(XPOWERS_DCDC2)) { if (PMU->isChannelAvailable(XPOWERS_DCDC2)) {
LOG_DEBUG("DC2 : %s Voltage:%u mV \n", PMU->isPowerChannelEnable(XPOWERS_DCDC2) ? "+" : "-", PMU->getPowerChannelVoltage(XPOWERS_DCDC2)); LOG_DEBUG("DC2 : %s Voltage:%u mV \n", PMU->isPowerChannelEnable(XPOWERS_DCDC2) ? "+" : "-",
PMU->getPowerChannelVoltage(XPOWERS_DCDC2));
} }
if (PMU->isChannelAvailable(XPOWERS_DCDC3)) { if (PMU->isChannelAvailable(XPOWERS_DCDC3)) {
LOG_DEBUG("DC3 : %s Voltage:%u mV \n", PMU->isPowerChannelEnable(XPOWERS_DCDC3) ? "+" : "-", PMU->getPowerChannelVoltage(XPOWERS_DCDC3)); LOG_DEBUG("DC3 : %s Voltage:%u mV \n", PMU->isPowerChannelEnable(XPOWERS_DCDC3) ? "+" : "-",
PMU->getPowerChannelVoltage(XPOWERS_DCDC3));
} }
if (PMU->isChannelAvailable(XPOWERS_DCDC4)) { if (PMU->isChannelAvailable(XPOWERS_DCDC4)) {
LOG_DEBUG("DC4 : %s Voltage:%u mV \n", PMU->isPowerChannelEnable(XPOWERS_DCDC4) ? "+" : "-", PMU->getPowerChannelVoltage(XPOWERS_DCDC4)); LOG_DEBUG("DC4 : %s Voltage:%u mV \n", PMU->isPowerChannelEnable(XPOWERS_DCDC4) ? "+" : "-",
PMU->getPowerChannelVoltage(XPOWERS_DCDC4));
} }
if (PMU->isChannelAvailable(XPOWERS_LDO2)) { if (PMU->isChannelAvailable(XPOWERS_LDO2)) {
LOG_DEBUG("LDO2 : %s Voltage:%u mV \n", PMU->isPowerChannelEnable(XPOWERS_LDO2) ? "+" : "-", PMU->getPowerChannelVoltage(XPOWERS_LDO2)); LOG_DEBUG("LDO2 : %s Voltage:%u mV \n", PMU->isPowerChannelEnable(XPOWERS_LDO2) ? "+" : "-",
PMU->getPowerChannelVoltage(XPOWERS_LDO2));
} }
if (PMU->isChannelAvailable(XPOWERS_LDO3)) { if (PMU->isChannelAvailable(XPOWERS_LDO3)) {
LOG_DEBUG("LDO3 : %s Voltage:%u mV \n", PMU->isPowerChannelEnable(XPOWERS_LDO3) ? "+" : "-", PMU->getPowerChannelVoltage(XPOWERS_LDO3)); LOG_DEBUG("LDO3 : %s Voltage:%u mV \n", PMU->isPowerChannelEnable(XPOWERS_LDO3) ? "+" : "-",
PMU->getPowerChannelVoltage(XPOWERS_LDO3));
} }
if (PMU->isChannelAvailable(XPOWERS_ALDO1)) { if (PMU->isChannelAvailable(XPOWERS_ALDO1)) {
LOG_DEBUG("ALDO1: %s Voltage:%u mV \n", PMU->isPowerChannelEnable(XPOWERS_ALDO1) ? "+" : "-", PMU->getPowerChannelVoltage(XPOWERS_ALDO1)); LOG_DEBUG("ALDO1: %s Voltage:%u mV \n", PMU->isPowerChannelEnable(XPOWERS_ALDO1) ? "+" : "-",
PMU->getPowerChannelVoltage(XPOWERS_ALDO1));
} }
if (PMU->isChannelAvailable(XPOWERS_ALDO2)) { if (PMU->isChannelAvailable(XPOWERS_ALDO2)) {
LOG_DEBUG("ALDO2: %s Voltage:%u mV \n", PMU->isPowerChannelEnable(XPOWERS_ALDO2) ? "+" : "-", PMU->getPowerChannelVoltage(XPOWERS_ALDO2)); LOG_DEBUG("ALDO2: %s Voltage:%u mV \n", PMU->isPowerChannelEnable(XPOWERS_ALDO2) ? "+" : "-",
PMU->getPowerChannelVoltage(XPOWERS_ALDO2));
} }
if (PMU->isChannelAvailable(XPOWERS_ALDO3)) { if (PMU->isChannelAvailable(XPOWERS_ALDO3)) {
LOG_DEBUG("ALDO3: %s Voltage:%u mV \n", PMU->isPowerChannelEnable(XPOWERS_ALDO3) ? "+" : "-", PMU->getPowerChannelVoltage(XPOWERS_ALDO3)); LOG_DEBUG("ALDO3: %s Voltage:%u mV \n", PMU->isPowerChannelEnable(XPOWERS_ALDO3) ? "+" : "-",
PMU->getPowerChannelVoltage(XPOWERS_ALDO3));
} }
if (PMU->isChannelAvailable(XPOWERS_ALDO4)) { if (PMU->isChannelAvailable(XPOWERS_ALDO4)) {
LOG_DEBUG("ALDO4: %s Voltage:%u mV \n", PMU->isPowerChannelEnable(XPOWERS_ALDO4) ? "+" : "-", PMU->getPowerChannelVoltage(XPOWERS_ALDO4)); LOG_DEBUG("ALDO4: %s Voltage:%u mV \n", PMU->isPowerChannelEnable(XPOWERS_ALDO4) ? "+" : "-",
PMU->getPowerChannelVoltage(XPOWERS_ALDO4));
} }
if (PMU->isChannelAvailable(XPOWERS_BLDO1)) { if (PMU->isChannelAvailable(XPOWERS_BLDO1)) {
LOG_DEBUG("BLDO1: %s Voltage:%u mV \n", PMU->isPowerChannelEnable(XPOWERS_BLDO1) ? "+" : "-", PMU->getPowerChannelVoltage(XPOWERS_BLDO1)); LOG_DEBUG("BLDO1: %s Voltage:%u mV \n", PMU->isPowerChannelEnable(XPOWERS_BLDO1) ? "+" : "-",
PMU->getPowerChannelVoltage(XPOWERS_BLDO1));
} }
if (PMU->isChannelAvailable(XPOWERS_BLDO2)) { if (PMU->isChannelAvailable(XPOWERS_BLDO2)) {
LOG_DEBUG("BLDO2: %s Voltage:%u mV \n", PMU->isPowerChannelEnable(XPOWERS_BLDO2) ? "+" : "-", PMU->getPowerChannelVoltage(XPOWERS_BLDO2)); LOG_DEBUG("BLDO2: %s Voltage:%u mV \n", PMU->isPowerChannelEnable(XPOWERS_BLDO2) ? "+" : "-",
PMU->getPowerChannelVoltage(XPOWERS_BLDO2));
} }
LOG_DEBUG("=======================================================================\n"); LOG_DEBUG("=======================================================================\n");
@@ -597,7 +615,6 @@ bool Power::axpChipInit()
PMU->setSysPowerDownVoltage(2600); PMU->setSysPowerDownVoltage(2600);
#endif #endif
#ifdef PMU_IRQ #ifdef PMU_IRQ
uint64_t pmuIrqMask = 0; uint64_t pmuIrqMask = 0;

View File

@@ -16,7 +16,7 @@ static bool isPowered()
return true; return true;
#endif #endif
bool isRouter = (config.device.role == Config_DeviceConfig_Role_ROUTER ? 1 : 0); bool isRouter = (config.device.role == meshtastic_Config_DeviceConfig_Role_ROUTER ? 1 : 0);
// If we are not a router and we already have AC power go to POWER state after init, otherwise go to ON // If we are not a router and we already have AC power go to POWER state after init, otherwise go to ON
// We assume routers might be powered all the time, but from a low current (solar) source // We assume routers might be powered all the time, but from a low current (solar) source
@@ -199,7 +199,8 @@ static void onEnter()
uint32_t now = millis(); uint32_t now = millis();
if ((now - lastPingMs) > 30 * 1000) { // if more than a minute since our last press, ask node we are looking at to update their state if ((now - lastPingMs) >
30 * 1000) { // if more than a minute since our last press, ask node we are looking at to update their state
if (displayedNodeNum) if (displayedNodeNum)
service.sendNetworkPing(displayedNodeNum, true); // Refresh the currently displayed node service.sendNetworkPing(displayedNodeNum, true); // Refresh the currently displayed node
lastPingMs = now; lastPingMs = now;
@@ -237,7 +238,7 @@ Fsm powerFSM(&stateBOOT);
void PowerFSM_setup() void PowerFSM_setup()
{ {
bool isRouter = (config.device.role == Config_DeviceConfig_Role_ROUTER ? 1 : 0); bool isRouter = (config.device.role == meshtastic_Config_DeviceConfig_Role_ROUTER ? 1 : 0);
bool hasPower = isPowered(); bool hasPower = isPowered();
LOG_INFO("PowerFSM init, USB power=%d\n", hasPower ? 1 : 0); LOG_INFO("PowerFSM init, USB power=%d\n", hasPower ? 1 : 0);
@@ -249,7 +250,8 @@ void PowerFSM_setup()
// We need this transition, because we might not transition if we were waiting to enter light-sleep, because when we wake from // We need this transition, because we might not transition if we were waiting to enter light-sleep, because when we wake from
// light sleep we _always_ transition to NB or dark and // light sleep we _always_ transition to NB or dark and
powerFSM.add_transition(&stateLS, isRouter ? &stateNB : &stateDARK, EVENT_PACKET_FOR_PHONE, NULL, "Received packet, exiting light sleep"); powerFSM.add_transition(&stateLS, isRouter ? &stateNB : &stateDARK, EVENT_PACKET_FOR_PHONE, NULL,
"Received packet, exiting light sleep");
powerFSM.add_transition(&stateNB, &stateNB, EVENT_PACKET_FOR_PHONE, NULL, "Received packet, resetting win wake"); powerFSM.add_transition(&stateNB, &stateNB, EVENT_PACKET_FOR_PHONE, NULL, "Received packet, resetting win wake");
// Handle press events - note: we ignore button presses when in API mode // Handle press events - note: we ignore button presses when in API mode
@@ -258,7 +260,8 @@ void PowerFSM_setup()
powerFSM.add_transition(&stateDARK, &stateON, EVENT_PRESS, NULL, "Press"); powerFSM.add_transition(&stateDARK, &stateON, EVENT_PRESS, NULL, "Press");
powerFSM.add_transition(&statePOWER, &statePOWER, EVENT_PRESS, screenPress, "Press"); powerFSM.add_transition(&statePOWER, &statePOWER, EVENT_PRESS, screenPress, "Press");
powerFSM.add_transition(&stateON, &stateON, EVENT_PRESS, screenPress, "Press"); // reenter On to restart our timers powerFSM.add_transition(&stateON, &stateON, EVENT_PRESS, screenPress, "Press"); // reenter On to restart our timers
powerFSM.add_transition(&stateSERIAL, &stateSERIAL, EVENT_PRESS, screenPress, "Press"); // Allow button to work while in serial API powerFSM.add_transition(&stateSERIAL, &stateSERIAL, EVENT_PRESS, screenPress,
"Press"); // Allow button to work while in serial API
// Handle critically low power battery by forcing deep sleep // Handle critically low power battery by forcing deep sleep
powerFSM.add_transition(&stateBOOT, &stateSDS, EVENT_LOW_BATTERY, NULL, "LowBat"); powerFSM.add_transition(&stateBOOT, &stateSDS, EVENT_LOW_BATTERY, NULL, "LowBat");
@@ -324,7 +327,9 @@ void PowerFSM_setup()
powerFSM.add_transition(&stateDARK, &stateDARK, EVENT_CONTACT_FROM_PHONE, NULL, "Contact from phone"); powerFSM.add_transition(&stateDARK, &stateDARK, EVENT_CONTACT_FROM_PHONE, NULL, "Contact from phone");
powerFSM.add_timed_transition(&stateON, &stateDARK, getConfiguredOrDefaultMs(config.display.screen_on_secs, default_screen_on_secs), NULL, "Screen-on timeout"); powerFSM.add_timed_transition(&stateON, &stateDARK,
getConfiguredOrDefaultMs(config.display.screen_on_secs, default_screen_on_secs), NULL,
"Screen-on timeout");
#ifdef ARCH_ESP32 #ifdef ARCH_ESP32
State *lowPowerState = &stateLS; State *lowPowerState = &stateLS;
@@ -332,14 +337,18 @@ void PowerFSM_setup()
// See: https://github.com/meshtastic/firmware/issues/1071 // See: https://github.com/meshtastic/firmware/issues/1071
if (isRouter || config.power.is_power_saving) { if (isRouter || config.power.is_power_saving) {
powerFSM.add_timed_transition(&stateNB, &stateLS, getConfiguredOrDefaultMs(config.power.min_wake_secs, default_min_wake_secs), NULL, "Min wake timeout"); powerFSM.add_timed_transition(&stateNB, &stateLS,
powerFSM.add_timed_transition(&stateDARK, &stateLS, getConfiguredOrDefaultMs(config.power.wait_bluetooth_secs, default_wait_bluetooth_secs), NULL, "Bluetooth timeout"); getConfiguredOrDefaultMs(config.power.min_wake_secs, default_min_wake_secs), NULL,
"Min wake timeout");
powerFSM.add_timed_transition(&stateDARK, &stateLS,
getConfiguredOrDefaultMs(config.power.wait_bluetooth_secs, default_wait_bluetooth_secs),
NULL, "Bluetooth timeout");
} }
if (config.power.sds_secs != UINT32_MAX) if (config.power.sds_secs != UINT32_MAX)
powerFSM.add_timed_transition(lowPowerState, &stateSDS, getConfiguredOrDefaultMs(config.power.sds_secs), NULL, "mesh timeout"); powerFSM.add_timed_transition(lowPowerState, &stateSDS, getConfiguredOrDefaultMs(config.power.sds_secs), NULL,
"mesh timeout");
#endif #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 interation of the state machine, so we run our on enter tasks for the initial DARK state
} }

View File

@@ -26,9 +26,10 @@ class PowerFSMThread : public OSThread
if (powerStatus->getHasUSB()) { if (powerStatus->getHasUSB()) {
timeLastPowered = millis(); timeLastPowered = millis();
} else if (config.power.on_battery_shutdown_after_secs > 0 && } else if (config.power.on_battery_shutdown_after_secs > 0 && config.power.on_battery_shutdown_after_secs != UINT32_MAX &&
config.power.on_battery_shutdown_after_secs != UINT32_MAX && millis() > (timeLastPowered +
millis() > (timeLastPowered + getConfiguredOrDefaultMs(config.power.on_battery_shutdown_after_secs))) { // shutdown after 30 minutes unpowered getConfiguredOrDefaultMs(
config.power.on_battery_shutdown_after_secs))) { // shutdown after 30 minutes unpowered
powerFSM.trigger(EVENT_SHUTDOWN); powerFSM.trigger(EVENT_SHUTDOWN);
} }

View File

@@ -1,12 +1,12 @@
#include "configuration.h"
#include "RedirectablePrint.h" #include "RedirectablePrint.h"
#include "RTC.h"
#include "NodeDB.h" #include "NodeDB.h"
#include "RTC.h"
#include "concurrency/OSThread.h" #include "concurrency/OSThread.h"
#include "configuration.h"
#include <assert.h> #include <assert.h>
#include <cstring>
#include <sys/time.h> #include <sys/time.h>
#include <time.h> #include <time.h>
#include <cstring>
/** /**
* A printer that doesn't go anywhere * A printer that doesn't go anywhere
@@ -42,7 +42,8 @@ size_t RedirectablePrint::vprintf(const char *format, va_list arg)
size_t len = vsnprintf(printBuf, sizeof(printBuf), format, copy); size_t len = vsnprintf(printBuf, sizeof(printBuf), format, copy);
va_end(copy); va_end(copy);
// If the resulting string is longer than sizeof(printBuf)-1 characters, the remaining characters are still counted for the return value // If the resulting string is longer than sizeof(printBuf)-1 characters, the remaining characters are still counted for the
// return value
if (len > sizeof(printBuf) - 1) { if (len > sizeof(printBuf) - 1) {
len = sizeof(printBuf) - 1; len = sizeof(printBuf) - 1;
@@ -104,7 +105,8 @@ size_t RedirectablePrint::log(const char *logLevel, const char *format, ...)
return r; return r;
} }
void RedirectablePrint::hexDump(const char *logLevel, unsigned char *buf, uint16_t len) { void RedirectablePrint::hexDump(const char *logLevel, unsigned char *buf, uint16_t len)
{
const char alphabet[17] = "0123456789abcdef"; const char alphabet[17] = "0123456789abcdef";
log(logLevel, " +------------------------------------------------+ +----------------+\n"); log(logLevel, " +------------------------------------------------+ +----------------+\n");
log(logLevel, " |.0 .1 .2 .3 .4 .5 .6 .7 .8 .9 .a .b .c .d .e .f | | ASCII |\n"); log(logLevel, " |.0 .1 .2 .3 .4 .5 .6 .7 .8 .9 .a .b .c .d .e .f | | ASCII |\n");
@@ -119,12 +121,15 @@ void RedirectablePrint::hexDump(const char *logLevel, unsigned char *buf, uint16
s[ix++] = alphabet[(c >> 4) & 0x0F]; s[ix++] = alphabet[(c >> 4) & 0x0F];
s[ix++] = alphabet[c & 0x0F]; s[ix++] = alphabet[c & 0x0F];
ix++; ix++;
if (c > 31 && c < 128) s[iy++] = c; if (c > 31 && c < 128)
else s[iy++] = '.'; s[iy++] = c;
else
s[iy++] = '.';
} }
} }
uint8_t index = i / 16; uint8_t index = i / 16;
if (i < 256) log(logLevel, " "); if (i < 256)
log(logLevel, " ");
log(logLevel, "%02x", index); log(logLevel, "%02x", index);
log(logLevel, "."); log(logLevel, ".");
log(logLevel, s); log(logLevel, s);

View File

@@ -1,5 +1,5 @@
#include "configuration.h"
#include "SPILock.h" #include "SPILock.h"
#include "configuration.h"
#include <Arduino.h> #include <Arduino.h>
#include <assert.h> #include <assert.h>

View File

@@ -49,7 +49,8 @@ int32_t SerialConsole::runOnce()
return runOncePart(); return runOncePart();
} }
void SerialConsole::flush() { void SerialConsole::flush()
{
Port.flush(); Port.flush();
} }

View File

@@ -29,7 +29,6 @@ class SerialConsole : public StreamAPI, public RedirectablePrint, private concur
void flush(); void flush();
protected: protected:
/// Check the current underlying physical link to see if the client is currently connected /// Check the current underlying physical link to see if the client is currently connected
virtual bool checkIsConnected() override; virtual bool checkIsConnected() override;
}; };

View File

@@ -8,7 +8,6 @@
#define STATUS_TYPE_GPS 2 #define STATUS_TYPE_GPS 2
#define STATUS_TYPE_NODE 3 #define STATUS_TYPE_NODE 3
namespace meshtastic namespace meshtastic
{ {
@@ -17,7 +16,8 @@ namespace meshtastic
{ {
protected: protected:
// Allows us to observe an Observable // Allows us to observe an Observable
CallbackObserver<Status, const Status *> statusObserver = CallbackObserver<Status, const Status *>(this, &Status::updateStatus); CallbackObserver<Status, const Status *> statusObserver =
CallbackObserver<Status, const Status *>(this, &Status::updateStatus);
bool initialized = false; bool initialized = false;
// Workaround for no typeid support // Workaround for no typeid support
int statusType = 0; int statusType = 0;
@@ -29,9 +29,9 @@ namespace meshtastic
// Enable polymorphism ? // Enable polymorphism ?
virtual ~Status() = default; virtual ~Status() = default;
Status() { Status()
if (!statusType)
{ {
if (!statusType) {
statusType = STATUS_TYPE_BASE; statusType = STATUS_TYPE_BASE;
} }
} }
@@ -41,32 +41,16 @@ namespace meshtastic
Status &operator=(const Status &) = delete; Status &operator=(const Status &) = delete;
// Start observing a source of data // Start observing a source of data
void observe(Observable<const Status *> *source) void observe(Observable<const Status *> *source) { statusObserver.observe(source); }
{
statusObserver.observe(source);
}
// Determines whether or not existing data matches the data in another Status instance // Determines whether or not existing data matches the data in another Status instance
bool matches(const Status *otherStatus) const bool matches(const Status *otherStatus) const { return true; }
{
return true;
}
bool isInitialized() const bool isInitialized() const { return initialized; }
{
return initialized;
}
int getStatusType() const int getStatusType() const { return statusType; }
{
return statusType;
}
// Called when the Observable we're observing generates a new notification // Called when the Observable we're observing generates a new notification
int updateStatus(const Status *newStatus) int updateStatus(const Status *newStatus) { return 0; }
{
return 0;
}
};
}; };
}; // namespace meshtastic

View File

@@ -34,11 +34,13 @@ uint8_t AirTime::currentPeriodIndex()
return ((getSecondsSinceBoot() / SECONDS_PER_PERIOD) % PERIODS_TO_LOG); return ((getSecondsSinceBoot() / SECONDS_PER_PERIOD) % PERIODS_TO_LOG);
} }
uint8_t AirTime::getPeriodUtilMinute() { uint8_t AirTime::getPeriodUtilMinute()
{
return (getSecondsSinceBoot() / 10) % CHANNEL_UTILIZATION_PERIODS; return (getSecondsSinceBoot() / 10) % CHANNEL_UTILIZATION_PERIODS;
} }
uint8_t AirTime::getPeriodUtilHour() { uint8_t AirTime::getPeriodUtilHour()
{
return (getSecondsSinceBoot() / 60) % MINUTES_IN_HOUR; return (getSecondsSinceBoot() / 60) % MINUTES_IN_HOUR;
} }
@@ -128,14 +130,14 @@ bool AirTime::isTxAllowedChannelUtil(bool polite)
} }
} }
bool AirTime::isTxAllowedAirUtil() bool AirTime::isTxAllowedAirUtil()
{ {
if (!config.lora.override_duty_cycle && myRegion->dutyCycle < 100) { if (!config.lora.override_duty_cycle && myRegion->dutyCycle < 100) {
if (utilizationTXPercent() < myRegion->dutyCycle * polite_duty_cycle_percent / 100) { if (utilizationTXPercent() < myRegion->dutyCycle * polite_duty_cycle_percent / 100) {
return true; return true;
} else { } else {
LOG_WARN("Tx air utilization is >%d percent. Skipping this opportunity to send.\n", myRegion->dutyCycle * polite_duty_cycle_percent / 100); LOG_WARN("Tx air utilization is >%f percent. Skipping this opportunity to send.\n",
myRegion->dutyCycle * polite_duty_cycle_percent / 100);
return false; return false;
} }
} }
@@ -155,9 +157,7 @@ uint8_t AirTime::getSilentMinutes(float txPercent, float dutyCycle)
return MINUTES_IN_HOUR; return MINUTES_IN_HOUR;
} }
AirTime::AirTime() : concurrency::OSThread("AirTime"), airtimes({}) {}
AirTime::AirTime() : concurrency::OSThread("AirTime"),airtimes({}) {
}
int32_t AirTime::runOnce() int32_t AirTime::runOnce()
{ {

View File

@@ -1,10 +1,10 @@
#pragma once #pragma once
#include "MeshRadio.h"
#include "concurrency/OSThread.h" #include "concurrency/OSThread.h"
#include "configuration.h" #include "configuration.h"
#include <Arduino.h> #include <Arduino.h>
#include <functional> #include <functional>
#include "MeshRadio.h"
/* /*
TX_LOG - Time on air this device has transmitted TX_LOG - Time on air this device has transmitted
@@ -33,7 +33,6 @@
#define MS_IN_MINUTE (SECONDS_IN_MINUTE * 1000) #define MS_IN_MINUTE (SECONDS_IN_MINUTE * 1000)
#define MS_IN_HOUR (MINUTES_IN_HOUR * SECONDS_IN_MINUTE * 1000) #define MS_IN_HOUR (MINUTES_IN_HOUR * SECONDS_IN_MINUTE * 1000)
enum reportTypes { TX_LOG, RX_LOG, RX_ALL_LOG }; enum reportTypes { TX_LOG, RX_LOG, RX_ALL_LOG };
void logAirtime(reportTypes reportType, uint32_t airtime_ms); void logAirtime(reportTypes reportType, uint32_t airtime_ms);

View File

@@ -1,6 +1,6 @@
#include "buzz.h" #include "buzz.h"
#include "configuration.h"
#include "NodeDB.h" #include "NodeDB.h"
#include "configuration.h"
#if !defined(ARCH_ESP32) && !defined(ARCH_RP2040) && !defined(ARCH_PORTDUINO) #if !defined(ARCH_ESP32) && !defined(ARCH_RP2040) && !defined(ARCH_PORTDUINO)
#include "Tone.h" #include "Tone.h"
@@ -33,7 +33,8 @@ struct ToneDuration {
const int DURATION_1_8 = 125; // 1/8 note const int DURATION_1_8 = 125; // 1/8 note
const int DURATION_1_4 = 250; // 1/4 note const int DURATION_1_4 = 250; // 1/4 note
void playTones(const ToneDuration *tone_durations, int size) { void playTones(const ToneDuration *tone_durations, int size)
{
#ifdef PIN_BUZZER #ifdef PIN_BUZZER
if (!config.device.buzzer_gpio) if (!config.device.buzzer_gpio)
config.device.buzzer_gpio = PIN_BUZZER; config.device.buzzer_gpio = PIN_BUZZER;
@@ -48,22 +49,20 @@ void playTones(const ToneDuration *tone_durations, int size) {
} }
} }
void playBeep()
void playBeep() { {
ToneDuration melody[] = {{NOTE_B3, DURATION_1_4}}; ToneDuration melody[] = {{NOTE_B3, DURATION_1_4}};
playTones(melody, sizeof(melody) / sizeof(ToneDuration)); playTones(melody, sizeof(melody) / sizeof(ToneDuration));
} }
void playStartMelody() { void playStartMelody()
ToneDuration melody[] = {{NOTE_FS3, DURATION_1_8}, {
{NOTE_AS3, DURATION_1_8}, ToneDuration melody[] = {{NOTE_FS3, DURATION_1_8}, {NOTE_AS3, DURATION_1_8}, {NOTE_CS4, DURATION_1_4}};
{NOTE_CS4, DURATION_1_4}};
playTones(melody, sizeof(melody) / sizeof(ToneDuration)); playTones(melody, sizeof(melody) / sizeof(ToneDuration));
} }
void playShutdownMelody() { void playShutdownMelody()
ToneDuration melody[] = {{NOTE_CS4, DURATION_1_8}, {
{NOTE_AS3, DURATION_1_8}, ToneDuration melody[] = {{NOTE_CS4, DURATION_1_8}, {NOTE_AS3, DURATION_1_8}, {NOTE_FS3, DURATION_1_4}};
{NOTE_FS3, DURATION_1_4}};
playTones(melody, sizeof(melody) / sizeof(ToneDuration)); playTones(melody, sizeof(melody) / sizeof(ToneDuration));
} }

View File

@@ -1,5 +1,5 @@
#include "configuration.h"
#include "concurrency/BinarySemaphoreFreeRTOS.h" #include "concurrency/BinarySemaphoreFreeRTOS.h"
#include "configuration.h"
#include <assert.h> #include <assert.h>
#ifdef HAS_FREE_RTOS #ifdef HAS_FREE_RTOS

View File

@@ -1,18 +1,14 @@
#include "configuration.h"
#include "concurrency/BinarySemaphorePosix.h" #include "concurrency/BinarySemaphorePosix.h"
#include "configuration.h"
#ifndef HAS_FREE_RTOS #ifndef HAS_FREE_RTOS
namespace concurrency namespace concurrency
{ {
BinarySemaphorePosix::BinarySemaphorePosix() BinarySemaphorePosix::BinarySemaphorePosix() {}
{
}
BinarySemaphorePosix::~BinarySemaphorePosix() BinarySemaphorePosix::~BinarySemaphorePosix() {}
{
}
/** /**
* Returns false if we timed out * Returns false if we timed out
@@ -23,13 +19,9 @@ bool BinarySemaphorePosix::take(uint32_t msec)
return false; return false;
} }
void BinarySemaphorePosix::give() void BinarySemaphorePosix::give() {}
{
}
IRAM_ATTR void BinarySemaphorePosix::giveFromISR(BaseType_t *pxHigherPriorityTaskWoken) IRAM_ATTR void BinarySemaphorePosix::giveFromISR(BaseType_t *pxHigherPriorityTaskWoken) {}
{
}
} // namespace concurrency } // namespace concurrency

View File

@@ -1,5 +1,5 @@
#include "configuration.h"
#include "concurrency/InterruptableDelay.h" #include "concurrency/InterruptableDelay.h"
#include "configuration.h"
namespace concurrency namespace concurrency
{ {

View File

@@ -2,7 +2,6 @@
#include "../freertosinc.h" #include "../freertosinc.h"
#ifdef HAS_FREE_RTOS #ifdef HAS_FREE_RTOS
#include "concurrency/BinarySemaphoreFreeRTOS.h" #include "concurrency/BinarySemaphoreFreeRTOS.h"
#define BinarySemaphore BinarySemaphoreFreeRTOS #define BinarySemaphore BinarySemaphoreFreeRTOS

View File

@@ -1,5 +1,5 @@
#include "configuration.h"
#include "Lock.h" #include "Lock.h"
#include "configuration.h"
#include <cassert> #include <cassert>
namespace concurrency namespace concurrency

View File

@@ -1,7 +1,8 @@
#include "configuration.h"
#include "LockGuard.h" #include "LockGuard.h"
#include "configuration.h"
namespace concurrency { namespace concurrency
{
LockGuard::LockGuard(Lock *lock) : lock(lock) LockGuard::LockGuard(Lock *lock) : lock(lock)
{ {

View File

@@ -2,7 +2,8 @@
#include "Lock.h" #include "Lock.h"
namespace concurrency { namespace concurrency
{
/** /**
* @brief RAII lock guard * @brief RAII lock guard

View File

@@ -1,5 +1,5 @@
#include "configuration.h"
#include "NotifiedWorkerThread.h" #include "NotifiedWorkerThread.h"
#include "configuration.h"
#include "main.h" #include "main.h"
namespace concurrency namespace concurrency
@@ -80,8 +80,6 @@ void NotifiedWorkerThread::checkNotification()
} }
} }
int32_t NotifiedWorkerThread::runOnce() int32_t NotifiedWorkerThread::runOnce()
{ {
enabled = false; // Only run once per notification enabled = false; // Only run once per notification

View File

@@ -41,9 +41,9 @@ class NotifiedWorkerThread : public OSThread
/// just calls checkNotification() /// just calls checkNotification()
virtual int32_t runOnce() override; virtual int32_t runOnce() override;
/// Sometimes we might want to check notifications independently of when our thread was getting woken up (i.e. if we are about to change /// Sometimes we might want to check notifications independently of when our thread was getting woken up (i.e. if we are about
/// radio transmit/receive modes we want to handle any pending interrupts first). You can call this method and if any notifications are currently /// to change radio transmit/receive modes we want to handle any pending interrupts first). You can call this method and if
/// pending they will be handled immediately. /// any notifications are currently pending they will be handled immediately.
void checkNotification(); void checkNotification();
private: private:

View File

@@ -1,5 +1,5 @@
#include "configuration.h"
#include "OSThread.h" #include "OSThread.h"
#include "configuration.h"
#include <assert.h> #include <assert.h>
namespace concurrency namespace concurrency

View File

@@ -42,7 +42,8 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#error APP_VERSION must be set by the build environment #error APP_VERSION must be set by the build environment
#endif #endif
// FIXME: This is still needed by the Bluetooth Stack and needs to be replaced by something better. Remnant of the old versioning system. // FIXME: This is still needed by the Bluetooth Stack and needs to be replaced by something better. Remnant of the old versioning
// system.
#ifndef HW_VERSION #ifndef HW_VERSION
#define HW_VERSION "1.0" #define HW_VERSION "1.0"
#endif #endif
@@ -175,8 +176,8 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#define HAS_BLUETOOTH 0 #define HAS_BLUETOOTH 0
#endif #endif
#include "RF95Configuration.h"
#include "DebugConfiguration.h" #include "DebugConfiguration.h"
#include "RF95Configuration.h"
#ifndef HW_VENDOR #ifndef HW_VENDOR
#error HW_VENDOR must be defined #error HW_VENDOR must be defined

View File

@@ -7,41 +7,48 @@
void d_writeCommand(uint8_t c) void d_writeCommand(uint8_t c)
{ {
SPI1.beginTransaction(SPISettings(4000000, MSBFIRST, SPI_MODE0)); SPI1.beginTransaction(SPISettings(4000000, MSBFIRST, SPI_MODE0));
if (PIN_EINK_DC >= 0) digitalWrite(PIN_EINK_DC, LOW); if (PIN_EINK_DC >= 0)
if (PIN_EINK_CS >= 0) digitalWrite(PIN_EINK_CS, LOW); digitalWrite(PIN_EINK_DC, LOW);
if (PIN_EINK_CS >= 0)
digitalWrite(PIN_EINK_CS, LOW);
SPI1.transfer(c); SPI1.transfer(c);
if (PIN_EINK_CS >= 0) digitalWrite(PIN_EINK_CS, HIGH); if (PIN_EINK_CS >= 0)
if (PIN_EINK_DC >= 0) digitalWrite(PIN_EINK_DC, HIGH); digitalWrite(PIN_EINK_CS, HIGH);
if (PIN_EINK_DC >= 0)
digitalWrite(PIN_EINK_DC, HIGH);
SPI1.endTransaction(); SPI1.endTransaction();
} }
void d_writeData(uint8_t d) void d_writeData(uint8_t d)
{ {
SPI1.beginTransaction(SPISettings(4000000, MSBFIRST, SPI_MODE0)); SPI1.beginTransaction(SPISettings(4000000, MSBFIRST, SPI_MODE0));
if (PIN_EINK_CS >= 0) digitalWrite(PIN_EINK_CS, LOW); if (PIN_EINK_CS >= 0)
digitalWrite(PIN_EINK_CS, LOW);
SPI1.transfer(d); SPI1.transfer(d);
if (PIN_EINK_CS >= 0) digitalWrite(PIN_EINK_CS, HIGH); if (PIN_EINK_CS >= 0)
digitalWrite(PIN_EINK_CS, HIGH);
SPI1.endTransaction(); SPI1.endTransaction();
} }
unsigned long d_waitWhileBusy(uint16_t busy_time) unsigned long d_waitWhileBusy(uint16_t busy_time)
{ {
if (PIN_EINK_BUSY >= 0) if (PIN_EINK_BUSY >= 0) {
{
delay(1); // add some margin to become active delay(1); // add some margin to become active
unsigned long start = micros(); unsigned long start = micros();
while (1) while (1) {
{ if (digitalRead(PIN_EINK_BUSY) != HIGH)
if (digitalRead(PIN_EINK_BUSY) != HIGH) break; break;
delay(1); delay(1);
if (digitalRead(PIN_EINK_BUSY) != HIGH) break; if (digitalRead(PIN_EINK_BUSY) != HIGH)
if (micros() - start > 10000000) break; break;
if (micros() - start > 10000000)
break;
} }
unsigned long elapsed = micros() - start; unsigned long elapsed = micros() - start;
(void)start; (void)start;
return elapsed; return elapsed;
} } else
else return busy_time; return busy_time;
} }
void scanEInkDevice(void) void scanEInkDevice(void)

View File

@@ -168,13 +168,13 @@ void scanI2Cdevice()
registerValue = getRegisterValue(addr, 0xD0, 1); // GET_ID registerValue = getRegisterValue(addr, 0xD0, 1); // GET_ID
if (registerValue == 0x61) { if (registerValue == 0x61) {
LOG_INFO("BME-680 sensor found at address 0x%x\n", (uint8_t)addr); LOG_INFO("BME-680 sensor found at address 0x%x\n", (uint8_t)addr);
nodeTelemetrySensorsMap[TelemetrySensorType_BME680] = addr; nodeTelemetrySensorsMap[meshtastic_TelemetrySensorType_BME680] = addr;
} else if (registerValue == 0x60) { } else if (registerValue == 0x60) {
LOG_INFO("BME-280 sensor found at address 0x%x\n", (uint8_t)addr); LOG_INFO("BME-280 sensor found at address 0x%x\n", (uint8_t)addr);
nodeTelemetrySensorsMap[TelemetrySensorType_BME280] = addr; nodeTelemetrySensorsMap[meshtastic_TelemetrySensorType_BME280] = addr;
} else { } else {
LOG_INFO("BMP-280 sensor found at address 0x%x\n", (uint8_t)addr); LOG_INFO("BMP-280 sensor found at address 0x%x\n", (uint8_t)addr);
nodeTelemetrySensorsMap[TelemetrySensorType_BMP280] = addr; nodeTelemetrySensorsMap[meshtastic_TelemetrySensorType_BMP280] = addr;
} }
} }
if (addr == INA_ADDR || addr == INA_ADDR_ALTERNATE) { if (addr == INA_ADDR || addr == INA_ADDR_ALTERNATE) {
@@ -182,41 +182,41 @@ void scanI2Cdevice()
LOG_DEBUG("Register MFG_UID: 0x%x\n", registerValue); LOG_DEBUG("Register MFG_UID: 0x%x\n", registerValue);
if (registerValue == 0x5449) { if (registerValue == 0x5449) {
LOG_INFO("INA260 sensor found at address 0x%x\n", (uint8_t)addr); LOG_INFO("INA260 sensor found at address 0x%x\n", (uint8_t)addr);
nodeTelemetrySensorsMap[TelemetrySensorType_INA260] = addr; nodeTelemetrySensorsMap[meshtastic_TelemetrySensorType_INA260] = addr;
} else { // Assume INA219 if INA260 ID is not found } else { // Assume INA219 if INA260 ID is not found
LOG_INFO("INA219 sensor found at address 0x%x\n", (uint8_t)addr); LOG_INFO("INA219 sensor found at address 0x%x\n", (uint8_t)addr);
nodeTelemetrySensorsMap[TelemetrySensorType_INA219] = addr; nodeTelemetrySensorsMap[meshtastic_TelemetrySensorType_INA219] = addr;
} }
} }
if (addr == MCP9808_ADDR) { if (addr == MCP9808_ADDR) {
nodeTelemetrySensorsMap[TelemetrySensorType_MCP9808] = addr; nodeTelemetrySensorsMap[meshtastic_TelemetrySensorType_MCP9808] = addr;
LOG_INFO("MCP9808 sensor found\n"); LOG_INFO("MCP9808 sensor found\n");
} }
if (addr == SHT31_ADDR) { if (addr == SHT31_ADDR) {
LOG_INFO("SHT31 sensor found\n"); LOG_INFO("SHT31 sensor found\n");
nodeTelemetrySensorsMap[TelemetrySensorType_SHT31] = addr; nodeTelemetrySensorsMap[meshtastic_TelemetrySensorType_SHT31] = addr;
} }
if (addr == SHTC3_ADDR) { if (addr == SHTC3_ADDR) {
LOG_INFO("SHTC3 sensor found\n"); LOG_INFO("SHTC3 sensor found\n");
nodeTelemetrySensorsMap[TelemetrySensorType_SHTC3] = addr; nodeTelemetrySensorsMap[meshtastic_TelemetrySensorType_SHTC3] = addr;
} }
if (addr == LPS22HB_ADDR || addr == LPS22HB_ADDR_ALT) { if (addr == LPS22HB_ADDR || addr == LPS22HB_ADDR_ALT) {
LOG_INFO("LPS22HB sensor found\n"); LOG_INFO("LPS22HB sensor found\n");
nodeTelemetrySensorsMap[TelemetrySensorType_LPS22] = addr; nodeTelemetrySensorsMap[meshtastic_TelemetrySensorType_LPS22] = addr;
} }
// High rate sensors, will be processed internally // High rate sensors, will be processed internally
if (addr == QMC6310_ADDR) { if (addr == QMC6310_ADDR) {
LOG_INFO("QMC6310 Highrate 3-Axis magnetic sensor found\n"); LOG_INFO("QMC6310 Highrate 3-Axis magnetic sensor found\n");
nodeTelemetrySensorsMap[TelemetrySensorType_QMC6310] = addr; nodeTelemetrySensorsMap[meshtastic_TelemetrySensorType_QMC6310] = addr;
} }
if (addr == QMI8658_ADDR) { if (addr == QMI8658_ADDR) {
LOG_INFO("QMI8658 Highrate 6-Axis inertial measurement sensor found\n"); LOG_INFO("QMI8658 Highrate 6-Axis inertial measurement sensor found\n");
nodeTelemetrySensorsMap[TelemetrySensorType_QMI8658] = addr; nodeTelemetrySensorsMap[meshtastic_TelemetrySensorType_QMI8658] = addr;
} }
if (addr == QMC5883L_ADDR) { if (addr == QMC5883L_ADDR) {
LOG_INFO("QMC5883L Highrate 3-Axis magnetic sensor found\n"); LOG_INFO("QMC5883L Highrate 3-Axis magnetic sensor found\n");
nodeTelemetrySensorsMap[TelemetrySensorType_QMC5883L] = addr; nodeTelemetrySensorsMap[meshtastic_TelemetrySensorType_QMC5883L] = addr;
} }
} else if (err == 4) { } else if (err == 4) {
LOG_ERROR("Unknow error at address 0x%x\n", addr); LOG_ERROR("Unknow error at address 0x%x\n", addr);

View File

@@ -8,5 +8,5 @@
#define RECORD_CRITICALERROR(code) recordCriticalError(code, __LINE__, __FILE__) #define RECORD_CRITICALERROR(code) recordCriticalError(code, __LINE__, __FILE__)
/// Record an error that should be reported via analytics /// Record an error that should be reported via analytics
void recordCriticalError(CriticalErrorCode code = CriticalErrorCode_UNSPECIFIED, uint32_t address = 0, void recordCriticalError(meshtastic_CriticalErrorCode code = meshtastic_CriticalErrorCode_UNSPECIFIED, uint32_t address = 0,
const char *filename = NULL); const char *filename = NULL);

View File

@@ -21,7 +21,8 @@ GPS *gps;
/// only init that port once. /// only init that port once.
static bool didSerialInit; static bool didSerialInit;
bool GPS::getACK(uint8_t c, uint8_t i) { bool GPS::getACK(uint8_t c, uint8_t i)
{
uint8_t b; uint8_t b;
uint8_t ack = 0; uint8_t ack = 0;
const uint8_t ackP[2] = {c, i}; const uint8_t ackP[2] = {c, i};
@@ -50,8 +51,7 @@ bool GPS::getACK(uint8_t c, uint8_t i) {
b = _serial_gps->read(); b = _serial_gps->read();
if (b == buf[ack]) { if (b == buf[ack]) {
ack++; ack++;
} } else {
else {
ack = 0; ack = 0;
} }
} }
@@ -178,8 +178,8 @@ if (!config.position.tx_gpio)
* t-beam-s3-core uses the same L76K GNSS module as t-echo. * t-beam-s3-core uses the same L76K GNSS module as t-echo.
* Unlike t-echo, L76K uses 9600 baud rate for communication by default. * Unlike t-echo, L76K uses 9600 baud rate for communication by default.
* */ * */
// _serial_gps->begin(9600); //The baud rate of 9600 has been initialized at the beginning of setupGPS, this line is the redundant part // _serial_gps->begin(9600); //The baud rate of 9600 has been initialized at the beginning of setupGPS, this line
// delay(250); // is the redundant part delay(250);
// Initialize the L76K Chip, use GPS + GLONASS // Initialize the L76K Chip, use GPS + GLONASS
_serial_gps->write("$PCAS04,5*1C\r\n"); _serial_gps->write("$PCAS04,5*1C\r\n");
@@ -190,7 +190,6 @@ if (!config.position.tx_gpio)
// Switch to Vehicle Mode, since SoftRF enables Aviation < 2g // Switch to Vehicle Mode, since SoftRF enables Aviation < 2g
_serial_gps->write("$PCAS11,3*1E\r\n"); _serial_gps->write("$PCAS11,3*1E\r\n");
delay(250); delay(250);
} else if (gnssModel == GNSS_MODEL_UBLOX) { } else if (gnssModel == GNSS_MODEL_UBLOX) {
/* /*
@@ -210,7 +209,8 @@ if (!config.position.tx_gpio)
// ublox-M10S can be compatible with UBLOX traditional protocol, so the following sentence settings are also valid // ublox-M10S can be compatible with UBLOX traditional protocol, so the following sentence settings are also valid
// disable GGL // disable GGL
byte _message_GGL[] = {0xB5, 0x62, 0x06, 0x01, 0x08, 0x00, 0xF0, 0x01, 0x01, 0x00, 0x01, 0x01, 0x01, 0x01, 0x05, 0x3A}; byte _message_GGL[] = {0xB5, 0x62, 0x06, 0x01, 0x08, 0x00, 0xF0, 0x01,
0x01, 0x00, 0x01, 0x01, 0x01, 0x01, 0x05, 0x3A};
_serial_gps->write(_message_GGL, sizeof(_message_GGL)); _serial_gps->write(_message_GGL, sizeof(_message_GGL));
if (!getACK(0x06, 0x01)) { if (!getACK(0x06, 0x01)) {
LOG_WARN("Unable to disable NMEA GGL.\n"); LOG_WARN("Unable to disable NMEA GGL.\n");
@@ -218,7 +218,8 @@ if (!config.position.tx_gpio)
} }
// disable GSA // disable GSA
byte _message_GSA[] = {0xB5, 0x62, 0x06, 0x01, 0x08, 0x00, 0xF0, 0x02, 0x01, 0x00, 0x01, 0x01, 0x01, 0x01, 0x06, 0x41}; byte _message_GSA[] = {0xB5, 0x62, 0x06, 0x01, 0x08, 0x00, 0xF0, 0x02,
0x01, 0x00, 0x01, 0x01, 0x01, 0x01, 0x06, 0x41};
_serial_gps->write(_message_GSA, sizeof(_message_GSA)); _serial_gps->write(_message_GSA, sizeof(_message_GSA));
if (!getACK(0x06, 0x01)) { if (!getACK(0x06, 0x01)) {
LOG_WARN("Unable to disable NMEA GSA.\n"); LOG_WARN("Unable to disable NMEA GSA.\n");
@@ -226,7 +227,8 @@ if (!config.position.tx_gpio)
} }
// disable GSV // disable GSV
byte _message_GSV[] = {0xB5, 0x62, 0x06, 0x01, 0x08, 0x00, 0xF0, 0x03, 0x01, 0x00, 0x01, 0x01, 0x01, 0x01, 0x07, 0x48}; byte _message_GSV[] = {0xB5, 0x62, 0x06, 0x01, 0x08, 0x00, 0xF0, 0x03,
0x01, 0x00, 0x01, 0x01, 0x01, 0x01, 0x07, 0x48};
_serial_gps->write(_message_GSV, sizeof(_message_GSV)); _serial_gps->write(_message_GSV, sizeof(_message_GSV));
if (!getACK(0x06, 0x01)) { if (!getACK(0x06, 0x01)) {
LOG_WARN("Unable to disable NMEA GSV.\n"); LOG_WARN("Unable to disable NMEA GSV.\n");
@@ -234,7 +236,8 @@ if (!config.position.tx_gpio)
} }
// disable VTG // disable VTG
byte _message_VTG[] = {0xB5, 0x62, 0x06, 0x01, 0x08, 0x00, 0xF0, 0x05, 0x01, 0x00, 0x01, 0x01, 0x01, 0x01, 0x09, 0x56}; byte _message_VTG[] = {0xB5, 0x62, 0x06, 0x01, 0x08, 0x00, 0xF0, 0x05,
0x01, 0x00, 0x01, 0x01, 0x01, 0x01, 0x09, 0x56};
_serial_gps->write(_message_VTG, sizeof(_message_VTG)); _serial_gps->write(_message_VTG, sizeof(_message_VTG));
if (!getACK(0x06, 0x01)) { if (!getACK(0x06, 0x01)) {
LOG_WARN("Unable to disable NMEA VTG.\n"); LOG_WARN("Unable to disable NMEA VTG.\n");
@@ -242,7 +245,8 @@ if (!config.position.tx_gpio)
} }
// enable RMC // enable RMC
byte _message_RMC[] = {0xB5, 0x62, 0x06, 0x01, 0x08, 0x00, 0xF0, 0x04, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x09, 0x54}; byte _message_RMC[] = {0xB5, 0x62, 0x06, 0x01, 0x08, 0x00, 0xF0, 0x04,
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x09, 0x54};
_serial_gps->write(_message_RMC, sizeof(_message_RMC)); _serial_gps->write(_message_RMC, sizeof(_message_RMC));
if (!getACK(0x06, 0x01)) { if (!getACK(0x06, 0x01)) {
LOG_WARN("Unable to enable NMEA RMC.\n"); LOG_WARN("Unable to enable NMEA RMC.\n");
@@ -250,7 +254,8 @@ if (!config.position.tx_gpio)
} }
// enable GGA // enable GGA
byte _message_GGA[] = {0xB5, 0x62, 0x06, 0x01, 0x08, 0x00, 0xF0, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x05, 0x38}; byte _message_GGA[] = {0xB5, 0x62, 0x06, 0x01, 0x08, 0x00, 0xF0, 0x00,
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x05, 0x38};
_serial_gps->write(_message_GGA, sizeof(_message_GGA)); _serial_gps->write(_message_GGA, sizeof(_message_GGA));
if (!getACK(0x06, 0x01)) { if (!getACK(0x06, 0x01)) {
LOG_WARN("Unable to enable NMEA GGA.\n"); LOG_WARN("Unable to enable NMEA GGA.\n");
@@ -289,7 +294,8 @@ if(config.position.gps_enabled){
notifyDeepSleepObserver.observe(&notifyDeepSleep); notifyDeepSleepObserver.observe(&notifyDeepSleep);
notifyGPSSleepObserver.observe(&notifyGPSSleep); notifyGPSSleepObserver.observe(&notifyGPSSleep);
} }
if (config.position.gps_enabled==false) {
if (config.position.gps_enabled == false && config.position.fixed_position == false) {
setAwake(false); setAwake(false);
doGPSpowersave(false); doGPSpowersave(false);
} }
@@ -396,7 +402,8 @@ uint32_t GPS::getSleepTime() const
uint32_t t = config.position.gps_update_interval; uint32_t t = config.position.gps_update_interval;
bool gps_enabled = config.position.gps_enabled; bool gps_enabled = config.position.gps_enabled;
if (!gps_enabled) // We'll not need the GPS thread to wake up again after first acq. with fixed position.
if (!gps_enabled || config.position.fixed_position)
t = UINT32_MAX; // Sleep forever now t = UINT32_MAX; // Sleep forever now
if (t == UINT32_MAX) if (t == UINT32_MAX)
@@ -421,6 +428,10 @@ void GPS::publishUpdate()
int32_t GPS::runOnce() int32_t GPS::runOnce()
{ {
// Repeaters have no need for GPS
if (config.device.role == meshtastic_Config_DeviceConfig_Role_REPEATER)
disable();
if (whileIdle()) { if (whileIdle()) {
// if we have received valid NMEA claim we are connected // if we have received valid NMEA claim we are connected
setConnected(); setConnected();
@@ -431,6 +442,7 @@ int32_t GPS::runOnce()
LOG_DEBUG("GPS is not communicating, trying factory reset on next bootup.\n"); LOG_DEBUG("GPS is not communicating, trying factory reset on next bootup.\n");
devicestate.did_gps_reset = false; devicestate.did_gps_reset = false;
nodeDB.saveDeviceStateToDisk(); nodeDB.saveDeviceStateToDisk();
disable(); // Stop the GPS thread as it can do nothing useful until next reboot.
} }
} }
} }
@@ -480,7 +492,7 @@ int32_t GPS::runOnce()
if (hasValidLocation) { if (hasValidLocation) {
LOG_DEBUG("hasValidLocation FALLING EDGE (last read: %d)\n", gotLoc); LOG_DEBUG("hasValidLocation FALLING EDGE (last read: %d)\n", gotLoc);
} }
p = Position_init_default; p = meshtastic_Position_init_default;
hasValidLocation = false; hasValidLocation = false;
} }
@@ -492,6 +504,14 @@ int32_t GPS::runOnce()
// If state has changed do a publish // If state has changed do a publish
publishUpdate(); publishUpdate();
if (!(fixeddelayCtr >= 20) && config.position.fixed_position && hasValidLocation) {
fixeddelayCtr++;
// LOG_DEBUG("Our delay counter is %d\n", fixeddelayCtr);
if (fixeddelayCtr >= 20) {
doGPSpowersave(false);
forceWake(false);
}
}
// 9600bps is approx 1 byte per msec, so considering our buffer size we never need to wake more often than 200ms // 9600bps is approx 1 byte per msec, so considering our buffer size we never need to wake more often than 200ms
// if not awake we can run super infrquently (once every 5 secs?) to see if we need to wake. // if not awake we can run super infrquently (once every 5 secs?) to see if we need to wake.
return isAwake ? GPS_THREAD_INTERVAL : 5000; return isAwake ? GPS_THREAD_INTERVAL : 5000;
@@ -574,7 +594,6 @@ GnssModel_t GPS::probe()
} }
} }
uint8_t cfg_rate[] = {0xB5, 0x62, 0x06, 0x08, 0x00, 0x00, 0x0E, 0x30}; uint8_t cfg_rate[] = {0xB5, 0x62, 0x06, 0x08, 0x00, 0x00, 0x0E, 0x30};
_serial_gps->write(cfg_rate, sizeof(cfg_rate)); _serial_gps->write(cfg_rate, sizeof(cfg_rate));
// Check that the returned response class and message ID are correct // Check that the returned response class and message ID are correct
@@ -662,8 +681,7 @@ GPS *createGps()
new_gps->setup(); new_gps->setup();
return new_gps; return new_gps;
} }
} } else {
else{
GPS *new_gps = new NMEAGPS(); GPS *new_gps = new NMEAGPS();
new_gps->setup(); new_gps->setup();
return new_gps; return new_gps;

View File

@@ -4,7 +4,6 @@
#include "Observer.h" #include "Observer.h"
#include "concurrency/OSThread.h" #include "concurrency/OSThread.h"
struct uBloxGnssModelInfo { struct uBloxGnssModelInfo {
char swVersion[30]; char swVersion[30];
char hwVersion[10]; char hwVersion[10];
@@ -55,7 +54,7 @@ class GPS : private concurrency::OSThread
/** If !NULL we will use this serial port to construct our GPS */ /** If !NULL we will use this serial port to construct our GPS */
static HardwareSerial *_serial_gps; static HardwareSerial *_serial_gps;
Position p = Position_init_default; meshtastic_Position p = meshtastic_Position_init_default;
GPS() : concurrency::OSThread("GPS") {} GPS() : concurrency::OSThread("GPS") {}
@@ -169,6 +168,9 @@ class GPS : private concurrency::OSThread
int getAck(uint8_t *buffer, uint16_t size, uint8_t requestedClass, uint8_t requestedID); int getAck(uint8_t *buffer, uint16_t size, uint8_t requestedClass, uint8_t requestedID);
// delay counter to allow more sats before fixed position stops GPS thread
uint8_t fixeddelayCtr = 0;
protected: protected:
GnssModel_t gnssModel = GNSS_MODEL_UNKONW; GnssModel_t gnssModel = GNSS_MODEL_UNKONW;
}; };

View File

@@ -1,21 +1,25 @@
#include "GeoCoord.h" #include "GeoCoord.h"
GeoCoord::GeoCoord() { GeoCoord::GeoCoord()
{
_dirty = true; _dirty = true;
} }
GeoCoord::GeoCoord (int32_t lat, int32_t lon, int32_t alt) : _latitude(lat), _longitude(lon), _altitude(alt) { GeoCoord::GeoCoord(int32_t lat, int32_t lon, int32_t alt) : _latitude(lat), _longitude(lon), _altitude(alt)
{
GeoCoord::setCoords(); GeoCoord::setCoords();
} }
GeoCoord::GeoCoord (float lat, float lon, int32_t alt) : _altitude(alt) { 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 reprsentation to int32_t. I.e., 12.345 becomes 123450000
_latitude = int32_t(lat * 1e+7); _latitude = int32_t(lat * 1e+7);
_longitude = int32_t(lon * 1e+7); _longitude = int32_t(lon * 1e+7);
GeoCoord::setCoords(); GeoCoord::setCoords();
} }
GeoCoord::GeoCoord(double lat, double 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 reprsentation to int32_t. I.e., 12.345 becomes 123450000
_latitude = int32_t(lat * 1e+7); _latitude = int32_t(lat * 1e+7);
_longitude = int32_t(lon * 1e+7); _longitude = int32_t(lon * 1e+7);
@@ -23,7 +27,8 @@ GeoCoord::GeoCoord(double lat, double lon, int32_t alt): _altitude(alt) {
} }
// Initialize all the coordinate systems // Initialize all the coordinate systems
void GeoCoord::setCoords() { void GeoCoord::setCoords()
{
double lat = _latitude * 1e-7; double lat = _latitude * 1e-7;
double lon = _longitude * 1e-7; double lon = _longitude * 1e-7;
GeoCoord::latLongToDMS(lat, lon, _dms); GeoCoord::latLongToDMS(lat, lon, _dms);
@@ -34,7 +39,8 @@ void GeoCoord::setCoords() {
_dirty = false; _dirty = false;
} }
void GeoCoord::updateCoords(int32_t lat, int32_t lon, int32_t alt) { void GeoCoord::updateCoords(int32_t lat, int32_t lon, int32_t alt)
{
// If marked dirty or new coordiantes // If marked dirty or new coordiantes
if (_dirty || _latitude != lat || _longitude != lon || _altitude != alt) { if (_dirty || _latitude != lat || _longitude != lon || _altitude != alt) {
_dirty = true; _dirty = true;
@@ -45,7 +51,8 @@ void GeoCoord::updateCoords(int32_t lat, int32_t lon, int32_t alt) {
} }
} }
void GeoCoord::updateCoords(const double lat, const double lon, const int32_t alt) { void GeoCoord::updateCoords(const double lat, const double lon, const int32_t alt)
{
int32_t iLat = lat * 1e+7; int32_t iLat = lat * 1e+7;
int32_t iLon = lon * 1e+7; int32_t iLon = lon * 1e+7;
// If marked dirty or new coordiantes // If marked dirty or new coordiantes
@@ -56,10 +63,10 @@ void GeoCoord::updateCoords(const double lat, const double lon, const int32_t al
_altitude = alt; _altitude = alt;
setCoords(); setCoords();
} }
} }
void GeoCoord::updateCoords(const float lat, const float lon, const int32_t alt) { void GeoCoord::updateCoords(const float lat, const float lon, const int32_t alt)
{
int32_t iLat = lat * 1e+7; int32_t iLat = lat * 1e+7;
int32_t iLon = lon * 1e+7; int32_t iLon = lon * 1e+7;
// If marked dirty or new coordiantes // If marked dirty or new coordiantes
@@ -76,9 +83,12 @@ void GeoCoord::updateCoords(const float lat, const float lon, const int32_t alt)
* Converts lat long coordinates from decimal degrees to degrees minutes seconds format. * Converts lat long coordinates from decimal degrees to degrees minutes seconds format.
* DD°MM'SS"C DDD°MM'SS"C * DD°MM'SS"C DDD°MM'SS"C
*/ */
void GeoCoord::latLongToDMS(const double lat, const double lon, DMS &dms) { void GeoCoord::latLongToDMS(const double lat, const double lon, DMS &dms)
if (lat < 0) dms.latCP = 'S'; {
else dms.latCP = 'N'; if (lat < 0)
dms.latCP = 'S';
else
dms.latCP = 'N';
double latDeg = lat; double latDeg = lat;
@@ -90,8 +100,10 @@ void GeoCoord::latLongToDMS(const double lat, const double lon, DMS &dms) {
dms.latMin = floor(latMin); dms.latMin = floor(latMin);
dms.latSec = (latMin - dms.latMin) * 60; dms.latSec = (latMin - dms.latMin) * 60;
if (lon < 0) dms.lonCP = 'W'; if (lon < 0)
else dms.lonCP = 'E'; dms.lonCP = 'W';
else
dms.lonCP = 'E';
double lonDeg = lon; double lonDeg = lon;
@@ -108,7 +120,8 @@ void GeoCoord::latLongToDMS(const double lat, const double lon, DMS &dms) {
* Converts lat long coordinates to UTM. * Converts lat long coordinates to UTM.
* based on this: https://github.com/walvok/LatLonToUTM/blob/master/latlon_utm.ino * based on this: https://github.com/walvok/LatLonToUTM/blob/master/latlon_utm.ino
*/ */
void GeoCoord::latLongToUTM(const double lat, const double lon, UTM &utm) { void GeoCoord::latLongToUTM(const double lat, const double lon, UTM &utm)
{
const std::string latBands = "CDEFGHJKLMNPQRSTUVWXX"; const std::string latBands = "CDEFGHJKLMNPQRSTUVWXX";
utm.zone = int((lon + 180) / 6 + 1); utm.zone = int((lon + 180) / 6 + 1);
@@ -124,10 +137,14 @@ void GeoCoord::latLongToUTM(const double lat, const double lon, UTM &utm) {
if (lat >= 56.0 && lat < 64.0 && lonTemp >= 3.0 && lonTemp < 12.0) // Norway if (lat >= 56.0 && lat < 64.0 && lonTemp >= 3.0 && lonTemp < 12.0) // Norway
utm.zone = 32; utm.zone = 32;
if (lat >= 72.0 && lat < 84.0) { // Svalbard if (lat >= 72.0 && lat < 84.0) { // Svalbard
if ( lonTemp >= 0.0 && lonTemp < 9.0 ) utm.zone = 31; if (lonTemp >= 0.0 && lonTemp < 9.0)
else if( lonTemp >= 9.0 && lonTemp < 21.0 ) utm.zone = 33; utm.zone = 31;
else if( lonTemp >= 21.0 && lonTemp < 33.0 ) utm.zone = 35; else if (lonTemp >= 9.0 && lonTemp < 21.0)
else if( lonTemp >= 33.0 && lonTemp < 42.0 ) utm.zone = 37; utm.zone = 33;
else if (lonTemp >= 21.0 && lonTemp < 33.0)
utm.zone = 35;
else if (lonTemp >= 33.0 && lonTemp < 42.0)
utm.zone = 37;
} }
double lonOrigin = (utm.zone - 1) * 6 - 180 + 3; // puts origin in middle of zone double lonOrigin = (utm.zone - 1) * 6 - 180 + 3; // puts origin in middle of zone
@@ -137,21 +154,28 @@ void GeoCoord::latLongToUTM(const double lat, const double lon, UTM &utm) {
double T = tan(latRad) * tan(latRad); double T = tan(latRad) * tan(latRad);
double C = eccPrimeSquared * cos(latRad) * cos(latRad); double C = eccPrimeSquared * cos(latRad) * cos(latRad);
double A = cos(latRad) * (lonRad - lonOriginRad); double A = cos(latRad) * (lonRad - lonOriginRad);
double M = a*((1 - eccSquared/4 - 3*eccSquared*eccSquared/64 - 5*eccSquared*eccSquared*eccSquared/256)*latRad double M =
- (3*eccSquared/8 + 3*eccSquared*eccSquared/32 + 45*eccSquared*eccSquared*eccSquared/1024)*sin(2*latRad) a * ((1 - eccSquared / 4 - 3 * eccSquared * eccSquared / 64 - 5 * eccSquared * eccSquared * eccSquared / 256) * latRad -
+ (15*eccSquared*eccSquared/256 + 45*eccSquared*eccSquared*eccSquared/1024)*sin(4*latRad) (3 * eccSquared / 8 + 3 * eccSquared * eccSquared / 32 + 45 * eccSquared * eccSquared * eccSquared / 1024) *
- (35*eccSquared*eccSquared*eccSquared/3072)*sin(6*latRad)); sin(2 * latRad) +
utm.easting = (double)(k0*N*(A+(1-T+C)*pow(A, 3)/6 + (5-18*T+T*T+72*C-58*eccPrimeSquared)*A*A*A*A*A/120) (15 * eccSquared * eccSquared / 256 + 45 * eccSquared * eccSquared * eccSquared / 1024) * sin(4 * latRad) -
+ 500000.0); (35 * eccSquared * eccSquared * eccSquared / 3072) * sin(6 * latRad));
utm.northing = (double)(k0*(M+N*tan(latRad)*(A*A/2+(5-T+9*C+4*C*C)*A*A*A*A/24 utm.easting = (double)(k0 * N *
+ (61-58*T+T*T+600*C-330*eccPrimeSquared)*A*A*A*A*A*A/720))); (A + (1 - T + C) * pow(A, 3) / 6 +
(5 - 18 * T + T * T + 72 * C - 58 * eccPrimeSquared) * A * A * A * A * A / 120) +
500000.0);
utm.northing =
(double)(k0 * (M + N * tan(latRad) *
(A * A / 2 + (5 - T + 9 * C + 4 * C * C) * A * A * A * A / 24 +
(61 - 58 * T + T * T + 600 * C - 330 * eccPrimeSquared) * A * A * A * A * A * A / 720)));
if (lat < 0) if (lat < 0)
utm.northing += 10000000.0; // 10000000 meter offset for southern hemisphere utm.northing += 10000000.0; // 10000000 meter offset for southern hemisphere
} }
// Converts lat long coordinates to an MGRS. // Converts lat long coordinates to an MGRS.
void GeoCoord::latLongToMGRS(const double lat, const double lon, MGRS &mgrs) { void GeoCoord::latLongToMGRS(const double lat, const double lon, MGRS &mgrs)
{
const std::string e100kLetters[3] = {"ABCDEFGH", "JKLMNPQR", "STUVWXYZ"}; const std::string e100kLetters[3] = {"ABCDEFGH", "JKLMNPQR", "STUVWXYZ"};
const std::string n100kLetters[2] = {"ABCDEFGHJKLMNPQRSTUV", "FGHJKLMNPQRSTUVABCDE"}; const std::string n100kLetters[2] = {"ABCDEFGHJKLMNPQRSTUV", "FGHJKLMNPQRSTUVABCDE"};
UTM utm; UTM utm;
@@ -170,7 +194,8 @@ void GeoCoord::latLongToMGRS(const double lat, const double lon, MGRS &mgrs) {
* Converts lat long coordinates to Ordnance Survey Grid Reference (UK National Grid Ref). * Converts lat long coordinates to Ordnance Survey Grid Reference (UK National Grid Ref).
* Based on: https://www.movable-type.co.uk/scripts/latlong-os-gridref.html * Based on: https://www.movable-type.co.uk/scripts/latlong-os-gridref.html
*/ */
void GeoCoord::latLongToOSGR(const double lat, const double lon, OSGR &osgr) { void GeoCoord::latLongToOSGR(const double lat, const double lon, OSGR &osgr)
{
const char letter[] = "ABCDEFGHJKLMNOPQRSTUVWXYZ"; // No 'I' in OSGR const char letter[] = "ABCDEFGHJKLMNOPQRSTUVWXYZ"; // No 'I' in OSGR
double a = 6377563.396; // Airy 1830 semi-major axis double a = 6377563.396; // Airy 1830 semi-major axis
double b = 6356256.909; // Airy 1830 semi-minor axis double b = 6356256.909; // Airy 1830 semi-minor axis
@@ -211,7 +236,8 @@ void GeoCoord::latLongToOSGR(const double lat, const double lon, OSGR &osgr) {
double deltaLambda = lambda - lambda0; double deltaLambda = lambda - lambda0;
double deltaLambda2 = deltaLambda * deltaLambda; double deltaLambda2 = deltaLambda * deltaLambda;
double northing = I + II*deltaLambda2 + III*deltaLambda2*deltaLambda2 + IIIA*deltaLambda2*deltaLambda2*deltaLambda2; double northing =
I + II * deltaLambda2 + III * deltaLambda2 * deltaLambda2 + IIIA * deltaLambda2 * deltaLambda2 * deltaLambda2;
double easting = e0 + IV * deltaLambda + V * deltaLambda2 * deltaLambda + VI * deltaLambda2 * deltaLambda2 * deltaLambda; double easting = e0 + IV * deltaLambda + V * deltaLambda2 * deltaLambda + VI * deltaLambda2 * deltaLambda2 * deltaLambda;
if (easting < 0 || easting > 700000 || northing < 0 || northing > 1300000) // Check if out of boundaries if (easting < 0 || easting > 700000 || northing < 0 || northing > 1300000) // Check if out of boundaries
@@ -232,7 +258,8 @@ void GeoCoord::latLongToOSGR(const double lat, const double lon, OSGR &osgr) {
* Converts lat long coordinates to Open Location Code. * Converts lat long coordinates to Open Location Code.
* Based on: https://github.com/google/open-location-code/blob/main/c/src/olc.c * Based on: https://github.com/google/open-location-code/blob/main/c/src/olc.c
*/ */
void GeoCoord::latLongToOLC(double lat, double lon, OLC &olc) { void GeoCoord::latLongToOLC(double lat, double lon, OLC &olc)
{
char tempCode[] = "1234567890abc"; char tempCode[] = "1234567890abc";
const char kAlphabet[] = "23456789CFGHJMPQRVWX"; const char kAlphabet[] = "23456789CFGHJMPQRVWX";
double latitude; double latitude;
@@ -304,7 +331,8 @@ void GeoCoord::latLongToOLC(double lat, double lon, OLC &olc) {
} }
// Converts the coordinate in WGS84 datum to the OSGB36 datum. // Converts the coordinate in WGS84 datum to the OSGB36 datum.
void GeoCoord::convertWGS84ToOSGB36(const double lat, const double lon, double &osgb_Latitude, double &osgb_Longitude) { void GeoCoord::convertWGS84ToOSGB36(const double lat, const double lon, double &osgb_Latitude, double &osgb_Longitude)
{
// Convert lat long to cartesian // Convert lat long to cartesian
double phi = toRadians(lat); double phi = toRadians(lat);
double lambda = toRadians(lon); double lambda = toRadians(lon);
@@ -340,7 +368,8 @@ void GeoCoord::convertWGS84ToOSGB36(const double lat, const double lon, double &
double tanBeta = (airyB * osgbZ) / (airyA * p) * (1 + airyEcc2 * airyB / R); double tanBeta = (airyB * osgbZ) / (airyA * p) * (1 + airyEcc2 * airyB / R);
double sinBeta = tanBeta / sqrt(1 + tanBeta * tanBeta); double sinBeta = tanBeta / sqrt(1 + tanBeta * tanBeta);
double cosBeta = sinBeta / tanBeta; double cosBeta = sinBeta / tanBeta;
osgb_Latitude = atan2(osgbZ + airyEcc2*airyB*sinBeta*sinBeta*sinBeta, p - airyEcc*airyA*cosBeta*cosBeta*cosBeta); // leave in radians osgb_Latitude = atan2(osgbZ + airyEcc2 * airyB * sinBeta * sinBeta * sinBeta,
p - airyEcc * airyA * cosBeta * cosBeta * cosBeta); // leave in radians
osgb_Longitude = atan2(osgbY, osgbX); // leave in radians osgb_Longitude = atan2(osgbY, osgbX); // leave in radians
// osgb height = p*cos(osgb.latitude) + osgbZ*sin(osgb.latitude) - // osgb height = p*cos(osgb.latitude) + osgbZ*sin(osgb.latitude) -
//(airyA*airyA/(airyA / sqrt(1 - airyEcc*sin(osgb.latitude)*sin(osgb.latitude)))); // Not used, no OSTN data //(airyA*airyA/(airyA / sqrt(1 - airyEcc*sin(osgb.latitude)*sin(osgb.latitude)))); // Not used, no OSTN data
@@ -399,7 +428,8 @@ float GeoCoord::bearing(double lat1, double lon1, double lat2, double lon2)
* The range in meters * The range in meters
* @return range in radians on a great circle * @return range in radians on a great circle
*/ */
float GeoCoord::rangeMetersToRadians(double range_meters) { float GeoCoord::rangeMetersToRadians(double range_meters)
{
// 1 nm is 1852 meters // 1 nm is 1852 meters
double distance_nm = range_meters * 1852; double distance_nm = range_meters * 1852;
return (PI / (180 * 60)) * distance_nm; return (PI / (180 * 60)) * distance_nm;
@@ -412,20 +442,25 @@ float GeoCoord::rangeMetersToRadians(double range_meters) {
* The range in radians * The range in radians
* @return Range in meters on a great circle * @return Range in meters on a great circle
*/ */
float GeoCoord::rangeRadiansToMeters(double range_radians) { float GeoCoord::rangeRadiansToMeters(double range_radians)
{
double distance_nm = ((180 * 60) / PI) * range_radians; double distance_nm = ((180 * 60) / PI) * range_radians;
// 1 meter is 0.000539957 nm // 1 meter is 0.000539957 nm
return distance_nm * 0.000539957; return distance_nm * 0.000539957;
} }
// Find distance from point to passed in point // Find distance from point to passed in point
int32_t GeoCoord::distanceTo(const GeoCoord& pointB) { int32_t GeoCoord::distanceTo(const GeoCoord &pointB)
return latLongToMeter(this->getLatitude() * 1e-7, this->getLongitude() * 1e-7, pointB.getLatitude() * 1e-7, pointB.getLongitude() * 1e-7); {
return latLongToMeter(this->getLatitude() * 1e-7, this->getLongitude() * 1e-7, pointB.getLatitude() * 1e-7,
pointB.getLongitude() * 1e-7);
} }
// Find bearing from point to passed in point // Find bearing from point to passed in point
int32_t GeoCoord::bearingTo(const GeoCoord& pointB) { int32_t GeoCoord::bearingTo(const GeoCoord &pointB)
return bearing(this->getLatitude() * 1e-7, this->getLongitude() * 1e-7, pointB.getLatitude() * 1e-7, pointB.getLongitude() * 1e-7); {
return bearing(this->getLatitude() * 1e-7, this->getLongitude() * 1e-7, pointB.getLatitude() * 1e-7,
pointB.getLongitude() * 1e-7);
} }
/** /**
@@ -437,7 +472,8 @@ int32_t GeoCoord::bearingTo(const GeoCoord& pointB) {
* range in meters * range in meters
* @return GeoCoord object of point at bearing and range from initial point * @return GeoCoord object of point at bearing and range from initial point
*/ */
std::shared_ptr<GeoCoord> GeoCoord::pointAtDistance(double bearing, double range_meters) { std::shared_ptr<GeoCoord> GeoCoord::pointAtDistance(double bearing, double range_meters)
{
double range_radians = rangeMetersToRadians(range_meters); double range_radians = rangeMetersToRadians(range_meters);
double lat1 = this->getLatitude() * 1e-7; double lat1 = this->getLatitude() * 1e-7;
double lon1 = this->getLongitude() * 1e-7; double lon1 = this->getLongitude() * 1e-7;
@@ -446,5 +482,4 @@ std::shared_ptr<GeoCoord> GeoCoord::pointAtDistance(double bearing, double range
double lon = fmod(lon1 - dlon + PI, 2 * PI) - PI; double lon = fmod(lon1 - dlon + PI, 2 * PI) - PI;
return std::make_shared<GeoCoord>(double(lat), double(lon), this->getAltitude()); return std::make_shared<GeoCoord>(double(lat), double(lon), this->getAltitude());
} }

View File

@@ -1,20 +1,21 @@
#pragma once #pragma once
#include <algorithm> #include <algorithm>
#include <string>
#include <cstring>
#include <cstdint> #include <cstdint>
#include <cstring>
#include <math.h> #include <math.h>
#include <stdint.h>
#include <stdexcept>
#include <memory> #include <memory>
#include <stdexcept>
#include <stdint.h>
#include <string>
#define PI 3.1415926535897932384626433832795 #define PI 3.1415926535897932384626433832795
#define OLC_CODE_LEN 11 #define OLC_CODE_LEN 11
// Helper functions // Helper functions
// Raises a number to an exponent, handling negative exponents. // Raises a number to an exponent, handling negative exponents.
static inline double pow_neg(double base, double exponent) { static inline double pow_neg(double base, double exponent)
{
if (exponent == 0) { if (exponent == 0) {
return 1; return 1;
} else if (exponent > 0) { } else if (exponent > 0) {
@@ -35,8 +36,7 @@ static inline double toDegrees(double r)
// GeoCoord structs/classes // GeoCoord structs/classes
// A struct to hold the data for a DMS coordinate. // A struct to hold the data for a DMS coordinate.
struct DMS struct DMS {
{
uint8_t latDeg; uint8_t latDeg;
uint8_t latMin; uint8_t latMin;
uint32_t latSec; uint32_t latSec;
@@ -48,8 +48,7 @@ struct DMS
}; };
// A struct to hold the data for a UTM coordinate, this is also used when creating an MGRS coordinate. // A struct to hold the data for a UTM coordinate, this is also used when creating an MGRS coordinate.
struct UTM struct UTM {
{
uint8_t zone; uint8_t zone;
char band; char band;
uint32_t easting; uint32_t easting;
@@ -57,8 +56,7 @@ struct UTM
}; };
// A struct to hold the data for a MGRS coordinate. // A struct to hold the data for a MGRS coordinate.
struct MGRS struct MGRS {
{
uint8_t zone; uint8_t zone;
char band; char band;
char east100k; char east100k;
@@ -80,7 +78,8 @@ struct OLC {
char code[OLC_CODE_LEN + 1]; // +1 for null termination char code[OLC_CODE_LEN + 1]; // +1 for null termination
}; };
class GeoCoord { class GeoCoord
{
private: private:
int32_t _latitude = 0; int32_t _latitude = 0;
int32_t _longitude = 0; int32_t _longitude = 0;
@@ -161,4 +160,3 @@ class GeoCoord {
// OLC getter // OLC getter
void getOLCCode(char *code) { strncpy(code, _olc.code, OLC_CODE_LEN + 1); } // +1 for null termination void getOLCCode(char *code) { strncpy(code, _olc.code, OLC_CODE_LEN + 1); } // +1 for null termination
}; };

View File

@@ -1,6 +1,6 @@
#include "configuration.h"
#include "NMEAGPS.h" #include "NMEAGPS.h"
#include "RTC.h" #include "RTC.h"
#include "configuration.h"
#include <TinyGPS++.h> #include <TinyGPS++.h>
@@ -29,9 +29,8 @@ bool NMEAGPS::factoryReset()
// send the UBLOX Factory Reset Command regardless of detect state, something is very wrong, just assume it's UBLOX. // send the UBLOX Factory Reset Command regardless of detect state, something is very wrong, just assume it's UBLOX.
// Factory Reset // Factory Reset
byte _message_reset[] = {0xB5, 0x62, 0x06, 0x09, 0x0D, 0x00, 0xFF, byte _message_reset[] = {0xB5, 0x62, 0x06, 0x09, 0x0D, 0x00, 0xFF, 0xFB, 0x00, 0x00, 0x00,
0xFB, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x17, 0x2B, 0x7E};
0xFF, 0xFF, 0x00, 0x00, 0x17, 0x2B, 0x7E};
_serial_gps->write(_message_reset, sizeof(_message_reset)); _serial_gps->write(_message_reset, sizeof(_message_reset));
delay(1000); delay(1000);
return true; return true;
@@ -85,7 +84,8 @@ The Unix epoch (or Unix time or POSIX time or Unix timestamp) is the number of s
t.tm_year = d.year() - 1900; t.tm_year = d.year() - 1900;
t.tm_isdst = false; t.tm_isdst = false;
if (t.tm_mon > -1) { if (t.tm_mon > -1) {
LOG_DEBUG("NMEA GPS time %02d-%02d-%02d %02d:%02d:%02d\n", d.year(), d.month(), t.tm_mday, t.tm_hour, t.tm_min, t.tm_sec); LOG_DEBUG("NMEA GPS time %02d-%02d-%02d %02d:%02d:%02d\n", d.year(), d.month(), t.tm_mday, t.tm_hour, t.tm_min,
t.tm_sec);
perhapsSetRTC(RTCQualityGPS, t); perhapsSetRTC(RTCQualityGPS, t);
return true; return true;
} else } else
@@ -117,8 +117,7 @@ bool NMEAGPS::lookForLocation()
return false; return false;
#ifdef GPS_EXTRAVERBOSE #ifdef GPS_EXTRAVERBOSE
LOG_DEBUG("AGE: LOC=%d FIX=%d DATE=%d TIME=%d\n", LOG_DEBUG("AGE: LOC=%d FIX=%d DATE=%d TIME=%d\n", reader.location.age(),
reader.location.age(),
#ifndef TINYGPS_OPTION_NO_CUSTOM_FIELDS #ifndef TINYGPS_OPTION_NO_CUSTOM_FIELDS
gsafixtype.age(), gsafixtype.age(),
#else #else
@@ -134,9 +133,7 @@ bool NMEAGPS::lookForLocation()
#ifndef TINYGPS_OPTION_NO_CUSTOM_FIELDS #ifndef TINYGPS_OPTION_NO_CUSTOM_FIELDS
(gsafixtype.age() < GPS_SOL_EXPIRY_MS) && (gsafixtype.age() < GPS_SOL_EXPIRY_MS) &&
#endif #endif
(reader.time.age() < GPS_SOL_EXPIRY_MS) && (reader.time.age() < GPS_SOL_EXPIRY_MS) && (reader.date.age() < GPS_SOL_EXPIRY_MS))) {
(reader.date.age() < GPS_SOL_EXPIRY_MS)))
{
LOG_WARN("SOME data is TOO OLD: LOC %u, TIME %u, DATE %u\n", reader.location.age(), reader.time.age(), reader.date.age()); LOG_WARN("SOME data is TOO OLD: LOC %u, TIME %u, DATE %u\n", reader.location.age(), reader.time.age(), reader.date.age());
return false; return false;
} }
@@ -162,7 +159,7 @@ bool NMEAGPS::lookForLocation()
return false; return false;
} }
p.location_source = Position_LocSource_LOC_INTERNAL; p.location_source = meshtastic_Position_LocSource_LOC_INTERNAL;
// Dilution of precision (an accuracy metric) is reported in 10^2 units, so we need to scale down when we use it // Dilution of precision (an accuracy metric) is reported in 10^2 units, so we need to scale down when we use it
#ifndef TINYGPS_OPTION_NO_CUSTOM_FIELDS #ifndef TINYGPS_OPTION_NO_CUSTOM_FIELDS
@@ -210,10 +207,10 @@ bool NMEAGPS::lookForLocation()
if (reader.course.isUpdated() && reader.course.isValid()) { if (reader.course.isUpdated() && reader.course.isValid()) {
if (reader.course.value() < 36000) { // sanity check if (reader.course.value() < 36000) { // sanity check
p.ground_track = reader.course.value() * 1e3; // Scale the heading (in degrees * 10^-2) to match the expected degrees * 10^-5 p.ground_track =
reader.course.value() * 1e3; // Scale the heading (in degrees * 10^-2) to match the expected degrees * 10^-5
} else { } else {
LOG_WARN("BOGUS course.value() REJECTED: %d\n", LOG_WARN("BOGUS course.value() REJECTED: %d\n", reader.course.value());
reader.course.value());
} }
} }
@@ -224,7 +221,6 @@ bool NMEAGPS::lookForLocation()
return true; return true;
} }
bool NMEAGPS::hasLock() bool NMEAGPS::hasLock()
{ {
// Using GPGGA fix quality indicator // Using GPGGA fix quality indicator

View File

@@ -16,17 +16,13 @@
* ------------------------------------------- * -------------------------------------------
*/ */
uint32_t printWPL(char *buf, size_t bufsz, const Position &pos, const char *name) uint32_t printWPL(char *buf, size_t bufsz, const meshtastic_Position &pos, const char *name)
{ {
GeoCoord geoCoord(pos.latitude_i, pos.longitude_i, pos.altitude); GeoCoord geoCoord(pos.latitude_i, pos.longitude_i, pos.altitude);
uint32_t len = snprintf(buf, bufsz, "$GNWPL,%02d%07.4f,%c,%03d%07.4f,%c,%s", uint32_t len = snprintf(buf, bufsz, "$GNWPL,%02d%07.4f,%c,%03d%07.4f,%c,%s", geoCoord.getDMSLatDeg(),
geoCoord.getDMSLatDeg(), (abs(geoCoord.getLatitude()) - geoCoord.getDMSLatDeg() * 1e+7) * 6e-6, geoCoord.getDMSLatCP(),
(abs(geoCoord.getLatitude()) - geoCoord.getDMSLatDeg() * 1e+7) * 6e-6, geoCoord.getDMSLonDeg(), (abs(geoCoord.getLongitude()) - geoCoord.getDMSLonDeg() * 1e+7) * 6e-6,
geoCoord.getDMSLatCP(), geoCoord.getDMSLonCP(), name);
geoCoord.getDMSLonDeg(),
(abs(geoCoord.getLongitude()) - geoCoord.getDMSLonDeg() * 1e+7) * 6e-6,
geoCoord.getDMSLonCP(),
name);
uint32_t chk = 0; uint32_t chk = 0;
for (uint32_t i = 1; i < len; i++) { for (uint32_t i = 1; i < len; i++) {
chk ^= buf[i]; chk ^= buf[i];
@@ -51,35 +47,21 @@ uint32_t printWPL(char *buf, size_t bufsz, const Position &pos, const char *name
* 8 Horizontal Dilution of precision (meters) * 8 Horizontal Dilution of precision (meters)
* 9 Antenna Altitude above/below mean-sea-level (geoid) (in meters) * 9 Antenna Altitude above/below mean-sea-level (geoid) (in meters)
* 10 Units of antenna altitude, meters * 10 Units of antenna altitude, meters
* 11 Geoidal separation, the difference between the WGS-84 earth ellipsoid and mean-sea-level (geoid), "-" means mean-sea-level below ellipsoid * 11 Geoidal separation, the difference between the WGS-84 earth ellipsoid and mean-sea-level (geoid), "-" means mean-sea-level
* 12 Units of geoidal separation, meters * below ellipsoid 12 Units of geoidal separation, meters 13 Age of differential GPS data, time in seconds since last SC104 type 1
* 13 Age of differential GPS data, time in seconds since last SC104 type 1 or 9 update, null field when DGPS is not used * or 9 update, null field when DGPS is not used 14 Differential reference station ID, 0000-1023 15 Checksum
* 14 Differential reference station ID, 0000-1023
* 15 Checksum
* ------------------------------------------- * -------------------------------------------
*/ */
uint32_t printGGA(char *buf, size_t bufsz, const Position &pos) uint32_t printGGA(char *buf, size_t bufsz, const meshtastic_Position &pos)
{ {
GeoCoord geoCoord(pos.latitude_i, pos.longitude_i, pos.altitude); GeoCoord geoCoord(pos.latitude_i, pos.longitude_i, pos.altitude);
uint32_t len = snprintf(buf, bufsz, "$GNGGA,%06u.%03u,%02d%07.4f,%c,%03d%07.4f,%c,%u,%02u,%04u,%04d,%c,%04d,%c,%d,%04d", uint32_t len =
pos.time / 1000, snprintf(buf, bufsz, "$GNGGA,%06u.%03u,%02d%07.4f,%c,%03d%07.4f,%c,%u,%02u,%04u,%04d,%c,%04d,%c,%d,%04d", pos.time / 1000,
pos.time % 1000, pos.time % 1000, geoCoord.getDMSLatDeg(), (abs(geoCoord.getLatitude()) - geoCoord.getDMSLatDeg() * 1e+7) * 6e-6,
geoCoord.getDMSLatDeg(), geoCoord.getDMSLatCP(), geoCoord.getDMSLonDeg(),
(abs(geoCoord.getLatitude()) - geoCoord.getDMSLatDeg() * 1e+7) * 6e-6, (abs(geoCoord.getLongitude()) - geoCoord.getDMSLonDeg() * 1e+7) * 6e-6, geoCoord.getDMSLonCP(), pos.fix_type,
geoCoord.getDMSLatCP(), pos.sats_in_view, pos.HDOP, geoCoord.getAltitude(), 'M', pos.altitude_geoidal_separation, 'M', 0, 0);
geoCoord.getDMSLonDeg(),
(abs(geoCoord.getLongitude()) - geoCoord.getDMSLonDeg() * 1e+7) * 6e-6,
geoCoord.getDMSLonCP(),
pos.fix_type,
pos.sats_in_view,
pos.HDOP,
geoCoord.getAltitude(),
'M',
pos.altitude_geoidal_separation,
'M',
0,
0);
uint32_t chk = 0; uint32_t chk = 0;
for (uint32_t i = 1; i < len; i++) { for (uint32_t i = 1; i < len; i++) {

View File

@@ -1,7 +1,7 @@
#pragma once #pragma once
#include <Arduino.h>
#include "main.h" #include "main.h"
#include <Arduino.h>
uint32_t printWPL(char *buf, size_t bufsz, const Position &pos, const char *name); uint32_t printWPL(char *buf, size_t bufsz, const meshtastic_Position &pos, const char *name);
uint32_t printGGA(char *buf, size_t bufsz, const Position &pos); uint32_t printGGA(char *buf, size_t bufsz, const meshtastic_Position &pos);

View File

@@ -91,8 +91,7 @@ bool perhapsSetRTC(RTCQuality q, const struct timeval *tv)
// Every 12 hrs we will slam in a new GPS time, to correct for local RTC clock drift // Every 12 hrs we will slam in a new GPS time, to correct for local RTC clock drift
shouldSet = true; shouldSet = true;
LOG_DEBUG("Reapplying external time to correct clock drift %ld secs\n", tv->tv_sec); LOG_DEBUG("Reapplying external time to correct clock drift %ld secs\n", tv->tv_sec);
} } else
else
shouldSet = false; shouldSet = false;
if (shouldSet) { if (shouldSet) {
@@ -109,7 +108,8 @@ bool perhapsSetRTC(RTCQuality q, const struct timeval *tv)
rtc.initI2C(); rtc.initI2C();
tm *t = localtime(&tv->tv_sec); tm *t = localtime(&tv->tv_sec);
rtc.setTime(t->tm_year + 1900, t->tm_mon + 1, t->tm_wday, t->tm_mday, t->tm_hour, t->tm_min, t->tm_sec); rtc.setTime(t->tm_year + 1900, t->tm_mon + 1, t->tm_wday, t->tm_mday, t->tm_hour, t->tm_min, t->tm_sec);
LOG_DEBUG("RV3028_RTC setTime %02d-%02d-%02d %02d:%02d:%02d %ld\n", t->tm_year + 1900, t->tm_mon + 1, t->tm_mday, t->tm_hour, t->tm_min, t->tm_sec, tv->tv_sec); LOG_DEBUG("RV3028_RTC setTime %02d-%02d-%02d %02d:%02d:%02d %ld\n", t->tm_year + 1900, t->tm_mon + 1, t->tm_mday,
t->tm_hour, t->tm_min, t->tm_sec, tv->tv_sec);
} }
#elif defined(PCF8563_RTC) #elif defined(PCF8563_RTC)
if (rtc_found == PCF8563_RTC) { if (rtc_found == PCF8563_RTC) {
@@ -121,7 +121,8 @@ bool perhapsSetRTC(RTCQuality q, const struct timeval *tv)
#endif #endif
tm *t = localtime(&tv->tv_sec); tm *t = localtime(&tv->tv_sec);
rtc.setDateTime(t->tm_year + 1900, t->tm_mon + 1, t->tm_mday, t->tm_hour, t->tm_min, t->tm_sec); rtc.setDateTime(t->tm_year + 1900, t->tm_mon + 1, t->tm_mday, t->tm_hour, t->tm_min, t->tm_sec);
LOG_DEBUG("PCF8563_RTC setDateTime %02d-%02d-%02d %02d:%02d:%02d %ld\n", t->tm_year + 1900, t->tm_mon + 1, t->tm_mday, t->tm_hour, t->tm_min, t->tm_sec, tv->tv_sec); LOG_DEBUG("PCF8563_RTC setDateTime %02d-%02d-%02d %02d:%02d:%02d %ld\n", t->tm_year + 1900, t->tm_mon + 1, t->tm_mday,
t->tm_hour, t->tm_min, t->tm_sec, tv->tv_sec);
} }
#elif defined(ARCH_ESP32) #elif defined(ARCH_ESP32)
settimeofday(tv, NULL); settimeofday(tv, NULL);

View File

@@ -1,11 +1,11 @@
#include "configuration.h" #include "configuration.h"
#ifdef USE_EINK #ifdef USE_EINK
#include "main.h"
#include "EInkDisplay2.h" #include "EInkDisplay2.h"
#include "SPILock.h"
#include <SPI.h>
#include "GxEPD2_BW.h" #include "GxEPD2_BW.h"
#include "SPILock.h"
#include "main.h"
#include <SPI.h>
#define COLORED GxEPD_BLACK #define COLORED GxEPD_BLACK
#define UNCOLORED GxEPD_WHITE #define UNCOLORED GxEPD_WHITE
@@ -14,7 +14,8 @@
#define TECHO_DISPLAY_MODEL GxEPD2_154_D67 #define TECHO_DISPLAY_MODEL GxEPD2_154_D67
#elif defined(RAK4630) #elif defined(RAK4630)
//GxEPD2_213_BN - RAK14000 2.13 inch b/w 250x122 - changed from GxEPD2_213_B74 - which was not going to give partial update support // GxEPD2_213_BN - RAK14000 2.13 inch b/w 250x122 - changed from GxEPD2_213_B74 - which was not going to give partial update
// support
#define TECHO_DISPLAY_MODEL GxEPD2_213_BN #define TECHO_DISPLAY_MODEL GxEPD2_213_BN
// 4.2 inch 300x400 - GxEPD2_420_M01 // 4.2 inch 300x400 - GxEPD2_420_M01
@@ -40,7 +41,7 @@
GxEPD2_BW<TECHO_DISPLAY_MODEL, TECHO_DISPLAY_MODEL::HEIGHT> *adafruitDisplay; GxEPD2_BW<TECHO_DISPLAY_MODEL, TECHO_DISPLAY_MODEL::HEIGHT> *adafruitDisplay;
EInkDisplay::EInkDisplay(uint8_t address, int sda, int scl) EInkDisplay::EInkDisplay(uint8_t address, int sda, int scl, uint8_t screen_model)
{ {
#if defined(TTGO_T_ECHO) #if defined(TTGO_T_ECHO)
setGeometry(GEOMETRY_RAWMODE, TECHO_DISPLAY_MODEL::WIDTH, TECHO_DISPLAY_MODEL::HEIGHT); setGeometry(GEOMETRY_RAWMODE, TECHO_DISPLAY_MODEL::WIDTH, TECHO_DISPLAY_MODEL::HEIGHT);
@@ -175,7 +176,6 @@ bool EInkDisplay::connect()
pinMode(PIN_EINK_EN, OUTPUT); pinMode(PIN_EINK_EN, OUTPUT);
#endif #endif
#if defined(TTGO_T_ECHO) #if defined(TTGO_T_ECHO)
{ {
auto lowLevel = new TECHO_DISPLAY_MODEL(PIN_EINK_CS, PIN_EINK_DC, PIN_EINK_RES, PIN_EINK_BUSY, SPI1); auto lowLevel = new TECHO_DISPLAY_MODEL(PIN_EINK_CS, PIN_EINK_DC, PIN_EINK_RES, PIN_EINK_BUSY, SPI1);
@@ -218,7 +218,6 @@ bool EInkDisplay::connect()
adafruitDisplay->setPartialWindow(0, 0, EPD_WIDTH, EPD_HEIGHT); adafruitDisplay->setPartialWindow(0, 0, EPD_WIDTH, EPD_HEIGHT);
#endif #endif
// adafruitDisplay->setFullWindow(); // adafruitDisplay->setFullWindow();
// adafruitDisplay->fillScreen(UNCOLORED); // adafruitDisplay->fillScreen(UNCOLORED);
// adafruitDisplay->drawCircle(100, 100, 20, COLORED); // adafruitDisplay->drawCircle(100, 100, 20, COLORED);

View File

@@ -22,7 +22,7 @@ class EInkDisplay : public OLEDDisplay
/* constructor /* constructor
FIXME - the parameters are not used, just a temporary hack to keep working like the old displays FIXME - the parameters are not used, just a temporary hack to keep working like the old displays
*/ */
EInkDisplay(uint8_t address, int sda, int scl); EInkDisplay(uint8_t address, int sda, int scl, uint8_t screen_model);
// Write the buffer to the display memory (for eink we only do this occasionally) // Write the buffer to the display memory (for eink we only do this occasionally)
virtual void display(void) override; virtual void display(void) override;
@@ -50,5 +50,3 @@ class EInkDisplay : public OLEDDisplay
// Connect to the display // Connect to the display
virtual bool connect() override; virtual bool connect() override;
}; };

View File

@@ -352,7 +352,7 @@ static void drawCriticalFaultFrame(OLEDDisplay *display, OLEDDisplayUiState *sta
} }
// Ignore messages orginating from phone (from the current node 0x0) unless range test or store and forward module are enabled // Ignore messages orginating from phone (from the current node 0x0) unless range test or store and forward module are enabled
static bool shouldDrawMessage(const MeshPacket *packet) static bool shouldDrawMessage(const meshtastic_MeshPacket *packet)
{ {
return packet->from != 0 && !moduleConfig.range_test.enabled && !moduleConfig.store_forward.enabled; return packet->from != 0 && !moduleConfig.range_test.enabled && !moduleConfig.store_forward.enabled;
} }
@@ -365,8 +365,8 @@ static void drawTextMessageFrame(OLEDDisplay *display, OLEDDisplayUiState *state
// the max length of this buffer is much longer than we can possibly print // the max length of this buffer is much longer than we can possibly print
static char tempBuf[237]; static char tempBuf[237];
MeshPacket &mp = devicestate.rx_text_message; meshtastic_MeshPacket &mp = devicestate.rx_text_message;
NodeInfo *node = nodeDB.getNode(getFrom(&mp)); meshtastic_NodeInfo *node = nodeDB.getNode(getFrom(&mp));
// LOG_DEBUG("drawing text message from 0x%x: %s\n", mp.from, // LOG_DEBUG("drawing text message from 0x%x: %s\n", mp.from,
// mp.decoded.variant.data.decoded.bytes); // mp.decoded.variant.data.decoded.bytes);
@@ -375,14 +375,20 @@ static void drawTextMessageFrame(OLEDDisplay *display, OLEDDisplayUiState *state
// be wrapped. Currently only spaces and "-" are allowed for wrapping // be wrapped. Currently only spaces and "-" are allowed for wrapping
display->setTextAlignment(TEXT_ALIGN_LEFT); display->setTextAlignment(TEXT_ALIGN_LEFT);
display->setFont(FONT_SMALL); display->setFont(FONT_SMALL);
if (config.display.displaymode == Config_DisplayConfig_DisplayMode_INVERTED) { if (config.display.displaymode == meshtastic_Config_DisplayConfig_DisplayMode_INVERTED) {
display->fillRect(0 + x, 0 + y, x + display->getWidth(), y + FONT_HEIGHT_SMALL); display->fillRect(0 + x, 0 + y, x + display->getWidth(), y + FONT_HEIGHT_SMALL);
display->setColor(BLACK); display->setColor(BLACK);
} }
display->drawStringf(0 + x, 0 + y, tempBuf, "From: %s", (node && node->has_user) ? node->user.short_name : "???");
tm *tm = localtime(reinterpret_cast<const time_t *>(&mp.rx_time));
if (config.display.heading_bold) { if (config.display.heading_bold) {
display->drawStringf(1 + x, 0 + y, tempBuf, "From: %s", (node && node->has_user) ? node->user.short_name : "???"); display->drawStringf(1 + x, 0 + y, tempBuf, "[%02d:%02d:%02d] From: %s", tm->tm_hour, tm->tm_min, tm->tm_sec,
(node && node->has_user) ? node->user.short_name : "???");
} }
display->drawStringf(0 + x, 0 + y, tempBuf, "[%02d:%02d:%02d] From: %s", tm->tm_hour, tm->tm_min, tm->tm_sec,
(node && node->has_user) ? node->user.short_name : "???");
display->setColor(WHITE); display->setColor(WHITE);
snprintf(tempBuf, sizeof(tempBuf), "%s", mp.decoded.payload.bytes); snprintf(tempBuf, sizeof(tempBuf), "%s", mp.decoded.payload.bytes);
display->drawStringMaxWidth(0 + x, 0 + y + FONT_HEIGHT_SMALL, x + display->getWidth(), tempBuf); display->drawStringMaxWidth(0 + x, 0 + y + FONT_HEIGHT_SMALL, x + display->getWidth(), tempBuf);
@@ -556,7 +562,7 @@ static void drawGPSAltitude(OLEDDisplay *display, int16_t x, int16_t y, const GP
} else { } else {
geoCoord.updateCoords(int32_t(gps->getLatitude()), int32_t(gps->getLongitude()), int32_t(gps->getAltitude())); geoCoord.updateCoords(int32_t(gps->getLatitude()), int32_t(gps->getLongitude()), int32_t(gps->getAltitude()));
displayLine = "Altitude: " + String(geoCoord.getAltitude()) + "m"; displayLine = "Altitude: " + String(geoCoord.getAltitude()) + "m";
if (config.display.units == Config_DisplayConfig_DisplayUnits_IMPERIAL) if (config.display.units == meshtastic_Config_DisplayConfig_DisplayUnits_IMPERIAL)
displayLine = "Altitude: " + String(geoCoord.getAltitude() * METERS_TO_FEET) + "ft"; displayLine = "Altitude: " + String(geoCoord.getAltitude() * METERS_TO_FEET) + "ft";
display->drawString(x + (SCREEN_WIDTH - (display->getStringWidth(displayLine))) / 2, y, displayLine); display->drawString(x + (SCREEN_WIDTH - (display->getStringWidth(displayLine))) / 2, y, displayLine);
} }
@@ -578,21 +584,21 @@ static void drawGPScoordinates(OLEDDisplay *display, int16_t x, int16_t y, const
geoCoord.updateCoords(int32_t(gps->getLatitude()), int32_t(gps->getLongitude()), int32_t(gps->getAltitude())); geoCoord.updateCoords(int32_t(gps->getLatitude()), int32_t(gps->getLongitude()), int32_t(gps->getAltitude()));
if (gpsFormat != Config_DisplayConfig_GpsCoordinateFormat_DMS) { if (gpsFormat != meshtastic_Config_DisplayConfig_GpsCoordinateFormat_DMS) {
char coordinateLine[22]; char coordinateLine[22];
if (gpsFormat == Config_DisplayConfig_GpsCoordinateFormat_DEC) { // Decimal Degrees if (gpsFormat == meshtastic_Config_DisplayConfig_GpsCoordinateFormat_DEC) { // Decimal Degrees
snprintf(coordinateLine, sizeof(coordinateLine), "%f %f", geoCoord.getLatitude() * 1e-7, snprintf(coordinateLine, sizeof(coordinateLine), "%f %f", geoCoord.getLatitude() * 1e-7,
geoCoord.getLongitude() * 1e-7); geoCoord.getLongitude() * 1e-7);
} else if (gpsFormat == Config_DisplayConfig_GpsCoordinateFormat_UTM) { // Universal Transverse Mercator } else if (gpsFormat == meshtastic_Config_DisplayConfig_GpsCoordinateFormat_UTM) { // Universal Transverse Mercator
snprintf(coordinateLine, sizeof(coordinateLine), "%2i%1c %06u %07u", geoCoord.getUTMZone(), geoCoord.getUTMBand(), snprintf(coordinateLine, sizeof(coordinateLine), "%2i%1c %06u %07u", geoCoord.getUTMZone(), geoCoord.getUTMBand(),
geoCoord.getUTMEasting(), geoCoord.getUTMNorthing()); geoCoord.getUTMEasting(), geoCoord.getUTMNorthing());
} else if (gpsFormat == Config_DisplayConfig_GpsCoordinateFormat_MGRS) { // Military Grid Reference System } else if (gpsFormat == meshtastic_Config_DisplayConfig_GpsCoordinateFormat_MGRS) { // Military Grid Reference System
snprintf(coordinateLine, sizeof(coordinateLine), "%2i%1c %1c%1c %05u %05u", geoCoord.getMGRSZone(), snprintf(coordinateLine, sizeof(coordinateLine), "%2i%1c %1c%1c %05u %05u", geoCoord.getMGRSZone(),
geoCoord.getMGRSBand(), geoCoord.getMGRSEast100k(), geoCoord.getMGRSNorth100k(), geoCoord.getMGRSBand(), geoCoord.getMGRSEast100k(), geoCoord.getMGRSNorth100k(),
geoCoord.getMGRSEasting(), geoCoord.getMGRSNorthing()); geoCoord.getMGRSEasting(), geoCoord.getMGRSNorthing());
} else if (gpsFormat == Config_DisplayConfig_GpsCoordinateFormat_OLC) { // Open Location Code } else if (gpsFormat == meshtastic_Config_DisplayConfig_GpsCoordinateFormat_OLC) { // Open Location Code
geoCoord.getOLCCode(coordinateLine); geoCoord.getOLCCode(coordinateLine);
} else if (gpsFormat == Config_DisplayConfig_GpsCoordinateFormat_OSGR) { // Ordnance Survey Grid Reference } else if (gpsFormat == meshtastic_Config_DisplayConfig_GpsCoordinateFormat_OSGR) { // Ordnance Survey Grid Reference
if (geoCoord.getOSGRE100k() == 'I' || geoCoord.getOSGRN100k() == 'I') // OSGR is only valid around the UK region if (geoCoord.getOSGRE100k() == 'I' || geoCoord.getOSGRN100k() == 'I') // OSGR is only valid around the UK region
snprintf(coordinateLine, sizeof(coordinateLine), "%s", "Out of Boundary"); snprintf(coordinateLine, sizeof(coordinateLine), "%s", "Out of Boundary");
else else
@@ -610,7 +616,6 @@ static void drawGPScoordinates(OLEDDisplay *display, int16_t x, int16_t y, const
} else { } else {
display->drawString(x + (SCREEN_WIDTH - (display->getStringWidth(coordinateLine))) / 2, y, coordinateLine); display->drawString(x + (SCREEN_WIDTH - (display->getStringWidth(coordinateLine))) / 2, y, coordinateLine);
} }
} else { } else {
char latLine[22]; char latLine[22];
char lonLine[22]; char lonLine[22];
@@ -699,7 +704,7 @@ static float estimatedHeading(double lat, double lon)
/// Sometimes we will have Position objects that only have a time, so check for /// Sometimes we will have Position objects that only have a time, so check for
/// valid lat/lon /// valid lat/lon
static bool hasPosition(NodeInfo *n) static bool hasPosition(meshtastic_NodeInfo *n)
{ {
return n->has_position && (n->position.latitude_i != 0 || n->position.longitude_i != 0); return n->has_position && (n->position.latitude_i != 0 || n->position.longitude_i != 0);
} }
@@ -709,7 +714,7 @@ static uint16_t getCompassDiam(OLEDDisplay *display)
uint16_t diam = 0; uint16_t diam = 0;
uint16_t offset = 0; uint16_t offset = 0;
if (config.display.displaymode != Config_DisplayConfig_DisplayMode_DEFAULT) if (config.display.displaymode != meshtastic_Config_DisplayConfig_DisplayMode_DEFAULT)
offset = FONT_HEIGHT_SMALL; offset = FONT_HEIGHT_SMALL;
// get the smaller of the 2 dimensions and subtract 20 // get the smaller of the 2 dimensions and subtract 20
@@ -786,7 +791,7 @@ static void drawNodeInfo(OLEDDisplay *display, OLEDDisplayUiState *state, int16_
prevFrame = state->currentFrame; prevFrame = state->currentFrame;
nodeIndex = (nodeIndex + 1) % nodeDB.getNumNodes(); nodeIndex = (nodeIndex + 1) % nodeDB.getNumNodes();
NodeInfo *n = nodeDB.getNodeByIndex(nodeIndex); meshtastic_NodeInfo *n = nodeDB.getNodeByIndex(nodeIndex);
if (n->num == nodeDB.getNodeNum()) { if (n->num == nodeDB.getNodeNum()) {
// Don't show our node, just skip to next // Don't show our node, just skip to next
nodeIndex = (nodeIndex + 1) % nodeDB.getNumNodes(); nodeIndex = (nodeIndex + 1) % nodeDB.getNumNodes();
@@ -795,14 +800,14 @@ static void drawNodeInfo(OLEDDisplay *display, OLEDDisplayUiState *state, int16_
displayedNodeNum = n->num; displayedNodeNum = n->num;
} }
NodeInfo *node = nodeDB.getNodeByIndex(nodeIndex); meshtastic_NodeInfo *node = nodeDB.getNodeByIndex(nodeIndex);
display->setFont(FONT_SMALL); display->setFont(FONT_SMALL);
// The coordinates define the left starting point of the text // The coordinates define the left starting point of the text
display->setTextAlignment(TEXT_ALIGN_LEFT); display->setTextAlignment(TEXT_ALIGN_LEFT);
if (config.display.displaymode == Config_DisplayConfig_DisplayMode_INVERTED) { if (config.display.displaymode == meshtastic_Config_DisplayConfig_DisplayMode_INVERTED) {
display->fillRect(0 + x, 0 + y, x + display->getWidth(), y + FONT_HEIGHT_SMALL); display->fillRect(0 + x, 0 + y, x + display->getWidth(), y + FONT_HEIGHT_SMALL);
} }
@@ -832,12 +837,12 @@ static void drawNodeInfo(OLEDDisplay *display, OLEDDisplayUiState *state, int16_
static char distStr[20]; static char distStr[20];
strncpy(distStr, "? km", sizeof(distStr)); // might not have location data strncpy(distStr, "? km", sizeof(distStr)); // might not have location data
NodeInfo *ourNode = nodeDB.getNode(nodeDB.getNodeNum()); meshtastic_NodeInfo *ourNode = nodeDB.getNode(nodeDB.getNodeNum());
const char *fields[] = {username, distStr, signalStr, lastStr, NULL}; const char *fields[] = {username, distStr, signalStr, lastStr, NULL};
int16_t compassX = 0, compassY = 0; int16_t compassX = 0, compassY = 0;
// coordinates for the center of the compass/circle // coordinates for the center of the compass/circle
if (config.display.displaymode == Config_DisplayConfig_DisplayMode_DEFAULT) { if (config.display.displaymode == meshtastic_Config_DisplayConfig_DisplayMode_DEFAULT) {
compassX = x + SCREEN_WIDTH - getCompassDiam(display) / 2 - 5; compassX = x + SCREEN_WIDTH - getCompassDiam(display) / 2 - 5;
compassY = y + SCREEN_HEIGHT / 2; compassY = y + SCREEN_HEIGHT / 2;
} else { } else {
@@ -847,18 +852,18 @@ static void drawNodeInfo(OLEDDisplay *display, OLEDDisplayUiState *state, int16_
bool hasNodeHeading = false; bool hasNodeHeading = false;
if (ourNode && hasPosition(ourNode)) { if (ourNode && hasPosition(ourNode)) {
Position &op = ourNode->position; meshtastic_Position &op = ourNode->position;
float myHeading = estimatedHeading(DegD(op.latitude_i), DegD(op.longitude_i)); float myHeading = estimatedHeading(DegD(op.latitude_i), DegD(op.longitude_i));
drawCompassNorth(display, compassX, compassY, myHeading); drawCompassNorth(display, compassX, compassY, myHeading);
if (hasPosition(node)) { if (hasPosition(node)) {
// display direction toward node // display direction toward node
hasNodeHeading = true; hasNodeHeading = true;
Position &p = node->position; meshtastic_Position &p = node->position;
float d = float d =
GeoCoord::latLongToMeter(DegD(p.latitude_i), DegD(p.longitude_i), DegD(op.latitude_i), DegD(op.longitude_i)); GeoCoord::latLongToMeter(DegD(p.latitude_i), DegD(p.longitude_i), DegD(op.latitude_i), DegD(op.longitude_i));
if (config.display.units == Config_DisplayConfig_DisplayUnits_IMPERIAL) { if (config.display.units == meshtastic_Config_DisplayConfig_DisplayUnits_IMPERIAL) {
if (d < (2 * MILES_TO_FEET)) if (d < (2 * MILES_TO_FEET))
snprintf(distStr, sizeof(distStr), "%.0f ft", d * METERS_TO_FEET); snprintf(distStr, sizeof(distStr), "%.0f ft", d * METERS_TO_FEET);
else else
@@ -887,7 +892,7 @@ static void drawNodeInfo(OLEDDisplay *display, OLEDDisplayUiState *state, int16_
} }
display->drawCircle(compassX, compassY, getCompassDiam(display) / 2); display->drawCircle(compassX, compassY, getCompassDiam(display) / 2);
if (config.display.displaymode == Config_DisplayConfig_DisplayMode_INVERTED) { if (config.display.displaymode == meshtastic_Config_DisplayConfig_DisplayMode_INVERTED) {
display->setColor(BLACK); display->setColor(BLACK);
} }
// Must be after distStr is populated // Must be after distStr is populated
@@ -908,7 +913,11 @@ static void drawNodeInfo(OLEDDisplay *display, OLEDDisplayUiState *state, int16_
// } // }
// } // }
// #else // #else
Screen::Screen(uint8_t address, int sda, int scl) : OSThread("Screen"), cmdQueue(32), dispdev(address, sda, scl), ui(&dispdev) Screen::Screen(uint8_t address, int sda, int scl)
: OSThread("Screen"), cmdQueue(32),
dispdev(address, sda, scl,
screen_model == meshtastic_Config_DisplayConfig_OledType_OLED_SH1107 ? GEOMETRY_128_128 : GEOMETRY_128_64),
ui(&dispdev)
{ {
address_found = address; address_found = address;
cmdQueue.setReader(this); cmdQueue.setReader(this);
@@ -958,6 +967,8 @@ void Screen::setup()
useDisplay = true; useDisplay = true;
#ifdef AutoOLEDWire_h #ifdef AutoOLEDWire_h
if (screen_model == meshtastic_Config_DisplayConfig_OledType_OLED_SH1107)
screen_model = meshtastic_Config_DisplayConfig_OledType_OLED_SH1106;
dispdev.setDetected(screen_model); dispdev.setDetected(screen_model);
#endif #endif
@@ -1079,7 +1090,7 @@ int32_t Screen::runOnce()
} }
#ifndef DISABLE_WELCOME_UNSET #ifndef DISABLE_WELCOME_UNSET
if (showingNormalScreen && config.lora.region == Config_LoRaConfig_RegionCode_UNSET) { if (showingNormalScreen && config.lora.region == meshtastic_Config_LoRaConfig_RegionCode_UNSET) {
setWelcomeFrames(); setWelcomeFrames();
} }
#endif #endif
@@ -1399,7 +1410,7 @@ void DebugInfo::drawFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16
// The coordinates define the left starting point of the text // The coordinates define the left starting point of the text
display->setTextAlignment(TEXT_ALIGN_LEFT); display->setTextAlignment(TEXT_ALIGN_LEFT);
if (config.display.displaymode == Config_DisplayConfig_DisplayMode_INVERTED) { if (config.display.displaymode == meshtastic_Config_DisplayConfig_DisplayMode_INVERTED) {
display->fillRect(0 + x, 0 + y, x + display->getWidth(), y + FONT_HEIGHT_SMALL); display->fillRect(0 + x, 0 + y, x + display->getWidth(), y + FONT_HEIGHT_SMALL);
display->setColor(BLACK); display->setColor(BLACK);
} }
@@ -1413,20 +1424,20 @@ void DebugInfo::drawFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16
// Display power status // Display power status
if (powerStatus->getHasBattery()) { if (powerStatus->getHasBattery()) {
if (config.display.displaymode == Config_DisplayConfig_DisplayMode_DEFAULT) { if (config.display.displaymode == meshtastic_Config_DisplayConfig_DisplayMode_DEFAULT) {
drawBattery(display, x, y + 2, imgBattery, powerStatus); drawBattery(display, x, y + 2, imgBattery, powerStatus);
} else { } else {
drawBattery(display, x + 1, y + 3, imgBattery, powerStatus); drawBattery(display, x + 1, y + 3, imgBattery, powerStatus);
} }
} else if (powerStatus->knowsUSB()) { } else if (powerStatus->knowsUSB()) {
if (config.display.displaymode == Config_DisplayConfig_DisplayMode_DEFAULT) { if (config.display.displaymode == meshtastic_Config_DisplayConfig_DisplayMode_DEFAULT) {
display->drawFastImage(x, y + 2, 16, 8, powerStatus->getHasUSB() ? imgUSB : imgPower); display->drawFastImage(x, y + 2, 16, 8, powerStatus->getHasUSB() ? imgUSB : imgPower);
} else { } else {
display->drawFastImage(x + 1, y + 3, 16, 8, powerStatus->getHasUSB() ? imgUSB : imgPower); display->drawFastImage(x + 1, y + 3, 16, 8, powerStatus->getHasUSB() ? imgUSB : imgPower);
} }
} }
// Display nodes status // Display nodes status
if (config.display.displaymode == Config_DisplayConfig_DisplayMode_DEFAULT) { if (config.display.displaymode == meshtastic_Config_DisplayConfig_DisplayMode_DEFAULT) {
drawNodes(display, x + (SCREEN_WIDTH * 0.25), y + 2, nodeStatus); drawNodes(display, x + (SCREEN_WIDTH * 0.25), y + 2, nodeStatus);
} else { } else {
drawNodes(display, x + (SCREEN_WIDTH * 0.25), y + 3, nodeStatus); drawNodes(display, x + (SCREEN_WIDTH * 0.25), y + 3, nodeStatus);
@@ -1439,7 +1450,7 @@ void DebugInfo::drawFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16
#endif #endif
drawGPSpowerstat(display, x, yPos, gpsStatus); drawGPSpowerstat(display, x, yPos, gpsStatus);
} else { } else {
if (config.display.displaymode == Config_DisplayConfig_DisplayMode_DEFAULT) { if (config.display.displaymode == meshtastic_Config_DisplayConfig_DisplayMode_DEFAULT) {
drawGPS(display, x + (SCREEN_WIDTH * 0.63), y + 2, gpsStatus); drawGPS(display, x + (SCREEN_WIDTH * 0.63), y + 2, gpsStatus);
} else { } else {
drawGPS(display, x + (SCREEN_WIDTH * 0.63), y + 3, gpsStatus); drawGPS(display, x + (SCREEN_WIDTH * 0.63), y + 3, gpsStatus);
@@ -1512,7 +1523,7 @@ void DebugInfo::drawFrameWiFi(OLEDDisplay *display, OLEDDisplayUiState *state, i
// The coordinates define the left starting point of the text // The coordinates define the left starting point of the text
display->setTextAlignment(TEXT_ALIGN_LEFT); display->setTextAlignment(TEXT_ALIGN_LEFT);
if (config.display.displaymode == Config_DisplayConfig_DisplayMode_INVERTED) { if (config.display.displaymode == meshtastic_Config_DisplayConfig_DisplayMode_INVERTED) {
display->fillRect(0 + x, 0 + y, x + display->getWidth(), y + FONT_HEIGHT_SMALL); display->fillRect(0 + x, 0 + y, x + display->getWidth(), y + FONT_HEIGHT_SMALL);
display->setColor(BLACK); display->setColor(BLACK);
} }
@@ -1644,7 +1655,7 @@ void DebugInfo::drawFrameSettings(OLEDDisplay *display, OLEDDisplayUiState *stat
// The coordinates define the left starting point of the text // The coordinates define the left starting point of the text
display->setTextAlignment(TEXT_ALIGN_LEFT); display->setTextAlignment(TEXT_ALIGN_LEFT);
if (config.display.displaymode == Config_DisplayConfig_DisplayMode_INVERTED) { if (config.display.displaymode == meshtastic_Config_DisplayConfig_DisplayMode_INVERTED) {
display->fillRect(0 + x, 0 + y, x + display->getWidth(), y + FONT_HEIGHT_SMALL); display->fillRect(0 + x, 0 + y, x + display->getWidth(), y + FONT_HEIGHT_SMALL);
display->setColor(BLACK); display->setColor(BLACK);
} }
@@ -1671,25 +1682,28 @@ void DebugInfo::drawFrameSettings(OLEDDisplay *display, OLEDDisplayUiState *stat
auto mode = ""; auto mode = "";
switch (config.lora.modem_preset) { switch (config.lora.modem_preset) {
case Config_LoRaConfig_ModemPreset_SHORT_SLOW: case meshtastic_Config_LoRaConfig_ModemPreset_SHORT_SLOW:
mode = "ShortS"; mode = "ShortS";
break; break;
case Config_LoRaConfig_ModemPreset_SHORT_FAST: case meshtastic_Config_LoRaConfig_ModemPreset_SHORT_FAST:
mode = "ShortF"; mode = "ShortF";
break; break;
case Config_LoRaConfig_ModemPreset_MEDIUM_SLOW: case meshtastic_Config_LoRaConfig_ModemPreset_MEDIUM_SLOW:
mode = "MedS"; mode = "MedS";
break; break;
case Config_LoRaConfig_ModemPreset_MEDIUM_FAST: case meshtastic_Config_LoRaConfig_ModemPreset_MEDIUM_FAST:
mode = "MedF"; mode = "MedF";
break; break;
case Config_LoRaConfig_ModemPreset_LONG_SLOW: case meshtastic_Config_LoRaConfig_ModemPreset_LONG_SLOW:
mode = "LongS"; mode = "LongS";
break; break;
case Config_LoRaConfig_ModemPreset_LONG_FAST: case meshtastic_Config_LoRaConfig_ModemPreset_LONG_FAST:
mode = "LongF"; mode = "LongF";
break; break;
case Config_LoRaConfig_ModemPreset_VERY_LONG_SLOW: case meshtastic_Config_LoRaConfig_ModemPreset_LONG_MODERATE:
mode = "LongM";
break;
case meshtastic_Config_LoRaConfig_ModemPreset_VERY_LONG_SLOW:
mode = "VeryL"; mode = "VeryL";
break; break;
default: default:
@@ -1751,7 +1765,8 @@ void DebugInfo::drawFrameSettings(OLEDDisplay *display, OLEDDisplayUiState *stat
display->drawString(x + SCREEN_WIDTH - display->getStringWidth(chUtil), y + FONT_HEIGHT_SMALL * 1, chUtil); display->drawString(x + SCREEN_WIDTH - display->getStringWidth(chUtil), y + FONT_HEIGHT_SMALL * 1, chUtil);
if (config.position.gps_enabled) { if (config.position.gps_enabled) {
// Line 3 // Line 3
if (config.display.gps_format != Config_DisplayConfig_GpsCoordinateFormat_DMS) // if DMS then don't draw altitude if (config.display.gps_format !=
meshtastic_Config_DisplayConfig_GpsCoordinateFormat_DMS) // if DMS then don't draw altitude
drawGPSAltitude(display, x, y + FONT_HEIGHT_SMALL * 2, gpsStatus); drawGPSAltitude(display, x, y + FONT_HEIGHT_SMALL * 2, gpsStatus);
// Line 4 // Line 4
@@ -1799,7 +1814,7 @@ int Screen::handleStatusUpdate(const meshtastic::Status *arg)
return 0; return 0;
} }
int Screen::handleTextMessage(const MeshPacket *packet) int Screen::handleTextMessage(const meshtastic_MeshPacket *packet)
{ {
if (showingNormalScreen) { if (showingNormalScreen) {
setFrames(); // Regen the list of screens (will show new text message) setFrames(); // Regen the list of screens (will show new text message)

View File

@@ -23,7 +23,7 @@ class Screen
void startRebootScreen() {} void startRebootScreen() {}
void startFirmwareUpdateScreen() {} void startFirmwareUpdateScreen() {}
}; };
} } // namespace graphics
#else #else
#include <cstring> #include <cstring>
@@ -34,7 +34,7 @@ class Screen
#ifdef USE_ST7567 #ifdef USE_ST7567
#include <ST7567Wire.h> #include <ST7567Wire.h>
#elif defined(USE_SH1106) #elif defined(USE_SH1106) || defined(USE_SH1107)
#include <SH1106Wire.h> #include <SH1106Wire.h>
#elif defined(USE_SSD1306) #elif defined(USE_SSD1306)
#include <SSD1306Wire.h> #include <SSD1306Wire.h>
@@ -49,9 +49,9 @@ class Screen
#include "commands.h" #include "commands.h"
#include "concurrency/LockGuard.h" #include "concurrency/LockGuard.h"
#include "concurrency/OSThread.h" #include "concurrency/OSThread.h"
#include "mesh/MeshModule.h"
#include "power.h" #include "power.h"
#include <string> #include <string>
#include "mesh/MeshModule.h"
// 0 to 255, though particular variants might define different defaults // 0 to 255, though particular variants might define different defaults
#ifndef BRIGHTNESS_DEFAULT #ifndef BRIGHTNESS_DEFAULT
@@ -110,8 +110,8 @@ class Screen : public concurrency::OSThread
CallbackObserver<Screen, const meshtastic::Status *>(this, &Screen::handleStatusUpdate); CallbackObserver<Screen, const meshtastic::Status *>(this, &Screen::handleStatusUpdate);
CallbackObserver<Screen, const meshtastic::Status *> nodeStatusObserver = CallbackObserver<Screen, const meshtastic::Status *> nodeStatusObserver =
CallbackObserver<Screen, const meshtastic::Status *>(this, &Screen::handleStatusUpdate); CallbackObserver<Screen, const meshtastic::Status *>(this, &Screen::handleStatusUpdate);
CallbackObserver<Screen, const MeshPacket *> textMessageObserver = CallbackObserver<Screen, const meshtastic_MeshPacket *> textMessageObserver =
CallbackObserver<Screen, const MeshPacket *>(this, &Screen::handleTextMessage); CallbackObserver<Screen, const meshtastic_MeshPacket *>(this, &Screen::handleTextMessage);
CallbackObserver<Screen, const UIFrameEvent *> uiFrameEventObserver = CallbackObserver<Screen, const UIFrameEvent *> uiFrameEventObserver =
CallbackObserver<Screen, const UIFrameEvent *>(this, &Screen::handleUIFrameEvent); CallbackObserver<Screen, const UIFrameEvent *>(this, &Screen::handleUIFrameEvent);
@@ -132,7 +132,8 @@ class Screen : public concurrency::OSThread
void setOn(bool on) void setOn(bool on)
{ {
if (!on) if (!on)
handleSetOn(false); // We handle off commands immediately, because they might be called because the CPU is shutting down handleSetOn(
false); // We handle off commands immediately, because they might be called because the CPU is shutting down
else else
enqueueCmd(ScreenCmd{.cmd = on ? Cmd::SET_ON : Cmd::SET_OFF}); enqueueCmd(ScreenCmd{.cmd = on ? Cmd::SET_ON : Cmd::SET_OFF});
} }
@@ -232,18 +233,22 @@ class Screen : public concurrency::OSThread
return (uint8_t)(ch | 0xC0); return (uint8_t)(ch | 0xC0);
} }
// map UTF-8 cyrillic chars to it Windows-1251 (CP-1251) ASCII codes // map UTF-8 cyrillic chars to it Windows-1251 (CP-1251) ASCII codes
// note: in this case we must use compatible font - provided ArialMT_Plain_10/16/24 by 'ThingPulse/esp8266-oled-ssd1306' library // note: in this case we must use compatible font - provided ArialMT_Plain_10/16/24 by 'ThingPulse/esp8266-oled-ssd1306'
// have empty chars for non-latin ASCII symbols // library have empty chars for non-latin ASCII symbols
case 0xD0: { case 0xD0: {
SKIPREST = false; SKIPREST = false;
if (ch == 129) return (uint8_t)(168); // Ё if (ch == 129)
if (ch > 143 && ch < 192) return (uint8_t)(ch + 48); return (uint8_t)(168); // Ё
if (ch > 143 && ch < 192)
return (uint8_t)(ch + 48);
break; break;
} }
case 0xD1: { case 0xD1: {
SKIPREST = false; SKIPREST = false;
if (ch == 145) return (uint8_t)(184); // ё if (ch == 145)
if (ch > 127 && ch < 144) return (uint8_t)(ch + 112); return (uint8_t)(184); // ё
if (ch > 127 && ch < 144)
return (uint8_t)(ch + 112);
break; break;
} }
} }
@@ -268,7 +273,7 @@ class Screen : public concurrency::OSThread
DebugInfo *debug_info() { return &debugInfo; } DebugInfo *debug_info() { return &debugInfo; }
int handleStatusUpdate(const meshtastic::Status *arg); int handleStatusUpdate(const meshtastic::Status *arg);
int handleTextMessage(const MeshPacket *arg); int handleTextMessage(const meshtastic_MeshPacket *arg);
int handleUIFrameEvent(const UIFrameEvent *arg); int handleUIFrameEvent(const UIFrameEvent *arg);
/// Used to force (super slow) eink displays to draw critical frames /// Used to force (super slow) eink displays to draw critical frames
@@ -342,10 +347,7 @@ class Screen : public concurrency::OSThread
/// Display device /// Display device
// #ifdef RAK4630 #if defined(USE_SH1106) || defined(USE_SH1107)
// EInkDisplay dispdev;
// AutoOLEDWire dispdev_oled;
#ifdef USE_SH1106
SH1106Wire dispdev; SH1106Wire dispdev;
#elif defined(USE_SSD1306) #elif defined(USE_SSD1306)
SSD1306Wire dispdev; SSD1306Wire dispdev;

View File

@@ -8,7 +8,7 @@
static TFT_eSPI tft = TFT_eSPI(); // Invoke library, pins defined in User_Setup.h static TFT_eSPI tft = TFT_eSPI(); // Invoke library, pins defined in User_Setup.h
TFTDisplay::TFTDisplay(uint8_t address, int sda, int scl) TFTDisplay::TFTDisplay(uint8_t address, int sda, int scl, uint8_t screen_model)
{ {
#ifdef SCREEN_ROTATE #ifdef SCREEN_ROTATE
setGeometry(GEOMETRY_RAWMODE, TFT_HEIGHT, TFT_WIDTH); setGeometry(GEOMETRY_RAWMODE, TFT_HEIGHT, TFT_WIDTH);

View File

@@ -18,7 +18,7 @@ class TFTDisplay : public OLEDDisplay
/* constructor /* constructor
FIXME - the parameters are not used, just a temporary hack to keep working like the old displays FIXME - the parameters are not used, just a temporary hack to keep working like the old displays
*/ */
TFTDisplay(uint8_t address, int sda, int scl); TFTDisplay(uint8_t address, int sda, int scl, uint8_t screen_model);
// Write the buffer to the display memory // Write the buffer to the display memory
virtual void display(void) override; virtual void display(void) override;

View File

@@ -8,7 +8,8 @@ const uint8_t SATELLITE_IMAGE[] PROGMEM = {0x00, 0x08, 0x00, 0x1C, 0x00, 0x0E, 0
const uint8_t imgSatellite[] PROGMEM = {0x70, 0x71, 0x22, 0xFA, 0xFA, 0x22, 0x71, 0x70}; const uint8_t imgSatellite[] PROGMEM = {0x70, 0x71, 0x22, 0xFA, 0xFA, 0x22, 0x71, 0x70};
const uint8_t imgUSB[] PROGMEM = {0x60, 0x60, 0x30, 0x18, 0x18, 0x18, 0x24, 0x42, 0x42, 0x42, 0x42, 0x7E, 0x24, 0x24, 0x24, 0x3C}; const uint8_t imgUSB[] PROGMEM = {0x60, 0x60, 0x30, 0x18, 0x18, 0x18, 0x24, 0x42, 0x42, 0x42, 0x42, 0x7E, 0x24, 0x24, 0x24, 0x3C};
const uint8_t imgPower[] PROGMEM = { 0x40, 0x40, 0x40, 0x58, 0x48, 0x08, 0x08, 0x08, 0x1C, 0x22, 0x22, 0x41, 0x7F, 0x22, 0x22, 0x22 }; const uint8_t imgPower[] PROGMEM = {0x40, 0x40, 0x40, 0x58, 0x48, 0x08, 0x08, 0x08,
0x1C, 0x22, 0x22, 0x41, 0x7F, 0x22, 0x22, 0x22};
const uint8_t imgUser[] PROGMEM = {0x3C, 0x42, 0x99, 0xA5, 0xA5, 0x99, 0x42, 0x3C}; const uint8_t imgUser[] PROGMEM = {0x3C, 0x42, 0x99, 0xA5, 0xA5, 0x99, 0x42, 0x3C};
const uint8_t imgPositionEmpty[] PROGMEM = {0x20, 0x30, 0x28, 0x24, 0x42, 0xFF}; const uint8_t imgPositionEmpty[] PROGMEM = {0x20, 0x30, 0x28, 0x24, 0x42, 0xFF};
const uint8_t imgPositionSolid[] PROGMEM = {0x20, 0x30, 0x38, 0x3C, 0x7E, 0xFF}; const uint8_t imgPositionSolid[] PROGMEM = {0x20, 0x30, 0x38, 0x3C, 0x7E, 0xFF};
@@ -18,8 +19,10 @@ const uint8_t imgQuestionL1[] PROGMEM = { 0xff, 0x01, 0x01, 0x32, 0x7b, 0
const uint8_t imgQuestionL2[] PROGMEM = {0x0f, 0x08, 0x08, 0x08, 0x06, 0x0f, 0x0f, 0x06, 0x08, 0x08, 0x08, 0x0f}; 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}; const uint8_t imgInfoL1[] PROGMEM = {0xff, 0x01, 0x01, 0x01, 0x1e, 0x7f, 0x1e, 0x01, 0x01, 0x01, 0x01, 0xff};
const uint8_t imgInfoL2[] PROGMEM = {0x0f, 0x08, 0x08, 0x08, 0x06, 0x0f, 0x0f, 0x06, 0x08, 0x08, 0x08, 0x0f}; const uint8_t imgInfoL2[] PROGMEM = {0x0f, 0x08, 0x08, 0x08, 0x06, 0x0f, 0x0f, 0x06, 0x08, 0x08, 0x08, 0x0f};
const uint8_t imgSFL1[] PROGMEM = { 0xb6, 0x8f, 0x19, 0x11, 0x31, 0xe3, 0xc2, 0x01, 0x01, 0xf9, 0xf9, 0x89, 0x89, 0x89, 0x09, 0xeb}; const uint8_t imgSFL1[] PROGMEM = {0xb6, 0x8f, 0x19, 0x11, 0x31, 0xe3, 0xc2, 0x01,
const uint8_t imgSFL2[] PROGMEM = { 0x0e, 0x09, 0x09, 0x09, 0x09, 0x09, 0x08, 0x08, 0x00, 0x0f, 0x0f, 0x00, 0x08, 0x08, 0x08, 0x0f}; 0x01, 0xf9, 0xf9, 0x89, 0x89, 0x89, 0x09, 0xeb};
const uint8_t imgSFL2[] PROGMEM = {0x0e, 0x09, 0x09, 0x09, 0x09, 0x09, 0x08, 0x08,
0x00, 0x0f, 0x0f, 0x00, 0x08, 0x08, 0x08, 0x0f};
#else #else
const uint8_t imgInfo[] PROGMEM = {0xff, 0x81, 0x00, 0xfb, 0xfb, 0x00, 0x81, 0xff}; const uint8_t imgInfo[] PROGMEM = {0xff, 0x81, 0x00, 0xfb, 0xfb, 0x00, 0x81, 0xff};
const uint8_t imgQuestion[] PROGMEM = {0xbf, 0x41, 0xc0, 0x8b, 0xdb, 0x70, 0xa1, 0xdf}; const uint8_t imgQuestion[] PROGMEM = {0xbf, 0x41, 0xc0, 0x8b, 0xdb, 0x70, 0xa1, 0xdf};

View File

@@ -3,9 +3,7 @@
InputBroker *inputBroker; InputBroker *inputBroker;
InputBroker::InputBroker() InputBroker::InputBroker(){};
{
};
void InputBroker::registerSource(Observable<const InputEvent *> *source) void InputBroker::registerSource(Observable<const InputEvent *> *source)
{ {

View File

@@ -9,8 +9,7 @@ typedef struct _InputEvent {
char inputEvent; char inputEvent;
char kbchar; char kbchar;
} InputEvent; } InputEvent;
class InputBroker : class InputBroker : public Observable<const InputEvent *>
public Observable<const InputEvent *>
{ {
CallbackObserver<InputBroker, const InputEvent *> inputEventObserver = CallbackObserver<InputBroker, const InputEvent *> inputEventObserver =
CallbackObserver<InputBroker, const InputEvent *>(this, &InputBroker::handleInputEvent); CallbackObserver<InputBroker, const InputEvent *>(this, &InputBroker::handleInputEvent);

View File

@@ -34,7 +34,7 @@ void RotaryEncoderInterruptBase::init(
int32_t RotaryEncoderInterruptBase::runOnce() int32_t RotaryEncoderInterruptBase::runOnce()
{ {
InputEvent e; InputEvent e;
e.inputEvent = ModuleConfig_CannedMessageConfig_InputEventChar_NONE; e.inputEvent = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_NONE;
e.source = this->_originName; e.source = this->_originName;
if (this->action == ROTARY_ACTION_PRESSED) { if (this->action == ROTARY_ACTION_PRESSED) {
@@ -48,7 +48,7 @@ int32_t RotaryEncoderInterruptBase::runOnce()
e.inputEvent = this->_eventCcw; e.inputEvent = this->_eventCcw;
} }
if (e.inputEvent != ModuleConfig_CannedMessageConfig_InputEventChar_NONE) { if (e.inputEvent != meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_NONE) {
this->notifyObservers(&e); this->notifyObservers(&e);
} }

View File

@@ -33,8 +33,8 @@ class RotaryEncoderInterruptBase : public Observable<const InputEvent *>, public
private: private:
uint8_t _pinA = 0; uint8_t _pinA = 0;
uint8_t _pinB = 0; uint8_t _pinB = 0;
char _eventCw = ModuleConfig_CannedMessageConfig_InputEventChar_NONE; char _eventCw = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_NONE;
char _eventCcw = ModuleConfig_CannedMessageConfig_InputEventChar_NONE; char _eventCcw = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_NONE;
char _eventPressed = ModuleConfig_CannedMessageConfig_InputEventChar_NONE; char _eventPressed = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_NONE;
const char *_originName; const char *_originName;
}; };

View File

@@ -8,8 +8,7 @@
* to your device as you wish, but you always need to have separate event * to your device as you wish, but you always need to have separate event
* handlers, thus you need to have a RotaryEncoderInterrupt implementation. * handlers, thus you need to have a RotaryEncoderInterrupt implementation.
*/ */
class RotaryEncoderInterruptImpl1 : class RotaryEncoderInterruptImpl1 : public RotaryEncoderInterruptBase
public RotaryEncoderInterruptBase
{ {
public: public:
RotaryEncoderInterruptImpl1(); RotaryEncoderInterruptImpl1();

View File

@@ -1,15 +1,12 @@
#include "configuration.h"
#include "UpDownInterruptBase.h" #include "UpDownInterruptBase.h"
#include "configuration.h"
UpDownInterruptBase::UpDownInterruptBase( UpDownInterruptBase::UpDownInterruptBase(const char *name)
const char *name)
{ {
this->_originName = name; this->_originName = name;
} }
void UpDownInterruptBase::init( void UpDownInterruptBase::init(uint8_t pinDown, uint8_t pinUp, uint8_t pinPress, char eventDown, char eventUp, char eventPressed,
uint8_t pinDown, uint8_t pinUp, uint8_t pinPress,
char eventDown, char eventUp, char eventPressed,
void (*onIntDown)(), void (*onIntUp)(), void (*onIntPress)()) void (*onIntDown)(), void (*onIntUp)(), void (*onIntPress)())
{ {
this->_pinDown = pinDown; this->_pinDown = pinDown;
@@ -26,8 +23,7 @@ void UpDownInterruptBase::init(
attachInterrupt(this->_pinDown, onIntDown, RISING); attachInterrupt(this->_pinDown, onIntDown, RISING);
attachInterrupt(this->_pinUp, onIntUp, RISING); attachInterrupt(this->_pinUp, onIntUp, RISING);
LOG_DEBUG("GPIO initialized (%d, %d, %d)\n", LOG_DEBUG("GPIO initialized (%d, %d, %d)\n", this->_pinDown, this->_pinUp, pinPress);
this->_pinDown, this->_pinUp, pinPress);
} }
void UpDownInterruptBase::intPressHandler() void UpDownInterruptBase::intPressHandler()

View File

@@ -16,8 +16,8 @@ class UpDownInterruptBase : public Observable<const InputEvent *>
private: private:
uint8_t _pinDown = 0; uint8_t _pinDown = 0;
uint8_t _pinUp = 0; uint8_t _pinUp = 0;
char _eventDown = ModuleConfig_CannedMessageConfig_InputEventChar_NONE; char _eventDown = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_NONE;
char _eventUp = ModuleConfig_CannedMessageConfig_InputEventChar_NONE; char _eventUp = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_NONE;
char _eventPressed = ModuleConfig_CannedMessageConfig_InputEventChar_NONE; char _eventPressed = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_NONE;
const char *_originName; const char *_originName;
}; };

View File

@@ -17,9 +17,9 @@ void UpDownInterruptImpl1::init()
uint8_t pinDown = moduleConfig.canned_message.inputbroker_pin_b; uint8_t pinDown = moduleConfig.canned_message.inputbroker_pin_b;
uint8_t pinPress = moduleConfig.canned_message.inputbroker_pin_press; uint8_t pinPress = moduleConfig.canned_message.inputbroker_pin_press;
char eventDown = static_cast<char>(ModuleConfig_CannedMessageConfig_InputEventChar_DOWN); char eventDown = static_cast<char>(meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_DOWN);
char eventUp = static_cast<char>(ModuleConfig_CannedMessageConfig_InputEventChar_UP); char eventUp = static_cast<char>(meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_UP);
char eventPressed = static_cast<char>(ModuleConfig_CannedMessageConfig_InputEventChar_SELECT); char eventPressed = static_cast<char>(meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_SELECT);
UpDownInterruptBase::init(pinDown, pinUp, pinPress, eventDown, eventUp, eventPressed, UpDownInterruptImpl1::handleIntDown, UpDownInterruptBase::init(pinDown, pinUp, pinPress, eventDown, eventUp, eventPressed, UpDownInterruptImpl1::handleIntDown,
UpDownInterruptImpl1::handleIntUp, UpDownInterruptImpl1::handleIntPressed); UpDownInterruptImpl1::handleIntUp, UpDownInterruptImpl1::handleIntPressed);

View File

@@ -1,8 +1,7 @@
#pragma once #pragma once
#include "UpDownInterruptBase.h" #include "UpDownInterruptBase.h"
class UpDownInterruptImpl1 : class UpDownInterruptImpl1 : public UpDownInterruptBase
public UpDownInterruptBase
{ {
public: public:
UpDownInterruptImpl1(); UpDownInterruptImpl1();

View File

@@ -3,15 +3,11 @@
CardKbI2cImpl *cardKbI2cImpl; CardKbI2cImpl *cardKbI2cImpl;
CardKbI2cImpl::CardKbI2cImpl() : CardKbI2cImpl::CardKbI2cImpl() : KbI2cBase("cardKB") {}
KbI2cBase("cardKB")
{
}
void CardKbI2cImpl::init() void CardKbI2cImpl::init()
{ {
if (cardkb_found != CARDKB_ADDR) if (cardkb_found != CARDKB_ADDR) {
{
disable(); disable();
return; return;
} }

View File

@@ -9,8 +9,7 @@
* to your device as you wish, but you always need to have separate event * to your device as you wish, but you always need to have separate event
* handlers, thus you need to have a RotaryEncoderInterrupt implementation. * handlers, thus you need to have a RotaryEncoderInterrupt implementation.
*/ */
class CardKbI2cImpl : class CardKbI2cImpl : public KbI2cBase
public KbI2cBase
{ {
public: public:
CardKbI2cImpl(); CardKbI2cImpl();

View File

@@ -70,35 +70,35 @@ int32_t KbI2cBase::runOnce()
while (Wire.available()) { while (Wire.available()) {
char c = Wire.read(); char c = Wire.read();
InputEvent e; InputEvent e;
e.inputEvent = ModuleConfig_CannedMessageConfig_InputEventChar_NONE; e.inputEvent = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_NONE;
e.source = this->_originName; e.source = this->_originName;
switch (c) { switch (c) {
case 0x1b: // ESC case 0x1b: // ESC
e.inputEvent = ModuleConfig_CannedMessageConfig_InputEventChar_CANCEL; e.inputEvent = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_CANCEL;
break; break;
case 0x08: // Back case 0x08: // Back
e.inputEvent = ModuleConfig_CannedMessageConfig_InputEventChar_BACK; e.inputEvent = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_BACK;
e.kbchar = c; e.kbchar = c;
break; break;
case 0xb5: // Up case 0xb5: // Up
e.inputEvent = ModuleConfig_CannedMessageConfig_InputEventChar_UP; e.inputEvent = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_UP;
break; break;
case 0xb6: // Down case 0xb6: // Down
e.inputEvent = ModuleConfig_CannedMessageConfig_InputEventChar_DOWN; e.inputEvent = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_DOWN;
break; break;
case 0xb4: // Left case 0xb4: // Left
e.inputEvent = ModuleConfig_CannedMessageConfig_InputEventChar_LEFT; e.inputEvent = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_LEFT;
e.kbchar = c; e.kbchar = c;
break; break;
case 0xb7: // Right case 0xb7: // Right
e.inputEvent = ModuleConfig_CannedMessageConfig_InputEventChar_RIGHT; e.inputEvent = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_RIGHT;
e.kbchar = c; e.kbchar = c;
break; break;
case 0x0d: // Enter case 0x0d: // Enter
e.inputEvent = ModuleConfig_CannedMessageConfig_InputEventChar_SELECT; e.inputEvent = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_SELECT;
break; break;
case 0x00: // nopress case 0x00: // nopress
e.inputEvent = ModuleConfig_CannedMessageConfig_InputEventChar_NONE; e.inputEvent = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_NONE;
break; break;
default: // all other keys default: // all other keys
e.inputEvent = ANYKEY; e.inputEvent = ANYKEY;
@@ -106,7 +106,7 @@ int32_t KbI2cBase::runOnce()
break; break;
} }
if (e.inputEvent != ModuleConfig_CannedMessageConfig_InputEventChar_NONE) { if (e.inputEvent != meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_NONE) {
this->notifyObservers(&e); this->notifyObservers(&e);
} }
} }

View File

@@ -1,11 +1,9 @@
#pragma once #pragma once
#include "SinglePortModule.h" // TODO: what header file to include?
#include "InputBroker.h" #include "InputBroker.h"
#include "SinglePortModule.h" // TODO: what header file to include?
class KbI2cBase : class KbI2cBase : public Observable<const InputEvent *>, public concurrency::OSThread
public Observable<const InputEvent *>,
public concurrency::OSThread
{ {
public: public:
explicit KbI2cBase(const char *name); explicit KbI2cBase(const char *name);

View File

@@ -3,12 +3,12 @@
#include "MeshService.h" #include "MeshService.h"
#include "NodeDB.h" #include "NodeDB.h"
#include "PowerFSM.h" #include "PowerFSM.h"
#include "ReliableRouter.h"
#include "airtime.h" #include "airtime.h"
#include "buzz.h" #include "buzz.h"
#include "configuration.h" #include "configuration.h"
#include "error.h" #include "error.h"
#include "power.h" #include "power.h"
#include "ReliableRouter.h"
// #include "debug.h" // #include "debug.h"
#include "FSCommon.h" #include "FSCommon.h"
#include "RTC.h" #include "RTC.h"
@@ -27,8 +27,8 @@
#include <Wire.h> #include <Wire.h>
// #include <driver/rtc_io.h> // #include <driver/rtc_io.h>
#include "mesh/http/WiFiAPClient.h"
#include "mesh/eth/ethClient.h" #include "mesh/eth/ethClient.h"
#include "mesh/http/WiFiAPClient.h"
#ifdef ARCH_ESP32 #ifdef ARCH_ESP32
#include "mesh/http/WebServer.h" #include "mesh/http/WebServer.h"
@@ -87,7 +87,7 @@ uint8_t rtc_found;
// Keystore Chips // Keystore Chips
uint8_t keystore_found; uint8_t keystore_found;
#ifndef ARCH_PORTDUINO #if !defined(ARCH_PORTDUINO) && !defined(ARCH_STM32WL)
ATECCX08A atecc; ATECCX08A atecc;
#endif #endif
@@ -98,7 +98,8 @@ uint32_t serialSinceMsec;
bool pmu_found; bool pmu_found;
// Array map of sensor types (as array index) and i2c address as value we'll find in the i2c scan // Array map of sensor types (as array index) and i2c address as value we'll find in the i2c scan
uint8_t nodeTelemetrySensorsMap[_TelemetrySensorType_MAX + 1] = { 0 }; // one is enough, missing elements will be initialized to 0 anyway. uint8_t nodeTelemetrySensorsMap[_meshtastic_TelemetrySensorType_MAX + 1] = {
0}; // one is enough, missing elements will be initialized to 0 anyway.
Router *router = NULL; // Users of router don't care what sort of subclass implements that API Router *router = NULL; // Users of router don't care what sort of subclass implements that API
@@ -127,6 +128,17 @@ static int32_t ledBlinker()
setLed(ledOn); setLed(ledOn);
#ifdef ARCH_ESP32
auto newHeap = ESP.getFreeHeap();
if (newHeap < 11000) {
LOG_DEBUG("\n\n====== heap too low [11000] -> reboot in 1s ======\n\n");
#ifdef HAS_SCREEN
screen->startRebootScreen();
#endif
rebootAtMsec = millis() + 900;
}
#endif
// have a very sparse duty cycle of LED being on, unless charging, then blink 0.5Hz square wave rate to indicate that // have a very sparse duty cycle of LED being on, unless charging, then blink 0.5Hz square wave rate to indicate that
return powerStatus->getIsCharging() ? 1000 : (ledOn ? 1 : 1000); return powerStatus->getIsCharging() ? 1000 : (ledOn ? 1 : 1000);
} }
@@ -249,7 +261,6 @@ void setup()
powerStatus->observe(&power->newStatus); powerStatus->observe(&power->newStatus);
power->setup(); // Must be after status handler is installed, so that handler gets notified of the initial configuration power->setup(); // Must be after status handler is installed, so that handler gets notified of the initial configuration
#ifdef LILYGO_TBEAM_S3_CORE #ifdef LILYGO_TBEAM_S3_CORE
// In T-Beam-S3-core, the I2C device cannot be scanned before power initialization, otherwise the device will be stuck // In T-Beam-S3-core, the I2C device cannot be scanned before power initialization, otherwise the device will be stuck
// PCF8563 RTC in tbeam-s3 uses Wire1 to share I2C bus // PCF8563 RTC in tbeam-s3 uses Wire1 to share I2C bus
@@ -299,12 +310,20 @@ void setup()
// but we need to do this after main cpu iniot (esp32setup), because we need the random seed set // but we need to do this after main cpu iniot (esp32setup), because we need the random seed set
nodeDB.init(); nodeDB.init();
// If we're taking on the repeater role, use flood router
if (config.device.role == meshtastic_Config_DeviceConfig_Role_REPEATER)
router = new FloodingRouter();
playStartMelody(); playStartMelody();
// fixed screen override? // fixed screen override?
if (config.display.oled != Config_DisplayConfig_OledType_OLED_AUTO) if (config.display.oled != meshtastic_Config_DisplayConfig_OledType_OLED_AUTO)
screen_model = config.display.oled; screen_model = config.display.oled;
#if defined(USE_SH1107)
screen_model = Config_DisplayConfig_OledType_OLED_SH1107; // set dimension of 128x128
#endif
// Init our SPI controller (must be before screen and lora) // Init our SPI controller (must be before screen and lora)
initSPI(); initSPI();
#ifndef ARCH_ESP32 #ifndef ARCH_ESP32
@@ -337,7 +356,7 @@ void setup()
// Do this after service.init (because that clears error_code) // Do this after service.init (because that clears error_code)
#ifdef HAS_PMU #ifdef HAS_PMU
if (!pmu_found) if (!pmu_found)
RECORD_CRITICALERROR(CriticalErrorCode_NO_AXP192); // Record a hardware fault for missing hardware RECORD_CRITICALERROR(meshtastic_CriticalErrorCode_NO_AXP192); // Record a hardware fault for missing hardware
#endif #endif
// Don't call screen setup until after nodedb is setup (because we need // Don't call screen setup until after nodedb is setup (because we need
@@ -450,9 +469,9 @@ void setup()
// check if the radio chip matches the selected region // check if the radio chip matches the selected region
if((config.lora.region == Config_LoRaConfig_RegionCode_LORA_24) && (!rIf->wideLora())){ if ((config.lora.region == meshtastic_Config_LoRaConfig_RegionCode_LORA_24) && (!rIf->wideLora())) {
LOG_WARN("Radio chip does not support 2.4GHz LoRa. Reverting to unset.\n"); LOG_WARN("Radio chip does not support 2.4GHz LoRa. Reverting to unset.\n");
config.lora.region = Config_LoRaConfig_RegionCode_UNSET; config.lora.region = meshtastic_Config_LoRaConfig_RegionCode_UNSET;
nodeDB.saveToDisk(SEGMENT_CONFIG); nodeDB.saveToDisk(SEGMENT_CONFIG);
if (!rIf->reconfigure()) { if (!rIf->reconfigure()) {
LOG_WARN("Reconfigure failed, rebooting\n"); LOG_WARN("Reconfigure failed, rebooting\n");
@@ -486,13 +505,15 @@ if((config.lora.region == Config_LoRaConfig_RegionCode_LORA_24) && (!rIf->wideLo
airTime = new AirTime(); airTime = new AirTime();
if (!rIf) if (!rIf)
RECORD_CRITICALERROR(CriticalErrorCode_NO_RADIO); RECORD_CRITICALERROR(meshtastic_CriticalErrorCode_NO_RADIO);
else { else {
router->addInterface(rIf); router->addInterface(rIf);
// Calculate and save the bit rate to myNodeInfo // Calculate and save the bit rate to myNodeInfo
// TODO: This needs to be added what ever method changes the channel from the phone. // TODO: This needs to be added what ever method changes the channel from the phone.
myNodeInfo.bitrate = (float(Constants_DATA_PAYLOAD_LEN) / (float(rIf->getPacketTime(Constants_DATA_PAYLOAD_LEN)))) * 1000; myNodeInfo.bitrate =
(float(meshtastic_Constants_DATA_PAYLOAD_LEN) / (float(rIf->getPacketTime(meshtastic_Constants_DATA_PAYLOAD_LEN)))) *
1000;
LOG_DEBUG("myNodeInfo.bitrate = %f bytes / sec\n", myNodeInfo.bitrate); LOG_DEBUG("myNodeInfo.bitrate = %f bytes / sec\n", myNodeInfo.bitrate);
} }

View File

@@ -26,7 +26,7 @@ extern bool isUSBPowered;
extern ATECCX08A atecc; extern ATECCX08A atecc;
#endif #endif
extern uint8_t nodeTelemetrySensorsMap[_TelemetrySensorType_MAX + 1]; extern uint8_t nodeTelemetrySensorsMap[_meshtastic_TelemetrySensorType_MAX + 1];
extern int TCPPort; // set by Portduino extern int TCPPort; // set by Portduino

View File

@@ -45,23 +45,23 @@ int16_t Channels::generateHash(ChannelIndex channelNum)
/** /**
* Validate a channel, fixing any errors as needed * Validate a channel, fixing any errors as needed
*/ */
Channel &Channels::fixupChannel(ChannelIndex chIndex) meshtastic_Channel &Channels::fixupChannel(ChannelIndex chIndex)
{ {
Channel &ch = getByIndex(chIndex); meshtastic_Channel &ch = getByIndex(chIndex);
ch.index = chIndex; // Preinit the index so it be ready to share with the phone (we'll never change it later) ch.index = chIndex; // Preinit the index so it be ready to share with the phone (we'll never change it later)
if (!ch.has_settings) { if (!ch.has_settings) {
// No settings! Must disable and skip // No settings! Must disable and skip
ch.role = Channel_Role_DISABLED; ch.role = meshtastic_Channel_Role_DISABLED;
memset(&ch.settings, 0, sizeof(ch.settings)); memset(&ch.settings, 0, sizeof(ch.settings));
ch.has_settings = true; ch.has_settings = true;
} else { } else {
ChannelSettings &channelSettings = ch.settings; meshtastic_ChannelSettings &meshtastic_channelSettings = ch.settings;
// Convert the old string "Default" to our new short representation // Convert the old string "Default" to our new short representation
if (strcmp(channelSettings.name, "Default") == 0) if (strcmp(meshtastic_channelSettings.name, "Default") == 0)
*channelSettings.name = '\0'; *meshtastic_channelSettings.name = '\0';
} }
hashes[chIndex] = generateHash(chIndex); hashes[chIndex] = generateHash(chIndex);
@@ -74,11 +74,11 @@ Channel &Channels::fixupChannel(ChannelIndex chIndex)
*/ */
void Channels::initDefaultChannel(ChannelIndex chIndex) void Channels::initDefaultChannel(ChannelIndex chIndex)
{ {
Channel &ch = getByIndex(chIndex); meshtastic_Channel &ch = getByIndex(chIndex);
ChannelSettings &channelSettings = ch.settings; meshtastic_ChannelSettings &channelSettings = ch.settings;
Config_LoRaConfig &loraConfig = config.lora; meshtastic_Config_LoRaConfig &loraConfig = config.lora;
loraConfig.modem_preset = Config_LoRaConfig_ModemPreset_LONG_FAST; // Default to Long Range & Fast loraConfig.modem_preset = meshtastic_Config_LoRaConfig_ModemPreset_LONG_FAST; // Default to Long Range & Fast
loraConfig.use_preset = true; loraConfig.use_preset = true;
loraConfig.tx_power = 0; // default loraConfig.tx_power = 0; // default
uint8_t defaultpskIndex = 1; uint8_t defaultpskIndex = 1;
@@ -87,25 +87,25 @@ void Channels::initDefaultChannel(ChannelIndex chIndex)
strncpy(channelSettings.name, "", sizeof(channelSettings.name)); strncpy(channelSettings.name, "", sizeof(channelSettings.name));
ch.has_settings = true; ch.has_settings = true;
ch.role = Channel_Role_PRIMARY; ch.role = meshtastic_Channel_Role_PRIMARY;
} }
CryptoKey Channels::getKey(ChannelIndex chIndex) CryptoKey Channels::getKey(ChannelIndex chIndex)
{ {
Channel &ch = getByIndex(chIndex); meshtastic_Channel &ch = getByIndex(chIndex);
const ChannelSettings &channelSettings = ch.settings; const meshtastic_ChannelSettings &channelSettings = ch.settings;
assert(ch.has_settings); assert(ch.has_settings);
CryptoKey k; CryptoKey k;
memset(k.bytes, 0, sizeof(k.bytes)); // In case the user provided a short key, we want to pad the rest with zeros memset(k.bytes, 0, sizeof(k.bytes)); // In case the user provided a short key, we want to pad the rest with zeros
if (ch.role == Channel_Role_DISABLED) { if (ch.role == meshtastic_Channel_Role_DISABLED) {
k.length = -1; // invalid k.length = -1; // invalid
} else { } else {
memcpy(k.bytes, channelSettings.psk.bytes, channelSettings.psk.size); memcpy(k.bytes, channelSettings.psk.bytes, channelSettings.psk.size);
k.length = channelSettings.psk.size; k.length = channelSettings.psk.size;
if (k.length == 0) { if (k.length == 0) {
if (ch.role == Channel_Role_SECONDARY) { if (ch.role == meshtastic_Channel_Role_SECONDARY) {
LOG_DEBUG("Unset PSK for secondary channel %s. using primary key\n", ch.settings.name); LOG_DEBUG("Unset PSK for secondary channel %s. using primary key\n", ch.settings.name);
k = getKey(primaryIndex); k = getKey(primaryIndex);
} else } else
@@ -182,24 +182,24 @@ void Channels::onConfigChanged()
{ {
// Make sure the phone hasn't mucked anything up // Make sure the phone hasn't mucked anything up
for (int i = 0; i < channelFile.channels_count; i++) { for (int i = 0; i < channelFile.channels_count; i++) {
Channel &ch = fixupChannel(i); meshtastic_Channel &ch = fixupChannel(i);
if (ch.role == Channel_Role_PRIMARY) if (ch.role == meshtastic_Channel_Role_PRIMARY)
primaryIndex = i; primaryIndex = i;
} }
} }
Channel &Channels::getByIndex(ChannelIndex chIndex) meshtastic_Channel &Channels::getByIndex(ChannelIndex chIndex)
{ {
// remove this assert cause malformed packets can make our firmware reboot here. // remove this assert cause malformed packets can make our firmware reboot here.
if (chIndex < channelFile.channels_count) { // This should be equal to MAX_NUM_CHANNELS if (chIndex < channelFile.channels_count) { // This should be equal to MAX_NUM_CHANNELS
Channel *ch = channelFile.channels + chIndex; meshtastic_Channel *ch = channelFile.channels + chIndex;
return *ch; return *ch;
} else { } else {
LOG_ERROR("Invalid channel index %d > %d, malformed packet received?\n", chIndex, channelFile.channels_count); LOG_ERROR("Invalid channel index %d > %d, malformed packet received?\n", chIndex, channelFile.channels_count);
static Channel *ch = (Channel *)malloc(sizeof(Channel)); static meshtastic_Channel *ch = (meshtastic_Channel *)malloc(sizeof(meshtastic_Channel));
memset(ch, 0, sizeof(Channel)); memset(ch, 0, sizeof(meshtastic_Channel));
// ch.index -1 means we don't know the channel locally and need to look it up by settings.name // ch.index -1 means we don't know the channel locally and need to look it up by settings.name
// not sure this is handled right everywhere // not sure this is handled right everywhere
ch->index = -1; ch->index = -1;
@@ -207,7 +207,7 @@ Channel &Channels::getByIndex(ChannelIndex chIndex)
} }
} }
Channel &Channels::getByName(const char* chName) meshtastic_Channel &Channels::getByName(const char *chName)
{ {
for (ChannelIndex i = 0; i < getNumChannels(); i++) { for (ChannelIndex i = 0; i < getNumChannels(); i++) {
if (strcasecmp(getGlobalId(i), chName) == 0) { if (strcasecmp(getGlobalId(i), chName) == 0) {
@@ -218,15 +218,15 @@ Channel &Channels::getByName(const char* chName)
return getByIndex(getPrimaryIndex()); return getByIndex(getPrimaryIndex());
} }
void Channels::setChannel(const Channel &c) void Channels::setChannel(const meshtastic_Channel &c)
{ {
Channel &old = getByIndex(c.index); meshtastic_Channel &old = getByIndex(c.index);
// if this is the new primary, demote any existing roles // if this is the new primary, demote any existing roles
if (c.role == Channel_Role_PRIMARY) if (c.role == meshtastic_Channel_Role_PRIMARY)
for (int i = 0; i < getNumChannels(); i++) for (int i = 0; i < getNumChannels(); i++)
if (channelFile.channels[i].role == Channel_Role_PRIMARY) if (channelFile.channels[i].role == meshtastic_Channel_Role_PRIMARY)
channelFile.channels[i].role = Channel_Role_SECONDARY; channelFile.channels[i].role = meshtastic_Channel_Role_SECONDARY;
old = c; // slam in the new settings/role old = c; // slam in the new settings/role
} }
@@ -234,7 +234,7 @@ void Channels::setChannel(const Channel &c)
const char *Channels::getName(size_t chIndex) const char *Channels::getName(size_t chIndex)
{ {
// Convert the short "" representation for Default into a usable string // Convert the short "" representation for Default into a usable string
const ChannelSettings &channelSettings = getByIndex(chIndex).settings; const meshtastic_ChannelSettings &channelSettings = getByIndex(chIndex).settings;
const char *channelName = channelSettings.name; const char *channelName = channelSettings.name;
if (!*channelName) { // emptystring if (!*channelName) { // emptystring
// Per mesh.proto spec, if bandwidth is specified we must ignore modemPreset enum, we assume that in that case // Per mesh.proto spec, if bandwidth is specified we must ignore modemPreset enum, we assume that in that case
@@ -242,33 +242,32 @@ const char *Channels::getName(size_t chIndex)
if (config.lora.use_preset) { if (config.lora.use_preset) {
switch (config.lora.modem_preset) { switch (config.lora.modem_preset) {
case Config_LoRaConfig_ModemPreset_SHORT_SLOW: case meshtastic_Config_LoRaConfig_ModemPreset_SHORT_SLOW:
channelName = "ShortSlow"; channelName = "ShortSlow";
break; break;
case Config_LoRaConfig_ModemPreset_SHORT_FAST: case meshtastic_Config_LoRaConfig_ModemPreset_SHORT_FAST:
channelName = "ShortFast"; channelName = "ShortFast";
break; break;
case Config_LoRaConfig_ModemPreset_MEDIUM_SLOW: case meshtastic_Config_LoRaConfig_ModemPreset_MEDIUM_SLOW:
channelName = "MediumSlow"; channelName = "MediumSlow";
break; break;
case Config_LoRaConfig_ModemPreset_MEDIUM_FAST: case meshtastic_Config_LoRaConfig_ModemPreset_MEDIUM_FAST:
channelName = "MediumFast"; channelName = "MediumFast";
break; break;
case Config_LoRaConfig_ModemPreset_LONG_SLOW: case meshtastic_Config_LoRaConfig_ModemPreset_LONG_SLOW:
channelName = "LongSlow"; channelName = "LongSlow";
break; break;
case Config_LoRaConfig_ModemPreset_LONG_FAST: case meshtastic_Config_LoRaConfig_ModemPreset_LONG_FAST:
channelName = "LongFast"; channelName = "LongFast";
break; break;
case Config_LoRaConfig_ModemPreset_VERY_LONG_SLOW: case meshtastic_Config_LoRaConfig_ModemPreset_VERY_LONG_SLOW:
channelName = "VLongSlow"; channelName = "VLongSlow";
break; break;
default: default:
channelName = "Invalid"; channelName = "Invalid";
break; break;
} }
} } else {
else {
channelName = "Custom"; channelName = "Custom";
} }
} }

View File

@@ -29,24 +29,23 @@ class Channels
int16_t hashes[MAX_NUM_CHANNELS] = {}; int16_t hashes[MAX_NUM_CHANNELS] = {};
public: public:
Channels() {} Channels() {}
/// Well known channel names /// Well known channel names
static const char *adminChannel, *gpioChannel, *serialChannel; static const char *adminChannel, *gpioChannel, *serialChannel;
const ChannelSettings &getPrimary() { return getByIndex(getPrimaryIndex()).settings; } const meshtastic_ChannelSettings &getPrimary() { return getByIndex(getPrimaryIndex()).settings; }
/** Return the Channel for a specified index */ /** Return the Channel for a specified index */
Channel &getByIndex(ChannelIndex chIndex); meshtastic_Channel &getByIndex(ChannelIndex chIndex);
/** Return the Channel for a specified name, return primary if not found. */ /** Return the Channel for a specified name, return primary if not found. */
Channel &getByName(const char* chName); meshtastic_Channel &getByName(const char *chName);
/** Using the index inside the channel, update the specified channel's settings and role. If this channel is being promoted /** Using the index inside the channel, update the specified channel's settings and role. If this channel is being promoted
* to be primary, force all other channels to be secondary. * to be primary, force all other channels to be secondary.
*/ */
void setChannel(const Channel &c); void setChannel(const meshtastic_Channel &c);
/** Return a human friendly name for this channel (and expand any short strings as needed) /** Return a human friendly name for this channel (and expand any short strings as needed)
*/ */
@@ -125,7 +124,7 @@ class Channels
/** /**
* Validate a channel, fixing any errors as needed * Validate a channel, fixing any errors as needed
*/ */
Channel &fixupChannel(ChannelIndex chIndex); meshtastic_Channel &fixupChannel(ChannelIndex chIndex);
/** /**
* Write a default channel to the specified channel index * Write a default channel to the specified channel index

View File

@@ -1,5 +1,5 @@
#include "configuration.h"
#include "CryptoEngine.h" #include "CryptoEngine.h"
#include "configuration.h"
void CryptoEngine::setKey(const CryptoKey &k) void CryptoEngine::setKey(const CryptoKey &k)
{ {

View File

@@ -9,7 +9,7 @@ FloodingRouter::FloodingRouter() {}
* later free() the packet to pool. This routine is not allowed to stall. * later free() the packet to pool. This routine is not allowed to stall.
* If the txmit queue is full it might return an error * If the txmit queue is full it might return an error
*/ */
ErrorCode FloodingRouter::send(MeshPacket *p) ErrorCode FloodingRouter::send(meshtastic_MeshPacket *p)
{ {
// Add any messages _we_ send to the seen message list (so we will ignore all retransmissions we see) // Add any messages _we_ send to the seen message list (so we will ignore all retransmissions we see)
wasSeenRecently(p); // FIXME, move this to a sniffSent method wasSeenRecently(p); // FIXME, move this to a sniffSent method
@@ -17,7 +17,7 @@ ErrorCode FloodingRouter::send(MeshPacket *p)
return Router::send(p); return Router::send(p);
} }
bool FloodingRouter::shouldFilterReceived(const MeshPacket *p) bool FloodingRouter::shouldFilterReceived(const meshtastic_MeshPacket *p)
{ {
if (wasSeenRecently(p)) { // Note: this will also add a recent packet record if (wasSeenRecently(p)) { // Note: this will also add a recent packet record
printPacket("Ignoring incoming msg, because we've already seen it", p); printPacket("Ignoring incoming msg, because we've already seen it", p);
@@ -27,9 +27,10 @@ bool FloodingRouter::shouldFilterReceived(const MeshPacket *p)
return Router::shouldFilterReceived(p); return Router::shouldFilterReceived(p);
} }
void FloodingRouter::sniffReceived(const MeshPacket *p, const Routing *c) void FloodingRouter::sniffReceived(const meshtastic_MeshPacket *p, const meshtastic_Routing *c)
{ {
bool isAck = ((c && c->error_reason == Routing_Error_NONE)); // consider only ROUTING_APP message without error as ACK bool isAck =
((c && c->error_reason == meshtastic_Routing_Error_NONE)); // consider only ROUTING_APP message without error as ACK
if (isAck && p->to != getNodeNum()) { if (isAck && p->to != getNodeNum()) {
// do not flood direct message that is ACKed // do not flood direct message that is ACKed
LOG_DEBUG("Receiving an ACK not for me, but don't need to rebroadcast this direct message anymore.\n"); LOG_DEBUG("Receiving an ACK not for me, but don't need to rebroadcast this direct message anymore.\n");
@@ -37,30 +38,32 @@ void FloodingRouter::sniffReceived(const MeshPacket *p, const Routing *c)
} }
if ((p->to != getNodeNum()) && (p->hop_limit > 0) && (getFrom(p) != getNodeNum())) { if ((p->to != getNodeNum()) && (p->hop_limit > 0) && (getFrom(p) != getNodeNum())) {
if (p->id != 0) { if (p->id != 0) {
if (config.device.role != Config_DeviceConfig_Role_CLIENT_MUTE) { if (config.device.role != meshtastic_Config_DeviceConfig_Role_CLIENT_MUTE) {
MeshPacket *tosend = packetPool.allocCopy(*p); // keep a copy because we will be sending it meshtastic_MeshPacket *tosend = packetPool.allocCopy(*p); // keep a copy because we will be sending it
tosend->hop_limit--; // bump down the hop count tosend->hop_limit--; // bump down the hop count
// If it is a traceRoute request, update the route that it went via me // If it is a traceRoute request, update the route that it went via me
if (p->which_payload_variant == MeshPacket_decoded_tag && traceRouteModule->wantPacket(p)) { if (p->which_payload_variant == meshtastic_MeshPacket_decoded_tag && traceRouteModule->wantPacket(p)) {
traceRouteModule->updateRoute(tosend); traceRouteModule->updateRoute(tosend);
} }
LOG_INFO("Rebroadcasting received floodmsg to neighbors", p); LOG_INFO("Rebroadcasting received floodmsg to neighbors\n");
// Note: we are careful to resend using the original senders node id // Note: we are careful to resend using the original senders node id
// We are careful not to call our hooked version of send() - because we don't want to check this again // We are careful not to call our hooked version of send() - because we don't want to check this again
Router::send(tosend); Router::send(tosend);
} else { } else {
LOG_DEBUG("Not rebroadcasting. Role = Role_ClientMute\n"); LOG_DEBUG("Not rebroadcasting. Role = Role_ClientMute\n");
} }
} else { } else {
LOG_DEBUG("Ignoring a simple (0 id) broadcast\n"); LOG_DEBUG("Ignoring a simple (0 id) broadcast\n");
} }
} }
if (config.device.rebroadcast_mode == meshtastic_Config_DeviceConfig_RebroadcastMode_LOCAL_ONLY) {
LOG_DEBUG("Cancelling rebroadcast of message from node on a foreign mesh, due to local only rebroadcast mode\n");
Router::cancelSending(p->to, p->decoded.request_id);
}
// handle the packet as normal // handle the packet as normal
Router::sniffReceived(p, c); Router::sniffReceived(p, c);
} }

View File

@@ -42,7 +42,7 @@ class FloodingRouter : public Router, protected PacketHistory
* later free() the packet to pool. This routine is not allowed to stall. * later free() the packet to pool. This routine is not allowed to stall.
* If the txmit queue is full it might return an error * If the txmit queue is full it might return an error
*/ */
virtual ErrorCode send(MeshPacket *p) override; virtual ErrorCode send(meshtastic_MeshPacket *p) override;
protected: protected:
/** /**
@@ -51,10 +51,10 @@ class FloodingRouter : public Router, protected PacketHistory
* Called immedately on receiption, before any further processing. * Called immedately on receiption, before any further processing.
* @return true to abandon the packet * @return true to abandon the packet
*/ */
virtual bool shouldFilterReceived(const MeshPacket *p) override; virtual bool shouldFilterReceived(const meshtastic_MeshPacket *p) override;
/** /**
* Look for broadcasts we need to rebroadcast * Look for broadcasts we need to rebroadcast
*/ */
virtual void sniffReceived(const MeshPacket *p, const Routing *c) override; virtual void sniffReceived(const meshtastic_MeshPacket *p, const meshtastic_Routing *c) override;
}; };

View File

@@ -1,9 +1,9 @@
#include "SX126xInterface.h"
#include "SX126xInterface.cpp" #include "SX126xInterface.cpp"
#include "SX128xInterface.h" #include "SX126xInterface.h"
#include "SX128xInterface.cpp" #include "SX128xInterface.cpp"
#include "api/ServerAPI.h" #include "SX128xInterface.h"
#include "api/ServerAPI.cpp" #include "api/ServerAPI.cpp"
#include "api/ServerAPI.h"
// We need this declaration for proper linking in derived classes // We need this declaration for proper linking in derived classes
template class SX126xInterface<SX1262>; template class SX126xInterface<SX1262>;

View File

@@ -1,5 +1,5 @@
#include "configuration.h"
#include "LLCC68Interface.h" #include "LLCC68Interface.h"
#include "configuration.h"
#include "error.h" #include "error.h"
LLCC68Interface::LLCC68Interface(RADIOLIB_PIN_TYPE cs, RADIOLIB_PIN_TYPE irq, RADIOLIB_PIN_TYPE rst, RADIOLIB_PIN_TYPE busy, LLCC68Interface::LLCC68Interface(RADIOLIB_PIN_TYPE cs, RADIOLIB_PIN_TYPE irq, RADIOLIB_PIN_TYPE rst, RADIOLIB_PIN_TYPE busy,

View File

@@ -1,20 +1,20 @@
#include "configuration.h"
#include "MeshModule.h" #include "MeshModule.h"
#include "Channels.h" #include "Channels.h"
#include "MeshService.h" #include "MeshService.h"
#include "NodeDB.h" #include "NodeDB.h"
#include "configuration.h"
#include "modules/RoutingModule.h" #include "modules/RoutingModule.h"
#include <assert.h> #include <assert.h>
std::vector<MeshModule *> *MeshModule::modules; std::vector<MeshModule *> *MeshModule::modules;
const MeshPacket *MeshModule::currentRequest; const meshtastic_MeshPacket *MeshModule::currentRequest;
/** /**
* If any of the current chain of modules has already sent a reply, it will be here. This is useful to allow * If any of the current chain of modules has already sent a reply, it will be here. This is useful to allow
* the RoutingPlugin to avoid sending redundant acks * the RoutingPlugin to avoid sending redundant acks
*/ */
MeshPacket *MeshModule::currentReply; meshtastic_MeshPacket *MeshModule::currentReply;
MeshModule::MeshModule(const char *_name) : name(_name) MeshModule::MeshModule(const char *_name) : name(_name)
{ {
@@ -32,21 +32,22 @@ MeshModule::~MeshModule()
assert(0); // FIXME - remove from list of modules once someone needs this feature assert(0); // FIXME - remove from list of modules once someone needs this feature
} }
MeshPacket *MeshModule::allocAckNak(Routing_Error err, NodeNum to, PacketId idFrom, ChannelIndex chIndex) meshtastic_MeshPacket *MeshModule::allocAckNak(meshtastic_Routing_Error err, NodeNum to, PacketId idFrom, ChannelIndex chIndex)
{ {
Routing c = Routing_init_default; meshtastic_Routing c = meshtastic_Routing_init_default;
c.error_reason = err; c.error_reason = err;
c.which_variant = Routing_error_reason_tag; 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 heirarchy we can no longer assume we are a RoutingPlugin
// So we manually call pb_encode_to_bytes and specify routing port number // So we manually call pb_encode_to_bytes and specify routing port number
// auto p = allocDataProtobuf(c); // auto p = allocDataProtobuf(c);
MeshPacket *p = router->allocForSending(); meshtastic_MeshPacket *p = router->allocForSending();
p->decoded.portnum = PortNum_ROUTING_APP; p->decoded.portnum = meshtastic_PortNum_ROUTING_APP;
p->decoded.payload.size = pb_encode_to_bytes(p->decoded.payload.bytes, sizeof(p->decoded.payload.bytes), &Routing_msg, &c); p->decoded.payload.size =
pb_encode_to_bytes(p->decoded.payload.bytes, sizeof(p->decoded.payload.bytes), &meshtastic_Routing_msg, &c);
p->priority = MeshPacket_Priority_ACK; p->priority = meshtastic_MeshPacket_Priority_ACK;
p->hop_limit = config.lora.hop_limit; // Flood ACK back to original sender p->hop_limit = config.lora.hop_limit; // Flood ACK back to original sender
p->to = to; p->to = to;
@@ -57,7 +58,7 @@ MeshPacket *MeshModule::allocAckNak(Routing_Error err, NodeNum to, PacketId idFr
return p; return p;
} }
MeshPacket *MeshModule::allocErrorResponse(Routing_Error err, const MeshPacket *p) meshtastic_MeshPacket *MeshModule::allocErrorResponse(meshtastic_Routing_Error err, const meshtastic_MeshPacket *p)
{ {
auto r = allocAckNak(err, getFrom(p), p->id, p->channel); auto r = allocAckNak(err, getFrom(p), p->id, p->channel);
@@ -66,13 +67,13 @@ MeshPacket *MeshModule::allocErrorResponse(Routing_Error err, const MeshPacket *
return r; return r;
} }
void MeshModule::callPlugins(const MeshPacket &mp, RxSource src) void MeshModule::callPlugins(const meshtastic_MeshPacket &mp, RxSource src)
{ {
// LOG_DEBUG("In call modules\n"); // LOG_DEBUG("In call modules\n");
bool moduleFound = false; bool moduleFound = false;
// We now allow **encrypted** packets to pass through the modules // We now allow **encrypted** packets to pass through the modules
bool isDecoded = mp.which_payload_variant == MeshPacket_decoded_tag; bool isDecoded = mp.which_payload_variant == meshtastic_MeshPacket_decoded_tag;
currentReply = NULL; // No reply yet currentReply = NULL; // No reply yet
@@ -101,13 +102,13 @@ void MeshModule::callPlugins(const MeshPacket &mp, RxSource src)
moduleFound = true; moduleFound = true;
/// received channel (or NULL if not decoded) /// received channel (or NULL if not decoded)
Channel *ch = isDecoded ? &channels.getByIndex(mp.channel) : NULL; meshtastic_Channel *ch = isDecoded ? &channels.getByIndex(mp.channel) : NULL;
/// Is the channel this packet arrived on acceptable? (security check) /// Is the channel this packet arrived on acceptable? (security check)
/// Note: we can't know channel names for encrypted packets, so those are NEVER sent to boundChannel modules /// Note: we can't know channel names for encrypted packets, so those are NEVER sent to boundChannel modules
/// Also: if a packet comes in on the local PC interface, we don't check for bound channels, because it is TRUSTED and it needs to /// Also: if a packet comes in on the local PC interface, we don't check for bound channels, because it is TRUSTED and
/// to be able to fetch the initial admin packets without yet knowing any channels. /// it needs to to be able to fetch the initial admin packets without yet knowing any channels.
bool rxChannelOk = !pi.boundChannel || (mp.from == 0) || (strcasecmp(ch->settings.name, pi.boundChannel) == 0); bool rxChannelOk = !pi.boundChannel || (mp.from == 0) || (strcasecmp(ch->settings.name, pi.boundChannel) == 0);
@@ -117,7 +118,7 @@ void MeshModule::callPlugins(const MeshPacket &mp, RxSource src)
if (mp.decoded.want_response) { if (mp.decoded.want_response) {
printPacket("packet on wrong channel, returning error", &mp); printPacket("packet on wrong channel, returning error", &mp);
currentReply = pi.allocErrorResponse(Routing_Error_NOT_AUTHORIZED, &mp); currentReply = pi.allocErrorResponse(meshtastic_Routing_Error_NOT_AUTHORIZED, &mp);
} else } else
printPacket("packet on wrong channel, but can't respond", &mp); printPacket("packet on wrong channel, but can't respond", &mp);
} else { } else {
@@ -170,17 +171,16 @@ void MeshModule::callPlugins(const MeshPacket &mp, RxSource src)
// SECURITY NOTE! I considered sending back a different error code if we didn't find the psk (i.e. !isDecoded) // SECURITY NOTE! I considered sending back a different error code if we didn't find the psk (i.e. !isDecoded)
// but opted NOT TO. Because it is not a good idea to let remote nodes 'probe' to find out which PSKs were "good" vs // but opted NOT TO. Because it is not a good idea to let remote nodes 'probe' to find out which PSKs were "good" vs
// bad. // bad.
routingModule->sendAckNak(Routing_Error_NO_RESPONSE, getFrom(&mp), mp.id, mp.channel); routingModule->sendAckNak(meshtastic_Routing_Error_NO_RESPONSE, getFrom(&mp), mp.id, mp.channel);
} }
} }
if (!moduleFound) if (!moduleFound)
LOG_DEBUG("No modules interested in portnum=%d, src=%s\n", LOG_DEBUG("No modules interested in portnum=%d, src=%s\n", mp.decoded.portnum,
mp.decoded.portnum,
(src == RX_SRC_LOCAL) ? "LOCAL" : "REMOTE"); (src == RX_SRC_LOCAL) ? "LOCAL" : "REMOTE");
} }
MeshPacket *MeshModule::allocReply() meshtastic_MeshPacket *MeshModule::allocReply()
{ {
auto r = myReply; auto r = myReply;
myReply = NULL; // Only use each reply once myReply = NULL; // Only use each reply once
@@ -191,7 +191,7 @@ MeshPacket *MeshModule::allocReply()
* so that subclasses can (optionally) send a response back to the original sender. Implementing this method * so that subclasses can (optionally) send a response back to the original sender. Implementing this method
* is optional * is optional
*/ */
void MeshModule::sendResponse(const MeshPacket &req) void MeshModule::sendResponse(const meshtastic_MeshPacket &req)
{ {
auto r = allocReply(); auto r = allocReply();
if (r) { if (r) {
@@ -206,16 +206,16 @@ void MeshModule::sendResponse(const MeshPacket &req)
/** set the destination and packet parameters of packet p intended as a reply to a particular "to" packet /** set the destination and packet parameters of packet p intended as a reply to a particular "to" packet
* This ensures that if the request packet was sent reliably, the reply is sent that way as well. * This ensures that if the request packet was sent reliably, the reply is sent that way as well.
*/ */
void setReplyTo(MeshPacket *p, const MeshPacket &to) void setReplyTo(meshtastic_MeshPacket *p, const meshtastic_MeshPacket &to)
{ {
assert(p->which_payload_variant == MeshPacket_decoded_tag); // Should already be set by now assert(p->which_payload_variant == meshtastic_MeshPacket_decoded_tag); // Should already be set by now
p->to = getFrom(&to); // Make sure that if we are sending to the local node, we use our local node addr, not 0 p->to = getFrom(&to); // Make sure that if we are sending to the local node, we use our local node addr, not 0
p->channel = to.channel; // Use the same channel that the request came in on p->channel = to.channel; // Use the same channel that the request came in on
// No need for an ack if we are just delivering locally (it just generates an ignored ack) // No need for an ack if we are just delivering locally (it just generates an ignored ack)
p->want_ack = (to.from != 0) ? to.want_ack : false; p->want_ack = (to.from != 0) ? to.want_ack : false;
if (p->priority == MeshPacket_Priority_UNSET) if (p->priority == meshtastic_MeshPacket_Priority_UNSET)
p->priority = MeshPacket_Priority_RELIABLE; p->priority = meshtastic_MeshPacket_Priority_RELIABLE;
p->decoded.request_id = to.id; p->decoded.request_id = to.id;
} }
@@ -235,14 +235,12 @@ std::vector<MeshModule *> MeshModule::GetMeshModulesWithUIFrames()
return modulesWithUIFrames; return modulesWithUIFrames;
} }
void MeshModule::observeUIEvents( void MeshModule::observeUIEvents(Observer<const UIFrameEvent *> *observer)
Observer<const UIFrameEvent *> *observer)
{ {
if (modules) { if (modules) {
for (auto i = modules->begin(); i != modules->end(); ++i) { for (auto i = modules->begin(); i != modules->end(); ++i) {
auto &pi = **i; auto &pi = **i;
Observable<const UIFrameEvent *> *observable = Observable<const UIFrameEvent *> *observable = pi.getUIFrameObservable();
pi.getUIFrameObservable();
if (observable != NULL) { if (observable != NULL) {
LOG_DEBUG("Module wants a UI Frame\n"); LOG_DEBUG("Module wants a UI Frame\n");
observer->observe(observable); observer->observe(observable);
@@ -251,24 +249,20 @@ void MeshModule::observeUIEvents(
} }
} }
AdminMessageHandleResult MeshModule::handleAdminMessageForAllPlugins(const MeshPacket &mp, AdminMessage *request, AdminMessage *response) AdminMessageHandleResult MeshModule::handleAdminMessageForAllPlugins(const meshtastic_MeshPacket &mp,
meshtastic_AdminMessage *request,
meshtastic_AdminMessage *response)
{ {
AdminMessageHandleResult handled = AdminMessageHandleResult::NOT_HANDLED; AdminMessageHandleResult handled = AdminMessageHandleResult::NOT_HANDLED;
if (modules) { if (modules) {
for (auto i = modules->begin(); i != modules->end(); ++i) { for (auto i = modules->begin(); i != modules->end(); ++i) {
auto &pi = **i; auto &pi = **i;
AdminMessageHandleResult h = pi.handleAdminMessageForModule(mp, request, response); AdminMessageHandleResult h = pi.handleAdminMessageForModule(mp, request, response);
if (h == AdminMessageHandleResult::HANDLED_WITH_RESPONSE) if (h == AdminMessageHandleResult::HANDLED_WITH_RESPONSE) {
{
// In case we have a response it always has priority. // In case we have a response it always has priority.
LOG_DEBUG("Reply prepared by module '%s' of variant: %d\n", LOG_DEBUG("Reply prepared by module '%s' of variant: %d\n", pi.name, response->which_payload_variant);
pi.name,
response->which_payload_variant);
handled = h; handled = h;
} } else if ((handled != AdminMessageHandleResult::HANDLED_WITH_RESPONSE) && (h == AdminMessageHandleResult::HANDLED)) {
else if ((handled != AdminMessageHandleResult::HANDLED_WITH_RESPONSE) &&
(h == AdminMessageHandleResult::HANDLED))
{
// In case the message is handled it should be populated, but will not overwrite // In case the message is handled it should be populated, but will not overwrite
// a result with response. // a result with response.
handled = h; handled = h;

View File

@@ -15,8 +15,7 @@
* *
* Use ProcessMessage::STOP to stop further message processing. * Use ProcessMessage::STOP to stop further message processing.
*/ */
enum class ProcessMessage enum class ProcessMessage {
{
CONTINUE = 0, CONTINUE = 0,
STOP = 1, STOP = 1,
}; };
@@ -27,8 +26,7 @@ enum class ProcessMessage
* If response is also prepared for the request, then HANDLED_WITH_RESPONSE * If response is also prepared for the request, then HANDLED_WITH_RESPONSE
* should be returned. * should be returned.
*/ */
enum class AdminMessageHandleResult enum class AdminMessageHandleResult {
{
NOT_HANDLED = 0, NOT_HANDLED = 0,
HANDLED = 1, HANDLED = 1,
HANDLED_WITH_RESPONSE = 2, HANDLED_WITH_RESPONSE = 2,
@@ -66,14 +64,18 @@ class MeshModule
/** For use only by MeshService /** For use only by MeshService
*/ */
static void callPlugins(const MeshPacket &mp, RxSource src = RX_SRC_RADIO); static void callPlugins(const meshtastic_MeshPacket &mp, RxSource src = RX_SRC_RADIO);
static std::vector<MeshModule *> GetMeshModulesWithUIFrames(); static std::vector<MeshModule *> GetMeshModulesWithUIFrames();
static void observeUIEvents(Observer<const UIFrameEvent *> *observer); static void observeUIEvents(Observer<const UIFrameEvent *> *observer);
static AdminMessageHandleResult handleAdminMessageForAllPlugins( static AdminMessageHandleResult handleAdminMessageForAllPlugins(const meshtastic_MeshPacket &mp,
const MeshPacket &mp, AdminMessage *request, AdminMessage *response); meshtastic_AdminMessage *request,
meshtastic_AdminMessage *response);
#if HAS_SCREEN #if HAS_SCREEN
virtual void drawFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y) { return; } virtual void drawFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y)
{
return;
}
#endif #endif
protected: protected:
const char *name; const char *name;
@@ -107,12 +109,12 @@ class MeshModule
* Note: this can be static because we are guaranteed to be processing only one * Note: this can be static because we are guaranteed to be processing only one
* plumodulegin at a time. * plumodulegin at a time.
*/ */
static const MeshPacket *currentRequest; static const meshtastic_MeshPacket *currentRequest;
/** /**
* If your handler wants to send a response, simply set currentReply and it will be sent at the end of response handling. * If your handler wants to send a response, simply set currentReply and it will be sent at the end of response handling.
*/ */
MeshPacket *myReply = NULL; meshtastic_MeshPacket *myReply = NULL;
/** /**
* Initialize your module. This setup function is called once after all hardware and mesh protocol layers have * Initialize your module. This setup function is called once after all hardware and mesh protocol layers have
@@ -123,13 +125,17 @@ class MeshModule
/** /**
* @return true if you want to receive the specified portnum * @return true if you want to receive the specified portnum
*/ */
virtual bool wantPacket(const MeshPacket *p) = 0; virtual bool wantPacket(const meshtastic_MeshPacket *p) = 0;
/** Called to handle a particular incoming message /** Called to handle a particular incoming message
@return ProcessMessage::STOP if you've guaranteed you've handled this message and no other handlers should be considered for it @return ProcessMessage::STOP if you've guaranteed you've handled this message and no other handlers should be considered for
it
*/ */
virtual ProcessMessage handleReceived(const MeshPacket &mp) { return ProcessMessage::CONTINUE; } virtual ProcessMessage handleReceived(const meshtastic_MeshPacket &mp)
{
return ProcessMessage::CONTINUE;
}
/** Messages can be received that have the want_response bit set. If set, this callback will be invoked /** Messages can be received that have the want_response bit set. If set, this callback will be invoked
* so that subclasses can (optionally) send a response back to the original sender. * so that subclasses can (optionally) send a response back to the original sender.
@@ -137,18 +143,24 @@ class MeshModule
* Note: most implementers don't need to override this, instead: If while handling a request you have a reply, just set * Note: most implementers don't need to override this, instead: If while handling a request you have a reply, just set
* the protected reply field in this instance. * the protected reply field in this instance.
* */ * */
virtual MeshPacket *allocReply(); virtual meshtastic_MeshPacket *allocReply();
/*** /***
* @return true if you want to be alloced a UI screen frame * @return true if you want to be alloced a UI screen frame
*/ */
virtual bool wantUIFrame() { return false; } virtual bool wantUIFrame()
virtual Observable<const UIFrameEvent *>* getUIFrameObservable() { return NULL; } {
return false;
}
virtual Observable<const UIFrameEvent *> *getUIFrameObservable()
{
return NULL;
}
MeshPacket *allocAckNak(Routing_Error err, NodeNum to, PacketId idFrom, ChannelIndex chIndex); meshtastic_MeshPacket *allocAckNak(meshtastic_Routing_Error err, NodeNum to, PacketId idFrom, ChannelIndex chIndex);
/// Send an error response for the specified packet. /// Send an error response for the specified packet.
MeshPacket *allocErrorResponse(Routing_Error err, const MeshPacket *p); meshtastic_MeshPacket *allocErrorResponse(meshtastic_Routing_Error err, const meshtastic_MeshPacket *p);
/** /**
* @brief An admin message arrived to AdminModule. Module was asked whether it want to handle the request. * @brief An admin message arrived to AdminModule. Module was asked whether it want to handle the request.
@@ -160,15 +172,19 @@ class MeshModule
* HANDLED if message was handled * HANDLED if message was handled
* HANDLED_WITH_RESPONSE if a response is also prepared and to be sent. * HANDLED_WITH_RESPONSE if a response is also prepared and to be sent.
*/ */
virtual AdminMessageHandleResult handleAdminMessageForModule( virtual AdminMessageHandleResult handleAdminMessageForModule(const meshtastic_MeshPacket &mp,
const MeshPacket &mp, AdminMessage *request, AdminMessage *response) { return AdminMessageHandleResult::NOT_HANDLED; }; meshtastic_AdminMessage *request,
meshtastic_AdminMessage *response)
{
return AdminMessageHandleResult::NOT_HANDLED;
};
private: private:
/** /**
* If any of the current chain of modules has already sent a reply, it will be here. This is useful to allow * If any of the current chain of modules has already sent a reply, it will be here. This is useful to allow
* the RoutingModule to avoid sending redundant acks * the RoutingModule to avoid sending redundant acks
*/ */
static MeshPacket *currentReply; static meshtastic_MeshPacket *currentReply;
friend class ReliableRouter; friend class ReliableRouter;
@@ -176,10 +192,10 @@ class MeshModule
* so that subclasses can (optionally) send a response back to the original sender. This method calls allocReply() * so that subclasses can (optionally) send a response back to the original sender. This method calls allocReply()
* to generate the reply message, and if !NULL that message will be delivered to whoever sent req * to generate the reply message, and if !NULL that message will be delivered to whoever sent req
*/ */
void sendResponse(const MeshPacket &req); void sendResponse(const meshtastic_MeshPacket &req);
}; };
/** set the destination and packet parameters of packet p intended as a reply to a particular "to" packet /** set the destination and packet parameters of packet p intended as a reply to a particular "to" packet
* This ensures that if the request packet was sent reliably, the reply is sent that way as well. * This ensures that if the request packet was sent reliably, the reply is sent that way as well.
*/ */
void setReplyTo(MeshPacket *p, const MeshPacket &to); void setReplyTo(meshtastic_MeshPacket *p, const meshtastic_MeshPacket &to);

View File

@@ -1,18 +1,18 @@
#include "configuration.h"
#include "MeshPacketQueue.h" #include "MeshPacketQueue.h"
#include "configuration.h"
#include <assert.h> #include <assert.h>
#include <algorithm> #include <algorithm>
/// @return the priority of the specified packet /// @return the priority of the specified packet
inline uint32_t getPriority(const MeshPacket *p) inline uint32_t getPriority(const meshtastic_MeshPacket *p)
{ {
auto pri = p->priority; auto pri = p->priority;
return pri; return pri;
} }
/// @return "true" if "p1" is ordered before "p2" /// @return "true" if "p1" is ordered before "p2"
bool CompareMeshPacketFunc(const MeshPacket *p1, const MeshPacket *p2) bool CompareMeshPacketFunc(const meshtastic_MeshPacket *p1, const meshtastic_MeshPacket *p2)
{ {
assert(p1 && p2); assert(p1 && p2);
auto p1p = getPriority(p1), p2p = getPriority(p2); auto p1p = getPriority(p1), p2p = getPriority(p2);
@@ -26,27 +26,29 @@ bool CompareMeshPacketFunc(const MeshPacket *p1, const MeshPacket *p2)
MeshPacketQueue::MeshPacketQueue(size_t _maxLen) : maxLen(_maxLen) {} MeshPacketQueue::MeshPacketQueue(size_t _maxLen) : maxLen(_maxLen) {}
bool MeshPacketQueue::empty() { bool MeshPacketQueue::empty()
{
return queue.empty(); return queue.empty();
} }
/** /**
* Some clients might not properly set priority, therefore we fix it here. * Some clients might not properly set priority, therefore we fix it here.
*/ */
void fixPriority(MeshPacket *p) void fixPriority(meshtastic_MeshPacket *p)
{ {
// We might receive acks from other nodes (and since generated remotely, they won't have priority assigned. Check for that // We might receive acks from other nodes (and since generated remotely, they won't have priority assigned. Check for that
// and fix it // and fix it
if (p->priority == MeshPacket_Priority_UNSET) { if (p->priority == meshtastic_MeshPacket_Priority_UNSET) {
// if acks give high priority // if acks give high priority
// if a reliable message give a bit higher default priority // if a reliable message give a bit higher default priority
p->priority = (p->decoded.portnum == PortNum_ROUTING_APP) ? MeshPacket_Priority_ACK : p->priority = (p->decoded.portnum == meshtastic_PortNum_ROUTING_APP)
(p->want_ack ? MeshPacket_Priority_RELIABLE : MeshPacket_Priority_DEFAULT); ? meshtastic_MeshPacket_Priority_ACK
: (p->want_ack ? meshtastic_MeshPacket_Priority_RELIABLE : meshtastic_MeshPacket_Priority_DEFAULT);
} }
} }
/** enqueue a packet, return false if full */ /** enqueue a packet, return false if full */
bool MeshPacketQueue::enqueue(MeshPacket *p) bool MeshPacketQueue::enqueue(meshtastic_MeshPacket *p)
{ {
fixPriority(p); fixPriority(p);
@@ -60,7 +62,7 @@ bool MeshPacketQueue::enqueue(MeshPacket *p)
return true; return true;
} }
MeshPacket *MeshPacketQueue::dequeue() meshtastic_MeshPacket *MeshPacketQueue::dequeue()
{ {
if (empty()) { if (empty()) {
return NULL; return NULL;
@@ -73,7 +75,7 @@ MeshPacket *MeshPacketQueue::dequeue()
return p; return p;
} }
MeshPacket *MeshPacketQueue::getFront() meshtastic_MeshPacket *MeshPacketQueue::getFront()
{ {
if (empty()) { if (empty()) {
return NULL; return NULL;
@@ -84,7 +86,7 @@ MeshPacket *MeshPacketQueue::getFront()
} }
/** Attempt to find and remove a packet from this queue. Returns a pointer to the removed packet, or NULL if not found */ /** Attempt to find and remove a packet from this queue. Returns a pointer to the removed packet, or NULL if not found */
MeshPacket *MeshPacketQueue::remove(NodeNum from, PacketId id) meshtastic_MeshPacket *MeshPacketQueue::remove(NodeNum from, PacketId id)
{ {
for (auto it = queue.begin(); it != queue.end(); it++) { for (auto it = queue.begin(); it != queue.end(); it++) {
auto p = (*it); auto p = (*it);
@@ -99,7 +101,8 @@ MeshPacket *MeshPacketQueue::remove(NodeNum from, PacketId id)
} }
/** Attempt to find and remove a packet from this queue. Returns the packet which was removed from the queue */ /** Attempt to find and remove a packet from this queue. Returns the packet which was removed from the queue */
bool MeshPacketQueue::replaceLowerPriorityPacket(MeshPacket *p) { bool MeshPacketQueue::replaceLowerPriorityPacket(meshtastic_MeshPacket *p)
{
std::sort_heap(queue.begin(), queue.end(), &CompareMeshPacketFunc); // sort ascending based on priority (0 -> 127) std::sort_heap(queue.begin(), queue.end(), &CompareMeshPacketFunc); // sort ascending based on priority (0 -> 127)
// find first packet which does not compare less (in priority) than parameter packet // find first packet which does not compare less (in priority) than parameter packet

View File

@@ -4,23 +4,23 @@
#include <queue> #include <queue>
/** /**
* A priority queue of packets * A priority queue of packets
*/ */
class MeshPacketQueue class MeshPacketQueue
{ {
size_t maxLen; size_t maxLen;
std::vector<MeshPacket *> queue; std::vector<meshtastic_MeshPacket *> queue;
/** Replace a lower priority package in the queue with 'mp' (provided there are lower pri packages). Return true if replaced. */ /** Replace a lower priority package in the queue with 'mp' (provided there are lower pri packages). Return true if replaced.
bool replaceLowerPriorityPacket(MeshPacket *mp); */
bool replaceLowerPriorityPacket(meshtastic_MeshPacket *mp);
public: public:
explicit MeshPacketQueue(size_t _maxLen); explicit MeshPacketQueue(size_t _maxLen);
/** enqueue a packet, return false if full */ /** enqueue a packet, return false if full */
bool enqueue(MeshPacket *p); bool enqueue(meshtastic_MeshPacket *p);
/** return true if the queue is empty */ /** return true if the queue is empty */
bool empty(); bool empty();
@@ -31,10 +31,10 @@ class MeshPacketQueue
/** return total size of the Queue */ /** return total size of the Queue */
size_t getMaxLen() { return maxLen; } size_t getMaxLen() { return maxLen; }
MeshPacket *dequeue(); meshtastic_MeshPacket *dequeue();
MeshPacket *getFront(); meshtastic_MeshPacket *getFront();
/** Attempt to find and remove a packet from this queue. Returns the packet which was removed from the queue */ /** Attempt to find and remove a packet from this queue. Returns the packet which was removed from the queue */
MeshPacket *remove(NodeNum from, PacketId id); meshtastic_MeshPacket *remove(NodeNum from, PacketId id);
}; };

View File

@@ -7,7 +7,7 @@
// Map from old region names to new region enums // Map from old region names to new region enums
struct RegionInfo { struct RegionInfo {
Config_LoRaConfig_RegionCode code; meshtastic_Config_LoRaConfig_RegionCode code;
float freqStart; float freqStart;
float freqEnd; float freqEnd;
float dutyCycle; float dutyCycle;

View File

@@ -2,9 +2,9 @@
#include <assert.h> #include <assert.h>
#include <string> #include <string>
#include "GPS.h"
#include "../concurrency/Periodic.h" #include "../concurrency/Periodic.h"
#include "BluetoothCommon.h" // needed for updateBatteryLevel, FIXME, eventually when we pull mesh out into a lib we shouldn't be whacking bluetooth from here #include "BluetoothCommon.h" // needed for updateBatteryLevel, FIXME, eventually when we pull mesh out into a lib we shouldn't be whacking bluetooth from here
#include "GPS.h"
#include "MeshService.h" #include "MeshService.h"
#include "NodeDB.h" #include "NodeDB.h"
#include "PowerFSM.h" #include "PowerFSM.h"
@@ -51,9 +51,9 @@ FIXME in the initial proof of concept we just skip the entire want/deny flow and
MeshService service; MeshService service;
static MemoryDynamic<QueueStatus> staticQueueStatusPool; static MemoryDynamic<meshtastic_QueueStatus> staticQueueStatusPool;
Allocator<QueueStatus> &queueStatusPool = staticQueueStatusPool; Allocator<meshtastic_QueueStatus> &queueStatusPool = staticQueueStatusPool;
#include "Router.h" #include "Router.h"
@@ -71,14 +71,14 @@ void MeshService::init()
gpsObserver.observe(&gps->newStatus); gpsObserver.observe(&gps->newStatus);
} }
int MeshService::handleFromRadio(const MeshPacket *mp) int MeshService::handleFromRadio(const meshtastic_MeshPacket *mp)
{ {
powerFSM.trigger(EVENT_PACKET_FOR_PHONE); // Possibly keep the node from sleeping powerFSM.trigger(EVENT_PACKET_FOR_PHONE); // Possibly keep the node from sleeping
printPacket("Forwarding to phone", mp); printPacket("Forwarding to phone", mp);
nodeDB.updateFrom(*mp); // update our DB state based off sniffing every RX packet from the radio nodeDB.updateFrom(*mp); // update our DB state based off sniffing every RX packet from the radio
sendToPhone((MeshPacket *)mp); sendToPhone((meshtastic_MeshPacket *)mp);
return 0; return 0;
} }
@@ -87,7 +87,7 @@ int MeshService::handleFromRadio(const MeshPacket *mp)
void MeshService::loop() void MeshService::loop()
{ {
if (lastQueueStatus.free == 0) { // check if there is now free space in TX queue if (lastQueueStatus.free == 0) { // check if there is now free space in TX queue
QueueStatus qs = router->getQueueStatus(); meshtastic_QueueStatus qs = router->getQueueStatus();
if (qs.free != lastQueueStatus.free) if (qs.free != lastQueueStatus.free)
(void)sendQueueStatusToPhone(qs, 0, 0); (void)sendQueueStatusToPhone(qs, 0, 0);
} }
@@ -130,17 +130,18 @@ void MeshService::reloadOwner(bool shouldSave)
* Called by PhoneAPI.handleToRadio. Note: p is a scratch buffer, this function is allowed to write to it but it can not keep a * Called by PhoneAPI.handleToRadio. Note: p is a scratch buffer, this function is allowed to write to it but it can not keep a
* reference * reference
*/ */
void MeshService::handleToRadio(MeshPacket &p) void MeshService::handleToRadio(meshtastic_MeshPacket &p)
{ {
#ifdef ARCH_PORTDUINO #ifdef ARCH_PORTDUINO
// Simulates device is receiving a packet via the LoRa chip // Simulates device is receiving a packet via the LoRa chip
if (p.decoded.portnum == PortNum_SIMULATOR_APP) { if (p.decoded.portnum == meshtastic_PortNum_SIMULATOR_APP) {
// Simulator packet (=Compressed packet) is encapsulated in a MeshPacket, so need to unwrap first // Simulator packet (=Compressed packet) is encapsulated in a MeshPacket, so need to unwrap first
Compressed scratch; meshtastic_Compressed scratch;
Compressed *decoded = NULL; meshtastic_Compressed *decoded = NULL;
if (p.which_payload_variant == MeshPacket_decoded_tag) { if (p.which_payload_variant == meshtastic_MeshPacket_decoded_tag) {
memset(&scratch, 0, sizeof(scratch)); memset(&scratch, 0, sizeof(scratch));
p.decoded.payload.size = pb_decode_from_bytes(p.decoded.payload.bytes, p.decoded.payload.size, &Compressed_msg, &scratch); p.decoded.payload.size =
pb_decode_from_bytes(p.decoded.payload.bytes, p.decoded.payload.size, &meshtastic_Compressed_msg, &scratch);
if (p.decoded.payload.size) { if (p.decoded.payload.size) {
decoded = &scratch; decoded = &scratch;
// Extract the original payload and replace // Extract the original payload and replace
@@ -187,16 +188,16 @@ bool MeshService::cancelSending(PacketId id)
return router->cancelSending(nodeDB.getNodeNum(), id); return router->cancelSending(nodeDB.getNodeNum(), id);
} }
ErrorCode MeshService::sendQueueStatusToPhone(const QueueStatus &qs, ErrorCode res, uint32_t mesh_packet_id) ErrorCode MeshService::sendQueueStatusToPhone(const meshtastic_QueueStatus &qs, ErrorCode res, uint32_t mesh_packet_id)
{ {
QueueStatus *copied = queueStatusPool.allocCopy(qs); meshtastic_QueueStatus *copied = queueStatusPool.allocCopy(qs);
copied->res = res; copied->res = res;
copied->mesh_packet_id = mesh_packet_id; copied->mesh_packet_id = mesh_packet_id;
if (toPhoneQueueStatusQueue.numFree() == 0) { if (toPhoneQueueStatusQueue.numFree() == 0) {
LOG_DEBUG("NOTE: tophone queue status queue is full, discarding oldest\n"); LOG_DEBUG("NOTE: tophone queue status queue is full, discarding oldest\n");
QueueStatus *d = toPhoneQueueStatusQueue.dequeuePtr(0); meshtastic_QueueStatus *d = toPhoneQueueStatusQueue.dequeuePtr(0);
if (d) if (d)
releaseQueueStatusToPool(d); releaseQueueStatusToPool(d);
} }
@@ -209,7 +210,7 @@ ErrorCode MeshService::sendQueueStatusToPhone(const QueueStatus &qs, ErrorCode r
return res ? ERRNO_OK : ERRNO_UNKNOWN; return res ? ERRNO_OK : ERRNO_UNKNOWN;
} }
void MeshService::sendToMesh(MeshPacket *p, RxSource src, bool ccToPhone) void MeshService::sendToMesh(meshtastic_MeshPacket *p, RxSource src, bool ccToPhone)
{ {
uint32_t mesh_packet_id = p->id; uint32_t mesh_packet_id = p->id;
nodeDB.updateFrom(*p); // update our local DB for this packet (because phone might have sent position packets etc...) nodeDB.updateFrom(*p); // update our local DB for this packet (because phone might have sent position packets etc...)
@@ -219,7 +220,7 @@ void MeshService::sendToMesh(MeshPacket *p, RxSource src, bool ccToPhone)
/* NOTE(pboldin): Prepare and send QueueStatus message to the phone as a /* NOTE(pboldin): Prepare and send QueueStatus message to the phone as a
* high-priority message. */ * high-priority message. */
QueueStatus qs = router->getQueueStatus(); meshtastic_QueueStatus qs = router->getQueueStatus();
ErrorCode r = sendQueueStatusToPhone(qs, res, mesh_packet_id); ErrorCode r = sendQueueStatusToPhone(qs, res, mesh_packet_id);
if (r != ERRNO_OK) { if (r != ERRNO_OK) {
LOG_DEBUG("Can't send status to phone"); LOG_DEBUG("Can't send status to phone");
@@ -232,7 +233,7 @@ void MeshService::sendToMesh(MeshPacket *p, RxSource src, bool ccToPhone)
void MeshService::sendNetworkPing(NodeNum dest, bool wantReplies) void MeshService::sendNetworkPing(NodeNum dest, bool wantReplies)
{ {
NodeInfo *node = nodeDB.getNode(nodeDB.getNodeNum()); meshtastic_NodeInfo *node = nodeDB.getNode(nodeDB.getNodeNum());
assert(node); assert(node);
if (node->has_position && (node->position.latitude_i != 0 || node->position.longitude_i != 0)) { if (node->has_position && (node->position.latitude_i != 0 || node->position.longitude_i != 0)) {
@@ -248,24 +249,24 @@ void MeshService::sendNetworkPing(NodeNum dest, bool wantReplies)
} }
} }
void MeshService::sendToPhone(MeshPacket *p) void MeshService::sendToPhone(meshtastic_MeshPacket *p)
{ {
if (toPhoneQueue.numFree() == 0) { if (toPhoneQueue.numFree() == 0) {
LOG_WARN("ToPhone queue is full, discarding oldest\n"); LOG_WARN("ToPhone queue is full, discarding oldest\n");
MeshPacket *d = toPhoneQueue.dequeuePtr(0); meshtastic_MeshPacket *d = toPhoneQueue.dequeuePtr(0);
if (d) if (d)
releaseToPool(d); releaseToPool(d);
} }
MeshPacket *copied = packetPool.allocCopy(*p); meshtastic_MeshPacket *copied = packetPool.allocCopy(*p);
perhapsDecode(copied); perhapsDecode(copied);
assert(toPhoneQueue.enqueue(copied, 0)); assert(toPhoneQueue.enqueue(copied, 0));
fromNum++; fromNum++;
} }
NodeInfo *MeshService::refreshMyNodeInfo() meshtastic_NodeInfo *MeshService::refreshMyNodeInfo()
{ {
NodeInfo *node = nodeDB.getNode(nodeDB.getNodeNum()); meshtastic_NodeInfo *node = nodeDB.getNode(nodeDB.getNodeNum());
assert(node); assert(node);
// We might not have a position yet for our local node, in that case, at least try to send the time // We might not have a position yet for our local node, in that case, at least try to send the time
@@ -274,7 +275,7 @@ NodeInfo *MeshService::refreshMyNodeInfo()
node->has_position = true; node->has_position = true;
} }
Position &position = node->position; meshtastic_Position &position = node->position;
// Update our local node info with our time (even if we don't decide to update anyone else) // Update our local node info with our time (even if we don't decide to update anyone else)
node->last_heard = node->last_heard =
@@ -290,8 +291,8 @@ NodeInfo *MeshService::refreshMyNodeInfo()
int MeshService::onGPSChanged(const meshtastic::GPSStatus *newStatus) int MeshService::onGPSChanged(const meshtastic::GPSStatus *newStatus)
{ {
// Update our local node info with our position (even if we don't decide to update anyone else) // Update our local node info with our position (even if we don't decide to update anyone else)
NodeInfo *node = refreshMyNodeInfo(); meshtastic_NodeInfo *node = refreshMyNodeInfo();
Position pos = Position_init_default; meshtastic_Position pos = meshtastic_Position_init_default;
if (newStatus->getHasLock()) { if (newStatus->getHasLock()) {
// load data from GPS object, will add timestamp + battery further down // load data from GPS object, will add timestamp + battery further down

View File

@@ -14,7 +14,7 @@
#include "../platform/portduino/SimRadio.h" #include "../platform/portduino/SimRadio.h"
#endif #endif
extern Allocator<QueueStatus> &queueStatusPool; extern Allocator<meshtastic_QueueStatus> &queueStatusPool;
/** /**
* Top level app for this service. keeps the mesh, the radio config and the queue of received packets. * Top level app for this service. keeps the mesh, the radio config and the queue of received packets.
@@ -29,13 +29,13 @@ class MeshService
/// FIXME, change to a DropOldestQueue and keep a count of the number of dropped packets to ensure /// FIXME, change to a DropOldestQueue and keep a count of the number of dropped packets to ensure
/// we never hang because android hasn't been there in a while /// we never hang because android hasn't been there in a while
/// FIXME - save this to flash on deep sleep /// FIXME - save this to flash on deep sleep
PointerQueue<MeshPacket> toPhoneQueue; PointerQueue<meshtastic_MeshPacket> toPhoneQueue;
// keep list of QueueStatus packets to be send to the phone // keep list of QueueStatus packets to be send to the phone
PointerQueue<QueueStatus> toPhoneQueueStatusQueue; PointerQueue<meshtastic_QueueStatus> toPhoneQueueStatusQueue;
// This holds the last QueueStatus send // This holds the last QueueStatus send
QueueStatus lastQueueStatus; meshtastic_QueueStatus lastQueueStatus;
/// The current nonce for the newest packet which has been queued for the phone /// The current nonce for the newest packet which has been queued for the phone
uint32_t fromNum = 0; uint32_t fromNum = 0;
@@ -59,23 +59,23 @@ class MeshService
/// Return the next packet destined to the phone. FIXME, somehow use fromNum to allow the phone to retry the /// Return the next packet destined to the phone. FIXME, somehow use fromNum to allow the phone to retry the
/// last few packets if needs to. /// last few packets if needs to.
MeshPacket *getForPhone() { return toPhoneQueue.dequeuePtr(0); } meshtastic_MeshPacket *getForPhone() { return toPhoneQueue.dequeuePtr(0); }
/// Allows the bluetooth handler to free packets after they have been sent /// Allows the bluetooth handler to free packets after they have been sent
void releaseToPool(MeshPacket *p) { packetPool.release(p); } void releaseToPool(meshtastic_MeshPacket *p) { packetPool.release(p); }
/// Return the next QueueStatus packet destined to the phone. /// Return the next QueueStatus packet destined to the phone.
QueueStatus *getQueueStatusForPhone() { return toPhoneQueueStatusQueue.dequeuePtr(0); } meshtastic_QueueStatus *getQueueStatusForPhone() { return toPhoneQueueStatusQueue.dequeuePtr(0); }
// Release QueueStatus packet to pool // Release QueueStatus packet to pool
void releaseQueueStatusToPool(QueueStatus *p) { queueStatusPool.release(p); } void releaseQueueStatusToPool(meshtastic_QueueStatus *p) { queueStatusPool.release(p); }
/** /**
* Given a ToRadio buffer parse it and properly handle it (setup radio, owner or send packet into the mesh) * 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 * Called by PhoneAPI.handleToRadio. Note: p is a scratch buffer, this function is allowed to write to it but it can not keep
* a reference * a reference
*/ */
void handleToRadio(MeshPacket &p); void handleToRadio(meshtastic_MeshPacket &p);
/** The radioConfig object just changed, call this to force the hw to change to the new settings /** The radioConfig object just changed, call this to force the hw to change to the new settings
* @return true if client devices should be sent a new set of radio configs * @return true if client devices should be sent a new set of radio configs
@@ -92,16 +92,16 @@ class MeshService
/// Send a packet into the mesh - note p must have been allocated from packetPool. We will return it to that pool after /// Send a packet into the mesh - note p must have been allocated from packetPool. We will return it to that pool after
/// sending. This is the ONLY function you should use for sending messages into the mesh, because it also updates the nodedb /// sending. This is the ONLY function you should use for sending messages into the mesh, because it also updates the nodedb
/// cache /// cache
void sendToMesh(MeshPacket *p, RxSource src = RX_SRC_LOCAL, bool ccToPhone = false); void sendToMesh(meshtastic_MeshPacket *p, RxSource src = RX_SRC_LOCAL, bool ccToPhone = false);
/** Attempt to cancel a previously sent packet from this _local_ node. Returns true if a packet was found we could cancel */ /** Attempt to cancel a previously sent packet from this _local_ node. Returns true if a packet was found we could cancel */
bool cancelSending(PacketId id); bool cancelSending(PacketId id);
/// Pull the latest power and time info into my nodeinfo /// Pull the latest power and time info into my nodeinfo
NodeInfo *refreshMyNodeInfo(); meshtastic_NodeInfo *refreshMyNodeInfo();
/// Send a packet to the phone /// Send a packet to the phone
void sendToPhone(MeshPacket *p); void sendToPhone(meshtastic_MeshPacket *p);
bool isToPhoneQueueEmpty(); bool isToPhoneQueueEmpty();
@@ -112,10 +112,10 @@ class MeshService
/// Handle a packet that just arrived from the radio. This method does _ReliableRouternot_ free the provided packet. If it /// Handle a packet that just arrived from the radio. This method does _ReliableRouternot_ free the provided packet. If it
/// needs to keep the packet around it makes a copy /// needs to keep the packet around it makes a copy
int handleFromRadio(const MeshPacket *p); int handleFromRadio(const meshtastic_MeshPacket *p);
friend class RoutingModule; friend class RoutingModule;
ErrorCode sendQueueStatusToPhone(const QueueStatus &qs, ErrorCode res, uint32_t mesh_packet_id); ErrorCode sendQueueStatusToPhone(const meshtastic_QueueStatus &qs, ErrorCode res, uint32_t mesh_packet_id);
}; };
extern MeshService service; extern MeshService service;

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