Compare commits

...

88 Commits

Author SHA1 Message Date
Jonathan Bennett
30fbcabf84 add conffiles to .deb packaging (#3722) 2024-04-25 14:23:38 -05:00
Arkadiusz Miśkiewicz
c14043f196 Split warning into two messages, so we know which one is the case. (#3710) 2024-04-25 06:47:39 -05:00
Jonathan Bennett
e3610a2eb1 Move to lovyangfx develop for Native 2024-04-24 13:17:43 -05:00
Oleksandr Podolchak
9baccc80d8 Add SX1268 modules support for linux-native (#3702)
* Add portduino Ebyte E22 XXXM30S/XXXM33S (sx1268) module support

* Add Ebyte E22 XXXM3XS module config

* Update comment for sx1268 module

* Address review comments

---------

Co-authored-by: Ben Meadors <benmmeadors@gmail.com>
2024-04-24 08:41:01 -05:00
Gareth Coleman
ac16ccf40c fix for unPhone hangs during boot without sd card present (#3709)
* work around sd card hang if not present

* comment out the define for HAS_SDCARD
2024-04-24 06:41:05 -05:00
Jonathan Bennett
57d296e0db Add better support for the Adafruit PiTFT 2.8 for Native (#3704)
* Add better support for the Adafruit PiTFT 2.8 for Native

* native: Make touch i2c address configurable

* Bump portduino to pick up I2C features

---------

Co-authored-by: Ben Meadors <benmmeadors@gmail.com>
2024-04-23 14:18:51 -05:00
SCWhite
9c9d126f6b [BOARD] Add new variant: TWC_Mesh (#3705)
* add new variant: TWC_mesh_v4

* fix trunk format

* fix format under wsl

* change board to TWC_mesh_v4

* change platformio & variant.h properly

---------

Co-authored-by: Ben Meadors <benmmeadors@gmail.com>
2024-04-23 14:09:28 -05:00
github-actions[bot]
27f0e42d2f [create-pull-request] automated change (#3708)
Co-authored-by: thebentern <thebentern@users.noreply.github.com>
2024-04-23 13:32:33 -05:00
todd-herbert
4599534616 Terminate an async-full-refresh when caught by determineMode() instead of onNotify() (#3706) 2024-04-23 12:00:48 -05:00
Tom Fifield
7acaec8ef5 Add power limit for TW region (#3701)
The TW region had now power limit set, so defaulted to 16dBm.

The relevant regulation is section 5.8.1 of the Low-power Radio-frequency Devices Technical Regulations, which notes the limits of  0.5W (27dBM) indoor or coastal, 1.0W (30dBM) outdoor.

This patch updates the power limit to 27dbM, using the the lower limit specified in the regulations to be conservative.

Regulation references:
https://www.ncc.gov.tw/english/files/23070/102_5190_230703_1_doc_C.PDF (latest English version)
https://gazette.nat.gov.tw/egFront/e_detail.do?metaid=147283 (latest Chinese version, February 2024)
2024-04-23 07:11:22 -05:00
Nicholas Baddorf
d0e81b9151 Fixed node and channel selection for t-deck (#3695)
This enables the node and channel selection to be accessed by pressing the tab shortcut and then swiping between nodes or pressing tab again to change channels.

(To access the tab function look at my other pull request https://github.com/meshtastic/firmware/pull/3668)

Co-authored-by: Ben Meadors <benmmeadors@gmail.com>
2024-04-23 07:09:26 -05:00
Thomas Göttgens
3302fbcc53 Merge pull request #3647 from garethhcoleman/RGBLED
Support for generic 4pin RGB LEDs (both CC and CA) and NeoPixels, also RGB LED and vibration notification support for unPhone
2024-04-23 13:57:23 +02:00
Gareth Coleman
ccbf635eef corrected a bit of overzealous tidying 2024-04-22 17:21:41 +01:00
Gareth Coleman
6669b22db3 tidied up, prob broke everything 2024-04-22 16:37:05 +01:00
Gareth Coleman
ec2b854ea2 oops missed the extern enabling little chap 2024-04-22 14:44:59 +01:00
Gareth Coleman
378a2d723e Merge branch 'RGBLED' of github.com:garethhcoleman/firmware into RGBLED 2024-04-22 14:43:07 +01:00
Gareth Coleman
5dd08e9533 added NeoPixel support using Adafruit library 2024-04-22 14:42:52 +01:00
Gareth Coleman
125add9792 Merge branch 'master' into RGBLED 2024-04-22 14:42:14 +01:00
Andrew Yong
250cf16bf8 Add ability to turn off heartbeat LED blinking (#3674)
* Add ability to turn off status LED blinking

Fixes #3635 and depends on [protobufs PR #485](https://github.com/meshtastic/protobufs/pull/485)

Signed-off-by: Andrew Yong <me@ndoo.sg>

* led_heartbeat_disabled

* trunk

---------

Signed-off-by: Andrew Yong <me@ndoo.sg>
Co-authored-by: Ben Meadors <benmmeadors@gmail.com>
2024-04-22 08:21:50 -05:00
Thomas Göttgens
8b5fad21b0 Merge pull request #3693 from titan098/updates_for_esp32s2_build
Updates for esp32s2 builds
2024-04-22 13:56:14 +02:00
David Ellefsen
30d4c3a945 Updates for esp32s2 build 2024-04-22 11:01:13 +02:00
Gareth Coleman
45fd5e25ac Merge branch 'master' into RGBLED 2024-04-22 09:15:44 +01:00
Thomas Göttgens
ac6a668362 Merge pull request #3697 from meshtastic/nrf52-signfix
fix signedness warnings of NRF52 toolchain
2024-04-22 10:13:38 +02:00
Thomas Göttgens
f47b40cf68 fix signedness warnings of NRF52 toolchain 2024-04-22 09:49:06 +02:00
quimnut
fd9461505f adjust adc for rak11310 devices (#3698) 2024-04-21 19:51:02 -05:00
Ben Meadors
84edaabfe9 Merge branch 'master' into RGBLED 2024-04-21 14:46:18 -05:00
Nicholas Baddorf
4a48a3fb52 Fixed bug making t-deck reboot when muted (#3694) 2024-04-21 14:41:22 -05:00
Ben Meadors
39bbf0d352 Added more clear RTC handling and quality logging (#3691)
* Also refresh timestamp for "timeonly" fixed position nodes

* Added more clear RTC quality handling

* Fix clock drift from Phone GPS / NTP too
2024-04-21 14:40:47 -05:00
Mictronics
0406be82d2 Use correct format specifier and fixed typo. (#3696)
* Fix LED pinout for T-Echo board marked v1.0, date 2021-6-28

* Merge PR #420

* Fixed double and missing Default class.

* Use correct format specifier and fixed typo.

---------

Co-authored-by: Ben Meadors <benmmeadors@gmail.com>
2024-04-21 12:36:37 -05:00
Ric In New Mexico
679e068e19 Missing break in INA3221 i2c scan (#3692)
* INA3221 Mis-identification fix

* Missing break in INA3221 i2c scan
2024-04-21 12:35:42 -05:00
Ben Meadors
ac87c0065f Also refresh timestamp for "timeonly" fixed position nodes (#3689) 2024-04-21 08:45:36 -05:00
S5NC
9822a85274 Add board and variant definitions for EBYTE_ESP32-S3 (#2882)
* Create ESP32-S3-WROOM-1-N4.json

* Create pins_arduino.h

* Create platformio.ini

* Create variant.h

* Update mesh.pb.h

* Update architecture.h

* Update mesh.pb.h

* Update variant.h

* Update variant.h

Add example schematic

* Update architecture.h

* Revert update architecture.h

* Create variant.h

* Create pins_arduino.h

* Create platformio.ini

* Delete variants/E22-900M_S3 directory

* Update architecture.h

* Update variant.h

* Update platformio.ini

* Update variant.h

* Update variant.h

* Update architecture.h

* Update platformio.ini

* Update architecture.h

* Update ESP32-S3-WROOM-1-N4.json

* Update platformio.ini

* Update ESP32-S3-WROOM-1-N4.json

* Update variant.h

* Update variant.h

* Update variant.h

* Update variant.h

* Update pins_arduino.h

* Update architecture.h

* add SX1268 allow

* GPS

* Commit

* Whitespace

* Update variant.h

* Update variant.h

* trunk

---------

Co-authored-by: Ben Meadors <benmmeadors@gmail.com>
Co-authored-by: Thomas Göttgens <tgoettgens@gmail.com>
Co-authored-by: S5NC <>
2024-04-21 08:40:23 -05:00
Ben Meadors
41f3557491 Refactor smart position to use throttle helper (#3671)
* Added one minute throttling to NodeDB

* Derp

* Refactor smart-position to use throttle
2024-04-21 07:42:36 -05:00
Ben Meadors
df718ab294 Merge branch 'master' into RGBLED 2024-04-21 07:31:54 -05:00
todd-herbert
dfc43bae18 Fix crash on shutdown, if Bluetooth not enabled (#3686)
Previously attempted to call deinit method for a nullptr
2024-04-21 07:25:58 -05:00
todd-herbert
f6cfdfe881 (ESP-32S) Fix "critical error 3" after deep-sleep (#3685) 2024-04-21 07:25:12 -05:00
S5NC
820c5dc8c5 Update architecture.h (#3688) 2024-04-21 07:24:39 -05:00
Gareth Coleman
9e4ef92e6d lets just define it without guards! 2024-04-21 09:16:50 +01:00
Gareth Coleman
cf65661c7c another silly error 2024-04-21 08:59:40 +01:00
Gareth Coleman
fb7a878d94 tweaked guards to allow various combinations of RGB leds 2024-04-21 08:24:51 +01:00
github-actions[bot]
e72792afc8 [create-pull-request] automated change (#3683)
Co-authored-by: thebentern <thebentern@users.noreply.github.com>
2024-04-20 15:58:42 -05:00
Ric In New Mexico
ec39e1136a INA3221 Mis-identification fix (#3681) 2024-04-20 15:58:21 -05:00
Thomas Göttgens
ef9808cdd6 Merge pull request #3680 from meshtastic/create-pull-request/patch
Changes by create-pull-request action
2024-04-20 20:25:14 +02:00
caveman99
0972a8dccb [create-pull-request] automated change 2024-04-20 18:24:40 +00:00
github-actions[bot]
419eb13968 [create-pull-request] automated change (#3679)
Co-authored-by: thebentern <thebentern@users.noreply.github.com>
2024-04-20 09:56:55 -05:00
github-actions[bot]
e7828c4c64 [create-pull-request] automated change (#3676)
Co-authored-by: thebentern <thebentern@users.noreply.github.com>
2024-04-20 07:36:53 -05:00
Manuel
44aa248099 added new display parameters (#3670) 2024-04-19 19:27:13 -05:00
Gareth Coleman
e0513d4078 ahem, another minor edit to have another go at CI 2024-04-19 09:27:10 +01:00
Gareth Coleman
2100f3135e minor edit to have another go at CI 2024-04-19 09:25:38 +01:00
Gareth Coleman
2f36d4990e Merge branch 'master' into RGBLED 2024-04-19 08:12:13 +01:00
github-actions[bot]
65bde8538f [create-pull-request] automated change (#3663)
Co-authored-by: thebentern <thebentern@users.noreply.github.com>
2024-04-18 20:33:23 -05:00
github-actions[bot]
7a3570aecf [create-pull-request] automated change (#3662)
Co-authored-by: thebentern <thebentern@users.noreply.github.com>
2024-04-18 18:29:50 -05:00
Gareth Coleman
4a471ded79 Merge branch 'RGBLED' of github.com:garethhcoleman/firmware into RGBLED 2024-04-19 00:28:39 +01:00
Gareth Coleman
eea85d26ca oh god the bugs, they are everywhere, I feel so dirty... 2024-04-19 00:28:20 +01:00
GUVWAF
64edfb76e0 Uplink to MQTT after potentially altering content (#3646)
Mainly for traceroute module now

Co-authored-by: Ben Meadors <benmmeadors@gmail.com>
2024-04-18 17:44:13 -05:00
Gareth Coleman
8ac308e73b Merge branch 'master' into RGBLED 2024-04-18 23:12:08 +01:00
Gareth Coleman
0ae7674982 I'm sure there's a cleverer way to do this, but I'm stupid and I didn't find it after a few minutes of searching stack overflow 2024-04-18 22:18:50 +01:00
GUVWAF
e4b5f2ce14 NeighborInfo: Only keep neighbors in RAM (#3660)
* NeighborInfo: Only keep neighbors in RAM
It fills up quickly when nodes are running >=2.3

* Defer first transmission as it's usually empty

---------

Co-authored-by: Ben Meadors <benmmeadors@gmail.com>
2024-04-18 16:16:50 -05:00
Gareth Coleman
7d77b23eb6 support for generic 4 pin CC and CA RGB LEDS 2024-04-18 22:00:33 +01:00
Gareth Coleman
a149999cec tidy up first 2024-04-18 20:57:03 +01:00
Ben Meadors
78d915b454 Merge branch 'master' into RGBLED 2024-04-18 14:44:53 -05:00
GUVWAF
4c0b7ea409 StoreForward: Remove assert when receiving unhandled case (#3661) 2024-04-18 14:28:11 -05:00
Ben Meadors
425a715995 Added one minute throttling to NodeDB save to disk (#3648)
* Added one minute throttling to NodeDB

* Derp
2024-04-18 14:20:39 -05:00
Ben Meadors
2e13aeeacb Merge branch 'master' into RGBLED 2024-04-18 07:32:25 -05:00
todd-herbert
747c713ba9 (ESP32) Fix bluetooth after light-sleep; de-init for deep sleep (#3655) 2024-04-18 07:27:18 -05:00
Gareth Coleman
4b5549be8f added vibration notifications 2024-04-18 09:22:31 +01:00
Gareth Coleman
172d271b0b Merge branch 'master' into RGBLED 2024-04-18 07:11:49 +01:00
Oliver Seiler
2e14234b77 don't enable the CDC interface already at boot (#3652)
Co-authored-by: Ben Meadors <benmmeadors@gmail.com>
2024-04-17 16:55:47 -05:00
Jonathan Bennett
d47e9bed19 Add multiple SPI devices for Radio, Display, and Touchscreen (#3638)
This changeset gives us the ability to specify a separate SPI device for the LoRa, Display, and Touchscreen. The changes in Portduino also add support for specifying a new SPI speed for each transaction. All together, this means that we can let the Linux OS manage the CS lines, and also get much faster SPI speeds, leading to better framerates.

* Add multiple SPI devices to put Radio, Display, and Touchscreen on each their own

---------

Co-authored-by: Ben Meadors <benmmeadors@gmail.com>
2024-04-17 14:25:52 -05:00
GUVWAF
bc085ab840 Fix #3641: Always set MAC when picking new NodeNum (#3651)
Co-authored-by: Ben Meadors <benmmeadors@gmail.com>
2024-04-17 07:07:40 -05:00
Ben Meadors
2450031b1b Add device metrics uptime to MQTT JSON (#3643)
* Add device metrics uptime to MQTT JSON

* Cast a spell
2024-04-17 07:00:18 -05:00
Ben Meadors
2cd877d2eb Merge branch 'master' into RGBLED 2024-04-16 20:37:02 -05:00
GUVWAF
c34956e9d8 Cosmetics: rename remaining plugins → modules and less errors (#3645) 2024-04-16 17:47:56 -05:00
Gareth Coleman
afb4de21d9 yet another random edit, think i'm brushing the touchpad or perhaps my computer is possessed by the devil determined to make me look foolish 2024-04-16 22:37:57 +01:00
Gareth Coleman
86223d8806 Merge branch 'RGBLED' of github.com:garethhcoleman/firmware into RGBLED 2024-04-16 21:41:57 +01:00
Gareth Coleman
0632b96fcb just tiny tweak to minimise changes 2024-04-16 21:40:13 +01:00
Gareth Coleman
dcfc9c9f03 Merge branch 'meshtastic:master' into RGBLED 2024-04-16 21:29:12 +01:00
Gareth Coleman
8a3322fbcb rgb led support for unPhone 2024-04-16 21:28:12 +01:00
David Ellefsen
55c9c3b298 Support for the ATGM336H series of GPS modules (#3610)
Co-authored-by: Ben Meadors <benmmeadors@gmail.com>
2024-04-16 09:03:51 -05:00
Andrew Yong
9599549477 Add configuration option for LoRa Region Code override for region-locked builds/variants (#3540)
The main use case for this will be to create a custom Heltec WiFi LoRa 32 V3 SG_923 variant, which will be pre-flashed and sent for regulatory approval for retail sale.

Signed-off-by: Andrew Yong <me@ndoo.sg>
Co-authored-by: Ben Meadors <benmmeadors@gmail.com>
2024-04-16 09:03:36 -05:00
S5NC
e813703bf5 Add support for CDEBYTE_EoRa-S3 (#3613)
* Create CDEBYTE_EoRa-S3.json

* Update CDEBYTE_EoRa-S3.json

* Update architecture.h

* Create variant.h

* Create platformio.ini

* Create pins_arduino.h

* Update variant.h

* Update variant.h

* Update variant.h

* Trunk format

* update variant.h

---------

Co-authored-by: Ben Meadors <benmmeadors@gmail.com>
Co-authored-by: S5NC <>
2024-04-16 09:00:16 -05:00
github-actions[bot]
699ea74672 [create-pull-request] automated change (#3642)
Co-authored-by: thebentern <thebentern@users.noreply.github.com>
2024-04-16 08:01:32 -05:00
todd-herbert
a01069a549 No more printing power-state changes to screen (#3640) 2024-04-16 07:36:14 -05:00
Gareth Coleman
3413b9da41 Fixed XPT2046 syntax and using unPhone library to clean up support (#3631)
* Fixed XPT2046 syntax and using unPhone library to clean up main and TFTDisplay.

* strange extra edits removed wtf
2024-04-16 07:29:08 -05:00
Jonathan Bennett
7d3175dc83 More useful default input device for Pi 400 (#3639) 2024-04-16 07:22:31 -05:00
github-actions[bot]
441638c2eb [create-pull-request] automated change (#3636)
Co-authored-by: thebentern <thebentern@users.noreply.github.com>
2024-04-15 20:23:49 -05:00
Gareth Coleman
385d7296fe strange extra edits removed wtf 2024-04-15 17:37:39 +01:00
Gareth Coleman
d1cd686644 Fixed XPT2046 syntax and using unPhone library to clean up main and TFTDisplay. 2024-04-15 17:24:08 +01:00
89 changed files with 1608 additions and 408 deletions

View File

@@ -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:

View File

@@ -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

View File

@@ -1,6 +1,6 @@
; The Portduino based sim environment on top of any host OS, all hardware will be simulated
[portduino_base]
platform = https://github.com/meshtastic/platform-native.git#c95616208ffff4c8a36d48df810a3f072cce3521
platform = https://github.com/meshtastic/platform-native.git#659e49346aa33008b150dfb206b1817ddabc7132
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#d35e60f269dfecbb18a8cb0fd07d594c2fb7e7a8
build_flags =
${arduino_base.build_flags}
@@ -34,4 +34,4 @@ build_flags =
-DPORTDUINO_LINUX_HARDWARE
-lbluetooth
-lgpiod
-lyaml-cpp
-lyaml-cpp

View File

@@ -38,6 +38,15 @@ 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
@@ -96,23 +105,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
###

View 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"
}

View 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"
}

View File

@@ -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"

View File

@@ -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
}
};

View File

@@ -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()

View File

@@ -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, ...)

View File

@@ -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
// -----------------------------------------------------------------------------

View File

@@ -41,9 +41,7 @@ class ScanI2C
BQ24295,
LSM6DS3,
TCA9555,
#ifdef HAS_NCP5623
NCP5623,
#endif
} DeviceType;
// typedef uint8_t DeviceAddress;

View File

@@ -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);

View File

@@ -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 *payload = (uint32_t *)(message + 6);
for (size_t i = 0; i < (length - 10) / 4; i++) {
uint32_t p = payload[i];
cksum += p;
}
// 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 (uint 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");
@@ -1423,7 +1584,7 @@ bool GPS::hasFlow()
bool GPS::whileIdle()
{
int charsInBuf = 0;
uint charsInBuf = 0;
bool isValid = false;
if (!isAwake) {
clearBuffer();

View File

@@ -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
*/

View File

@@ -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.
*

View File

@@ -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
View 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
};

View File

@@ -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
View File

@@ -0,0 +1,4 @@
#ifdef HAS_NEOPIXEL
#include <Adafruit_NeoPixel.h>
extern Adafruit_NeoPixel pixels;
#endif

View File

@@ -356,6 +356,7 @@ class LGFX : public lgfx::LGFX_Device
_panel_instance = new lgfx::Panel_ILI9341;
auto buscfg = _bus_instance.config();
buscfg.spi_mode = 0;
_bus_instance.spi_device(DisplaySPI);
buscfg.pin_dc = settingsMap[displayDC]; // Set SPI DC pin number (-1 = disable)
@@ -381,6 +382,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 +395,9 @@ 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];
}
_touch_instance->config(touch_cfg);
_panel_instance->setTouch(_touch_instance);
@@ -411,8 +417,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 +471,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 +482,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 +500,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,11 +585,7 @@ 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)
@@ -612,11 +617,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)
@@ -690,11 +691,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 +715,4 @@ bool TFTDisplay::connect()
return true;
}
#endif
#endif

View File

@@ -4,7 +4,7 @@
#include "configuration.h"
#include "modules/ExternalNotificationModule.h"
#ifdef ARCH_PORTDUINO
#if ARCH_PORTDUINO
#include "platform/portduino/PortduinoGlue.h"
#endif

View File

@@ -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;
@@ -590,20 +595,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;
@@ -621,7 +612,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 +637,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
@@ -738,7 +729,7 @@ 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(*LoraSPI, spiSettings);
rIf = new SX1262Interface((LockingArduinoHal *)RadioLibHAL, settingsMap[cs], settingsMap[irq], settingsMap[reset],
settingsMap[busy]);
if (!rIf->init()) {
@@ -752,7 +743,7 @@ 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(*LoraSPI, spiSettings);
rIf = new RF95Interface((LockingArduinoHal *)RadioLibHAL, settingsMap[cs], settingsMap[irq], settingsMap[reset],
settingsMap[busy]);
if (!rIf->init()) {
@@ -767,7 +758,7 @@ void setup()
} else if (settingsMap[use_sx1280]) {
if (!rIf) {
LOG_DEBUG("Attempting to activate sx1280 radio on SPI port %s\n", settingsStrings[spidev].c_str());
LockingArduinoHal *RadioLibHAL = new LockingArduinoHal(SPI, spiSettings);
LockingArduinoHal *RadioLibHAL = new LockingArduinoHal(*LoraSPI, spiSettings);
rIf = new SX1280Interface((LockingArduinoHal *)RadioLibHAL, settingsMap[cs], settingsMap[irq], settingsMap[reset],
settingsMap[busy]);
if (!rIf->init()) {
@@ -779,6 +770,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(*LoraSPI, 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)

View File

@@ -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;

View File

@@ -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);
};
};

View File

@@ -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)
{

View File

@@ -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);

View File

@@ -527,8 +527,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 +813,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 +908,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;

View File

@@ -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.

View File

@@ -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);

View File

@@ -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;
uint 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);
}
}

View File

@@ -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);
}
}

View File

@@ -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
View 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
View 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);
};

View File

@@ -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

View File

@@ -308,7 +308,7 @@ extern const pb_msgdesc_t meshtastic_OEMStore_msg;
#define MESHTASTIC_MESHTASTIC_DEVICEONLY_PB_H_MAX_SIZE meshtastic_OEMStore_size
#define meshtastic_ChannelFile_size 702
#define meshtastic_NodeInfoLite_size 166
#define meshtastic_OEMStore_size 3344
#define meshtastic_OEMStore_size 3346
#define meshtastic_PositionLite_size 28
#ifdef __cplusplus

View File

@@ -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

View File

@@ -146,6 +146,11 @@ 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,
/* ------------------------------------------------------------------------------------------------------------------------------------------
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.
------------------------------------------------------------------------------------------------------------------------------------------ */

View File

@@ -43,7 +43,9 @@ 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
} meshtastic_TelemetrySensorType;
/* Struct definitions */
@@ -78,6 +80,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 +152,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_RCWL9620
#define _meshtastic_TelemetrySensorType_ARRAYSIZE ((meshtastic_TelemetrySensorType)(meshtastic_TelemetrySensorType_RCWL9620+1))
@@ -159,12 +163,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 +186,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 +228,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 +289,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

View File

@@ -256,7 +256,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);

View File

@@ -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

View File

@@ -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);
}
}
}

View File

@@ -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 */
@@ -143,7 +117,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, requestReplies);
}
return Default::getConfiguredOrDefaultMs(moduleConfig.neighbor_info.update_interval, default_broadcast_interval_secs);
}
@@ -178,10 +154,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 +174,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();
}

View File

@@ -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;

View File

@@ -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,16 @@ bool PositionModule::handleReceivedProtobuf(const meshtastic_MeshPacket &mp, mes
return false; // Let others look at this message also if they want
}
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 +227,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 +314,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 +324,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);
uint32_t 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 +400,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;
}
}
}

View File

@@ -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();
@@ -50,8 +52,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 {

View File

@@ -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
}
}

View File

@@ -1,5 +1,5 @@
#include "configuration.h"
#if defined(ARCH_ESP32)
#if defined(ARCH_ESP32) && !MESHTASTIC_EXCLUDE_PAXCOUNTER
#include "Default.h"
#include "MeshService.h"
#include "PaxcounterModule.h"

View File

@@ -506,7 +506,7 @@ bool StoreForwardModule::handleReceivedProtobuf(const meshtastic_MeshPacket &mp,
break;
default:
assert(0); // unexpected state
break; // no need to do anything
}
return true; // There's no need for others to look at this message.
}

View File

@@ -548,7 +548,10 @@ void MQTT::perhapsReportToMap()
} else {
if (map_position_precision == 0 || (localPosition.latitude_i == 0 && localPosition.longitude_i == 0)) {
last_report_to_map = millis();
LOG_WARN("MQTT Map reporting is enabled, but precision is 0 or no position available.\n");
if (map_position_precision == 0)
LOG_WARN("MQTT Map reporting is enabled, but precision is 0\n");
if (localPosition.latitude_i == 0 && localPosition.longitude_i == 0)
LOG_WARN("MQTT Map reporting is enabled, but no position available.\n");
return;
}
@@ -656,6 +659,7 @@ std::string MQTT::meshPacketToJson(meshtastic_MeshPacket *mp)
msgPayload["voltage"] = new JSONValue(decoded->variant.device_metrics.voltage);
msgPayload["channel_utilization"] = new JSONValue(decoded->variant.device_metrics.channel_utilization);
msgPayload["air_util_tx"] = new JSONValue(decoded->variant.device_metrics.air_util_tx);
msgPayload["uptime_seconds"] = new JSONValue((uint)decoded->variant.device_metrics.uptime_seconds);
} else if (decoded->which_variant == meshtastic_Telemetry_environment_metrics_tag) {
msgPayload["temperature"] = new JSONValue(decoded->variant.environment_metrics.temperature);
msgPayload["relative_humidity"] = new JSONValue(decoded->variant.environment_metrics.relative_humidity);

View File

@@ -106,20 +106,26 @@ static NimbleBluetoothFromRadioCallback *fromRadioCallbacks;
void NimbleBluetooth::shutdown()
{
// No measurable power saving for ESP32 during light-sleep(?)
#ifndef ARCH_ESP32
// Shutdown bluetooth for minimum power draw
LOG_INFO("Disable bluetooth\n");
// Bluefruit.Advertising.stop();
NimBLEAdvertising *pAdvertising = NimBLEDevice::getAdvertising();
pAdvertising->reset();
pAdvertising->stop();
#endif
}
// Extra power-saving on some devices
// Proper shutdown for ESP32. Needs reboot to reverse.
void NimbleBluetooth::deinit()
{
#ifdef ARCH_ESP32
LOG_INFO("Disable bluetooth until reboot\n");
NimBLEDevice::deinit();
#endif
}
// Has initial setup been completed
bool NimbleBluetooth::isActive()
{
return bleServer;

View File

@@ -117,6 +117,8 @@
#define HW_VENDOR meshtastic_HardwareModel_HELTEC_WIRELESS_PAPER
#elif defined(TLORA_T3S3_V1)
#define HW_VENDOR meshtastic_HardwareModel_TLORA_T3_S3
#elif defined(CDEBYTE_EORA_S3)
#define HW_VENDOR meshtastic_HardwareModel_CDEBYTE_EORA_S3
#elif defined(BETAFPV_2400_TX)
#define HW_VENDOR meshtastic_HardwareModel_BETAFPV_2400_TX
#elif defined(NANO_G1_EXPLORER)
@@ -125,6 +127,10 @@
#define HW_VENDOR meshtastic_HardwareModel_BETAFPV_900_NANO_TX
#elif defined(PICOMPUTER_S3)
#define HW_VENDOR meshtastic_HardwareModel_PICOMPUTER_S3
#elif defined(HELTEC_HT62)
#define HW_VENDOR meshtastic_HardwareModel_HELTEC_HT62
#elif defined(EBYTE_ESP32_S3)
#define HW_VENDOR meshtastic_HardwareModel_EBYTE_ESP32_S3
#elif defined(ESP32_S3_PICO)
#define HW_VENDOR meshtastic_HardwareModel_ESP32_S3_PICO
#elif defined(SENSELORA_S3)

View File

@@ -30,9 +30,10 @@ void setBluetoothEnable(bool enable)
}
if (enable && !nimbleBluetooth->isActive()) {
nimbleBluetooth->setup();
} else if (!enable) {
nimbleBluetooth->shutdown();
}
// For ESP32, no way to recover from bluetooth shutdown without reboot
// BLE advertising automatically stops when MCU enters light-sleep(?)
// For deep-sleep, shutdown hardware with nimbleBluetooth->deinit(). Requires reboot to reverse
}
}
#else

View File

@@ -52,6 +52,8 @@
#define HW_VENDOR meshtastic_HardwareModel_CANARYONE
#elif defined(NORDIC_PCA10059)
#define HW_VENDOR meshtastic_HardwareModel_NRF52840_PCA10059
#elif defined(TWC_MESH_V4)
#define HW_VENDOR meshtastic_HardwareModel_TWC_MESH_V4
#elif defined(PRIVATE_HW) || defined(FEATHER_DIY)
#define HW_VENDOR meshtastic_HardwareModel_PRIVATE_HW
#else
@@ -110,4 +112,4 @@
#if !defined(PIN_SERIAL_RX) && !defined(NRF52840_XXAA)
// No serial ports on this board - ONLY use segger in memory console
#define USE_SEGGER
#endif
#endif

View File

@@ -15,6 +15,8 @@
#include <map>
#include <unistd.h>
HardwareSPI *DisplaySPI;
HardwareSPI *LoraSPI;
std::map<configNames, int> settingsMap;
std::map<configNames, std::string> settingsStrings;
char *configPath = nullptr;
@@ -81,6 +83,7 @@ void portduinoSetup()
settingsStrings[keyboardDevice] = "";
settingsStrings[webserverrootpath] = "";
settingsStrings[spidev] = "";
settingsStrings[displayspidev] = "";
YAML::Node yamlConfig;
@@ -133,6 +136,7 @@ void portduinoSetup()
settingsMap[use_sx1262] = false;
settingsMap[use_rf95] = false;
settingsMap[use_sx1280] = false;
settingsMap[use_sx1268] = false;
if (yamlConfig["Lora"]["Module"] && yamlConfig["Lora"]["Module"].as<std::string>("") == "sx1262") {
settingsMap[use_sx1262] = true;
@@ -140,6 +144,8 @@ void portduinoSetup()
settingsMap[use_rf95] = true;
} else if (yamlConfig["Lora"]["Module"] && yamlConfig["Lora"]["Module"].as<std::string>("") == "sx1280") {
settingsMap[use_sx1280] = true;
} else if (yamlConfig["Lora"]["Module"] && yamlConfig["Lora"]["Module"].as<std::string>("") == "sx1268") {
settingsMap[use_sx1268] = true;
}
settingsMap[dio2_as_rf_switch] = yamlConfig["Lora"]["DIO2_AS_RF_SWITCH"].as<bool>(false);
settingsMap[dio3_tcxo_voltage] = yamlConfig["Lora"]["DIO3_TCXO_VOLTAGE"].as<bool>(false);
@@ -175,18 +181,34 @@ void portduinoSetup()
settingsMap[displayPanel] = st7735;
else if (yamlConfig["Display"]["Panel"].as<std::string>("") == "ST7735S")
settingsMap[displayPanel] = st7735s;
else if (yamlConfig["Display"]["Panel"].as<std::string>("") == "ST7796")
settingsMap[displayPanel] = st7796;
else if (yamlConfig["Display"]["Panel"].as<std::string>("") == "ILI9341")
settingsMap[displayPanel] = ili9341;
else if (yamlConfig["Display"]["Panel"].as<std::string>("") == "ILI9488")
settingsMap[displayPanel] = ili9488;
else if (yamlConfig["Display"]["Panel"].as<std::string>("") == "HX8357D")
settingsMap[displayPanel] = hx8357d;
else if (yamlConfig["Display"]["Panel"].as<std::string>("") == "X11")
settingsMap[displayPanel] = x11;
settingsMap[displayHeight] = yamlConfig["Display"]["Height"].as<int>(0);
settingsMap[displayWidth] = yamlConfig["Display"]["Width"].as<int>(0);
settingsMap[displayDC] = yamlConfig["Display"]["DC"].as<int>(-1);
settingsMap[displayCS] = yamlConfig["Display"]["CS"].as<int>(-1);
settingsMap[displayRGBOrder] = yamlConfig["Display"]["RGBOrder"].as<bool>(false);
settingsMap[displayBacklight] = yamlConfig["Display"]["Backlight"].as<int>(-1);
settingsMap[displayBacklightInvert] = yamlConfig["Display"]["BacklightInvert"].as<bool>(false);
settingsMap[displayBacklightPWMChannel] = yamlConfig["Display"]["BacklightPWMChannel"].as<int>(-1);
settingsMap[displayReset] = yamlConfig["Display"]["Reset"].as<int>(-1);
settingsMap[displayOffsetX] = yamlConfig["Display"]["OffsetX"].as<int>(0);
settingsMap[displayOffsetY] = yamlConfig["Display"]["OffsetY"].as<int>(0);
settingsMap[displayRotate] = yamlConfig["Display"]["Rotate"].as<bool>(false);
settingsMap[displayOffsetRotate] = yamlConfig["Display"]["OffsetRotate"].as<int>(1);
settingsMap[displayInvert] = yamlConfig["Display"]["Invert"].as<bool>(false);
settingsMap[displayBusFrequency] = yamlConfig["Display"]["BusFrequency"].as<int>(40000000);
if (yamlConfig["Display"]["spidev"]) {
settingsStrings[displayspidev] = "/dev/" + yamlConfig["Display"]["spidev"].as<std::string>("spidev0.1");
}
}
settingsMap[touchscreenModule] = no_touchscreen;
if (yamlConfig["Touchscreen"]) {
@@ -194,8 +216,18 @@ void portduinoSetup()
settingsMap[touchscreenModule] = xpt2046;
else if (yamlConfig["Touchscreen"]["Module"].as<std::string>("") == "STMPE610")
settingsMap[touchscreenModule] = stmpe610;
else if (yamlConfig["Touchscreen"]["Module"].as<std::string>("") == "GT911")
settingsMap[touchscreenModule] = gt911;
else if (yamlConfig["Touchscreen"]["Module"].as<std::string>("") == "FT5x06")
settingsMap[touchscreenModule] = ft5x06;
settingsMap[touchscreenCS] = yamlConfig["Touchscreen"]["CS"].as<int>(-1);
settingsMap[touchscreenIRQ] = yamlConfig["Touchscreen"]["IRQ"].as<int>(-1);
settingsMap[touchscreenBusFrequency] = yamlConfig["Touchscreen"]["BusFrequency"].as<int>(1000000);
settingsMap[touchscreenRotate] = yamlConfig["Touchscreen"]["Rotate"].as<int>(-1);
settingsMap[touchscreenI2CAddr] = yamlConfig["Touchscreen"]["I2CAddr"].as<int>(-1);
if (yamlConfig["Touchscreen"]["spidev"]) {
settingsStrings[touchscreenspidev] = "/dev/" + yamlConfig["Touchscreen"]["spidev"].as<std::string>("");
}
}
if (yamlConfig["Input"]) {
settingsStrings[keyboardDevice] = (yamlConfig["Input"]["KeyboardDevice"]).as<std::string>("");
@@ -267,6 +299,26 @@ void portduinoSetup()
initGPIOPin(settingsMap[touchscreenIRQ], gpioChipName);
}
// if we specify a touchscreen dev, that is SPI.
// else if we specify a screen dev, that is SPI
// else if we specify a LoRa dev, that is SPI.
if (settingsStrings[touchscreenspidev] != "") {
SPI.begin(settingsStrings[touchscreenspidev].c_str());
DisplaySPI = new HardwareSPI;
DisplaySPI->begin(settingsStrings[displayspidev].c_str());
LoraSPI = new HardwareSPI;
LoraSPI->begin(settingsStrings[spidev].c_str());
} else if (settingsStrings[displayspidev] != "") {
SPI.begin(settingsStrings[displayspidev].c_str());
DisplaySPI = &SPI;
LoraSPI = new HardwareSPI;
LoraSPI->begin(settingsStrings[spidev].c_str());
} else {
SPI.begin(settingsStrings[spidev].c_str());
LoraSPI = &SPI;
DisplaySPI = &SPI;
}
return;
}
@@ -284,4 +336,4 @@ int initGPIOPin(int pinNum, std::string gpioChipName)
std::cout << "Warning, cannot claim pin " << gpio_name << (p ? p.__cxa_exception_type()->name() : "null") << std::endl;
return ERRNO_DISABLED;
}
}
}

View File

@@ -13,6 +13,7 @@ enum configNames {
dio3_tcxo_voltage,
use_rf95,
use_sx1280,
use_sx1268,
user,
gpiochip,
spidev,
@@ -21,14 +22,24 @@ enum configNames {
touchscreenModule,
touchscreenCS,
touchscreenIRQ,
touchscreenI2CAddr,
touchscreenBusFrequency,
touchscreenRotate,
touchscreenspidev,
displayspidev,
displayBusFrequency,
displayPanel,
displayWidth,
displayHeight,
displayCS,
displayDC,
displayRGBOrder,
displayBacklight,
displayBacklightPWMChannel,
displayBacklightInvert,
displayReset,
displayRotate,
displayOffsetRotate,
displayOffsetX,
displayOffsetY,
displayInvert,
@@ -39,10 +50,12 @@ enum configNames {
webserverrootpath,
maxnodes
};
enum { no_screen, st7789, st7735, st7735s, ili9341 };
enum { no_touchscreen, xpt2046, stmpe610 };
enum { no_screen, x11, st7789, st7735, st7735s, st7796, ili9341, ili9488, hx8357d };
enum { no_touchscreen, xpt2046, stmpe610, gt911, ft5x06 };
enum { level_error, level_warn, level_info, level_debug };
extern std::map<configNames, int> settingsMap;
extern std::map<configNames, std::string> settingsStrings;
int initGPIOPin(int pinNum, std::string gpioChipname);
int initGPIOPin(int pinNum, std::string gpioChipname);
extern HardwareSPI *DisplaySPI;
extern HardwareSPI *LoraSPI;

View File

@@ -157,6 +157,10 @@ void initDeepSleep()
for (uint8_t i = 0; i <= GPIO_NUM_MAX; i++) {
if (rtc_gpio_is_valid_gpio((gpio_num_t)i))
rtc_gpio_hold_dis((gpio_num_t)i);
// ESP32 (original)
else if (GPIO_IS_VALID_OUTPUT_GPIO((gpio_num_t)i))
gpio_hold_dis((gpio_num_t)i);
}
}
#endif
@@ -207,9 +211,10 @@ void doDeepSleep(uint32_t msecToWake, bool skipPreflight = false)
// esp_wifi_stop();
waitEnterSleep(skipPreflight);
#ifdef NIMBLE_DEINIT_FOR_DEEPSLEEP
// Extra power saving on some devices
nimbleBluetooth->deinit();
#if defined(ARCH_ESP32) && !MESHTASTIC_EXCLUDE_BLUETOOTH
// Full shutdown of bluetooth hardware
if (nimbleBluetooth)
nimbleBluetooth->deinit();
#endif
#ifdef ARCH_ESP32
@@ -258,14 +263,17 @@ void doDeepSleep(uint32_t msecToWake, bool skipPreflight = false)
}
#ifdef BUTTON_PIN
// Avoid leakage through button pin
pinMode(BUTTON_PIN, INPUT);
gpio_hold_en((gpio_num_t)BUTTON_PIN);
if (GPIO_IS_VALID_OUTPUT_GPIO(BUTTON_PIN)) {
pinMode(BUTTON_PIN, INPUT);
gpio_hold_en((gpio_num_t)BUTTON_PIN);
}
#endif
// LoRa CS (RADIO_NSS) needs to stay HIGH, even during deep sleep
pinMode(LORA_CS, OUTPUT);
digitalWrite(LORA_CS, HIGH);
gpio_hold_en((gpio_num_t)LORA_CS);
if (GPIO_IS_VALID_OUTPUT_GPIO(LORA_CS)) {
// LoRa CS (RADIO_NSS) needs to stay HIGH, even during deep sleep
pinMode(LORA_CS, OUTPUT);
digitalWrite(LORA_CS, HIGH);
gpio_hold_en((gpio_num_t)LORA_CS);
}
#endif
#ifdef HAS_PMU

View File

@@ -0,0 +1,37 @@
// Need this file for ESP32-S3
// No need to modify this file, changes to pins imported from variant.h
// Most is similar to https://github.com/espressif/arduino-esp32/blob/master/variants/esp32s3/pins_arduino.h
#ifndef Pins_Arduino_h
#define Pins_Arduino_h
#include <stdint.h>
#include <variant.h>
#define USB_VID 0x303a
#define USB_PID 0x1001
#define EXTERNAL_NUM_INTERRUPTS 46
#define NUM_DIGITAL_PINS 48
#define NUM_ANALOG_INPUTS 20
#define analogInputToDigitalPin(p) (((p) < 20) ? (analogChannelToDigitalPin(p)) : -1)
#define digitalPinToInterrupt(p) \
(((p) < 48) ? (p) : -1) // Maybe it should be <= 48 but this is from a trustworthy source so it is likely correct
#define digitalPinHasPWM(p) (p < 46)
// Serial
static const uint8_t TX = UART_TX;
static const uint8_t RX = UART_RX;
// Default SPI will be mapped to Radio
static const uint8_t SS = LORA_CS;
static const uint8_t SCK = LORA_SCK;
static const uint8_t MOSI = LORA_MOSI;
static const uint8_t MISO = LORA_MISO;
// The default Wire will be mapped to PMU and RTC
static const uint8_t SCL = I2C_SCL;
static const uint8_t SDA = I2C_SDA;
#endif /* Pins_Arduino_h */

View File

@@ -0,0 +1,8 @@
[env:CDEBYTE_EoRa-S3]
extends = esp32s3_base
board = CDEBYTE_EoRa-S3
build_flags =
${esp32s3_base.build_flags}
-D CDEBYTE_EORA_S3
-I variants/CDEBYTE_EoRa-S3
-D GPS_POWER_TOGGLE

View File

@@ -0,0 +1,63 @@
// LED - status indication
#define LED_PIN 37
// Button - user interface
#define BUTTON_PIN 0 // This is the BOOT button, and it has its own pull-up resistor
// SD card - TODO: test, currently untested, copied from T3S3 variant
#define HAS_SDCARD
#define SDCARD_USE_SPI1
// TODO: rename this to make this SD-card specific
#define SPI_CS 13
#define SPI_SCK 14
#define SPI_MOSI 11
#define SPI_MISO 2
// FIXME: there are two other SPI pins that are not defined here
// Compatibility
#define SDCARD_CS SPI_CS
// Battery voltage monitoring - TODO: test, currently untested, copied from T3S3 variant
#define BATTERY_PIN 1 // A battery voltage measurement pin, voltage divider connected here to measure battery voltage
#define ADC_CHANNEL ADC1_GPIO1_CHANNEL
#define ADC_MULTIPLIER \
2.11 // ratio of voltage divider = 2.0 (R10=1M, R13=1M), plus some undervoltage correction - TODO: this was carried over from
// the T3S3, test to see if the undervoltage correction is needed.
// Display - OLED connected via I2C by the default hardware configuration
#define HAS_SCREEN 1
#define USE_SSD1306
#define I2C_SCL 17
#define I2C_SDA 18
// UART - The 1mm JST SH connector closest to the USB-C port
#define UART_TX 43
#define UART_RX 44
// Peripheral I2C - The 1mm JST SH connector furthest from the USB-C port which follows Adafruit connection standard. There are no
// pull-up resistors on these lines, the downstream device needs to include them. TODO: test, currently untested
#define I2C_SCL1 21
#define I2C_SDA1 10
// Radio
#define USE_SX1262 // CDEBYTE EoRa-S3-900TB <- CDEBYTE E22-900MM22S <- Semtech SX1262
#define USE_SX1268 // CDEBYTE EoRa-S3-400TB <- CDEBYTE E22-400MM22S <- Semtech SX1268
#define SX126X_CS 7
#define LORA_SCK 5
#define LORA_MOSI 6
#define LORA_MISO 3
#define SX126X_RESET 8
#define SX126X_BUSY 34
#define SX126X_DIO1 33
#define SX126X_DIO2_AS_RF_SWITCH // All switching is performed with DIO2, it is automatically inverted using circuitry.
// CDEBYTE EoRa-S3 uses an XTAL, thus we do not need DIO3 as TCXO voltage reference. Don't define SX126X_DIO3_TCXO_VOLTAGE for
// simplicity rather than defining it as 0.
#define SX126X_MAX_POWER \
22 // E22-900MM22S and E22-400MM22S have a raw SX1262 or SX1268 respsectively, they are rated to output up and including 22
// dBm out of their SX126x IC.
// Compatibility with old variant.h file structure - FIXME: this should be done in the respective radio interface modules to clean
// up all variants.
#define LORA_CS SX126X_CS
#define LORA_DIO1 SX126X_DIO1

View File

@@ -29,10 +29,7 @@ const uint32_t g_ADigitalPinMap[] = {
void initVariant()
{
// LED1 & LED2
// LED1
pinMode(PIN_LED1, OUTPUT);
ledOff(PIN_LED1);
pinMode(PIN_LED2, OUTPUT);
ledOff(PIN_LED2);
}
}

View File

@@ -43,16 +43,12 @@ extern "C" {
#define NUM_ANALOG_OUTPUTS (0)
// LEDs
#define PIN_LED1 (0 + 12) // Blue LED P1.12
#define PIN_LED2 (0 + 6) // Built in Green P0.06
// Green Built in LED1
// #define PIN_LED1 (0 + 6) // LED1 P1.15
// RGB NeoPixel LED2
// #define PIN_LED1 (0 + 8) Red
// #define PIN_LED1 (32 + 9) Green
// #define PIN_LED1 (0 + 12) Blue
#define PIN_LED1 (0 + 6) // Built in Green P0.06
#define PIN_LED2 (0 + 6) // Just here for completeness
#define RGBLED_RED (0 + 8) // Red of RGB P0.08
#define RGBLED_GREEN (32 + 9) // Green of RGB P1.09
#define RGBLED_BLUE (0 + 12) // Blue of RGB P0.12
#define RGBLED_CA // comment out this line if you have a common cathode type, as defined use common anode logic
#define LED_BUILTIN PIN_LED1
#define LED_CONN PIN_LED2
@@ -168,4 +164,4 @@ static const uint8_t SCK = PIN_SPI_SCK;
* Arduino objects - C++ only
*----------------------------------------------------------------------------*/
#endif
#endif

View File

@@ -0,0 +1,37 @@
// Need this file for ESP32-S3
// No need to modify this file, changes to pins imported from variant.h
// Most is similar to https://github.com/espressif/arduino-esp32/blob/master/variants/esp32s3/pins_arduino.h
#ifndef Pins_Arduino_h
#define Pins_Arduino_h
#include <stdint.h>
#include <variant.h>
#define USB_VID 0x303a
#define USB_PID 0x1001
#define EXTERNAL_NUM_INTERRUPTS 46
#define NUM_DIGITAL_PINS 48
#define NUM_ANALOG_INPUTS 20
#define analogInputToDigitalPin(p) (((p) < 20) ? (analogChannelToDigitalPin(p)) : -1)
#define digitalPinToInterrupt(p) \
(((p) < 48) ? (p) : -1) // Maybe it should be <= 48 but this is from a trustworthy source so it is likely correct
#define digitalPinHasPWM(p) (p < 46)
// Serial
static const uint8_t TX = UART_TX;
static const uint8_t RX = UART_RX;
// Default SPI will be mapped to Radio
static const uint8_t SS = LORA_CS;
static const uint8_t SCK = LORA_SCK;
static const uint8_t MOSI = LORA_MOSI;
static const uint8_t MISO = LORA_MISO;
// The default Wire will be mapped to PMU and RTC
static const uint8_t SCL = I2C_SCL;
static const uint8_t SDA = I2C_SDA;
#endif /* Pins_Arduino_h */

View File

@@ -0,0 +1,9 @@
[env:EBYTE_ESP32-S3]
extends = esp32s3_base
; board assumes the lowest spec WROOM module: 4 MB (Quad SPI) Flash, No PSRAM
board = ESP32-S3-WROOM-1-N4
board_level = extra
build_flags =
${esp32s3_base.build_flags}
-D EBYTE_ESP32_S3
-I variants/EBYTE_ESP32-S3

View File

@@ -0,0 +1,193 @@
// Supporting information: https://github.com/S5NC/EBYTE_ESP32-S3/
// Originally developed for E22-900M30S with ESP32-S3-WROOM-1-N4
// NOTE: Uses ESP32-S3-WROOM-1-N4.json in boards folder (via platformio.ini board field), assumes 4 MB (quad SPI) flash, no PSRAM
// FIXME: implement SX12 module type autodetection and have setup for each case (add E32 support)
// E32 has same pinout except having extra pins. I assume that the GND on it is connected internally to other GNDs so it is not a
// problem to NC the extra GND pins.
// For each EBYTE module pin in this section, provide the pin number of the ESP32-S3 you connected it to
// The ESP32-S3 is great because YOU CAN USE PRACTICALLY ANY PINS for the connections, but avoid some pins (such as on the WROOM
// modules the following): strapping pins (except 0 as a user button input as it already has a pulldown resistor in typical
// application schematic) (0, 3, 45, 46), USB-reserved (19, 20), and pins which aren't present on the WROOM-2 module for
// compatiblity as it uses octal SPI, or are likely connected internally in either WROOM version (26-37), and avoid pins whose
// voltages are set by the SPI voltage (47, 48), and pins that don't exist (22-25) You can ALSO set the SPI pins (SX126X_CS,
// SX126X_SCK, SX126X_MISO, SX126X_MOSI) to any pin with the ESP32-S3 due to \ GPIO Matrix / IO MUX / RTC IO MUX \, and also the
// serial pins, but this isn't recommended for Serial0 as the WROOM modules have a 499 Ohm resistor on U0TXD (to reduce harmonics
// but also acting as a sort of protection)
// We have many free pins on the ESP32-S3-WROOM-X-Y module, perhaps it is best to use one of its pins to control TXEN, and use
// DIO2 as an extra interrupt, but right now Meshtastic does not benefit from having another interrupt pin available.
// Adding two 0-ohm links on your PCB design so that you can choose between the two modes for controlling the E22's TXEN would
// enable future software to make the most of an extra available interrupt pin
// Possible improvement: can add extremely low resistance MOSFET to physically toggle power to E22 module when in full sleep (not
// waiting for interrupt)?
// PA stands for Power Amplifier, used when transmitting to increase output power
// LNA stands for Low Noise Amplifier, used when \ listening for / receiving \ data to increase sensitivity
//////////////////////////////////////////////////////////////////////////////////
// //
// Have custom connections or functionality? Configure them in this section //
// //
//////////////////////////////////////////////////////////////////////////////////
#define SX126X_CS 14 // EBYTE module's NSS pin // FIXME: rename to SX126X_SS
#define LORA_SCK 21 // EBYTE module's SCK pin
#define LORA_MOSI 38 // EBYTE module's MOSI pin
#define LORA_MISO 39 // EBYTE module's MISO pin
#define SX126X_RESET 40 // EBYTE module's NRST pin
#define SX126X_BUSY 41 // EBYTE module's BUSY pin
#define SX126X_DIO1 42 // EBYTE module's DIO1 pin
// We don't define a pin for SX126X_DIO2 as Meshtastic doesn't use it as an interrupt output, so it is never connected to an MCU
// pin! Also E22 module datasheets say not to connect it to an MCU pin.
// We don't define a pin for SX126X_DIO3 as Meshtastic doesn't use it as an interrupt output, so it is never connected to an MCU
// pin! Also E22 module datasheets say to use it as the TCXO's reference voltage.
// E32 module (which uses SX1276) may not have ability to set TCXO voltage using a DIO pin.
// The radio module needs to be told whether to enable RX mode or TX mode. Each radio module takes different actions based on
// these values, but generally the path from the antenna to SX1262 is changed from signal output to signal input. Also, if there
// are LNAs (Low-Noise Amplifiers) or PAs (Power Amplifiers) in the output or input paths, their power is also controlled by
// these pins. You should never have both TXEN and RXEN set high, this can cause problems for some radio modules, and is
// commonly referred to as 'undefined behaviour' in datasheets. For the SX1262, you shouldn't connect DIO2 to the MCU. DIO2 is
// an output only, and can be controlled via SPI instructions, the use for this is to save an MCU pin by using the DIO2 pin to
// control the RF switching mode.
// Choose ONLY ONE option from below, comment in/out the '/*'s and '*/'s
// SX126X_TXEN is the E22's [SX1262's] TXEN pin, SX126X_RXEN is the E22's [SX1262's] RXEN pin
// Option 1: E22's TXEN pin connected to E22's DIO2 pin, E22's RXEN pin connected to NEGATED output of E22's DIO2 pin (more
// expensive option hardware-wise, is the 'most proper' way, removes need for routing one/two traces from MCU to RF switching
// pins), however you can't have E22 in low-power 'sleep' mode (TXEN and RXEN both low cannot be achieved this this option).
/*
#define SX126X_DIO2_AS_RF_SWITCH
#define SX126X_TXEN RADIOLIB_NC
#define SX126X_RXEN RADIOLIB_NC
*/
// Option 2: E22's TXEN pin connected to E22's DIO2 pin, E22's RXEN pin connected to MCU pin (cheaper option hardware-wise,
// removes need for routing another trace from MCU to an RF switching pin).
// /*
#define SX126X_DIO2_AS_RF_SWITCH
#define SX126X_TXEN RADIOLIB_NC
#define SX126X_RXEN 10
// */
// Option 3: E22's TXEN pin connected to MCU pin, E22's RXEN pin connected to MCU pin (cheaper option hardware-wise, allows for
// ramping up PA before transmission (add/expand on feature yourself in RadioLib) if PA takes a while to stabilise)
// Don't define DIO2_AS_RF_SWITCH because we only use DIO2 or an MCU pin mutually exclusively to connect to E22's TXEN (to prevent
// a short if they are both connected at the same time (suboptimal PCB design) and there's a slight non-neglibible delay and/or
// voltage difference between DIO2 and TXEN). Can use DIO2 as an IRQ (but not in Meshtastic at the moment).
/*
#define SX126X_TXEN 9
#define SX126X_RXEN 10
*/
// (NOT RECOMMENDED, if need to ramp up PA before transmission, better to use option 3)
// Option 4: E22's TXEN pin connected to MCU pin, E22's RXEN pin connected to NEGATED output of E22's DIO2 pin (more expensive
// option hardware-wise, allows for ramping up PA before transmission (add/expand on feature yourself in RadioLib) if PA takes
// a while to stabilise, removes need for routing another trace from MCU to an RF switching pin, however may mean if in
// RadioLib you don't tell DIO2 to go high to indicate transmission (so the negated output goes to RXEN to turn the LNA off)
// then you may end up enabling E22's TXEN and RXEN pins at the same time whilst you ramp up the PA which is not ideal,
// changing DIO2's switching advance in RadioLib may not even be possible, may be baked into the SX126x).
/*
#define SX126X_DIO2_AS_RF_SWITCH
#define SX126X_TXEN 9
#define SX126X_RXEN RADIOLIB_NC
*/
// Status
#define LED_PIN 1
#define LED_INVERTED 0
// External notification
// FIXME: Check if EXT_NOTIFY_OUT actualy has any effect and removes the need for setting the external notication pin in the
// app/preferences
#define EXT_NOTIFY_OUT 2 // The GPIO pin that acts as the external notification output (here we connect an LED to it)
// Buzzer
#define PIN_BUZZER 11
// Buttons
#define BUTTON_PIN 0 // Use the BOOT button as the user button
// I2C
#define I2C_SCL 18
#define I2C_SDA 8
// UART
#define UART_TX 43
#define UART_RX 44
// Power
// Outputting 22dBm from SX1262 results in ~30dBm E22-900M30S output (module only uses last stage of the YP2233W PA)
// Respect local regulations! If your E22-900M30S outputs the advertised 30 dBm and you use a 6 dBi antenna, you are at the
// equivalent of 36 EIRP (Effective Isotropic Radiated Power), which in this case is the limit for non-HAM users in the US (4W
// EIRP, at SPECIFIC frequencies).
// In the EU (and UK), as of now, you are allowed 27 dBm ERP which is 29.15 EIRP.
// https://eur-lex.europa.eu/legal-content/EN/TXT/?uri=CELEX:32022D0180
// https://www.legislation.gov.uk/uksi/1999/930/schedule/6/made
// To respect the 29.15 dBm EIRP (at SPECIFIC frequencies, others are lower) EU limit with a 2.5 dBi gain antenna, consulting
// https://github.com/S5NC/EBYTE_ESP32-S3/blob/main/power%20testing.txt, assuming 0.1 dBm insertion loss, output 20 dBm from the
// E22-900M30S's SX1262. It is worth noting that if you are in this situation and don't have a HAM license, you may be better off
// with a lower gain antenna, and output the difference as a higher total power input into the antenna, as your EIRP would be the
// same, but you would get a wider angle of coverage. Also take insertion loss and possibly VSWR into account
// (https://www.everythingrf.com/tech-resources/vswr). Please check regulations yourself and check airtime, usage (for example
// whether you are airborne), frequency, and power laws.
#define SX126X_MAX_POWER 22 // SX126xInterface.cpp defaults to 22 if not defined, but here we define it for good practice
// Display
// FIXME: change behavior in src to default to not having screen if is undefined
// FIXME: remove 0/1 option for HAS_SCREEN in src, change to being defined or not
// FIXME: check if it actually causes a crash when not specifiying that a display isn't present
#define HAS_SCREEN 0 // Assume no screen present by default to prevent crash...
// GPS
// FIXME: unsure what to define HAS_GPS as if GPS isn't always present
#define HAS_GPS 1 // Don't need to set this to 0 to prevent a crash as it doesn't crash if GPS not found, will probe by default
#define PIN_GPS_EN 15
#define GPS_EN_ACTIVE 1
#define GPS_TX_PIN 16
#define GPS_RX_PIN 17
/////////////////////////////////////////////////////////////////////////////////
// //
// You should have no need to modify the code below, nor in pins_arduino.h //
// //
/////////////////////////////////////////////////////////////////////////////////
#define USE_SX1262 // E22-900M30S, E22-900M22S, and E22-900MM22S (not E220!) use SX1262
#define USE_SX1268 // E22-400M30S, E22-400M33S, E22-400M22S, and E22-400MM22S use SX1268
// The below isn't needed as we directly define SX126X_TXEN and SX126X_RXEN instead of using proxies E22_TXEN and E22_RXEN
/*
// FALLBACK: If somehow E22_TXEN isn't defined or clearly isn't a valid pin number, set it to RADIOLIB_NC to avoid SX126X_TXEN
being defined but having no value #if (!defined(E22_TXEN) || !(0 <= E22_TXEN && E22_TXEN <= 48)) #define E22_TXEN RADIOLIB_NC
#endif
// FALLBACK: If somehow E22_RXEN isn't defined or clearly isn't a valid pin number, set it to RADIOLIB_NC to avoid SX126X_RXEN
being defined but having no value #if (!defined(E22_RXEN) || !(0 <= E22_RXEN && E22_RXEN <= 48)) #define E22_RXEN RADIOLIB_NC
#endif
#define SX126X_TXEN E22_TXEN
#define SX126X_RXEN E22_RXEN
*/
// E22 series TCXO voltage is 1.8V per https://www.ebyte.com/en/pdf-down.aspx?id=781 (source
// https://github.com/jgromes/RadioLib/issues/12#issuecomment-520695575), so set it as such
#define SX126X_DIO3_TCXO_VOLTAGE 1.8
#define LORA_CS SX126X_CS // FIXME: for some reason both are used in /src
// Many of the below values would only be used if USE_RF95 was defined, but it's not as we aren't actually using an RF95, just
// that the 4 pins above are named like it If they aren't used they don't need to be defined and doing so cause confusion to those
// adapting this file LORA_RESET value is never used in src (as we are not using RF95), so no need to define LORA_DIO0 is not used
// in src (as we are not using RF95) as SX1262 does not have it per SX1262 datasheet, so no need to define
// FIXME: confirm that the linked lines below are actually only called when using the SX126x or SX128x and no other modules
// then use SX126X_DIO1 and SX128X_DIO1 respectively for that purpose, removing the need for RF95-style LORA_* definitions when
// the RF95 isn't used
#define LORA_DIO1 \
SX126X_DIO1 // The old name is used in
// https://github.com/meshtastic/firmware/blob/7eff5e7bcb2084499b723c5e3846c15ee089e36d/src/sleep.cpp#L298, so
// must also define the old name
// LORA_DIO2 value is never used in src (as we are not using RF95), so no need to define, and if DIO2_AS_RF_SWITCH is set then it
// cannot serve any extra function even if requested to LORA_DIO3 value is never used in src (as we are not using RF95), so no
// need to define, and DIO3_AS_TCXO_AT_1V8 is set so it cannot serve any extra function even if requested to (from 13.3.2.1
// DioxMask in SX1262 datasheet: Note that if DIO2 or DIO3 are used to control the RF Switch or the TCXO, the IRQ will not be
// generated even if it is mapped to the pins.)

View File

@@ -0,0 +1,10 @@
[env:TWC_mesh_v4]
extends = nrf52840_base
board = TWC_mesh_v4
board_level = extra
build_flags = ${nrf52840_base.build_flags} -I variants/TWC_mesh_v4 -D TWC_mesh_v4 -L".pio\libdeps\TWC_mesh_v4\BSEC2 Software Library\src\cortex-m4\fpv4-sp-d16-hard"
build_src_filter = ${nrf52_base.build_src_filter} +<../variants/TWC_mesh_v4>
lib_deps =
${nrf52840_base.lib_deps}
zinggjm/GxEPD2@^1.4.9
debug_tool = jlink

View File

@@ -0,0 +1,38 @@
/*
Copyright (c) 2014-2015 Arduino LLC. All right reserved.
Copyright (c) 2016 Sandeep Mistry All right reserved.
Copyright (c) 2018, Adafruit Industries (adafruit.com)
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "variant.h"
#include "nrf.h"
#include "wiring_constants.h"
#include "wiring_digital.h"
const uint32_t g_ADigitalPinMap[] = {
// P0
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
// P1
32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47};
void initVariant()
{
// LED1 & LED2
pinMode(PIN_LED1, OUTPUT);
ledOff(PIN_LED1);
pinMode(PIN_LED2, OUTPUT);
ledOff(PIN_LED2);
}

View File

@@ -0,0 +1,133 @@
#ifndef _VARIANT_TWC_MESH_V4_
#define _VARIANT_TWC_MESH_V4_
#define PCA10059
/** Master clock frequency */
#define VARIANT_MCK (64000000ul)
#define USE_LFXO // Board uses 32khz crystal for LF
// define USE_LFRC // Board uses RC for LF
/*----------------------------------------------------------------------------
* Headers
*----------------------------------------------------------------------------*/
#include "WVariant.h"
#ifdef __cplusplus
extern "C" {
#endif // __cplusplus
// Number of pins defined in PinDescription array
#define PINS_COUNT (48)
#define NUM_DIGITAL_PINS (48)
#define NUM_ANALOG_INPUTS (6)
#define NUM_ANALOG_OUTPUTS (0)
// LEDs
#define PIN_LED1 (32 + 10) // Blue LED P1.10
#define PIN_LED2 (32 + 15) // Built in Green P1.15
// RGB NeoPixel LED2
// #define PIN_LED1 (0 + 8) Red
// #define PIN_LED1 (32 + 9) Green
// #define PIN_LED1 (0 + 12) Blue
#define LED_BUILTIN PIN_LED1
#define LED_CONN PIN_LED2
#define LED_GREEN PIN_LED1
#define LED_BLUE PIN_LED2
#define LED_STATE_ON 0 // State when LED is litted
/*
* Buttons
*/
#define PIN_BUTTON1 (32 + 2) // BTN_DN P1.02 Built in button
/*
* Analog pins
*/
#define PIN_A0 (0 + 29) // using VDIV (A6 / P0.29)
static const uint8_t A0 = PIN_A0;
#define ADC_RESOLUTION 14
// Other pins
#define PIN_AREF (-1) // AREF Not yet used
static const uint8_t AREF = PIN_AREF;
/*
* Serial interfaces
*/
#define PIN_SERIAL1_RX (0 + 24)
#define PIN_SERIAL1_TX (0 + 25)
// Connected to Jlink CDC
#define PIN_SERIAL2_RX (-1)
#define PIN_SERIAL2_TX (-1)
/*
* SPI Interfaces
*/
#define SPI_INTERFACES_COUNT 1
#define PIN_SPI_MISO (0 + 15) // MISO P0.15
#define PIN_SPI_MOSI (0 + 13) // MOSI P0.13
#define PIN_SPI_SCK (0 + 14) // SCK P0.14
static const uint8_t SS = (0 + 6); // LORA_CS P0.6
static const uint8_t MOSI = PIN_SPI_MOSI;
static const uint8_t MISO = PIN_SPI_MISO;
static const uint8_t SCK = PIN_SPI_SCK;
////#define USE_EINK
#define USE_SSD1306
/*
* Wire Interfaces
*/
#define WIRE_INTERFACES_COUNT 1
#define PIN_WIRE_SDA (0 + 12) // SDA P0.12
#define PIN_WIRE_SCL (0 + 11) // SCL P0.11
// NiceRF 868 LoRa module
#define USE_SX1262
#define USE_LLCC68
#define SX126X_CS (0 + 6) // LORA_CS P0.06
#define SX126X_DIO1 (0 + 7) // DIO1 P0.07
#define SX126X_BUSY (0 + 26) // LORA_BUSY P0.26
#define SX126X_RESET (0 + 27) // LORA_RESET P0.27
#define SX126X_DIO3_TCXO_VOLTAGE 1.8
#define PIN_GPS_EN (-1)
#define PIN_GPS_PPS (-1) // Pulse per second input from the GPS
#define GPS_RX_PIN PIN_SERIAL1_RX
#define GPS_TX_PIN PIN_SERIAL1_TX
// Battery
// The battery sense is hooked to pin A6 (0.29)
#define BATTERY_PIN PIN_A0
// and has 12 bit resolution
#define BATTERY_SENSE_RESOLUTION_BITS 12
#define BATTERY_SENSE_RESOLUTION 4096.0
#undef AREF_VOLTAGE
#define AREF_VOLTAGE 3.0
#define VBAT_AR_INTERNAL AR_INTERNAL_3_0
#define ADC_MULTIPLIER (2.0F)
#ifdef __cplusplus
}
#endif
/*----------------------------------------------------------------------------
* Arduino objects - C++ only
*----------------------------------------------------------------------------*/
#endif

View File

@@ -15,4 +15,4 @@ upload_protocol = esptool
upload_speed = 460800
lib_deps =
${esp32_base.lib_deps}
makuna/NeoPixelBus@^2.7.1
adafruit/Adafruit NeoPixel @ ^1.12.0

View File

@@ -1,5 +1,4 @@
// https://betafpv.com/products/elrs-micro-tx-module
#include <NeoPixelBus.h>
// 0.96" OLED
#define I2C_SDA 22
@@ -15,7 +14,11 @@
#define LORA_CS 5
#define RF95_FAN_EN 17
#define LED_PIN 16 // This is a LED_WS2812 not a standard LED
// #define LED_PIN 16 // This is a LED_WS2812 not a standard LED
#define HAS_NEOPIXEL // Enable the use of neopixels
#define NEOPIXEL_COUNT 1 // How many neopixels are connected
#define NEOPIXEL_DATA 16 // gpio pin used to send data to the neopixels
#define NEOPIXEL_TYPE (NEO_GRB + NEO_KHZ800) // type of neopixels in use
#define BUTTON_PIN 25
#define BUTTON_NEED_PULLUP
@@ -31,4 +34,4 @@
#define SX128X_TXEN 26
#define SX128X_RXEN 27
#define SX128X_RESET LORA_RESET
#define SX128X_MAX_POWER 13
#define SX128X_MAX_POWER 13

View File

@@ -22,4 +22,4 @@ build_flags = ${esp32_base.build_flags}
lib_deps = ${esp32s3_base.lib_deps}
zinggjm/GxEPD2@^1.5.3
;adafruit/Adafruit NeoPixel@^1.10.7
adafruit/Adafruit NeoPixel @ ^1.12.0

View File

@@ -10,6 +10,10 @@
// #define LED_PIN PIN_LED
// Board has RGB LED 21
#define HAS_NEOPIXEL // Enable the use of neopixels
#define NEOPIXEL_COUNT 1 // How many neopixels are connected
#define NEOPIXEL_DATA 21 // gpio pin used to send data to the neopixels
#define NEOPIXEL_TYPE (NEO_GRB + NEO_KHZ800) // type of neopixels in use
// The usbPower state is revered ?
// DEBUG | ??:??:?? 365 [Power] Battery: usbPower=0, isCharging=0, batMv=4116, batPct=90

View File

@@ -55,6 +55,3 @@
#define SX126X_DIO2_AS_RF_SWITCH
#define SX126X_DIO3_TCXO_VOLTAGE 1.8
// Power management
#define NIMBLE_DEINIT_FOR_DEEPSLEEP // Required to reach manufacturers claim of 18uA

View File

@@ -55,6 +55,3 @@
#define SX126X_DIO2_AS_RF_SWITCH
#define SX126X_DIO3_TCXO_VOLTAGE 1.8
// Power management
#define NIMBLE_DEINIT_FOR_DEEPSLEEP // Required to reach manufacturers claim of 18uA

View File

@@ -20,4 +20,5 @@ build_src_filter = ${nrf52_base.build_src_filter} +<../variants/lora_relay_v1>
lib_deps =
${nrf52840_base.lib_deps}
sparkfun/SparkFun BQ27441 LiPo Fuel Gauge Arduino Library@^1.1.0
bodmer/TFT_eSPI@^2.4.76
bodmer/TFT_eSPI@^2.4.76
adafruit/Adafruit NeoPixel @ ^1.12.0

View File

@@ -44,7 +44,11 @@ extern "C" {
// LEDs
#define PIN_LED1 (3)
#define PIN_LED2 (4)
#define PIN_NEOPIXEL (8)
// #define PIN_NEOPIXEL (8)
#define HAS_NEOPIXEL // Enable the use of neopixels
#define NEOPIXEL_COUNT 1 // How many neopixels are connected
#define NEOPIXEL_DATA 8 // gpio pin used to send data to the neopixels
#define NEOPIXEL_TYPE (NEO_GRB + NEO_KHZ800) // type of neopixels in use
#define LED_BUILTIN PIN_LED1
#define LED_CONN PIN_LED2

View File

@@ -23,3 +23,4 @@ lib_deps =
${nrf52840_base.lib_deps}
sparkfun/SparkFun BQ27441 LiPo Fuel Gauge Arduino Library@^1.1.0
bodmer/TFT_eSPI@^2.4.76
adafruit/Adafruit NeoPixel @ ^1.12.0

View File

@@ -61,7 +61,12 @@ extern "C" {
// LEDs
#define PIN_LED1 (3)
#define PIN_LED2 (4)
#define PIN_NEOPIXEL (8)
// #define PIN_NEOPIXEL (8)
#define HAS_NEOPIXEL // Enable the use of neopixels
#define NEOPIXEL_COUNT 1 // How many neopixels are connected
#define NEOPIXEL_DATA 8 // gpio pin used to send data to the neopixels
#define NEOPIXEL_TYPE (NEO_GRB + NEO_KHZ800) // type of neopixels in use
#define PIN_BUZZER (40)
#define LED_BUILTIN PIN_LED1

View File

@@ -13,7 +13,7 @@ platform_packages =
lib_deps =
${esp32_base.lib_deps}
zinggjm/GxEPD2@^1.5.1
adafruit/Adafruit NeoPixel@^1.10.7
adafruit/Adafruit NeoPixel @ ^1.12.0
build_unflags = -DARDUINO_USB_MODE=1
build_flags =
;${esp32_base.build_flags} -D MY_ESP32S3_DIY -I variants/my_esp32s3_diy_eink
@@ -24,4 +24,4 @@ build_flags =
-DEINK_HEIGHT=128
-DBOARD_HAS_PSRAM
-mfix-esp32-psram-cache-issue
-DARDUINO_USB_MODE=0
-DARDUINO_USB_MODE=0

View File

@@ -12,6 +12,10 @@
#define I2C_SCL 17 // 2
// #define LED_PIN 38 // This is a RGB LED not a standard LED
#define HAS_NEOPIXEL // Enable the use of neopixels
#define NEOPIXEL_COUNT 1 // How many neopixels are connected
#define NEOPIXEL_DATA 38 // gpio pin used to send data to the neopixels
#define NEOPIXEL_TYPE (NEO_GRB + NEO_KHZ800) // type of neopixels in use
#define BUTTON_PIN 0 // This is the BOOT button
#define BUTTON_NEED_PULLUP

View File

@@ -12,11 +12,11 @@ platform_packages =
tool-esptoolpy@^1.40500.0
lib_deps =
${esp32_base.lib_deps}
adafruit/Adafruit NeoPixel@^1.10.7
adafruit/Adafruit NeoPixel @ ^1.12.0
build_unflags = -DARDUINO_USB_MODE=1
build_flags =
;${esp32_base.build_flags} -D MY_ESP32S3_DIY -I variants/my_esp32s3_diy_oled
${esp32_base.build_flags} -D PRIVATE_HW -I variants/my_esp32s3_diy_oled
-DBOARD_HAS_PSRAM
-mfix-esp32-psram-cache-issue
-DARDUINO_USB_MODE=0
-DARDUINO_USB_MODE=0

View File

@@ -12,6 +12,10 @@
#define I2C_SCL 17 // 2
// #define LED_PIN 38 // This is a RGB LED not a standard LED
#define HAS_NEOPIXEL // Enable the use of neopixels
#define NEOPIXEL_COUNT 1 // How many neopixels are connected
#define NEOPIXEL_DATA 38 // gpio pin used to send data to the neopixels
#define NEOPIXEL_TYPE (NEO_GRB + NEO_KHZ800) // type of neopixels in use
#define BUTTON_PIN 0 // This is the BOOT button
#define BUTTON_NEED_PULLUP
@@ -53,4 +57,4 @@
// #define PIN_EINK_DC 1
// #define PIN_EINK_RES (-1)
// #define PIN_EINK_SCLK 5
// #define PIN_EINK_MOSI 6
// #define PIN_EINK_MOSI 6

View File

@@ -14,7 +14,7 @@
#define BATTERY_PIN 26
#define BATTERY_SENSE_RESOLUTION_BITS ADC_RESOLUTION
// ratio of voltage divider = 3.0 (R17=200k, R18=100k)
#define ADC_MULTIPLIER 3.1 // 3.0 + a bit for being optimistic
#define ADC_MULTIPLIER 1.84
#define DETECTION_SENSOR_EN 28
@@ -47,4 +47,4 @@
// DIO2 controlls an antenna switch and the TCXO voltage is controlled by DIO3
#define SX126X_DIO2_AS_RF_SWITCH
#define SX126X_DIO3_TCXO_VOLTAGE 1.8
#endif
#endif

View File

@@ -1,5 +1,7 @@
; platformio.ini for unphone meshtastic
[env:unphone]
;build_type = debug ; to make it possible to step through our jtag debugger
extends = esp32s3_base
board_level = extra
board = unphone9
@@ -11,9 +13,20 @@ build_unflags =
-D ARDUINO_USB_MODE
build_flags = ${esp32_base.build_flags}
;-D BOARD_HAS_PSRAM // what's up with this - doesn't seem to be recognised at boot
-D UNPHONE
-I variants/unphone
-D ARDUINO_USB_MODE=0
-D UNPHONE_ACCEL=0
-D UNPHONE_TOUCHS=0
-D UNPHONE_SDCARD=0
-D UNPHONE_UI0=0
-D UNPHONE_LORA=0
-D UNPHONE_FACTORY_MODE=0
build_src_filter = ${esp32_base.build_src_filter} +<../variants/unphone>
lib_deps = ${esp32s3_base.lib_deps}
lovyan03/LovyanGFX@^1.1.8
lovyan03/LovyanGFX @ ^1.1.8
https://gitlab.com/hamishcunningham/unphonelibrary#meshtastic @ ^9.0.0
adafruit/Adafruit NeoPixel @ ^1.12.0

View File

@@ -0,0 +1,21 @@
// meshtastic/firmware/variants/unphone/variant.cpp
#include "unPhone.h"
unPhone unphone = unPhone("meshtastic_unphone");
void initVariant()
{
unphone.begin(); // initialise hardware etc.
unphone.store(unphone.buildTime);
unphone.printWakeupReason(); // what woke us up? (stored, not printed :|)
unphone.checkPowerSwitch(); // if power switch is off, shutdown
unphone.backlight(false); // setup backlight and make sure its off
unphone.expanderPower(true); // enable power to expander / hat / sheild
for (int i = 0; i < 3; i++) { // buzz a bit
unphone.vibe(true);
delay(150);
unphone.vibe(false);
delay(150);
}
}

View File

@@ -1,3 +1,7 @@
// meshtastic/firmware/variants/unphone/variant.h
#pragma once
#define SPI_SCK 39
#define SPI_MOSI 40
#define SPI_MISO 41
@@ -28,7 +32,7 @@
#define TFT_WIDTH 320
#define TFT_OFFSET_X 0
#define TFT_OFFSET_Y 0
#define TFT_OFFSET_ROTATION 6 // the unPhone's screen is wired unusually, 0 is typical value here
#define TFT_OFFSET_ROTATION 6 // unPhone's screen wired unusually, 0 typical
#define TFT_INVERT false
#define SCREEN_ROTATE true
#define SCREEN_TRANSITION_FRAMERATE 5
@@ -37,11 +41,14 @@
#define USE_XPT2046 1
#define TOUCH_CS 38
#define HAS_GPS 0 // the unphone doesn't have a gps module
#define HAS_GPS \
0 // the unphone doesn't have a gps module by default (though
// GPS featherwing -- https://www.adafruit.com/product/3133
// -- can be added)
#undef GPS_RX_PIN
#undef GPS_TX_PIN
#define HAS_SDCARD 1
// #define HAS_SDCARD 1 // causes hang if defined
#define SDCARD_CS 43
#define LED_PIN 13 // the red part of the RGB LED
@@ -49,6 +56,7 @@
#define BUTTON_PIN 21 // Button 3 - square - top button in landscape mode
#define BUTTON_NEED_PULLUP // we do need a helping hand up
#define BUTTON_PIN_ALT 45 // Button 1 - triangle - bottom button in landscape mode
#define I2C_SDA 3 // I2C pins for this board
#define I2C_SCL 4
@@ -58,6 +66,6 @@
// ratio of voltage divider = 3.20 (R1=100k, R2=220k)
// #define ADC_MULTIPLIER 3.2
// #define BATTERY_PIN 13 // A battery voltage measurement pin, voltage divider connected here to measure battery voltage
// #define BATTERY_PIN 13 // battery V measurement pin; vbat divider is here
// #define ADC_CHANNEL ADC2_GPIO13_CHANNEL
// #define BAT_MEASURE_ADC_UNIT 2

View File

@@ -1,4 +1,4 @@
[VERSION]
major = 2
minor = 3
build = 5
build = 7