mirror of
https://github.com/meshtastic/firmware.git
synced 2026-02-06 17:11:52 +00:00
Compare commits
180 Commits
v2.3.5.2f9
...
v2.3.9.f06
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f06c56a51b | ||
|
|
ac22a503de | ||
|
|
676319a9ca | ||
|
|
5d9800b7c2 | ||
|
|
0c89aff0f6 | ||
|
|
5e160b21c7 | ||
|
|
75dc8cccec | ||
|
|
147de75a02 | ||
|
|
5371f134ba | ||
|
|
8105c0440a | ||
|
|
cbf20e4cee | ||
|
|
c009c0db1e | ||
|
|
2c99f11073 | ||
|
|
0d57d29cbd | ||
|
|
353c7e07d1 | ||
|
|
77a66e1dce | ||
|
|
e98c3bf5d0 | ||
|
|
5e9d48d0d7 | ||
|
|
8e91f895a6 | ||
|
|
b155a5b6dc | ||
|
|
2c30923e3e | ||
|
|
0afe2d459f | ||
|
|
0b239e618d | ||
|
|
e9ebdfeff2 | ||
|
|
6fb7d7f2d7 | ||
|
|
70712d859c | ||
|
|
4d9081b3b1 | ||
|
|
7643a1acb1 | ||
|
|
61216e579e | ||
|
|
e31bb2d513 | ||
|
|
a8c38c4580 | ||
|
|
85e0372d26 | ||
|
|
53bd9de9b8 | ||
|
|
13ad524538 | ||
|
|
5f90f45ac4 | ||
|
|
dc0593c5a7 | ||
|
|
df3cceb108 | ||
|
|
827dcfca4a | ||
|
|
9fb6148aff | ||
|
|
6c1377aa39 | ||
|
|
077ca5919a | ||
|
|
668b716119 | ||
|
|
eaa7e21bc7 | ||
|
|
be0e882be1 | ||
|
|
09080d76ad | ||
|
|
d490a332a7 | ||
|
|
5dfa4b837f | ||
|
|
9501f3bda9 | ||
|
|
b69a1cada9 | ||
|
|
06e7d2b845 | ||
|
|
71400103b3 | ||
|
|
40e361e6d0 | ||
|
|
d1b6f11429 | ||
|
|
0527fb10ce | ||
|
|
5f929a8024 | ||
|
|
4f54862d63 | ||
|
|
0f4ac94559 | ||
|
|
45c1b46bd0 | ||
|
|
5095efc55f | ||
|
|
ec92f7a5a3 | ||
|
|
57da37cfbc | ||
|
|
3619ac87b8 | ||
|
|
e51ee91c39 | ||
|
|
21311bbeda | ||
|
|
472db5b237 | ||
|
|
18e69a0906 | ||
|
|
93f77ea7d2 | ||
|
|
ee4c4ae6c9 | ||
|
|
6cc7dee95c | ||
|
|
38c4d35a7b | ||
|
|
e683d8f552 | ||
|
|
e66aec8223 | ||
|
|
a06a01d25e | ||
|
|
f8c3f43ea6 | ||
|
|
dfcabba0b2 | ||
|
|
827bacdfc8 | ||
|
|
5806a266d3 | ||
|
|
30fbcabf84 | ||
|
|
c14043f196 | ||
|
|
e3610a2eb1 | ||
|
|
9baccc80d8 | ||
|
|
ac16ccf40c | ||
|
|
1c0227f90c | ||
|
|
57d296e0db | ||
|
|
9c9d126f6b | ||
|
|
27f0e42d2f | ||
|
|
4599534616 | ||
|
|
7acaec8ef5 | ||
|
|
d0e81b9151 | ||
|
|
c6e940af81 | ||
|
|
3302fbcc53 | ||
|
|
ccbf635eef | ||
|
|
6669b22db3 | ||
|
|
ec2b854ea2 | ||
|
|
378a2d723e | ||
|
|
5dd08e9533 | ||
|
|
125add9792 | ||
|
|
250cf16bf8 | ||
|
|
8b5fad21b0 | ||
|
|
30d4c3a945 | ||
|
|
45fd5e25ac | ||
|
|
ac6a668362 | ||
|
|
f47b40cf68 | ||
|
|
fd9461505f | ||
|
|
84edaabfe9 | ||
|
|
048f0a1601 | ||
|
|
4a48a3fb52 | ||
|
|
39bbf0d352 | ||
|
|
675d8fe089 | ||
|
|
0406be82d2 | ||
|
|
679e068e19 | ||
|
|
952393ca0f | ||
|
|
a231cd2ad0 | ||
|
|
ac87c0065f | ||
|
|
9822a85274 | ||
|
|
a957065fe8 | ||
|
|
41f3557491 | ||
|
|
402b0d7e0b | ||
|
|
13ebda6b2f | ||
|
|
1dd19cec6e | ||
|
|
df718ab294 | ||
|
|
dfc43bae18 | ||
|
|
f6cfdfe881 | ||
|
|
820c5dc8c5 | ||
|
|
1f9c295c9e | ||
|
|
5218aaafcf | ||
|
|
c480f0870c | ||
|
|
9e4ef92e6d | ||
|
|
cf65661c7c | ||
|
|
fb7a878d94 | ||
|
|
e72792afc8 | ||
|
|
ec39e1136a | ||
|
|
94e1f016e5 | ||
|
|
9170fe0580 | ||
|
|
ef9808cdd6 | ||
|
|
0972a8dccb | ||
|
|
419eb13968 | ||
|
|
e7828c4c64 | ||
|
|
44aa248099 | ||
|
|
e0513d4078 | ||
|
|
2100f3135e | ||
|
|
2f36d4990e | ||
|
|
65bde8538f | ||
|
|
7a3570aecf | ||
|
|
4a471ded79 | ||
|
|
eea85d26ca | ||
|
|
64edfb76e0 | ||
|
|
8ac308e73b | ||
|
|
0ae7674982 | ||
|
|
e4b5f2ce14 | ||
|
|
7d77b23eb6 | ||
|
|
a149999cec | ||
|
|
78d915b454 | ||
|
|
4c0b7ea409 | ||
|
|
425a715995 | ||
|
|
2e13aeeacb | ||
|
|
747c713ba9 | ||
|
|
4b5549be8f | ||
|
|
172d271b0b | ||
|
|
2e14234b77 | ||
|
|
d47e9bed19 | ||
|
|
bc085ab840 | ||
|
|
2450031b1b | ||
|
|
2cd877d2eb | ||
|
|
c34956e9d8 | ||
|
|
afb4de21d9 | ||
|
|
86223d8806 | ||
|
|
0632b96fcb | ||
|
|
dcfc9c9f03 | ||
|
|
8a3322fbcb | ||
|
|
55c9c3b298 | ||
|
|
9599549477 | ||
|
|
e813703bf5 | ||
|
|
699ea74672 | ||
|
|
a01069a549 | ||
|
|
3413b9da41 | ||
|
|
7d3175dc83 | ||
|
|
441638c2eb | ||
|
|
385d7296fe | ||
|
|
d1cd686644 |
2
.github/workflows/package_raspbian.yml
vendored
2
.github/workflows/package_raspbian.yml
vendored
@@ -45,6 +45,7 @@ jobs:
|
||||
|
||||
- name: build .debpkg
|
||||
run: |
|
||||
mkdir -p .debpkg/debian
|
||||
mkdir -p .debpkg/usr/share/doc/meshtasticd/web
|
||||
mkdir -p .debpkg/usr/sbin
|
||||
mkdir -p .debpkg/etc/meshtasticd
|
||||
@@ -55,6 +56,7 @@ jobs:
|
||||
cp bin/config-dist.yaml .debpkg/etc/meshtasticd/config.yaml
|
||||
chmod +x .debpkg/usr/sbin/meshtasticd
|
||||
cp bin/meshtasticd.service .debpkg/usr/lib/systemd/system/meshtasticd.service
|
||||
echo "etc/meshtasticd/config.yaml" > .debpkg/debian/conffiles
|
||||
|
||||
- uses: jiro4989/build-deb-action@v3
|
||||
with:
|
||||
|
||||
@@ -2,14 +2,17 @@
|
||||
extends = esp32_base
|
||||
|
||||
build_src_filter =
|
||||
${esp32_base.build_src_filter} -<nimble/> -<mesh/raspihttp>
|
||||
${esp32_base.build_src_filter} - <libpax/> -<nimble/> -<mesh/raspihttp>
|
||||
|
||||
monitor_speed = 115200
|
||||
|
||||
build_flags =
|
||||
${esp32_base.build_flags}
|
||||
-DHAS_BLUETOOTH=0
|
||||
-DMESHTASTIC_EXCLUDE_PAXCOUNTER
|
||||
-DMESHTASTIC_EXCLUDE_BLUETOOTH
|
||||
|
||||
lib_ignore =
|
||||
${esp32_base.lib_ignore}
|
||||
NimBLE-Arduino
|
||||
NimBLE-Arduino
|
||||
libpax
|
||||
@@ -3,7 +3,7 @@
|
||||
platform = platformio/nordicnrf52@^10.4.0
|
||||
extends = arduino_base
|
||||
|
||||
build_type = debug ; I'm debugging with ICE a lot now
|
||||
build_type = debug
|
||||
build_flags =
|
||||
${arduino_base.build_flags}
|
||||
-DSERIAL_BUFFER_SIZE=1024
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
; The Portduino based sim environment on top of any host OS, all hardware will be simulated
|
||||
[portduino_base]
|
||||
platform = https://github.com/meshtastic/platform-native.git#c95616208ffff4c8a36d48df810a3f072cce3521
|
||||
platform = https://github.com/meshtastic/platform-native.git#9881bf3721d610cccacf5ae8e3a07839cce75d63
|
||||
framework = arduino
|
||||
|
||||
build_src_filter =
|
||||
@@ -24,7 +24,7 @@ lib_deps =
|
||||
${env.lib_deps}
|
||||
${networking_base.lib_deps}
|
||||
rweather/Crypto@^0.4.0
|
||||
lovyan03/LovyanGFX@^1.1.12
|
||||
https://github.com/lovyan03/LovyanGFX.git#5a39989aa2c9492572255b22f033843ec8900233
|
||||
|
||||
build_flags =
|
||||
${arduino_base.build_flags}
|
||||
|
||||
@@ -38,11 +38,22 @@ Lora:
|
||||
# Busy: 20
|
||||
# Reset: 18
|
||||
|
||||
# Module: sx1268 # SX1268-based modules, tested with Ebyte E22 400M33S
|
||||
# CS: 21
|
||||
# IRQ: 16
|
||||
# Busy: 20
|
||||
# Reset: 18
|
||||
# TXen: 6
|
||||
# RXen: 12
|
||||
# DIO3_TCXO_VOLTAGE: true
|
||||
|
||||
# DIO3_TCXO_VOLTAGE: true # the Waveshare Core1262 and others are known to need this setting
|
||||
|
||||
# TXen: x # TX and RX enable pins
|
||||
# RXen: x
|
||||
|
||||
# ch341_quirk: true # Uncomment this to use the chunked SPI transfer that seems to fix the ch341
|
||||
|
||||
### Set gpio chip to use in /dev/. Defaults to 0.
|
||||
### Notably the Raspberry Pi 5 puts the GPIO header on gpiochip4
|
||||
# gpiochip: 4
|
||||
@@ -96,23 +107,29 @@ Display:
|
||||
# Panel: ILI9341
|
||||
# CS: 8
|
||||
# DC: 25
|
||||
# Backlight: 2
|
||||
# Width: 320
|
||||
# Height: 240
|
||||
# Width: 240
|
||||
# Height: 320
|
||||
# Rotate: true
|
||||
|
||||
Touchscreen:
|
||||
# Module: STMPE610
|
||||
### Note, at least for now, the touchscreen must have a CS pin defined, even if you let Linux manage the CS switching.
|
||||
|
||||
# Module: STMPE610 # Option 1 for Adafruit PiTFT 2.8
|
||||
# CS: 7
|
||||
# IRQ: 24
|
||||
|
||||
# Module: XPT2046
|
||||
# Module: FT5x06 # Option 2 for Adafruit PiTFT 2.8
|
||||
# IRQ: 24
|
||||
# I2CAddr: 0x38
|
||||
|
||||
# Module: XPT2046 # Waveshare 2.8inch
|
||||
# CS: 7
|
||||
# IRQ: 17
|
||||
|
||||
### Configure device for direct keyboard input
|
||||
|
||||
Input:
|
||||
# KeyboardDevice: /dev/input/event0
|
||||
# KeyboardDevice: /dev/input/by-id/usb-_Raspberry_Pi_Internal_Keyboard-event-kbd
|
||||
|
||||
###
|
||||
|
||||
|
||||
38
boards/CDEBYTE_EoRa-S3.json
Normal file
38
boards/CDEBYTE_EoRa-S3.json
Normal file
@@ -0,0 +1,38 @@
|
||||
{
|
||||
"build": {
|
||||
"arduino": {
|
||||
"ldscript": "esp32s3_out.ld"
|
||||
},
|
||||
"core": "esp32",
|
||||
"extra_flags": [
|
||||
"-D CDEBYTE_EORA_S3",
|
||||
"-D ARDUINO_USB_CDC_ON_BOOT=1",
|
||||
"-D ARDUINO_USB_MODE=0",
|
||||
"-D ARDUINO_RUNNING_CORE=1",
|
||||
"-D ARDUINO_EVENT_RUNNING_CORE=1",
|
||||
"-D BOARD_HAS_PSRAM"
|
||||
],
|
||||
"f_cpu": "240000000L",
|
||||
"f_flash": "80000000L",
|
||||
"flash_mode": "dio",
|
||||
"hwids": [["0x303A", "0x1001"]],
|
||||
"mcu": "esp32s3",
|
||||
"variant": "CDEBYTE_EoRa-S3"
|
||||
},
|
||||
"connectivity": ["wifi"],
|
||||
"debug": {
|
||||
"openocd_target": "esp32s3.cfg"
|
||||
},
|
||||
"frameworks": ["arduino", "espidf"],
|
||||
"name": "CDEBYTE EoRa-S3",
|
||||
"upload": {
|
||||
"flash_size": "4MB",
|
||||
"maximum_ram_size": 327680,
|
||||
"maximum_size": 4194304,
|
||||
"wait_for_upload_port": true,
|
||||
"require_upload_port": true,
|
||||
"speed": 921600
|
||||
},
|
||||
"url": "https://www.cdebyte.com/Module-Testkits-EoRaPI",
|
||||
"vendor": "CDEBYTE"
|
||||
}
|
||||
39
boards/ESP32-S3-WROOM-1-N4.json
Normal file
39
boards/ESP32-S3-WROOM-1-N4.json
Normal file
@@ -0,0 +1,39 @@
|
||||
{
|
||||
"build": {
|
||||
"arduino": {
|
||||
"ldscript": "esp32s3_out.ld"
|
||||
},
|
||||
"core": "esp32",
|
||||
"extra_flags": [
|
||||
"-D ARDUINO_USB_CDC_ON_BOOT=0",
|
||||
"-D ARDUINO_USB_MSC_ON_BOOT=0",
|
||||
"-D ARDUINO_USB_DFU_ON_BOOT=0",
|
||||
"-D ARDUINO_USB_MODE=0",
|
||||
"-D ARDUINO_RUNNING_CORE=1",
|
||||
"-D ARDUINO_EVENT_RUNNING_CORE=1"
|
||||
],
|
||||
"f_cpu": "240000000L",
|
||||
"f_flash": "80000000L",
|
||||
"flash_mode": "qio",
|
||||
"hwids": [["0x303A", "0x1001"]],
|
||||
"mcu": "esp32s3",
|
||||
"variant": "ESP32-S3-WROOM-1-N4"
|
||||
},
|
||||
"connectivity": ["wifi"],
|
||||
"debug": {
|
||||
"default_tool": "esp-builtin",
|
||||
"onboard_tools": ["esp-builtin"],
|
||||
"openocd_target": "esp32s3.cfg"
|
||||
},
|
||||
"frameworks": ["arduino", "espidf"],
|
||||
"name": "ESP32-S3-WROOM-1-N4 (4 MB Flash, No PSRAM)",
|
||||
"upload": {
|
||||
"flash_size": "4MB",
|
||||
"maximum_ram_size": 524288,
|
||||
"maximum_size": 4194304,
|
||||
"require_upload_port": true,
|
||||
"speed": 921600
|
||||
},
|
||||
"url": "https://www.espressif.com/sites/default/files/documentation/esp32-s3-wroom-1_wroom-1u_datasheet_en.pdf",
|
||||
"vendor": "Espressif"
|
||||
}
|
||||
52
boards/promicro-nrf52840.json
Normal file
52
boards/promicro-nrf52840.json
Normal file
@@ -0,0 +1,52 @@
|
||||
{
|
||||
"build": {
|
||||
"arduino": {
|
||||
"ldscript": "nrf52840_s140_v6.ld"
|
||||
},
|
||||
"core": "nRF5",
|
||||
"cpu": "cortex-m4",
|
||||
"extra_flags": "-DARDUINO_NRF52840_FEATHER -DNRF52840_XXAA",
|
||||
"f_cpu": "64000000L",
|
||||
"hwids": [
|
||||
["0x239A", "0x00B3"],
|
||||
["0x239A", "0x8029"],
|
||||
["0x239A", "0x0029"],
|
||||
["0x239A", "0x002A"],
|
||||
["0x239A", "0x802A"]
|
||||
],
|
||||
"usb_product": "ProMicro compatible nRF52840",
|
||||
"mcu": "nrf52840",
|
||||
"variant": "promicro_diy",
|
||||
"bsp": {
|
||||
"name": "adafruit"
|
||||
},
|
||||
"softdevice": {
|
||||
"sd_flags": "-DS140",
|
||||
"sd_name": "s140",
|
||||
"sd_version": "6.1.1",
|
||||
"sd_fwid": "0x00B6"
|
||||
},
|
||||
"bootloader": {
|
||||
"settings_addr": "0xFF000"
|
||||
}
|
||||
},
|
||||
"connectivity": ["bluetooth"],
|
||||
"debug": {
|
||||
"jlink_device": "nRF52840_xxAA",
|
||||
"svd_path": "nrf52840.svd"
|
||||
},
|
||||
"frameworks": ["arduino"],
|
||||
"name": "ProMicro compatible nRF52840",
|
||||
"upload": {
|
||||
"maximum_ram_size": 248832,
|
||||
"maximum_size": 815104,
|
||||
"speed": 115200,
|
||||
"protocol": "nrfutil",
|
||||
"protocols": ["nrfutil", "jlink", "nrfjprog", "stlink"],
|
||||
"use_1200bps_touch": true,
|
||||
"require_upload_port": true,
|
||||
"wait_for_upload_port": true
|
||||
},
|
||||
"url": "https://www.nologo.tech/product/otherboard/NRF52840.html",
|
||||
"vendor": "Nologo"
|
||||
}
|
||||
@@ -7,7 +7,6 @@
|
||||
"extra_flags": [
|
||||
"-DBOARD_HAS_PSRAM",
|
||||
"-DLILYGO_TBEAM_S3_CORE",
|
||||
"-DARDUINO_USB_CDC_ON_BOOT=1",
|
||||
"-DARDUINO_USB_MODE=1",
|
||||
"-DARDUINO_RUNNING_CORE=1",
|
||||
"-DARDUINO_EVENT_RUNNING_CORE=1"
|
||||
|
||||
34
boards/wiphone.json
Normal file
34
boards/wiphone.json
Normal file
@@ -0,0 +1,34 @@
|
||||
{
|
||||
"build": {
|
||||
"arduino": {
|
||||
"ldscript": "esp32_out.ld",
|
||||
"partitions": "default_16MB.csv"
|
||||
},
|
||||
"core": "esp32",
|
||||
"extra_flags": [
|
||||
"-DARDUINO_WIPHONE14",
|
||||
"-DBOARD_HAS_PSRAM",
|
||||
"-mfix-esp32-psram-cache-issue",
|
||||
"-mfix-esp32-psram-cache-strategy=memw"
|
||||
],
|
||||
"f_cpu": "240000000L",
|
||||
"f_flash": "40000000L",
|
||||
"flash_mode": "dio",
|
||||
"mcu": "esp32",
|
||||
"variant": "wiphone",
|
||||
"board": "WiPhone"
|
||||
},
|
||||
"connectivity": ["wifi", "bluetooth"],
|
||||
"frameworks": ["arduino", "espidf"],
|
||||
"name": "WIPhone Integrated 1.4",
|
||||
"upload": {
|
||||
"flash_size": "16MB",
|
||||
"maximum_ram_size": 532480,
|
||||
"maximum_size": 6553600,
|
||||
"maximum_data_size": 4521984,
|
||||
"require_upload_port": true,
|
||||
"speed": 921600
|
||||
},
|
||||
"url": "https://www.wiphone.io/",
|
||||
"vendor": "HackEDA"
|
||||
}
|
||||
@@ -78,7 +78,7 @@ lib_deps =
|
||||
https://github.com/meshtastic/esp8266-oled-ssd1306.git#ee628ee6c9588d4c56c9e3da35f0fc9448ad54a8 ; ESP8266_SSD1306
|
||||
mathertel/OneButton@^2.5.0 ; OneButton library for non-blocking button debounce
|
||||
https://github.com/meshtastic/arduino-fsm.git#7db3702bf0cfe97b783d6c72595e3f38e0b19159
|
||||
https://github.com/meshtastic/TinyGPSPlus.git#964f75a72cccd6b53cd74e4add1f7a42c6f7344d
|
||||
https://github.com/meshtastic/TinyGPSPlus.git#71a82db35f3b973440044c476d4bcdc673b104f4
|
||||
https://github.com/meshtastic/ArduinoThread.git#1ae8778c85d0a2a729f989e0b1e7d7c4dc84eef0
|
||||
nanopb/Nanopb@^0.4.7
|
||||
erriez/ErriezCRC32@^1.0.1
|
||||
@@ -96,7 +96,6 @@ check_flags =
|
||||
framework = arduino
|
||||
lib_deps =
|
||||
${env.lib_deps}
|
||||
mprograms/QMC5883LCompass@^1.2.0
|
||||
end2endzone/NonBlockingRTTTL@^1.3.0
|
||||
https://github.com/meshtastic/SparkFun_ATECCX08a_Arduino_Library.git#5cf62b36c6f30bc72a07bdb2c11fc9a22d1e31da
|
||||
|
||||
@@ -132,4 +131,6 @@ lib_deps =
|
||||
adafruit/Adafruit MPU6050@^2.2.4
|
||||
adafruit/Adafruit LIS3DH@^1.2.4
|
||||
https://github.com/lewisxhe/SensorLib#27fd0f721e20cd09e1f81383f0ba58a54fe84a17
|
||||
adafruit/Adafruit LSM6DS@^4.7.2
|
||||
adafruit/Adafruit LSM6DS@^4.7.2
|
||||
mprograms/QMC5883LCompass@^1.2.0
|
||||
https://github.com/Sensirion/arduino-i2c-sht4x#1.1.0
|
||||
|
||||
Submodule protobufs updated: f92900c5f8...1bfe0354d1
@@ -1,6 +1,9 @@
|
||||
#include "configuration.h"
|
||||
|
||||
#if !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR
|
||||
|
||||
#include "PowerFSM.h"
|
||||
#include "concurrency/OSThread.h"
|
||||
#include "configuration.h"
|
||||
#include "main.h"
|
||||
#include "power.h"
|
||||
|
||||
@@ -172,4 +175,6 @@ class AccelerometerThread : public concurrency::OSThread
|
||||
Adafruit_LSM6DS3TRC lsm;
|
||||
};
|
||||
|
||||
} // namespace concurrency
|
||||
} // namespace concurrency
|
||||
|
||||
#endif
|
||||
@@ -5,6 +5,16 @@
|
||||
NCP5623 rgb;
|
||||
#endif
|
||||
|
||||
#ifdef HAS_NEOPIXEL
|
||||
#include <graphics/NeoPixel.h>
|
||||
Adafruit_NeoPixel pixels(NEOPIXEL_COUNT, NEOPIXEL_DATA, NEOPIXEL_TYPE);
|
||||
#endif
|
||||
|
||||
#ifdef UNPHONE
|
||||
#include "unPhone.h"
|
||||
extern unPhone unphone;
|
||||
#endif
|
||||
|
||||
namespace concurrency
|
||||
{
|
||||
class AmbientLightingThread : public concurrency::OSThread
|
||||
@@ -27,15 +37,31 @@ class AmbientLightingThread : public concurrency::OSThread
|
||||
disable();
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
#if defined(HAS_NCP5623) || defined(RGBLED_RED) || defined(HAS_NEOPIXEL) || defined(UNPHONE)
|
||||
if (!moduleConfig.ambient_lighting.led_state) {
|
||||
LOG_DEBUG("AmbientLightingThread disabling due to moduleConfig.ambient_lighting.led_state OFF\n");
|
||||
disable();
|
||||
return;
|
||||
}
|
||||
LOG_DEBUG("AmbientLightingThread initializing\n");
|
||||
#ifdef HAS_NCP5623
|
||||
if (_type == ScanI2C::NCP5623) {
|
||||
rgb.begin();
|
||||
#endif
|
||||
#ifdef RGBLED_RED
|
||||
pinMode(RGBLED_RED, OUTPUT);
|
||||
pinMode(RGBLED_GREEN, OUTPUT);
|
||||
pinMode(RGBLED_BLUE, OUTPUT);
|
||||
#endif
|
||||
#ifdef HAS_NEOPIXEL
|
||||
pixels.begin(); // Initialise the pixel(s)
|
||||
pixels.clear(); // Set all pixel colors to 'off'
|
||||
pixels.setBrightness(moduleConfig.ambient_lighting.current);
|
||||
#endif
|
||||
setLighting();
|
||||
#endif
|
||||
#ifdef HAS_NCP5623
|
||||
}
|
||||
#endif
|
||||
}
|
||||
@@ -43,16 +69,17 @@ class AmbientLightingThread : public concurrency::OSThread
|
||||
protected:
|
||||
int32_t runOnce() override
|
||||
{
|
||||
#if defined(HAS_NCP5623) || defined(RGBLED_RED) || defined(HAS_NEOPIXEL) || defined(UNPHONE)
|
||||
#ifdef HAS_NCP5623
|
||||
if (_type == ScanI2C::NCP5623 && moduleConfig.ambient_lighting.led_state) {
|
||||
#endif
|
||||
setLighting();
|
||||
return 30000; // 30 seconds to reset from any animations that may have been running from Ext. Notification
|
||||
} else {
|
||||
return disable();
|
||||
#ifdef HAS_NCP5623
|
||||
}
|
||||
#else
|
||||
return disable();
|
||||
#endif
|
||||
#endif
|
||||
return disable();
|
||||
}
|
||||
|
||||
private:
|
||||
@@ -65,9 +92,36 @@ class AmbientLightingThread : public concurrency::OSThread
|
||||
rgb.setRed(moduleConfig.ambient_lighting.red);
|
||||
rgb.setGreen(moduleConfig.ambient_lighting.green);
|
||||
rgb.setBlue(moduleConfig.ambient_lighting.blue);
|
||||
LOG_DEBUG("Initializing Ambient lighting w/ current=%d, red=%d, green=%d, blue=%d\n",
|
||||
LOG_DEBUG("Initializing NCP5623 Ambient lighting w/ current=%d, red=%d, green=%d, blue=%d\n",
|
||||
moduleConfig.ambient_lighting.current, moduleConfig.ambient_lighting.red, moduleConfig.ambient_lighting.green,
|
||||
moduleConfig.ambient_lighting.blue);
|
||||
#endif
|
||||
#ifdef HAS_NEOPIXEL
|
||||
pixels.fill(pixels.Color(moduleConfig.ambient_lighting.red, moduleConfig.ambient_lighting.green,
|
||||
moduleConfig.ambient_lighting.blue),
|
||||
0, NEOPIXEL_COUNT);
|
||||
pixels.show();
|
||||
LOG_DEBUG("Initializing NeoPixel Ambient lighting w/ brightness(current)=%d, red=%d, green=%d, blue=%d\n",
|
||||
moduleConfig.ambient_lighting.current, moduleConfig.ambient_lighting.red, moduleConfig.ambient_lighting.green,
|
||||
moduleConfig.ambient_lighting.blue);
|
||||
#endif
|
||||
#ifdef RGBLED_CA
|
||||
analogWrite(RGBLED_RED, 255 - moduleConfig.ambient_lighting.red);
|
||||
analogWrite(RGBLED_GREEN, 255 - moduleConfig.ambient_lighting.green);
|
||||
analogWrite(RGBLED_BLUE, 255 - moduleConfig.ambient_lighting.blue);
|
||||
LOG_DEBUG("Initializing Ambient lighting RGB Common Anode w/ red=%d, green=%d, blue=%d\n",
|
||||
moduleConfig.ambient_lighting.red, moduleConfig.ambient_lighting.green, moduleConfig.ambient_lighting.blue);
|
||||
#elif defined(RGBLED_RED)
|
||||
analogWrite(RGBLED_RED, moduleConfig.ambient_lighting.red);
|
||||
analogWrite(RGBLED_GREEN, moduleConfig.ambient_lighting.green);
|
||||
analogWrite(RGBLED_BLUE, moduleConfig.ambient_lighting.blue);
|
||||
LOG_DEBUG("Initializing Ambient lighting RGB Common Cathode w/ red=%d, green=%d, blue=%d\n",
|
||||
moduleConfig.ambient_lighting.red, moduleConfig.ambient_lighting.green, moduleConfig.ambient_lighting.blue);
|
||||
#endif
|
||||
#ifdef UNPHONE
|
||||
unphone.rgb(moduleConfig.ambient_lighting.red, moduleConfig.ambient_lighting.green, moduleConfig.ambient_lighting.blue);
|
||||
LOG_DEBUG("Initializing unPhone Ambient lighting w/ red=%d, green=%d, blue=%d\n", moduleConfig.ambient_lighting.red,
|
||||
moduleConfig.ambient_lighting.green, moduleConfig.ambient_lighting.blue);
|
||||
#endif
|
||||
}
|
||||
};
|
||||
|
||||
@@ -52,8 +52,8 @@ ButtonThread::ButtonThread() : OSThread("Button")
|
||||
|
||||
#if defined(BUTTON_PIN) || defined(ARCH_PORTDUINO)
|
||||
userButton.attachClick(userButtonPressed);
|
||||
userButton.setClickMs(250);
|
||||
userButton.setPressMs(c_longPressTime);
|
||||
userButton.setClickMs(BUTTON_CLICK_MS);
|
||||
userButton.setPressMs(BUTTON_LONGPRESS_MS);
|
||||
userButton.setDebounceMs(1);
|
||||
userButton.attachDoubleClick(userButtonDoublePressed);
|
||||
userButton.attachMultiClick(userButtonMultiPressed, this); // Reference to instance: get click count from non-static OneButton
|
||||
@@ -70,8 +70,8 @@ ButtonThread::ButtonThread() : OSThread("Button")
|
||||
pinMode(BUTTON_PIN_ALT, INPUT_PULLUP_SENSE);
|
||||
#endif
|
||||
userButtonAlt.attachClick(userButtonPressed);
|
||||
userButtonAlt.setClickMs(250);
|
||||
userButtonAlt.setPressMs(c_longPressTime);
|
||||
userButtonAlt.setClickMs(BUTTON_CLICK_MS);
|
||||
userButtonAlt.setPressMs(BUTTON_LONGPRESS_MS);
|
||||
userButtonAlt.setDebounceMs(1);
|
||||
userButtonAlt.attachDoubleClick(userButtonDoublePressed);
|
||||
userButtonAlt.attachLongPressStart(userButtonPressedLongStart);
|
||||
@@ -80,7 +80,7 @@ ButtonThread::ButtonThread() : OSThread("Button")
|
||||
|
||||
#ifdef BUTTON_PIN_TOUCH
|
||||
userButtonTouch = OneButton(BUTTON_PIN_TOUCH, true, true);
|
||||
userButtonTouch.setPressMs(400);
|
||||
userButtonTouch.setPressMs(BUTTON_TOUCH_MS);
|
||||
userButtonTouch.attachLongPressStart(touchPressedLongStart); // Better handling with longpress than click?
|
||||
#endif
|
||||
|
||||
@@ -136,9 +136,12 @@ int32_t ButtonThread::runOnce()
|
||||
case BUTTON_EVENT_DOUBLE_PRESSED: {
|
||||
LOG_BUTTON("Double press!\n");
|
||||
service.refreshLocalMeshNode();
|
||||
service.sendNetworkPing(NODENUM_BROADCAST, true);
|
||||
auto sentPosition = service.trySendPosition(NODENUM_BROADCAST, true);
|
||||
if (screen) {
|
||||
screen->print("Sent ad-hoc ping\n");
|
||||
if (sentPosition)
|
||||
screen->print("Sent ad-hoc position\n");
|
||||
else
|
||||
screen->print("Sent ad-hoc nodeinfo\n");
|
||||
screen->forceDisplay(true); // Force a new UI frame, then force an EInk update
|
||||
}
|
||||
break;
|
||||
@@ -193,15 +196,13 @@ int32_t ButtonThread::runOnce()
|
||||
#ifdef BUTTON_PIN_TOUCH
|
||||
case BUTTON_EVENT_TOUCH_LONG_PRESSED: {
|
||||
LOG_BUTTON("Touch press!\n");
|
||||
if (config.display.wake_on_tap_or_motion) {
|
||||
if (screen) {
|
||||
// Wake if asleep
|
||||
if (powerFSM.getState() == &stateDARK)
|
||||
powerFSM.trigger(EVENT_PRESS);
|
||||
if (screen) {
|
||||
// Wake if asleep
|
||||
if (powerFSM.getState() == &stateDARK)
|
||||
powerFSM.trigger(EVENT_PRESS);
|
||||
|
||||
// Update display (legacy behaviour)
|
||||
screen->forceDisplay();
|
||||
}
|
||||
// Update display (legacy behaviour)
|
||||
screen->forceDisplay();
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -213,6 +214,7 @@ int32_t ButtonThread::runOnce()
|
||||
btnEvent = BUTTON_EVENT_NONE;
|
||||
}
|
||||
|
||||
runASAP = false;
|
||||
return 50;
|
||||
}
|
||||
|
||||
@@ -233,6 +235,7 @@ void ButtonThread::attachButtonInterrupts()
|
||||
BaseType_t higherWake = 0;
|
||||
mainDelay.interruptFromISR(&higherWake);
|
||||
ButtonThread::userButton.tick();
|
||||
runASAP = true;
|
||||
},
|
||||
CHANGE);
|
||||
#endif
|
||||
@@ -279,6 +282,7 @@ void ButtonThread::wakeOnIrq(int irq, int mode)
|
||||
[] {
|
||||
BaseType_t higherWake = 0;
|
||||
mainDelay.interruptFromISR(&higherWake);
|
||||
runASAP = true;
|
||||
},
|
||||
FALLING);
|
||||
}
|
||||
|
||||
@@ -4,11 +4,22 @@
|
||||
#include "concurrency/OSThread.h"
|
||||
#include "configuration.h"
|
||||
|
||||
#ifndef BUTTON_CLICK_MS
|
||||
#define BUTTON_CLICK_MS 250
|
||||
#endif
|
||||
|
||||
#ifndef BUTTON_LONGPRESS_MS
|
||||
#define BUTTON_LONGPRESS_MS 5000
|
||||
#endif
|
||||
|
||||
#ifndef BUTTON_TOUCH_MS
|
||||
#define BUTTON_TOCH_MS 400
|
||||
#endif
|
||||
|
||||
class ButtonThread : public concurrency::OSThread
|
||||
{
|
||||
public:
|
||||
static const uint32_t c_longPressTime = 5000; // shutdown after 5s
|
||||
static const uint32_t c_holdOffTime = 30000; // hold off 30s after boot
|
||||
static const uint32_t c_holdOffTime = 30000; // hold off 30s after boot
|
||||
|
||||
enum ButtonEventType {
|
||||
BUTTON_EVENT_NONE,
|
||||
|
||||
@@ -212,8 +212,23 @@ void fsInit()
|
||||
LOG_ERROR("Filesystem mount Failed.\n");
|
||||
// assert(0); This auto-formats the partition, so no need to fail here.
|
||||
}
|
||||
#ifdef ARCH_ESP32
|
||||
#if defined(ARCH_ESP32)
|
||||
LOG_DEBUG("Filesystem files (%d/%d Bytes):\n", FSCom.usedBytes(), FSCom.totalBytes());
|
||||
#elif defined(ARCH_NRF52)
|
||||
/*
|
||||
* nRF52840 has a certain chance of automatic formatting failure.
|
||||
* Try to create a file after initializing the file system. If the creation fails,
|
||||
* it means that the file system is not working properly. Please format it manually again.
|
||||
* */
|
||||
Adafruit_LittleFS_Namespace::File file(FSCom);
|
||||
const char *filename = "/meshtastic.txt";
|
||||
if (!file.open(filename, FILE_O_WRITE)) {
|
||||
LOG_DEBUG("Format ....");
|
||||
FSCom.format();
|
||||
FSCom.begin();
|
||||
} else {
|
||||
file.close();
|
||||
}
|
||||
#else
|
||||
LOG_DEBUG("Filesystem files:\n");
|
||||
#endif
|
||||
|
||||
@@ -69,7 +69,7 @@ static const uint8_t ext_chrg_detect_value = EXT_CHRG_DETECT_VALUE;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if HAS_TELEMETRY && !defined(ARCH_PORTDUINO)
|
||||
#if HAS_TELEMETRY && !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR && !defined(ARCH_PORTDUINO)
|
||||
INA260Sensor ina260Sensor;
|
||||
INA219Sensor ina219Sensor;
|
||||
INA3221Sensor ina3221Sensor;
|
||||
@@ -184,7 +184,7 @@ class AnalogBatteryLevel : public HasBatteryLevel
|
||||
virtual uint16_t getBattVoltage() override
|
||||
{
|
||||
|
||||
#if defined(HAS_TELEMETRY) && !defined(ARCH_PORTDUINO) && !defined(HAS_PMU)
|
||||
#if HAS_TELEMETRY && !defined(ARCH_PORTDUINO) && !defined(HAS_PMU) && !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR
|
||||
if (hasINA()) {
|
||||
LOG_DEBUG("Using INA on I2C addr 0x%x for device battery voltage\n", config.power.device_battery_ina_address);
|
||||
return getINAVoltage();
|
||||
@@ -223,7 +223,17 @@ class AnalogBatteryLevel : public HasBatteryLevel
|
||||
raw = raw / BATTERY_SENSE_SAMPLES;
|
||||
scaled = operativeAdcMultiplier * ((1000 * AREF_VOLTAGE) / pow(2, BATTERY_SENSE_RESOLUTION_BITS)) * raw;
|
||||
#endif
|
||||
last_read_value += (scaled - last_read_value) * 0.5; // Virtual LPF
|
||||
|
||||
if (!initial_read_done) {
|
||||
// Flush the smoothing filter with an ADC reading, if the reading is plausibly correct
|
||||
if (scaled > last_read_value)
|
||||
last_read_value = scaled;
|
||||
initial_read_done = true;
|
||||
} else {
|
||||
// Already initialized - filter this reading
|
||||
last_read_value += (scaled - last_read_value) * 0.5; // Virtual LPF
|
||||
}
|
||||
|
||||
// LOG_DEBUG("battery gpio %d raw val=%u scaled=%u filtered=%u\n", BATTERY_PIN, raw, (uint32_t)(scaled), (uint32_t)
|
||||
// (last_read_value));
|
||||
}
|
||||
@@ -357,10 +367,12 @@ class AnalogBatteryLevel : public HasBatteryLevel
|
||||
const float noBatVolt = (OCV[NUM_OCV_POINTS - 1] - 500) * NUM_CELLS;
|
||||
// Start value from minimum voltage for the filter to not start from 0
|
||||
// that could trigger some events.
|
||||
// This value is over-written by the first ADC reading, it the voltage seems reasonable.
|
||||
bool initial_read_done = false;
|
||||
float last_read_value = (OCV[NUM_OCV_POINTS - 1] * NUM_CELLS);
|
||||
uint32_t last_read_time_ms = 0;
|
||||
|
||||
#if defined(HAS_TELEMETRY) && !defined(ARCH_PORTDUINO)
|
||||
#if HAS_TELEMETRY && !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR && !defined(ARCH_PORTDUINO)
|
||||
uint16_t getINAVoltage()
|
||||
{
|
||||
if (nodeTelemetrySensorsMap[meshtastic_TelemetrySensorType_INA219].first == config.power.device_battery_ina_address) {
|
||||
|
||||
@@ -185,10 +185,12 @@ static void powerEnter()
|
||||
screen->setOn(true);
|
||||
setBluetoothEnable(true);
|
||||
// within enter() the function getState() returns the state we came from
|
||||
if (strcmp(powerFSM.getState()->name, "BOOT") != 0 && strcmp(powerFSM.getState()->name, "POWER") != 0 &&
|
||||
|
||||
// Mothballed: print change of power-state to device screen
|
||||
/* if (strcmp(powerFSM.getState()->name, "BOOT") != 0 && strcmp(powerFSM.getState()->name, "POWER") != 0 &&
|
||||
strcmp(powerFSM.getState()->name, "DARK") != 0) {
|
||||
screen->print("Powered...\n");
|
||||
}
|
||||
}*/
|
||||
}
|
||||
}
|
||||
|
||||
@@ -205,8 +207,10 @@ static void powerExit()
|
||||
{
|
||||
screen->setOn(true);
|
||||
setBluetoothEnable(true);
|
||||
if (!isPowered())
|
||||
screen->print("Unpowered...\n");
|
||||
|
||||
// Mothballed: print change of power-state to device screen
|
||||
/*if (!isPowered())
|
||||
screen->print("Unpowered...\n");*/
|
||||
}
|
||||
|
||||
static void onEnter()
|
||||
|
||||
@@ -182,11 +182,11 @@ size_t RedirectablePrint::log(const char *logLevel, const char *format, ...)
|
||||
void RedirectablePrint::hexDump(const char *logLevel, unsigned char *buf, uint16_t len)
|
||||
{
|
||||
const char alphabet[17] = "0123456789abcdef";
|
||||
log(logLevel, " +------------------------------------------------+ +----------------+\n");
|
||||
log(logLevel, " |.0 .1 .2 .3 .4 .5 .6 .7 .8 .9 .a .b .c .d .e .f | | ASCII |\n");
|
||||
log(logLevel, " +------------------------------------------------+ +----------------+\n");
|
||||
log(logLevel, " |.0 .1 .2 .3 .4 .5 .6 .7 .8 .9 .a .b .c .d .e .f | | ASCII |\n");
|
||||
for (uint16_t i = 0; i < len; i += 16) {
|
||||
if (i % 128 == 0)
|
||||
log(logLevel, " +------------------------------------------------+ +----------------+\n");
|
||||
log(logLevel, " +------------------------------------------------+ +----------------+\n");
|
||||
char s[] = "| | | |\n";
|
||||
uint8_t ix = 1, iy = 52;
|
||||
for (uint8_t j = 0; j < 16; j++) {
|
||||
@@ -208,7 +208,7 @@ void RedirectablePrint::hexDump(const char *logLevel, unsigned char *buf, uint16
|
||||
log(logLevel, ".");
|
||||
log(logLevel, s);
|
||||
}
|
||||
log(logLevel, " +------------------------------------------------+ +----------------+\n");
|
||||
log(logLevel, " +------------------------------------------------+ +----------------+\n");
|
||||
}
|
||||
|
||||
std::string RedirectablePrint::mt_sprintf(const std::string fmt_str, ...)
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
#include "NodeDB.h"
|
||||
#include "PowerFSM.h"
|
||||
#include "configuration.h"
|
||||
#include "time.h"
|
||||
|
||||
#ifdef RP2040_SLOW_CLOCK
|
||||
#define Port Serial2
|
||||
@@ -50,7 +51,9 @@ SerialConsole::SerialConsole() : StreamAPI(&Port), RedirectablePrint(&Port), con
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#if !ARCH_PORTDUINO
|
||||
emitRebooted();
|
||||
#endif
|
||||
}
|
||||
|
||||
int32_t SerialConsole::runOnce()
|
||||
|
||||
@@ -74,6 +74,13 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#define RTC_DATA_ATTR
|
||||
#endif
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Regulatory overrides for producing regional builds
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
// Define if region should override user saved region
|
||||
// #define LORA_REGIONCODE meshtastic_Config_LoRaConfig_RegionCode_SG_923
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Feature toggles
|
||||
// -----------------------------------------------------------------------------
|
||||
@@ -119,8 +126,9 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#define SHTC3_ADDR 0x70
|
||||
#define LPS22HB_ADDR 0x5C
|
||||
#define LPS22HB_ADDR_ALT 0x5D
|
||||
#define SHT31_ADDR 0x44
|
||||
#define SHT31_4x_ADDR 0x44
|
||||
#define PMSA0031_ADDR 0x12
|
||||
#define RCWL9620_ADDR 0x57
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// ACCELEROMETER
|
||||
|
||||
@@ -29,6 +29,7 @@ class ScanI2C
|
||||
INA3221,
|
||||
MCP9808,
|
||||
SHT31,
|
||||
SHT4X,
|
||||
SHTC3,
|
||||
LPS22HB,
|
||||
QMC6310,
|
||||
@@ -41,9 +42,8 @@ class ScanI2C
|
||||
BQ24295,
|
||||
LSM6DS3,
|
||||
TCA9555,
|
||||
#ifdef HAS_NCP5623
|
||||
RCWL9620,
|
||||
NCP5623,
|
||||
#endif
|
||||
} DeviceType;
|
||||
|
||||
// typedef uint8_t DeviceAddress;
|
||||
|
||||
@@ -271,8 +271,14 @@ void ScanI2CTwoWire::scanPort(I2CPort port)
|
||||
}
|
||||
break;
|
||||
case INA3221_ADDR:
|
||||
LOG_INFO("INA3221 sensor found at address 0x%x\n", (uint8_t)addr.address);
|
||||
type = INA3221;
|
||||
registerValue = getRegisterValue(ScanI2CTwoWire::RegisterLocation(addr, 0xFE), 2);
|
||||
LOG_DEBUG("Register MFG_UID: 0x%x\n", registerValue);
|
||||
if (registerValue == 0x5449) {
|
||||
LOG_INFO("INA3221 sensor found at address 0x%x\n", (uint8_t)addr.address);
|
||||
type = INA3221;
|
||||
} else { // Unknown device
|
||||
LOG_INFO("No INA3221 found at address 0x%x\n", (uint8_t)addr.address);
|
||||
}
|
||||
break;
|
||||
case MCP9808_ADDR:
|
||||
registerValue = getRegisterValue(ScanI2CTwoWire::RegisterLocation(addr, 0x07), 2);
|
||||
@@ -286,8 +292,20 @@ void ScanI2CTwoWire::scanPort(I2CPort port)
|
||||
|
||||
break;
|
||||
|
||||
SCAN_SIMPLE_CASE(SHT31_ADDR, SHT31, "SHT31 sensor found\n")
|
||||
case SHT31_4x_ADDR:
|
||||
registerValue = getRegisterValue(ScanI2CTwoWire::RegisterLocation(addr, 0x89), 2);
|
||||
if (registerValue == 0x11a2) {
|
||||
type = SHT4X;
|
||||
LOG_INFO("SHT4X sensor found\n");
|
||||
} else {
|
||||
type = SHT31;
|
||||
LOG_INFO("SHT31 sensor found\n");
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
SCAN_SIMPLE_CASE(SHTC3_ADDR, SHTC3, "SHTC3 sensor found\n")
|
||||
SCAN_SIMPLE_CASE(RCWL9620_ADDR, RCWL9620, "RCWL9620 sensor found\n")
|
||||
|
||||
case LPS22HB_ADDR_ALT:
|
||||
SCAN_SIMPLE_CASE(LPS22HB_ADDR, LPS22HB, "LPS22HB sensor found\n")
|
||||
@@ -350,4 +368,4 @@ TwoWire *ScanI2CTwoWire::fetchI2CBus(ScanI2C::DeviceAddress address) const
|
||||
size_t ScanI2CTwoWire::countDevices() const
|
||||
{
|
||||
return foundDevices.size();
|
||||
}
|
||||
}
|
||||
|
||||
167
src/gps/GPS.cpp
167
src/gps/GPS.cpp
@@ -7,6 +7,8 @@
|
||||
|
||||
#include "main.h" // pmu_found
|
||||
#include "sleep.h"
|
||||
|
||||
#include "cas.h"
|
||||
#include "ubx.h"
|
||||
|
||||
#ifdef ARCH_PORTDUINO
|
||||
@@ -51,6 +53,28 @@ void GPS::UBXChecksum(uint8_t *message, size_t length)
|
||||
message[length - 1] = CK_B;
|
||||
}
|
||||
|
||||
// Calculate the checksum for a CAS packet
|
||||
void GPS::CASChecksum(uint8_t *message, size_t length)
|
||||
{
|
||||
uint32_t cksum = ((uint32_t)message[5] << 24); // Message ID
|
||||
cksum += ((uint32_t)message[4]) << 16; // Class
|
||||
cksum += message[2]; // Payload Len
|
||||
|
||||
// Iterate over the payload as a series of uint32_t's and
|
||||
// accumulate the cksum
|
||||
uint32_t const *payload = (uint32_t *)(message + 6);
|
||||
for (size_t i = 0; i < (length - 10) / 4; i++) {
|
||||
uint32_t pl = payload[i];
|
||||
cksum += pl;
|
||||
}
|
||||
|
||||
// Place the checksum values in the message
|
||||
message[length - 4] = (cksum & 0xFF);
|
||||
message[length - 3] = (cksum & (0xFF << 8)) >> 8;
|
||||
message[length - 2] = (cksum & (0xFF << 16)) >> 16;
|
||||
message[length - 1] = (cksum & (0xFF << 24)) >> 24;
|
||||
}
|
||||
|
||||
// Function to create a ublox packet for editing in memory
|
||||
uint8_t GPS::makeUBXPacket(uint8_t class_id, uint8_t msg_id, uint8_t payload_size, const uint8_t *msg)
|
||||
{
|
||||
@@ -72,6 +96,41 @@ uint8_t GPS::makeUBXPacket(uint8_t class_id, uint8_t msg_id, uint8_t payload_siz
|
||||
return (payload_size + 8);
|
||||
}
|
||||
|
||||
// Function to create a CAS packet for editing in memory
|
||||
uint8_t GPS::makeCASPacket(uint8_t class_id, uint8_t msg_id, uint8_t payload_size, const uint8_t *msg)
|
||||
{
|
||||
// General CAS structure
|
||||
// | H1 | H2 | payload_len | cls | msg | Payload ... | Checksum |
|
||||
// Size: | 1 | 1 | 2 | 1 | 1 | payload_len | 4 |
|
||||
// Pos: | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 ... | 6 + payload_len ... |
|
||||
// |------|------|-------------|------|------|------|--------------|---------------------------|
|
||||
// | 0xBA | 0xCE | 0xXX | 0xXX | 0xXX | 0xXX | 0xXX | 0xXX ... | 0xXX | 0xXX | 0xXX | 0xXX |
|
||||
|
||||
// Construct the CAS packet
|
||||
UBXscratch[0] = 0xBA; // header 1 (0xBA)
|
||||
UBXscratch[1] = 0xCE; // header 2 (0xCE)
|
||||
UBXscratch[2] = payload_size; // length 1
|
||||
UBXscratch[3] = 0; // length 2
|
||||
UBXscratch[4] = class_id; // class
|
||||
UBXscratch[5] = msg_id; // id
|
||||
|
||||
UBXscratch[6 + payload_size] = 0x00; // Checksum
|
||||
UBXscratch[7 + payload_size] = 0x00;
|
||||
UBXscratch[8 + payload_size] = 0x00;
|
||||
UBXscratch[9 + payload_size] = 0x00;
|
||||
|
||||
for (int i = 0; i < payload_size; i++) {
|
||||
UBXscratch[6 + i] = pgm_read_byte(&msg[i]);
|
||||
}
|
||||
CASChecksum(UBXscratch, (payload_size + 10));
|
||||
|
||||
#if defined(GPS_DEBUG) && defined(DEBUG_PORT)
|
||||
LOG_DEBUG("Constructed CAS packet: \n");
|
||||
DEBUG_PORT.hexDump(MESHTASTIC_LOG_LEVEL_DEBUG, UBXscratch, payload_size + 10);
|
||||
#endif
|
||||
return (payload_size + 10);
|
||||
}
|
||||
|
||||
GPS_RESPONSE GPS::getACK(const char *message, uint32_t waitMillis)
|
||||
{
|
||||
uint8_t buffer[768] = {0};
|
||||
@@ -81,6 +140,7 @@ GPS_RESPONSE GPS::getACK(const char *message, uint32_t waitMillis)
|
||||
while (millis() < startTimeout) {
|
||||
if (_serial_gps->available()) {
|
||||
b = _serial_gps->read();
|
||||
|
||||
#ifdef GPS_DEBUG
|
||||
LOG_DEBUG("%02X", (char *)buffer);
|
||||
#endif
|
||||
@@ -104,6 +164,67 @@ GPS_RESPONSE GPS::getACK(const char *message, uint32_t waitMillis)
|
||||
return GNSS_RESPONSE_NONE;
|
||||
}
|
||||
|
||||
GPS_RESPONSE GPS::getACKCas(uint8_t class_id, uint8_t msg_id, uint32_t waitMillis)
|
||||
{
|
||||
uint32_t startTime = millis();
|
||||
uint8_t buffer[CAS_ACK_NACK_MSG_SIZE] = {0};
|
||||
uint8_t bufferPos = 0;
|
||||
|
||||
// CAS-ACK-(N)ACK structure
|
||||
// | H1 | H2 | Payload Len | cls | msg | Payload | Checksum (4) |
|
||||
// | | | | | | Cls | Msg | Reserved | |
|
||||
// |------|------|-------------|------|------|------|------|-------------|---------------------------|
|
||||
// ACK-NACK| 0xBA | 0xCE | 0x04 | 0x00 | 0x05 | 0x00 | 0xXX | 0xXX | 0x00 | 0x00 | 0xXX | 0xXX | 0xXX | 0xXX |
|
||||
// ACK-ACK | 0xBA | 0xCE | 0x04 | 0x00 | 0x05 | 0x01 | 0xXX | 0xXX | 0x00 | 0x00 | 0xXX | 0xXX | 0xXX | 0xXX |
|
||||
|
||||
while (millis() - startTime < waitMillis) {
|
||||
if (_serial_gps->available()) {
|
||||
buffer[bufferPos++] = _serial_gps->read();
|
||||
|
||||
// keep looking at the first two bytes of buffer until
|
||||
// we have found the CAS frame header (0xBA, 0xCE), if not
|
||||
// keep reading bytes until we find a frame header or we run
|
||||
// out of time.
|
||||
if ((bufferPos == 2) && !(buffer[0] == 0xBA && buffer[1] == 0xCE)) {
|
||||
buffer[0] = buffer[1];
|
||||
buffer[1] = 0;
|
||||
bufferPos = 1;
|
||||
}
|
||||
}
|
||||
|
||||
// we have read all the bytes required for the Ack/Nack (14-bytes)
|
||||
// and we must have found a frame to get this far
|
||||
if (bufferPos == sizeof(buffer) - 1) {
|
||||
uint8_t msg_cls = buffer[4]; // message class should be 0x05
|
||||
uint8_t msg_msg_id = buffer[5]; // message id should be 0x00 or 0x01
|
||||
uint8_t payload_cls = buffer[6]; // payload class id
|
||||
uint8_t payload_msg = buffer[7]; // payload message id
|
||||
|
||||
// Check for an ACK-ACK for the specified class and message id
|
||||
if ((msg_cls == 0x05) && (msg_msg_id == 0x01) && payload_cls == class_id && payload_msg == msg_id) {
|
||||
#ifdef GPS_DEBUG
|
||||
LOG_INFO("Got ACK for class %02X message %02X in %d millis.\n", class_id, msg_id, millis() - startTime);
|
||||
#endif
|
||||
return GNSS_RESPONSE_OK;
|
||||
}
|
||||
|
||||
// Check for an ACK-NACK for the specified class and message id
|
||||
if ((msg_cls == 0x05) && (msg_msg_id == 0x00) && payload_cls == class_id && payload_msg == msg_id) {
|
||||
#ifdef GPS_DEBUG
|
||||
LOG_WARN("Got NACK for class %02X message %02X in %d millis.\n", class_id, msg_id, millis() - startTime);
|
||||
#endif
|
||||
return GNSS_RESPONSE_NAK;
|
||||
}
|
||||
|
||||
// This isn't the frame we are looking for, clear the buffer
|
||||
// and try again until we run out of time.
|
||||
memset(buffer, 0x0, sizeof(buffer));
|
||||
bufferPos = 0;
|
||||
}
|
||||
}
|
||||
return GNSS_RESPONSE_NONE;
|
||||
}
|
||||
|
||||
GPS_RESPONSE GPS::getACK(uint8_t class_id, uint8_t msg_id, uint32_t waitMillis)
|
||||
{
|
||||
uint8_t b;
|
||||
@@ -313,6 +434,33 @@ bool GPS::setup()
|
||||
// Switch to Fitness Mode, for running and walking purpose with low speed (<5 m/s)
|
||||
_serial_gps->write("$PMTK886,1*29\r\n");
|
||||
delay(250);
|
||||
} else if (gnssModel == GNSS_MODEL_ATGM336H) {
|
||||
// Set the intial configuration of the device - these _should_ work for most AT6558 devices
|
||||
msglen = makeCASPacket(0x06, 0x07, sizeof(_message_CAS_CFG_NAVX_CONF), _message_CAS_CFG_NAVX_CONF);
|
||||
_serial_gps->write(UBXscratch, msglen);
|
||||
if (getACKCas(0x06, 0x07, 250) != GNSS_RESPONSE_OK) {
|
||||
LOG_WARN("ATGM336H - Could not set Configuration");
|
||||
}
|
||||
|
||||
// Set the update frequence to 1Hz
|
||||
msglen = makeCASPacket(0x06, 0x04, sizeof(_message_CAS_CFG_RATE_1HZ), _message_CAS_CFG_RATE_1HZ);
|
||||
_serial_gps->write(UBXscratch, msglen);
|
||||
if (getACKCas(0x06, 0x04, 250) != GNSS_RESPONSE_OK) {
|
||||
LOG_WARN("ATGM336H - Could not set Update Frequency");
|
||||
}
|
||||
|
||||
// Set the NEMA output messages
|
||||
// Ask for only RMC and GGA
|
||||
uint8_t fields[] = {CAS_NEMA_RMC, CAS_NEMA_GGA};
|
||||
for (unsigned int i = 0; i < sizeof(fields); i++) {
|
||||
// Construct a CAS-CFG-MSG packet
|
||||
uint8_t cas_cfg_msg_packet[] = {0x4e, fields[i], 0x01, 0x00};
|
||||
msglen = makeCASPacket(0x06, 0x01, sizeof(cas_cfg_msg_packet), cas_cfg_msg_packet);
|
||||
_serial_gps->write(UBXscratch, msglen);
|
||||
if (getACKCas(0x06, 0x01, 250) != GNSS_RESPONSE_OK) {
|
||||
LOG_WARN("ATGM336H - Could not enable NMEA MSG: %d\n", fields[i]);
|
||||
}
|
||||
}
|
||||
} else if (gnssModel == GNSS_MODEL_UC6580) {
|
||||
// The Unicore UC6580 can use a lot of sat systems, enable it to
|
||||
// use GPS L1 & L5 + BDS B1I & B2a + GLONASS L1 + GALILEO E1 & E5a + SBAS
|
||||
@@ -948,10 +1096,18 @@ GnssModel_t GPS::probe(int serialSpeed)
|
||||
uint8_t buffer[768] = {0};
|
||||
delay(100);
|
||||
|
||||
// Close all NMEA sentences , Only valid for L76K MTK platform
|
||||
// Close all NMEA sentences, valid for L76K, ATGM336H (and likely other AT6558 devices)
|
||||
_serial_gps->write("$PCAS03,0,0,0,0,0,0,0,0,0,0,,,0,0*02\r\n");
|
||||
delay(20);
|
||||
|
||||
// Get version information
|
||||
clearBuffer();
|
||||
_serial_gps->write("$PCAS06,1*1A\r\n");
|
||||
if (getACK("$GPTXT,01,01,02,HW=ATGM336H", 500) == GNSS_RESPONSE_OK) {
|
||||
LOG_INFO("ATGM336H GNSS init succeeded, using ATGM336H Module\n");
|
||||
return GNSS_MODEL_ATGM336H;
|
||||
}
|
||||
|
||||
// Get version information
|
||||
clearBuffer();
|
||||
_serial_gps->write("$PCAS06,0*1B\r\n");
|
||||
@@ -1216,6 +1372,11 @@ bool GPS::factoryReset()
|
||||
LOG_INFO("GNSS Factory Reset via PCAS10,3\n");
|
||||
_serial_gps->write("$PCAS10,3*1F\r\n");
|
||||
delay(100);
|
||||
} else if (gnssModel == GNSS_MODEL_ATGM336H) {
|
||||
LOG_INFO("Factory Reset via CAS-CFG-RST\n");
|
||||
uint8_t msglen = makeCASPacket(0x06, 0x02, sizeof(_message_CAS_CFG_RST_FACTORY), _message_CAS_CFG_RST_FACTORY);
|
||||
_serial_gps->write(UBXscratch, msglen);
|
||||
delay(100);
|
||||
} else {
|
||||
// fire this for good measure, if we have an L76B - won't harm other devices.
|
||||
_serial_gps->write("$PMTK104*37\r\n");
|
||||
@@ -1306,7 +1467,7 @@ bool GPS::lookForLocation()
|
||||
#endif // GPS_EXTRAVERBOSE
|
||||
|
||||
// Is this a new point or are we re-reading the previous one?
|
||||
if (!reader.location.isUpdated())
|
||||
if (!reader.location.isUpdated() && !reader.altitude.isUpdated())
|
||||
return false;
|
||||
|
||||
// check if a complete GPS solution set is available for reading
|
||||
@@ -1423,7 +1584,7 @@ bool GPS::hasFlow()
|
||||
|
||||
bool GPS::whileIdle()
|
||||
{
|
||||
int charsInBuf = 0;
|
||||
unsigned int charsInBuf = 0;
|
||||
bool isValid = false;
|
||||
if (!isAwake) {
|
||||
clearBuffer();
|
||||
|
||||
@@ -22,7 +22,14 @@ struct uBloxGnssModelInfo {
|
||||
char extension[10][30];
|
||||
};
|
||||
|
||||
typedef enum { GNSS_MODEL_MTK, GNSS_MODEL_UBLOX, GNSS_MODEL_UC6580, GNSS_MODEL_UNKNOWN, GNSS_MODEL_MTK_L76B } GnssModel_t;
|
||||
typedef enum {
|
||||
GNSS_MODEL_ATGM336H,
|
||||
GNSS_MODEL_MTK,
|
||||
GNSS_MODEL_UBLOX,
|
||||
GNSS_MODEL_UC6580,
|
||||
GNSS_MODEL_UNKNOWN,
|
||||
GNSS_MODEL_MTK_L76B
|
||||
} GnssModel_t;
|
||||
|
||||
typedef enum {
|
||||
GNSS_RESPONSE_NONE,
|
||||
@@ -133,6 +140,11 @@ class GPS : private concurrency::OSThread
|
||||
static const uint8_t _message_VALSET_DISABLE_SBAS_RAM[];
|
||||
static const uint8_t _message_VALSET_DISABLE_SBAS_BBR[];
|
||||
|
||||
// CASIC commands for ATGM336H
|
||||
static const uint8_t _message_CAS_CFG_RST_FACTORY[];
|
||||
static const uint8_t _message_CAS_CFG_NAVX_CONF[];
|
||||
static const uint8_t _message_CAS_CFG_RATE_1HZ[];
|
||||
|
||||
meshtastic_Position p = meshtastic_Position_init_default;
|
||||
|
||||
GPS() : concurrency::OSThread("GPS") {}
|
||||
@@ -174,6 +186,7 @@ class GPS : private concurrency::OSThread
|
||||
|
||||
// Create a ublox packet for editing in memory
|
||||
uint8_t makeUBXPacket(uint8_t class_id, uint8_t msg_id, uint8_t payload_size, const uint8_t *msg);
|
||||
uint8_t makeCASPacket(uint8_t class_id, uint8_t msg_id, uint8_t payload_size, const uint8_t *msg);
|
||||
|
||||
// scratch space for creating ublox packets
|
||||
uint8_t UBXscratch[250] = {0};
|
||||
@@ -184,6 +197,8 @@ class GPS : private concurrency::OSThread
|
||||
GPS_RESPONSE getACK(uint8_t c, uint8_t i, uint32_t waitMillis);
|
||||
GPS_RESPONSE getACK(const char *message, uint32_t waitMillis);
|
||||
|
||||
GPS_RESPONSE getACKCas(uint8_t class_id, uint8_t msg_id, uint32_t waitMillis);
|
||||
|
||||
/**
|
||||
* Switch the GPS into a mode where we are actively looking for a lock, or alternatively switch GPS into a low power mode
|
||||
*
|
||||
@@ -243,6 +258,7 @@ class GPS : private concurrency::OSThread
|
||||
|
||||
// Calculate checksum
|
||||
void UBXChecksum(uint8_t *message, size_t length);
|
||||
void CASChecksum(uint8_t *message, size_t length);
|
||||
|
||||
/** Get how long we should stay looking for each aquisition
|
||||
*/
|
||||
|
||||
@@ -104,13 +104,15 @@ bool perhapsSetRTC(RTCQuality q, const struct timeval *tv)
|
||||
bool shouldSet;
|
||||
if (q > currentQuality) {
|
||||
shouldSet = true;
|
||||
LOG_DEBUG("Upgrading time to quality %d\n", q);
|
||||
} else if (q == RTCQualityGPS && (now - lastSetMsec) > (12 * 60 * 60 * 1000UL)) {
|
||||
// Every 12 hrs we will slam in a new GPS time, to correct for local RTC clock drift
|
||||
LOG_DEBUG("Upgrading time to quality %s\n", RtcName(q));
|
||||
} else if (q >= RTCQualityNTP && (now - lastSetMsec) > (12 * 60 * 60 * 1000UL)) {
|
||||
// Every 12 hrs we will slam in a new GPS or Phone GPS / NTP time, to correct for local RTC clock drift
|
||||
shouldSet = true;
|
||||
LOG_DEBUG("Reapplying external time to correct clock drift %ld secs\n", tv->tv_sec);
|
||||
} else
|
||||
} else {
|
||||
shouldSet = false;
|
||||
LOG_DEBUG("Current RTC quality: %s. Ignoring time of RTC quality of %s\n", RtcName(currentQuality), RtcName(q));
|
||||
}
|
||||
|
||||
if (shouldSet) {
|
||||
currentQuality = q;
|
||||
@@ -162,6 +164,24 @@ bool perhapsSetRTC(RTCQuality q, const struct timeval *tv)
|
||||
}
|
||||
}
|
||||
|
||||
const char *RtcName(RTCQuality quality)
|
||||
{
|
||||
switch (quality) {
|
||||
case RTCQualityNone:
|
||||
return "None";
|
||||
case RTCQualityDevice:
|
||||
return "Device";
|
||||
case RTCQualityFromNet:
|
||||
return "Net";
|
||||
case RTCQualityNTP:
|
||||
return "NTP";
|
||||
case RTCQualityGPS:
|
||||
return "GPS";
|
||||
default:
|
||||
return "Unknown";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the RTC time if the provided time is of higher quality than the current RTC time.
|
||||
*
|
||||
@@ -203,7 +223,7 @@ int32_t getTZOffset()
|
||||
now = time(NULL);
|
||||
gmt = gmtime(&now);
|
||||
gmt->tm_isdst = -1;
|
||||
return (int16_t)difftime(now, mktime(gmt));
|
||||
return (int32_t)difftime(now, mktime(gmt));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -28,6 +28,9 @@ RTCQuality getRTCQuality();
|
||||
bool perhapsSetRTC(RTCQuality q, const struct timeval *tv);
|
||||
bool perhapsSetRTC(RTCQuality q, struct tm &t);
|
||||
|
||||
/// Return a string name for the quality
|
||||
const char *RtcName(RTCQuality quality);
|
||||
|
||||
/// Return time since 1970 in secs. While quality is RTCQualityNone we will be returning time based at zero
|
||||
uint32_t getTime(bool local = false);
|
||||
|
||||
|
||||
63
src/gps/cas.h
Normal file
63
src/gps/cas.h
Normal file
@@ -0,0 +1,63 @@
|
||||
#pragma once
|
||||
|
||||
// CASIC binary message definitions
|
||||
// Reference: https://www.icofchina.com/d/file/xiazai/2020-09-22/20f1b42b3a11ac52089caf3603b43fb5.pdf
|
||||
// ATGM33H-5N: https://www.icofchina.com/pro/mokuai/2016-08-01/4.html
|
||||
// (https://www.icofchina.com/d/file/xiazai/2016-12-05/b5c57074f4b1fcc62ba8c7868548d18a.pdf)
|
||||
|
||||
// NEMA (Class ID - 0x4e) message IDs
|
||||
#define CAS_NEMA_GGA 0x00
|
||||
#define CAS_NEMA_GLL 0x01
|
||||
#define CAS_NEMA_GSA 0x02
|
||||
#define CAS_NEMA_GSV 0x03
|
||||
#define CAS_NEMA_RMC 0x04
|
||||
#define CAS_NEMA_VTG 0x05
|
||||
#define CAS_NEMA_GST 0x07
|
||||
#define CAS_NEMA_ZDA 0x08
|
||||
#define CAS_NEMA_DHV 0x0D
|
||||
|
||||
// Size of a CAS-ACK-(N)ACK message (14 bytes)
|
||||
#define CAS_ACK_NACK_MSG_SIZE 0x0E
|
||||
|
||||
// CFG-RST (0x06, 0x02)
|
||||
// Factory reset
|
||||
const uint8_t GPS::_message_CAS_CFG_RST_FACTORY[] = {
|
||||
0xFF, 0x03, // Fields to clear
|
||||
0x01, // Reset Mode: Controlled Software reset
|
||||
0x03 // Startup Mode: Factory
|
||||
};
|
||||
|
||||
// CFG_RATE (0x06, 0x01)
|
||||
// 1HZ update rate, this should always be the case after
|
||||
// factory reset but update it regardless
|
||||
const uint8_t GPS::_message_CAS_CFG_RATE_1HZ[] = {
|
||||
0xE8, 0x03, // Update Rate: 0x03E8 = 1000ms
|
||||
0x00, 0x00 // Reserved
|
||||
};
|
||||
|
||||
// CFG-NAVX (0x06, 0x07)
|
||||
// Initial ATGM33H-5N configuration, Updates for Dynamic Mode, Fix Mode, and SV system
|
||||
// Qwirk: The ATGM33H-5N-31 should only support GPS+BDS, however it will happily enable
|
||||
// and use GPS+BDS+GLONASS iff the correct CFG_NAVX command is used.
|
||||
const uint8_t GPS::_message_CAS_CFG_NAVX_CONF[] = {
|
||||
0x03, 0x01, 0x00, 0x00, // Update Mask: Dynamic Mode, Fix Mode, Nav Settings
|
||||
0x03, // Dynamic Mode: Automotive
|
||||
0x03, // Fix Mode: Auto 2D/3D
|
||||
0x00, // Min SV
|
||||
0x00, // Max SVs
|
||||
0x00, // Min CNO
|
||||
0x00, // Reserved1
|
||||
0x00, // Init 3D fix
|
||||
0x00, // Min Elevation
|
||||
0x00, // Dr Limit
|
||||
0x07, // Nav System: 2^0 = GPS, 2^1 = BDS 2^2 = GLONASS: 2^3
|
||||
// 3=GPS+BDS, 7=GPS+BDS+GLONASS
|
||||
0x00, 0x00, // Rollover Week
|
||||
0x00, 0x00, 0x00, 0x00, // Fix Altitude
|
||||
0x00, 0x00, 0x00, 0x00, // Fix Height Error
|
||||
0x00, 0x00, 0x00, 0x00, // PDOP Maximum
|
||||
0x00, 0x00, 0x00, 0x00, // TDOP Maximum
|
||||
0x00, 0x00, 0x00, 0x00, // Position Accuracy Max
|
||||
0x00, 0x00, 0x00, 0x00, // Time Accuracy Max
|
||||
0x00, 0x00, 0x00, 0x00 // Static Hold Threshold
|
||||
};
|
||||
@@ -534,6 +534,10 @@ void EInkDynamicDisplay::checkBusyAsyncRefresh()
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Async refresh appears to have stopped, but wasn't caught by onNotify()
|
||||
else
|
||||
pollAsyncRefresh(); // Check (and terminate) the async refresh manually
|
||||
}
|
||||
|
||||
// Hold control while an async refresh runs
|
||||
|
||||
4
src/graphics/NeoPixel.h
Normal file
4
src/graphics/NeoPixel.h
Normal file
@@ -0,0 +1,4 @@
|
||||
#ifdef HAS_NEOPIXEL
|
||||
#include <Adafruit_NeoPixel.h>
|
||||
extern Adafruit_NeoPixel pixels;
|
||||
#endif
|
||||
@@ -94,6 +94,11 @@ std::vector<MeshModule *> moduleFrames;
|
||||
// Stores the last 4 of our hardware ID, to make finding the device for pairing easier
|
||||
static char ourId[5];
|
||||
|
||||
// vector where symbols (string) are displayed in bottom corner of display.
|
||||
std::vector<std::string> functionSymbals;
|
||||
// string displayed in bottom right corner of display. Created from elements in functionSymbals vector
|
||||
std::string functionSymbalString = "";
|
||||
|
||||
#if HAS_GPS
|
||||
// GeoCoord object for the screen
|
||||
GeoCoord geoCoord;
|
||||
@@ -260,6 +265,18 @@ static void drawWelcomeScreen(OLEDDisplay *display, OLEDDisplayUiState *state, i
|
||||
#endif
|
||||
}
|
||||
|
||||
// draw overlay in bottom right corner of screen to show when notifications are muted or modifier key is active
|
||||
static void drawFunctionOverlay(OLEDDisplay *display, OLEDDisplayUiState *state)
|
||||
{
|
||||
// LOG_DEBUG("Drawing function overlay\n");
|
||||
if (functionSymbals.begin() != functionSymbals.end()) {
|
||||
char buf[64];
|
||||
display->setFont(FONT_SMALL);
|
||||
snprintf(buf, sizeof(buf), "%s", functionSymbalString.c_str());
|
||||
display->drawString(SCREEN_WIDTH - display->getStringWidth(buf), SCREEN_HEIGHT - FONT_HEIGHT_SMALL, buf);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef USE_EINK
|
||||
/// Used on eink displays while in deep sleep
|
||||
static void drawDeepSleepScreen(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y)
|
||||
@@ -1023,7 +1040,14 @@ void Screen::handleSetOn(bool on, FrameCallback einkScreensaver)
|
||||
#if !ARCH_PORTDUINO
|
||||
dispdev->displayOn();
|
||||
#endif
|
||||
|
||||
#if defined(ST7789_CS) && \
|
||||
!defined(M5STACK) // set display brightness when turning on screens. Just moved function from TFTDisplay to here.
|
||||
static_cast<TFTDisplay *>(dispdev)->setDisplayBrightness(brightness);
|
||||
#endif
|
||||
|
||||
dispdev->displayOn();
|
||||
|
||||
enabled = true;
|
||||
setInterval(0); // Draw ASAP
|
||||
runASAP = true;
|
||||
@@ -1490,6 +1514,11 @@ void Screen::setFrames()
|
||||
ui->setFrames(normalFrames, numframes);
|
||||
ui->enableAllIndicators();
|
||||
|
||||
// Add function overlay here. This can show when notifications muted, modifier key is active etc
|
||||
static OverlayCallback functionOverlay[] = {drawFunctionOverlay};
|
||||
static const int functionOverlayCount = sizeof(functionOverlay) / sizeof(functionOverlay[0]);
|
||||
ui->setOverlays(functionOverlay, functionOverlayCount);
|
||||
|
||||
prevFrame = -1; // Force drawNodeInfo to pick a new node (because our list
|
||||
// just changed)
|
||||
|
||||
@@ -1573,9 +1602,55 @@ void Screen::blink()
|
||||
delay(50);
|
||||
count = count - 1;
|
||||
}
|
||||
// The dispdev->setBrightness does not work for t-deck display, it seems to run the setBrightness function in OLEDDisplay.
|
||||
dispdev->setBrightness(brightness);
|
||||
}
|
||||
|
||||
void Screen::increaseBrightness()
|
||||
{
|
||||
brightness = ((brightness + 62) > 254) ? brightness : (brightness + 62);
|
||||
|
||||
#if defined(ST7789_CS)
|
||||
// run the setDisplayBrightness function. This works on t-decks
|
||||
static_cast<TFTDisplay *>(dispdev)->setDisplayBrightness(brightness);
|
||||
#endif
|
||||
|
||||
/* TO DO: add little popup in center of screen saying what brightness level it is set to*/
|
||||
}
|
||||
|
||||
void Screen::decreaseBrightness()
|
||||
{
|
||||
brightness = (brightness < 70) ? brightness : (brightness - 62);
|
||||
|
||||
#if defined(ST7789_CS)
|
||||
static_cast<TFTDisplay *>(dispdev)->setDisplayBrightness(brightness);
|
||||
#endif
|
||||
|
||||
/* TO DO: add little popup in center of screen saying what brightness level it is set to*/
|
||||
}
|
||||
|
||||
void Screen::setFunctionSymbal(std::string sym)
|
||||
{
|
||||
if (std::find(functionSymbals.begin(), functionSymbals.end(), sym) == functionSymbals.end()) {
|
||||
functionSymbals.push_back(sym);
|
||||
functionSymbalString = "";
|
||||
for (auto symbol : functionSymbals) {
|
||||
functionSymbalString = symbol + " " + functionSymbalString;
|
||||
}
|
||||
setFastFramerate();
|
||||
}
|
||||
}
|
||||
|
||||
void Screen::removeFunctionSymbal(std::string sym)
|
||||
{
|
||||
functionSymbals.erase(std::remove(functionSymbals.begin(), functionSymbals.end(), sym), functionSymbals.end());
|
||||
functionSymbalString = "";
|
||||
for (auto symbol : functionSymbals) {
|
||||
functionSymbalString = symbol + " " + functionSymbalString;
|
||||
}
|
||||
setFastFramerate();
|
||||
}
|
||||
|
||||
std::string Screen::drawTimeDelta(uint32_t days, uint32_t hours, uint32_t minutes, uint32_t seconds)
|
||||
{
|
||||
std::string uptime;
|
||||
@@ -1998,4 +2073,4 @@ int Screen::handleInputEvent(const InputEvent *event)
|
||||
} // namespace graphics
|
||||
#else
|
||||
graphics::Screen::Screen(ScanI2C::DeviceAddress, meshtastic_Config_DisplayConfig_OledType, OLEDDISPLAY_GEOMETRY) {}
|
||||
#endif // HAS_SCREEN
|
||||
#endif // HAS_SCREEN
|
||||
@@ -166,9 +166,6 @@ class Screen : public concurrency::OSThread
|
||||
void showPrevFrame() { enqueueCmd(ScreenCmd{.cmd = Cmd::SHOW_PREV_FRAME}); }
|
||||
void showNextFrame() { enqueueCmd(ScreenCmd{.cmd = Cmd::SHOW_NEXT_FRAME}); }
|
||||
|
||||
// Implementation to Adjust Brightness
|
||||
uint8_t brightness = BRIGHTNESS_DEFAULT;
|
||||
|
||||
/// Starts showing the Bluetooth PIN screen.
|
||||
//
|
||||
// Switches over to a static frame showing the Bluetooth pairing screen
|
||||
@@ -202,6 +199,13 @@ class Screen : public concurrency::OSThread
|
||||
enqueueCmd(cmd);
|
||||
}
|
||||
|
||||
// functions for display brightness
|
||||
void increaseBrightness();
|
||||
void decreaseBrightness();
|
||||
|
||||
void setFunctionSymbal(std::string sym);
|
||||
void removeFunctionSymbal(std::string sym);
|
||||
|
||||
/// Stops showing the bluetooth PIN screen.
|
||||
void stopBluetoothPinScreen() { enqueueCmd(ScreenCmd{.cmd = Cmd::STOP_BLUETOOTH_PIN_SCREEN}); }
|
||||
|
||||
@@ -395,6 +399,9 @@ class Screen : public concurrency::OSThread
|
||||
// Bluetooth PIN screen)
|
||||
bool showingNormalScreen = false;
|
||||
|
||||
// Implementation to Adjust Brightness
|
||||
uint8_t brightness = BRIGHTNESS_DEFAULT; // H = 254, MH = 192, ML = 130 L = 103
|
||||
|
||||
/// Holds state for debug information
|
||||
DebugInfo debugInfo;
|
||||
|
||||
|
||||
@@ -8,6 +8,12 @@
|
||||
#define TFT_BACKLIGHT_ON HIGH
|
||||
#endif
|
||||
|
||||
#ifdef GPIO_EXTENDER
|
||||
#include <SparkFunSX1509.h>
|
||||
#include <Wire.h>
|
||||
extern SX1509 gpioExtender;
|
||||
#endif
|
||||
|
||||
#ifndef TFT_MESH
|
||||
#define TFT_MESH COLOR565(0x67, 0xEA, 0x94)
|
||||
#endif
|
||||
@@ -356,6 +362,7 @@ class LGFX : public lgfx::LGFX_Device
|
||||
_panel_instance = new lgfx::Panel_ILI9341;
|
||||
auto buscfg = _bus_instance.config();
|
||||
buscfg.spi_mode = 0;
|
||||
buscfg.spi_host = settingsMap[displayspidev];
|
||||
|
||||
buscfg.pin_dc = settingsMap[displayDC]; // Set SPI DC pin number (-1 = disable)
|
||||
|
||||
@@ -381,6 +388,8 @@ class LGFX : public lgfx::LGFX_Device
|
||||
_touch_instance = new lgfx::Touch_XPT2046;
|
||||
} else if (settingsMap[touchscreenModule] == stmpe610) {
|
||||
_touch_instance = new lgfx::Touch_STMPE610;
|
||||
} else if (settingsMap[touchscreenModule] == ft5x06) {
|
||||
_touch_instance = new lgfx::Touch_FT5x06;
|
||||
}
|
||||
auto touch_cfg = _touch_instance->config();
|
||||
|
||||
@@ -392,6 +401,11 @@ class LGFX : public lgfx::LGFX_Device
|
||||
touch_cfg.pin_int = settingsMap[touchscreenIRQ];
|
||||
touch_cfg.bus_shared = true;
|
||||
touch_cfg.offset_rotation = 1;
|
||||
if (settingsMap[touchscreenI2CAddr] != -1) {
|
||||
touch_cfg.i2c_addr = settingsMap[touchscreenI2CAddr];
|
||||
} else {
|
||||
touch_cfg.spi_host = settingsMap[touchscreenspidev];
|
||||
}
|
||||
|
||||
_touch_instance->config(touch_cfg);
|
||||
_panel_instance->setTouch(_touch_instance);
|
||||
@@ -411,8 +425,7 @@ class LGFX : public lgfx::LGFX_Device
|
||||
lgfx::Panel_HX8357D _panel_instance;
|
||||
lgfx::Bus_SPI _bus_instance;
|
||||
#if defined(USE_XPT2046)
|
||||
lgfx::ITouch *_touch_instance;
|
||||
// lgfx::Touch_XPT2046 _touch_instance;
|
||||
lgfx::Touch_XPT2046 _touch_instance;
|
||||
#endif
|
||||
|
||||
public:
|
||||
@@ -466,8 +479,7 @@ class LGFX : public lgfx::LGFX_Device
|
||||
#if defined(USE_XPT2046)
|
||||
{
|
||||
// Configure settings for touch control.
|
||||
_touch_instance = new lgfx::Touch_XPT2046;
|
||||
auto touch_cfg = _touch_instance->config();
|
||||
auto touch_cfg = _touch_instance.config();
|
||||
|
||||
touch_cfg.pin_cs = TOUCH_CS;
|
||||
touch_cfg.x_min = 0;
|
||||
@@ -478,8 +490,8 @@ class LGFX : public lgfx::LGFX_Device
|
||||
touch_cfg.bus_shared = true;
|
||||
touch_cfg.offset_rotation = 1;
|
||||
|
||||
_touch_instance->config(touch_cfg);
|
||||
//_panel_instance->setTouch(_touch_instance);
|
||||
_touch_instance.config(touch_cfg);
|
||||
_panel_instance.setTouch(&_touch_instance);
|
||||
}
|
||||
#endif
|
||||
setPanel(&_panel_instance);
|
||||
@@ -496,6 +508,11 @@ static LGFX *tft = nullptr;
|
||||
#include "TFTDisplay.h"
|
||||
#include <SPI.h>
|
||||
|
||||
#ifdef UNPHONE
|
||||
#include "unPhone.h"
|
||||
extern unPhone unphone;
|
||||
#endif
|
||||
|
||||
TFTDisplay::TFTDisplay(uint8_t address, int sda, int scl, OLEDDISPLAY_GEOMETRY geometry, HW_I2C i2cBus)
|
||||
{
|
||||
LOG_DEBUG("TFTDisplay!\n");
|
||||
@@ -576,14 +593,10 @@ void TFTDisplay::sendCommand(uint8_t com)
|
||||
digitalWrite(VTFT_CTRL, LOW);
|
||||
#endif
|
||||
#ifdef UNPHONE
|
||||
Wire.beginTransmission(0x26);
|
||||
Wire.write(0x02);
|
||||
Wire.write(0x04); // Backlight on
|
||||
Wire.write(0x22); // G&B LEDs off
|
||||
Wire.endTransmission();
|
||||
unphone.backlight(true); // using unPhone library
|
||||
#endif
|
||||
#ifdef RAK14014
|
||||
#elif !defined(M5STACK)
|
||||
#elif !defined(M5STACK) && !defined(ST7789_CS) // T-Deck gets brightness set in Screen.cpp in the handleSetOn function
|
||||
tft->setBrightness(172);
|
||||
#endif
|
||||
break;
|
||||
@@ -612,11 +625,7 @@ void TFTDisplay::sendCommand(uint8_t com)
|
||||
digitalWrite(VTFT_CTRL, HIGH);
|
||||
#endif
|
||||
#ifdef UNPHONE
|
||||
Wire.beginTransmission(0x26);
|
||||
Wire.write(0x02);
|
||||
Wire.write(0x00); // Backlight off
|
||||
Wire.write(0x22); // G&B LEDs off
|
||||
Wire.endTransmission();
|
||||
unphone.backlight(false); // using unPhone library
|
||||
#endif
|
||||
#ifdef RAK14014
|
||||
#elif !defined(M5STACK)
|
||||
@@ -631,6 +640,12 @@ void TFTDisplay::sendCommand(uint8_t com)
|
||||
// Drop all other commands to device (we just update the buffer)
|
||||
}
|
||||
|
||||
void TFTDisplay::setDisplayBrightness(uint8_t _brightness)
|
||||
{
|
||||
tft->setBrightness(_brightness);
|
||||
LOG_DEBUG("Brightness is set to value: %i \n", _brightness);
|
||||
}
|
||||
|
||||
void TFTDisplay::flipScreenVertically()
|
||||
{
|
||||
#if defined(T_WATCH_S3)
|
||||
@@ -690,11 +705,7 @@ bool TFTDisplay::connect()
|
||||
digitalWrite(ST7735_BL_V05, TFT_BACKLIGHT_ON);
|
||||
#endif
|
||||
#ifdef UNPHONE
|
||||
Wire.beginTransmission(0x26);
|
||||
Wire.write(0x02);
|
||||
Wire.write(0x04); // Backlight on
|
||||
Wire.write(0x22); // G&B LEDs off
|
||||
Wire.endTransmission();
|
||||
unphone.backlight(true); // using unPhone library
|
||||
LOG_INFO("Power to TFT Backlight\n");
|
||||
#endif
|
||||
|
||||
@@ -718,4 +729,4 @@ bool TFTDisplay::connect()
|
||||
return true;
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif
|
||||
@@ -30,6 +30,9 @@ class TFTDisplay : public OLEDDisplay
|
||||
static bool hasTouch(void);
|
||||
static bool getTouch(int16_t *x, int16_t *y);
|
||||
|
||||
// Functions for changing display brightness
|
||||
void setDisplayBrightness(uint8_t);
|
||||
|
||||
/**
|
||||
* shim to make the abstraction happy
|
||||
*
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
#include "InputBroker.h"
|
||||
#include "concurrency/OSThread.h"
|
||||
#include "mesh/NodeDB.h"
|
||||
#include "time.h"
|
||||
|
||||
typedef struct _TouchEvent {
|
||||
const char *source;
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
#include "configuration.h"
|
||||
#include "modules/ExternalNotificationModule.h"
|
||||
|
||||
#ifdef ARCH_PORTDUINO
|
||||
#if ARCH_PORTDUINO
|
||||
#include "platform/portduino/PortduinoGlue.h"
|
||||
#endif
|
||||
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
#include "kbI2cBase.h"
|
||||
|
||||
#include "configuration.h"
|
||||
#include "detect/ScanI2C.h"
|
||||
|
||||
@@ -138,6 +137,9 @@ int32_t KbI2cBase::runOnce()
|
||||
break;
|
||||
case 0x13: // Code scanner says the SYM key is 0x13
|
||||
is_sym = !is_sym;
|
||||
e.inputEvent = ANYKEY;
|
||||
e.kbchar =
|
||||
is_sym ? 0xf1 : 0xf2; // send 0xf1 to tell CannedMessages to display that the modifier key is active
|
||||
break;
|
||||
case 0x0a: // apparently Enter on Q10 is a line feed instead of carriage return
|
||||
e.inputEvent = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_SELECT;
|
||||
@@ -193,6 +195,75 @@ int32_t KbI2cBase::runOnce()
|
||||
e.inputEvent = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_NONE;
|
||||
e.source = this->_originName;
|
||||
switch (c) {
|
||||
case 0x71: // This is the button q. If modifier and q pressed, it cancels the input
|
||||
if (is_sym) {
|
||||
is_sym = false;
|
||||
e.inputEvent = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_CANCEL;
|
||||
} else {
|
||||
e.inputEvent = ANYKEY;
|
||||
e.kbchar = c;
|
||||
}
|
||||
break;
|
||||
case 0x74: // letter t. if modifier and t pressed call 'tab'
|
||||
if (is_sym) {
|
||||
is_sym = false;
|
||||
e.inputEvent = ANYKEY;
|
||||
e.kbchar = 0x09; // TAB Scancode
|
||||
} else {
|
||||
e.inputEvent = ANYKEY;
|
||||
e.kbchar = c;
|
||||
}
|
||||
break;
|
||||
case 0x6d: // letter m. Modifier makes it mute notifications
|
||||
if (is_sym) {
|
||||
is_sym = false;
|
||||
e.inputEvent = ANYKEY;
|
||||
e.kbchar = 0xac; // mute notifications
|
||||
} else {
|
||||
e.inputEvent = ANYKEY;
|
||||
e.kbchar = c;
|
||||
}
|
||||
break;
|
||||
case 0x6f: // letter o(+). Modifier makes screen increase in brightness
|
||||
if (is_sym) {
|
||||
is_sym = false;
|
||||
e.inputEvent = ANYKEY;
|
||||
e.kbchar = 0x11; // Increase Brightness code
|
||||
} else {
|
||||
e.inputEvent = ANYKEY;
|
||||
e.kbchar = c;
|
||||
}
|
||||
break;
|
||||
case 0x69: // letter i(-). Modifier makes screen decrease in brightness
|
||||
if (is_sym) {
|
||||
is_sym = false;
|
||||
e.inputEvent = ANYKEY;
|
||||
e.kbchar = 0x12; // Decrease Brightness code
|
||||
} else {
|
||||
e.inputEvent = ANYKEY;
|
||||
e.kbchar = c;
|
||||
}
|
||||
break;
|
||||
case 0x20: // Space. Send network ping like double press does
|
||||
if (is_sym) {
|
||||
is_sym = false;
|
||||
e.inputEvent = ANYKEY;
|
||||
e.kbchar = 0xaf; // (fn + space)
|
||||
} else {
|
||||
e.inputEvent = ANYKEY;
|
||||
e.kbchar = c;
|
||||
}
|
||||
break;
|
||||
case 0x67: // letter g. toggle gps
|
||||
if (is_sym) {
|
||||
is_sym = false;
|
||||
e.inputEvent = ANYKEY;
|
||||
e.kbchar = 0x9e;
|
||||
} else {
|
||||
e.inputEvent = ANYKEY;
|
||||
e.kbchar = c;
|
||||
}
|
||||
break;
|
||||
case 0x1b: // ESC
|
||||
e.inputEvent = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_CANCEL;
|
||||
break;
|
||||
@@ -216,6 +287,12 @@ int32_t KbI2cBase::runOnce()
|
||||
e.inputEvent = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_RIGHT;
|
||||
e.kbchar = 0xb7;
|
||||
break;
|
||||
case 0xc: // Modifier key: 0xc is alt+c (Other options could be: 0xea = shift+mic button or 0x4 shift+$(speaker))
|
||||
// toggle moddifiers button.
|
||||
is_sym = !is_sym;
|
||||
e.inputEvent = ANYKEY;
|
||||
e.kbchar = is_sym ? 0xf1 : 0xf2; // send 0xf1 to tell CannedMessages to display that the modifier key is active
|
||||
break;
|
||||
case 0x90: // fn+r
|
||||
case 0x91: // fn+t
|
||||
case 0x9b: // fn+s
|
||||
@@ -239,6 +316,7 @@ int32_t KbI2cBase::runOnce()
|
||||
}
|
||||
e.inputEvent = ANYKEY;
|
||||
e.kbchar = c;
|
||||
is_sym = false;
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
66
src/main.cpp
66
src/main.cpp
@@ -179,6 +179,11 @@ const char *getDeviceName()
|
||||
|
||||
static int32_t ledBlinker()
|
||||
{
|
||||
// Still set up the blinking (heartbeat) interval but skip code path below, so LED will blink if
|
||||
// config.device.led_heartbeat_disabled is changed
|
||||
if (config.device.led_heartbeat_disabled)
|
||||
return 1000;
|
||||
|
||||
static bool ledOn;
|
||||
ledOn ^= 1;
|
||||
|
||||
@@ -192,7 +197,9 @@ uint32_t timeLastPowered = 0;
|
||||
|
||||
static Periodic *ledPeriodic;
|
||||
static OSThread *powerFSMthread;
|
||||
#if !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR
|
||||
static OSThread *accelerometerThread;
|
||||
#endif
|
||||
static OSThread *ambientLightingThread;
|
||||
SPISettings spiSettings(4000000, MSBFIRST, SPI_MODE0);
|
||||
|
||||
@@ -337,7 +344,7 @@ void setup()
|
||||
Wire.begin(I2C_SDA, I2C_SCL);
|
||||
#elif defined(ARCH_PORTDUINO)
|
||||
if (settingsStrings[i2cdev] != "") {
|
||||
LOG_INFO("Using %s as I2C device.\n", settingsStrings[i2cdev]);
|
||||
LOG_INFO("Using %s as I2C device.\n", settingsStrings[i2cdev].c_str());
|
||||
Wire.begin(settingsStrings[i2cdev].c_str());
|
||||
} else {
|
||||
LOG_INFO("No I2C device configured, skipping.\n");
|
||||
@@ -533,6 +540,8 @@ void setup()
|
||||
SCANNER_TO_SENSORS_MAP(ScanI2C::DeviceType::QMI8658, meshtastic_TelemetrySensorType_QMI8658)
|
||||
SCANNER_TO_SENSORS_MAP(ScanI2C::DeviceType::QMC5883L, meshtastic_TelemetrySensorType_QMC5883L)
|
||||
SCANNER_TO_SENSORS_MAP(ScanI2C::DeviceType::PMSA0031, meshtastic_TelemetrySensorType_PMSA003I)
|
||||
SCANNER_TO_SENSORS_MAP(ScanI2C::DeviceType::RCWL9620, meshtastic_TelemetrySensorType_RCWL9620)
|
||||
SCANNER_TO_SENSORS_MAP(ScanI2C::DeviceType::SHT4X, meshtastic_TelemetrySensorType_SHT4X)
|
||||
|
||||
i2cScanner.reset();
|
||||
|
||||
@@ -590,20 +599,6 @@ void setup()
|
||||
if (config.display.oled != meshtastic_Config_DisplayConfig_OledType_OLED_AUTO)
|
||||
screen_model = config.display.oled;
|
||||
|
||||
#ifdef UNPHONE
|
||||
// initialise IO expander with pinmodes
|
||||
Wire.beginTransmission(0x26);
|
||||
Wire.write(0x06);
|
||||
Wire.write(0x7A);
|
||||
Wire.write(0xDD);
|
||||
Wire.endTransmission();
|
||||
Wire.beginTransmission(0x26);
|
||||
Wire.write(0x02);
|
||||
Wire.write(0x04); // Backlight on
|
||||
Wire.write(0x22); // G&B LEDs off
|
||||
Wire.endTransmission();
|
||||
#endif
|
||||
|
||||
#if defined(USE_SH1107)
|
||||
screen_model = meshtastic_Config_DisplayConfig_OledType_OLED_SH1107; // set dimension of 128x128
|
||||
display_geometry = GEOMETRY_128_128;
|
||||
@@ -613,7 +608,7 @@ void setup()
|
||||
screen_model = meshtastic_Config_DisplayConfig_OledType_OLED_SH1107; // keep dimension of 128x64
|
||||
#endif
|
||||
|
||||
#if !defined(ARCH_PORTDUINO) && !defined(ARCH_STM32WL)
|
||||
#if !defined(ARCH_PORTDUINO) && !defined(ARCH_STM32WL) && !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR
|
||||
if (acc_info.type != ScanI2C::DeviceType::NONE) {
|
||||
config.display.wake_on_tap_or_motion = true;
|
||||
moduleConfig.external_notification.enabled = true;
|
||||
@@ -621,7 +616,9 @@ void setup()
|
||||
}
|
||||
#endif
|
||||
|
||||
#if !defined(ARCH_PORTDUINO) && !defined(ARCH_STM32WL)
|
||||
#if defined(HAS_NEOPIXEL) || defined(UNPHONE) || defined(RGBLED_RED)
|
||||
ambientLightingThread = new AmbientLightingThread(ScanI2C::DeviceType::NONE);
|
||||
#elif !defined(ARCH_PORTDUINO) && !defined(ARCH_STM32WL)
|
||||
if (rgb_found.type != ScanI2C::DeviceType::NONE) {
|
||||
ambientLightingThread = new AmbientLightingThread(rgb_found.type);
|
||||
}
|
||||
@@ -644,14 +641,12 @@ void setup()
|
||||
pinMode(LORA_CS, OUTPUT);
|
||||
digitalWrite(LORA_CS, HIGH);
|
||||
SPI1.begin(false);
|
||||
#else // HW_SPI1_DEVICE
|
||||
#else // HW_SPI1_DEVICE
|
||||
SPI.setSCK(LORA_SCK);
|
||||
SPI.setTX(LORA_MOSI);
|
||||
SPI.setRX(LORA_MISO);
|
||||
SPI.begin(false);
|
||||
#endif // HW_SPI1_DEVICE
|
||||
#elif ARCH_PORTDUINO
|
||||
SPI.begin(settingsStrings[spidev].c_str());
|
||||
#endif // HW_SPI1_DEVICE
|
||||
#elif !defined(ARCH_ESP32) // ARCH_RP2040
|
||||
SPI.begin();
|
||||
#else
|
||||
@@ -702,6 +697,12 @@ void setup()
|
||||
// Now that the mesh service is created, create any modules
|
||||
setupModules();
|
||||
|
||||
#ifdef LED_PIN
|
||||
// Turn LED off after boot, if heartbeat by config
|
||||
if (config.device.led_heartbeat_disabled)
|
||||
digitalWrite(LED_PIN, LOW ^ LED_INVERTED);
|
||||
#endif
|
||||
|
||||
// Do this after service.init (because that clears error_code)
|
||||
#ifdef HAS_PMU
|
||||
if (!pmu_found)
|
||||
@@ -738,7 +739,8 @@ void setup()
|
||||
if (settingsMap[use_sx1262]) {
|
||||
if (!rIf) {
|
||||
LOG_DEBUG("Attempting to activate sx1262 radio on SPI port %s\n", settingsStrings[spidev].c_str());
|
||||
LockingArduinoHal *RadioLibHAL = new LockingArduinoHal(SPI, spiSettings);
|
||||
LockingArduinoHal *RadioLibHAL =
|
||||
new LockingArduinoHal(SPI, spiSettings, (settingsMap[ch341Quirk] ? settingsMap[busy] : RADIOLIB_NC));
|
||||
rIf = new SX1262Interface((LockingArduinoHal *)RadioLibHAL, settingsMap[cs], settingsMap[irq], settingsMap[reset],
|
||||
settingsMap[busy]);
|
||||
if (!rIf->init()) {
|
||||
@@ -752,7 +754,8 @@ void setup()
|
||||
} else if (settingsMap[use_rf95]) {
|
||||
if (!rIf) {
|
||||
LOG_DEBUG("Attempting to activate rf95 radio on SPI port %s\n", settingsStrings[spidev].c_str());
|
||||
LockingArduinoHal *RadioLibHAL = new LockingArduinoHal(SPI, spiSettings);
|
||||
LockingArduinoHal *RadioLibHAL =
|
||||
new LockingArduinoHal(SPI, spiSettings, (settingsMap[ch341Quirk] ? settingsMap[busy] : RADIOLIB_NC));
|
||||
rIf = new RF95Interface((LockingArduinoHal *)RadioLibHAL, settingsMap[cs], settingsMap[irq], settingsMap[reset],
|
||||
settingsMap[busy]);
|
||||
if (!rIf->init()) {
|
||||
@@ -779,6 +782,21 @@ void setup()
|
||||
LOG_INFO("SX1280 Radio init succeeded, using SX1280 radio\n");
|
||||
}
|
||||
}
|
||||
} else if (settingsMap[use_sx1268]) {
|
||||
if (!rIf) {
|
||||
LOG_DEBUG("Attempting to activate sx1268 radio on SPI port %s\n", settingsStrings[spidev].c_str());
|
||||
LockingArduinoHal *RadioLibHAL = new LockingArduinoHal(SPI, spiSettings);
|
||||
rIf = new SX1268Interface((LockingArduinoHal *)RadioLibHAL, settingsMap[cs], settingsMap[irq], settingsMap[reset],
|
||||
settingsMap[busy]);
|
||||
if (!rIf->init()) {
|
||||
LOG_ERROR("Failed to find SX1268 radio\n");
|
||||
delete rIf;
|
||||
rIf = NULL;
|
||||
exit(EXIT_FAILURE);
|
||||
} else {
|
||||
LOG_INFO("SX1268 Radio init succeeded, using SX1268 radio\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#elif defined(HW_SPI1_DEVICE)
|
||||
@@ -1017,4 +1035,4 @@ void loop()
|
||||
mainDelay.delay(delayMsec);
|
||||
}
|
||||
// if (didWake) LOG_DEBUG("wake!\n");
|
||||
}
|
||||
}
|
||||
@@ -22,6 +22,11 @@ extern NimbleBluetooth *nimbleBluetooth;
|
||||
extern NRF52Bluetooth *nrf52Bluetooth;
|
||||
#endif
|
||||
|
||||
#if ARCH_PORTDUINO
|
||||
extern HardwareSPI *DisplaySPI;
|
||||
extern HardwareSPI *LoraSPI;
|
||||
|
||||
#endif
|
||||
extern ScanI2C::DeviceAddress screen_found;
|
||||
extern ScanI2C::DeviceAddress cardkb_found;
|
||||
extern uint8_t kb_model;
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
#include <NodeDB.h>
|
||||
#include <cstdint>
|
||||
#define ONE_DAY 24 * 60 * 60
|
||||
#define ONE_MINUTE_MS 60 * 1000
|
||||
|
||||
#define default_gps_update_interval IF_ROUTER(ONE_DAY, 2 * 60)
|
||||
#define default_broadcast_interval_secs IF_ROUTER(ONE_DAY / 2, 15 * 60)
|
||||
@@ -27,4 +28,4 @@ class Default
|
||||
static uint32_t getConfiguredOrDefaultMs(uint32_t configuredInterval);
|
||||
static uint32_t getConfiguredOrDefaultMs(uint32_t configuredInterval, uint32_t defaultInterval);
|
||||
static uint32_t getConfiguredOrDefault(uint32_t configured, uint32_t defaultValue);
|
||||
};
|
||||
};
|
||||
@@ -35,11 +35,10 @@ bool FloodingRouter::shouldFilterReceived(const meshtastic_MeshPacket *p)
|
||||
|
||||
void FloodingRouter::sniffReceived(const meshtastic_MeshPacket *p, const meshtastic_Routing *c)
|
||||
{
|
||||
bool isAck =
|
||||
((c && c->error_reason == meshtastic_Routing_Error_NONE)); // consider only ROUTING_APP message without error as ACK
|
||||
if (isAck && p->to != getNodeNum()) {
|
||||
// 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");
|
||||
bool isAckorReply = (p->which_payload_variant == meshtastic_MeshPacket_decoded_tag) && (p->decoded.request_id != 0);
|
||||
if (isAckorReply && p->to != getNodeNum() && p->to != NODENUM_BROADCAST) {
|
||||
// do not flood direct message that is ACKed or replied to
|
||||
LOG_DEBUG("Receiving an ACK or reply not for me, but don't need to rebroadcast this direct message anymore.\n");
|
||||
Router::cancelSending(p->to, p->decoded.request_id); // cancel rebroadcast for this DM
|
||||
}
|
||||
if ((p->to != getNodeNum()) && (p->hop_limit > 0) && (getFrom(p) != getNodeNum())) {
|
||||
|
||||
@@ -12,7 +12,7 @@ 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
|
||||
* the RoutingPlugin to avoid sending redundant acks
|
||||
* the RoutingModule to avoid sending redundant acks
|
||||
*/
|
||||
meshtastic_MeshPacket *MeshModule::currentReply;
|
||||
|
||||
@@ -40,7 +40,7 @@ meshtastic_MeshPacket *MeshModule::allocAckNak(meshtastic_Routing_Error err, Nod
|
||||
c.error_reason = err;
|
||||
c.which_variant = meshtastic_Routing_error_reason_tag;
|
||||
|
||||
// Now that we have moded sendAckNak up one level into the class hierarchy we can no longer assume we are a RoutingPlugin
|
||||
// Now that we have moded sendAckNak up one level into the class hierarchy we can no longer assume we are a RoutingModule
|
||||
// So we manually call pb_encode_to_bytes and specify routing port number
|
||||
// auto p = allocDataProtobuf(c);
|
||||
meshtastic_MeshPacket *p = router->allocForSending();
|
||||
@@ -54,7 +54,8 @@ meshtastic_MeshPacket *MeshModule::allocAckNak(meshtastic_Routing_Error err, Nod
|
||||
p->to = to;
|
||||
p->decoded.request_id = idFrom;
|
||||
p->channel = chIndex;
|
||||
LOG_ERROR("Alloc an err=%d,to=0x%x,idFrom=0x%x,id=0x%x\n", err, to, idFrom, p->id);
|
||||
if (err != meshtastic_Routing_Error_NONE)
|
||||
LOG_ERROR("Alloc an err=%d,to=0x%x,idFrom=0x%x,id=0x%x\n", err, to, idFrom, p->id);
|
||||
|
||||
return p;
|
||||
}
|
||||
@@ -68,7 +69,7 @@ meshtastic_MeshPacket *MeshModule::allocErrorResponse(meshtastic_Routing_Error e
|
||||
return r;
|
||||
}
|
||||
|
||||
void MeshModule::callPlugins(meshtastic_MeshPacket &mp, RxSource src)
|
||||
void MeshModule::callModules(meshtastic_MeshPacket &mp, RxSource src)
|
||||
{
|
||||
// LOG_DEBUG("In call modules\n");
|
||||
bool moduleFound = false;
|
||||
@@ -258,7 +259,7 @@ void MeshModule::observeUIEvents(Observer<const UIFrameEvent *> *observer)
|
||||
}
|
||||
}
|
||||
|
||||
AdminMessageHandleResult MeshModule::handleAdminMessageForAllPlugins(const meshtastic_MeshPacket &mp,
|
||||
AdminMessageHandleResult MeshModule::handleAdminMessageForAllModules(const meshtastic_MeshPacket &mp,
|
||||
meshtastic_AdminMessage *request,
|
||||
meshtastic_AdminMessage *response)
|
||||
{
|
||||
|
||||
@@ -64,11 +64,11 @@ class MeshModule
|
||||
|
||||
/** For use only by MeshService
|
||||
*/
|
||||
static void callPlugins(meshtastic_MeshPacket &mp, RxSource src = RX_SRC_RADIO);
|
||||
static void callModules(meshtastic_MeshPacket &mp, RxSource src = RX_SRC_RADIO);
|
||||
|
||||
static std::vector<MeshModule *> GetMeshModulesWithUIFrames();
|
||||
static void observeUIEvents(Observer<const UIFrameEvent *> *observer);
|
||||
static AdminMessageHandleResult handleAdminMessageForAllPlugins(const meshtastic_MeshPacket &mp,
|
||||
static AdminMessageHandleResult handleAdminMessageForAllModules(const meshtastic_MeshPacket &mp,
|
||||
meshtastic_AdminMessage *request,
|
||||
meshtastic_AdminMessage *response);
|
||||
#if HAS_SCREEN
|
||||
@@ -195,4 +195,4 @@ class MeshModule
|
||||
/** 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.
|
||||
*/
|
||||
void setReplyTo(meshtastic_MeshPacket *p, const meshtastic_MeshPacket &to);
|
||||
void setReplyTo(meshtastic_MeshPacket *p, const meshtastic_MeshPacket &to);
|
||||
@@ -192,12 +192,7 @@ void MeshService::handleToRadio(meshtastic_MeshPacket &p)
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
if (p.from != 0) { // We don't let phones assign nodenums to their sent messages
|
||||
LOG_WARN("phone tried to pick a nodenum, we don't allow that.\n");
|
||||
p.from = 0;
|
||||
} else {
|
||||
// p.from = nodeDB->getNodeNum();
|
||||
}
|
||||
p.from = 0; // We don't let phones assign nodenums to their sent messages
|
||||
|
||||
if (p.id == 0)
|
||||
p.id = generatePacketId(); // If the phone didn't supply one, then pick one
|
||||
@@ -262,12 +257,12 @@ void MeshService::sendToMesh(meshtastic_MeshPacket *p, RxSource src, bool ccToPh
|
||||
LOG_DEBUG("Can't send status to phone");
|
||||
}
|
||||
|
||||
if (ccToPhone) {
|
||||
if (res == ERRNO_OK && ccToPhone) { // Check if p is not released in case it couldn't be sent
|
||||
sendToPhone(packetPool.allocCopy(*p));
|
||||
}
|
||||
}
|
||||
|
||||
void MeshService::sendNetworkPing(NodeNum dest, bool wantReplies)
|
||||
bool MeshService::trySendPosition(NodeNum dest, bool wantReplies)
|
||||
{
|
||||
meshtastic_NodeInfoLite *node = nodeDB->getMeshNode(nodeDB->getNodeNum());
|
||||
|
||||
@@ -278,6 +273,7 @@ void MeshService::sendNetworkPing(NodeNum dest, bool wantReplies)
|
||||
if (positionModule) {
|
||||
LOG_INFO("Sending position ping to 0x%x, wantReplies=%d, channel=%d\n", dest, wantReplies, node->channel);
|
||||
positionModule->sendOurPosition(dest, wantReplies, node->channel);
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
#endif
|
||||
@@ -286,6 +282,7 @@ void MeshService::sendNetworkPing(NodeNum dest, bool wantReplies)
|
||||
nodeInfoModule->sendOurNodeInfo(dest, wantReplies, node->channel);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void MeshService::sendToPhone(meshtastic_MeshPacket *p)
|
||||
|
||||
@@ -108,8 +108,9 @@ class MeshService
|
||||
void reloadOwner(bool shouldSave = true);
|
||||
|
||||
/// Called when the user wakes up our GUI, normally sends our latest location to the mesh (if we have it), otherwise at least
|
||||
/// sends our owner
|
||||
void sendNetworkPing(NodeNum dest, bool wantReplies = false);
|
||||
/// sends our nodeinfo
|
||||
/// returns true if we sent a position
|
||||
bool trySendPosition(NodeNum dest, bool wantReplies = false);
|
||||
|
||||
/// 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
|
||||
|
||||
@@ -56,7 +56,7 @@ meshtastic_OEMStore oemStore;
|
||||
bool meshtastic_DeviceState_callback(pb_istream_t *istream, pb_ostream_t *ostream, const pb_field_iter_t *field)
|
||||
{
|
||||
if (ostream) {
|
||||
std::vector<meshtastic_NodeInfoLite> *vec = (std::vector<meshtastic_NodeInfoLite> *)field->pData;
|
||||
std::vector<meshtastic_NodeInfoLite> const *vec = (std::vector<meshtastic_NodeInfoLite> *)field->pData;
|
||||
for (auto item : *vec) {
|
||||
if (!pb_encode_tag_for_field(ostream, field))
|
||||
return false;
|
||||
@@ -269,7 +269,7 @@ void NodeDB::installDefaultConfig()
|
||||
config.device.node_info_broadcast_secs = default_node_info_broadcast_secs;
|
||||
config.device.serial_enabled = true;
|
||||
resetRadioConfig();
|
||||
strncpy(config.network.ntp_server, "0.pool.ntp.org", 32);
|
||||
strncpy(config.network.ntp_server, "meshtastic.pool.ntp.org", 32);
|
||||
// FIXME: Default to bluetooth capability of platform as default
|
||||
config.bluetooth.enabled = true;
|
||||
config.bluetooth.fixed_pin = defaultBLEPin;
|
||||
@@ -352,9 +352,6 @@ void NodeDB::installDefaultModuleConfig()
|
||||
moduleConfig.external_notification.alert_message = true;
|
||||
moduleConfig.external_notification.output_ms = 100;
|
||||
moduleConfig.external_notification.active = true;
|
||||
#endif
|
||||
#ifdef TTGO_T_ECHO
|
||||
config.display.wake_on_tap_or_motion = true; // Enable touch button for screen-on / refresh
|
||||
#endif
|
||||
moduleConfig.has_canned_message = true;
|
||||
|
||||
@@ -452,7 +449,7 @@ void NodeDB::resetNodes()
|
||||
neighborInfoModule->resetNeighbors();
|
||||
}
|
||||
|
||||
void NodeDB::removeNodeByNum(uint nodeNum)
|
||||
void NodeDB::removeNodeByNum(NodeNum nodeNum)
|
||||
{
|
||||
int newPos = 0, removed = 0;
|
||||
for (int i = 0; i < numMeshNodes; i++) {
|
||||
@@ -527,8 +524,8 @@ void NodeDB::installDefaultDeviceState()
|
||||
void NodeDB::pickNewNodeNum()
|
||||
{
|
||||
NodeNum nodeNum = myNodeInfo.my_node_num;
|
||||
getMacAddr(ourMacAddr); // Make sure ourMacAddr is set
|
||||
if (nodeNum == 0) {
|
||||
getMacAddr(ourMacAddr); // Make sure ourMacAddr is set
|
||||
// Pick an initial nodenum based on the macaddr
|
||||
nodeNum = (ourMacAddr[2] << 24) | (ourMacAddr[3] << 16) | (ourMacAddr[4] << 8) | ourMacAddr[5];
|
||||
}
|
||||
@@ -813,6 +810,7 @@ size_t NodeDB::getNumOnlineMeshNodes(bool localOnly)
|
||||
}
|
||||
|
||||
#include "MeshModule.h"
|
||||
#include "Throttle.h"
|
||||
|
||||
/** Update position info for this node based on received position data
|
||||
*/
|
||||
@@ -907,8 +905,10 @@ bool NodeDB::updateUser(uint32_t nodeId, const meshtastic_User &p, uint8_t chann
|
||||
powerFSM.trigger(EVENT_NODEDB_UPDATED);
|
||||
notifyObservers(true); // Force an update whether or not our node counts have changed
|
||||
|
||||
// We just changed something important about the user, store our DB
|
||||
saveToDisk(SEGMENT_DEVICESTATE);
|
||||
// We just changed something about the user, store our DB
|
||||
Throttle::execute(
|
||||
&lastNodeDbSave, ONE_MINUTE_MS, []() { nodeDB->saveToDisk(SEGMENT_DEVICESTATE); },
|
||||
[]() { LOG_DEBUG("Deferring NodeDB saveToDisk for now, since we saved less than a minute ago\n"); });
|
||||
}
|
||||
|
||||
return changed;
|
||||
|
||||
@@ -124,7 +124,7 @@ class NodeDB
|
||||
*/
|
||||
size_t getNumOnlineMeshNodes(bool localOnly = false);
|
||||
|
||||
void initConfigIntervals(), initModuleConfigIntervals(), resetNodes(), removeNodeByNum(uint nodeNum);
|
||||
void initConfigIntervals(), initModuleConfigIntervals(), resetNodes(), removeNodeByNum(NodeNum nodeNum);
|
||||
|
||||
bool factoryReset();
|
||||
|
||||
@@ -150,16 +150,18 @@ class NodeDB
|
||||
void setLocalPosition(meshtastic_Position position, bool timeOnly = false)
|
||||
{
|
||||
if (timeOnly) {
|
||||
LOG_DEBUG("Setting local position time only: time=%i\n", position.time);
|
||||
LOG_DEBUG("Setting local position time only: time=%u timestamp=%u\n", position.time, position.timestamp);
|
||||
localPosition.time = position.time;
|
||||
localPosition.timestamp = position.timestamp > 0 ? position.timestamp : position.time;
|
||||
return;
|
||||
}
|
||||
LOG_DEBUG("Setting local position: latitude=%i, longitude=%i, time=%i\n", position.latitude_i, position.longitude_i,
|
||||
position.time);
|
||||
LOG_DEBUG("Setting local position: latitude=%i, longitude=%i, time=%u, timestamp=%u\n", position.latitude_i,
|
||||
position.longitude_i, position.time, position.timestamp);
|
||||
localPosition = position;
|
||||
}
|
||||
|
||||
private:
|
||||
uint32_t lastNodeDbSave = 0; // when we last saved our db to flash
|
||||
/// Find a node in our DB, create an empty NodeInfoLite if missing
|
||||
meshtastic_NodeInfoLite *getOrCreateMeshNode(NodeNum n);
|
||||
|
||||
@@ -229,4 +231,4 @@ extern uint32_t error_address;
|
||||
ModuleConfig_RangeTestConfig_size + ModuleConfig_SerialConfig_size + ModuleConfig_StoreForwardConfig_size + \
|
||||
ModuleConfig_TelemetryConfig_size + ModuleConfig_size)
|
||||
|
||||
// Please do not remove this comment, it makes trunk and compiler happy at the same time.
|
||||
// Please do not remove this comment, it makes trunk and compiler happy at the same time.
|
||||
@@ -95,12 +95,11 @@ template <class T> class ProtobufModule : protected SinglePortModule
|
||||
*/
|
||||
virtual void alterReceived(meshtastic_MeshPacket &mp) override
|
||||
{
|
||||
auto &p = mp.decoded;
|
||||
|
||||
T scratch;
|
||||
T *decoded = NULL;
|
||||
if (mp.which_payload_variant == meshtastic_MeshPacket_decoded_tag && mp.decoded.portnum == ourPortNum) {
|
||||
memset(&scratch, 0, sizeof(scratch));
|
||||
auto &p = mp.decoded;
|
||||
if (pb_decode_from_bytes(p.payload.bytes, p.payload.size, fields, &scratch)) {
|
||||
decoded = &scratch;
|
||||
} else {
|
||||
|
||||
@@ -215,7 +215,7 @@ bool RF95Interface::isChannelActive()
|
||||
// LOG_DEBUG("Channel is busy!\n");
|
||||
return true;
|
||||
}
|
||||
if (result != RADIOLIB_ERR_WRONG_MODEM)
|
||||
if (result != RADIOLIB_CHANNEL_FREE)
|
||||
LOG_ERROR("Radiolib error %d when attempting RF95 isChannelActive!\n", result);
|
||||
assert(result != RADIOLIB_ERR_WRONG_MODEM);
|
||||
|
||||
|
||||
@@ -76,9 +76,12 @@ const RegionInfo regions[] = {
|
||||
RDEF(KR, 920.0f, 923.0f, 100, 0, 0, true, false, false),
|
||||
|
||||
/*
|
||||
???
|
||||
Taiwan, 920-925Mhz, limited to 0.5W indoor or coastal, 1.0W outdoor.
|
||||
5.8.1 in the Low-power Radio-frequency Devices Technical Regulations
|
||||
https://www.ncc.gov.tw/english/files/23070/102_5190_230703_1_doc_C.PDF
|
||||
https://gazette.nat.gov.tw/egFront/e_detail.do?metaid=147283
|
||||
*/
|
||||
RDEF(TW, 920.0f, 925.0f, 100, 0, 0, true, false, false),
|
||||
RDEF(TW, 920.0f, 925.0f, 100, 0, 27, true, false, false),
|
||||
|
||||
/*
|
||||
https://lora-alliance.org/wp-content/uploads/2020/11/lorawan_regional_parameters_v1.0.3reva_0.pdf
|
||||
@@ -151,10 +154,16 @@ static uint8_t bytes[MAX_RHPACKETLEN];
|
||||
void initRegion()
|
||||
{
|
||||
const RegionInfo *r = regions;
|
||||
#ifdef LORA_REGIONCODE
|
||||
for (; r->code != meshtastic_Config_LoRaConfig_RegionCode_UNSET && r->code != LORA_REGIONCODE; r++)
|
||||
;
|
||||
LOG_INFO("Wanted region %d, regulatory override to %s\n", config.lora.region, r->name);
|
||||
#else
|
||||
for (; r->code != meshtastic_Config_LoRaConfig_RegionCode_UNSET && r->code != config.lora.region; r++)
|
||||
;
|
||||
myRegion = r;
|
||||
LOG_INFO("Wanted region %d, using %s\n", config.lora.region, r->name);
|
||||
#endif
|
||||
myRegion = r;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -486,7 +495,7 @@ void RadioInterface::applyModemConfig()
|
||||
// If user has manually specified a channel num, then use that, otherwise generate one by hashing the name
|
||||
const char *channelName = channels.getName(channels.getPrimaryIndex());
|
||||
// channel_num is actually (channel_num - 1), since modulus (%) returns values from 0 to (numChannels - 1)
|
||||
int channel_num = (loraConfig.channel_num ? loraConfig.channel_num - 1 : hash(channelName)) % numChannels;
|
||||
uint32_t channel_num = (loraConfig.channel_num ? loraConfig.channel_num - 1 : hash(channelName)) % numChannels;
|
||||
|
||||
// Check if we use the default frequency slot
|
||||
RadioInterface::uses_default_frequency_slot =
|
||||
@@ -580,4 +589,4 @@ size_t RadioInterface::beginSending(meshtastic_MeshPacket *p)
|
||||
|
||||
sendingPacket = p;
|
||||
return p->encrypted.size + sizeof(PacketHeader);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,7 +25,31 @@ void LockingArduinoHal::spiEndTransaction()
|
||||
#if ARCH_PORTDUINO
|
||||
void LockingArduinoHal::spiTransfer(uint8_t *out, size_t len, uint8_t *in)
|
||||
{
|
||||
spi->transfer(out, in, len);
|
||||
if (busy == RADIOLIB_NC) {
|
||||
spi->transfer(out, in, len);
|
||||
} else {
|
||||
uint16_t offset = 0;
|
||||
|
||||
while (len) {
|
||||
uint8_t block_size = (len < 20 ? len : 20);
|
||||
spi->transfer((out != NULL ? out + offset : NULL), (in != NULL ? in + offset : NULL), block_size);
|
||||
if (block_size == len)
|
||||
return;
|
||||
|
||||
// ensure GPIO is low
|
||||
|
||||
uint32_t start = millis();
|
||||
while (digitalRead(busy)) {
|
||||
if (millis() - start >= 2000) {
|
||||
LOG_ERROR("GPIO mid-transfer timeout, is it connected?");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
offset += block_size;
|
||||
len -= block_size;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -414,4 +438,4 @@ void RadioLibInterface::startSend(meshtastic_MeshPacket *txp)
|
||||
// bits
|
||||
enableInterrupt(isrTxLevel0);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -21,12 +21,20 @@
|
||||
class LockingArduinoHal : public ArduinoHal
|
||||
{
|
||||
public:
|
||||
LockingArduinoHal(SPIClass &spi, SPISettings spiSettings) : ArduinoHal(spi, spiSettings){};
|
||||
LockingArduinoHal(SPIClass &spi, SPISettings spiSettings, RADIOLIB_PIN_TYPE _busy = RADIOLIB_NC)
|
||||
: ArduinoHal(spi, spiSettings)
|
||||
{
|
||||
#if ARCH_PORTDUINO
|
||||
busy = _busy;
|
||||
#endif
|
||||
};
|
||||
|
||||
void spiBeginTransaction() override;
|
||||
void spiEndTransaction() override;
|
||||
#if ARCH_PORTDUINO
|
||||
RADIOLIB_PIN_TYPE busy;
|
||||
void spiTransfer(uint8_t *out, size_t len, uint8_t *in) override;
|
||||
|
||||
#endif
|
||||
};
|
||||
|
||||
@@ -179,4 +187,4 @@ class RadioLibInterface : public RadioInterface, protected concurrency::Notified
|
||||
virtual void addReceiveMetadata(meshtastic_MeshPacket *mp) = 0;
|
||||
|
||||
virtual void setStandby() = 0;
|
||||
};
|
||||
};
|
||||
@@ -465,21 +465,22 @@ void Router::handleReceived(meshtastic_MeshPacket *p, RxSource src)
|
||||
cancelSending(p->from, p->id);
|
||||
skipHandle = true;
|
||||
}
|
||||
#if !MESHTASTIC_EXCLUDE_MQTT
|
||||
// Publish received message to MQTT if we're not the original transmitter of the packet
|
||||
if (!skipHandle && moduleConfig.mqtt.enabled && getFrom(p) != nodeDB->getNodeNum() && mqtt)
|
||||
mqtt->onSend(*p_encrypted, *p, p->channel);
|
||||
#endif
|
||||
|
||||
} else {
|
||||
printPacket("packet decoding failed or skipped (no PSK?)", p);
|
||||
}
|
||||
|
||||
packetPool.release(p_encrypted); // Release the encrypted packet
|
||||
|
||||
// call modules here
|
||||
if (!skipHandle)
|
||||
MeshModule::callPlugins(*p, src);
|
||||
if (!skipHandle) {
|
||||
MeshModule::callModules(*p, src);
|
||||
|
||||
#if !MESHTASTIC_EXCLUDE_MQTT
|
||||
// After potentially altering it, publish received message to MQTT if we're not the original transmitter of the packet
|
||||
if (decoded && moduleConfig.mqtt.enabled && getFrom(p) != nodeDB->getNodeNum() && mqtt)
|
||||
mqtt->onSend(*p_encrypted, *p, p->channel);
|
||||
#endif
|
||||
}
|
||||
|
||||
packetPool.release(p_encrypted); // Release the encrypted packet
|
||||
}
|
||||
|
||||
void Router::perhapsHandleReceived(meshtastic_MeshPacket *p)
|
||||
@@ -499,4 +500,4 @@ void Router::perhapsHandleReceived(meshtastic_MeshPacket *p)
|
||||
handleReceived(p);
|
||||
|
||||
packetPool.release(p);
|
||||
}
|
||||
}
|
||||
@@ -280,7 +280,7 @@ template <typename T> bool SX128xInterface<T>::isChannelActive()
|
||||
result = lora.scanChannel();
|
||||
if (result == RADIOLIB_LORA_DETECTED)
|
||||
return true;
|
||||
if (result != RADIOLIB_ERR_WRONG_MODEM)
|
||||
if (result != RADIOLIB_CHANNEL_FREE)
|
||||
LOG_ERROR("Radiolib error %d when attempting SX128X scanChannel!\n", result);
|
||||
assert(result != RADIOLIB_ERR_WRONG_MODEM);
|
||||
|
||||
|
||||
27
src/mesh/Throttle.cpp
Normal file
27
src/mesh/Throttle.cpp
Normal file
@@ -0,0 +1,27 @@
|
||||
#include "Throttle.h"
|
||||
#include <Arduino.h>
|
||||
|
||||
/// @brief Execute a function throttled to a minimum interval
|
||||
/// @param lastExecutionMs Pointer to the last execution time in milliseconds
|
||||
/// @param minumumIntervalMs Minimum execution interval in milliseconds
|
||||
/// @param throttleFunc Function to execute if the execution is not deferred
|
||||
/// @param onDefer Default to NULL, execute the function if the execution is deferred
|
||||
/// @return true if the function was executed, false if it was deferred
|
||||
bool Throttle::execute(uint32_t *lastExecutionMs, uint32_t minumumIntervalMs, void (*throttleFunc)(void), void (*onDefer)(void))
|
||||
{
|
||||
if (*lastExecutionMs == 0) {
|
||||
*lastExecutionMs = millis();
|
||||
throttleFunc();
|
||||
return true;
|
||||
}
|
||||
uint32_t now = millis();
|
||||
|
||||
if ((now - *lastExecutionMs) >= minumumIntervalMs) {
|
||||
throttleFunc();
|
||||
*lastExecutionMs = now;
|
||||
return true;
|
||||
} else if (onDefer != NULL) {
|
||||
onDefer();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
9
src/mesh/Throttle.h
Normal file
9
src/mesh/Throttle.h
Normal file
@@ -0,0 +1,9 @@
|
||||
#pragma once
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
|
||||
class Throttle
|
||||
{
|
||||
public:
|
||||
static bool execute(uint32_t *lastExecutionMs, uint32_t minumumIntervalMs, void (*func)(void), void (*onDefer)(void) = NULL);
|
||||
};
|
||||
@@ -55,7 +55,7 @@ extern const pb_msgdesc_t meshtastic_ChannelSet_msg;
|
||||
|
||||
/* Maximum encoded size of messages (where known) */
|
||||
#define MESHTASTIC_MESHTASTIC_APPONLY_PB_H_MAX_SIZE meshtastic_ChannelSet_size
|
||||
#define meshtastic_ChannelSet_size 658
|
||||
#define meshtastic_ChannelSet_size 674
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
|
||||
@@ -34,6 +34,9 @@ typedef enum _meshtastic_Channel_Role {
|
||||
typedef struct _meshtastic_ModuleSettings {
|
||||
/* Bits of precision for the location sent in position packets. */
|
||||
uint32_t position_precision;
|
||||
/* Controls whether or not the phone / clients should mute the current channel
|
||||
Useful for noisy public channels you don't necessarily want to disable */
|
||||
bool is_client_muted;
|
||||
} meshtastic_ModuleSettings;
|
||||
|
||||
typedef PB_BYTES_ARRAY_T(32) meshtastic_ChannelSettings_psk_t;
|
||||
@@ -126,14 +129,15 @@ extern "C" {
|
||||
|
||||
/* Initializer values for message structs */
|
||||
#define meshtastic_ChannelSettings_init_default {0, {0, {0}}, "", 0, 0, 0, false, meshtastic_ModuleSettings_init_default}
|
||||
#define meshtastic_ModuleSettings_init_default {0}
|
||||
#define meshtastic_ModuleSettings_init_default {0, 0}
|
||||
#define meshtastic_Channel_init_default {0, false, meshtastic_ChannelSettings_init_default, _meshtastic_Channel_Role_MIN}
|
||||
#define meshtastic_ChannelSettings_init_zero {0, {0, {0}}, "", 0, 0, 0, false, meshtastic_ModuleSettings_init_zero}
|
||||
#define meshtastic_ModuleSettings_init_zero {0}
|
||||
#define meshtastic_ModuleSettings_init_zero {0, 0}
|
||||
#define meshtastic_Channel_init_zero {0, false, meshtastic_ChannelSettings_init_zero, _meshtastic_Channel_Role_MIN}
|
||||
|
||||
/* Field tags (for use in manual encoding/decoding) */
|
||||
#define meshtastic_ModuleSettings_position_precision_tag 1
|
||||
#define meshtastic_ModuleSettings_is_client_muted_tag 2
|
||||
#define meshtastic_ChannelSettings_channel_num_tag 1
|
||||
#define meshtastic_ChannelSettings_psk_tag 2
|
||||
#define meshtastic_ChannelSettings_name_tag 3
|
||||
@@ -159,7 +163,8 @@ X(a, STATIC, OPTIONAL, MESSAGE, module_settings, 7)
|
||||
#define meshtastic_ChannelSettings_module_settings_MSGTYPE meshtastic_ModuleSettings
|
||||
|
||||
#define meshtastic_ModuleSettings_FIELDLIST(X, a) \
|
||||
X(a, STATIC, SINGULAR, UINT32, position_precision, 1)
|
||||
X(a, STATIC, SINGULAR, UINT32, position_precision, 1) \
|
||||
X(a, STATIC, SINGULAR, BOOL, is_client_muted, 2)
|
||||
#define meshtastic_ModuleSettings_CALLBACK NULL
|
||||
#define meshtastic_ModuleSettings_DEFAULT NULL
|
||||
|
||||
@@ -182,9 +187,9 @@ extern const pb_msgdesc_t meshtastic_Channel_msg;
|
||||
|
||||
/* Maximum encoded size of messages (where known) */
|
||||
#define MESHTASTIC_MESHTASTIC_CHANNEL_PB_H_MAX_SIZE meshtastic_Channel_size
|
||||
#define meshtastic_ChannelSettings_size 70
|
||||
#define meshtastic_Channel_size 85
|
||||
#define meshtastic_ModuleSettings_size 6
|
||||
#define meshtastic_ChannelSettings_size 72
|
||||
#define meshtastic_Channel_size 87
|
||||
#define meshtastic_ModuleSettings_size 8
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
|
||||
@@ -283,6 +283,8 @@ typedef struct _meshtastic_Config_DeviceConfig {
|
||||
bool disable_triple_click;
|
||||
/* POSIX Timezone definition string from https://github.com/nayarsystems/posix_tz_db/blob/master/zones.csv. */
|
||||
char tzdef[65];
|
||||
/* If true, disable the default blinking LED (LED_PIN) behavior on the device */
|
||||
bool led_heartbeat_disabled;
|
||||
} meshtastic_Config_DeviceConfig;
|
||||
|
||||
/* Position Config */
|
||||
@@ -324,35 +326,30 @@ typedef struct _meshtastic_Config_PositionConfig {
|
||||
/* Power Config\
|
||||
See [Power Config](/docs/settings/config/power) for additional power config details. */
|
||||
typedef struct _meshtastic_Config_PowerConfig {
|
||||
/* If set, we are powered from a low-current source (i.e. solar), so even if it looks like we have power flowing in
|
||||
we should try to minimize power consumption as much as possible.
|
||||
YOU DO NOT NEED TO SET THIS IF YOU'VE set is_router (it is implied in that case).
|
||||
Advanced Option */
|
||||
/* Description: Will sleep everything as much as possible, for the tracker and sensor role this will also include the lora radio.
|
||||
Don't use this setting if you want to use your device with the phone apps or are using a device without a user button.
|
||||
Technical Details: Works for ESP32 devices and NRF52 devices in the Sensor or Tracker roles */
|
||||
bool is_power_saving;
|
||||
/* If non-zero, the device will fully power off this many seconds after external power is removed. */
|
||||
/* Description: If non-zero, the device will fully power off this many seconds after external power is removed. */
|
||||
uint32_t on_battery_shutdown_after_secs;
|
||||
/* Ratio of voltage divider for battery pin eg. 3.20 (R1=100k, R2=220k)
|
||||
Overrides the ADC_MULTIPLIER defined in variant for battery voltage calculation.
|
||||
Should be set to floating point value between 2 and 4
|
||||
Fixes issues on Heltec v2 */
|
||||
https://meshtastic.org/docs/configuration/radio/power/#adc-multiplier-override
|
||||
Should be set to floating point value between 2 and 6 */
|
||||
float adc_multiplier_override;
|
||||
/* Wait Bluetooth Seconds
|
||||
The number of seconds for to wait before turning off BLE in No Bluetooth states
|
||||
0 for default of 1 minute */
|
||||
/* Description: The number of seconds for to wait before turning off BLE in No Bluetooth states
|
||||
Technical Details: ESP32 Only 0 for default of 1 minute */
|
||||
uint32_t wait_bluetooth_secs;
|
||||
/* Super Deep Sleep Seconds
|
||||
While in Light Sleep if mesh_sds_timeout_secs is exceeded we will lower into super deep sleep
|
||||
for this value (default 1 year) or a button press
|
||||
0 for default of one year */
|
||||
uint32_t sds_secs;
|
||||
/* Light Sleep Seconds
|
||||
In light sleep the CPU is suspended, LoRa radio is on, BLE is off an GPS is on
|
||||
ESP32 Only
|
||||
0 for default of 300 */
|
||||
/* Description: In light sleep the CPU is suspended, LoRa radio is on, BLE is off an GPS is on
|
||||
Technical Details: ESP32 Only 0 for default of 300 */
|
||||
uint32_t ls_secs;
|
||||
/* Minimum Wake Seconds
|
||||
While in light sleep when we receive packets on the LoRa radio we will wake and handle them and stay awake in no BLE mode for this value
|
||||
0 for default of 10 seconds */
|
||||
/* Description: While in light sleep when we receive packets on the LoRa radio we will wake and handle them and stay awake in no BLE mode for this value
|
||||
Technical Details: ESP32 Only 0 for default of 10 seconds */
|
||||
uint32_t min_wake_secs;
|
||||
/* I2C address of INA_2XX to use for reading device battery voltage */
|
||||
uint8_t device_battery_ina_address;
|
||||
@@ -585,7 +582,7 @@ extern "C" {
|
||||
|
||||
/* Initializer values for message structs */
|
||||
#define meshtastic_Config_init_default {0, {meshtastic_Config_DeviceConfig_init_default}}
|
||||
#define meshtastic_Config_DeviceConfig_init_default {_meshtastic_Config_DeviceConfig_Role_MIN, 0, 0, 0, 0, _meshtastic_Config_DeviceConfig_RebroadcastMode_MIN, 0, 0, 0, 0, ""}
|
||||
#define meshtastic_Config_DeviceConfig_init_default {_meshtastic_Config_DeviceConfig_Role_MIN, 0, 0, 0, 0, _meshtastic_Config_DeviceConfig_RebroadcastMode_MIN, 0, 0, 0, 0, "", 0}
|
||||
#define meshtastic_Config_PositionConfig_init_default {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, _meshtastic_Config_PositionConfig_GpsMode_MIN}
|
||||
#define meshtastic_Config_PowerConfig_init_default {0, 0, 0, 0, 0, 0, 0, 0}
|
||||
#define meshtastic_Config_NetworkConfig_init_default {0, "", "", "", 0, _meshtastic_Config_NetworkConfig_AddressMode_MIN, false, meshtastic_Config_NetworkConfig_IpV4Config_init_default, ""}
|
||||
@@ -594,7 +591,7 @@ extern "C" {
|
||||
#define meshtastic_Config_LoRaConfig_init_default {0, _meshtastic_Config_LoRaConfig_ModemPreset_MIN, 0, 0, 0, 0, _meshtastic_Config_LoRaConfig_RegionCode_MIN, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0}, 0}
|
||||
#define meshtastic_Config_BluetoothConfig_init_default {0, _meshtastic_Config_BluetoothConfig_PairingMode_MIN, 0}
|
||||
#define meshtastic_Config_init_zero {0, {meshtastic_Config_DeviceConfig_init_zero}}
|
||||
#define meshtastic_Config_DeviceConfig_init_zero {_meshtastic_Config_DeviceConfig_Role_MIN, 0, 0, 0, 0, _meshtastic_Config_DeviceConfig_RebroadcastMode_MIN, 0, 0, 0, 0, ""}
|
||||
#define meshtastic_Config_DeviceConfig_init_zero {_meshtastic_Config_DeviceConfig_Role_MIN, 0, 0, 0, 0, _meshtastic_Config_DeviceConfig_RebroadcastMode_MIN, 0, 0, 0, 0, "", 0}
|
||||
#define meshtastic_Config_PositionConfig_init_zero {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, _meshtastic_Config_PositionConfig_GpsMode_MIN}
|
||||
#define meshtastic_Config_PowerConfig_init_zero {0, 0, 0, 0, 0, 0, 0, 0}
|
||||
#define meshtastic_Config_NetworkConfig_init_zero {0, "", "", "", 0, _meshtastic_Config_NetworkConfig_AddressMode_MIN, false, meshtastic_Config_NetworkConfig_IpV4Config_init_zero, ""}
|
||||
@@ -615,6 +612,7 @@ extern "C" {
|
||||
#define meshtastic_Config_DeviceConfig_is_managed_tag 9
|
||||
#define meshtastic_Config_DeviceConfig_disable_triple_click_tag 10
|
||||
#define meshtastic_Config_DeviceConfig_tzdef_tag 11
|
||||
#define meshtastic_Config_DeviceConfig_led_heartbeat_disabled_tag 12
|
||||
#define meshtastic_Config_PositionConfig_position_broadcast_secs_tag 1
|
||||
#define meshtastic_Config_PositionConfig_position_broadcast_smart_enabled_tag 2
|
||||
#define meshtastic_Config_PositionConfig_fixed_position_tag 3
|
||||
@@ -715,7 +713,8 @@ X(a, STATIC, SINGULAR, UINT32, node_info_broadcast_secs, 7) \
|
||||
X(a, STATIC, SINGULAR, BOOL, double_tap_as_button_press, 8) \
|
||||
X(a, STATIC, SINGULAR, BOOL, is_managed, 9) \
|
||||
X(a, STATIC, SINGULAR, BOOL, disable_triple_click, 10) \
|
||||
X(a, STATIC, SINGULAR, STRING, tzdef, 11)
|
||||
X(a, STATIC, SINGULAR, STRING, tzdef, 11) \
|
||||
X(a, STATIC, SINGULAR, BOOL, led_heartbeat_disabled, 12)
|
||||
#define meshtastic_Config_DeviceConfig_CALLBACK NULL
|
||||
#define meshtastic_Config_DeviceConfig_DEFAULT NULL
|
||||
|
||||
@@ -834,7 +833,7 @@ extern const pb_msgdesc_t meshtastic_Config_BluetoothConfig_msg;
|
||||
/* Maximum encoded size of messages (where known) */
|
||||
#define MESHTASTIC_MESHTASTIC_CONFIG_PB_H_MAX_SIZE meshtastic_Config_size
|
||||
#define meshtastic_Config_BluetoothConfig_size 10
|
||||
#define meshtastic_Config_DeviceConfig_size 98
|
||||
#define meshtastic_Config_DeviceConfig_size 100
|
||||
#define meshtastic_Config_DisplayConfig_size 28
|
||||
#define meshtastic_Config_LoRaConfig_size 80
|
||||
#define meshtastic_Config_NetworkConfig_IpV4Config_size 20
|
||||
|
||||
@@ -306,9 +306,9 @@ extern const pb_msgdesc_t meshtastic_OEMStore_msg;
|
||||
/* Maximum encoded size of messages (where known) */
|
||||
/* meshtastic_DeviceState_size depends on runtime parameters */
|
||||
#define MESHTASTIC_MESHTASTIC_DEVICEONLY_PB_H_MAX_SIZE meshtastic_OEMStore_size
|
||||
#define meshtastic_ChannelFile_size 702
|
||||
#define meshtastic_ChannelFile_size 718
|
||||
#define meshtastic_NodeInfoLite_size 166
|
||||
#define meshtastic_OEMStore_size 3344
|
||||
#define meshtastic_OEMStore_size 3346
|
||||
#define meshtastic_PositionLite_size 28
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
@@ -181,7 +181,7 @@ extern const pb_msgdesc_t meshtastic_LocalModuleConfig_msg;
|
||||
|
||||
/* Maximum encoded size of messages (where known) */
|
||||
#define MESHTASTIC_MESHTASTIC_LOCALONLY_PB_H_MAX_SIZE meshtastic_LocalModuleConfig_size
|
||||
#define meshtastic_LocalConfig_size 535
|
||||
#define meshtastic_LocalConfig_size 537
|
||||
#define meshtastic_LocalModuleConfig_size 663
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
@@ -63,6 +63,8 @@ typedef enum _meshtastic_HardwareModel {
|
||||
meshtastic_HardwareModel_NANO_G2_ULTRA = 18,
|
||||
/* LoRAType device: https://loratype.org/ */
|
||||
meshtastic_HardwareModel_LORA_TYPE = 19,
|
||||
/* wiphone https://www.wiphone.io/ */
|
||||
meshtastic_HardwareModel_WIPHONE = 20,
|
||||
/* B&Q Consulting Station Edition G1: https://uniteng.com/wiki/doku.php?id=meshtastic:station */
|
||||
meshtastic_HardwareModel_STATION_G1 = 25,
|
||||
/* RAK11310 (RP2040 + SX1262) */
|
||||
@@ -146,6 +148,14 @@ typedef enum _meshtastic_HardwareModel {
|
||||
/* Teledatics TD-LORAC NRF52840 based M.2 LoRA module
|
||||
Compatible with the TD-WRLS development board */
|
||||
meshtastic_HardwareModel_TD_LORAC = 60,
|
||||
/* CDEBYTE EoRa-S3 board using their own MM modules, clone of LILYGO T3S3 */
|
||||
meshtastic_HardwareModel_CDEBYTE_EORA_S3 = 61,
|
||||
/* TWC_MESH_V4
|
||||
Adafruit NRF52840 feather express with SX1262, SSD1306 OLED and NEO6M GPS */
|
||||
meshtastic_HardwareModel_TWC_MESH_V4 = 62,
|
||||
/* NRF52_PROMICRO_DIY
|
||||
Promicro NRF52840 with SX1262/LLCC68, SSD1306 OLED and NEO6M GPS */
|
||||
meshtastic_HardwareModel_NRF52_PROMICRO_DIY = 63,
|
||||
/* ------------------------------------------------------------------------------------------------------------------------------------------
|
||||
Reserved ID For developing private Ports. These will show up in live traffic sparsely, so we can use a high number. Keep it within 8 bits.
|
||||
------------------------------------------------------------------------------------------------------------------------------------------ */
|
||||
|
||||
@@ -43,7 +43,11 @@ typedef enum _meshtastic_TelemetrySensorType {
|
||||
/* INA3221 3 Channel Voltage / Current Sensor */
|
||||
meshtastic_TelemetrySensorType_INA3221 = 14,
|
||||
/* BMP085/BMP180 High accuracy temperature and pressure (older Version of BMP280) */
|
||||
meshtastic_TelemetrySensorType_BMP085 = 15
|
||||
meshtastic_TelemetrySensorType_BMP085 = 15,
|
||||
/* RCWL-9620 Doppler Radar Distance Sensor, used for water level detection */
|
||||
meshtastic_TelemetrySensorType_RCWL9620 = 16,
|
||||
/* Sensirion High accuracy temperature and humidity */
|
||||
meshtastic_TelemetrySensorType_SHT4X = 17
|
||||
} meshtastic_TelemetrySensorType;
|
||||
|
||||
/* Struct definitions */
|
||||
@@ -78,6 +82,8 @@ typedef struct _meshtastic_EnvironmentMetrics {
|
||||
/* relative scale IAQ value as measured by Bosch BME680 . value 0-500.
|
||||
Belongs to Air Quality but is not particle but VOC measurement. Other VOC values can also be put in here. */
|
||||
uint16_t iaq;
|
||||
/* RCWL9620 Doppler Radar Distance Sensor, used for water level detection. Float value in mm. */
|
||||
float distance;
|
||||
} meshtastic_EnvironmentMetrics;
|
||||
|
||||
/* Power Metrics (voltage / current / etc) */
|
||||
@@ -148,8 +154,8 @@ extern "C" {
|
||||
|
||||
/* Helper constants for enums */
|
||||
#define _meshtastic_TelemetrySensorType_MIN meshtastic_TelemetrySensorType_SENSOR_UNSET
|
||||
#define _meshtastic_TelemetrySensorType_MAX meshtastic_TelemetrySensorType_BMP085
|
||||
#define _meshtastic_TelemetrySensorType_ARRAYSIZE ((meshtastic_TelemetrySensorType)(meshtastic_TelemetrySensorType_BMP085+1))
|
||||
#define _meshtastic_TelemetrySensorType_MAX meshtastic_TelemetrySensorType_SHT4X
|
||||
#define _meshtastic_TelemetrySensorType_ARRAYSIZE ((meshtastic_TelemetrySensorType)(meshtastic_TelemetrySensorType_SHT4X+1))
|
||||
|
||||
|
||||
|
||||
@@ -159,12 +165,12 @@ extern "C" {
|
||||
|
||||
/* Initializer values for message structs */
|
||||
#define meshtastic_DeviceMetrics_init_default {0, 0, 0, 0, 0}
|
||||
#define meshtastic_EnvironmentMetrics_init_default {0, 0, 0, 0, 0, 0, 0}
|
||||
#define meshtastic_EnvironmentMetrics_init_default {0, 0, 0, 0, 0, 0, 0, 0}
|
||||
#define meshtastic_PowerMetrics_init_default {0, 0, 0, 0, 0, 0}
|
||||
#define meshtastic_AirQualityMetrics_init_default {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
|
||||
#define meshtastic_Telemetry_init_default {0, 0, {meshtastic_DeviceMetrics_init_default}}
|
||||
#define meshtastic_DeviceMetrics_init_zero {0, 0, 0, 0, 0}
|
||||
#define meshtastic_EnvironmentMetrics_init_zero {0, 0, 0, 0, 0, 0, 0}
|
||||
#define meshtastic_EnvironmentMetrics_init_zero {0, 0, 0, 0, 0, 0, 0, 0}
|
||||
#define meshtastic_PowerMetrics_init_zero {0, 0, 0, 0, 0, 0}
|
||||
#define meshtastic_AirQualityMetrics_init_zero {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
|
||||
#define meshtastic_Telemetry_init_zero {0, 0, {meshtastic_DeviceMetrics_init_zero}}
|
||||
@@ -182,6 +188,7 @@ extern "C" {
|
||||
#define meshtastic_EnvironmentMetrics_voltage_tag 5
|
||||
#define meshtastic_EnvironmentMetrics_current_tag 6
|
||||
#define meshtastic_EnvironmentMetrics_iaq_tag 7
|
||||
#define meshtastic_EnvironmentMetrics_distance_tag 8
|
||||
#define meshtastic_PowerMetrics_ch1_voltage_tag 1
|
||||
#define meshtastic_PowerMetrics_ch1_current_tag 2
|
||||
#define meshtastic_PowerMetrics_ch2_voltage_tag 3
|
||||
@@ -223,7 +230,8 @@ X(a, STATIC, SINGULAR, FLOAT, barometric_pressure, 3) \
|
||||
X(a, STATIC, SINGULAR, FLOAT, gas_resistance, 4) \
|
||||
X(a, STATIC, SINGULAR, FLOAT, voltage, 5) \
|
||||
X(a, STATIC, SINGULAR, FLOAT, current, 6) \
|
||||
X(a, STATIC, SINGULAR, UINT32, iaq, 7)
|
||||
X(a, STATIC, SINGULAR, UINT32, iaq, 7) \
|
||||
X(a, STATIC, SINGULAR, FLOAT, distance, 8)
|
||||
#define meshtastic_EnvironmentMetrics_CALLBACK NULL
|
||||
#define meshtastic_EnvironmentMetrics_DEFAULT NULL
|
||||
|
||||
@@ -283,7 +291,7 @@ extern const pb_msgdesc_t meshtastic_Telemetry_msg;
|
||||
#define MESHTASTIC_MESHTASTIC_TELEMETRY_PB_H_MAX_SIZE meshtastic_Telemetry_size
|
||||
#define meshtastic_AirQualityMetrics_size 72
|
||||
#define meshtastic_DeviceMetrics_size 27
|
||||
#define meshtastic_EnvironmentMetrics_size 34
|
||||
#define meshtastic_EnvironmentMetrics_size 39
|
||||
#define meshtastic_PowerMetrics_size 30
|
||||
#define meshtastic_Telemetry_size 79
|
||||
|
||||
|
||||
@@ -23,6 +23,10 @@
|
||||
#include "mqtt/MQTT.h"
|
||||
#endif
|
||||
|
||||
#if !MESHTASTIC_EXCLUDE_GPS
|
||||
#include "GPS.h"
|
||||
#endif
|
||||
|
||||
AdminModule *adminModule;
|
||||
bool hasOpenEditTransaction;
|
||||
|
||||
@@ -217,6 +221,12 @@ bool AdminModule::handleReceivedProtobuf(const meshtastic_MeshPacket &mp, meshta
|
||||
nodeDB->setLocalPosition(r->set_fixed_position);
|
||||
config.position.fixed_position = true;
|
||||
saveChanges(SEGMENT_DEVICESTATE | SEGMENT_CONFIG, false);
|
||||
// Send our new fixed position to the mesh for good measure
|
||||
positionModule->sendOurPosition();
|
||||
#if !MESHTASTIC_EXCLUDE_GPS
|
||||
if (gps != nullptr)
|
||||
gps->enable();
|
||||
#endif
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -256,7 +266,7 @@ bool AdminModule::handleReceivedProtobuf(const meshtastic_MeshPacket &mp, meshta
|
||||
|
||||
default:
|
||||
meshtastic_AdminMessage res = meshtastic_AdminMessage_init_default;
|
||||
AdminMessageHandleResult handleResult = MeshModule::handleAdminMessageForAllPlugins(mp, r, &res);
|
||||
AdminMessageHandleResult handleResult = MeshModule::handleAdminMessageForAllModules(mp, r, &res);
|
||||
|
||||
if (handleResult == AdminMessageHandleResult::HANDLED_WITH_RESPONSE) {
|
||||
myReply = allocDataProtobuf(res);
|
||||
|
||||
@@ -161,10 +161,10 @@ int CannedMessageModule::handleInputEvent(const InputEvent *event)
|
||||
if (!event->kbchar) {
|
||||
if (event->inputEvent == static_cast<char>(meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_LEFT)) {
|
||||
this->payload = 0xb4;
|
||||
this->destSelect = CANNED_MESSAGE_DESTINATION_TYPE_NODE;
|
||||
// this->destSelect = CANNED_MESSAGE_DESTINATION_TYPE_NODE;
|
||||
} else if (event->inputEvent == static_cast<char>(meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_RIGHT)) {
|
||||
this->payload = 0xb7;
|
||||
this->destSelect = CANNED_MESSAGE_DESTINATION_TYPE_NODE;
|
||||
// this->destSelect = CANNED_MESSAGE_DESTINATION_TYPE_NODE;
|
||||
}
|
||||
} else {
|
||||
// pass the pressed key
|
||||
@@ -180,11 +180,75 @@ int CannedMessageModule::handleInputEvent(const InputEvent *event)
|
||||
(this->runState == CANNED_MESSAGE_RUN_STATE_DISABLED)) {
|
||||
this->runState = CANNED_MESSAGE_RUN_STATE_FREETEXT;
|
||||
}
|
||||
// pass the pressed key
|
||||
// LOG_DEBUG("Canned message ANYKEY (%x)\n", event->kbchar);
|
||||
this->payload = event->kbchar;
|
||||
this->lastTouchMillis = millis();
|
||||
validEvent = true;
|
||||
|
||||
validEvent = false; // If key is normal than it will be set to true.
|
||||
|
||||
// Run modifier key code below, (doesnt inturrupt typing or reset to start screen page)
|
||||
switch (event->kbchar) {
|
||||
case 0x11: // make screen brighter
|
||||
if (screen)
|
||||
screen->increaseBrightness();
|
||||
LOG_DEBUG("increasing Screen Brightness\n");
|
||||
break;
|
||||
case 0x12: // make screen dimmer
|
||||
if (screen)
|
||||
screen->decreaseBrightness();
|
||||
LOG_DEBUG("Decreasing Screen Brightness\n");
|
||||
break;
|
||||
case 0xf1: // draw modifier (function) symbal
|
||||
if (screen)
|
||||
screen->setFunctionSymbal("Fn");
|
||||
break;
|
||||
case 0xf2: // remove modifier (function) symbal
|
||||
if (screen)
|
||||
screen->removeFunctionSymbal("Fn");
|
||||
break;
|
||||
// mute (switch off/toggle) external notifications on fn+m
|
||||
case 0xac:
|
||||
if (moduleConfig.external_notification.enabled == true) {
|
||||
if (externalNotificationModule->getMute()) {
|
||||
externalNotificationModule->setMute(false);
|
||||
showTemporaryMessage("Notifications \nEnabled");
|
||||
if (screen)
|
||||
screen->removeFunctionSymbal("M"); // remove the mute symbol from the bottom right corner
|
||||
} else {
|
||||
externalNotificationModule->stopNow(); // this will turn off all GPIO and sounds and idle the loop
|
||||
externalNotificationModule->setMute(true);
|
||||
showTemporaryMessage("Notifications \nDisabled");
|
||||
if (screen)
|
||||
screen->setFunctionSymbal("M"); // add the mute symbol to the bottom right corner
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 0x9e: // toggle GPS like triple press does
|
||||
#if !MESHTASTIC_EXCLUDE_GPS
|
||||
if (gps != nullptr) {
|
||||
gps->toggleGpsMode();
|
||||
}
|
||||
if (screen)
|
||||
screen->forceDisplay();
|
||||
showTemporaryMessage("GPS Toggled");
|
||||
#endif
|
||||
break;
|
||||
case 0xaf: // fn+space send network ping like double press does
|
||||
service.refreshLocalMeshNode();
|
||||
if (service.trySendPosition(NODENUM_BROADCAST, true)) {
|
||||
showTemporaryMessage("Position \nUpdate Sent");
|
||||
} else {
|
||||
showTemporaryMessage("Node Info \nUpdate Sent");
|
||||
}
|
||||
break;
|
||||
default:
|
||||
// pass the pressed key
|
||||
// LOG_DEBUG("Canned message ANYKEY (%x)\n", event->kbchar);
|
||||
this->payload = event->kbchar;
|
||||
this->lastTouchMillis = millis();
|
||||
validEvent = true;
|
||||
break;
|
||||
}
|
||||
if (screen && (event->kbchar != 0xf1)) {
|
||||
screen->removeFunctionSymbal("Fn"); // remove modifier (function) symbal
|
||||
}
|
||||
}
|
||||
if (event->inputEvent == static_cast<char>(MATRIXKEY)) {
|
||||
LOG_DEBUG("Canned message event Matrix key pressed\n");
|
||||
@@ -233,14 +297,16 @@ int32_t CannedMessageModule::runOnce()
|
||||
{
|
||||
if (((!moduleConfig.canned_message.enabled) && !CANNED_MESSAGE_MODULE_ENABLE) ||
|
||||
(this->runState == CANNED_MESSAGE_RUN_STATE_DISABLED) || (this->runState == CANNED_MESSAGE_RUN_STATE_INACTIVE)) {
|
||||
temporaryMessage = "";
|
||||
return INT32_MAX;
|
||||
}
|
||||
// LOG_DEBUG("Check status\n");
|
||||
UIFrameEvent e = {false, true};
|
||||
if ((this->runState == CANNED_MESSAGE_RUN_STATE_SENDING_ACTIVE) ||
|
||||
(this->runState == CANNED_MESSAGE_RUN_STATE_ACK_NACK_RECEIVED)) {
|
||||
// TODO: might have some feedback of sendig state
|
||||
(this->runState == CANNED_MESSAGE_RUN_STATE_ACK_NACK_RECEIVED) || (this->runState == CANNED_MESSAGE_RUN_STATE_MESSAGE)) {
|
||||
// TODO: might have some feedback of sending state
|
||||
this->runState = CANNED_MESSAGE_RUN_STATE_INACTIVE;
|
||||
temporaryMessage = "";
|
||||
e.frameChanged = true;
|
||||
this->currentMessageIndex = -1;
|
||||
this->freetext = ""; // clear freetext
|
||||
@@ -388,8 +454,9 @@ int32_t CannedMessageModule::runOnce()
|
||||
}
|
||||
if (this->runState == CANNED_MESSAGE_RUN_STATE_FREETEXT) {
|
||||
e.frameChanged = true;
|
||||
switch (this->payload) {
|
||||
case 0x08: // backspace
|
||||
switch (this->payload) { // code below all trigger the freetext window (where you type to send a message) or reset the
|
||||
// display back to the default window
|
||||
case 0x08: // backspace
|
||||
if (this->freetext.length() > 0) {
|
||||
if (this->cursor == this->freetext.length()) {
|
||||
this->freetext = this->freetext.substring(0, this->freetext.length() - 1);
|
||||
@@ -401,7 +468,6 @@ int32_t CannedMessageModule::runOnce()
|
||||
}
|
||||
break;
|
||||
case 0x09: // tab
|
||||
case 0x91: // alt+t for T-Deck that doesn't have a tab key
|
||||
if (this->destSelect == CANNED_MESSAGE_DESTINATION_TYPE_CHANNEL) {
|
||||
this->destSelect = CANNED_MESSAGE_DESTINATION_TYPE_NONE;
|
||||
} else if (this->destSelect == CANNED_MESSAGE_DESTINATION_TYPE_NODE) {
|
||||
@@ -414,7 +480,7 @@ int32_t CannedMessageModule::runOnce()
|
||||
case 0xb7: // right
|
||||
// already handled above
|
||||
break;
|
||||
// handle fn+s for shutdown
|
||||
// handle fn+s for shutdown
|
||||
case 0x9b:
|
||||
if (screen)
|
||||
screen->startShutdownScreen();
|
||||
@@ -428,33 +494,6 @@ int32_t CannedMessageModule::runOnce()
|
||||
rebootAtMsec = millis() + DEFAULT_REBOOT_SECONDS * 1000;
|
||||
runState = CANNED_MESSAGE_RUN_STATE_INACTIVE;
|
||||
break;
|
||||
case 0x9e: // toggle GPS like triple press does
|
||||
if (gps != nullptr) {
|
||||
gps->toggleGpsMode();
|
||||
}
|
||||
if (screen)
|
||||
screen->forceDisplay();
|
||||
runState = CANNED_MESSAGE_RUN_STATE_INACTIVE;
|
||||
break;
|
||||
|
||||
// mute (switch off/toggle) external notifications on fn+m
|
||||
case 0xac:
|
||||
if (moduleConfig.external_notification.enabled == true) {
|
||||
if (externalNotificationModule->getMute()) {
|
||||
externalNotificationModule->setMute(false);
|
||||
runState = CANNED_MESSAGE_RUN_STATE_INACTIVE;
|
||||
} else {
|
||||
externalNotificationModule->stopNow(); // this will turn off all GPIO and sounds and idle the loop
|
||||
externalNotificationModule->setMute(true);
|
||||
runState = CANNED_MESSAGE_RUN_STATE_INACTIVE;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 0xaf: // fn+space send network ping like double press does
|
||||
service.refreshLocalMeshNode();
|
||||
service.sendNetworkPing(NODENUM_BROADCAST, true);
|
||||
runState = CANNED_MESSAGE_RUN_STATE_INACTIVE;
|
||||
break;
|
||||
default:
|
||||
if (this->cursor == this->freetext.length()) {
|
||||
this->freetext += this->payload;
|
||||
@@ -470,6 +509,8 @@ int32_t CannedMessageModule::runOnce()
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (screen)
|
||||
screen->removeFunctionSymbal("Fn");
|
||||
}
|
||||
|
||||
this->lastTouchMillis = millis();
|
||||
@@ -542,12 +583,27 @@ int CannedMessageModule::getPrevIndex()
|
||||
return this->currentMessageIndex - 1;
|
||||
}
|
||||
}
|
||||
void CannedMessageModule::showTemporaryMessage(const String &message)
|
||||
{
|
||||
temporaryMessage = message;
|
||||
UIFrameEvent e = {false, true};
|
||||
e.frameChanged = true;
|
||||
notifyObservers(&e);
|
||||
runState = CANNED_MESSAGE_RUN_STATE_MESSAGE;
|
||||
// run this loop again in 2 seconds, next iteration will clear the display
|
||||
setIntervalFromNow(2000);
|
||||
}
|
||||
|
||||
void CannedMessageModule::drawFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y)
|
||||
{
|
||||
char buffer[50];
|
||||
|
||||
if (cannedMessageModule->runState == CANNED_MESSAGE_RUN_STATE_ACK_NACK_RECEIVED) {
|
||||
if (temporaryMessage.length() != 0) {
|
||||
LOG_DEBUG("Drawing temporary message: %s", temporaryMessage.c_str());
|
||||
display->setTextAlignment(TEXT_ALIGN_CENTER);
|
||||
display->setFont(FONT_MEDIUM);
|
||||
display->drawString(display->getWidth() / 2 + x, 0 + y + 12, temporaryMessage);
|
||||
} else if (cannedMessageModule->runState == CANNED_MESSAGE_RUN_STATE_ACK_NACK_RECEIVED) {
|
||||
display->setTextAlignment(TEXT_ALIGN_CENTER);
|
||||
display->setFont(FONT_MEDIUM);
|
||||
String displayString;
|
||||
|
||||
@@ -10,6 +10,7 @@ enum cannedMessageModuleRunState {
|
||||
CANNED_MESSAGE_RUN_STATE_FREETEXT,
|
||||
CANNED_MESSAGE_RUN_STATE_SENDING_ACTIVE,
|
||||
CANNED_MESSAGE_RUN_STATE_ACK_NACK_RECEIVED,
|
||||
CANNED_MESSAGE_RUN_STATE_MESSAGE,
|
||||
CANNED_MESSAGE_RUN_STATE_ACTION_SELECT,
|
||||
CANNED_MESSAGE_RUN_STATE_ACTION_UP,
|
||||
CANNED_MESSAGE_RUN_STATE_ACTION_DOWN,
|
||||
@@ -51,6 +52,8 @@ class CannedMessageModule : public SinglePortModule, public Observable<const UIF
|
||||
void handleGetCannedMessageModuleMessages(const meshtastic_MeshPacket &req, meshtastic_AdminMessage *response);
|
||||
void handleSetCannedMessageModuleMessages(const char *from_msg);
|
||||
|
||||
void showTemporaryMessage(const String &message);
|
||||
|
||||
String drawWithCursor(String text, int cursor);
|
||||
|
||||
/*
|
||||
@@ -112,7 +115,8 @@ class CannedMessageModule : public SinglePortModule, public Observable<const UIF
|
||||
char *messages[CANNED_MESSAGE_MODULE_MESSAGE_MAX_COUNT];
|
||||
int messagesCount = 0;
|
||||
unsigned long lastTouchMillis = 0;
|
||||
String temporaryMessage;
|
||||
};
|
||||
|
||||
extern CannedMessageModule *cannedMessageModule;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
@@ -26,7 +26,18 @@
|
||||
|
||||
#ifdef HAS_NCP5623
|
||||
#include <graphics/RAKled.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAS_NEOPIXEL
|
||||
#include <graphics/NeoPixel.h>
|
||||
#endif
|
||||
|
||||
#ifdef UNPHONE
|
||||
#include "unPhone.h"
|
||||
extern unPhone unphone;
|
||||
#endif
|
||||
|
||||
#if defined(HAS_NCP5623) || defined(RGBLED_RED) || defined(HAS_NEOPIXEL) || defined(UNPHONE)
|
||||
uint8_t red = 0;
|
||||
uint8_t green = 0;
|
||||
uint8_t blue = 0;
|
||||
@@ -108,27 +119,44 @@ int32_t ExternalNotificationModule::runOnce()
|
||||
millis()) {
|
||||
getExternal(2) ? setExternalOff(2) : setExternalOn(2);
|
||||
}
|
||||
#if defined(HAS_NCP5623) || defined(RGBLED_RED) || defined(HAS_NEOPIXEL) || defined(UNPHONE)
|
||||
red = (colorState & 4) ? brightnessValues[brightnessIndex] : 0; // Red enabled on colorState = 4,5,6,7
|
||||
green = (colorState & 2) ? brightnessValues[brightnessIndex] : 0; // Green enabled on colorState = 2,3,6,7
|
||||
blue = (colorState & 1) ? (brightnessValues[brightnessIndex] * 1.5) : 0; // Blue enabled on colorState = 1,3,5,7
|
||||
#ifdef HAS_NCP5623
|
||||
if (rgb_found.type == ScanI2C::NCP5623) {
|
||||
red = (colorState & 4) ? brightnessValues[brightnessIndex] : 0; // Red enabled on colorState = 4,5,6,7
|
||||
green = (colorState & 2) ? brightnessValues[brightnessIndex] : 0; // Green enabled on colorState = 2,3,6,7
|
||||
blue = (colorState & 1) ? (brightnessValues[brightnessIndex] * 1.5) : 0; // Blue enabled on colorState = 1,3,5,7
|
||||
rgb.setColor(red, green, blue);
|
||||
|
||||
if (ascending) { // fade in
|
||||
brightnessIndex++;
|
||||
if (brightnessIndex == (sizeof(brightnessValues) - 1)) {
|
||||
ascending = false;
|
||||
}
|
||||
} else {
|
||||
brightnessIndex--; // fade out
|
||||
}
|
||||
#endif
|
||||
#ifdef RGBLED_CA
|
||||
analogWrite(RGBLED_RED, 255 - red); // CA type needs reverse logic
|
||||
analogWrite(RGBLED_GREEN, 255 - green);
|
||||
analogWrite(RGBLED_BLUE, 255 - blue);
|
||||
#elif defined(RGBLED_RED)
|
||||
analogWrite(RGBLED_RED, red);
|
||||
analogWrite(RGBLED_GREEN, green);
|
||||
analogWrite(RGBLED_BLUE, blue);
|
||||
#endif
|
||||
#ifdef HAS_NEOPIXEL
|
||||
pixels.fill(pixels.Color(red, green, blue), 0, NEOPIXEL_COUNT);
|
||||
pixels.show();
|
||||
#endif
|
||||
#ifdef UNPHONE
|
||||
unphone.rgb(red, green, blue);
|
||||
#endif
|
||||
if (ascending) { // fade in
|
||||
brightnessIndex++;
|
||||
if (brightnessIndex == (sizeof(brightnessValues) - 1)) {
|
||||
ascending = false;
|
||||
}
|
||||
if (brightnessIndex == 0) {
|
||||
ascending = true;
|
||||
colorState++; // next color
|
||||
if (colorState > 7) {
|
||||
colorState = 1;
|
||||
}
|
||||
} else {
|
||||
brightnessIndex--; // fade out
|
||||
}
|
||||
if (brightnessIndex == 0) {
|
||||
ascending = true;
|
||||
colorState++; // next color
|
||||
if (colorState > 7) {
|
||||
colorState = 1;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -179,6 +207,9 @@ void ExternalNotificationModule::setExternalOn(uint8_t index)
|
||||
|
||||
switch (index) {
|
||||
case 1:
|
||||
#ifdef UNPHONE
|
||||
unphone.vibe(true); // the unPhone's vibration motor is on a i2c GPIO expander
|
||||
#endif
|
||||
if (moduleConfig.external_notification.output_vibra)
|
||||
digitalWrite(moduleConfig.external_notification.output_vibra, true);
|
||||
break;
|
||||
@@ -197,6 +228,22 @@ void ExternalNotificationModule::setExternalOn(uint8_t index)
|
||||
rgb.setColor(red, green, blue);
|
||||
}
|
||||
#endif
|
||||
#ifdef RGBLED_CA
|
||||
analogWrite(RGBLED_RED, 255 - red); // CA type needs reverse logic
|
||||
analogWrite(RGBLED_GREEN, 255 - green);
|
||||
analogWrite(RGBLED_BLUE, 255 - blue);
|
||||
#elif defined(RGBLED_RED)
|
||||
analogWrite(RGBLED_RED, red);
|
||||
analogWrite(RGBLED_GREEN, green);
|
||||
analogWrite(RGBLED_BLUE, blue);
|
||||
#endif
|
||||
#ifdef HAS_NEOPIXEL
|
||||
pixels.fill(pixels.Color(red, green, blue), 0, NEOPIXEL_COUNT);
|
||||
pixels.show();
|
||||
#endif
|
||||
#ifdef UNPHONE
|
||||
unphone.rgb(red, green, blue);
|
||||
#endif
|
||||
#ifdef T_WATCH_S3
|
||||
drv.go();
|
||||
#endif
|
||||
@@ -209,6 +256,9 @@ void ExternalNotificationModule::setExternalOff(uint8_t index)
|
||||
|
||||
switch (index) {
|
||||
case 1:
|
||||
#ifdef UNPHONE
|
||||
unphone.vibe(false); // the unPhone's vibration motor is on a i2c GPIO expander
|
||||
#endif
|
||||
if (moduleConfig.external_notification.output_vibra)
|
||||
digitalWrite(moduleConfig.external_notification.output_vibra, false);
|
||||
break;
|
||||
@@ -222,14 +272,33 @@ void ExternalNotificationModule::setExternalOff(uint8_t index)
|
||||
break;
|
||||
}
|
||||
|
||||
#if defined(HAS_NCP5623) || defined(RGBLED_RED) || defined(HAS_NEOPIXEL) || defined(UNPHONE)
|
||||
red = 0;
|
||||
green = 0;
|
||||
blue = 0;
|
||||
#ifdef HAS_NCP5623
|
||||
if (rgb_found.type == ScanI2C::NCP5623) {
|
||||
red = 0;
|
||||
green = 0;
|
||||
blue = 0;
|
||||
rgb.setColor(red, green, blue);
|
||||
}
|
||||
#endif
|
||||
#ifdef RGBLED_CA
|
||||
analogWrite(RGBLED_RED, 255 - red); // CA type needs reverse logic
|
||||
analogWrite(RGBLED_GREEN, 255 - green);
|
||||
analogWrite(RGBLED_BLUE, 255 - blue);
|
||||
#elif defined(RGBLED_RED)
|
||||
analogWrite(RGBLED_RED, red);
|
||||
analogWrite(RGBLED_GREEN, green);
|
||||
analogWrite(RGBLED_BLUE, blue);
|
||||
#endif
|
||||
#ifdef HAS_NEOPIXEL
|
||||
pixels.fill(pixels.Color(red, green, blue), 0, NEOPIXEL_COUNT);
|
||||
pixels.show();
|
||||
#endif
|
||||
#ifdef UNPHONE
|
||||
unphone.rgb(red, green, blue);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef T_WATCH_S3
|
||||
drv.stop();
|
||||
#endif
|
||||
@@ -244,7 +313,8 @@ void ExternalNotificationModule::stopNow()
|
||||
{
|
||||
rtttl::stop();
|
||||
#ifdef HAS_I2S
|
||||
audioThread->stop();
|
||||
if (audioThread->isPlaying())
|
||||
audioThread->stop();
|
||||
#endif
|
||||
nagCycleCutoff = 1; // small value
|
||||
isNagging = false;
|
||||
@@ -327,6 +397,21 @@ ExternalNotificationModule::ExternalNotificationModule()
|
||||
rgb.begin();
|
||||
rgb.setCurrent(10);
|
||||
}
|
||||
#endif
|
||||
#ifdef RGBLED_RED
|
||||
pinMode(RGBLED_RED, OUTPUT); // set up the RGB led pins
|
||||
pinMode(RGBLED_GREEN, OUTPUT);
|
||||
pinMode(RGBLED_BLUE, OUTPUT);
|
||||
#endif
|
||||
#ifdef RGBLED_CA
|
||||
analogWrite(RGBLED_RED, 255); // with a common anode type, logic is reversed
|
||||
analogWrite(RGBLED_GREEN, 255); // so we want to initialise with lights off
|
||||
analogWrite(RGBLED_BLUE, 255);
|
||||
#endif
|
||||
#ifdef HAS_NEOPIXEL
|
||||
pixels.begin(); // Initialise the pixel(s)
|
||||
pixels.clear(); // Set all pixel colors to 'off'
|
||||
pixels.setBrightness(moduleConfig.ambient_lighting.current);
|
||||
#endif
|
||||
} else {
|
||||
LOG_INFO("External Notification Module Disabled\n");
|
||||
@@ -508,4 +593,4 @@ void ExternalNotificationModule::handleSetRingtone(const char *from_msg)
|
||||
if (changed) {
|
||||
nodeDB->saveProto(rtttlConfigFile, meshtastic_RTTTLConfig_size, &meshtastic_RTTTLConfig_msg, &rtttlConfig);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -45,7 +45,7 @@
|
||||
#include "modules/Telemetry/AirQualityTelemetry.h"
|
||||
#include "modules/Telemetry/EnvironmentTelemetry.h"
|
||||
#endif
|
||||
#if HAS_TELEMETRY && !defined(ARCH_PORTDUINO) && !MESHTASTIC_EXCLUDE_POWER_TELEMETRY
|
||||
#if HAS_TELEMETRY && !MESHTASTIC_EXCLUDE_POWER_TELEMETRY
|
||||
#include "modules/Telemetry/PowerTelemetry.h"
|
||||
#endif
|
||||
#ifdef ARCH_ESP32
|
||||
@@ -137,7 +137,7 @@ void setupModules()
|
||||
#if HAS_SCREEN && !MESHTASTIC_EXCLUDE_CANNEDMESSAGES
|
||||
cannedMessageModule = new CannedMessageModule();
|
||||
#endif
|
||||
#if HAS_TELEMETRY && !defined(ARCH_PORTDUINO)
|
||||
#if HAS_TELEMETRY
|
||||
new DeviceTelemetryModule();
|
||||
#endif
|
||||
#if HAS_SENSOR && !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR
|
||||
@@ -146,7 +146,7 @@ void setupModules()
|
||||
new AirQualityTelemetryModule();
|
||||
}
|
||||
#endif
|
||||
#if HAS_TELEMETRY && !defined(ARCH_PORTDUINO) && !MESHTASTIC_EXCLUDE_POWER_TELEMETRY
|
||||
#if HAS_TELEMETRY && !MESHTASTIC_EXCLUDE_POWER_TELEMETRY && !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR
|
||||
new PowerTelemetryModule();
|
||||
#endif
|
||||
#if (defined(ARCH_ESP32) || defined(ARCH_NRF52) || defined(ARCH_RP2040)) && !defined(CONFIG_IDF_TARGET_ESP32S2) && \
|
||||
|
||||
@@ -4,11 +4,8 @@
|
||||
#include "NodeDB.h"
|
||||
#include "RTC.h"
|
||||
|
||||
#define MAX_NUM_NEIGHBORS 10 // also defined in NeighborInfo protobuf options
|
||||
NeighborInfoModule *neighborInfoModule;
|
||||
|
||||
static const char *neighborInfoConfigFile = "/prefs/neighbors.proto";
|
||||
|
||||
/*
|
||||
Prints a single neighbor info packet and associated neighbors
|
||||
Uses LOG_DEBUG, which equates to Console.log
|
||||
@@ -30,26 +27,23 @@ NOTE: for debugging only
|
||||
*/
|
||||
void NeighborInfoModule::printNodeDBNeighbors()
|
||||
{
|
||||
int num_neighbors = getNumNeighbors();
|
||||
LOG_DEBUG("Our NodeDB contains %d neighbors\n", num_neighbors);
|
||||
for (int i = 0; i < num_neighbors; i++) {
|
||||
const meshtastic_Neighbor *dbEntry = getNeighborByIndex(i);
|
||||
LOG_DEBUG(" Node %d: node_id=0x%x, snr=%.2f\n", i, dbEntry->node_id, dbEntry->snr);
|
||||
LOG_DEBUG("Our NodeDB contains %d neighbors\n", neighbors.size());
|
||||
for (size_t i = 0; i < neighbors.size(); i++) {
|
||||
LOG_DEBUG("Node %d: node_id=0x%x, snr=%.2f\n", i, neighbors[i].node_id, neighbors[i].snr);
|
||||
}
|
||||
}
|
||||
|
||||
/* Send our initial owner announcement 35 seconds after we start (to give network time to setup) */
|
||||
NeighborInfoModule::NeighborInfoModule()
|
||||
: ProtobufModule("neighborinfo", meshtastic_PortNum_NEIGHBORINFO_APP, &meshtastic_NeighborInfo_msg),
|
||||
concurrency::OSThread("NeighborInfoModule"), neighbors(neighborState.neighbors),
|
||||
numNeighbors(&neighborState.neighbors_count)
|
||||
concurrency::OSThread("NeighborInfoModule")
|
||||
{
|
||||
ourPortNum = meshtastic_PortNum_NEIGHBORINFO_APP;
|
||||
|
||||
if (moduleConfig.neighbor_info.enabled) {
|
||||
isPromiscuous = true; // Update neighbors from all packets
|
||||
this->loadProtoForModule();
|
||||
setIntervalFromNow(35 * 1000);
|
||||
setIntervalFromNow(
|
||||
Default::getConfiguredOrDefaultMs(moduleConfig.neighbor_info.update_interval, default_broadcast_interval_secs));
|
||||
} else {
|
||||
LOG_DEBUG("NeighborInfoModule is disabled\n");
|
||||
disable();
|
||||
@@ -63,18 +57,17 @@ Assumes that the neighborInfo packet has been allocated
|
||||
*/
|
||||
uint32_t NeighborInfoModule::collectNeighborInfo(meshtastic_NeighborInfo *neighborInfo)
|
||||
{
|
||||
uint my_node_id = nodeDB->getNodeNum();
|
||||
NodeNum my_node_id = nodeDB->getNodeNum();
|
||||
neighborInfo->node_id = my_node_id;
|
||||
neighborInfo->last_sent_by_id = my_node_id;
|
||||
neighborInfo->node_broadcast_interval_secs = moduleConfig.neighbor_info.update_interval;
|
||||
|
||||
int num_neighbors = cleanUpNeighbors();
|
||||
cleanUpNeighbors();
|
||||
|
||||
for (int i = 0; i < num_neighbors; i++) {
|
||||
const meshtastic_Neighbor *dbEntry = getNeighborByIndex(i);
|
||||
if ((neighborInfo->neighbors_count < MAX_NUM_NEIGHBORS) && (dbEntry->node_id != my_node_id)) {
|
||||
neighborInfo->neighbors[neighborInfo->neighbors_count].node_id = dbEntry->node_id;
|
||||
neighborInfo->neighbors[neighborInfo->neighbors_count].snr = dbEntry->snr;
|
||||
for (auto nbr : neighbors) {
|
||||
if ((neighborInfo->neighbors_count < MAX_NUM_NEIGHBORS) && (nbr.node_id != my_node_id)) {
|
||||
neighborInfo->neighbors[neighborInfo->neighbors_count].node_id = nbr.node_id;
|
||||
neighborInfo->neighbors[neighborInfo->neighbors_count].snr = nbr.snr;
|
||||
// Note: we don't set the last_rx_time and node_broadcast_intervals_secs here, because we don't want to send this over
|
||||
// the mesh
|
||||
neighborInfo->neighbors_count++;
|
||||
@@ -85,41 +78,22 @@ uint32_t NeighborInfoModule::collectNeighborInfo(meshtastic_NeighborInfo *neighb
|
||||
}
|
||||
|
||||
/*
|
||||
Remove neighbors from the database that we haven't heard from in a while
|
||||
@returns new number of neighbors
|
||||
Remove neighbors from the database that we haven't heard from in a while
|
||||
*/
|
||||
size_t NeighborInfoModule::cleanUpNeighbors()
|
||||
void NeighborInfoModule::cleanUpNeighbors()
|
||||
{
|
||||
uint32_t now = getTime();
|
||||
int num_neighbors = getNumNeighbors();
|
||||
NodeNum my_node_id = nodeDB->getNodeNum();
|
||||
|
||||
// Find neighbors to remove
|
||||
std::vector<int> indices_to_remove;
|
||||
for (int i = 0; i < num_neighbors; i++) {
|
||||
const meshtastic_Neighbor *dbEntry = getNeighborByIndex(i);
|
||||
for (auto it = neighbors.rbegin(); it != neighbors.rend();) {
|
||||
// We will remove a neighbor if we haven't heard from them in twice the broadcast interval
|
||||
if ((now - dbEntry->last_rx_time > dbEntry->node_broadcast_interval_secs * 2) && (dbEntry->node_id != my_node_id)) {
|
||||
indices_to_remove.push_back(i);
|
||||
if ((now - it->last_rx_time > it->node_broadcast_interval_secs * 2) && (it->node_id != my_node_id)) {
|
||||
LOG_DEBUG("Removing neighbor with node ID 0x%x\n", it->node_id);
|
||||
it = std::vector<meshtastic_Neighbor>::reverse_iterator(
|
||||
neighbors.erase(std::next(it).base())); // Erase the element and update the iterator
|
||||
} else {
|
||||
++it;
|
||||
}
|
||||
}
|
||||
|
||||
// Update the neighbor list
|
||||
for (uint i = 0; i < indices_to_remove.size(); i++) {
|
||||
int index = indices_to_remove[i];
|
||||
LOG_DEBUG("Removing neighbor with node ID 0x%x\n", neighbors[index].node_id);
|
||||
for (int j = index; j < num_neighbors - 1; j++) {
|
||||
neighbors[j] = neighbors[j + 1];
|
||||
}
|
||||
(*numNeighbors)--;
|
||||
}
|
||||
|
||||
// Save the neighbor list if we removed any neighbors or neighbors were already updated upon receiving a packet
|
||||
if (indices_to_remove.size() > 0 || shouldSave) {
|
||||
saveProtoForModule();
|
||||
}
|
||||
|
||||
return *numNeighbors;
|
||||
}
|
||||
|
||||
/* Send neighbor info to the mesh */
|
||||
@@ -142,8 +116,9 @@ Will be used for broadcast.
|
||||
*/
|
||||
int32_t NeighborInfoModule::runOnce()
|
||||
{
|
||||
bool requestReplies = false;
|
||||
sendNeighborInfo(NODENUM_BROADCAST, requestReplies);
|
||||
if (airTime->isTxAllowedChannelUtil(true) && airTime->isTxAllowedAirUtil()) {
|
||||
sendNeighborInfo(NODENUM_BROADCAST, false);
|
||||
}
|
||||
return Default::getConfiguredOrDefaultMs(moduleConfig.neighbor_info.update_interval, default_broadcast_interval_secs);
|
||||
}
|
||||
|
||||
@@ -178,10 +153,7 @@ void NeighborInfoModule::alterReceivedProtobuf(meshtastic_MeshPacket &p, meshtas
|
||||
|
||||
void NeighborInfoModule::resetNeighbors()
|
||||
{
|
||||
*numNeighbors = 0;
|
||||
neighborState.neighbors_count = 0;
|
||||
memset(neighborState.neighbors, 0, sizeof(neighborState.neighbors));
|
||||
saveProtoForModule();
|
||||
neighbors.clear();
|
||||
}
|
||||
|
||||
void NeighborInfoModule::updateNeighbors(const meshtastic_MeshPacket &mp, const meshtastic_NeighborInfo *np)
|
||||
@@ -201,61 +173,36 @@ meshtastic_Neighbor *NeighborInfoModule::getOrCreateNeighbor(NodeNum originalSen
|
||||
n = nodeDB->getNodeNum();
|
||||
}
|
||||
// look for one in the existing list
|
||||
for (int i = 0; i < (*numNeighbors); i++) {
|
||||
meshtastic_Neighbor *nbr = &neighbors[i];
|
||||
if (nbr->node_id == n) {
|
||||
for (size_t i = 0; i < neighbors.size(); i++) {
|
||||
if (neighbors[i].node_id == n) {
|
||||
// if found, update it
|
||||
nbr->snr = snr;
|
||||
nbr->last_rx_time = getTime();
|
||||
neighbors[i].snr = snr;
|
||||
neighbors[i].last_rx_time = getTime();
|
||||
// Only if this is the original sender, the broadcast interval corresponds to it
|
||||
if (originalSender == n && node_broadcast_interval_secs != 0)
|
||||
nbr->node_broadcast_interval_secs = node_broadcast_interval_secs;
|
||||
return nbr;
|
||||
neighbors[i].node_broadcast_interval_secs = node_broadcast_interval_secs;
|
||||
return &neighbors[i];
|
||||
}
|
||||
}
|
||||
// otherwise, allocate one and assign data to it
|
||||
// TODO: max memory for the database should take neighbors into account, but currently doesn't
|
||||
if (*numNeighbors < MAX_NUM_NEIGHBORS) {
|
||||
(*numNeighbors)++;
|
||||
}
|
||||
meshtastic_Neighbor *new_nbr = &neighbors[((*numNeighbors) - 1)];
|
||||
new_nbr->node_id = n;
|
||||
new_nbr->snr = snr;
|
||||
new_nbr->last_rx_time = getTime();
|
||||
|
||||
meshtastic_Neighbor new_nbr = meshtastic_Neighbor_init_zero;
|
||||
new_nbr.node_id = n;
|
||||
new_nbr.snr = snr;
|
||||
new_nbr.last_rx_time = getTime();
|
||||
// Only if this is the original sender, the broadcast interval corresponds to it
|
||||
if (originalSender == n && node_broadcast_interval_secs != 0)
|
||||
new_nbr->node_broadcast_interval_secs = node_broadcast_interval_secs;
|
||||
new_nbr.node_broadcast_interval_secs = node_broadcast_interval_secs;
|
||||
else // Assume the same broadcast interval as us for the neighbor if we don't know it
|
||||
new_nbr->node_broadcast_interval_secs = moduleConfig.neighbor_info.update_interval;
|
||||
shouldSave = true; // Save the new neighbor upon next cleanup
|
||||
return new_nbr;
|
||||
}
|
||||
new_nbr.node_broadcast_interval_secs = moduleConfig.neighbor_info.update_interval;
|
||||
|
||||
void NeighborInfoModule::loadProtoForModule()
|
||||
{
|
||||
if (nodeDB->loadProto(neighborInfoConfigFile, meshtastic_NeighborInfo_size, sizeof(meshtastic_NeighborInfo),
|
||||
&meshtastic_NeighborInfo_msg, &neighborState) != LoadFileResult::SUCCESS) {
|
||||
neighborState = meshtastic_NeighborInfo_init_zero;
|
||||
if (neighbors.size() < MAX_NUM_NEIGHBORS) {
|
||||
neighbors.push_back(new_nbr);
|
||||
} else {
|
||||
// If we have too many neighbors, replace the oldest one
|
||||
LOG_WARN("Neighbor DB is full, replacing oldest neighbor\n");
|
||||
neighbors.erase(neighbors.begin());
|
||||
neighbors.push_back(new_nbr);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Save the module config to file.
|
||||
*
|
||||
* @return true On success.
|
||||
* @return false On error.
|
||||
*/
|
||||
bool NeighborInfoModule::saveProtoForModule()
|
||||
{
|
||||
bool okay = true;
|
||||
|
||||
#ifdef FS
|
||||
FS.mkdir("/prefs");
|
||||
#endif
|
||||
|
||||
okay &= nodeDB->saveProto(neighborInfoConfigFile, meshtastic_NeighborInfo_size, &meshtastic_NeighborInfo_msg, &neighborState);
|
||||
if (okay)
|
||||
shouldSave = false;
|
||||
|
||||
return okay;
|
||||
return &neighbors.back();
|
||||
}
|
||||
@@ -1,13 +1,13 @@
|
||||
#pragma once
|
||||
#include "ProtobufModule.h"
|
||||
#define MAX_NUM_NEIGHBORS 10 // also defined in NeighborInfo protobuf options
|
||||
|
||||
/*
|
||||
* Neighborinfo module for sending info on each node's 0-hop neighbors to the mesh
|
||||
*/
|
||||
class NeighborInfoModule : public ProtobufModule<meshtastic_NeighborInfo>, private concurrency::OSThread
|
||||
{
|
||||
meshtastic_Neighbor *neighbors;
|
||||
pb_size_t *numNeighbors;
|
||||
std::vector<meshtastic_Neighbor> neighbors;
|
||||
|
||||
public:
|
||||
/*
|
||||
@@ -18,15 +18,7 @@ class NeighborInfoModule : public ProtobufModule<meshtastic_NeighborInfo>, priva
|
||||
/* Reset neighbor info after clearing nodeDB*/
|
||||
void resetNeighbors();
|
||||
|
||||
bool saveProtoForModule();
|
||||
|
||||
private:
|
||||
bool shouldSave = false; // Whether we should save the neighbor info to flash
|
||||
|
||||
protected:
|
||||
// Note: this holds our local info.
|
||||
meshtastic_NeighborInfo neighborState;
|
||||
|
||||
/*
|
||||
* Called to handle a particular incoming message
|
||||
* @return true if you've guaranteed you've handled this message and no other handlers should be considered for it
|
||||
@@ -40,10 +32,9 @@ class NeighborInfoModule : public ProtobufModule<meshtastic_NeighborInfo>, priva
|
||||
uint32_t collectNeighborInfo(meshtastic_NeighborInfo *neighborInfo);
|
||||
|
||||
/*
|
||||
Remove neighbors from the database that we haven't heard from in a while
|
||||
@returns new number of neighbors
|
||||
Remove neighbors from the database that we haven't heard from in a while
|
||||
*/
|
||||
size_t cleanUpNeighbors();
|
||||
void cleanUpNeighbors();
|
||||
|
||||
/* Allocate a new NeighborInfo packet */
|
||||
meshtastic_NeighborInfo *allocateNeighborInfoPacket();
|
||||
@@ -56,22 +47,12 @@ class NeighborInfoModule : public ProtobufModule<meshtastic_NeighborInfo>, priva
|
||||
*/
|
||||
void sendNeighborInfo(NodeNum dest = NODENUM_BROADCAST, bool wantReplies = false);
|
||||
|
||||
size_t getNumNeighbors() { return *numNeighbors; }
|
||||
|
||||
meshtastic_Neighbor *getNeighborByIndex(size_t x)
|
||||
{
|
||||
assert(x < *numNeighbors);
|
||||
return &neighbors[x];
|
||||
}
|
||||
|
||||
/* update neighbors with subpacket sniffed from network */
|
||||
void updateNeighbors(const meshtastic_MeshPacket &mp, const meshtastic_NeighborInfo *np);
|
||||
|
||||
/* update a NeighborInfo packet with our NodeNum as last_sent_by_id */
|
||||
void alterReceivedProtobuf(meshtastic_MeshPacket &p, meshtastic_NeighborInfo *n) override;
|
||||
|
||||
void loadProtoForModule();
|
||||
|
||||
/* Does our periodic broadcast */
|
||||
int32_t runOnce() override;
|
||||
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
|
||||
extern "C" {
|
||||
#include "mesh/compression/unishox2.h"
|
||||
#include <Throttle.h>
|
||||
}
|
||||
|
||||
PositionModule *positionModule;
|
||||
@@ -63,21 +64,15 @@ bool PositionModule::handleReceivedProtobuf(const meshtastic_MeshPacket &mp, mes
|
||||
}
|
||||
|
||||
// Log packet size and data fields
|
||||
LOG_INFO("POSITION node=%08x l=%d latI=%d lonI=%d msl=%d hae=%d geo=%d pdop=%d hdop=%d vdop=%d siv=%d fxq=%d fxt=%d pts=%d "
|
||||
"time=%d\n",
|
||||
getFrom(&mp), mp.decoded.payload.size, p.latitude_i, p.longitude_i, p.altitude, p.altitude_hae,
|
||||
p.altitude_geoidal_separation, p.PDOP, p.HDOP, p.VDOP, p.sats_in_view, p.fix_quality, p.fix_type, p.timestamp,
|
||||
p.time);
|
||||
LOG_DEBUG("POSITION node=%08x l=%d latI=%d lonI=%d msl=%d hae=%d geo=%d pdop=%d hdop=%d vdop=%d siv=%d fxq=%d fxt=%d pts=%d "
|
||||
"time=%d\n",
|
||||
getFrom(&mp), mp.decoded.payload.size, p.latitude_i, p.longitude_i, p.altitude, p.altitude_hae,
|
||||
p.altitude_geoidal_separation, p.PDOP, p.HDOP, p.VDOP, p.sats_in_view, p.fix_quality, p.fix_type, p.timestamp,
|
||||
p.time);
|
||||
|
||||
if (p.time && channels.getByIndex(mp.channel).role == meshtastic_Channel_Role_PRIMARY) {
|
||||
struct timeval tv;
|
||||
uint32_t secs = p.time;
|
||||
|
||||
tv.tv_sec = secs;
|
||||
tv.tv_usec = 0;
|
||||
|
||||
// Set from phone RTC Quality to RTCQualityNTP since it should be approximately so
|
||||
perhapsSetRTC(isLocal ? RTCQualityNTP : RTCQualityFromNet, &tv);
|
||||
trySetRtc(p, isLocal);
|
||||
}
|
||||
|
||||
nodeDB->updatePosition(getFrom(&mp), p);
|
||||
@@ -92,6 +87,33 @@ bool PositionModule::handleReceivedProtobuf(const meshtastic_MeshPacket &mp, mes
|
||||
return false; // Let others look at this message also if they want
|
||||
}
|
||||
|
||||
void PositionModule::alterReceivedProtobuf(meshtastic_MeshPacket &mp, meshtastic_Position *p)
|
||||
{
|
||||
// Phone position packets need to be truncated to the channel precision
|
||||
if (nodeDB->getNodeNum() == getFrom(&mp) && (precision < 32 && precision > 0)) {
|
||||
LOG_DEBUG("Truncating phone position to channel precision %i\n", precision);
|
||||
p->latitude_i = p->latitude_i & (UINT32_MAX << (32 - precision));
|
||||
p->longitude_i = p->longitude_i & (UINT32_MAX << (32 - precision));
|
||||
|
||||
// We want the imprecise position to be the middle of the possible location, not
|
||||
p->latitude_i += (1 << (31 - precision));
|
||||
p->longitude_i += (1 << (31 - precision));
|
||||
|
||||
mp.decoded.payload.size =
|
||||
pb_encode_to_bytes(mp.decoded.payload.bytes, sizeof(mp.decoded.payload.bytes), &meshtastic_Position_msg, p);
|
||||
}
|
||||
}
|
||||
|
||||
void PositionModule::trySetRtc(meshtastic_Position p, bool isLocal)
|
||||
{
|
||||
struct timeval tv;
|
||||
uint32_t secs = p.time;
|
||||
|
||||
tv.tv_sec = secs;
|
||||
tv.tv_usec = 0;
|
||||
perhapsSetRTC(isLocal ? RTCQualityNTP : RTCQualityFromNet, &tv);
|
||||
}
|
||||
|
||||
meshtastic_MeshPacket *PositionModule::allocReply()
|
||||
{
|
||||
if (precision == 0) {
|
||||
@@ -222,6 +244,16 @@ meshtastic_MeshPacket *PositionModule::allocAtakPli()
|
||||
return mp;
|
||||
}
|
||||
|
||||
void PositionModule::sendOurPosition()
|
||||
{
|
||||
bool requestReplies = currentGeneration != radioGeneration;
|
||||
currentGeneration = radioGeneration;
|
||||
|
||||
// If we changed channels, ask everyone else for their latest info
|
||||
LOG_INFO("Sending pos@%x:6 to mesh (wantReplies=%d)\n", localPosition.timestamp, requestReplies);
|
||||
sendOurPosition(NODENUM_BROADCAST, requestReplies);
|
||||
}
|
||||
|
||||
void PositionModule::sendOurPosition(NodeNum dest, bool wantReplies, uint8_t channel)
|
||||
{
|
||||
// cancel any not yet sent (now stale) position packets
|
||||
@@ -299,12 +331,7 @@ int32_t PositionModule::runOnce()
|
||||
lastGpsLatitude = node->position.latitude_i;
|
||||
lastGpsLongitude = node->position.longitude_i;
|
||||
|
||||
// If we changed channels, ask everyone else for their latest info
|
||||
bool requestReplies = currentGeneration != radioGeneration;
|
||||
currentGeneration = radioGeneration;
|
||||
|
||||
LOG_INFO("Sending pos@%x:6 to mesh (wantReplies=%d)\n", localPosition.timestamp, requestReplies);
|
||||
sendOurPosition(NODENUM_BROADCAST, requestReplies);
|
||||
sendOurPosition();
|
||||
if (config.device.role == meshtastic_Config_DeviceConfig_Role_LOST_AND_FOUND) {
|
||||
sendLostAndFoundText();
|
||||
}
|
||||
@@ -314,29 +341,23 @@ int32_t PositionModule::runOnce()
|
||||
|
||||
if (hasValidPosition(node2)) {
|
||||
// The minimum time (in seconds) that would pass before we are able to send a new position packet.
|
||||
const uint32_t minimumTimeThreshold =
|
||||
Default::getConfiguredOrDefaultMs(config.position.broadcast_smart_minimum_interval_secs, 30);
|
||||
|
||||
auto smartPosition = getDistanceTraveledSinceLastSend(node->position);
|
||||
msSinceLastSend = now - lastGpsSend;
|
||||
|
||||
if (smartPosition.hasTraveledOverThreshold && msSinceLastSend >= minimumTimeThreshold) {
|
||||
bool requestReplies = currentGeneration != radioGeneration;
|
||||
currentGeneration = radioGeneration;
|
||||
if (smartPosition.hasTraveledOverThreshold &&
|
||||
Throttle::execute(
|
||||
&lastGpsSend, minimumTimeThreshold, []() { positionModule->sendOurPosition(); },
|
||||
[]() { LOG_DEBUG("Skipping send smart broadcast due to time throttling\n"); })) {
|
||||
|
||||
LOG_INFO("Sending smart pos@%x:6 to mesh (distanceTraveled=%fm, minDistanceThreshold=%im, timeElapsed=%ims, "
|
||||
"minTimeInterval=%ims)\n",
|
||||
localPosition.timestamp, smartPosition.distanceTraveled, smartPosition.distanceThreshold,
|
||||
msSinceLastSend, minimumTimeThreshold);
|
||||
sendOurPosition(NODENUM_BROADCAST, requestReplies);
|
||||
LOG_DEBUG("Sent smart pos@%x:6 to mesh (distanceTraveled=%fm, minDistanceThreshold=%im, timeElapsed=%ims, "
|
||||
"minTimeInterval=%ims)\n",
|
||||
localPosition.timestamp, smartPosition.distanceTraveled, smartPosition.distanceThreshold,
|
||||
msSinceLastSend, minimumTimeThreshold);
|
||||
|
||||
// Set the current coords as our last ones, after we've compared distance with current and decided to send
|
||||
lastGpsLatitude = node->position.latitude_i;
|
||||
lastGpsLongitude = node->position.longitude_i;
|
||||
|
||||
/* Update lastGpsSend to now. This means if the device is stationary, then
|
||||
getPref_position_broadcast_secs will still apply.
|
||||
*/
|
||||
lastGpsSend = now;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -396,27 +417,21 @@ void PositionModule::handleNewPosition()
|
||||
meshtastic_NodeInfoLite *node = nodeDB->getMeshNode(nodeDB->getNodeNum());
|
||||
const meshtastic_NodeInfoLite *node2 = service.refreshLocalMeshNode(); // should guarantee there is now a position
|
||||
// We limit our GPS broadcasts to a max rate
|
||||
uint32_t now = millis();
|
||||
uint32_t msSinceLastSend = now - lastGpsSend;
|
||||
|
||||
if (hasValidPosition(node2)) {
|
||||
auto smartPosition = getDistanceTraveledSinceLastSend(node->position);
|
||||
if (smartPosition.hasTraveledOverThreshold) {
|
||||
bool requestReplies = currentGeneration != radioGeneration;
|
||||
currentGeneration = radioGeneration;
|
||||
|
||||
LOG_INFO("Sending smart pos@%x:6 to mesh (distanceTraveled=%fm, minDistanceThreshold=%im, timeElapsed=%ims)\n",
|
||||
localPosition.timestamp, smartPosition.distanceTraveled, smartPosition.distanceThreshold, msSinceLastSend);
|
||||
sendOurPosition(NODENUM_BROADCAST, requestReplies);
|
||||
uint32_t msSinceLastSend = millis() - lastGpsSend;
|
||||
if (smartPosition.hasTraveledOverThreshold &&
|
||||
Throttle::execute(
|
||||
&lastGpsSend, minimumTimeThreshold, []() { positionModule->sendOurPosition(); },
|
||||
[]() { LOG_DEBUG("Skipping send smart broadcast due to time throttling\n"); })) {
|
||||
LOG_DEBUG("Sent smart pos@%x:6 to mesh (distanceTraveled=%fm, minDistanceThreshold=%im, timeElapsed=%ims, "
|
||||
"minTimeInterval=%ims)\n",
|
||||
localPosition.timestamp, smartPosition.distanceTraveled, smartPosition.distanceThreshold, msSinceLastSend,
|
||||
minimumTimeThreshold);
|
||||
|
||||
// Set the current coords as our last ones, after we've compared distance with current and decided to send
|
||||
lastGpsLatitude = node->position.latitude_i;
|
||||
lastGpsLongitude = node->position.longitude_i;
|
||||
|
||||
/* Update lastGpsSend to now. This means if the device is stationary, then
|
||||
getPref_position_broadcast_secs will still apply.
|
||||
*/
|
||||
lastGpsSend = now;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
#pragma once
|
||||
#include "Default.h"
|
||||
#include "ProtobufModule.h"
|
||||
#include "concurrency/OSThread.h"
|
||||
|
||||
@@ -29,7 +30,8 @@ class PositionModule : public ProtobufModule<meshtastic_Position>, private concu
|
||||
/**
|
||||
* Send our position into the mesh
|
||||
*/
|
||||
void sendOurPosition(NodeNum dest = NODENUM_BROADCAST, bool wantReplies = false, uint8_t channel = 0);
|
||||
void sendOurPosition(NodeNum dest, bool wantReplies = false, uint8_t channel = 0);
|
||||
void sendOurPosition();
|
||||
|
||||
void handleNewPosition();
|
||||
|
||||
@@ -40,6 +42,8 @@ class PositionModule : public ProtobufModule<meshtastic_Position>, private concu
|
||||
*/
|
||||
virtual bool handleReceivedProtobuf(const meshtastic_MeshPacket &mp, meshtastic_Position *p) override;
|
||||
|
||||
virtual void alterReceivedProtobuf(meshtastic_MeshPacket &mp, meshtastic_Position *p) override;
|
||||
|
||||
/** 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. */
|
||||
virtual meshtastic_MeshPacket *allocReply() override;
|
||||
@@ -50,8 +54,12 @@ class PositionModule : public ProtobufModule<meshtastic_Position>, private concu
|
||||
private:
|
||||
struct SmartPosition getDistanceTraveledSinceLastSend(meshtastic_PositionLite currentPosition);
|
||||
meshtastic_MeshPacket *allocAtakPli();
|
||||
void trySetRtc(meshtastic_Position p, bool isLocal);
|
||||
uint32_t precision;
|
||||
void sendLostAndFoundText();
|
||||
|
||||
const uint32_t minimumTimeThreshold =
|
||||
Default::getConfiguredOrDefaultMs(config.position.broadcast_smart_minimum_interval_secs, 30);
|
||||
};
|
||||
|
||||
struct SmartPosition {
|
||||
|
||||
@@ -51,7 +51,7 @@ uint8_t RoutingModule::getHopLimitForResponse(uint8_t hopStart, uint8_t hopLimit
|
||||
uint8_t hopsUsed = hopStart < hopLimit ? config.lora.hop_limit : hopStart - hopLimit;
|
||||
if (hopsUsed > config.lora.hop_limit) {
|
||||
return hopsUsed; // If the request used more hops than the limit, use the same amount of hops
|
||||
} else if (hopsUsed + 2 < config.lora.hop_limit) {
|
||||
} else if ((uint8_t)(hopsUsed + 2) < config.lora.hop_limit) {
|
||||
return hopsUsed + 2; // Use only the amount of hops needed with some margin as the way back may be different
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,12 +1,15 @@
|
||||
#include "AirQualityTelemetry.h"
|
||||
#include "configuration.h"
|
||||
|
||||
#if !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR
|
||||
|
||||
#include "../mesh/generated/meshtastic/telemetry.pb.h"
|
||||
#include "AirQualityTelemetry.h"
|
||||
#include "Default.h"
|
||||
#include "MeshService.h"
|
||||
#include "NodeDB.h"
|
||||
#include "PowerFSM.h"
|
||||
#include "RTC.h"
|
||||
#include "Router.h"
|
||||
#include "configuration.h"
|
||||
#include "main.h"
|
||||
|
||||
int32_t AirQualityTelemetryModule::runOnce()
|
||||
@@ -130,3 +133,5 @@ bool AirQualityTelemetryModule::sendTelemetry(NodeNum dest, bool phoneOnly)
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,3 +1,7 @@
|
||||
#include "configuration.h"
|
||||
|
||||
#if !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR
|
||||
|
||||
#pragma once
|
||||
#include "../mesh/generated/meshtastic/telemetry.pb.h"
|
||||
#include "Adafruit_PM25AQI.h"
|
||||
@@ -35,3 +39,5 @@ class AirQualityTelemetryModule : private concurrency::OSThread, public Protobuf
|
||||
uint32_t sendToPhoneIntervalMs = SECONDS_IN_MINUTE * 1000; // Send to phone every minute
|
||||
uint32_t lastSentToMesh = 0;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -1,12 +1,15 @@
|
||||
#include "EnvironmentTelemetry.h"
|
||||
#include "configuration.h"
|
||||
|
||||
#if !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR
|
||||
|
||||
#include "../mesh/generated/meshtastic/telemetry.pb.h"
|
||||
#include "Default.h"
|
||||
#include "EnvironmentTelemetry.h"
|
||||
#include "MeshService.h"
|
||||
#include "NodeDB.h"
|
||||
#include "PowerFSM.h"
|
||||
#include "RTC.h"
|
||||
#include "Router.h"
|
||||
#include "configuration.h"
|
||||
#include "main.h"
|
||||
#include "power.h"
|
||||
#include "sleep.h"
|
||||
@@ -21,7 +24,9 @@
|
||||
#include "Sensor/BMP280Sensor.h"
|
||||
#include "Sensor/LPS22HBSensor.h"
|
||||
#include "Sensor/MCP9808Sensor.h"
|
||||
#include "Sensor/RCWL9620Sensor.h"
|
||||
#include "Sensor/SHT31Sensor.h"
|
||||
#include "Sensor/SHT4XSensor.h"
|
||||
#include "Sensor/SHTC3Sensor.h"
|
||||
|
||||
BMP085Sensor bmp085Sensor;
|
||||
@@ -32,6 +37,8 @@ MCP9808Sensor mcp9808Sensor;
|
||||
SHTC3Sensor shtc3Sensor;
|
||||
LPS22HBSensor lps22hbSensor;
|
||||
SHT31Sensor sht31Sensor;
|
||||
SHT4XSensor sht4xSensor;
|
||||
RCWL9620Sensor rcwl9620Sensor;
|
||||
|
||||
#define FAILED_STATE_SENSOR_READ_MULTIPLIER 10
|
||||
#define DISPLAY_RECEIVEID_MEASUREMENTS_ON_SCREEN true
|
||||
@@ -86,10 +93,14 @@ int32_t EnvironmentTelemetryModule::runOnce()
|
||||
result = lps22hbSensor.runOnce();
|
||||
if (sht31Sensor.hasSensor())
|
||||
result = sht31Sensor.runOnce();
|
||||
if (sht4xSensor.hasSensor())
|
||||
result = sht4xSensor.runOnce();
|
||||
if (ina219Sensor.hasSensor())
|
||||
result = ina219Sensor.runOnce();
|
||||
if (ina260Sensor.hasSensor())
|
||||
result = ina260Sensor.runOnce();
|
||||
if (rcwl9620Sensor.hasSensor())
|
||||
result = rcwl9620Sensor.runOnce();
|
||||
}
|
||||
return result;
|
||||
} else {
|
||||
@@ -144,45 +155,56 @@ uint32_t GetTimeSinceMeshPacket(const meshtastic_MeshPacket *mp)
|
||||
void EnvironmentTelemetryModule::drawFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y)
|
||||
{
|
||||
display->setTextAlignment(TEXT_ALIGN_LEFT);
|
||||
display->setFont(FONT_MEDIUM);
|
||||
display->drawString(x, y, "Environment");
|
||||
display->setFont(FONT_SMALL);
|
||||
|
||||
if (lastMeasurementPacket == nullptr) {
|
||||
display->setFont(FONT_SMALL);
|
||||
display->drawString(x, y += fontHeight(FONT_MEDIUM), "No measurement");
|
||||
// If there's no valid packet, display "Environment"
|
||||
display->drawString(x, y, "Environment");
|
||||
display->drawString(x, y += fontHeight(FONT_SMALL), "No measurement");
|
||||
return;
|
||||
}
|
||||
|
||||
// Decode the last measurement packet
|
||||
meshtastic_Telemetry lastMeasurement;
|
||||
|
||||
uint32_t agoSecs = GetTimeSinceMeshPacket(lastMeasurementPacket);
|
||||
const char *lastSender = getSenderShortName(*lastMeasurementPacket);
|
||||
|
||||
auto &p = lastMeasurementPacket->decoded;
|
||||
if (!pb_decode_from_bytes(p.payload.bytes, p.payload.size, &meshtastic_Telemetry_msg, &lastMeasurement)) {
|
||||
display->setFont(FONT_SMALL);
|
||||
display->drawString(x, y += fontHeight(FONT_MEDIUM), "Measurement Error");
|
||||
display->drawString(x, y, "Measurement Error");
|
||||
LOG_ERROR("Unable to decode last packet");
|
||||
return;
|
||||
}
|
||||
|
||||
display->setFont(FONT_SMALL);
|
||||
// Display "Env. From: ..." on its own
|
||||
display->drawString(x, y, "Env. From: " + String(lastSender) + "(" + String(agoSecs) + "s)");
|
||||
|
||||
String last_temp = String(lastMeasurement.variant.environment_metrics.temperature, 0) + "°C";
|
||||
if (moduleConfig.telemetry.environment_display_fahrenheit) {
|
||||
last_temp = String(CelsiusToFahrenheit(lastMeasurement.variant.environment_metrics.temperature), 0) + "°F";
|
||||
}
|
||||
display->drawString(x, y += fontHeight(FONT_MEDIUM) - 2, "From: " + String(lastSender) + "(" + String(agoSecs) + "s)");
|
||||
display->drawString(x, y += fontHeight(FONT_SMALL) - 2,
|
||||
|
||||
// Continue with the remaining details
|
||||
display->drawString(x, y += fontHeight(FONT_SMALL),
|
||||
"Temp/Hum: " + last_temp + " / " +
|
||||
String(lastMeasurement.variant.environment_metrics.relative_humidity, 0) + "%");
|
||||
if (lastMeasurement.variant.environment_metrics.barometric_pressure != 0)
|
||||
|
||||
if (lastMeasurement.variant.environment_metrics.barometric_pressure != 0) {
|
||||
display->drawString(x, y += fontHeight(FONT_SMALL),
|
||||
"Press: " + String(lastMeasurement.variant.environment_metrics.barometric_pressure, 0) + "hPA");
|
||||
if (lastMeasurement.variant.environment_metrics.voltage != 0)
|
||||
}
|
||||
|
||||
if (lastMeasurement.variant.environment_metrics.voltage != 0) {
|
||||
display->drawString(x, y += fontHeight(FONT_SMALL),
|
||||
"Volt/Cur: " + String(lastMeasurement.variant.environment_metrics.voltage, 0) + "V / " +
|
||||
String(lastMeasurement.variant.environment_metrics.current, 0) + "mA");
|
||||
if (lastMeasurement.variant.environment_metrics.iaq != 0)
|
||||
}
|
||||
if (lastMeasurement.variant.environment_metrics.iaq != 0) {
|
||||
display->drawString(x, y += fontHeight(FONT_SMALL), "IAQ: " + String(lastMeasurement.variant.environment_metrics.iaq));
|
||||
}
|
||||
if (lastMeasurement.variant.environment_metrics.distance != 0)
|
||||
display->drawString(x, y += fontHeight(FONT_SMALL),
|
||||
"Water Level: " + String(lastMeasurement.variant.environment_metrics.distance, 0) + "mm");
|
||||
}
|
||||
|
||||
bool EnvironmentTelemetryModule::handleReceivedProtobuf(const meshtastic_MeshPacket &mp, meshtastic_Telemetry *t)
|
||||
@@ -192,10 +214,13 @@ bool EnvironmentTelemetryModule::handleReceivedProtobuf(const meshtastic_MeshPac
|
||||
const char *sender = getSenderShortName(mp);
|
||||
|
||||
LOG_INFO("(Received from %s): barometric_pressure=%f, current=%f, gas_resistance=%f, relative_humidity=%f, "
|
||||
"temperature=%f, voltage=%f\n",
|
||||
"temperature=%f\n",
|
||||
sender, t->variant.environment_metrics.barometric_pressure, t->variant.environment_metrics.current,
|
||||
t->variant.environment_metrics.gas_resistance, t->variant.environment_metrics.relative_humidity,
|
||||
t->variant.environment_metrics.temperature, t->variant.environment_metrics.voltage);
|
||||
t->variant.environment_metrics.temperature);
|
||||
LOG_INFO("(Received from %s): voltage=%f, IAQ=%d, distance=%f\n", sender, t->variant.environment_metrics.voltage,
|
||||
t->variant.environment_metrics.iaq, t->variant.environment_metrics.distance);
|
||||
|
||||
#endif
|
||||
// release previous packet before occupying a new spot
|
||||
if (lastMeasurementPacket != nullptr)
|
||||
@@ -220,9 +245,13 @@ bool EnvironmentTelemetryModule::sendTelemetry(NodeNum dest, bool phoneOnly)
|
||||
m.variant.environment_metrics.relative_humidity = 0;
|
||||
m.variant.environment_metrics.temperature = 0;
|
||||
m.variant.environment_metrics.voltage = 0;
|
||||
m.variant.environment_metrics.iaq = 0;
|
||||
m.variant.environment_metrics.distance = 0;
|
||||
|
||||
if (sht31Sensor.hasSensor())
|
||||
valid = sht31Sensor.getMetrics(&m);
|
||||
if (sht4xSensor.hasSensor())
|
||||
valid = sht4xSensor.getMetrics(&m);
|
||||
if (lps22hbSensor.hasSensor())
|
||||
valid = lps22hbSensor.getMetrics(&m);
|
||||
if (shtc3Sensor.hasSensor())
|
||||
@@ -241,13 +270,16 @@ bool EnvironmentTelemetryModule::sendTelemetry(NodeNum dest, bool phoneOnly)
|
||||
valid = ina219Sensor.getMetrics(&m);
|
||||
if (ina260Sensor.hasSensor())
|
||||
valid = ina260Sensor.getMetrics(&m);
|
||||
if (rcwl9620Sensor.hasSensor())
|
||||
valid = rcwl9620Sensor.getMetrics(&m);
|
||||
|
||||
if (valid) {
|
||||
LOG_INFO("(Sending): barometric_pressure=%f, current=%f, gas_resistance=%f, relative_humidity=%f, temperature=%f, "
|
||||
"voltage=%f\n",
|
||||
LOG_INFO("(Sending): barometric_pressure=%f, current=%f, gas_resistance=%f, relative_humidity=%f, temperature=%f\n",
|
||||
m.variant.environment_metrics.barometric_pressure, m.variant.environment_metrics.current,
|
||||
m.variant.environment_metrics.gas_resistance, m.variant.environment_metrics.relative_humidity,
|
||||
m.variant.environment_metrics.temperature, m.variant.environment_metrics.voltage);
|
||||
m.variant.environment_metrics.temperature);
|
||||
LOG_INFO("(Sending): voltage=%f, IAQ=%d, distance=%f\n", m.variant.environment_metrics.voltage,
|
||||
m.variant.environment_metrics.iaq, m.variant.environment_metrics.distance);
|
||||
|
||||
sensor_read_error_count = 0;
|
||||
|
||||
@@ -278,4 +310,6 @@ bool EnvironmentTelemetryModule::sendTelemetry(NodeNum dest, bool phoneOnly)
|
||||
}
|
||||
}
|
||||
return valid;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,3 +1,7 @@
|
||||
#include "configuration.h"
|
||||
|
||||
#if !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR
|
||||
|
||||
#pragma once
|
||||
#include "../mesh/generated/meshtastic/telemetry.pb.h"
|
||||
#include "NodeDB.h"
|
||||
@@ -42,3 +46,5 @@ class EnvironmentTelemetryModule : private concurrency::OSThread, public Protobu
|
||||
uint32_t lastSentToPhone = 0;
|
||||
uint32_t sensor_read_error_count = 0;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -1,12 +1,15 @@
|
||||
#include "PowerTelemetry.h"
|
||||
#include "configuration.h"
|
||||
|
||||
#if !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR
|
||||
|
||||
#include "../mesh/generated/meshtastic/telemetry.pb.h"
|
||||
#include "Default.h"
|
||||
#include "MeshService.h"
|
||||
#include "NodeDB.h"
|
||||
#include "PowerFSM.h"
|
||||
#include "PowerTelemetry.h"
|
||||
#include "RTC.h"
|
||||
#include "Router.h"
|
||||
#include "configuration.h"
|
||||
#include "main.h"
|
||||
#include "power.h"
|
||||
#include "sleep.h"
|
||||
@@ -217,4 +220,6 @@ bool PowerTelemetryModule::sendTelemetry(NodeNum dest, bool phoneOnly)
|
||||
}
|
||||
}
|
||||
return valid;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,4 +1,9 @@
|
||||
#pragma once
|
||||
|
||||
#include "configuration.h"
|
||||
|
||||
#if !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR
|
||||
|
||||
#include "../mesh/generated/meshtastic/telemetry.pb.h"
|
||||
#include "NodeDB.h"
|
||||
#include "ProtobufModule.h"
|
||||
@@ -41,3 +46,5 @@ class PowerTelemetryModule : private concurrency::OSThread, public ProtobufModul
|
||||
uint32_t lastSentToPhone = 0;
|
||||
uint32_t sensor_read_error_count = 0;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -1,7 +1,10 @@
|
||||
#include "BME280Sensor.h"
|
||||
#include "../mesh/generated/meshtastic/telemetry.pb.h"
|
||||
#include "TelemetrySensor.h"
|
||||
#include "configuration.h"
|
||||
|
||||
#if !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR
|
||||
|
||||
#include "../mesh/generated/meshtastic/telemetry.pb.h"
|
||||
#include "BME280Sensor.h"
|
||||
#include "TelemetrySensor.h"
|
||||
#include <Adafruit_BME280.h>
|
||||
#include <typeinfo>
|
||||
|
||||
@@ -35,4 +38,5 @@ bool BME280Sensor::getMetrics(meshtastic_Telemetry *measurement)
|
||||
measurement->variant.environment_metrics.barometric_pressure = bme280.readPressure() / 100.0F;
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -1,3 +1,7 @@
|
||||
#include "configuration.h"
|
||||
|
||||
#if !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR
|
||||
|
||||
#include "../mesh/generated/meshtastic/telemetry.pb.h"
|
||||
#include "TelemetrySensor.h"
|
||||
#include <Adafruit_BME280.h>
|
||||
@@ -14,4 +18,6 @@ class BME280Sensor : public TelemetrySensor
|
||||
BME280Sensor();
|
||||
virtual int32_t runOnce() override;
|
||||
virtual bool getMetrics(meshtastic_Telemetry *measurement) override;
|
||||
};
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -1,8 +1,11 @@
|
||||
#include "BME680Sensor.h"
|
||||
#include "configuration.h"
|
||||
|
||||
#if !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR
|
||||
|
||||
#include "../mesh/generated/meshtastic/telemetry.pb.h"
|
||||
#include "BME680Sensor.h"
|
||||
#include "FSCommon.h"
|
||||
#include "TelemetrySensor.h"
|
||||
#include "configuration.h"
|
||||
|
||||
BME680Sensor::BME680Sensor() : TelemetrySensor(meshtastic_TelemetrySensorType_BME680, "BME680") {}
|
||||
|
||||
@@ -134,3 +137,5 @@ void BME680Sensor::checkStatus(String functionName)
|
||||
else if (bme680.sensor.status > BME68X_OK)
|
||||
LOG_WARN("%s BME68X code: %s\n", functionName.c_str(), String(bme680.sensor.status).c_str());
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,3 +1,7 @@
|
||||
#include "configuration.h"
|
||||
|
||||
#if !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR
|
||||
|
||||
#include "../mesh/generated/meshtastic/telemetry.pb.h"
|
||||
#include "TelemetrySensor.h"
|
||||
#include <bsec2.h>
|
||||
@@ -35,4 +39,6 @@ class BME680Sensor : public TelemetrySensor
|
||||
int32_t runTrigger();
|
||||
virtual int32_t runOnce() override;
|
||||
virtual bool getMetrics(meshtastic_Telemetry *measurement) override;
|
||||
};
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -1,7 +1,10 @@
|
||||
#include "BMP085Sensor.h"
|
||||
#include "../mesh/generated/meshtastic/telemetry.pb.h"
|
||||
#include "TelemetrySensor.h"
|
||||
#include "configuration.h"
|
||||
|
||||
#if !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR
|
||||
|
||||
#include "../mesh/generated/meshtastic/telemetry.pb.h"
|
||||
#include "BMP085Sensor.h"
|
||||
#include "TelemetrySensor.h"
|
||||
#include <Adafruit_BMP085.h>
|
||||
#include <typeinfo>
|
||||
|
||||
@@ -29,3 +32,5 @@ bool BMP085Sensor::getMetrics(meshtastic_Telemetry *measurement)
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,3 +1,7 @@
|
||||
#include "configuration.h"
|
||||
|
||||
#if !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR
|
||||
|
||||
#include "../mesh/generated/meshtastic/telemetry.pb.h"
|
||||
#include "TelemetrySensor.h"
|
||||
#include <Adafruit_BMP085.h>
|
||||
@@ -14,4 +18,6 @@ class BMP085Sensor : public TelemetrySensor
|
||||
BMP085Sensor();
|
||||
virtual int32_t runOnce() override;
|
||||
virtual bool getMetrics(meshtastic_Telemetry *measurement) override;
|
||||
};
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -1,7 +1,10 @@
|
||||
#include "BMP280Sensor.h"
|
||||
#include "../mesh/generated/meshtastic/telemetry.pb.h"
|
||||
#include "TelemetrySensor.h"
|
||||
#include "configuration.h"
|
||||
|
||||
#if !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR
|
||||
|
||||
#include "../mesh/generated/meshtastic/telemetry.pb.h"
|
||||
#include "BMP280Sensor.h"
|
||||
#include "TelemetrySensor.h"
|
||||
#include <Adafruit_BMP280.h>
|
||||
#include <typeinfo>
|
||||
|
||||
@@ -35,3 +38,5 @@ bool BMP280Sensor::getMetrics(meshtastic_Telemetry *measurement)
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,3 +1,7 @@
|
||||
#include "configuration.h"
|
||||
|
||||
#if !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR
|
||||
|
||||
#include "../mesh/generated/meshtastic/telemetry.pb.h"
|
||||
#include "TelemetrySensor.h"
|
||||
#include <Adafruit_BMP280.h>
|
||||
@@ -14,4 +18,6 @@ class BMP280Sensor : public TelemetrySensor
|
||||
BMP280Sensor();
|
||||
virtual int32_t runOnce() override;
|
||||
virtual bool getMetrics(meshtastic_Telemetry *measurement) override;
|
||||
};
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -1,7 +1,10 @@
|
||||
#include "INA219Sensor.h"
|
||||
#include "../mesh/generated/meshtastic/telemetry.pb.h"
|
||||
#include "TelemetrySensor.h"
|
||||
#include "configuration.h"
|
||||
|
||||
#if HAS_TELEMETRY && !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR
|
||||
|
||||
#include "../mesh/generated/meshtastic/telemetry.pb.h"
|
||||
#include "INA219Sensor.h"
|
||||
#include "TelemetrySensor.h"
|
||||
#include <Adafruit_INA219.h>
|
||||
|
||||
#ifndef INA219_MULTIPLIER
|
||||
@@ -37,4 +40,6 @@ bool INA219Sensor::getMetrics(meshtastic_Telemetry *measurement)
|
||||
uint16_t INA219Sensor::getBusVoltageMv()
|
||||
{
|
||||
return lround(ina219.getBusVoltage_V() * 1000);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,3 +1,7 @@
|
||||
#include "configuration.h"
|
||||
|
||||
#if HAS_TELEMETRY && !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR
|
||||
|
||||
#include "../mesh/generated/meshtastic/telemetry.pb.h"
|
||||
#include "TelemetrySensor.h"
|
||||
#include "VoltageSensor.h"
|
||||
@@ -16,4 +20,6 @@ class INA219Sensor : public TelemetrySensor, VoltageSensor
|
||||
virtual int32_t runOnce() override;
|
||||
virtual bool getMetrics(meshtastic_Telemetry *measurement) override;
|
||||
virtual uint16_t getBusVoltageMv() override;
|
||||
};
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -1,7 +1,10 @@
|
||||
#include "INA260Sensor.h"
|
||||
#include "../mesh/generated/meshtastic/telemetry.pb.h"
|
||||
#include "TelemetrySensor.h"
|
||||
#include "configuration.h"
|
||||
|
||||
#if HAS_TELEMETRY && !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR
|
||||
|
||||
#include "../mesh/generated/meshtastic/telemetry.pb.h"
|
||||
#include "INA260Sensor.h"
|
||||
#include "TelemetrySensor.h"
|
||||
#include <Adafruit_INA260.h>
|
||||
|
||||
INA260Sensor::INA260Sensor() : TelemetrySensor(meshtastic_TelemetrySensorType_INA260, "INA260") {}
|
||||
@@ -32,4 +35,6 @@ bool INA260Sensor::getMetrics(meshtastic_Telemetry *measurement)
|
||||
uint16_t INA260Sensor::getBusVoltageMv()
|
||||
{
|
||||
return lround(ina260.readBusVoltage());
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,3 +1,7 @@
|
||||
#include "configuration.h"
|
||||
|
||||
#if HAS_TELEMETRY && !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR
|
||||
|
||||
#include "../mesh/generated/meshtastic/telemetry.pb.h"
|
||||
#include "TelemetrySensor.h"
|
||||
#include "VoltageSensor.h"
|
||||
@@ -16,4 +20,6 @@ class INA260Sensor : public TelemetrySensor, VoltageSensor
|
||||
virtual int32_t runOnce() override;
|
||||
virtual bool getMetrics(meshtastic_Telemetry *measurement) override;
|
||||
virtual uint16_t getBusVoltageMv() override;
|
||||
};
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -1,7 +1,10 @@
|
||||
#include "INA3221Sensor.h"
|
||||
#include "../mesh/generated/meshtastic/telemetry.pb.h"
|
||||
#include "TelemetrySensor.h"
|
||||
#include "configuration.h"
|
||||
|
||||
#if HAS_TELEMETRY && !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR
|
||||
|
||||
#include "../mesh/generated/meshtastic/telemetry.pb.h"
|
||||
#include "INA3221Sensor.h"
|
||||
#include "TelemetrySensor.h"
|
||||
#include <INA3221.h>
|
||||
|
||||
INA3221Sensor::INA3221Sensor() : TelemetrySensor(meshtastic_TelemetrySensorType_INA3221, "INA3221"){};
|
||||
@@ -41,4 +44,6 @@ bool INA3221Sensor::getMetrics(meshtastic_Telemetry *measurement)
|
||||
uint16_t INA3221Sensor::getBusVoltageMv()
|
||||
{
|
||||
return lround(ina3221.getVoltage(INA3221_CH1) * 1000);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,3 +1,7 @@
|
||||
#include "configuration.h"
|
||||
|
||||
#if HAS_TELEMETRY && !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR
|
||||
|
||||
#include "../mesh/generated/meshtastic/telemetry.pb.h"
|
||||
#include "TelemetrySensor.h"
|
||||
#include "VoltageSensor.h"
|
||||
@@ -16,4 +20,6 @@ class INA3221Sensor : public TelemetrySensor, VoltageSensor
|
||||
int32_t runOnce() override;
|
||||
bool getMetrics(meshtastic_Telemetry *measurement) override;
|
||||
virtual uint16_t getBusVoltageMv() override;
|
||||
};
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -1,7 +1,10 @@
|
||||
#include "LPS22HBSensor.h"
|
||||
#include "../mesh/generated/meshtastic/telemetry.pb.h"
|
||||
#include "TelemetrySensor.h"
|
||||
#include "configuration.h"
|
||||
|
||||
#if !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR
|
||||
|
||||
#include "../mesh/generated/meshtastic/telemetry.pb.h"
|
||||
#include "LPS22HBSensor.h"
|
||||
#include "TelemetrySensor.h"
|
||||
#include <Adafruit_LPS2X.h>
|
||||
#include <Adafruit_Sensor.h>
|
||||
|
||||
@@ -32,4 +35,6 @@ bool LPS22HBSensor::getMetrics(meshtastic_Telemetry *measurement)
|
||||
measurement->variant.environment_metrics.barometric_pressure = pressure.pressure;
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,3 +1,7 @@
|
||||
#include "configuration.h"
|
||||
|
||||
#if !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR
|
||||
|
||||
#include "../mesh/generated/meshtastic/telemetry.pb.h"
|
||||
#include "TelemetrySensor.h"
|
||||
#include <Adafruit_LPS2X.h>
|
||||
@@ -15,4 +19,6 @@ class LPS22HBSensor : public TelemetrySensor
|
||||
LPS22HBSensor();
|
||||
virtual int32_t runOnce() override;
|
||||
virtual bool getMetrics(meshtastic_Telemetry *measurement) override;
|
||||
};
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -1,7 +1,10 @@
|
||||
#include "MCP9808Sensor.h"
|
||||
#include "../mesh/generated/meshtastic/telemetry.pb.h"
|
||||
#include "TelemetrySensor.h"
|
||||
#include "configuration.h"
|
||||
|
||||
#if !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR
|
||||
|
||||
#include "../mesh/generated/meshtastic/telemetry.pb.h"
|
||||
#include "MCP9808Sensor.h"
|
||||
#include "TelemetrySensor.h"
|
||||
#include <Adafruit_MCP9808.h>
|
||||
|
||||
MCP9808Sensor::MCP9808Sensor() : TelemetrySensor(meshtastic_TelemetrySensorType_MCP9808, "MCP9808") {}
|
||||
@@ -26,4 +29,6 @@ bool MCP9808Sensor::getMetrics(meshtastic_Telemetry *measurement)
|
||||
LOG_DEBUG("MCP9808Sensor::getMetrics\n");
|
||||
measurement->variant.environment_metrics.temperature = mcp9808.readTempC();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,3 +1,7 @@
|
||||
#include "configuration.h"
|
||||
|
||||
#if !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR
|
||||
|
||||
#include "../mesh/generated/meshtastic/telemetry.pb.h"
|
||||
#include "TelemetrySensor.h"
|
||||
#include <Adafruit_MCP9808.h>
|
||||
@@ -14,4 +18,6 @@ class MCP9808Sensor : public TelemetrySensor
|
||||
MCP9808Sensor();
|
||||
virtual int32_t runOnce() override;
|
||||
virtual bool getMetrics(meshtastic_Telemetry *measurement) override;
|
||||
};
|
||||
};
|
||||
|
||||
#endif
|
||||
65
src/modules/Telemetry/Sensor/RCWL9620Sensor.cpp
Normal file
65
src/modules/Telemetry/Sensor/RCWL9620Sensor.cpp
Normal file
@@ -0,0 +1,65 @@
|
||||
#include "configuration.h"
|
||||
|
||||
#if !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR
|
||||
|
||||
#include "../mesh/generated/meshtastic/telemetry.pb.h"
|
||||
#include "RCWL9620Sensor.h"
|
||||
#include "TelemetrySensor.h"
|
||||
|
||||
RCWL9620Sensor::RCWL9620Sensor() : TelemetrySensor(meshtastic_TelemetrySensorType_RCWL9620, "RCWL9620") {}
|
||||
|
||||
int32_t RCWL9620Sensor::runOnce()
|
||||
{
|
||||
LOG_INFO("Init sensor: %s\n", sensorName);
|
||||
if (!hasSensor()) {
|
||||
return DEFAULT_SENSOR_MINIMUM_WAIT_TIME_BETWEEN_READS;
|
||||
}
|
||||
status = 1;
|
||||
begin(nodeTelemetrySensorsMap[sensorType].second, nodeTelemetrySensorsMap[sensorType].first);
|
||||
return initI2CSensor();
|
||||
}
|
||||
|
||||
void RCWL9620Sensor::setup() {}
|
||||
|
||||
bool RCWL9620Sensor::getMetrics(meshtastic_Telemetry *measurement)
|
||||
{
|
||||
LOG_DEBUG("RCWL9620Sensor::getMetrics\n");
|
||||
measurement->variant.environment_metrics.distance = getDistance();
|
||||
return true;
|
||||
}
|
||||
|
||||
void RCWL9620Sensor::begin(TwoWire *wire, uint8_t addr, uint8_t sda, uint8_t scl, uint32_t speed)
|
||||
{
|
||||
_wire = wire;
|
||||
_addr = addr;
|
||||
_sda = sda;
|
||||
_scl = scl;
|
||||
_speed = speed;
|
||||
_wire->begin();
|
||||
}
|
||||
|
||||
float RCWL9620Sensor::getDistance()
|
||||
{
|
||||
uint32_t data;
|
||||
_wire->beginTransmission(_addr); // Transfer data to addr.
|
||||
_wire->write(0x01);
|
||||
_wire->endTransmission(); // Stop data transmission with the Ultrasonic
|
||||
// Unit.
|
||||
|
||||
_wire->requestFrom(_addr,
|
||||
(uint8_t)3); // Request 3 bytes from Ultrasonic Unit.
|
||||
|
||||
data = _wire->read();
|
||||
data <<= 8;
|
||||
data |= _wire->read();
|
||||
data <<= 8;
|
||||
data |= _wire->read();
|
||||
float Distance = float(data) / 1000;
|
||||
if (Distance > 4500.00) {
|
||||
return 4500.00;
|
||||
} else {
|
||||
return Distance;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
29
src/modules/Telemetry/Sensor/RCWL9620Sensor.h
Normal file
29
src/modules/Telemetry/Sensor/RCWL9620Sensor.h
Normal file
@@ -0,0 +1,29 @@
|
||||
#include "configuration.h"
|
||||
|
||||
#if !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR
|
||||
|
||||
#include "../mesh/generated/meshtastic/telemetry.pb.h"
|
||||
#include "TelemetrySensor.h"
|
||||
#include <Wire.h>
|
||||
|
||||
class RCWL9620Sensor : public TelemetrySensor
|
||||
{
|
||||
private:
|
||||
uint8_t _addr = 0x57;
|
||||
TwoWire *_wire = &Wire;
|
||||
uint8_t _scl = -1;
|
||||
uint8_t _sda = -1;
|
||||
uint32_t _speed = 200000UL;
|
||||
|
||||
protected:
|
||||
virtual void setup() override;
|
||||
void begin(TwoWire *wire = &Wire, uint8_t addr = 0x57, uint8_t sda = -1, uint8_t scl = -1, uint32_t speed = 200000UL);
|
||||
float getDistance();
|
||||
|
||||
public:
|
||||
RCWL9620Sensor();
|
||||
virtual int32_t runOnce() override;
|
||||
virtual bool getMetrics(meshtastic_Telemetry *measurement) override;
|
||||
};
|
||||
|
||||
#endif
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user