Compare commits

..

165 Commits

Author SHA1 Message Date
Scott Powell 165fb33d5c * ver bump to v1.7.1 2025-06-29 20:06:24 +10:00
Scott Powell e31017be1a Merge branch 'main' into dev 2025-06-29 20:04:03 +10:00
Scott Powell 187eea1b18 * Preamble now 16 (for most variants) 2025-06-29 20:03:10 +10:00
ripplebiz c4c5d18a79 Merge pull request #456 from recrof/dev
add support for BMP280 temperature+pressure sensor, enable sensor support for tlora 2.1_1.6
2025-06-29 15:28:31 +10:00
recrof bcd31b7cdf fix: missing dependency 2025-06-29 00:28:01 +02:00
recrof 9530744ff4 add support for BMP280 temperature+pressure sensor 2025-06-29 00:17:46 +02:00
ripplebiz cea16bad89 Merge pull request #453 from recrof/dev
sx1276 boards: migrate to std_init()
2025-06-28 21:14:23 +10:00
Rastislav Vysoky 5fa6533291 Merge branch 'ripplebiz:dev' into dev 2025-06-28 11:03:15 +02:00
recrof 1ce180d6ea remove spi.begin in targets 2025-06-28 11:00:13 +02:00
Scott Powell 3bd1dc3ffa * minor tidy ups 2025-06-28 16:10:53 +10:00
ripplebiz 7c9cf2a5ee Merge pull request #446 from cod3doomy/dev
RAK4631: BME680 add and GPS cleanup
2025-06-28 16:00:36 +10:00
recrof 0e197254a2 remove old tbeam def 2025-06-27 17:38:07 +02:00
recrof e16f5349fa manual-merge tbeam conflicts 2025-06-27 15:30:01 +02:00
recrof 95e69cf273 RadioWrapper::std_init: add tbeam, unify coding style 2025-06-27 15:17:51 +02:00
recrof f666b8c8cf RadioWrapper::std_init: add missing definitions for rx/tx switching 2025-06-27 15:16:37 +02:00
recrof 07f25ccac8 sx1276 boards: migrate to std_init() 2025-06-27 15:12:48 +02:00
ripplebiz ba34cff4d4 Merge pull request #452 from fdlamotte/custom_sx1262_TXEN_fix
CustomSX1262: fix typo that would prevent compile when TXEN or RXEN i…
2025-06-27 21:37:57 +10:00
Florent de Lamotte 0f259d3b51 CustomSX1262: fix typo that would prevent compile when TXEN or RXEN is not set 2025-06-27 11:11:12 +02:00
ripplebiz 4e282a423a Merge pull request #451 from fdlamotte/wio-e5-dev_uart
wio-e5-sdk: adjust uart location
2025-06-26 21:51:11 +10:00
Florent 408ed549a8 wio-e5-sdk: adjust uart location 2025-06-26 13:04:15 +02:00
cod3doomy 63247667d0 String removed
Removed all string type casting
2025-06-25 21:12:36 -07:00
cod3doomy c872f72584 Merge branch 'ripplebiz:dev' into dev 2025-06-25 21:08:38 -07:00
ripplebiz 6e670aa2a4 Merge pull request #450 from rfmoz/main
Update faq.md
2025-06-26 13:16:14 +10:00
ripplebiz fe0234d208 Merge pull request #449 from recrof/dev
Station G2 refactor for radio.std_init, set max tx power to 19dBm
2025-06-26 13:10:06 +10:00
Ricardo F. 669ff39cd6 Update faq.md
Order last other questions and add fix to WebFlasher from linux
2025-06-25 22:41:14 +02:00
recrof f15f32e138 Station G2 refactor for radio.std_init, set max tx power to 19dBm 2025-06-25 22:21:22 +02:00
ripplebiz 56df7d15a7 Merge pull request #448 from fdlamotte/rak3x72_LP_Support
rak3x72: support variations in platformio.ini
2025-06-25 22:27:06 +10:00
Florent 387579922b rak3x72: support variations in platformio.ini 2025-06-25 13:55:54 +02:00
ripplebiz 816f3f8a6b Merge pull request #447 from fdlamotte/stm32_halt_reset
stm32: implement halt and reset
2025-06-25 19:04:15 +10:00
Scott Powell 55ff69bd25 * RAK: 'start ota' returned MAC address was reversed 2025-06-25 19:02:16 +10:00
Florent 8ccd4f3660 stm32: implement halt and reset 2025-06-25 11:00:24 +02:00
Scott Powell 556051955d * ESP32Board: added support for Neopixel TX led 2025-06-25 14:54:13 +10:00
Scott Powell 8191c0901b * new variant board: Tenstar C3 2025-06-25 14:34:27 +10:00
Scott Powell b37c8017d9 * Fix: /helpers/esp32/TBeamBoard was breaking non-TBeam builds 2025-06-25 14:04:29 +10:00
cod3doomy 001b996a24 RAK4631: BME680 add and GPS cleanup
- Added the BME680 environment sensor functionality
- Added the GPS Repeater env for those wanting it
- Cleaned up the GPS and other RAK4631SensorManager code

Verified build and functionality on normal and GPS repeater and companion envs.

IAQ readout is still a work in progress, but a placeholder can be seen on Channel 2 of the app telemetry.
2025-06-24 17:46:01 -07:00
ripplebiz 213f01cd40 Merge pull request #443 from fdlamotte/wio_e5_mini_rescue_cli
wio_e5_mini: led and rescue cli
2025-06-24 23:30:52 +10:00
Florent d94f469d53 wio_e5_mini: led and rescue cli 2025-06-24 14:34:42 +02:00
ripplebiz ba7839a60d Merge pull request #442 from oltaco/env-sens-manage-gps-revert
Fix: EnvironmentSensorManager.cpp: revert swapped GPS pins
2025-06-24 12:44:19 +10:00
taco 84c2cfdcf2 fix: revert swapped GPS pins
reverted GPS pin behaviour and swapped GPS pins for tbeam variants.
2025-06-24 12:39:07 +10:00
Scott Powell 6d8fae26da Merge commit '299e85b830f4bf51c2e4d90e3e1bbb59025f608d' into dev 2025-06-24 12:05:00 +10:00
Scott Powell bd020c6167 * removed deprecated tbeam variant 2025-06-24 12:03:51 +10:00
ripplebiz 299e85b830 Merge pull request #441 from oltaco/heltecv3-spi_begin_fix
fix: remove extra spi.begin() on heltec v3
2025-06-24 11:57:08 +10:00
ripplebiz 6ae6f8955a Merge pull request #439 from cod3doomy/dev
T-Beam refactor
2025-06-24 11:48:19 +10:00
ripplebiz b6b15e55ba Merge pull request #428 from 446564/radio-init-nano-g2
update nano g2 to use radio.std_init
2025-06-24 11:38:11 +10:00
taco b8db628ce8 fix: remove extra spi.begin() on heltec v3 2025-06-24 11:27:13 +10:00
Scott Powell 60d0064080 * room server: new posts now delayed by 6 seconds before syncing to clients 2025-06-23 15:56:19 +10:00
cod3doomy 218b96e4aa T-Beam refactor
There is a lot to this PR, so if there are any questions let me know.

The idea here is to merge T-Beam fw so that there is less redundant code. Most versions (except the 0.7) share PMU code, init sequence, and most IO pin definitions.

- Merged all T-Beam board.h files into one TBeamBoard.
- Added PMU code to identify different AXP chips.
- Modified "lilygo tbeam SX1276" variant to cover all T-Beam SX1276 versions
- Modified "lilygo tbeam SX1262" variant to cover all T-Beam SX1262 versions
- Enabled GPS on all T-Beam versions/models
- Enabled BME280 on the Supreme

I am also updating EnvironmentSensorManager to allow for boards that do or don't have GPS enable pins, as well as a PERSISTANT_GPS define check for boards that want GPS to stay active after boot.
2025-06-22 17:46:30 -07:00
Rob Loranger b99d29494e remove begin() 2025-06-22 09:10:49 -07:00
Scott Powell 478a57a6bd * AdvertDataParser: lat/lon can now be zeroes 2025-06-22 21:07:43 +10:00
Scott Powell 12a2f34598 * companion serial protocol ver bump to 6 2025-06-22 21:03:30 +10:00
ripplebiz e7609364ea Merge pull request #438 from liamcottle/storage/nrf52
Add support for storage stats on nRF52/LittleFS
2025-06-22 19:44:14 +10:00
liamcottle 583cdd4980 fix indentation 2025-06-22 21:38:35 +12:00
liamcottle 37c20a348e add support for storage stats on nrf52 2025-06-22 21:35:21 +12:00
Scott Powell 9df3c8c663 * companion: new 'advert_loc_policy' pref. Defaults to ADVERT_LOC_NONE (ie. do Not share location in adverts) 2025-06-22 16:21:04 +10:00
ripplebiz 4f9207f3eb Merge pull request #437 from jquatier/t114-display-flicker
Fix T114 display flicker
2025-06-22 15:15:04 +10:00
ripplebiz 727a044dde Merge pull request #436 from 446564/fix-nano-g2-ota-name
update nano g2 ultra BLE name for OTA
2025-06-22 15:11:30 +10:00
ripplebiz ea7a84b7a3 Merge pull request #427 from cod3doomy/dev
T-Beam refactor for radio.std_init
2025-06-22 15:07:59 +10:00
JQ 3719c0983c increase delay slightly 2025-06-21 18:17:38 -07:00
JQ d680852c99 fix t114 display flicker 2025-06-21 16:13:53 -07:00
cod3doomy ff10f37e7c T-Beam removed redundancy
Removed redundant SPI begin calls
2025-06-21 14:18:38 -07:00
cod3doomy aa9eac16a6 Merge branch 'ripplebiz:dev' into dev 2025-06-21 14:12:29 -07:00
Rob Loranger 5f2ea7ca87 update nano g2 ultra BLE name for OTA 2025-06-21 11:28:47 -07:00
Rob Loranger 0bf03f2309 remove SPI set pins 2025-06-21 11:22:14 -07:00
Scott Powell 1295c4633b * companion: minor refactor of who should invoke UITask::loop() 2025-06-21 20:48:28 +10:00
ripplebiz 39cc221125 Merge pull request #433 from oltaco/HeltecV3-GPS
Heltec v3 GPS support
2025-06-21 20:40:04 +10:00
Scott Powell 205624824a * added std_init() to CustomSX1268 2025-06-21 15:27:58 +10:00
ripplebiz 80d2b6c6bc Merge pull request #432 from oltaco/CustomLLCC68-std_init
added CustomLLCC68::std_init()
2025-06-21 13:56:41 +10:00
ripplebiz 5b1f4b0166 Merge pull request #431 from mattsains/packet-structure
minor changes and fixes to docs
2025-06-21 13:54:53 +10:00
ripplebiz 485749a053 Merge pull request #430 from oltaco/gps-update-fix
fix: EnvironmentSensorManager.cpp: don't update location if GPS is turned off
2025-06-21 13:49:07 +10:00
ripplebiz 8090992342 Merge pull request #429 from oltaco/rak4631-radioinit-refactor
refactor: RAK4631 with CustomSX1262::std_init()
2025-06-21 13:48:22 +10:00
ripplebiz 81a0816e22 Merge pull request #424 from 446564/fix-GH162
fix Heltec v2 getBattMilliVolts ADC multiplier
2025-06-21 13:42:03 +10:00
ripplebiz 00b5d3bcd5 Merge pull request #423 from 446564/fix-GH133
heltec v3 update ADC multipler to fix voltage reading
2025-06-21 13:41:04 +10:00
ripplebiz 7c421c1d2c Merge pull request #420 from 446564/feat-GH142
return range with advert interval setting error
2025-06-21 13:40:27 +10:00
ripplebiz 553e3c10f6 Merge pull request #419 from 446564/feat-GH44
add time and date feedback to cli commands
2025-06-21 13:36:30 +10:00
ripplebiz 5d85ed41c3 Merge pull request #407 from fdlamotte/seeed_xiao_c6
Seeed xiao c6 support
2025-06-21 13:32:15 +10:00
taco 4d2b176ccc feature: GPS support on HeltecV3
GPS support via EnvironmentSensorManager. Connect GPS RX to pin 45, TX to pin 46.
Note that while you can disable using the GPS there is no way to power down the GPS without using a mosfet and adjusting PIN_GPS_EN.
2025-06-21 13:04:39 +10:00
Matthew Sainsbury 1de5753a16 add advert detail 2025-06-20 19:41:07 -07:00
taco 14ff7bfbcd added std_init to CustomLLCC68.h 2025-06-21 11:03:25 +10:00
Matthew Sainsbury 0d78df1b8a minor changes and fixes to docs 2025-06-20 17:59:55 -07:00
taco 83842e4b25 fix: EnvironmentSensorManager.cpp: don't update location if GPS is turned off.
previously the location would always snap to the last heard GPS location after GPS had been on.
2025-06-21 10:09:28 +10:00
taco 9eff882e18 refactor: RAK4631 with CustomSX1262::std_init() 2025-06-21 09:52:39 +10:00
Rob Loranger bf2908faa6 update nano g2 to use radio.std_init 2025-06-20 16:46:16 -07:00
cod3doomy 7bcfbd3243 T-Beam refactor for radio.std_init
Changed radio init for both T-beam (SX1262) and Supreme (SX1262) to include radio.std_init()
2025-06-20 15:06:01 -07:00
Rob Loranger 52a579a366 fix Heltec v2 getBattMilliVolts 2025-06-20 15:00:46 -07:00
Rob Loranger e5ecf29d0c return range with advert interval set error
updates both local and flood advert preference
setting errors to include the allowable range and
time units
2025-06-20 09:22:49 -07:00
Rob Loranger f30698eacb add time output to both clock sync and time <epoch> cli 2025-06-20 08:40:06 -07:00
Rob Loranger dbee0d8b8e update ADC multipler to fix voltage reading 2025-06-20 08:25:19 -07:00
ripplebiz 7f0f3b7753 Merge pull request #418 from fdlamotte/xiao_nrf52-xiao_s3-techo_remove_lora_cr_fallback_from_target
remove LORA_CR fallback from target.cpp on xiao_nrf52, xiao_s3 and t-…
2025-06-20 18:37:16 +10:00
Florent de Lamotte 4579aa25d7 xiao_c6: fallback for LORA_CR is set in std_init 2025-06-20 09:51:35 +02:00
Florent de Lamotte 56e3bb153b remove LORA_CR fallback from target.cpp on xiao_nrf52, xiao_s3 and t-echo 2025-06-20 09:47:58 +02:00
Scott Powell a7c959631f * companion: added Datastore methods: getStorageUsedKb(), getStorageTotalKb()
* companion: CMD_GET_BATTERY now changed to CMD_GET_BATT_AND_STORAGE
2025-06-20 16:47:59 +10:00
Scott Powell 85b164bcf1 * PicoW refactor, now using radio.std_init() 2025-06-20 16:42:49 +10:00
ripplebiz b37f61d720 Merge pull request #416 from jquatier/analog-button
Button handling fix
2025-06-20 14:58:19 +10:00
JQ e6ba025f77 add new quad press 2025-06-19 21:52:57 -07:00
JQ cdca6fa52a Merge branch 'dev' into analog-button 2025-06-19 21:50:16 -07:00
ripplebiz 61301daf51 Merge pull request #415 from jquatier/thinknode-std_init
Thinknode radio.std_init refactor
2025-06-20 13:48:48 +10:00
ripplebiz 5eb08474f1 Merge pull request #417 from oltaco/promicro-CustomSX1262
refactor: promicro with CustomSX1262::std_init()
2025-06-20 13:47:40 +10:00
Scott Powell b865ac6c23 * refactored SensorManager::toggleGps() 2025-06-20 13:44:58 +10:00
ripplebiz 27388fcf2a Merge pull request #404 from fdlamotte/t1000_gps_toggle
Gps toggle on 4 clicks

Will merge, but I'll do a refactor of the gpsToggle()
2025-06-20 13:36:56 +10:00
taco e7b0e9e526 refactor: promicro with CustomSX1262::std_init()
added check in CustomSX1262.h to support both txco and non-txco radios
switched promicro to use CustomSX1262::std_init()
2025-06-20 11:22:34 +10:00
JQ ee68401ad0 fixing button handling to allow both button types simultaneously 2025-06-19 16:47:31 -07:00
JQ bbde446bdf refactoring thinknode to use radio.std_init 2025-06-19 16:27:42 -07:00
Florent de Lamotte 588a986976 t1000e: gps toggle not using board class 2025-06-19 17:26:58 +02:00
ripplebiz eb5826645e Merge pull request #406 from fdlamotte/techo_rx1262_refactor
Techo rx1262 refactor
2025-06-20 00:27:03 +10:00
ripplebiz b9ffd51890 Merge pull request #405 from fdlamotte/xiao_sx1262_init_refactor
Apply refactoring to xiao_nrf52 and xiao_s3
2025-06-20 00:23:50 +10:00
Florent de Lamotte 725ee477ff xiao_c6: apply sx1262 init refactoring 2025-06-19 15:49:30 +02:00
Florent de Lamotte c5167d0fd9 Merge branch 'dev' into seeed_xiao_c6 2025-06-19 15:30:55 +02:00
Florent de Lamotte 574822cafe techo: follow refactoring of CustomSX1262 2025-06-19 15:26:46 +02:00
Florent de Lamotte b65b4d51eb Apply refactoring to xiao_nrf52 and xiao_s3 2025-06-19 15:18:58 +02:00
Scott Powell 587d9d8818 * added CustomSX1262::std_init()
* refactored variants to use std_init(): heltec_v3, t114, xiao_c3
2025-06-19 10:58:10 +10:00
Florent de Lamotte 8765b3d040 Gps toggle on 4 clicks 2025-06-18 11:52:16 +02:00
Scott Powell b3184eb94c * T114 repeater build fix 2025-06-18 17:20:38 +10:00
ripplebiz 6972704c64 Merge pull request #402 from jquatier/t114-variants-display
Adding display support to all T114 builds
2025-06-18 16:49:01 +10:00
ripplebiz 673d577032 Merge pull request #401 from marrold/Seeed_NRF_RTC
Add RTC support to Seeed NRF
2025-06-18 16:45:43 +10:00
ripplebiz a5273883d5 Merge pull request #397 from fdlamotte/t1000e_gps_off_position_fix
t1000e: don't update position if gps is off
2025-06-18 16:40:28 +10:00
Scott Powell e6ce3c896d * companion: new CMD_GET_ADVERT_PATH -> RESP_CODE_ADVERT_PATH 2025-06-18 16:02:09 +10:00
Scott Powell 2a4b55a555 Merge commit 'e30eef73f7603bbc96e44ed5bae7a4588065c9a7' into dev 2025-06-18 14:59:19 +10:00
ripplebiz e30eef73f7 Merge pull request #396 from jbrazio/jbrazio/2025_5dba32d2
Adds support for the Waveshare RP2040-LoRa board
2025-06-18 14:57:45 +10:00
JQ b1fe57e892 adding display support to all T114 builds 2025-06-17 16:06:07 -07:00
Matthew Harrold 83b70b3167 Add support for Seeed NRF + RTC 2025-06-17 23:12:10 +01:00
Scott Powell 9363478d6f * noise floor can now be queried even when int.thresh = 0 2025-06-18 01:27:53 +10:00
ripplebiz fab84925c3 Merge pull request #387 from awolden/awolden/T3S3-sx1276
Add support T3S3 v1.2 (SX1726)
2025-06-17 12:30:03 +10:00
ripplebiz ec712c446f Merge pull request #384 from recrof/patch-6
Add companion roles to Station G2
2025-06-17 12:23:46 +10:00
João Brázio 24464d0c4e Update VBAT schematic 2025-06-16 21:28:59 +01:00
João Brázio 110bd49407 VBAT schematic 2025-06-16 19:51:53 +01:00
João Brázio f3e85a6fba Update SX126X_CURRENT_LIMIT 2025-06-16 16:57:43 +01:00
Florent de Lamotte 5c6f3457e2 t1000e: don't update position if gps is off 2025-06-16 09:14:42 +02:00
Scott Powell 0f9efa2ee8 * room server: suggested keep_alive interval now disabled 2025-06-16 17:02:44 +10:00
ripplebiz 7175decaf3 Merge pull request #380 from recrof/dev
re-introduce tlora c6 with fixed arduino versions
2025-06-16 16:38:14 +10:00
João Brázio 3448db6e36 Rename LED pin 2025-06-16 02:01:16 +01:00
João Brázio 52acae1fe7 Set default upload protocol 2025-06-16 02:01:04 +01:00
João Brázio 8f6b2b75d7 Waveshare RP2040-LoRa board support 2025-06-15 23:48:49 +01:00
ripplebiz 5b1c7fe250 Merge pull request #391 from LitBomb/patch-13
Update faq.md
2025-06-14 12:21:13 +10:00
uncle lit 7fffe7755a Update faq.md
add full erase instructions using flasher.meshcore.co.uk
add nRF fault tolerant bootloader by discord@che aporeps
2025-06-13 13:36:00 -07:00
Rastislav Vysoky a9ea7105e8 Merge branch 'ripplebiz:dev' into dev 2025-06-13 09:59:06 +02:00
Scott Powell 8a7ec9d7fe * interference threshold now disabled by default 2025-06-13 17:24:47 +10:00
Scott Powell 466bd6d596 * fix for when AGC reset is disabled (interval = 0) 2025-06-13 14:25:09 +10:00
Scott Powell 32ca3dc9d0 * repeater and room server: new CLI setting "agc.reset.interval" (seconds) 2025-06-13 14:15:21 +10:00
ripplebiz f7dcf01e81 Merge pull request #378 from recrof/patch-4
add mising config for `openocd_target`
2025-06-11 17:40:06 +10:00
Alex Wolden fca86d93f3 Added support for t3s3 sx1276 2025-06-10 22:10:24 -07:00
Matthew Sainsbury a2a9455dc0 corrections and style 2025-06-10 22:09:23 -07:00
Bence T. deaa0ec2c8 Create packet_structure.md
As mentioned by @mofosyne at issue #72
2025-06-10 22:09:23 -07:00
ripplebiz aa230d2bd8 Merge pull request #386 from jquatier/thinknode-led
ThinkNode M1 TX LED
2025-06-10 18:51:30 +10:00
JQ e1ceaab7ed add TX led to thinknode M1 2025-06-09 17:35:00 -07:00
ripplebiz 3f0c89d7be Merge pull request #379 from jquatier/ui-fixes
Minor companion ui fixes
2025-06-10 02:22:28 +10:00
Scott Powell c6f6e088fc * some HT-CT62 fixes 2025-06-09 17:34:04 +10:00
ripplebiz c5869c78a2 Merge pull request #382 from fdlamotte/ct62_usb_companion
ct62: adding companion radios
2025-06-09 14:23:13 +10:00
Rastislav Vysoky 516f6a36c4 Add companion roles to Station G2 2025-06-08 21:01:04 +02:00
Florent f208f04324 ct62: adding companion radios 2025-06-08 18:46:11 +02:00
JQ 7c011324f2 feedback 2025-06-08 08:25:54 -07:00
recrof 71982d4391 Merge branch 'dev' of github.com:recrof/MeshCore into dev 2025-06-08 17:02:53 +02:00
recrof e44f1eebb1 fix duplicate flag 2025-06-08 17:02:34 +02:00
Rastislav Vysoky 4679b03091 Merge branch 'ripplebiz:dev' into dev 2025-06-08 14:26:32 +02:00
Scott Powell fd4885e9aa * HT-CT62 SPI fixes 2025-06-08 20:11:35 +10:00
Scott Powell dafb5d3e98 * added repeater target for Heltec-CT62 2025-06-08 18:41:29 +10:00
JQ 42ef297241 set text width ahead of width calculation 2025-06-07 22:35:59 -07:00
JQ 1bc94c2ec3 minor companion ui fixes 2025-06-07 15:57:22 -07:00
Rastislav Vysoky 7525877f6c add mising config for openocd_target 2025-06-07 10:48:09 +02:00
Rastislav Vysoky 9d1c85526e Merge branch 'ripplebiz:dev' into dev 2025-06-07 09:39:36 +02:00
Rastislav Vysoky 7deb82823c Merge branch 'ripplebiz:dev' into dev 2025-06-06 12:35:00 +02:00
recrof bb1e5c5a1c nrf52 fix: don't allow LFS_ASSERT to freeze the board 2025-06-06 00:07:03 +02:00
Rastislav Vysoky 0de12b02f8 Merge branch 'ripplebiz:dev' into dev 2025-06-05 11:05:47 +02:00
Rastislav Vysoky 572dc56401 Merge branch 'ripplebiz:dev' into dev 2025-06-04 13:39:39 +02:00
recrof f7e79ada1e re-introduce tlora c6 with fixed arduino versions 2025-06-02 17:36:45 +02:00
Florent 211cf00a74 initial support for xiao_c6 2025-06-01 17:13:07 +02:00
117 changed files with 3169 additions and 1664 deletions
+3 -2
View File
@@ -46,7 +46,8 @@
],
"debug": {
"jlink_device": "nRF52840_xxAA",
"svd_path": "nrf52840.svd"
"svd_path": "nrf52840.svd",
"openocd_target": "nrf52.cfg"
},
"frameworks": [
"arduino"
@@ -69,4 +70,4 @@
},
"url": "https://wiki.uniteng.com/en/meshtastic/nano-g2-ultra",
"vendor": "BQ Consulting"
}
}
+64 -15
View File
@@ -64,9 +64,13 @@ author: https://github.com/LitBomb<!-- omit from toc -->
- [6.3. Q: How to connect to a repeater via BLE (Bluetooth)?](#63-q-how-to-connect-to-a-repeater-via-ble-bluetooth)
- [6.4. Q: I can't connect via Bluetooth, what is the Bluetooth pairing code?](#64-q-i-cant-connect-via-bluetooth-what-is-the-bluetooth-pairing-code)
- [6.5. Q: My Heltec V3 keeps disconnecting from my smartphone. It can't hold a solid Bluetooth connection.](#65-q-my-heltec-v3-keeps-disconnecting-from-my-smartphone--it-cant-hold-a-solid-bluetooth-connection)
- [6.6. Q: My RAK/T1000-E/xiao\_nRF52 device seems to be corrupted, how do I wipe it clean to start fresh?](#66-q-my-rakt1000-exiao_nrf52-device-seems-to-be-corrupted-how-do-i-wipe-it-clean-to-start-fresh)
- [6.7. Q: WebFlasher fails on Linux with failed to open](#67-q-webflasher-fails-on-Linux-with-failed-to-open)
- [7. Other Questions:](#7-other-questions)
- [7.2 Q: How to update ESP32-based devices over the air?](#72-q-how-to-update-esp32-based-devices-over-the-air)
- [7.1 Q: How to update nRF (RAK, T114, Seed XIAO) repeater and room server firmware over the air using the new simpler DFU app?](#71-q-how-to-update-nrf-rak-t114-seed-xiao-repeater-and-room-server-firmware-over-the-air-using-the-new-simpler-dfu-app)
- [7.2 Q: How to update ESP32-based devices over the air?](#72-q-how-to-update-esp32-based-devices-over-the-air)
- [7.3 Q: Is there a way to lower the chance of a failed OTA device firmware update (DFU)?](#73-q-is-there-a-way-to-lower-the-chance-of-a-failed-ota-device-firmware-update-dfu)
## 1. Introduction
@@ -533,9 +537,57 @@ You can get the epoch time on <https://www.epochconverter.com/> and use it to se
**A:** Heltec V3 has a very small coil antenna on its PCB for Wi-Fi and Bluetooth connectivity. It has a very short range, only a few feet. It is possible to remove the coil antenna and replace it with a 31mm wire. The BT range is much improved with the modification.
### 6.6. Q: My RAK/T1000-E/xiao_nRF52 device seems to be corrupted, how do I wipe it clean to start fresh?
**A:**
1. Connect USB-C cable to your device, per your device's instruction, get it to flash mode:
- For RAK, double click its reset button
- For T1000-e, quickly disconnect and reconnect the magnetic side of the cable from the device TWICE
- For Heltec T114, click the reset button once (the bottom button)
- For Xiao nRF52, click the reset button once. If that doesn't work, quickly double click the reset button twice. If that doesn't work, disconnection the board from your PC and reconnect again ([seeed studio wiki](https://wiki.seeedstudio.com/XIAO_BLE/#access-the-swd-pins-for-debugging-and-reflashing-bootloader))
5. A new folder will appear on your computer's desktop
6. Download the `flash_erase*.uf2` file for your device on flasher.meshcore.co.uk
- RAK WisBlock and Heltec T114: `Flash_erase-nRF32_softdevice_v6.uf2`
- Seeed Studio Xiao nRF52 WIO: `Flash_erase-nRF52_softdevice_v7.uf2`
8. drag and drop the uf2 file for your device to the root of the new folder
9. Wait for the copy to complete. You might get an error dialog, you can ignore it
10. Go to https://flasher.meshcore.co.uk/, click `Console` and select the serial port for your connected device
11. In the console, press enter. Your flash should now be erased
12. You may now flash the latest MeshCore firmware onto your device
Separately, starting in firmware version 1.7.0, there is a CLI Rescue mode. If your device has a user button (e.g. some RAK, T114), you can activate the rescue mode by hold down the user button of the device within 8 seconds of boot. Then you can use the 'Console' on flasher.meshcore.co.uk
### 6.7. Q: WebFlasher fails on Linux with failed to open
**A:** If the usb port doesn't have the right ownership for this task, the process fails with the following error:
`NetworkError: Failed to execute 'open' on 'SerialPort': Failed to open serial port.`
Allow the browser user on it:
`# setfacl -m u:YOUR_USER_HERE:rw /dev/ttyUSB0`
---
## 7. Other Questions:
### 7.1 Q: How to update nRF (RAK, T114, Seed XIAO) repeater and room server firmware over the air using the new simpler DFU app?
**A:** The steps below work on both Android and iOS as nRF has made both apps' user interface the same on both platforms:
1. Download nRF's DFU app from iOS App Store or Android's Play Store, you can find the app by searching for `nrf dfu`, the app's full name is `nRF Device Firmware Update`
2. On flasher.meshcore.co.uk, download the **ZIP** version of the firmware for your nRF device (e.g. RAK or Heltec T114 or Seeed Studio's Xiao)
3. From the MeshCore app, login remotely to the repeater you want to update with admin priviledge
4. Go to the Command Line tab, type `start ota` and hit enter.
5. you should see `OK` to confirm the repeater device is now in OTA mode
6. Run the DFU app,tab `Settings` on the top right corner
7. Enable `Packets receipt notifications`, and change `Number of Packets` to 10 for RAK, 8 for T114. 8 also works for RAK.
9. Select the firmware zip file you downloaded
10. Select the device you want to update. If the device you want to updat is not on the list, try enabling`OTA` on the device again
11. If the device is not found, enable `Force Scanning` in the DFU app
12. Tab the `Upload` to begin OTA update
13. If it fails, try turning off and on Bluetooth on your phone. If that doesn't work, try rebooting your phone.
14. Wait for the update to complete. It can take a few minutes.
### 7.2 Q: How to update ESP32-based devices over the air?
**A:** For ESP32-based devices (e.g. Heltec V3):
@@ -548,22 +600,19 @@ You can get the epoch time on <https://www.epochconverter.com/> and use it to se
8. From a browser, go to http://192.168.4.1/update and upload the non-merged bin from the flasher
### 7.1 Q: How to update nRF (RAK, T114, Seed XIAO) repeater and room server firmware over the air using the new simpler DFU app?
### 7.3 Q: Is there a way to lower the chance of a failed OTA device firmware update (DFU)?
**A:** Yes, developer `che aporeps` has an enhanced OTA DFU bootloader for nRF52 based devices. With this bootloader, if it detects that the application firmware is invalid, it falls back to OTA DFU mode so you can attempt to flash again to recover. This bootloader has other changes to make the OTA DFU process more fault tolerant.
Refer to https://github.com/oltaco/Adafruit_nRF52_Bootloader_OTAFIX for the latest information.
Currently, the following boards are supported:
- Nologo ProMicro
- Seeed Studio XIAO nRF52840 BLE
- Seeed Studio XIAO nRF52840 BLE SENSE
- RAK 4631
**A:** The steps below work on both Android and iOS as nRF has made both apps' user interface the same on both platforms:
1. Download nRF's DFU app from iOS App Store or Android's Play Store, you can find the app by searching for `nrf dfu`, the app's full name is `nRF Device Firmware Update`
2. On flasher.meshcore.co.uk, download the **ZIP** version of the firmware for your nRF device (e.g. RAK or Heltec T114 or Seeed Studio's Xiao)
3. From the MeshCore app, login remotely to the repeater you want to update with admin priviledge
4. Go to the Command Line tab, type `start ota` and hit enter.
5. you should see `OK` to confirm the repeater device is now in OTA mode
6. Run the DFU app,tab `Settings` on the top right corner
7. Enable `Packets receipt notifications` and change `Number of Packets` to 10 for RAK, 8 for T114. 8 also works for RAK.
8. Select the firmware zip file you downloaded
9. Select the device you want to update. If the device you want to updat is not on the list, try enabling`OTA` on the device again
10. Tab the `Upload` to begin OTA update
11. If it fails, try turning off and on Bluetooth on your phone. If that doesn't work, try rebooting your phone.
12. Wait for the update to complete. It can take a few minutes.
---
+11 -8
View File
@@ -11,20 +11,22 @@ Note: see the [payloads doc](./payloads.md) for more information about the conte
## Header Breakdown
bit 0 means the lowest bit (1s place)
| Bits | Mask | Field | Description |
|-------|--------|-----------------|-----------------------------------------------|
| 0-1 | `0x03` | Route Type | Flood, Direct, Reserved - see below. |
| 2-5 | `0x0F` | Payload Type | Request, Response, ACK, etc. - see below. |
| 6-7 | `0x03` | Payload Version | Versioning of the payload format - see below. |
| 2-5 | `0x3C` | Payload Type | Request, Response, ACK, etc. - see below. |
| 6-7 | `0xC0` | Payload Version | Versioning of the payload format - see below. |
## Route Type Values
| Value | Name | Description |
|--------|------------------------|--------------------------------------|
| `0x00` | `ROUTE_TYPE_RESERVED1` | Reserved for future use. |
| `0x01` | `ROUTE_TYPE_FLOOD` | Flood routing mode (builds up path). |
| `0x02` | `ROUTE_TYPE_DIRECT` | Direct route (path is supplied). |
| `0x03` | `ROUTE_TYPE_RESERVED2` | Reserved for future use. |
| Value | Name | Description |
|--------|-------------------------------|--------------------------------------|
| `0x00` | `ROUTE_TYPE_TRANSPORT_FLOOD` | Flood routing mode + transport codes |
| `0x01` | `ROUTE_TYPE_FLOOD` | Flood routing mode (builds up path). |
| `0x02` | `ROUTE_TYPE_DIRECT` | Direct route (path is supplied). |
| `0x03` | `ROUTE_TYPE_TRANSPORT_DIRECT` | direct route + transport codes |
## Payload Type Values
@@ -39,6 +41,7 @@ Note: see the [payloads doc](./payloads.md) for more information about the conte
| `0x06` | `PAYLOAD_TYPE_GRP_DATA` | Group datagram (unverified). |
| `0x07` | `PAYLOAD_TYPE_ANON_REQ` | Anonymous request. |
| `0x08` | `PAYLOAD_TYPE_PATH` | Returned path. |
| `0x09` | `PAYLOAD_TYPE_TRACE` | trace a path, collecting SNI for each hop. |
| `0x0F` | `PAYLOAD_TYPE_RAW_CUSTOM` | Custom packet (raw bytes, custom encryption). |
## Payload Version Values
+34 -23
View File
@@ -1,25 +1,29 @@
# Meshcore payloads
Inside of each [meshcore packet](./packet_structure.md) is a payload, identified by the payload type in the packet header. The types of payloads are:
* Node advertisement.
* Acknowledgment.
* Returned path.
* Request (destination/source hashes + MAC).
* Response to REQ or ANON_REQ.
* Plain text message.
* Acknowledgment.
* Node advertisement.
* Anonymous request.
* Group text message (unverified).
* Group datagram (unverified).
* Anonymous request.
* Returned path.
* Custom packet (raw bytes, custom encryption).
This document defines the structure of each of these payload types
## Important concepts:
* Node/channel hash: the first byte of the node or channel's public key
# Node advertisement
This kind of payload notifies receivers that a node exists, and gives information about the node
| Field | Size (bytes) | Description |
|---------------|-----------------|----------------------------------------------------------|
| public key | 32 | Ed25519 public key |
| public key | 32 | Ed25519 public key of the node |
| timestamp | 4 | unix timestamp of advertisement |
| signature | 64 | Ed25519 signature of public key, timestamp, and app data |
| appdata | rest of payload | optional, see below |
@@ -37,20 +41,29 @@ Appdata
Appdata Flags
| Value | Name | Description |
|--------|-----------|---------------------------------------|
| `0x10` | location | appdata contains lat/long information |
| `0x20` | feature 1 | Reserved for future use. |
| `0x40` | feature 2 | Reserved for future use. |
| `0x80` | name | appdata contains a node name |
| Value | Name | Description |
|--------|----------------|---------------------------------------|
| `0x01` | is chat node | advert is for a chat node |
| `0x02` | is repeater | advert is for a repeater |
| `0x03` | is room server | advert is for a room server |
| `0x10` | has location | appdata contains lat/long information |
| `0x20` | has feature 1 | Reserved for future use. |
| `0x40` | has feature 2 | Reserved for future use. |
| `0x80` | has name | appdata contains a node name |
# Acknowledgement
An acknowledgement that a message was received. Note that for returned path messages, an acknowledgement will be sent in the "extra" payload (see [Returned Path](#returned-path)) and not as a discrete ackowledgement. CLI commands do not require an acknowledgement, neither discrete nor extra.
| Field | Size (bytes) | Description |
|----------|--------------|------------------------------------------------------------|
| checksum | 4 | CRC checksum of message timestamp, text, and sender pubkey |
# Returned path, request, response, and plain text message
Returned path, request, response, and plain text messages are all formatted in the same way. See the subsection for more details about the ciphertext's associated plaintext representation.
| Field | Size (bytes) | Description |
|------------------|-----------------|------------------------------------------------------|
| destination hash | 1 | first byte of destination node public key |
@@ -60,11 +73,13 @@ Appdata Flags
## Returned path
Returned path messages provide a description of the route a packet took from the original author. Receivers will send returned path messages to the author of the original message.
| Field | Size (bytes) | Description |
|-------------|--------------|----------------------------------------------------------------------------------------------|
| path length | 1 | length of next field |
| path | see above | a list of node hashes (one byte each) describing the route from us to the packet author |
| extra type | 1 | extra, bundled payload type, eg., acknowledgement or response. See packet structure spec |
| path | see above | a list of node hashes (one byte each) |
| extra type | 1 | extra, bundled payload type, eg., acknowledgement or response. Same values as in [packet structure](./packet_structure.md) |
| extra | rest of data | extra, bundled payload content, follows same format as main content defined by this document |
## Request
@@ -156,18 +171,14 @@ Plaintext message
# Group text message / datagram
| Field | Size (bytes) | Description |
|--------------|-----------------|------------------------------------------|
| channel hash | 1 | TODO |
| cipher MAC | 2 | MAC for encrypted data in next field |
| ciphertext | rest of payload | encrypted message, see below for details |
| Field | Size (bytes) | Description |
|--------------|-----------------|--------------------------------------------|
| channel hash | 1 | the first byte of the channel's public key |
| cipher MAC | 2 | MAC for encrypted data in next field |
| ciphertext | rest of payload | encrypted message, see below for details |
Plaintext for text message
The plaintext contained in the ciphertext matches the format described in [plain text message](#plain-text-message). Specifically, it consists of a four byte timestamp, a flags byte, and the message. The flags byte will generally be `0x00` because it is a "plain text message". The message will be of the form `<sender name>: <message body>` (eg., `user123: I'm on my way`).
| Field | Size (bytes) | Description |
|-----------|-----------------|----------------------------------|
| timestamp | 4 | send time (unix timestamp) |
| content | rest of message | plain group text message content |
TODO: describe what datagram looks like
+7 -1
View File
@@ -50,9 +50,12 @@ void Button::update() {
triggerEvent(SHORT_PRESS);
} else if (_clickCount == 2) {
triggerEvent(DOUBLE_PRESS);
} else if (_clickCount >= 3) {
} else if (_clickCount == 3) {
triggerEvent(TRIPLE_PRESS);
} else if (_clickCount >= 4) {
triggerEvent(QUADRUPLE_PRESS);
}
_clickCount = 0;
_state = IDLE;
}
@@ -116,6 +119,9 @@ void Button::triggerEvent(EventType event) {
case TRIPLE_PRESS:
if (_onTriplePress) _onTriplePress();
break;
case QUADRUPLE_PRESS:
if (_onQuadruplePress) _onQuadruplePress();
break;
case LONG_PRESS:
if (_onLongPress) _onLongPress();
break;
+3
View File
@@ -16,6 +16,7 @@ public:
SHORT_PRESS,
DOUBLE_PRESS,
TRIPLE_PRESS,
QUADRUPLE_PRESS,
LONG_PRESS,
ANY_PRESS
};
@@ -32,6 +33,7 @@ public:
void onShortPress(EventCallback callback) { _onShortPress = callback; }
void onDoublePress(EventCallback callback) { _onDoublePress = callback; }
void onTriplePress(EventCallback callback) { _onTriplePress = callback; }
void onQuadruplePress(EventCallback callback) { _onQuadruplePress = callback; }
void onLongPress(EventCallback callback) { _onLongPress = callback; }
void onAnyPress(EventCallback callback) { _onAnyPress = callback; }
@@ -68,6 +70,7 @@ private:
EventCallback _onShortPress = nullptr;
EventCallback _onDoublePress = nullptr;
EventCallback _onTriplePress = nullptr;
EventCallback _onQuadruplePress = nullptr;
EventCallback _onLongPress = nullptr;
EventCallback _onAnyPress = nullptr;
+55 -2
View File
@@ -40,8 +40,59 @@ void DataStore::begin() {
#include <SPIFFS.h>
#elif defined(RP2040_PLATFORM)
#include <LittleFS.h>
#elif defined(NRF52_PLATFORM) || defined(STM32_PLATFORM)
#include <InternalFileSystem.h>
#endif
#if defined(NRF52_PLATFORM) || defined(STM32_PLATFORM)
int _countLfsBlock(void *p, lfs_block_t block){
lfs_size_t *size = (lfs_size_t*) p;
*size += 1;
return 0;
}
lfs_ssize_t _getLfsUsedBlockCount() {
lfs_size_t size = 0;
lfs_traverse(InternalFS._getFS(), _countLfsBlock, &size);
return size;
}
#endif
uint32_t DataStore::getStorageUsedKb() const {
#if defined(ESP32)
return SPIFFS.usedBytes() / 1024;
#elif defined(RP2040_PLATFORM)
FSInfo info;
info.usedBytes = 0;
_fs->info(info);
return info.usedBytes / 1024;
#elif defined(NRF52_PLATFORM) || defined(STM32_PLATFORM)
const lfs_config* config = InternalFS._getFS()->cfg;
int usedBlockCount = _getLfsUsedBlockCount();
int usedBytes = config->block_size * usedBlockCount;
return usedBytes / 1024;
#else
return 0;
#endif
}
uint32_t DataStore::getStorageTotalKb() const {
#if defined(ESP32)
return SPIFFS.totalBytes() / 1024;
#elif defined(RP2040_PLATFORM)
FSInfo info;
info.totalBytes = 0;
_fs->info(info);
return info.totalBytes / 1024;
#elif defined(NRF52_PLATFORM) || defined(STM32_PLATFORM)
const lfs_config* config = InternalFS._getFS()->cfg;
int totalBytes = config->block_size * config->block_count;
return totalBytes / 1024;
#else
return 0;
#endif
}
File DataStore::openRead(const char* filename) {
#if defined(NRF52_PLATFORM) || defined(STM32_PLATFORM)
return _fs->open(filename, FILE_O_READ);
@@ -111,7 +162,8 @@ void DataStore::loadPrefsInt(const char *filename, NodePrefs& _prefs, double& no
file.read((uint8_t *)&_prefs.telemetry_mode_loc, sizeof(_prefs.telemetry_mode_loc)); // 70
file.read((uint8_t *)&_prefs.telemetry_mode_env, sizeof(_prefs.telemetry_mode_env)); // 71
file.read((uint8_t *)&_prefs.rx_delay_base, sizeof(_prefs.rx_delay_base)); // 72
file.read(pad, 4); // 76
file.read((uint8_t *)&_prefs.advert_loc_policy, sizeof(_prefs.advert_loc_policy)); // 76
file.read(pad, 3); // 77
file.read((uint8_t *)&_prefs.ble_pin, sizeof(_prefs.ble_pin)); // 80
file.close();
@@ -140,7 +192,8 @@ void DataStore::savePrefs(const NodePrefs& _prefs, double node_lat, double node_
file.write((uint8_t *)&_prefs.telemetry_mode_loc, sizeof(_prefs.telemetry_mode_loc)); // 70
file.write((uint8_t *)&_prefs.telemetry_mode_env, sizeof(_prefs.telemetry_mode_env)); // 71
file.write((uint8_t *)&_prefs.rx_delay_base, sizeof(_prefs.rx_delay_base)); // 72
file.write(pad, 4); // 76
file.write((uint8_t *)&_prefs.advert_loc_policy, sizeof(_prefs.advert_loc_policy)); // 76
file.write(pad, 3); // 77
file.write((uint8_t *)&_prefs.ble_pin, sizeof(_prefs.ble_pin)); // 80
file.close();
+2
View File
@@ -39,4 +39,6 @@ public:
bool putBlobByKey(const uint8_t key[], int key_len, const uint8_t src_buf[], uint8_t len);
File openRead(const char* filename);
bool removeFile(const char* filename);
uint32_t getStorageUsedKb() const;
uint32_t getStorageTotalKb() const;
};
+80 -13
View File
@@ -22,7 +22,7 @@
#define CMD_EXPORT_CONTACT 17
#define CMD_IMPORT_CONTACT 18
#define CMD_REBOOT 19
#define CMD_GET_BATTERY_VOLTAGE 20
#define CMD_GET_BATT_AND_STORAGE 20 // was CMD_GET_BATTERY_VOLTAGE
#define CMD_SET_TUNING_PARAMS 21
#define CMD_DEVICE_QEURY 22
#define CMD_EXPORT_PRIVATE_KEY 23
@@ -44,6 +44,7 @@
#define CMD_SEND_TELEMETRY_REQ 39
#define CMD_GET_CUSTOM_VARS 40
#define CMD_SET_CUSTOM_VAR 41
#define CMD_GET_ADVERT_PATH 42
#define RESP_CODE_OK 0
#define RESP_CODE_ERR 1
@@ -57,7 +58,7 @@
#define RESP_CODE_CURR_TIME 9 // a reply to CMD_GET_DEVICE_TIME
#define RESP_CODE_NO_MORE_MESSAGES 10 // a reply to CMD_SYNC_NEXT_MESSAGE
#define RESP_CODE_EXPORT_CONTACT 11
#define RESP_CODE_BATTERY_VOLTAGE 12 // a reply to a CMD_GET_BATTERY_VOLTAGE
#define RESP_CODE_BATT_AND_STORAGE 12 // a reply to a CMD_GET_BATT_AND_STORAGE
#define RESP_CODE_DEVICE_INFO 13 // a reply to CMD_DEVICE_QEURY
#define RESP_CODE_PRIVATE_KEY 14 // a reply to CMD_EXPORT_PRIVATE_KEY
#define RESP_CODE_DISABLED 15
@@ -67,6 +68,7 @@
#define RESP_CODE_SIGN_START 19
#define RESP_CODE_SIGNATURE 20
#define RESP_CODE_CUSTOM_VARS 21
#define RESP_CODE_ADVERT_PATH 22
#define SEND_TIMEOUT_BASE_MILLIS 500
#define FLOOD_SEND_TIMEOUT_FACTOR 16.0f
@@ -219,7 +221,7 @@ bool MyMesh::isAutoAddEnabled() const {
return (_prefs.manual_add_contacts & 1) == 0;
}
void MyMesh::onDiscoveredContact(ContactInfo &contact, bool is_new) {
void MyMesh::onDiscoveredContact(ContactInfo &contact, bool is_new, uint8_t path_len, const uint8_t* path) {
if (_serial->isConnected()) {
if (!isAutoAddEnabled() && is_new) {
writeContactRespFrame(PUSH_CODE_NEW_ADVERT, contact);
@@ -234,6 +236,27 @@ void MyMesh::onDiscoveredContact(ContactInfo &contact, bool is_new) {
#endif
}
// add inbound-path to mem cache
if (path && path_len <= sizeof(AdvertPath::path)) { // check path is valid
AdvertPath* p = advert_paths;
uint32_t oldest = 0xFFFFFFFF;
for (int i = 0; i < ADVERT_PATH_TABLE_SIZE; i++) { // check if already in table, otherwise evict oldest
if (memcmp(advert_paths[i].pubkey_prefix, contact.id.pub_key, sizeof(AdvertPath::pubkey_prefix)) == 0) {
p = &advert_paths[i]; // found
break;
}
if (advert_paths[i].recv_timestamp < oldest) {
oldest = advert_paths[i].recv_timestamp;
p = &advert_paths[i];
}
}
memcpy(p->pubkey_prefix, contact.id.pub_key, sizeof(p->pubkey_prefix));
p->recv_timestamp = getRTCClock()->getCurrentTime();
p->path_len = path_len;
memcpy(p->path, path, p->path_len);
}
dirty_contacts_expiry = futureMillis(LAZY_CONTACTS_WRITE_DELAY);
}
@@ -541,6 +564,7 @@ MyMesh::MyMesh(mesh::Radio &radio, mesh::RNG &rng, mesh::RTCClock &rtc, SimpleMe
next_ack_idx = 0;
sign_data = NULL;
dirty_contacts_expiry = 0;
memset(advert_paths, 0, sizeof(advert_paths));
// defaults
memset(&_prefs, 0, sizeof(_prefs));
@@ -674,7 +698,7 @@ void MyMesh::handleCmdFrame(size_t len) {
memcpy(&out_frame[i], &lon, 4);
i += 4;
out_frame[i++] = 0; // reserved
out_frame[i++] = 0; // reserved
out_frame[i++] = _prefs.advert_loc_policy;
out_frame[i++] = (_prefs.telemetry_mode_env << 4) | (_prefs.telemetry_mode_loc << 2) |
(_prefs.telemetry_mode_base); // v5+
out_frame[i++] = _prefs.manual_add_contacts;
@@ -816,7 +840,12 @@ void MyMesh::handleCmdFrame(size_t len) {
writeErrFrame(ERR_CODE_ILLEGAL_ARG);
}
} else if (cmd_frame[0] == CMD_SEND_SELF_ADVERT) {
auto pkt = createSelfAdvert(_prefs.node_name, sensors.node_lat, sensors.node_lon);
mesh::Packet* pkt;
if (_prefs.advert_loc_policy == ADVERT_LOC_NONE) {
pkt = createSelfAdvert(_prefs.node_name);
} else {
pkt = createSelfAdvert(_prefs.node_name, sensors.node_lat, sensors.node_lon);
}
if (pkt) {
if (len >= 2 && cmd_frame[1] == 1) { // optional param (1 = flood, 0 = zero hop)
sendFlood(pkt);
@@ -890,7 +919,12 @@ void MyMesh::handleCmdFrame(size_t len) {
} else if (cmd_frame[0] == CMD_EXPORT_CONTACT) {
if (len < 1 + PUB_KEY_SIZE) {
// export SELF
auto pkt = createSelfAdvert(_prefs.node_name, sensors.node_lat, sensors.node_lon);
mesh::Packet* pkt;
if (_prefs.advert_loc_policy == ADVERT_LOC_NONE) {
pkt = createSelfAdvert(_prefs.node_name);
} else {
pkt = createSelfAdvert(_prefs.node_name, sensors.node_lat, sensors.node_lon);
}
if (pkt) {
pkt->header |= ROUTE_TYPE_FLOOD; // would normally be sent in this mode
@@ -984,6 +1018,10 @@ void MyMesh::handleCmdFrame(size_t len) {
_prefs.telemetry_mode_base = cmd_frame[2] & 0x03; // v5+
_prefs.telemetry_mode_loc = (cmd_frame[2] >> 2) & 0x03;
_prefs.telemetry_mode_env = (cmd_frame[2] >> 4) & 0x03;
if (len >= 4) {
_prefs.advert_loc_policy = cmd_frame[3];
}
}
savePrefs();
writeOKFrame();
@@ -992,12 +1030,17 @@ void MyMesh::handleCmdFrame(size_t len) {
saveContacts();
}
board.reboot();
} else if (cmd_frame[0] == CMD_GET_BATTERY_VOLTAGE) {
uint8_t reply[3];
reply[0] = RESP_CODE_BATTERY_VOLTAGE;
} else if (cmd_frame[0] == CMD_GET_BATT_AND_STORAGE) {
uint8_t reply[11];
int i = 0;
reply[i++] = RESP_CODE_BATT_AND_STORAGE;
uint16_t battery_millivolts = board.getBattMilliVolts();
memcpy(&reply[1], &battery_millivolts, 2);
_serial->writeFrame(reply, 3);
uint32_t used = _store->getStorageUsedKb();
uint32_t total = _store->getStorageTotalKb();
memcpy(&reply[i], &battery_millivolts, 2); i += 2;
memcpy(&reply[i], &used, 4); i += 4;
memcpy(&reply[i], &total, 4); i += 4;
_serial->writeFrame(reply, i);
} else if (cmd_frame[0] == CMD_EXPORT_PRIVATE_KEY) {
#if ENABLE_PRIVATE_KEY_EXPORT
uint8_t reply[65];
@@ -1249,6 +1292,26 @@ void MyMesh::handleCmdFrame(size_t len) {
} else {
writeErrFrame(ERR_CODE_ILLEGAL_ARG);
}
} else if (cmd_frame[0] == CMD_GET_ADVERT_PATH && len >= PUB_KEY_SIZE+2) {
// FUTURE use: uint8_t reserved = cmd_frame[1];
uint8_t *pub_key = &cmd_frame[2];
AdvertPath* found = NULL;
for (int i = 0; i < ADVERT_PATH_TABLE_SIZE; i++) {
auto p = &advert_paths[i];
if (memcmp(p->pubkey_prefix, pub_key, sizeof(p->pubkey_prefix)) == 0) {
found = p;
break;
}
}
if (found) {
out_frame[0] = RESP_CODE_ADVERT_PATH;
memcpy(&out_frame[1], &found->recv_timestamp, 4);
out_frame[5] = found->path_len;
memcpy(&out_frame[6], found->path, found->path_len);
_serial->writeFrame(out_frame, 6 + found->path_len);
} else {
writeErrFrame(ERR_CODE_NOT_FOUND);
}
} else {
writeErrFrame(ERR_CODE_UNSUPPORTED_CMD);
MESH_DEBUG_PRINTLN("ERROR: unknown command: %02X", cmd_frame[0]);
@@ -1425,12 +1488,16 @@ void MyMesh::loop() {
#ifdef DISPLAY_CLASS
ui_task.setHasConnection(_serial->isConnected());
ui_task.loop();
#endif
}
bool MyMesh::advert() {
auto pkt = createSelfAdvert(_prefs.node_name, sensors.node_lat, sensors.node_lon);
mesh::Packet* pkt;
if (_prefs.advert_loc_policy == ADVERT_LOC_NONE) {
pkt = createSelfAdvert(_prefs.node_name);
} else {
pkt = createSelfAdvert(_prefs.node_name, sensors.node_lat, sensors.node_lon);
}
if (pkt) {
sendZeroHop(pkt);
return true;
+14 -5
View File
@@ -7,14 +7,14 @@
#endif
/*------------ Frame Protocol --------------*/
#define FIRMWARE_VER_CODE 5
#define FIRMWARE_VER_CODE 6
#ifndef FIRMWARE_BUILD_DATE
#define FIRMWARE_BUILD_DATE "7 Jun 2025"
#define FIRMWARE_BUILD_DATE "29 Jun 2025"
#endif
#ifndef FIRMWARE_VERSION
#define FIRMWARE_VERSION "v1.7.0"
#define FIRMWARE_VERSION "v1.7.1"
#endif
#if defined(NRF52_PLATFORM) || defined(STM32_PLATFORM)
@@ -100,7 +100,7 @@ protected:
void logRxRaw(float snr, float rssi, const uint8_t raw[], int len) override;
bool isAutoAddEnabled() const override;
void onDiscoveredContact(ContactInfo &contact, bool is_new) override;
void onDiscoveredContact(ContactInfo &contact, bool is_new, uint8_t path_len, const uint8_t* path) override;
void onContactPathUpdated(const ContactInfo &contact) override;
bool processAck(const uint8_t *data) override;
void queueMessage(const ContactInfo &from, uint8_t txt_type, mesh::Packet *pkt, uint32_t sender_timestamp,
@@ -190,9 +190,18 @@ private:
unsigned long msg_sent;
uint32_t ack;
};
#define EXPECTED_ACK_TABLE_SIZE 8
#define EXPECTED_ACK_TABLE_SIZE 8
AckTableEntry expected_ack_table[EXPECTED_ACK_TABLE_SIZE]; // circular table
int next_ack_idx;
struct AdvertPath {
uint8_t pubkey_prefix[7];
uint8_t path_len;
uint32_t recv_timestamp;
uint8_t path[MAX_PATH_SIZE];
};
#define ADVERT_PATH_TABLE_SIZE 16
AdvertPath advert_paths[ADVERT_PATH_TABLE_SIZE]; // circular table
};
extern MyMesh the_mesh;
+4
View File
@@ -5,6 +5,9 @@
#define TELEM_MODE_ALLOW_FLAGS 1 // use contact.flags
#define TELEM_MODE_ALLOW_ALL 2
#define ADVERT_LOC_NONE 0
#define ADVERT_LOC_SHARE 1
struct NodePrefs { // persisted to file
float airtime_factor;
char node_name[32];
@@ -20,4 +23,5 @@ struct NodePrefs { // persisted to file
uint8_t telemetry_mode_env;
float rx_delay_base;
uint32_t ble_pin;
uint8_t advert_loc_policy;
};
+55 -16
View File
@@ -5,7 +5,7 @@
#include "MyMesh.h"
#define AUTO_OFF_MILLIS 15000 // 15 seconds
#define BOOT_SCREEN_MILLIS 4000 // 4 seconds
#define BOOT_SCREEN_MILLIS 3000 // 3 seconds
#ifdef PIN_STATUS_LED
#define LED_ON_MILLIS 20
@@ -34,8 +34,9 @@ static const uint8_t meshcore_logo [] PROGMEM = {
0xe3, 0xe3, 0x8f, 0xff, 0x1f, 0xfc, 0x3c, 0x0e, 0x1f, 0xf8, 0xff, 0xf8, 0x70, 0x3c, 0x7f, 0xf8,
};
void UITask::begin(DisplayDriver* display, NodePrefs* node_prefs) {
void UITask::begin(DisplayDriver* display, SensorManager* sensors, NodePrefs* node_prefs) {
_display = display;
_sensors = sensors;
_auto_off = millis() + AUTO_OFF_MILLIS;
clearMsgPreview();
_node_prefs = node_prefs;
@@ -58,23 +59,33 @@ void UITask::begin(DisplayDriver* display, NodePrefs* node_prefs) {
buzzer.begin();
#endif
// Initialize button with appropriate configuration
#if defined(PIN_USER_BTN) || defined(PIN_USER_BTN_ANA)
#ifdef PIN_USER_BTN
_userButton = new Button(PIN_USER_BTN, USER_BTN_PRESSED);
#else
_userButton = new Button(PIN_USER_BTN_ANA, USER_BTN_PRESSED, true, 20);
#endif
// Initialize digital button if available
#ifdef PIN_USER_BTN
_userButton = new Button(PIN_USER_BTN, USER_BTN_PRESSED);
_userButton->begin();
// Set up button callbacks
// Set up digital button callbacks
_userButton->onShortPress([this]() { handleButtonShortPress(); });
_userButton->onDoublePress([this]() { handleButtonDoublePress(); });
_userButton->onTriplePress([this]() { handleButtonTriplePress(); });
_userButton->onQuadruplePress([this]() { handleButtonQuadruplePress(); });
_userButton->onLongPress([this]() { handleButtonLongPress(); });
_userButton->onAnyPress([this]() { handleButtonAnyPress(); });
#endif
// Initialize analog button if available
#ifdef PIN_USER_BTN_ANA
_userButtonAnalog = new Button(PIN_USER_BTN_ANA, USER_BTN_PRESSED, true, 20);
_userButtonAnalog->begin();
// Set up analog button callbacks
_userButtonAnalog->onShortPress([this]() { handleButtonShortPress(); });
_userButtonAnalog->onDoublePress([this]() { handleButtonDoublePress(); });
_userButtonAnalog->onTriplePress([this]() { handleButtonTriplePress(); });
_userButtonAnalog->onQuadruplePress([this]() { handleButtonQuadruplePress(); });
_userButtonAnalog->onLongPress([this]() { handleButtonLongPress(); });
_userButtonAnalog->onAnyPress([this]() { handleButtonAnyPress(); });
#endif
ui_started_at = millis();
}
@@ -163,9 +174,9 @@ void UITask::renderCurrScreen() {
char tmp[80];
if (_alert[0]) {
_display->setTextSize(1.4);
uint16_t textWidth = _display->getTextWidth(_alert);
_display->setCursor((_display->width() - textWidth) / 2, 22);
_display->setTextSize(1.4);
_display->setColor(DisplayDriver::GREEN);
_display->print(_alert);
_alert[0] = 0;
@@ -191,7 +202,7 @@ void UITask::renderCurrScreen() {
sprintf(tmp, "%d", _msgcount);
_display->print(tmp);
_display->setColor(DisplayDriver::YELLOW); // last color will be kept on T114
} else if (millis() < BOOT_SCREEN_MILLIS) { // boot screen
} else if ((millis() - ui_started_at) < BOOT_SCREEN_MILLIS) { // boot screen
// meshcore logo
_display->setColor(DisplayDriver::BLUE);
int logoWidth = 128;
@@ -289,11 +300,16 @@ void UITask::shutdown(bool restart){
}
void UITask::loop() {
#if defined(PIN_USER_BTN) || defined(PIN_USER_BTN_ANA)
#ifdef PIN_USER_BTN
if (_userButton) {
_userButton->update();
}
#endif
#ifdef PIN_USER_BTN_ANA
if (_userButtonAnalog) {
_userButtonAnalog->update();
}
#endif
userLedHandler();
#ifdef PIN_BUZZER
@@ -302,7 +318,7 @@ void UITask::loop() {
if (_display != NULL && _display->isOn()) {
static bool _firstBoot = true;
if(_firstBoot && millis() >= BOOT_SCREEN_MILLIS) {
if(_firstBoot && (millis() - ui_started_at) >= BOOT_SCREEN_MILLIS) {
_need_refresh = true;
_firstBoot = false;
}
@@ -344,6 +360,8 @@ void UITask::handleButtonShortPress() {
// Otherwise, refresh the display
_need_refresh = true;
}
} else {
_need_refresh = true; // display just turned on, so we need to refresh
}
// Note: Display turn-on and auto-off timer extension are handled by handleButtonAnyPress
}
@@ -372,13 +390,34 @@ void UITask::handleButtonTriplePress() {
if (buzzer.isQuiet()) {
buzzer.quiet(false);
soundBuzzer(UIEventType::ack);
sprintf(_alert, "Buzzer: ON");
} else {
soundBuzzer(UIEventType::ack);
buzzer.quiet(true);
sprintf(_alert, "Buzzer: OFF");
}
_need_refresh = true;
#endif
}
void UITask::handleButtonQuadruplePress() {
MESH_DEBUG_PRINTLN("UITask: quad press triggered");
if (_sensors != NULL) {
// toggle GPS onn/off
int num = _sensors->getNumSettings();
for (int i = 0; i < num; i++) {
if (strcmp(_sensors->getSettingName(i), "gps") == 0) {
if (strcmp(_sensors->getSettingValue(i), "1") == 0) {
_sensors->setSettingValue("gps", "0");
} else {
_sensors->setSettingValue("gps", "1");
}
break;
}
}
}
_need_refresh = true;
}
void UITask::handleButtonLongPress() {
MESH_DEBUG_PRINTLN("UITask: long press triggered");
if (millis() - ui_started_at < 8000) { // long press in first 8 seconds since startup -> CLI/rescue
+9 -3
View File
@@ -2,6 +2,7 @@
#include <MeshCore.h>
#include <helpers/ui/DisplayDriver.h>
#include <helpers/SensorManager.h>
#include <stddef.h>
#ifdef PIN_BUZZER
@@ -24,6 +25,7 @@
class UITask {
DisplayDriver* _display;
mesh::MainBoard* _board;
SensorManager* _sensors;
#ifdef PIN_BUZZER
genericBuzzer buzzer;
#endif
@@ -40,9 +42,12 @@ class UITask {
unsigned long ui_started_at;
// Button handlers
#if defined(PIN_USER_BTN) || defined(PIN_USER_BTN_ANA)
#ifdef PIN_USER_BTN
Button* _userButton = nullptr;
#endif
#ifdef PIN_USER_BTN_ANA
Button* _userButtonAnalog = nullptr;
#endif
void renderCurrScreen();
void userLedHandler();
@@ -53,17 +58,18 @@ class UITask {
void handleButtonShortPress();
void handleButtonDoublePress();
void handleButtonTriplePress();
void handleButtonQuadruplePress();
void handleButtonLongPress();
public:
UITask(mesh::MainBoard* board) : _board(board), _display(NULL) {
UITask(mesh::MainBoard* board) : _board(board), _display(NULL), _sensors(NULL) {
_next_refresh = 0;
ui_started_at = 0;
_connected = false;
}
void begin(DisplayDriver* display, NodePrefs* node_prefs);
void begin(DisplayDriver* display, SensorManager* sensors, NodePrefs* node_prefs);
void setHasConnection(bool connected) { _connected = connected; }
bool hasDisplay() const { return _display != NULL; }
+4 -1
View File
@@ -186,11 +186,14 @@ void setup() {
sensors.begin();
#ifdef DISPLAY_CLASS
ui_task.begin(disp, the_mesh.getNodePrefs()); // still want to pass this in as dependency, as prefs might be moved
ui_task.begin(disp, &sensors, the_mesh.getNodePrefs()); // still want to pass this in as dependency, as prefs might be moved
#endif
}
void loop() {
the_mesh.loop();
sensors.loop();
#ifdef DISPLAY_CLASS
ui_task.loop();
#endif
}
+6 -3
View File
@@ -22,11 +22,11 @@
/* ------------------------------ Config -------------------------------- */
#ifndef FIRMWARE_BUILD_DATE
#define FIRMWARE_BUILD_DATE "7 Jun 2025"
#define FIRMWARE_BUILD_DATE "29 Jun 2025"
#endif
#ifndef FIRMWARE_VERSION
#define FIRMWARE_VERSION "v1.7.0"
#define FIRMWARE_VERSION "v1.7.1"
#endif
#ifndef LORA_FREQ
@@ -337,6 +337,9 @@ protected:
int getInterferenceThreshold() const override {
return _prefs.interference_threshold;
}
int getAGCResetInterval() const override {
return ((int)_prefs.agc_reset_interval) * 4000; // milliseconds
}
void onAnonDataRecv(mesh::Packet* packet, uint8_t type, const mesh::Identity& sender, uint8_t* data, size_t len) override {
if (type == PAYLOAD_TYPE_ANON_REQ) { // received an initial request by a possible admin client (unknown at this stage)
@@ -575,7 +578,7 @@ public:
_prefs.advert_interval = 1; // default to 2 minutes for NEW installs
_prefs.flood_advert_interval = 3; // 3 hours
_prefs.flood_max = 64;
_prefs.interference_threshold = 14; // DB
_prefs.interference_threshold = 0; // disabled
}
CommonCLI* getCLI() { return &_cli; }
+15 -8
View File
@@ -22,11 +22,11 @@
/* ------------------------------ Config -------------------------------- */
#ifndef FIRMWARE_BUILD_DATE
#define FIRMWARE_BUILD_DATE "7 Jun 2025"
#define FIRMWARE_BUILD_DATE "29 Jun 2025"
#endif
#ifndef FIRMWARE_VERSION
#define FIRMWARE_VERSION "v1.7.0"
#define FIRMWARE_VERSION "v1.7.1"
#endif
#ifndef LORA_FREQ
@@ -123,7 +123,9 @@ struct PostInfo {
#define PUSH_TIMEOUT_BASE 4000
#define PUSH_ACK_TIMEOUT_FACTOR 2000
#define CLIENT_KEEP_ALIVE_SECS 128
#define POST_SYNC_DELAY_SECS 6
#define CLIENT_KEEP_ALIVE_SECS 0 // Now Disabled (was 128)
#define REQ_TYPE_GET_STATUS 0x01 // same as _GET_STATS
#define REQ_TYPE_KEEP_ALIVE 0x02
@@ -420,6 +422,9 @@ protected:
int getInterferenceThreshold() const override {
return _prefs.interference_threshold;
}
int getAGCResetInterval() const override {
return ((int)_prefs.agc_reset_interval) * 4000; // milliseconds
}
bool allowPacketForward(const mesh::Packet* packet) override {
if (_prefs.disable_fwd) return false;
@@ -725,7 +730,7 @@ public:
_prefs.advert_interval = 1; // default to 2 minutes for NEW installs
_prefs.flood_advert_interval = 3; // 3 hours
_prefs.flood_max = 64;
_prefs.interference_threshold = 14; // DB
_prefs.interference_threshold = 0; // disabled
#ifdef ROOM_PASSWORD
StrHelper::strncpy(_prefs.guest_password, ROOM_PASSWORD, sizeof(_prefs.guest_password));
#endif
@@ -858,13 +863,15 @@ public:
bool did_push = false;
if (client->pending_ack == 0 && client->last_activity != 0 && client->push_failures < 3) { // not already waiting for ACK, AND not evicted, AND retries not max
MESH_DEBUG_PRINTLN("loop - checking for client %02X", (uint32_t) client->id.pub_key[0]);
uint32_t now = getRTCClock()->getCurrentTime();
for (int k = 0, idx = next_post_idx; k < MAX_UNSYNCED_POSTS; k++) {
if (posts[idx].post_timestamp > client->sync_since // is new post for this Client?
&& !posts[idx].author.matches(client->id)) { // don't push posts to the author
auto p = &posts[idx];
if (now >= p->post_timestamp + POST_SYNC_DELAY_SECS && p->post_timestamp > client->sync_since // is new post for this Client?
&& !p->author.matches(client->id)) { // don't push posts to the author
// push this post to Client, then wait for ACK
pushPostToClient(client, posts[idx]);
pushPostToClient(client, *p);
did_push = true;
MESH_DEBUG_PRINTLN("loop - pushed to client %02X: %s", (uint32_t) client->id.pub_key[0], posts[idx].text);
MESH_DEBUG_PRINTLN("loop - pushed to client %02X: %s", (uint32_t) client->id.pub_key[0], p->text);
break;
}
idx = (idx + 1) % MAX_UNSYNCED_POSTS; // wrap to start of cyclic queue
+1 -1
View File
@@ -202,7 +202,7 @@ protected:
return true;
}
void onDiscoveredContact(ContactInfo& contact, bool is_new) override {
void onDiscoveredContact(ContactInfo& contact, bool is_new, uint8_t path_len, const uint8_t* path) override {
// TODO: if not in favs, prompt to add as fav(?)
Serial.printf("ADVERT from -> %s\n", contact.name);
+9 -1
View File
@@ -37,7 +37,7 @@ build_src_filter =
[esp32_base]
extends = arduino_base
platform = espressif32
platform = platformio/espressif32@^6.11.0
monitor_filters = esp32_exception_decoder
extra_scripts = merge-bin.py
build_flags = ${arduino_base.build_flags}
@@ -49,6 +49,11 @@ lib_deps =
me-no-dev/ESPAsyncWebServer @ ^3.6.0
file://arch/esp32/AsyncElegantOTA
; esp32c6 uses arduino framework 3.x
[esp32c6_base]
extends = esp32_base
platform = https://github.com/pioarduino/platform-espressif32/releases/download/stable/platform-espressif32.zip
; ----------------- NRF52 ---------------------
[nrf52_base]
@@ -70,6 +75,9 @@ lib_deps =
[rp2040_base]
extends = arduino_base
upload_protocol = picotool
board_build.core = earlephilhower
platform = https://github.com/maxgerhardt/platform-raspberrypi.git
build_flags = ${arduino_base.build_flags}
-D RP2040_PLATFORM
+8
View File
@@ -87,6 +87,14 @@ void Dispatcher::loop() {
} else {
return; // can't do any more radio activity until send is complete or timed out
}
// going back into receive mode now...
next_agc_reset_time = futureMillis(getAGCResetInterval());
}
if (getAGCResetInterval() > 0 && millisHasNowPassed(next_agc_reset_time)) {
_radio->resetAGC();
next_agc_reset_time = futureMillis(getAGCResetInterval());
}
// check inbound (delayed) queue
+5 -2
View File
@@ -65,6 +65,8 @@ public:
virtual void triggerNoiseFloorCalibrate(int threshold) { }
virtual void resetAGC() { }
virtual bool isInRecvMode() const = 0;
/**
@@ -116,7 +118,7 @@ class Dispatcher {
unsigned long next_tx_time;
unsigned long cad_busy_start;
unsigned long radio_nonrx_start;
unsigned long next_floor_calib_time;
unsigned long next_floor_calib_time, next_agc_reset_time;
bool prev_isrecv_mode;
uint32_t n_sent_flood, n_sent_direct;
uint32_t n_recv_flood, n_recv_direct;
@@ -134,7 +136,7 @@ protected:
{
outbound = NULL; total_air_time = 0; next_tx_time = 0;
cad_busy_start = 0;
next_floor_calib_time = 0;
next_floor_calib_time = next_agc_reset_time = 0;
_err_flags = 0;
radio_nonrx_start = 0;
prev_isrecv_mode = true;
@@ -154,6 +156,7 @@ protected:
virtual uint32_t getCADFailRetryDelay() const;
virtual uint32_t getCADFailMaxDuration() const;
virtual int getInterferenceThreshold() const { return 0; } // disabled by default
virtual int getAGCResetInterval() const { return 0; } // disabled by default
public:
void begin();
+1 -1
View File
@@ -3,7 +3,7 @@
uint8_t AdvertDataBuilder::encodeTo(uint8_t app_data[]) {
app_data[0] = _type;
int i = 1;
if (!(_lat == 0 && _lon == 0)) {
if (_has_loc) {
app_data[0] |= ADV_LATLON_MASK;
memcpy(&app_data[i], &_lat, 4); i += 4;
memcpy(&app_data[i], &_lon, 4); i += 4;
+5 -4
View File
@@ -17,15 +17,16 @@
class AdvertDataBuilder {
uint8_t _type;
bool _has_loc;
const char* _name;
int32_t _lat, _lon;
uint16_t _extra1 = 0;
uint16_t _extra2 = 0;
public:
AdvertDataBuilder(uint8_t adv_type) : _type(adv_type), _name(NULL), _lat(0), _lon(0) { }
AdvertDataBuilder(uint8_t adv_type, const char* name) : _type(adv_type), _name(name), _lat(0), _lon(0) { }
AdvertDataBuilder(uint8_t adv_type) : _type(adv_type), _name(NULL), _has_loc(false) { }
AdvertDataBuilder(uint8_t adv_type, const char* name) : _type(adv_type), _name(name), _has_loc(false) { }
AdvertDataBuilder(uint8_t adv_type, const char* name, double lat, double lon) :
_type(adv_type), _name(name), _lat(lat * 1E6), _lon(lon * 1E6) { }
_type(adv_type), _name(name), _has_loc(true), _lat(lat * 1E6), _lon(lon * 1E6) { }
void setFeat1(uint16_t extra) { _extra1 = extra; }
void setFeat2(uint16_t extra) { _extra2 = extra; }
@@ -56,7 +57,7 @@ public:
bool hasName() const { return _name[0] != 0; }
const char* getName() const { return _name; }
bool hasLatLon() const { return !(_lat == 0 && _lon == 0); }
bool hasLatLon() const { return (_flags & ADV_LATLON_MASK) != 0; }
int32_t getIntLat() const { return _lat; }
int32_t getIntLon() const { return _lon; }
double getLat() const { return ((double)_lat) / 1000000.0; }
+13 -2
View File
@@ -9,6 +9,17 @@
#define TXT_ACK_DELAY 200
#endif
mesh::Packet* BaseChatMesh::createSelfAdvert(const char* name) {
uint8_t app_data[MAX_ADVERT_DATA_SIZE];
uint8_t app_data_len;
{
AdvertDataBuilder builder(ADV_TYPE_CHAT, name);
app_data_len = builder.encodeTo(app_data);
}
return createAdvert(self_id, app_data, app_data_len);
}
mesh::Packet* BaseChatMesh::createSelfAdvert(const char* name, double lat, double lon) {
uint8_t app_data[MAX_ADVERT_DATA_SIZE];
uint8_t app_data_len;
@@ -58,7 +69,7 @@ void BaseChatMesh::onAdvertRecv(mesh::Packet* packet, const mesh::Identity& id,
}
ci.last_advert_timestamp = timestamp;
ci.lastmod = getRTCClock()->getCurrentTime();
onDiscoveredContact(ci, true); // let UI know
onDiscoveredContact(ci, true, packet->path_len, packet->path); // let UI know
return;
}
@@ -89,7 +100,7 @@ void BaseChatMesh::onAdvertRecv(mesh::Packet* packet, const mesh::Identity& id,
from->last_advert_timestamp = timestamp;
from->lastmod = getRTCClock()->getCurrentTime();
onDiscoveredContact(*from, is_new); // let UI know
onDiscoveredContact(*from, is_new, packet->path_len, packet->path); // let UI know
}
int BaseChatMesh::searchPeersByHash(const uint8_t* hash) {
+3 -2
View File
@@ -89,7 +89,7 @@ protected:
// 'UI' concepts, for sub-classes to implement
virtual bool isAutoAddEnabled() const { return true; }
virtual void onDiscoveredContact(ContactInfo& contact, bool is_new) = 0;
virtual void onDiscoveredContact(ContactInfo& contact, bool is_new, uint8_t path_len, const uint8_t* path) = 0;
virtual bool processAck(const uint8_t *data) = 0;
virtual void onContactPathUpdated(const ContactInfo& contact) = 0;
virtual void onMessageRecv(const ContactInfo& contact, mesh::Packet* pkt, uint32_t sender_timestamp, const char *text) = 0;
@@ -127,7 +127,8 @@ protected:
void checkConnections();
public:
mesh::Packet* createSelfAdvert(const char* name, double lat=0.0, double lon=0.0);
mesh::Packet* createSelfAdvert(const char* name);
mesh::Packet* createSelfAdvert(const char* name, double lat, double lon);
int sendMessage(const ContactInfo& recipient, uint32_t timestamp, uint8_t attempt, const char* text, uint32_t& expected_ack, uint32_t& est_timeout);
int sendCommandData(const ContactInfo& recipient, uint32_t timestamp, uint8_t attempt, const char* text, uint32_t& est_timeout);
bool sendGroupMessage(uint32_t timestamp, mesh::GroupChannel& channel, const char* sender_name, const char* text, int text_len);
+20 -12
View File
@@ -53,7 +53,8 @@ void CommonCLI::loadPrefsInt(FILESYSTEM* fs, const char* filename) {
file.read((uint8_t *) &_prefs->allow_read_only, sizeof(_prefs->allow_read_only)); // 114
file.read((uint8_t *) &_prefs->reserved2, sizeof(_prefs->reserved2)); // 115
file.read((uint8_t *) &_prefs->bw, sizeof(_prefs->bw)); // 116
file.read(pad, 4); // 120
file.read((uint8_t *) &_prefs->agc_reset_interval, sizeof(_prefs->agc_reset_interval)); // 120
file.read(pad, 3); // 121
file.read((uint8_t *) &_prefs->flood_max, sizeof(_prefs->flood_max)); // 124
file.read((uint8_t *) &_prefs->flood_advert_interval, sizeof(_prefs->flood_advert_interval)); // 125
file.read((uint8_t *) &_prefs->interference_threshold, sizeof(_prefs->interference_threshold)); // 126
@@ -107,7 +108,8 @@ void CommonCLI::savePrefs(FILESYSTEM* fs) {
file.write((uint8_t *) &_prefs->allow_read_only, sizeof(_prefs->allow_read_only)); // 114
file.write((uint8_t *) &_prefs->reserved2, sizeof(_prefs->reserved2)); // 115
file.write((uint8_t *) &_prefs->bw, sizeof(_prefs->bw)); // 116
file.write(pad, 4); // 120
file.write((uint8_t *) &_prefs->agc_reset_interval, sizeof(_prefs->agc_reset_interval)); // 120
file.write(pad, 3); // 121
file.write((uint8_t *) &_prefs->flood_max, sizeof(_prefs->flood_max)); // 124
file.write((uint8_t *) &_prefs->flood_advert_interval, sizeof(_prefs->flood_advert_interval)); // 125
file.write((uint8_t *) &_prefs->interference_threshold, sizeof(_prefs->interference_threshold)); // 126
@@ -142,7 +144,9 @@ void CommonCLI::handleCommand(uint32_t sender_timestamp, const char* command, ch
uint32_t curr = getRTCClock()->getCurrentTime();
if (sender_timestamp > curr) {
getRTCClock()->setCurrentTime(sender_timestamp + 1);
strcpy(reply, "OK - clock set");
uint32_t now = getRTCClock()->getCurrentTime();
DateTime dt = DateTime(now);
sprintf(reply, "OK - clock set: %02d:%02d - %d/%d/%d UTC", dt.hour(), dt.minute(), dt.day(), dt.month(), dt.year());
} else {
strcpy(reply, "ERR: clock cannot go backwards");
}
@@ -159,7 +163,9 @@ void CommonCLI::handleCommand(uint32_t sender_timestamp, const char* command, ch
uint32_t curr = getRTCClock()->getCurrentTime();
if (secs > curr) {
getRTCClock()->setCurrentTime(secs);
strcpy(reply, "(OK - clock set!)");
uint32_t now = getRTCClock()->getCurrentTime();
DateTime dt = DateTime(now);
sprintf(reply, "OK - clock set: %02d:%02d - %d/%d/%d UTC", dt.hour(), dt.minute(), dt.day(), dt.month(), dt.year());
} else {
strcpy(reply, "(ERR: clock cannot go backwards)");
}
@@ -180,6 +186,8 @@ void CommonCLI::handleCommand(uint32_t sender_timestamp, const char* command, ch
sprintf(reply, "> %s", StrHelper::ftoa(_prefs->airtime_factor));
} else if (memcmp(config, "int.thresh", 10) == 0) {
sprintf(reply, "> %d", (uint32_t) _prefs->interference_threshold);
} else if (memcmp(config, "agc.reset.interval", 18) == 0) {
sprintf(reply, "> %d", ((uint32_t) _prefs->agc_reset_interval) * 4);
} else if (memcmp(config, "allow.read.only", 15) == 0) {
sprintf(reply, "> %s", _prefs->allow_read_only ? "on" : "off");
} else if (memcmp(config, "flood.advert.interval", 21) == 0) {
@@ -231,16 +239,18 @@ void CommonCLI::handleCommand(uint32_t sender_timestamp, const char* command, ch
_prefs->interference_threshold = atoi(&config[11]);
savePrefs();
strcpy(reply, "OK");
} else if (memcmp(config, "agc.reset.interval ", 19) == 0) {
_prefs->agc_reset_interval = atoi(&config[19]) / 4;
savePrefs();
strcpy(reply, "OK");
} else if (memcmp(config, "allow.read.only ", 16) == 0) {
_prefs->allow_read_only = memcmp(&config[16], "on", 2) == 0;
savePrefs();
strcpy(reply, "OK");
} else if (memcmp(config, "flood.advert.interval ", 22) == 0) {
int hours = _atoi(&config[22]);
if (hours > 0 && hours < 3) {
sprintf(reply, "Error: min is 3 hours");
} else if (hours > 48) {
strcpy(reply, "Error: max is 48 hours");
if ((hours > 0 && hours < 3) || (hours > 48)) {
strcpy(reply, "Error: interval range is 3-48 hours");
} else {
_prefs->flood_advert_interval = (uint8_t)(hours);
_callbacks->updateFloodAdvertTimer();
@@ -249,10 +259,8 @@ void CommonCLI::handleCommand(uint32_t sender_timestamp, const char* command, ch
}
} else if (memcmp(config, "advert.interval ", 16) == 0) {
int mins = _atoi(&config[16]);
if (mins > 0 && mins < MIN_LOCAL_ADVERT_INTERVAL) {
sprintf(reply, "Error: min is %d mins", MIN_LOCAL_ADVERT_INTERVAL);
} else if (mins > 240) {
strcpy(reply, "Error: max is 240 mins");
if ((mins > 0 && mins < MIN_LOCAL_ADVERT_INTERVAL) || (mins > 240)) {
sprintf(reply, "Error: interval range is %d-240 minutes", MIN_LOCAL_ADVERT_INTERVAL);
} else {
_prefs->advert_interval = (uint8_t)(mins / 2);
_callbacks->updateAdvertTimer();
+1
View File
@@ -25,6 +25,7 @@ struct NodePrefs { // persisted to file
float bw;
uint8_t flood_max;
uint8_t interference_threshold;
uint8_t agc_reset_interval; // secs / 4
};
class CommonCLICallbacks {
+70
View File
@@ -9,6 +9,76 @@ class CustomLLCC68 : public LLCC68 {
public:
CustomLLCC68(Module *mod) : LLCC68(mod) { }
#ifdef RP2040_PLATFORM
bool std_init(SPIClassRP2040* spi = NULL)
#else
bool std_init(SPIClass* spi = NULL)
#endif
{
#ifdef SX126X_DIO3_TCXO_VOLTAGE
float tcxo = SX126X_DIO3_TCXO_VOLTAGE;
#else
float tcxo = 1.6f;
#endif
#ifdef LORA_CR
uint8_t cr = LORA_CR;
#else
uint8_t cr = 5;
#endif
#if defined(P_LORA_SCLK)
#ifdef NRF52_PLATFORM
if (spi) { spi->setPins(P_LORA_MISO, P_LORA_SCLK, P_LORA_MOSI); spi->begin(); }
#elif defined(RP2040_PLATFORM)
if (spi) {
spi->setMISO(P_LORA_MISO);
//spi->setCS(P_LORA_NSS); // Setting CS results in freeze
spi->setSCK(P_LORA_SCLK);
spi->setMOSI(P_LORA_MOSI);
spi->begin();
}
#else
if (spi) spi->begin(P_LORA_SCLK, P_LORA_MISO, P_LORA_MOSI);
#endif
#endif
int status = begin(LORA_FREQ, LORA_BW, LORA_SF, cr, RADIOLIB_SX126X_SYNC_WORD_PRIVATE, LORA_TX_POWER, 16, tcxo);
// if radio init fails with -707/-706, try again with tcxo voltage set to 0.0f
if (status == RADIOLIB_ERR_SPI_CMD_FAILED || status == RADIOLIB_ERR_SPI_CMD_INVALID) {
#define SX126X_DIO3_TCXO_VOLTAGE (0.0f);
tcxo = SX126X_DIO3_TCXO_VOLTAGE;
status = begin(LORA_FREQ, LORA_BW, LORA_SF, cr, RADIOLIB_SX126X_SYNC_WORD_PRIVATE, LORA_TX_POWER, 16, tcxo);
}
if (status != RADIOLIB_ERR_NONE) {
Serial.print("ERROR: radio init failed: ");
Serial.println(status);
return false; // fail
}
setCRC(1);
#ifdef SX126X_CURRENT_LIMIT
setCurrentLimit(SX126X_CURRENT_LIMIT);
#endif
#ifdef SX126X_DIO2_AS_RF_SWITCH
setDio2AsRfSwitch(SX126X_DIO2_AS_RF_SWITCH);
#endif
#ifdef SX126X_RX_BOOSTED_GAIN
setRxBoostedGainMode(SX126X_RX_BOOSTED_GAIN);
#endif
#if defined(SX126X_RXEN) || defined(SX126X_TXEN)
#ifndef SX1262X_RXEN
#define SX1262X_RXEN RADIOLIB_NC
#endif
#ifndef SX1262X_TXEN
#define SX1262X_TXEN RADIOLIB_NC
#endif
setRfSwitchPins(SX126X_RXEN, SX126X_TXEN);
#endif
return true; // success
}
bool isReceiving() {
uint16_t irq = getIrqFlags();
bool detected = (irq & SX126X_IRQ_HEADER_VALID) || (irq & SX126X_IRQ_PREAMBLE_DETECTED);
+70
View File
@@ -9,6 +9,76 @@ class CustomSX1262 : public SX1262 {
public:
CustomSX1262(Module *mod) : SX1262(mod) { }
#ifdef RP2040_PLATFORM
bool std_init(SPIClassRP2040* spi = NULL)
#else
bool std_init(SPIClass* spi = NULL)
#endif
{
#ifdef SX126X_DIO3_TCXO_VOLTAGE
float tcxo = SX126X_DIO3_TCXO_VOLTAGE;
#else
float tcxo = 1.6f;
#endif
#ifdef LORA_CR
uint8_t cr = LORA_CR;
#else
uint8_t cr = 5;
#endif
#if defined(P_LORA_SCLK)
#ifdef NRF52_PLATFORM
if (spi) { spi->setPins(P_LORA_MISO, P_LORA_SCLK, P_LORA_MOSI); spi->begin(); }
#elif defined(RP2040_PLATFORM)
if (spi) {
spi->setMISO(P_LORA_MISO);
//spi->setCS(P_LORA_NSS); // Setting CS results in freeze
spi->setSCK(P_LORA_SCLK);
spi->setMOSI(P_LORA_MOSI);
spi->begin();
}
#else
if (spi) spi->begin(P_LORA_SCLK, P_LORA_MISO, P_LORA_MOSI);
#endif
#endif
int status = begin(LORA_FREQ, LORA_BW, LORA_SF, cr, RADIOLIB_SX126X_SYNC_WORD_PRIVATE, LORA_TX_POWER, 16, tcxo);
// if radio init fails with -707/-706, try again with tcxo voltage set to 0.0f
if (status == RADIOLIB_ERR_SPI_CMD_FAILED || status == RADIOLIB_ERR_SPI_CMD_INVALID) {
#define SX126X_DIO3_TCXO_VOLTAGE (0.0f);
tcxo = SX126X_DIO3_TCXO_VOLTAGE;
status = begin(LORA_FREQ, LORA_BW, LORA_SF, cr, RADIOLIB_SX126X_SYNC_WORD_PRIVATE, LORA_TX_POWER, 16, tcxo);
}
if (status != RADIOLIB_ERR_NONE) {
Serial.print("ERROR: radio init failed: ");
Serial.println(status);
return false; // fail
}
setCRC(1);
#ifdef SX126X_CURRENT_LIMIT
setCurrentLimit(SX126X_CURRENT_LIMIT);
#endif
#ifdef SX126X_DIO2_AS_RF_SWITCH
setDio2AsRfSwitch(SX126X_DIO2_AS_RF_SWITCH);
#endif
#ifdef SX126X_RX_BOOSTED_GAIN
setRxBoostedGainMode(SX126X_RX_BOOSTED_GAIN);
#endif
#if defined(SX126X_RXEN) || defined(SX126X_TXEN)
#ifndef SX126X_RXEN
#define SX126X_RXEN RADIOLIB_NC
#endif
#ifndef SX126X_TXEN
#define SX126X_TXEN RADIOLIB_NC
#endif
setRfSwitchPins(SX126X_RXEN, SX126X_TXEN);
#endif
return true; // success
}
bool isReceiving() {
uint16_t irq = getIrqFlags();
bool detected = (irq & SX126X_IRQ_HEADER_VALID) || (irq & SX126X_IRQ_PREAMBLE_DETECTED);
+70
View File
@@ -9,6 +9,76 @@ class CustomSX1268 : public SX1268 {
public:
CustomSX1268(Module *mod) : SX1268(mod) { }
#ifdef RP2040_PLATFORM
bool std_init(SPIClassRP2040* spi = NULL)
#else
bool std_init(SPIClass* spi = NULL)
#endif
{
#ifdef SX126X_DIO3_TCXO_VOLTAGE
float tcxo = SX126X_DIO3_TCXO_VOLTAGE;
#else
float tcxo = 1.6f;
#endif
#ifdef LORA_CR
uint8_t cr = LORA_CR;
#else
uint8_t cr = 5;
#endif
#if defined(P_LORA_SCLK)
#ifdef NRF52_PLATFORM
if (spi) { spi->setPins(P_LORA_MISO, P_LORA_SCLK, P_LORA_MOSI); spi->begin(); }
#elif defined(RP2040_PLATFORM)
if (spi) {
spi->setMISO(P_LORA_MISO);
//spi->setCS(P_LORA_NSS); // Setting CS results in freeze
spi->setSCK(P_LORA_SCLK);
spi->setMOSI(P_LORA_MOSI);
spi->begin();
}
#else
if (spi) spi->begin(P_LORA_SCLK, P_LORA_MISO, P_LORA_MOSI);
#endif
#endif
int status = begin(LORA_FREQ, LORA_BW, LORA_SF, cr, RADIOLIB_SX126X_SYNC_WORD_PRIVATE, LORA_TX_POWER, 16, tcxo);
// if radio init fails with -707/-706, try again with tcxo voltage set to 0.0f
if (status == RADIOLIB_ERR_SPI_CMD_FAILED || status == RADIOLIB_ERR_SPI_CMD_INVALID) {
#define SX126X_DIO3_TCXO_VOLTAGE (0.0f);
tcxo = SX126X_DIO3_TCXO_VOLTAGE;
status = begin(LORA_FREQ, LORA_BW, LORA_SF, cr, RADIOLIB_SX126X_SYNC_WORD_PRIVATE, LORA_TX_POWER, 16, tcxo);
}
if (status != RADIOLIB_ERR_NONE) {
Serial.print("ERROR: radio init failed: ");
Serial.println(status);
return false; // fail
}
setCRC(1);
#ifdef SX126X_CURRENT_LIMIT
setCurrentLimit(SX126X_CURRENT_LIMIT);
#endif
#ifdef SX126X_DIO2_AS_RF_SWITCH
setDio2AsRfSwitch(SX126X_DIO2_AS_RF_SWITCH);
#endif
#ifdef SX126X_RX_BOOSTED_GAIN
setRxBoostedGainMode(SX126X_RX_BOOSTED_GAIN);
#endif
#if defined(SX126X_RXEN) || defined(SX126X_TXEN)
#ifndef SX1262X_RXEN
#define SX1262X_RXEN RADIOLIB_NC
#endif
#ifndef SX1262X_TXEN
#define SX1262X_TXEN RADIOLIB_NC
#endif
setRfSwitchPins(SX126X_RXEN, SX126X_TXEN);
#endif
return true; // success
}
bool isReceiving() {
uint16_t irq = getIrqFlags();
bool detected = (irq & SX126X_IRQ_HEADER_VALID) || (irq & SX126X_IRQ_PREAMBLE_DETECTED);
+56 -3
View File
@@ -12,10 +12,63 @@ class CustomSX1276 : public SX1276 {
public:
CustomSX1276(Module *mod) : SX1276(mod) { }
#ifdef RP2040_PLATFORM
bool std_init(SPIClassRP2040* spi = NULL)
#else
bool std_init(SPIClass* spi = NULL)
#endif
{
#ifdef LORA_CR
uint8_t cr = LORA_CR;
#else
uint8_t cr = 5;
#endif
#if defined(P_LORA_SCLK)
#ifdef NRF52_PLATFORM
if (spi) { spi->setPins(P_LORA_MISO, P_LORA_SCLK, P_LORA_MOSI); spi->begin(); }
#elif defined(RP2040_PLATFORM)
if (spi) {
spi->setMISO(P_LORA_MISO);
//spi->setCS(P_LORA_NSS); // Setting CS results in freeze
spi->setSCK(P_LORA_SCLK);
spi->setMOSI(P_LORA_MOSI);
spi->begin();
}
#else
if (spi) spi->begin(P_LORA_SCLK, P_LORA_MISO, P_LORA_MOSI);
#endif
#endif
int status = begin(LORA_FREQ, LORA_BW, LORA_SF, cr, RADIOLIB_SX126X_SYNC_WORD_PRIVATE, LORA_TX_POWER, 16);
// if radio init fails with -707/-706, try again with tcxo voltage set to 0.0f
if (status != RADIOLIB_ERR_NONE) {
Serial.print("ERROR: radio init failed: ");
Serial.println(status);
return false; // fail
}
#ifdef SX127X_CURRENT_LIMIT
setCurrentLimit(SX127X_CURRENT_LIMIT);
#endif
#if defined(SX176X_RXEN) || defined(SX176X_TXEN)
#ifndef SX176X_RXEN
#define SX176X_RXEN RADIOLIB_NC
#endif
#ifndef SX176X_TXEN
#define SX176X_TXEN RADIOLIB_NC
#endif
setRfSwitchPins(SX176X_RXEN, SX176X_TXEN);
#endif
setCRC(1);
return true; // success
}
bool isReceiving() {
return (getModemStatus() &
(RH_RF95_MODEM_STATUS_SIGNAL_DETECTED
| RH_RF95_MODEM_STATUS_SIGNAL_SYNCHRONIZED
(RH_RF95_MODEM_STATUS_SIGNAL_DETECTED
| RH_RF95_MODEM_STATUS_SIGNAL_SYNCHRONIZED
| RH_RF95_MODEM_STATUS_HEADER_INFO_VALID)) != 0;
}
@@ -23,7 +76,7 @@ class CustomSX1276 : public SX1276 {
// start CAD
int16_t state = startChannelScan();
RADIOLIB_ASSERT(state);
// wait for channel activity detected or timeout
unsigned long timeout = millis() + 16;
while(!this->mod->hal->digitalRead(this->mod->getIrq()) && millis() < timeout) {
+9
View File
@@ -51,6 +51,15 @@ public:
void onAfterTransmit() override {
digitalWrite(P_LORA_TX_LED, LOW); // turn TX LED off
}
#elif defined(P_LORA_TX_NEOPIXEL_LED)
#define NEOPIXEL_BRIGHTNESS 64 // white brightness (max 255)
void onBeforeTransmit() override {
neopixelWrite(P_LORA_TX_NEOPIXEL_LED, NEOPIXEL_BRIGHTNESS, NEOPIXEL_BRIGHTNESS, NEOPIXEL_BRIGHTNESS); // turn TX neopixel on (White)
}
void onAfterTransmit() override {
neopixelWrite(P_LORA_TX_NEOPIXEL_LED, 0, 0, 0); // turn TX neopixel off
}
#endif
uint16_t getBattMilliVolts() override {
+1 -1
View File
@@ -68,7 +68,7 @@ public:
}
raw = raw / 8;
return (1.883 * (2 / 1024.0) * raw) * 1000;
return (1.98 * (2 / 1024.0) * raw) * 1000;
}
const char* getManufacturerName() const override {
+1 -1
View File
@@ -99,7 +99,7 @@ public:
digitalWrite(PIN_ADC_CTRL, !adc_active_state);
return (5.2 * (3.3 / 1024.0) * raw) * 1000;
return (5.42 * (3.3 / 1024.0) * raw) * 1000;
}
const char* getManufacturerName() const override {
+12 -2
View File
@@ -9,6 +9,7 @@
#define STATE_INT_READY 16
#define NUM_NOISE_FLOOR_SAMPLES 64
#define SAMPLING_THRESHOLD 14
static volatile uint8_t state = STATE_IDLE;
@@ -46,17 +47,26 @@ void RadioLibWrapper::idle() {
void RadioLibWrapper::triggerNoiseFloorCalibrate(int threshold) {
_threshold = threshold;
if (threshold > 0 && _num_floor_samples >= NUM_NOISE_FLOOR_SAMPLES) { // ignore trigger if currently sampling
if (_num_floor_samples >= NUM_NOISE_FLOOR_SAMPLES) { // ignore trigger if currently sampling
_num_floor_samples = 0;
_floor_sample_sum = 0;
}
}
void RadioLibWrapper::resetAGC() {
// make sure we're not mid-receive of packet!
if ((state & STATE_INT_READY) != 0 || isReceivingPacket()) return;
// NOTE: according to higher powers, just issuing RadioLib's startReceive() will reset the AGC.
// revisit this if a better impl is discovered.
state = STATE_IDLE; // trigger a startReceive()
}
void RadioLibWrapper::loop() {
if (state == STATE_RX && _num_floor_samples < NUM_NOISE_FLOOR_SAMPLES) {
if (!isReceivingPacket()) {
int rssi = getCurrentRSSI();
if (rssi < _noise_floor + _threshold) { // only consider samples below current floor+THRESHOLD
if (rssi < _noise_floor + SAMPLING_THRESHOLD) { // only consider samples below current floor + sampling THRESHOLD
_num_floor_samples++;
_floor_sample_sum += rssi;
}
+1
View File
@@ -39,6 +39,7 @@ public:
int getNoiseFloor() const override { return _noise_floor; }
void triggerNoiseFloorCalibrate(int threshold) override;
void resetAGC() override;
void loop() override;
-87
View File
@@ -1,87 +0,0 @@
#pragma once
#include <Wire.h>
#include <Arduino.h>
#include "XPowersLib.h"
// Defined using AXP2102
#define XPOWERS_CHIP_AXP2101
#define PIN_BOARD_SDA1 42 //SDA for PMU and PFC8563 (RTC)
#define PIN_BOARD_SCL1 41 //SCL for PMU and PFC8563 (RTC)
#define PIN_PMU_IRQ 40 //IRQ pin for PMU
// LoRa radio module pins for TBeam
#define P_LORA_DIO_0 26
#define P_LORA_DIO_2 32
#define P_LORA_DIO_1 33
#define P_LORA_NSS 18
#define P_LORA_RESET 14
#define P_LORA_BUSY RADIOLIB_NC
#define P_LORA_SCLK 5
#define P_LORA_MISO 19
#define P_LORA_MOSI 27
// built-ins
//#define PIN_VBAT_READ 37
//#define PIN_LED_BUILTIN 25
#include "ESP32Board.h"
#include <driver/rtc_io.h>
class TBeamBoard : public ESP32Board {
XPowersLibInterface *PMU = NULL;
public:
bool power_init();
void printPMU();
void begin() {
ESP32Board::begin();
pinMode(38, INPUT_PULLUP);
esp_reset_reason_t reason = esp_reset_reason();
if (reason == ESP_RST_DEEPSLEEP) {
long wakeup_source = esp_sleep_get_ext1_wakeup_status();
if (wakeup_source & (1 << P_LORA_DIO_1)) { // received a LoRa packet (while in deep sleep)
startup_reason = BD_STARTUP_RX_PACKET;
}
rtc_gpio_hold_dis((gpio_num_t)P_LORA_NSS);
rtc_gpio_deinit((gpio_num_t)P_LORA_DIO_1);
}
power_init();
}
void enterDeepSleep(uint32_t secs, int pin_wake_btn = -1) {
esp_sleep_pd_config(ESP_PD_DOMAIN_RTC_PERIPH, ESP_PD_OPTION_ON);
// Make sure the DIO1 and NSS GPIOs are hold on required levels during deep sleep
rtc_gpio_set_direction((gpio_num_t)P_LORA_DIO_1, RTC_GPIO_MODE_INPUT_ONLY);
rtc_gpio_pulldown_en((gpio_num_t)P_LORA_DIO_1);
rtc_gpio_hold_en((gpio_num_t)P_LORA_NSS);
if (pin_wake_btn < 0) {
esp_sleep_enable_ext1_wakeup( (1L << P_LORA_DIO_1), ESP_EXT1_WAKEUP_ANY_HIGH); // wake up on: recv LoRa packet
} else {
esp_sleep_enable_ext1_wakeup( (1L << P_LORA_DIO_1) | (1L << pin_wake_btn), ESP_EXT1_WAKEUP_ANY_HIGH); // wake up on: recv LoRa packet OR wake btn
}
if (secs > 0) {
esp_sleep_enable_timer_wakeup(secs * 1000000);
}
// Finally set ESP32 into sleep
esp_deep_sleep_start(); // CPU halts here and never returns!
}
uint16_t getBattMilliVolts() override {
if(PMU) return PMU->getBattVoltage();
else return 0;
}
const char* getManufacturerName() const override {
return "LilyGo T-Beam";
}
};
-79
View File
@@ -1,79 +0,0 @@
#pragma once
#include <Wire.h>
#include <Arduino.h>
#include "XPowersLib.h"
#define XPOWERS_CHIP_AXP192
// LoRa radio module pins for TBeam
#define P_LORA_DIO_1 33 // SX1262 IRQ pin
#define P_LORA_NSS 18
#define P_LORA_RESET 23
#define P_LORA_BUSY 32 // SX1262 Busy pin
#define P_LORA_SCLK 5
#define P_LORA_MISO 19
#define P_LORA_MOSI 27
#include "ESP32Board.h"
#include <driver/rtc_io.h>
class TBeamBoardSX1262 : public ESP32Board {
XPowersAXP192 power;
public:
void begin() {
ESP32Board::begin();
power.setLDO2Voltage(3300);
power.enableLDO2();
power.enableBattVoltageMeasure();
pinMode(38, INPUT_PULLUP);
esp_reset_reason_t reason = esp_reset_reason();
if (reason == ESP_RST_DEEPSLEEP) {
long wakeup_source = esp_sleep_get_ext1_wakeup_status();
if (wakeup_source & (1 << P_LORA_DIO_1)) { // received a LoRa packet (while in deep sleep)
startup_reason = BD_STARTUP_RX_PACKET;
}
rtc_gpio_hold_dis((gpio_num_t)P_LORA_NSS);
rtc_gpio_deinit((gpio_num_t)P_LORA_DIO_1);
}
}
void enterDeepSleep(uint32_t secs, int pin_wake_btn = -1) {
esp_sleep_pd_config(ESP_PD_DOMAIN_RTC_PERIPH, ESP_PD_OPTION_ON);
// Make sure the DIO1 and NSS GPIOs are hold on required levels during deep sleep
rtc_gpio_set_direction((gpio_num_t)P_LORA_DIO_1, RTC_GPIO_MODE_INPUT_ONLY);
rtc_gpio_pulldown_en((gpio_num_t)P_LORA_DIO_1);
rtc_gpio_hold_en((gpio_num_t)P_LORA_NSS);
if (pin_wake_btn < 0) {
esp_sleep_enable_ext1_wakeup( (1L << P_LORA_DIO_1), ESP_EXT1_WAKEUP_ANY_HIGH); // wake up on: recv LoRa packet
} else {
esp_sleep_enable_ext1_wakeup( (1L << P_LORA_DIO_1) | (1L << pin_wake_btn), ESP_EXT1_WAKEUP_ANY_HIGH); // wake up on: recv LoRa packet OR wake btn
}
if (secs > 0) {
esp_sleep_enable_timer_wakeup(secs * 1000000);
}
// Finally set ESP32 into sleep
esp_deep_sleep_start(); // CPU halts here and never returns!
}
uint16_t getBattMilliVolts() override {
return power.getBattVoltage();
}
const char* getManufacturerName() const override {
return "LilyGo T-Beam SX1262";
}
};
-116
View File
@@ -1,116 +0,0 @@
#pragma once
#include "ESP32Board.h"
#include <driver/rtc_io.h>
#include <Wire.h>
#include <Arduino.h>
#include "XPowersLib.h"
// LoRa radio module pins for TBeam S3 Supreme
#define P_LORA_DIO_1 1 //SX1262 IRQ pin
#define P_LORA_NSS 10 //SX1262 SS pin
#define P_LORA_RESET 5 //SX1262 Rest pin
#define P_LORA_BUSY 4 //SX1262 Busy pin
#define P_LORA_SCLK 12 //SX1262 SCLK pin
#define P_LORA_MISO 13 //SX1262 MISO pin
#define P_LORA_MOSI 11 //SX1262 MOSI pin
//#define PIN_BOARD_SDA 17 //SDA for OLED, BME280, and QMC6310U (0x1C)
//#define PIN_BOARD_SCL 18 //SCL for OLED, BME280, and QMC6310U (0x1C)
#define PIN_BOARD_SDA1 42 //SDA for PMU and PFC8563 (RTC)
#define PIN_BOARD_SCL1 41 //SCL for PMU and PFC8563 (RTC)
#define PIN_PMU_IRQ 40 //IRQ pin for PMU
//#define PIN_USER_BTN 0
#define P_BOARD_SPI_MOSI 35 //SPI for SD Card and QMI8653 (IMU)
#define P_BOARD_SPI_MISO 37 //SPI for SD Card and QMI8653 (IMU)
#define P_BOARD_SPI_SCK 36 //SPI for SD Card and QMI8653 (IMU)
#define P_BPARD_SPI_CS 47 //Pin for SD Card CS
#define P_BOARD_IMU_CS 34 //Pin for QMI8653 (IMU) CS
#define P_BOARD_IMU_INT 33 //IMU Int pin
#define P_BOARD_RTC_INT 14 //RTC Int pin
#define P_GPS_RX 9 //GPS RX pin
#define P_GPS_TX 8 //GPS TX pin
#define P_GPS_WAKE 7 //GPS Wakeup pin
//#define P_GPS_1PPS 6 //GPS 1PPS pin - repurposed for lora tx led
#define GPS_BAUD_RATE 9600
//I2C Wire addresses
#define I2C_BME280_ADD 0x76 //BME280 sensor I2C address on Wire
#define I2C_OLED_ADD 0x3C //SH1106 OLED I2C address on Wire
#define I2C_QMC6310U_ADD 0x1C //QMC6310U mag sensor I2C address on Wire
//I2C Wire1 addresses
#define I2C_RTC_ADD 0x51 //RTC I2C address on Wire1
#define I2C_PMU_ADD 0x34 //AXP2101 I2C address on Wire1
#define PMU_WIRE_PORT Wire1
#define XPOWERS_CHIP_AXP2101
class TBeamS3SupremeBoard : public ESP32Board {
XPowersAXP2101 PMU;
public:
#ifdef MESH_DEBUG
void printPMU();
#endif
bool power_init();
void begin() {
ESP32Board::begin();
power_init();
esp_reset_reason_t reason = esp_reset_reason();
if (reason == ESP_RST_DEEPSLEEP) {
long wakeup_source = esp_sleep_get_ext1_wakeup_status();
if (wakeup_source & (1 << P_LORA_DIO_1)) { // received a LoRa packet (while in deep sleep)
startup_reason = BD_STARTUP_RX_PACKET;
}
rtc_gpio_hold_dis((gpio_num_t)P_LORA_NSS);
rtc_gpio_deinit((gpio_num_t)P_LORA_DIO_1);
}
power_init();
}
void enterDeepSleep(uint32_t secs, int pin_wake_btn = -1) {
esp_sleep_pd_config(ESP_PD_DOMAIN_RTC_PERIPH, ESP_PD_OPTION_ON);
// Make sure the DIO1 and NSS GPIOs are hold on required levels during deep sleep
rtc_gpio_set_direction((gpio_num_t)P_LORA_DIO_1, RTC_GPIO_MODE_INPUT_ONLY);
rtc_gpio_pulldown_en((gpio_num_t)P_LORA_DIO_1);
rtc_gpio_hold_en((gpio_num_t)P_LORA_NSS);
if (pin_wake_btn < 0) {
esp_sleep_enable_ext1_wakeup( (1L << P_LORA_DIO_1), ESP_EXT1_WAKEUP_ANY_HIGH); // wake up on: recv LoRa packet
} else {
esp_sleep_enable_ext1_wakeup( (1L << P_LORA_DIO_1) | (1L << pin_wake_btn), ESP_EXT1_WAKEUP_ANY_HIGH); // wake up on: recv LoRa packet OR wake btn
}
if (secs > 0) {
esp_sleep_enable_timer_wakeup(secs * 1000000);
}
// Finally set ESP32 into sleep
esp_deep_sleep_start(); // CPU halts here and never returns!
}
uint16_t getBattMilliVolts() override {
return PMU.getBattVoltage();
}
uint16_t getBattPercent() {
//Read the PMU fuel guage for battery %
uint16_t battPercent = PMU.getBatteryPercent();
return battPercent;
}
const char* getManufacturerName() const override {
return "LilyGo T-Beam S3 Supreme SX1262";
}
};
+350
View File
@@ -0,0 +1,350 @@
#if defined(TBEAM_SUPREME_SX1262) || defined(TBEAM_SX1262) || defined(TBEAM_SX1276)
#include <Arduino.h>
#include "TBeamBoard.h"
//#include <RadioLib.h>
uint32_t deviceOnline = 0x00;
bool pmuInterrupt;
static void setPmuFlag()
{
pmuInterrupt = true;
}
void TBeamBoard::begin() {
ESP32Board::begin();
power_init();
//Configure user button
pinMode(PIN_USER_BTN, INPUT);
#ifndef TBEAM_SUPREME_SX1262
digitalWrite(P_LORA_TX_LED, HIGH); //inverted pin for SX1276 - HIGH for off
#endif
//radiotype_detect();
esp_reset_reason_t reason = esp_reset_reason();
if (reason == ESP_RST_DEEPSLEEP) {
long wakeup_source = esp_sleep_get_ext1_wakeup_status();
if (wakeup_source & (1 << P_LORA_DIO_1)) { // received a LoRa packet (while in deep sleep)
startup_reason = BD_STARTUP_RX_PACKET;
}
rtc_gpio_hold_dis((gpio_num_t)P_LORA_NSS);
rtc_gpio_deinit((gpio_num_t)P_LORA_DIO_1);
}
}
#ifdef MESH_DEBUG
void TBeamBoard::scanDevices(TwoWire *w)
{
uint8_t err, addr;
int nDevices = 0;
uint32_t start = 0;
Serial.println("Scanning I2C for Devices");
for (addr = 1; addr < 127; addr++) {
start = millis();
w->beginTransmission(addr); delay(2);
err = w->endTransmission();
if (err == 0) {
nDevices++;
switch (addr) {
case 0x77:
case 0x76:
Serial.println("\tFound BME280 Sensor");
deviceOnline |= BME280_ONLINE;
break;
case 0x34:
Serial.println("\tFound AXP192/AXP2101 PMU");
deviceOnline |= POWERMANAGE_ONLINE;
break;
case 0x3C:
Serial.println("\tFound SSD1306/SH1106 display");
deviceOnline |= DISPLAY_ONLINE;
break;
case 0x51:
Serial.println("\tFound PCF8563 RTC");
deviceOnline |= PCF8563_ONLINE;
break;
case 0x1C:
Serial.println("\tFound QMC6310 MAG Sensor");
deviceOnline |= QMC6310_ONLINE;
break;
default:
Serial.print("\tI2C device found at address 0x");
if (addr < 16) {
Serial.print("0");
}
Serial.print(addr, HEX);
Serial.println(" !");
break;
}
} else if (err == 4) {
Serial.print("Unknow error at address 0x");
if (addr < 16) {
Serial.print("0");
}
Serial.println(addr, HEX);
}
}
if (nDevices == 0)
Serial.println("No I2C devices found\n");
Serial.println("Scan for devices is complete.");
Serial.println("\n");
Serial.printf("GPS RX pin: %d", PIN_GPS_RX);
Serial.printf(" GPS TX pin: %d", PIN_GPS_TX);
Serial.println();
}
void TBeamBoard::printPMU()
{
Serial.print("isCharging:"); Serial.println(PMU->isCharging() ? "YES" : "NO");
Serial.print("isDischarge:"); Serial.println(PMU->isDischarge() ? "YES" : "NO");
Serial.print("isVbusIn:"); Serial.println(PMU->isVbusIn() ? "YES" : "NO");
Serial.print("getBattVoltage:"); Serial.print(PMU->getBattVoltage()); Serial.println("mV");
Serial.print("getVbusVoltage:"); Serial.print(PMU->getVbusVoltage()); Serial.println("mV");
Serial.print("getSystemVoltage:"); Serial.print(PMU->getSystemVoltage()); Serial.println("mV");
// The battery percentage may be inaccurate at first use, the PMU will automatically
// learn the battery curve and will automatically calibrate the battery percentage
// after a charge and discharge cycle
if (PMU->isBatteryConnect()) {
Serial.print("getBatteryPercent:"); Serial.print(PMU->getBatteryPercent()); Serial.println("%");
}
Serial.println();
}
#endif
bool TBeamBoard::power_init()
{
if (!PMU) {
#ifdef TBEAM_SUPREME_SX1262
PMU = new XPowersAXP2101(PMU_WIRE_PORT, PIN_BOARD_SDA1, PIN_BOARD_SCL1, I2C_PMU_ADD);
#else
PMU = new XPowersAXP2101(PMU_WIRE_PORT, PIN_BOARD_SDA, PIN_BOARD_SCL, I2C_PMU_ADD);
#endif
if (!PMU->init()) {
MESH_DEBUG_PRINTLN("Warning: Failed to find AXP2101 power management");
delete PMU;
PMU = NULL;
} else {
MESH_DEBUG_PRINTLN("AXP2101 PMU init succeeded, using AXP2101 PMU");
}
}
if (!PMU) {
PMU = new XPowersAXP192(PMU_WIRE_PORT, PIN_BOARD_SDA, PIN_BOARD_SCL, I2C_PMU_ADD);
if (!PMU->init()) {
MESH_DEBUG_PRINTLN("Warning: Failed to find AXP192 power management");
delete PMU;
PMU = NULL;
} else {
MESH_DEBUG_PRINTLN("AXP192 PMU init succeeded, using AXP192 PMU");
}
}
if (!PMU) {
return false;
}
deviceOnline |= POWERMANAGE_ONLINE;
PMU->setChargingLedMode(XPOWERS_CHG_LED_CTRL_CHG);
// Set up PMU interrupts
pinMode(PIN_PMU_IRQ, INPUT_PULLUP);
attachInterrupt(PIN_PMU_IRQ, setPmuFlag, FALLING);
if (PMU->getChipModel() == XPOWERS_AXP192) {
PMU->setPowerChannelVoltage(XPOWERS_LDO2, 3300); //Set up LoRa power rail
PMU->enablePowerOutput(XPOWERS_LDO2); //Enable the LoRa power rail
PMU->setPowerChannelVoltage(XPOWERS_DCDC1, 3300); //Set up OLED power rail
PMU->enablePowerOutput(XPOWERS_DCDC1); //Enable the OLED power rail
PMU->setPowerChannelVoltage(XPOWERS_LDO3, 3300); //Set up GPS power rail
PMU->enablePowerOutput(XPOWERS_LDO3); //Enable the GPS power rail
PMU->setProtectedChannel(XPOWERS_DCDC1); //Protect the OLED power rail
PMU->setProtectedChannel(XPOWERS_DCDC3); //Protect the ESP32 power rail
PMU->disablePowerOutput(XPOWERS_DCDC2); //Disable unsused power rail DC2
PMU->disableIRQ(XPOWERS_AXP192_ALL_IRQ); //Disable PMU IRQ
PMU->setChargerConstantCurr(XPOWERS_AXP192_CHG_CUR_450MA); //Set battery charging current
PMU->setChargeTargetVoltage(XPOWERS_AXP192_CHG_VOL_4V2); //Set battery charge-stop voltage
}
else if(PMU->getChipModel() == XPOWERS_AXP2101){
#ifdef TBEAM_SUPREME_SX1262
//Set up the GPS power rail
PMU->setPowerChannelVoltage(XPOWERS_ALDO4, 3300);
PMU->enablePowerOutput(XPOWERS_ALDO4);
//Set up the LoRa power rail
PMU->setPowerChannelVoltage(XPOWERS_ALDO3, 3300);
PMU->enablePowerOutput(XPOWERS_ALDO3);
//Set up power rail for the M.2 interface
PMU->setPowerChannelVoltage(XPOWERS_DCDC3, 3300);
PMU->enablePowerOutput(XPOWERS_DCDC3);
if (ESP_SLEEP_WAKEUP_UNDEFINED == esp_sleep_get_wakeup_cause()) {
MESH_DEBUG_PRINTLN("Power off and restart ALDO BLDO..");
PMU->disablePowerOutput(XPOWERS_ALDO1);
PMU->disablePowerOutput(XPOWERS_ALDO2);
PMU->disablePowerOutput(XPOWERS_BLDO1);
delay(250);
}
//Set up power rail for QMC6310U
PMU->setPowerChannelVoltage(XPOWERS_ALDO2, 3300);
PMU->enablePowerOutput(XPOWERS_ALDO2);
//Set up power rail for BME280 and OLED
PMU->setPowerChannelVoltage(XPOWERS_ALDO1, 3300);
PMU->enablePowerOutput(XPOWERS_ALDO1);
//Set up pwer rail for SD Card
PMU->setPowerChannelVoltage(XPOWERS_BLDO1, 3300);
PMU->enablePowerOutput(XPOWERS_BLDO1);
//Set up power rail BLDO2 to headers
PMU->setPowerChannelVoltage(XPOWERS_BLDO2, 3300);
PMU->enablePowerOutput(XPOWERS_BLDO2);
//Set up power rail DCDC4 to headers
PMU->setPowerChannelVoltage(XPOWERS_DCDC4, XPOWERS_AXP2101_DCDC4_VOL2_MAX);
PMU->enablePowerOutput(XPOWERS_DCDC4);
//Set up power rail DCDC5 to headers
PMU->setPowerChannelVoltage(XPOWERS_DCDC5, 3300);
PMU->enablePowerOutput(XPOWERS_DCDC5);
//Disable unused power rails
PMU->disablePowerOutput(XPOWERS_DCDC2);
PMU->disablePowerOutput(XPOWERS_DLDO1);
PMU->disablePowerOutput(XPOWERS_DLDO2);
PMU->disablePowerOutput(XPOWERS_VBACKUP);
#else
//Turn off unused power rails
PMU->disablePowerOutput(XPOWERS_DCDC2);
PMU->disablePowerOutput(XPOWERS_DCDC3);
PMU->disablePowerOutput(XPOWERS_DCDC4);
PMU->disablePowerOutput(XPOWERS_DCDC5);
PMU->disablePowerOutput(XPOWERS_ALDO1);
PMU->disablePowerOutput(XPOWERS_ALDO4);
PMU->disablePowerOutput(XPOWERS_BLDO1);
PMU->disablePowerOutput(XPOWERS_BLDO2);
PMU->disablePowerOutput(XPOWERS_DLDO1);
PMU->disablePowerOutput(XPOWERS_DLDO2);
//PMU->disablePowerOutput(XPOWERS_CPULDO);
PMU->setPowerChannelVoltage(XPOWERS_VBACKUP, 3300); //Set up GPS RTC power
PMU->enablePowerOutput(XPOWERS_VBACKUP); //Turn on GPS RTC power
PMU->setPowerChannelVoltage(XPOWERS_ALDO2, 3300); //Set up LoRa power rail
PMU->enablePowerOutput(XPOWERS_ALDO2); //Enable LoRa power rail
PMU->setPowerChannelVoltage(XPOWERS_ALDO3, 3300); //Set up GPS power rail
PMU->enablePowerOutput(XPOWERS_ALDO3); //Enable GPS power rail
#endif
PMU->disableIRQ(XPOWERS_AXP2101_ALL_IRQ); //Disable all PMU interrupts
PMU->setChargerConstantCurr(XPOWERS_AXP2101_CHG_CUR_500MA); //Set battery charging current to 500mA
PMU->setChargeTargetVoltage(XPOWERS_AXP2101_CHG_VOL_4V2); //Set battery charging cutoff voltage to 4.2V
}
PMU->clearIrqStatus(); //Clear interrupt flags
PMU->disableTSPinMeasure(); //Disable TS detection, since it is not used
//Enable voltage measurements
PMU->enableSystemVoltageMeasure();
PMU->enableVbusVoltageMeasure();
PMU->enableBattVoltageMeasure();
#ifdef MESH_DEBUG
scanDevices(&Wire);
printPMU();
#endif
// Set the power key off press time
PMU->setPowerKeyPressOffTime(XPOWERS_POWEROFF_4S);
return true;
}
#pragma region "Debug code"
// void TBeamBoard::radiotype_detect(){
// static SPIClass spi;
// char chipTypeInfo;
// #if defined(P_LORA_SCLK)
// spi.begin(P_LORA_SCLK, P_LORA_MISO, P_LORA_MOSI);
// #endif
// for(int i = 0; i<radioVersions; i++){
// switch(i){
// case 0:
// CustomSX1262 radio = new Module(P_LORA_NSS, P_LORA_DIO_0, P_LORA_RESET, P_LORA_DIO_1, spi);
// int status = radio.begin(LORA_FREQ, LORA_BW, LORA_SF, LORA_CR, RADIOLIB_SX126X_SYNC_WORD_PRIVATE, LORA_TX_POWER, 8);
// if (status != RADIOLIB_ERR_NONE) {
// Serial.print("ERROR: SX1262 not found: ");
// Serial.println(status);
// //delete radio;
// radio = NULL;
// break;
// }
// else{
// MESH_DEBUG_PRINTLN("SX1262 detected");
// P_LORA_BUSY = 32;
// RADIO_CLASS = CustomSX1262;
// WRAPPER_CLASS = CustomSX1262Wrapper;
// SX126X_RX_BOOSTED_GAIN = true;
// SX126X_CURRENT_LIMIT = 140;
// //delete radio;
// radio = NULL;
// break;
// }
// case 1:
// SX1276 radio = new Module(P_LORA_NSS, P_LORA_DIO_0, P_LORA_RESET, P_LORA_DIO_1, spi);
// int status1 = radio.begin(LORA_FREQ, LORA_BW, LORA_SF, LORA_CR, RADIOLIB_SX126X_SYNC_WORD_PRIVATE, LORA_TX_POWER, 8);
// if (status1 != RADIOLIB_ERR_NONE) {
// Serial.print("ERROR: SX1272 not found: ");
// Serial.println(status1);
// //delete radio;
// radio = NULL;
// }
// else{
// MESH_DEBUG_PRINTLN("SX1272 detected");
// P_LORA_BUSY = RADIOLIB_NC;
// P_LORA_DIO_2 = 32;
// RADIO_CLASS = CustomSX1272;
// WRAPPER_CLASS = CustomSX1272Wrapper;
// SX127X_CURRENT_LIMIT = 120;
// //delete radio;
// radio = NULL;
// return;
// }
// default:
// }
// }
// }
#pragma endregion
#endif
+168
View File
@@ -0,0 +1,168 @@
#pragma once
#if defined(TBEAM_SUPREME_SX1262) || defined(TBEAM_SX1262) || defined(TBEAM_SX1276)
#include <Wire.h>
#include <Arduino.h>
#include "XPowersLib.h"
#include "helpers/ESP32Board.h"
#include <driver/rtc_io.h>
//#include <RadioLib.h>
//#include <helpers/RadioLibWrappers.h>
//#include <helpers/CustomSX1262Wrapper.h>
//#include <helpers/CustomSX1276Wrapper.h>
#ifdef TBEAM_SUPREME_SX1262
// LoRa radio module pins for TBeam S3 Supreme SX1262
#define P_LORA_DIO_0 -1 //NC
#define P_LORA_DIO_1 1 //SX1262 IRQ pin
#define P_LORA_NSS 10 //SX1262 SS pin
#define P_LORA_RESET 5 //SX1262 Rest pin
#define P_LORA_BUSY 4 //SX1262 Busy pin
#define P_LORA_SCLK 12 //SX1262 SCLK pin
#define P_LORA_MISO 13 //SX1262 MISO pin
#define P_LORA_MOSI 11 //SX1262 MOSI pin
#define PIN_BOARD_SDA1 42 //SDA for PMU and PFC8563 (RTC)
#define PIN_BOARD_SCL1 41 //SCL for PMU and PFC8563 (RTC)
#define PIN_PMU_IRQ 40 //IRQ pin for PMU
// #define PIN_GPS_RX 9
// #define PIN_GPS_TX 8
// #define PIN_GPS_EN 7
#define P_BOARD_SPI_MOSI 35 //SPI for SD Card and QMI8653 (IMU)
#define P_BOARD_SPI_MISO 37 //SPI for SD Card and QMI8653 (IMU)
#define P_BOARD_SPI_SCK 36 //SPI for SD Card and QMI8653 (IMU)
#define P_BPARD_SPI_CS 47 //Pin for SD Card CS
#define P_BOARD_IMU_CS 34 //Pin for QMI8653 (IMU) CS
#define P_BOARD_IMU_INT 33 //IMU Int pin
#define P_BOARD_RTC_INT 14 //RTC Int pin
//I2C Wire addresses
#define I2C_BME280_ADD 0x76 //BME280 sensor I2C address on Wire
#define I2C_OLED_ADD 0x3C //SH1106 OLED I2C address on Wire
#define I2C_QMC6310U_ADD 0x1C //QMC6310U mag sensor I2C address on Wire
//I2C Wire1 addresses
#define I2C_RTC_ADD 0x51 //RTC I2C address on Wire1
#define I2C_PMU_ADD 0x34 //AXP2101 I2C address on Wire1
#define PMU_WIRE_PORT Wire1
#define RTC_WIRE_PORT Wire1
#endif
#ifdef TBEAM_SX1262
#define P_LORA_BUSY 32
#endif
#ifdef TBEAM_SX1276
#define P_LORA_DIO_2 32
#define P_LORA_BUSY RADIOLIB_NC
#endif
#if defined(TBEAM_SX1262) || defined(TBEAM_SX1276)
// LoRa radio module pins for TBeam
// uint32_t P_LORA_BUSY = 0; //shared, so define at run
// uint32_t P_LORA_DIO_2 = 0; //SX1276 only, so define at run
#define P_LORA_DIO_0 26
#define P_LORA_DIO_1 33
#define P_LORA_NSS 18
#define P_LORA_RESET 23
#define P_LORA_SCLK 5
#define P_LORA_MISO 19
#define P_LORA_MOSI 27
// #define PIN_GPS_RX 34
// #define PIN_GPS_TX 12
#define PIN_PMU_IRQ 35
#define PMU_WIRE_PORT Wire
#define RTC_WIRE_PORT Wire
#define I2C_PMU_ADD 0x34
#endif
// enum RadioType {
// SX1262,
// SX1276
// };
class TBeamBoard : public ESP32Board {
XPowersLibInterface *PMU = NULL;
//PhysicalLayer * pl;
//RadioType * radio = NULL;
// int radioVersions = 2;
enum {
POWERMANAGE_ONLINE = _BV(0),
DISPLAY_ONLINE = _BV(1),
RADIO_ONLINE = _BV(2),
GPS_ONLINE = _BV(3),
PSRAM_ONLINE = _BV(4),
SDCARD_ONLINE = _BV(5),
AXDL345_ONLINE = _BV(6),
BME280_ONLINE = _BV(7),
BMP280_ONLINE = _BV(8),
BME680_ONLINE = _BV(9),
QMC6310_ONLINE = _BV(10),
QMI8658_ONLINE = _BV(11),
PCF8563_ONLINE = _BV(12),
OSC32768_ONLINE = _BV(13),
};
bool power_init();
//void radiotype_detect();
public:
#ifdef MESH_DEBUG
void printPMU();
void scanDevices(TwoWire *w);
#endif
void begin();
#ifndef TBEAM_SUPREME_SX1262
void onBeforeTransmit() override{
digitalWrite(P_LORA_TX_LED, LOW); // turn TX LED on - invert pin for SX1276
}
void onAfterTransmit() override{
digitalWrite(P_LORA_TX_LED, HIGH); // turn TX LED off - invert pin for SX1276
}
#endif
void enterDeepSleep(uint32_t secs, int pin_wake_btn) {
esp_sleep_pd_config(ESP_PD_DOMAIN_RTC_PERIPH, ESP_PD_OPTION_ON);
// Make sure the DIO1 and NSS GPIOs are hold on required levels during deep sleep
rtc_gpio_set_direction((gpio_num_t)P_LORA_DIO_1, RTC_GPIO_MODE_INPUT_ONLY);
rtc_gpio_pulldown_en((gpio_num_t)P_LORA_DIO_1);
rtc_gpio_hold_en((gpio_num_t)P_LORA_NSS);
if (pin_wake_btn < 0) {
esp_sleep_enable_ext1_wakeup( (1L << P_LORA_DIO_1), ESP_EXT1_WAKEUP_ANY_HIGH); // wake up on: recv LoRa packet
} else {
esp_sleep_enable_ext1_wakeup( (1L << P_LORA_DIO_1) | (1L << pin_wake_btn), ESP_EXT1_WAKEUP_ANY_HIGH); // wake up on: recv LoRa packet OR wake btn
}
if (secs > 0) {
esp_sleep_enable_timer_wakeup(secs * 1000000);
}
// Finally set ESP32 into sleep
esp_deep_sleep_start(); // CPU halts here and never returns!
}
uint16_t getBattMilliVolts(){
return PMU->getBattVoltage();
}
const char* getManufacturerName() const{
return "LilyGo T-Beam";
}
};
#endif
+1 -1
View File
@@ -84,7 +84,7 @@ bool RAK4631Board::startOTAUpdate(const char* id, char reply[]) {
memset(mac_addr, 0, sizeof(mac_addr));
Bluefruit.getAddr(mac_addr);
sprintf(reply, "OK - mac: %02X:%02X:%02X:%02X:%02X:%02X",
mac_addr[0], mac_addr[1], mac_addr[2], mac_addr[3], mac_addr[4], mac_addr[5]);
mac_addr[5], mac_addr[4], mac_addr[3], mac_addr[2], mac_addr[1], mac_addr[0]);
return true;
}
+5
View File
@@ -26,6 +26,11 @@ void ThinkNodeM1Board::begin() {
Wire.begin();
#ifdef P_LORA_TX_LED
pinMode(P_LORA_TX_LED, OUTPUT);
digitalWrite(P_LORA_TX_LED, LOW);
#endif
pinMode(SX126X_POWER_EN, OUTPUT);
digitalWrite(SX126X_POWER_EN, HIGH);
delay(10); // give sx1262 some time to power up
+9
View File
@@ -39,6 +39,15 @@ public:
return startup_reason;
}
#if defined(P_LORA_TX_LED)
void onBeforeTransmit() override {
digitalWrite(P_LORA_TX_LED, HIGH); // turn TX LED on
}
void onAfterTransmit() override {
digitalWrite(P_LORA_TX_LED, LOW); // turn TX LED off
}
#endif
const char* getManufacturerName() const override {
return "Elecrow ThinkNode-M1";
}
+30
View File
@@ -0,0 +1,30 @@
#include "WaveshareBoard.h"
#include <Arduino.h>
#include <Wire.h>
void WaveshareBoard::begin() {
// for future use, sub-classes SHOULD call this from their begin()
startup_reason = BD_STARTUP_NORMAL;
#ifdef P_LORA_TX_LED
pinMode(P_LORA_TX_LED, OUTPUT);
#endif
#ifdef PIN_VBAT_READ
pinMode(PIN_VBAT_READ, INPUT);
#endif
#if defined(PIN_BOARD_SDA) && defined(PIN_BOARD_SCL)
Wire.setSDA(PIN_BOARD_SDA);
Wire.setSCL(PIN_BOARD_SCL);
#endif
Wire.begin();
delay(10); // give sx1262 some time to power up
}
bool WaveshareBoard::startOTAUpdate(const char *id, char reply[]) {
return false;
}
+73
View File
@@ -0,0 +1,73 @@
#pragma once
#include <Arduino.h>
#include <MeshCore.h>
// LoRa radio module pins for Waveshare RP2040-LoRa-HF/LF
// https://files.waveshare.com/wiki/RP2040-LoRa/Rp2040-lora-sch.pdf
#define P_LORA_DIO_1 16
#define P_LORA_NSS 13 // CS
#define P_LORA_RESET 23
#define P_LORA_BUSY 18
#define P_LORA_SCLK 14
#define P_LORA_MISO 24
#define P_LORA_MOSI 15
#define P_LORA_TX_LED 25
#define SX126X_DIO2_AS_RF_SWITCH true
#define SX126X_DIO3_TCXO_VOLTAGE 0
/*
* This board has no built-in way to read battery voltage.
* Nevertheless it's very easy to make it work, you only require two 1% resistors.
*
* BAT+ -----+
* |
* VSYS --+ -/\/\/\/\- --+
* 200k |
* +-- GPIO28
* |
* GND --+ -/\/\/\/\- --+
* | 100k
* BAT- -----+
*/
#define PIN_VBAT_READ 28
#define BATTERY_SAMPLES 8
#define ADC_MULTIPLIER (3.0f * 3.3f * 1000)
class WaveshareBoard : public mesh::MainBoard {
protected:
uint8_t startup_reason;
public:
void begin();
uint8_t getStartupReason() const override { return startup_reason; }
#ifdef P_LORA_TX_LED
void onBeforeTransmit() override { digitalWrite(P_LORA_TX_LED, HIGH); }
void onAfterTransmit() override { digitalWrite(P_LORA_TX_LED, LOW); }
#endif
uint16_t getBattMilliVolts() override {
#if defined(PIN_VBAT_READ) && defined(ADC_MULTIPLIER)
analogReadResolution(12);
uint32_t raw = 0;
for (int i = 0; i < BATTERY_SAMPLES; i++) {
raw += analogRead(PIN_VBAT_READ);
}
raw = raw / BATTERY_SAMPLES;
return (ADC_MULTIPLIER * raw) / 4096;
#else
return 0;
#endif
}
const char *getManufacturerName() const override { return "Waveshare RP2040-LoRa"; }
void reboot() override { rp2040.reboot(); }
bool startOTAUpdate(const char *id, char reply[]) override;
};
@@ -7,12 +7,24 @@ static Adafruit_AHTX0 AHTX0;
#endif
#if ENV_INCLUDE_BME280
#ifndef TELEM_BME280_ADDRESS
#define TELEM_BME280_ADDRESS 0x76 // BME280 environmental sensor I2C address
#endif
#define TELEM_BME280_SEALEVELPRESSURE_HPA (1013.25) // Athmospheric pressure at sea level
#include <Adafruit_BME280.h>
static Adafruit_BME280 BME280;
#endif
#if ENV_INCLUDE_BMP280
#ifndef TELEM_BMP280_ADDRESS
#define TELEM_BMP280_ADDRESS 0x76 // BMP280 environmental sensor I2C address
#endif
#define TELEM_BMP280_SEALEVELPRESSURE_HPA (1013.25) // Athmospheric pressure at sea level
#include <Adafruit_BMP280.h>
static Adafruit_BMP280 BMP280;
#endif
#if ENV_INCLUDE_INA3221
#define TELEM_INA3221_ADDRESS 0x42 // INA3221 3 channel current sensor I2C address
#define TELEM_INA3221_SHUNT_VALUE 0.100 // most variants will have a 0.1 ohm shunts
@@ -53,6 +65,17 @@ bool EnvironmentSensorManager::begin() {
}
#endif
#if ENV_INCLUDE_BMP280
if (BMP280.begin(TELEM_BMP280_ADDRESS)) {
MESH_DEBUG_PRINTLN("Found BMP280 at address: %02X", TELEM_BMP280_ADDRESS);
MESH_DEBUG_PRINTLN("BMP sensor ID: %02X", BMP280.sensorID());
BMP280_initialized = true;
} else {
BMP280_initialized = false;
MESH_DEBUG_PRINTLN("BMP280 was not found at I2C address %02X", TELEM_BMP280_ADDRESS);
}
#endif
#if ENV_INCLUDE_INA3221
if (INA3221.begin(TELEM_INA3221_ADDRESS, &Wire)) {
MESH_DEBUG_PRINTLN("Found INA3221 at address: %02X", TELEM_INA3221_ADDRESS);
@@ -84,7 +107,7 @@ bool EnvironmentSensorManager::begin() {
bool EnvironmentSensorManager::querySensors(uint8_t requester_permissions, CayenneLPP& telemetry) {
next_available_channel = TELEM_CHANNEL_SELF + 1;
if (requester_permissions & TELEM_PERM_LOCATION) {
if (requester_permissions & TELEM_PERM_LOCATION && gps_active) {
telemetry.addGPS(TELEM_CHANNEL_SELF, node_lat, node_lon, 0.0f); // allow lat/lon via telemetry even if no GPS is detected
}
@@ -95,7 +118,7 @@ bool EnvironmentSensorManager::querySensors(uint8_t requester_permissions, Cayen
sensors_event_t humidity, temp;
AHTX0.getEvent(&humidity, &temp);
telemetry.addTemperature(TELEM_CHANNEL_SELF, temp.temperature);
telemetry.addRelativeHumidity(TELEM_CHANNEL_SELF, humidity.relative_humidity);
telemetry.addRelativeHumidity(TELEM_CHANNEL_SELF, humidity.relative_humidity);
}
#endif
@@ -108,6 +131,14 @@ bool EnvironmentSensorManager::querySensors(uint8_t requester_permissions, Cayen
}
#endif
#if ENV_INCLUDE_BMP280
if (BMP280_initialized) {
telemetry.addTemperature(TELEM_CHANNEL_SELF, BMP280.readTemperature());
telemetry.addBarometricPressure(TELEM_CHANNEL_SELF, BMP280.readPressure());
telemetry.addAltitude(TELEM_CHANNEL_SELF, BME280.readAltitude(TELEM_BME280_SEALEVELPRESSURE_HPA));
}
#endif
#if ENV_INCLUDE_INA3221
if (INA3221_initialized) {
for(int i = 0; i < TELEM_INA3221_NUM_CHANNELS; i++) {
@@ -150,7 +181,7 @@ int EnvironmentSensorManager::getNumSettings() const {
const char* EnvironmentSensorManager::getSettingName(int i) const {
#if ENV_INCLUDE_GPS
return (gps_detected && i == 0) ? "gps" : NULL;
#else
#else
return NULL;
#endif
}
@@ -180,12 +211,24 @@ bool EnvironmentSensorManager::setSettingValue(const char* name, const char* val
#if ENV_INCLUDE_GPS
void EnvironmentSensorManager::initBasicGPS() {
Serial1.setPins(PIN_GPS_TX, PIN_GPS_RX);
#ifdef GPS_BAUD_RATE
Serial1.begin(GPS_BAUD_RATE);
#else
Serial1.begin(9600);
#endif
// Try to detect if GPS is physically connected to determine if we should expose the setting
pinMode(PIN_GPS_EN, OUTPUT);
digitalWrite(PIN_GPS_EN, HIGH); // Power on GPS
#ifdef PIN_GPS_EN
pinMode(PIN_GPS_EN, OUTPUT);
digitalWrite(PIN_GPS_EN, HIGH); // Power on GPS
#endif
#ifndef PIN_GPS_EN
MESH_DEBUG_PRINTLN("No GPS wake/reset pin found for this board. Continuing on...");
#endif
// Give GPS a moment to power up and send data
delay(1000);
@@ -195,23 +238,39 @@ void EnvironmentSensorManager::initBasicGPS() {
if (gps_detected) {
MESH_DEBUG_PRINTLN("GPS detected");
digitalWrite(PIN_GPS_EN, LOW); // Power off GPS until the setting is changed
#ifdef PERSISTANT_GPS
gps_active = true;
return;
#endif
} else {
MESH_DEBUG_PRINTLN("No GPS detected");
digitalWrite(PIN_GPS_EN, LOW);
}
#ifdef PIN_GPS_EN
digitalWrite(PIN_GPS_EN, LOW); // Power off GPS until the setting is changed
#endif
gps_active = false; //Set GPS visibility off until setting is changed
}
void EnvironmentSensorManager::start_gps() {
gps_active = true;
pinMode(PIN_GPS_EN, OUTPUT);
digitalWrite(PIN_GPS_EN, HIGH);
#ifdef PIN_GPS_EN
pinMode(PIN_GPS_EN, OUTPUT);
digitalWrite(PIN_GPS_EN, HIGH);
return;
#endif
MESH_DEBUG_PRINTLN("Start GPS is N/A on this board. Actual GPS state unchanged");
}
void EnvironmentSensorManager::stop_gps() {
gps_active = false;
pinMode(PIN_GPS_EN, OUTPUT);
digitalWrite(PIN_GPS_EN, LOW);
#ifdef PIN_GPS_EN
pinMode(PIN_GPS_EN, OUTPUT);
digitalWrite(PIN_GPS_EN, LOW);
return;
#endif
MESH_DEBUG_PRINTLN("Stop GPS is N/A on this board. Actual GPS state unchanged");
}
void EnvironmentSensorManager::loop() {
@@ -220,7 +279,7 @@ void EnvironmentSensorManager::loop() {
_location->loop();
if (millis() > next_gps_update) {
if (_location->isValid()) {
if (gps_active && _location->isValid()) {
node_lat = ((double)_location->getLatitude())/1000000.;
node_lon = ((double)_location->getLongitude())/1000000.;
MESH_DEBUG_PRINTLN("lat %f lon %f", node_lat, node_lon);
@@ -10,9 +10,10 @@ protected:
bool AHTX0_initialized = false;
bool BME280_initialized = false;
bool BMP280_initialized = false;
bool INA3221_initialized = false;
bool INA219_initialized = false;
bool gps_detected = false;
bool gps_active = false;
@@ -31,7 +32,7 @@ public:
EnvironmentSensorManager(){};
#endif
bool begin() override;
bool querySensors(uint8_t requester_permissions, CayenneLPP& telemetry) override;
bool querySensors(uint8_t requester_permissions, CayenneLPP& telemetry) override;
#if ENV_INCLUDE_GPS
void loop() override;
#endif
+17 -1
View File
@@ -8,7 +8,7 @@ protected:
uint8_t startup_reason;
public:
void begin() {
virtual void begin() {
startup_reason = BD_STARTUP_NORMAL;
}
@@ -23,7 +23,23 @@ public:
}
void reboot() override {
NVIC_SystemReset();
}
void powerOff() override {
HAL_PWREx_DisableInternalWakeUpLine();
__disable_irq();
HAL_PWREx_EnterSHUTDOWNMode();
}
#if defined(P_LORA_TX_LED)
void onBeforeTransmit() override {
digitalWrite(P_LORA_TX_LED, LOW); // turn TX LED on
}
void onAfterTransmit() override {
digitalWrite(P_LORA_TX_LED, HIGH); // turn TX LED off
}
#endif
bool startOTAUpdate(const char* id, char reply[]) override { return false; };
};
+15 -1
View File
@@ -32,7 +32,21 @@ bool ST7789Display::begin() {
}
void ST7789Display::turnOn() {
ST7789Display::begin();
if (!_isOn) {
// Restore power to the display but keep backlight off
digitalWrite(PIN_TFT_VDD_CTL, LOW);
digitalWrite(PIN_TFT_RST, HIGH);
// Re-initialize the display
display.init();
display.displayOn();
delay(20);
// Now turn on the backlight
digitalWrite(PIN_TFT_LEDA_CTL, LOW);
_isOn = true;
}
}
void ST7789Display::turnOff() {
+33
View File
@@ -0,0 +1,33 @@
#pragma once
#include <MeshCore.h>
#include <Arduino.h>
#if defined(ESP_PLATFORM)
#include <helpers/ESP32Board.h>
class Heltec_CT62_Board : public ESP32Board {
public:
uint16_t getBattMilliVolts() override {
#ifdef PIN_VBAT_READ
analogReadResolution(12); // ESP32-C3 ADC is 12-bit - 3.3/4096 (ref voltage/max counts)
uint32_t raw = 0;
for (int i = 0; i < 8; i++) {
raw += analogRead(PIN_VBAT_READ);
}
raw = raw / 8;
return ((6.52 * raw) / 1024.0) * 1000;
#else
return 0; // not supported
#endif
}
const char* getManufacturerName() const override {
return "Heltec CT62";
}
};
#endif
+88
View File
@@ -0,0 +1,88 @@
[Heltec_ct62]
extends = esp32_base
board = esp32-c3-devkitm-1
build_flags =
${esp32_base.build_flags}
-I variants/heltec_ct62
-D HELTEC_HT_CT62=1
-D RADIO_CLASS=CustomSX1262
-D WRAPPER_CLASS=CustomSX1262Wrapper
-D ESP32_CPU_FREQ=80
-D LORA_TX_POWER=22
-D P_LORA_TX_LED=18
-D PIN_BOARD_SDA=0
-D PIN_BOARD_SCL=1
;-D PIN_USER_BTN=9
-D PIN_VBAT_READ=2
-D P_LORA_DIO_1=3
-D P_LORA_NSS=8
-D P_LORA_RESET=5
-D P_LORA_DIO_0=RADIOLIB_NC
-D P_LORA_DIO_2=RADIOLIB_NC
-D P_LORA_BUSY=4
-D P_LORA_SCLK=10
-D P_LORA_MISO=6
-D P_LORA_MOSI=7
-D SX126X_DIO2_AS_RF_SWITCH=true
-D SX126X_DIO3_TCXO_VOLTAGE=1.8
-D SX126X_CURRENT_LIMIT=140
-D SX126X_RX_BOOSTED_GAIN=1
build_src_filter = ${esp32_base.build_src_filter}
+<../variants/heltec_ct62>
[env:Heltec_ct62_repeater]
extends = Heltec_ct62
build_flags =
${Heltec_ct62.build_flags}
;-D ARDUINO_USB_MODE=1
;-D ARDUINO_USB_CDC_ON_BOOT=1
-D ADVERT_NAME='"HT-CT62 Repeater"'
-D ADVERT_LAT=0.0
-D ADVERT_LON=0.0
-D ADMIN_PASSWORD='"password"'
-D MAX_NEIGHBOURS=8
; -D MESH_PACKET_LOGGING=1
; -D MESH_DEBUG=1
build_src_filter = ${Heltec_ct62.build_src_filter}
+<../examples/simple_repeater>
lib_deps =
${Heltec_ct62.lib_deps}
${esp32_ota.lib_deps}
[env:Heltec_ct62_companion_radio_usb]
extends = Heltec_ct62
build_flags =
${Heltec_ct62.build_flags}
; -D ARDUINO_USB_MODE=1
; -D ARDUINO_USB_CDC_ON_BOOT=1
-D MAX_CONTACTS=100
-D MAX_GROUP_CHANNELS=8
-D OFFLINE_QUEUE_SIZE=256
; -D MESH_PACKET_LOGGING=1
; -D MESH_DEBUG=1
build_src_filter = ${Heltec_ct62.build_src_filter}
+<../examples/companion_radio>
lib_deps =
${Heltec_ct62.lib_deps}
${esp32_ota.lib_deps}
densaugeo/base64 @ ~1.4.0
[env:Heltec_ct62_companion_radio_ble]
extends = Heltec_ct62
build_flags =
${Heltec_ct62.build_flags}
; -D ARDUINO_USB_MODE=1
; -D ARDUINO_USB_CDC_ON_BOOT=1
-D MAX_CONTACTS=100
-D MAX_GROUP_CHANNELS=8
-D OFFLINE_QUEUE_SIZE=256
-D BLE_PIN_CODE=123456
; -D MESH_PACKET_LOGGING=1
; -D MESH_DEBUG=1
build_src_filter = ${Heltec_ct62.build_src_filter}
+<../examples/companion_radio>
+<helpers/esp32/SerialBLEInterface.cpp>
lib_deps =
${Heltec_ct62.lib_deps}
${esp32_ota.lib_deps}
densaugeo/base64 @ ~1.4.0
+70
View File
@@ -0,0 +1,70 @@
#include <Arduino.h>
#include "target.h"
Heltec_CT62_Board board;
RADIO_CLASS radio = new Module(P_LORA_NSS, P_LORA_DIO_1, P_LORA_RESET, P_LORA_BUSY);
WRAPPER_CLASS radio_driver(radio, board);
ESP32RTCClock fallback_clock;
AutoDiscoverRTCClock rtc_clock(fallback_clock);
SensorManager sensors;
#ifndef LORA_CR
#define LORA_CR 5
#endif
bool radio_init() {
fallback_clock.begin();
rtc_clock.begin(Wire);
#ifdef SX126X_DIO3_TCXO_VOLTAGE
float tcxo = SX126X_DIO3_TCXO_VOLTAGE;
#else
float tcxo = 1.6f;
#endif
#if defined(P_LORA_SCLK)
SPI.begin(P_LORA_SCLK, P_LORA_MISO, P_LORA_MOSI);
#endif
int status = radio.begin(LORA_FREQ, LORA_BW, LORA_SF, LORA_CR, RADIOLIB_SX126X_SYNC_WORD_PRIVATE, LORA_TX_POWER, 8, tcxo);
if (status != RADIOLIB_ERR_NONE) {
Serial.print("ERROR: radio init failed: ");
Serial.println(status);
return false; // fail
}
radio.setCRC(1);
#ifdef SX126X_CURRENT_LIMIT
radio.setCurrentLimit(SX126X_CURRENT_LIMIT);
#endif
#ifdef SX126X_DIO2_AS_RF_SWITCH
radio.setDio2AsRfSwitch(SX126X_DIO2_AS_RF_SWITCH);
#endif
#ifdef SX126X_RX_BOOSTED_GAIN
radio.setRxBoostedGainMode(SX126X_RX_BOOSTED_GAIN);
#endif
return true; // success
}
uint32_t radio_get_rng_seed() {
return radio.random(0x7FFFFFFF);
}
void radio_set_params(float freq, float bw, uint8_t sf, uint8_t cr) {
radio.setFrequency(freq);
radio.setSpreadingFactor(sf);
radio.setBandwidth(bw);
radio.setCodingRate(cr);
}
void radio_set_tx_power(uint8_t dbm) {
radio.setOutputPower(dbm);
}
mesh::LocalIdentity radio_new_identity() {
RadioNoiseListener rng(radio);
return mesh::LocalIdentity(&rng); // create new random identity
}
+20
View File
@@ -0,0 +1,20 @@
#pragma once
#define RADIOLIB_STATIC_ONLY 1
#include <RadioLib.h>
#include <helpers/RadioLibWrappers.h>
#include "HT-CT62Board.h"
#include <helpers/CustomSX1262Wrapper.h>
#include <helpers/AutoDiscoverRTCClock.h>
#include <helpers/SensorManager.h>
extern Heltec_CT62_Board board;
extern WRAPPER_CLASS radio_driver;
extern AutoDiscoverRTCClock rtc_clock;
extern SensorManager sensors;
bool radio_init();
uint32_t radio_get_rng_seed();
void radio_set_params(float freq, float bw, uint8_t sf, uint8_t cr);
void radio_set_tx_power(uint8_t dbm);
mesh::LocalIdentity radio_new_identity();
+3 -19
View File
@@ -20,31 +20,15 @@ SensorManager sensors;
DISPLAY_CLASS display;
#endif
#ifndef LORA_CR
#define LORA_CR 5
#endif
bool radio_init() {
fallback_clock.begin();
rtc_clock.begin(Wire);
#if defined(P_LORA_SCLK)
spi.begin(P_LORA_SCLK, P_LORA_MISO, P_LORA_MOSI);
return radio.std_init(&spi);
#else
return radio.std_init();
#endif
int status = radio.begin(LORA_FREQ, LORA_BW, LORA_SF, LORA_CR, RADIOLIB_SX126X_SYNC_WORD_PRIVATE, LORA_TX_POWER, 8);
if (status != RADIOLIB_ERR_NONE) {
Serial.print("ERROR: radio init failed: ");
Serial.println(status);
return false; // fail
}
#ifdef SX127X_CURRENT_LIMIT
radio.setCurrentLimit(SX127X_CURRENT_LIMIT);
#endif
radio.setCRC(1);
return true; // success
}
uint32_t radio_get_rng_seed() {
+10 -3
View File
@@ -19,18 +19,25 @@ build_flags =
-D SX126X_RX_BOOSTED_GAIN=1
-D ENV_INCLUDE_AHTX0=1
-D ENV_INCLUDE_BME280=1
-D ENV_INCLUDE_BMP280=1
-D ENV_INCLUDE_INA3221=1
-D ENV_INCLUDE_INA219=1
-D ENV_INCLUDE_INA219=1
-D ENV_INCLUDE_GPS=1
-D PIN_GPS_RX=45
-D PIN_GPS_TX=46
-D PIN_GPS_EN=-1
build_src_filter = ${esp32_base.build_src_filter}
+<../variants/heltec_v3>
+<helpers/sensors>
+<helpers/sensors>
lib_deps =
${esp32_base.lib_deps}
adafruit/Adafruit SSD1306 @ ^2.5.13
adafruit/Adafruit INA3221 Library @ ^1.0.1
adafruit/Adafruit INA219 @ ^1.2.3
adafruit/Adafruit AHTX0 @ ^2.0.5
adafruit/Adafruit BME280 Library @ ^2.3.0
adafruit/Adafruit BME280 Library @ ^2.3.0
adafruit/Adafruit BMP280 Library@^2.6.8
stevemarple/MicroNMEA @ ^2.0.6
[env:Heltec_v3_repeater]
extends = Heltec_lora32_v3
+11 -32
View File
@@ -14,49 +14,28 @@ WRAPPER_CLASS radio_driver(radio, board);
ESP32RTCClock fallback_clock;
AutoDiscoverRTCClock rtc_clock(fallback_clock);
EnvironmentSensorManager sensors;
#if ENV_INCLUDE_GPS
#include <helpers/sensors/MicroNMEALocationProvider.h>
MicroNMEALocationProvider nmea = MicroNMEALocationProvider(Serial1);
EnvironmentSensorManager sensors = EnvironmentSensorManager(nmea);
#else
EnvironmentSensorManager sensors;
#endif
#ifdef DISPLAY_CLASS
DISPLAY_CLASS display;
#endif
#ifndef LORA_CR
#define LORA_CR 5
#endif
bool radio_init() {
fallback_clock.begin();
rtc_clock.begin(Wire);
#ifdef SX126X_DIO3_TCXO_VOLTAGE
float tcxo = SX126X_DIO3_TCXO_VOLTAGE;
#else
float tcxo = 1.6f;
#endif
#if defined(P_LORA_SCLK)
spi.begin(P_LORA_SCLK, P_LORA_MISO, P_LORA_MOSI);
return radio.std_init(&spi);
#else
return radio.std_init();
#endif
int status = radio.begin(LORA_FREQ, LORA_BW, LORA_SF, LORA_CR, RADIOLIB_SX126X_SYNC_WORD_PRIVATE, LORA_TX_POWER, 8, tcxo);
if (status != RADIOLIB_ERR_NONE) {
Serial.print("ERROR: radio init failed: ");
Serial.println(status);
return false; // fail
}
radio.setCRC(1);
#ifdef SX126X_CURRENT_LIMIT
radio.setCurrentLimit(SX126X_CURRENT_LIMIT);
#endif
#ifdef SX126X_DIO2_AS_RF_SWITCH
radio.setDio2AsRfSwitch(SX126X_DIO2_AS_RF_SWITCH);
#endif
#ifdef SX126X_RX_BOOSTED_GAIN
radio.setRxBoostedGainMode(SX126X_RX_BOOSTED_GAIN);
#endif
return true; // success
}
uint32_t radio_get_rng_seed() {
+121
View File
@@ -0,0 +1,121 @@
[LilyGo_T3S3_sx1276]
extends = esp32_base
board = t3_s3_v1_x
build_flags =
${esp32_base.build_flags}
-I variants/lilygo_t3s3_sx1276
-D LILYGO_T3S3
-D P_LORA_DIO_0=9
-D P_LORA_DIO_1=33
-D P_LORA_NSS=7
-D P_LORA_RESET=8
-D P_LORA_SCLK=5
-D P_LORA_MISO=3
-D P_LORA_MOSI=6
-D P_LORA_TX_LED=37
-D PIN_VBAT_READ=1
-D PIN_USER_BTN=0
-D PIN_BOARD_SDA=18
-D PIN_BOARD_SCL=17
-D PIN_OLED_RESET=21
-D RADIO_CLASS=CustomSX1276
-D WRAPPER_CLASS=CustomSX1276Wrapper
-D SX127X_CURRENT_LIMIT=120
-D SX176X_RXEN=21
-D SX176X_TXEN=10
-D LORA_TX_POWER=20
build_src_filter = ${esp32_base.build_src_filter}
+<../variants/lilygo_t3s3_sx1276>
lib_deps =
${esp32_base.lib_deps}
adafruit/Adafruit SSD1306 @ ^2.5.13
; === LilyGo T3S3 with SX1276 environments ===
[env:LilyGo_T3S3_sx1276_Repeater]
extends = LilyGo_T3S3_sx1276
build_flags =
${LilyGo_T3S3_sx1276.build_flags}
-D DISPLAY_CLASS=SSD1306Display
-D ADVERT_NAME='"T3S3-1276 Repeater"'
-D ADVERT_LAT=0.0
-D ADVERT_LON=0.0
-D ADMIN_PASSWORD='"password"'
-D MAX_NEIGHBOURS=8
; -D MESH_PACKET_LOGGING=1
; -D MESH_DEBUG=1
build_src_filter = ${LilyGo_T3S3_sx1276.build_src_filter}
+<helpers/ui/SSD1306Display.cpp>
+<../examples/simple_repeater>
lib_deps =
${LilyGo_T3S3_sx1276.lib_deps}
${esp32_ota.lib_deps}
[env:LilyGo_T3S3_sx1276_terminal_chat]
extends = LilyGo_T3S3_sx1276
build_flags =
${LilyGo_T3S3_sx1276.build_flags}
-D MAX_CONTACTS=100
-D MAX_GROUP_CHANNELS=1
; -D MESH_PACKET_LOGGING=1
; -D MESH_DEBUG=1
build_src_filter = ${LilyGo_T3S3_sx1276.build_src_filter}
+<../examples/simple_secure_chat/main.cpp>
lib_deps =
${LilyGo_T3S3_sx1276.lib_deps}
densaugeo/base64 @ ~1.4.0
[env:LilyGo_T3S3_sx1276_room_server]
extends = LilyGo_T3S3_sx1276
build_flags =
${LilyGo_T3S3_sx1276.build_flags}
-D DISPLAY_CLASS=SSD1306Display
-D ADVERT_NAME='"T3S3-1276 Room"'
-D ADVERT_LAT=0.0
-D ADVERT_LON=0.0
-D ADMIN_PASSWORD='"password"'
-D ROOM_PASSWORD='"hello"'
; -D MESH_PACKET_LOGGING=1
; -D MESH_DEBUG=1
build_src_filter = ${LilyGo_T3S3_sx1276.build_src_filter}
+<helpers/ui/SSD1306Display.cpp>
+<../examples/simple_room_server>
lib_deps =
${LilyGo_T3S3_sx1276.lib_deps}
${esp32_ota.lib_deps}
[env:LilyGo_T3S3_sx1276_companion_radio_usb]
extends = LilyGo_T3S3_sx1276
upload_speed = 115200
build_flags =
${LilyGo_T3S3_sx1276.build_flags}
-D DISPLAY_CLASS=SSD1306Display
-D MAX_CONTACTS=100
-D MAX_GROUP_CHANNELS=8
-D MESH_PACKET_LOGGING=1
-D MESH_DEBUG=1
build_src_filter = ${LilyGo_T3S3_sx1276.build_src_filter}
+<helpers/ui/SSD1306Display.cpp>
+<../examples/companion_radio>
lib_deps =
${LilyGo_T3S3_sx1276.lib_deps}
densaugeo/base64 @ ~1.4.0
[env:LilyGo_T3S3_sx1276_companion_radio_ble]
extends = LilyGo_T3S3_sx1276
build_flags =
${LilyGo_T3S3_sx1276.build_flags}
-D DISPLAY_CLASS=SSD1306Display
-D MAX_CONTACTS=100
-D MAX_GROUP_CHANNELS=8
-D BLE_PIN_CODE=123456
-D BLE_DEBUG_LOGGING=1
-D OFFLINE_QUEUE_SIZE=256
; -D MESH_PACKET_LOGGING=1
; -D MESH_DEBUG=1
build_src_filter = ${LilyGo_T3S3_sx1276.build_src_filter}
+<helpers/esp32/*.cpp>
+<helpers/ui/SSD1306Display.cpp>
+<../examples/companion_radio>
lib_deps =
${LilyGo_T3S3_sx1276.lib_deps}
densaugeo/base64 @ ~1.4.0
+53
View File
@@ -0,0 +1,53 @@
#include <Arduino.h>
#include "target.h"
ESP32Board board;
#if defined(P_LORA_SCLK)
static SPIClass spi;
RADIO_CLASS radio = new Module(P_LORA_NSS, P_LORA_DIO_0, P_LORA_RESET, P_LORA_DIO_1, spi);
#else
RADIO_CLASS radio = new Module(P_LORA_NSS, P_LORA_DIO_0, P_LORA_RESET, P_LORA_DIO_1);
#endif
WRAPPER_CLASS radio_driver(radio, board);
ESP32RTCClock fallback_clock;
AutoDiscoverRTCClock rtc_clock(fallback_clock);
SensorManager sensors;
#ifdef DISPLAY_CLASS
DISPLAY_CLASS display;
#endif
bool radio_init() {
fallback_clock.begin();
rtc_clock.begin(Wire);
#if defined(P_LORA_SCLK)
spi.begin(P_LORA_SCLK, P_LORA_MISO, P_LORA_MOSI);
return radio.std_init(&spi);
#else
return radio.std_init();
#endif
}
uint32_t radio_get_rng_seed() {
return radio.random(0x7FFFFFFF);
}
void radio_set_params(float freq, float bw, uint8_t sf, uint8_t cr) {
radio.setFrequency(freq);
radio.setSpreadingFactor(sf);
radio.setBandwidth(bw);
radio.setCodingRate(cr);
}
void radio_set_tx_power(uint8_t dbm) {
radio.setOutputPower(dbm);
}
mesh::LocalIdentity radio_new_identity() {
RadioNoiseListener rng(radio);
return mesh::LocalIdentity(&rng); // create new random identity
}
@@ -3,7 +3,7 @@
#define RADIOLIB_STATIC_ONLY 1
#include <RadioLib.h>
#include <helpers/RadioLibWrappers.h>
#include <helpers/TBeamBoard.h>
#include <helpers/ESP32Board.h>
#include <helpers/CustomSX1276Wrapper.h>
#include <helpers/AutoDiscoverRTCClock.h>
#include <helpers/SensorManager.h>
@@ -11,7 +11,7 @@
#include <helpers/ui/SSD1306Display.h>
#endif
extern TBeamBoard board;
extern ESP32Board board;
extern WRAPPER_CLASS radio_driver;
extern AutoDiscoverRTCClock rtc_clock;
extern SensorManager sensors;
@@ -24,4 +24,4 @@ bool radio_init();
uint32_t radio_get_rng_seed();
void radio_set_params(float freq, float bw, uint8_t sf, uint8_t cr);
void radio_set_tx_power(uint8_t dbm);
mesh::LocalIdentity radio_new_identity();
mesh::LocalIdentity radio_new_identity();
-203
View File
@@ -1,203 +0,0 @@
#include <Arduino.h>
#include "target.h"
TBeamBoard board;
// Using PMU AXP2102
#define PMU_WIRE_PORT Wire
bool pmuIntFlag = false;
static void setPMUIntFlag(){
pmuIntFlag = true;
}
#if defined(P_LORA_SCLK)
static SPIClass spi;
RADIO_CLASS radio = new Module(P_LORA_NSS, P_LORA_DIO_0, P_LORA_RESET, P_LORA_DIO_1, spi);
#else
RADIO_CLASS radio = new Module(P_LORA_NSS, P_LORA_DIO_0, P_LORA_RESET, P_LORA_DIO_1);
#endif
WRAPPER_CLASS radio_driver(radio, board);
ESP32RTCClock fallback_clock;
AutoDiscoverRTCClock rtc_clock(fallback_clock);
SensorManager sensors;
#ifdef DISPLAY_CLASS
DISPLAY_CLASS display;
#endif
#ifndef LORA_CR
#define LORA_CR 5
#endif
bool TBeamBoard::power_init()
{
if (!PMU)
{
PMU = new XPowersAXP2101(PMU_WIRE_PORT);
if (!PMU->init())
{
// Serial.println("Warning: Failed to find AXP2101 power management");
delete PMU;
PMU = NULL;
}
else
{
// Serial.println("AXP2101 PMU init succeeded, using AXP2101 PMU");
}
}
if (!PMU)
{
PMU = new XPowersAXP192(PMU_WIRE_PORT);
if (!PMU->init())
{
// Serial.println("Warning: Failed to find AXP192 power management");
delete PMU;
PMU = NULL;
}
else
{
// Serial.println("AXP192 PMU init succeeded, using AXP192 PMU");
}
}
if (!PMU)
{
MESH_DEBUG_PRINTLN("PMU init failed.");
return false;
}
// Serial.printf("PMU ID:0x%x\n", PMU->getChipID());
// printPMU();
if (PMU->getChipModel() == XPOWERS_AXP192)
{
// lora radio power channel
PMU->setPowerChannelVoltage(XPOWERS_LDO2, 3300);
PMU->enablePowerOutput(XPOWERS_LDO2);
// oled module power channel,
// disable it will cause abnormal communication between boot and AXP power supply,
// do not turn it off
PMU->setPowerChannelVoltage(XPOWERS_DCDC1, 3300);
// enable oled power
PMU->enablePowerOutput(XPOWERS_DCDC1);
// gnss module power channel
PMU->setPowerChannelVoltage(XPOWERS_LDO3, 3300);
// power->enablePowerOutput(XPOWERS_LDO3);
// protected oled power source
PMU->setProtectedChannel(XPOWERS_DCDC1);
// protected esp32 power source
PMU->setProtectedChannel(XPOWERS_DCDC3);
// disable not use channel
PMU->disablePowerOutput(XPOWERS_DCDC2);
// disable all axp chip interrupt
PMU->disableIRQ(XPOWERS_AXP192_ALL_IRQ);
PMU->setChargerConstantCurr(XPOWERS_AXP192_CHG_CUR_550MA);
}
else if (PMU->getChipModel() == XPOWERS_AXP2101)
{
// gnss module power channel
PMU->setPowerChannelVoltage(XPOWERS_ALDO4, 3300);
PMU->enablePowerOutput(XPOWERS_ALDO4);
// lora radio power channel
PMU->setPowerChannelVoltage(XPOWERS_ALDO3, 3300);
PMU->enablePowerOutput(XPOWERS_ALDO3);
// m.2 interface
PMU->setPowerChannelVoltage(XPOWERS_DCDC3, 3300);
PMU->enablePowerOutput(XPOWERS_DCDC3);
// power->setPowerChannelVoltage(XPOWERS_DCDC4, 3300);
// power->enablePowerOutput(XPOWERS_DCDC4);
// not use channel
PMU->disablePowerOutput(XPOWERS_DCDC2); // not elicited
PMU->disablePowerOutput(XPOWERS_DCDC5); // not elicited
PMU->disablePowerOutput(XPOWERS_DLDO1); // Invalid power channel, it does not exist
PMU->disablePowerOutput(XPOWERS_DLDO2); // Invalid power channel, it does not exist
PMU->disablePowerOutput(XPOWERS_VBACKUP);
// disable all axp chip interrupt
PMU->disableIRQ(XPOWERS_AXP2101_ALL_IRQ);
PMU->setChargerConstantCurr(XPOWERS_AXP2101_CHG_CUR_500MA);
// Set up PMU interrupts
// Serial.println("Setting up PMU interrupts");
pinMode(PIN_PMU_IRQ, INPUT_PULLUP);
attachInterrupt(PIN_PMU_IRQ, setPMUIntFlag, FALLING);
// Reset and re-enable PMU interrupts
// Serial.println("Re-enable interrupts");
PMU->disableIRQ(XPOWERS_AXP2101_ALL_IRQ);
PMU->clearIrqStatus();
PMU->enableIRQ(
XPOWERS_AXP2101_BAT_INSERT_IRQ | XPOWERS_AXP2101_BAT_REMOVE_IRQ | // Battery interrupts
XPOWERS_AXP2101_VBUS_INSERT_IRQ | XPOWERS_AXP2101_VBUS_REMOVE_IRQ | // VBUS interrupts
XPOWERS_AXP2101_PKEY_SHORT_IRQ | XPOWERS_AXP2101_PKEY_LONG_IRQ | // Power Key interrupts
XPOWERS_AXP2101_BAT_CHG_DONE_IRQ | XPOWERS_AXP2101_BAT_CHG_START_IRQ // Charging interrupts
);
}
return true;
}
bool radio_init() {
fallback_clock.begin();
rtc_clock.begin(Wire);
#if defined(P_LORA_SCLK)
spi.begin(P_LORA_SCLK, P_LORA_MISO, P_LORA_MOSI);
#endif
int status = radio.begin(LORA_FREQ, LORA_BW, LORA_SF, LORA_CR, RADIOLIB_SX126X_SYNC_WORD_PRIVATE, LORA_TX_POWER, 8);
if (status != RADIOLIB_ERR_NONE) {
Serial.print("ERROR: radio init failed: ");
Serial.println(status);
return false; // fail
}
#ifdef SX127X_CURRENT_LIMIT
radio.setCurrentLimit(SX127X_CURRENT_LIMIT);
#endif
radio.setCRC(1);
return true; // success
}
uint32_t radio_get_rng_seed() {
return radio.random(0x7FFFFFFF);
}
void radio_set_params(float freq, float bw, uint8_t sf, uint8_t cr) {
radio.setFrequency(freq);
radio.setSpreadingFactor(sf);
radio.setBandwidth(bw);
radio.setCodingRate(cr);
}
void radio_set_tx_power(uint8_t dbm) {
radio.setOutputPower(dbm);
}
mesh::LocalIdentity radio_new_identity() {
RadioNoiseListener rng(radio);
return mesh::LocalIdentity(&rng); // create new random identity
}
#ifdef MESH_DEBUG
void TBeamBoard::printPMU()
{
Serial.print("isCharging:"); Serial.println(PMU->isCharging() ? "YES" : "NO");
Serial.print("isDischarge:"); Serial.println(PMU->isDischarge() ? "YES" : "NO");
Serial.print("isVbusIn:"); Serial.println(PMU->isVbusIn() ? "YES" : "NO");
Serial.print("getBattVoltage:"); Serial.print(PMU->getBattVoltage()); Serial.println("mV");
Serial.print("getVbusVoltage:"); Serial.print(PMU->getVbusVoltage()); Serial.println("mV");
Serial.print("getSystemVoltage:"); Serial.print(PMU->getSystemVoltage()); Serial.println("mV");
// The battery percentage may be inaccurate at first use, the PMU will automatically
// learn the battery curve and will automatically calibrate the battery percentage
// after a charge and discharge cycle
if (PMU->isBatteryConnect()) {
Serial.print("getBatteryPercent:"); Serial.print(PMU->getBatteryPercent()); Serial.println("%");
}
Serial.println();
}
#endif
+9 -5
View File
@@ -4,32 +4,39 @@ board = ttgo-t-beam
build_flags =
${esp32_base.build_flags}
-I variants/lilygo_tbeam_SX1262
-D LILYGO_TBEAM_SX1262
-D TBEAM_SX1262
-D SX126X_DIO2_AS_RF_SWITCH=true
-D SX126X_DIO3_TCXO_VOLTAGE=1.8
-D SX126X_CURRENT_LIMIT=140
-D SX126X_RX_BOOSTED_GAIN=1
-D RADIO_CLASS=CustomSX1262
-D WRAPPER_CLASS=CustomSX1262Wrapper
-D DISPLAY_CLASS=SSD1306Display
-D LORA_TX_POWER=22
-D P_LORA_TX_LED=4
-D PIN_BOARD_SDA=21
-D PIN_BOARD_SCL=22
-D PIN_GPS_RX=12
-D PIN_GPS_TX=34
-D PIN_USER_BTN=38
-D ENV_INCLUDE_GPS=1
build_src_filter = ${esp32_base.build_src_filter}
+<../variants/lilygo_tbeam_SX1262>
+<helpers/ui/SSD1306Display.cpp>
+<helpers/esp32/TBeamBoard.cpp>
+<helpers/sensors>
board_build.partitions = min_spiffs.csv ; get around 4mb flash limit
lib_deps =
${esp32_base.lib_deps}
lewisxhe/XPowersLib@^0.2.7
adafruit/Adafruit SSD1306 @ ^2.5.13
stevemarple/MicroNMEA @ ^2.0.6
[env:Tbeam_SX1262_companion_radio_ble]
extends = LilyGo_TBeam_SX1262
board_build.upload.maximum_ram_size=2000000
build_flags =
${LilyGo_TBeam_SX1262.build_flags}
-D DISPLAY_CLASS=SSD1306Display
-D MAX_CONTACTS=100
-D MAX_GROUP_CHANNELS=8
-D BLE_PIN_CODE=123456
@@ -42,7 +49,6 @@ build_flags =
; -D MESH_DEBUG=1
build_src_filter = ${LilyGo_TBeam_SX1262.build_src_filter}
+<helpers/esp32/*.cpp>
+<helpers/ui/SSD1306Display.cpp>
+<../examples/companion_radio>
lib_deps =
${LilyGo_TBeam_SX1262.lib_deps}
@@ -52,7 +58,6 @@ lib_deps =
extends = LilyGo_TBeam_SX1262
build_flags =
${LilyGo_TBeam_SX1262.build_flags}
-D DISPLAY_CLASS=SSD1306Display
-D ADVERT_NAME='"Tbeam SX1262 Repeater"'
-D ADVERT_LAT=0.0
-D ADVERT_LON=0.0
@@ -61,7 +66,6 @@ build_flags =
; -D MESH_PACKET_LOGGING=1
; -D MESH_DEBUG=1
build_src_filter = ${LilyGo_TBeam_SX1262.build_src_filter}
+<helpers/ui/SSD1306Display.cpp>
+<../examples/simple_repeater>
lib_deps =
${LilyGo_TBeam_SX1262.lib_deps}
+10 -26
View File
@@ -1,7 +1,7 @@
#include <Arduino.h>
#include "target.h"
TBeamBoardSX1262 board;
TBeamBoard board;
#if defined(P_LORA_SCLK)
static SPIClass spi;
@@ -14,39 +14,23 @@ WRAPPER_CLASS radio_driver(radio, board);
ESP32RTCClock fallback_clock;
AutoDiscoverRTCClock rtc_clock(fallback_clock);
SensorManager sensors;
#if ENV_INCLUDE_GPS
#include <helpers/sensors/MicroNMEALocationProvider.h>
MicroNMEALocationProvider nmea = MicroNMEALocationProvider(Serial1);
EnvironmentSensorManager sensors = EnvironmentSensorManager(nmea);
#else
EnvironmentSensorManager sensors;
#endif
#ifdef DISPLAY_CLASS
DISPLAY_CLASS display;
#endif
#ifndef LORA_CR
#define LORA_CR 5
#endif
bool radio_init() {
fallback_clock.begin();
rtc_clock.begin(Wire);
#ifdef SX126X_DIO3_TCXO_VOLTAGE
float tcxo = SX126X_DIO3_TCXO_VOLTAGE;
#else
float tcxo = 1.6f;
#endif
#if defined(P_LORA_SCLK)
spi.begin(P_LORA_SCLK, P_LORA_MISO, P_LORA_MOSI);
#endif
int status = radio.begin(LORA_FREQ, LORA_BW, LORA_SF, LORA_CR, RADIOLIB_SX126X_SYNC_WORD_PRIVATE, LORA_TX_POWER, 8, tcxo);
if (status != RADIOLIB_ERR_NONE) {
Serial.print("ERROR: radio init failed: ");
Serial.println(status);
return false; // fail
}
radio.setCRC(1);
return true; // success
return radio.std_init(&spi);
}
uint32_t radio_get_rng_seed() {
+4 -4
View File
@@ -3,18 +3,18 @@
#define RADIOLIB_STATIC_ONLY 1
#include <RadioLib.h>
#include <helpers/RadioLibWrappers.h>
#include <helpers/TBeamBoardSX1262.h>
#include <helpers/esp32/TBeamBoard.h>
#include <helpers/CustomSX1262Wrapper.h>
#include <helpers/AutoDiscoverRTCClock.h>
#include <helpers/SensorManager.h>
#include <helpers/sensors/EnvironmentSensorManager.h>
#ifdef DISPLAY_CLASS
#include <helpers/ui/SSD1306Display.h>
#endif
extern TBeamBoardSX1262 board;
extern TBeamBoard board;
extern WRAPPER_CLASS radio_driver;
extern AutoDiscoverRTCClock rtc_clock;
extern SensorManager sensors;
extern EnvironmentSensorManager sensors;
#ifdef DISPLAY_CLASS
extern DISPLAY_CLASS display;
@@ -1,63 +1,70 @@
[LilyGo_TBeam]
[LilyGo_TBeam_SX1276]
extends = esp32_base
board = ttgo-t-beam
build_flags =
${esp32_base.build_flags}
-I variants/lilygo_tbeam
-D LILYGO_TBEAM
-I variants/lilygo_tbeam_SX1276
-D TBEAM_SX1276
-D SX127X_CURRENT_LIMIT=120
-D RADIO_CLASS=CustomSX1276
-D WRAPPER_CLASS=CustomSX1276Wrapper
-D SX127X_CURRENT_LIMIT=120
-D DISPLAY_CLASS=SSD1306Display
-D LORA_TX_POWER=20
-D P_LORA_TX_LED=4
-D PIN_BOARD_SDA=21
-D PIN_BOARD_SCL=22
-D PIN_GPS_RX=12
-D PIN_GPS_TX=34
-D PIN_USER_BTN=38
-D ENV_INCLUDE_GPS=1
;-D ENV_INCLUDE_BME680
build_src_filter = ${esp32_base.build_src_filter}
+<../variants/lilygo_tbeam>
+<../variants/lilygo_tbeam_SX1276>
+<helpers/ui/SSD1306Display.cpp>
+<helpers/esp32/TBeamBoard.cpp>
+<helpers/sensors>
board_build.partitions = min_spiffs.csv ; get around 4mb flash limit
lib_deps =
${esp32_base.lib_deps}
lewisxhe/XPowersLib@^0.2.7
adafruit/Adafruit SSD1306 @ ^2.5.13
stevemarple/MicroNMEA @ ^2.0.6
boschsensortec/BSEC Software Library @ ^1.8.1492
[env:Tbeam_companion_radio_ble]
extends = LilyGo_TBeam
[env:Tbeam_SX1276_companion_radio_ble]
extends = LilyGo_TBeam_SX1276
board_build.upload.maximum_ram_size=2000000
build_flags =
${LilyGo_TBeam.build_flags}
-D DISPLAY_CLASS=SSD1306Display
${LilyGo_TBeam_SX1276.build_flags}
-D MAX_CONTACTS=100
-D MAX_GROUP_CHANNELS=8
-D BLE_PIN_CODE=123456
-D BLE_DEBUG_LOGGING=1
; -D BLE_DEBUG_LOGGING=1
-D OFFLINE_QUEUE_SIZE=256
; -D RADIOLIB_DEBUG_BASIC=1
; -D MESH_PACKET_LOGGING=1
; -D MESH_DEBUG=1
build_src_filter = ${LilyGo_TBeam.build_src_filter}
build_src_filter = ${LilyGo_TBeam_SX1276.build_src_filter}
+<helpers/esp32/*.cpp>
+<helpers/ui/SSD1306Display.cpp>
+<../examples/companion_radio>
lib_deps =
${LilyGo_TBeam.lib_deps}
${LilyGo_TBeam_SX1276.lib_deps}
densaugeo/base64 @ ~1.4.0
[env:Tbeam_repeater]
extends = LilyGo_TBeam
[env:Tbeam_SX1276_repeater]
extends = LilyGo_TBeam_SX1276
build_flags =
${LilyGo_TBeam.build_flags}
-D DISPLAY_CLASS=SSD1306Display
${LilyGo_TBeam_SX1276.build_flags}
-D ADVERT_NAME='"Tbeam Repeater"'
-D ADVERT_LAT=0.0
-D ADVERT_LON=0.0
-D ADMIN_PASSWORD='"password"'
-D MAX_NEIGHBOURS=8
-D PERSISTANT_GPS=1
; -D MESH_PACKET_LOGGING=1
; -D MESH_DEBUG=1
build_src_filter = ${LilyGo_TBeam.build_src_filter}
+<helpers/ui/SSD1306Display.cpp>
build_src_filter = ${LilyGo_TBeam_SX1276.build_src_filter}
+<../examples/simple_repeater>
lib_deps =
${LilyGo_TBeam.lib_deps}
${LilyGo_TBeam_SX1276.lib_deps}
${esp32_ota.lib_deps}
+59
View File
@@ -0,0 +1,59 @@
#include <Arduino.h>
#include "target.h"
TBeamBoard board;
#if defined(P_LORA_SCLK)
static SPIClass spi;
RADIO_CLASS radio = new Module(P_LORA_NSS, P_LORA_DIO_0, P_LORA_RESET, P_LORA_DIO_1, spi);
#else
RADIO_CLASS radio = new Module(P_LORA_NSS, P_LORA_DIO_0, P_LORA_RESET, P_LORA_DIO_1);
#endif
WRAPPER_CLASS radio_driver(radio, board);
ESP32RTCClock fallback_clock;
AutoDiscoverRTCClock rtc_clock(fallback_clock);
#if ENV_INCLUDE_GPS
#include <helpers/sensors/MicroNMEALocationProvider.h>
MicroNMEALocationProvider nmea = MicroNMEALocationProvider(Serial1);
EnvironmentSensorManager sensors = EnvironmentSensorManager(nmea);
#else
EnvironmentSensorManager sensors;
#endif
#ifdef DISPLAY_CLASS
DISPLAY_CLASS display;
#endif
bool radio_init() {
fallback_clock.begin();
rtc_clock.begin(Wire);
#if defined(P_LORA_SCLK)
return radio.std_init(&spi);
#else
return radio.std_init();
#endif
}
uint32_t radio_get_rng_seed() {
return radio.random(0x7FFFFFFF);
}
void radio_set_params(float freq, float bw, uint8_t sf, uint8_t cr) {
radio.setFrequency(freq);
radio.setSpreadingFactor(sf);
radio.setBandwidth(bw);
radio.setCodingRate(cr);
}
void radio_set_tx_power(uint8_t dbm) {
radio.setOutputPower(dbm);
}
mesh::LocalIdentity radio_new_identity() {
RadioNoiseListener rng(radio);
return mesh::LocalIdentity(&rng); // create new random identity
}
+27
View File
@@ -0,0 +1,27 @@
#pragma once
#define RADIOLIB_STATIC_ONLY 1
//#include <RadioLib.h>
#include <helpers/RadioLibWrappers.h>
#include <helpers/esp32/TBeamBoard.h>
#include <helpers/CustomSX1276Wrapper.h>
#include <helpers/AutoDiscoverRTCClock.h>
#include <helpers/sensors/EnvironmentSensorManager.h>
#ifdef DISPLAY_CLASS
#include <helpers/ui/SSD1306Display.h>
#endif
extern TBeamBoard board;
extern WRAPPER_CLASS radio_driver;
extern AutoDiscoverRTCClock rtc_clock;
extern EnvironmentSensorManager sensors;
#ifdef DISPLAY_CLASS
extern DISPLAY_CLASS display;
#endif
bool radio_init();
uint32_t radio_get_rng_seed();
void radio_set_params(float freq, float bw, uint8_t sf, uint8_t cr);
void radio_set_tx_power(uint8_t dbm);
mesh::LocalIdentity radio_new_identity();
@@ -4,19 +4,28 @@ board = t_beams3_supreme ; LILYGO T-Beam Supreme ESP32S3 with SX1262
build_flags =
${esp32_base.build_flags}
-I variants/lilygo_tbeam_supreme_SX1262
-D TBEAM_SUPREME_SX1262
-D SX126X_CURRENT_LIMIT=140
-D SX126X_RX_BOOSTED_GAIN=1
-D RADIO_CLASS=CustomSX1262
-D WRAPPER_CLASS=CustomSX1262Wrapper
-D DISPLAY_CLASS=SH1106Display
-D LORA_TX_POWER=22
-D P_LORA_TX_LED=6
-D PIN_BOARD_SDA=17
-D PIN_BOARD_SCL=18
-D PIN_GPS_RX=8
-D PIN_GPS_TX=9
-D PIN_GPS_EN=7
-D PIN_USER_BTN=0
-D RADIO_CLASS=CustomSX1262
-D WRAPPER_CLASS=CustomSX1262Wrapper
-D DISPLAY_CLASS=SH1106Display
-D SX126X_RX_BOOSTED_GAIN=1
-D SX126X_CURRENT_LIMIT=140
-D TELEM_BME280_ADDRESS=0x77
-D ENV_INCLUDE_GPS=1
-D ENV_INCLUDE_BME280=1
build_src_filter = ${esp32_base.build_src_filter}
+<../variants/lilygo_tbeam_supreme_SX1262>
+<helpers/ui/SH1106Display.cpp>
+<helpers/esp32/TBeamBoard.cpp>
+<helpers/sensors>
board_build.partitions = min_spiffs.csv ; get around 4mb flash limit
lib_deps =
${esp32_base.lib_deps}
+10 -386
View File
@@ -1,292 +1,33 @@
#include <Arduino.h>
#include "target.h"
#include <helpers/sensors/MicroNMEALocationProvider.h>
TBeamS3SupremeBoard board;
TBeamBoard board;
#ifdef DISPLAY_CLASS
DISPLAY_CLASS display;
#endif
bool pmuIntFlag;
static SPIClass spi;
#ifndef LORA_CR
#define LORA_CR 5
#endif
#if defined(P_LORA_SCLK)
static SPIClass spi;
RADIO_CLASS radio = new Module(P_LORA_NSS, P_LORA_DIO_1, P_LORA_RESET, P_LORA_BUSY, spi);
#else
RADIO_CLASS radio = new Module(P_LORA_NSS, P_LORA_DIO_1, P_LORA_RESET, P_LORA_BUSY);
#endif
RADIO_CLASS radio = new Module(P_LORA_NSS, P_LORA_DIO_1, P_LORA_RESET, P_LORA_BUSY, spi);
WRAPPER_CLASS radio_driver(radio, board);
ESP32RTCClock fallback_clock;
AutoDiscoverRTCClock rtc_clock(fallback_clock);
MicroNMEALocationProvider nmea = MicroNMEALocationProvider(Serial1);
TbeamSupSensorManager sensors = TbeamSupSensorManager(nmea);
static void setPMUIntFlag(){
pmuIntFlag = true;
}
#ifdef MESH_DEBUG
uint32_t deviceOnline = 0x00;
void scanDevices(TwoWire *w)
{
uint8_t err, addr;
int nDevices = 0;
uint32_t start = 0;
Serial.println("Scanning I2C for Devices");
for (addr = 1; addr < 127; addr++) {
start = millis();
w->beginTransmission(addr); delay(2);
err = w->endTransmission();
if (err == 0) {
nDevices++;
switch (addr) {
case 0x77:
case 0x76:
Serial.println("\tFound BME280 Sensor");
deviceOnline |= BME280_ONLINE;
break;
case 0x34:
Serial.println("\tFound AXP192/AXP2101 PMU");
deviceOnline |= POWERMANAGE_ONLINE;
break;
case 0x3C:
Serial.println("\tFound SSD1306/SH1106 dispaly");
deviceOnline |= DISPLAY_ONLINE;
break;
case 0x51:
Serial.println("\tFound PCF8563 RTC");
deviceOnline |= PCF8563_ONLINE;
break;
case 0x1C:
Serial.println("\tFound QMC6310 MAG Sensor");
deviceOnline |= QMC6310_ONLINE;
break;
default:
Serial.print("\tI2C device found at address 0x");
if (addr < 16) {
Serial.print("0");
}
Serial.print(addr, HEX);
Serial.println(" !");
break;
}
} else if (err == 4) {
Serial.print("Unknow error at address 0x");
if (addr < 16) {
Serial.print("0");
}
Serial.println(addr, HEX);
}
}
if (nDevices == 0)
Serial.println("No I2C devices found\n");
Serial.println("Scan for devices is complete.");
Serial.println("\n");
}
void TBeamS3SupremeBoard::printPMU()
{
Serial.print("isCharging:"); Serial.println(PMU.isCharging() ? "YES" : "NO");
Serial.print("isDischarge:"); Serial.println(PMU.isDischarge() ? "YES" : "NO");
Serial.print("isVbusIn:"); Serial.println(PMU.isVbusIn() ? "YES" : "NO");
Serial.print("getBattVoltage:"); Serial.print(PMU.getBattVoltage()); Serial.println("mV");
Serial.print("getVbusVoltage:"); Serial.print(PMU.getVbusVoltage()); Serial.println("mV");
Serial.print("getSystemVoltage:"); Serial.print(PMU.getSystemVoltage()); Serial.println("mV");
// The battery percentage may be inaccurate at first use, the PMU will automatically
// learn the battery curve and will automatically calibrate the battery percentage
// after a charge and discharge cycle
if (PMU.isBatteryConnect()) {
Serial.print("getBatteryPercent:"); Serial.print(PMU.getBatteryPercent()); Serial.println("%");
}
Serial.println();
}
void TbeamSupSensorManager::printBMEValues() {
Serial.print("Temperature = ");
Serial.print(bme.readTemperature());
Serial.println(" *C");
Serial.print("Pressure = ");
Serial.print(bme.readPressure() / 100.0F);
Serial.println(" hPa");
Serial.print("Approx. Altitude = ");
Serial.print(bme.readAltitude(SEALEVELPRESSURE_HPA));
Serial.println(" m");
Serial.print("Humidity = ");
Serial.print(bme.readHumidity());
Serial.println(" %");
Serial.println();
}
#if ENV_INCLUDE_GPS
#include <helpers/sensors/MicroNMEALocationProvider.h>
MicroNMEALocationProvider nmea = MicroNMEALocationProvider(Serial1);
EnvironmentSensorManager sensors = EnvironmentSensorManager(nmea);
#else
EnvironmentSensorManager sensors;
#endif
bool TBeamS3SupremeBoard::power_init()
{
bool result = PMU.begin(PMU_WIRE_PORT, I2C_PMU_ADD, PIN_BOARD_SDA1, PIN_BOARD_SCL1);
if (result == false) {
MESH_DEBUG_PRINTLN("power is not online..."); while (1)delay(50);
}
MESH_DEBUG_PRINTLN("Setting charge led");
PMU.setChargingLedMode(XPOWERS_CHG_LED_CTRL_CHG);
// Set up PMU interrupts
MESH_DEBUG_PRINTLN("Setting up PMU interrupts");
pinMode(PIN_PMU_IRQ, INPUT_PULLUP);
attachInterrupt(PIN_PMU_IRQ, setPMUIntFlag, FALLING);
// GPS
MESH_DEBUG_PRINTLN("Setting and enabling a-ldo4 for GPS");
PMU.setALDO4Voltage(3300);
PMU.enableALDO4(); // disable to save power
// Lora
MESH_DEBUG_PRINTLN("Setting and enabling a-ldo3 for LoRa");
PMU.setALDO3Voltage(3300);
PMU.enableALDO3();
// To avoid SPI bus issues during power up, reset OLED, sensor, and SD card supplies
// MESH_DEBUG_PRINTLN("Reset a-ldo1&2 and b-ldo1");
// if (ESP_SLEEP_WAKEUP_UNDEFINED == esp_sleep_get_wakeup_cause())
// {
// PMU.disableALDO1();
// PMU.disableALDO2();
// PMU.disableBLDO1();
// delay(250);
// }
// m.2 interface
MESH_DEBUG_PRINTLN("Setting and enabling dcdc3 for m.2 interface");
PMU.setDC3Voltage(3300); // doesn't go anywhere in the schematic??
PMU.enableDC3();
// QMC6310U
MESH_DEBUG_PRINTLN("Setting and enabling a-ldo2 for QMC");
PMU.setALDO2Voltage(3300);
PMU.enableALDO2(); // disable to save power
// BME280 and OLED
MESH_DEBUG_PRINTLN("Setting and enabling a-ldo1 for oled");
PMU.setALDO1Voltage(3300);
PMU.enableALDO1();
// SD card
MESH_DEBUG_PRINTLN("Setting and enabling b-ldo2 for SD card");
PMU.setBLDO1Voltage(3300);
PMU.enableBLDO1();
// Out to header pins
MESH_DEBUG_PRINTLN("Setting and enabling b-ldo2 for output to header");
PMU.setBLDO2Voltage(3300);
PMU.enableBLDO2();
MESH_DEBUG_PRINTLN("Setting and enabling dcdc4 for output to header");
PMU.setDC4Voltage(XPOWERS_AXP2101_DCDC4_VOL2_MAX); // 1.8V
PMU.enableDC4();
MESH_DEBUG_PRINTLN("Setting and enabling dcdc5 for output to header");
PMU.setDC5Voltage(3300);
PMU.enableDC5();
// Unused power rails
MESH_DEBUG_PRINTLN("Disabling unused supplies dcdc2, dcdc5, dldo1 and dldo2");
PMU.disableDC2();
//PMU.disableDC5();
PMU.disableDLDO1();
PMU.disableDLDO2();
PMU.disableIRQ(XPOWERS_AXP2101_ALL_IRQ);
// Set charge current to 500mA
MESH_DEBUG_PRINTLN("Setting battery charge current limit and voltage");
PMU.setChargerConstantCurr(XPOWERS_AXP2101_CHG_CUR_500MA);
PMU.setChargeTargetVoltage(XPOWERS_AXP2101_CHG_VOL_4V2);
PMU.clearIrqStatus();
PMU.disableTSPinMeasure();
// enable battery voltage measurement
MESH_DEBUG_PRINTLN("Enabling battery measurement");
PMU.enableBattVoltageMeasure();
PMU.enableVbusVoltageMeasure();
// Reset and re-enable PMU interrupts
MESH_DEBUG_PRINTLN("Re-enable interrupts");
PMU.disableIRQ(XPOWERS_AXP2101_ALL_IRQ);
PMU.clearIrqStatus();
PMU.enableIRQ(
XPOWERS_AXP2101_BAT_INSERT_IRQ | XPOWERS_AXP2101_BAT_REMOVE_IRQ | // Battery interrupts
XPOWERS_AXP2101_VBUS_INSERT_IRQ | XPOWERS_AXP2101_VBUS_REMOVE_IRQ | // VBUS interrupts
XPOWERS_AXP2101_PKEY_SHORT_IRQ | XPOWERS_AXP2101_PKEY_LONG_IRQ | // Power Key interrupts
XPOWERS_AXP2101_BAT_CHG_DONE_IRQ | XPOWERS_AXP2101_BAT_CHG_START_IRQ // Charging interrupts
);
#ifdef MESH_DEBUG
scanDevices(&Wire);
scanDevices(&Wire1);
printPMU();
#endif
// Set the power key off press time
PMU.setPowerKeyPressOffTime(XPOWERS_POWEROFF_4S);
return true;
}
static bool readStringUntil(Stream& s, char dest[], size_t max_len, char term, unsigned int timeout_millis) {
unsigned long timeout = millis() + timeout_millis;
char *dp = dest;
while (millis() < timeout && dp - dest < max_len - 1) {
if (s.available()) {
char c = s.read();
if (c == term) break;
*dp++ = c; // append to dest[]
} else {
delay(1);
}
}
*dp = 0; // null terminator
return millis() < timeout; // false, if timed out
}
bool radio_init() {
fallback_clock.begin();
rtc_clock.begin(Wire1);
// #ifdef MESH_DEBUG
// printBMEValues();
// #endif
#ifdef SX126X_DIO3_TCXO_VOLTAGE
float tcxo = SX126X_DIO3_TCXO_VOLTAGE;
#else
float tcxo = 1.6f;
#endif
#if defined(P_LORA_SCLK)
spi.begin(P_LORA_SCLK, P_LORA_MISO, P_LORA_MOSI);
#endif
int status = radio.begin(LORA_FREQ, LORA_BW, LORA_SF, LORA_CR, RADIOLIB_SX126X_SYNC_WORD_PRIVATE, LORA_TX_POWER, 8, tcxo);
if (status != RADIOLIB_ERR_NONE) {
Serial.print("ERROR: radio init failed: ");
Serial.println(status);
return false; // fail
}
radio.setCRC(1);
return true; // success
return radio.std_init(&spi);
}
uint32_t radio_get_rng_seed() {
@@ -304,123 +45,6 @@ void radio_set_tx_power(uint8_t dbm) {
radio.setOutputPower(dbm);
}
void TbeamSupSensorManager::start_gps()
{
gps_active = true;
pinMode(P_GPS_WAKE, OUTPUT);
digitalWrite(P_GPS_WAKE, HIGH);
}
void TbeamSupSensorManager::sleep_gps() {
gps_active = false;
pinMode(P_GPS_WAKE, OUTPUT);
digitalWrite(P_GPS_WAKE, LOW);
}
bool TbeamSupSensorManager::begin() {
//init BME280
if (! bme.begin(0x77, &Wire)) {
MESH_DEBUG_PRINTLN("Could not find a valid BME280 sensor");
bme_active = false;
}
else
MESH_DEBUG_PRINTLN("BME280 found and init!");
bme_active = true;
// init GPS port
Serial1.begin(GPS_BAUD_RATE, SERIAL_8N1, P_GPS_RX, P_GPS_TX);
MESH_DEBUG_PRINTLN("Sleeping GPS for initial state");
sleep_gps();
return true;
}
bool TbeamSupSensorManager::querySensors(uint8_t requester_permissions, CayenneLPP& telemetry) {
if (requester_permissions & TELEM_PERM_LOCATION && gps_active) { // does requester have permission?
telemetry.addGPS(TELEM_CHANNEL_SELF, node_lat, node_lon, node_altitude);
}
if (requester_permissions & TELEM_PERM_ENVIRONMENT && bme_active) { // does requester have permission?
telemetry.addTemperature(TELEM_CHANNEL_SELF, node_temp);
telemetry.addRelativeHumidity(TELEM_CHANNEL_SELF, node_hum);
telemetry.addBarometricPressure(TELEM_CHANNEL_SELF, node_pres);
//telemetry.addAltitude(TELEM_CHANNEL_SELF, node_alt);
}
return true;
}
void TbeamSupSensorManager::loop() {
static long next_update = 0;
_nmea->loop();
if (millis() > next_update) {
if (_nmea->isValid() && gps_active) {
node_lat = ((double)_nmea->getLatitude())/1000000.;
node_lon = ((double)_nmea->getLongitude())/1000000.;
node_altitude = ((double)_nmea->getAltitude()) / 1000.0;
MESH_DEBUG_PRINT("lat %f lon %f alt %f\r\n", node_lat, node_lon, node_altitude);
}
//read BME280 values
if(bme_active){
//node_alt = bme.readAltitude(SEALEVELPRESSURE_HPA);
node_temp = bme.readTemperature();
node_hum = bme.readHumidity();
node_pres = (bme.readPressure() / 100.0F);
#ifdef MESH_DEBUG
// Serial.print("Temperature = ");
// Serial.print(node_temp);
// Serial.println(" *C");
// Serial.print("Humidity = ");
// Serial.print(node_hum);
// Serial.println(" %");
// Serial.print("Pressure = ");
// Serial.print(node_pres);
// Serial.println(" hPa");
// Serial.print("Approx. Altitude = ");
// Serial.print(node_alt);
// Serial.println(" m");
#endif
}
next_update = millis() + 1000;
}
}
int TbeamSupSensorManager::getNumSettings() const {
return 1;
}
const char* TbeamSupSensorManager::getSettingName(int i) const {
switch(i){
case 0: return "gps";
default: NULL;
}
}
const char* TbeamSupSensorManager::getSettingValue(int i) const {
switch(i){
case 0: return gps_active == true ? "1" : "0";
default: NULL;
}
}
bool TbeamSupSensorManager::setSettingValue(const char* name, const char* value) {
if (strcmp(name, "gps") == 0) {
if (strcmp(value, "0") == 0) {
sleep_gps();
} else {
start_gps();
}
return true;
}
return false; // not supported
}
mesh::LocalIdentity radio_new_identity() {
RadioNoiseListener rng(radio);
return mesh::LocalIdentity(&rng); // create new random identity
+6 -52
View File
@@ -3,66 +3,20 @@
#define RADIOLIB_STATIC_ONLY 1
#include <RadioLib.h>
#include <helpers/RadioLibWrappers.h>
#include <helpers/TBeamS3SupremeBoard.h>
#include <helpers/esp32/TBeamBoard.h>
#include <helpers/CustomSX1262Wrapper.h>
#include <helpers/AutoDiscoverRTCClock.h>
#include <helpers/SensorManager.h>
#include <helpers/sensors/LocationProvider.h>
#include <Adafruit_BME280.h>
class TbeamSupSensorManager: public SensorManager {
bool gps_active = false;
bool bme_active = false;
LocationProvider * _nmea;
Adafruit_BME280 bme;
double node_temp, node_hum, node_pres;
#define SEALEVELPRESSURE_HPA (1013.25)
void start_gps();
void sleep_gps();
public:
TbeamSupSensorManager(LocationProvider &nmea): _nmea(&nmea) {node_temp = 0; node_hum = 0; node_pres = 0;}
bool begin() override;
bool querySensors(uint8_t requester_permissions, CayenneLPP& telemetry) override;
void loop() override;
int getNumSettings() const override;
const char* getSettingName(int i) const override;
const char* getSettingValue(int i) const override;
bool setSettingValue(const char* name, const char* value) override;
#ifdef MESH_DEBUG
void printBMEValues();
#endif
};
extern TBeamS3SupremeBoard board;
extern WRAPPER_CLASS radio_driver;
extern AutoDiscoverRTCClock rtc_clock;
extern TbeamSupSensorManager sensors;
#include <helpers/sensors/EnvironmentSensorManager.h>
#ifdef DISPLAY_CLASS
#include <helpers/ui/SH1106Display.h>
extern DISPLAY_CLASS display;
#endif
enum {
POWERMANAGE_ONLINE = _BV(0),
DISPLAY_ONLINE = _BV(1),
RADIO_ONLINE = _BV(2),
GPS_ONLINE = _BV(3),
PSRAM_ONLINE = _BV(4),
SDCARD_ONLINE = _BV(5),
AXDL345_ONLINE = _BV(6),
BME280_ONLINE = _BV(7),
BMP280_ONLINE = _BV(8),
BME680_ONLINE = _BV(9),
QMC6310_ONLINE = _BV(10),
QMI8658_ONLINE = _BV(11),
PCF8563_ONLINE = _BV(12),
OSC32768_ONLINE = _BV(13),
};
extern TBeamBoard board;
extern WRAPPER_CLASS radio_driver;
extern AutoDiscoverRTCClock rtc_clock;
extern EnvironmentSensorManager sensors;
bool radio_init();
uint32_t radio_get_rng_seed();
+85
View File
@@ -0,0 +1,85 @@
[tlora_c6]
extends = esp32c6_base
board = esp32-c6-devkitm-1
board_build.partitions = min_spiffs.csv ; get around 4mb flash limit
build_flags =
${esp32c6_base.build_flags}
-I variants/lilygo_tlora_c6
-D ARDUINO_USB_CDC_ON_BOOT=1
-D ARDUINO_USB_MODE=1
-D P_LORA_TX_LED=7
-D P_LORA_SCLK=6
-D P_LORA_MISO=1
-D P_LORA_MOSI=0
-D P_LORA_NSS=18
-D P_LORA_DIO_1=23
-D P_LORA_BUSY=22
-D P_LORA_RESET=21
-D PIN_BOARD_SDA=8
-D PIN_BOARD_SCL=9
-D SX126X_RXEN=15
-D SX126X_TXEN=14
-D SX126X_DIO2_AS_RF_SWITCH=true
-D SX126X_DIO3_TCXO_VOLTAGE=1.8
-D SX126X_CURRENT_LIMIT=140
-D SX126X_RX_BOOSTED_GAIN=1
-D RADIO_CLASS=CustomSX1262
-D WRAPPER_CLASS=CustomSX1262Wrapper
-D LORA_TX_POWER=22
-D DISABLE_WIFI_OTA=1
build_src_filter = ${esp32c6_base.build_src_filter}
+<../variants/lilygo_tlora_c6>
[env:LilyGo_Tlora_C6_repeater]
extends = tlora_c6
build_src_filter = ${tlora_c6.build_src_filter}
+<../examples/simple_repeater/main.cpp>
build_flags =
${tlora_c6.build_flags}
-D ADVERT_NAME='"Tlora C6 Repeater"'
-D ADVERT_LAT=0.0
-D ADVERT_LON=0.0
-D ADMIN_PASSWORD='"password"'
-D MAX_NEIGHBOURS=8
; -D MESH_PACKET_LOGGING=1
; -D MESH_DEBUG=1
lib_deps =
${tlora_c6.lib_deps}
; ${esp32_ota.lib_deps}
[env:LilyGo_Tlora_C6_room_server]
extends = tlora_c6
build_src_filter = ${tlora_c6.build_src_filter}
+<../examples/simple_room_server>
build_flags =
${tlora_c6.build_flags}
-D ADVERT_NAME='"Tlora C6 Room"'
-D ADVERT_LAT=0.0
-D ADVERT_LON=0.0
-D ADMIN_PASSWORD='"password"'
-D ROOM_PASSWORD='"hello"'
; -D MESH_PACKET_LOGGING=1
; -D MESH_DEBUG=1
lib_deps =
${tlora_c6.lib_deps}
; ${esp32_ota.lib_deps}
[env:LilyGo_Tlora_C6_companion_radio_ble]
extends = tlora_c6
build_flags = ${tlora_c6.build_flags}
-D MAX_CONTACTS=100
-D MAX_GROUP_CHANNELS=8
-D BLE_PIN_CODE=123456
-D BLE_DEBUG_LOGGING=1
-D OFFLINE_QUEUE_SIZE=256
-D ENABLE_PRIVATE_KEY_IMPORT=1
-D ENABLE_PRIVATE_KEY_EXPORT=1
; -D MESH_PACKET_LOGGING=1
; -D MESH_DEBUG=1
build_src_filter = ${tlora_c6.build_src_filter}
+<helpers/esp32/*.cpp>
-<helpers/esp32/ESPNOWRadio.cpp>
+<../examples/companion_radio>
lib_deps =
${tlora_c6.lib_deps}
densaugeo/base64 @ ~1.4.0
+82
View File
@@ -0,0 +1,82 @@
#include <Arduino.h>
#include "target.h"
ESP32Board board;
#if defined(P_LORA_SCLK)
static SPIClass spi(0);
RADIO_CLASS radio = new Module(P_LORA_NSS, P_LORA_DIO_1, P_LORA_RESET, P_LORA_BUSY, spi);
#else
RADIO_CLASS radio = new Module(P_LORA_NSS, P_LORA_DIO_1, P_LORA_RESET, P_LORA_BUSY);
#endif
WRAPPER_CLASS radio_driver(radio, board);
ESP32RTCClock fallback_clock;
AutoDiscoverRTCClock rtc_clock(fallback_clock);
SensorManager sensors;
#ifndef LORA_CR
#define LORA_CR 5
#endif
bool radio_init() {
fallback_clock.begin();
rtc_clock.begin(Wire);
#ifdef SX126X_DIO3_TCXO_VOLTAGE
float tcxo = SX126X_DIO3_TCXO_VOLTAGE;
#else
float tcxo = 1.6f;
#endif
#if defined(P_LORA_SCLK)
spi.begin(P_LORA_SCLK, P_LORA_MISO, P_LORA_MOSI);
#endif
int status = radio.begin(LORA_FREQ, LORA_BW, LORA_SF, LORA_CR, RADIOLIB_SX126X_SYNC_WORD_PRIVATE, LORA_TX_POWER, 8, tcxo);
if (status != RADIOLIB_ERR_NONE) {
Serial.print("ERROR: radio init failed: ");
Serial.println(status);
return false; // fail
}
radio.setCRC(1);
#if defined(SX126X_RXEN) && defined(SX126X_TXEN)
radio.setRfSwitchPins(SX126X_RXEN, SX126X_TXEN);
#endif
#ifdef SX126X_CURRENT_LIMIT
radio.setCurrentLimit(SX126X_CURRENT_LIMIT);
#endif
#ifdef SX126X_DIO2_AS_RF_SWITCH
radio.setDio2AsRfSwitch(SX126X_DIO2_AS_RF_SWITCH);
#endif
#ifdef SX126X_RX_BOOSTED_GAIN
radio.setRxBoostedGainMode(SX126X_RX_BOOSTED_GAIN);
#endif
return true; // success
}
uint32_t radio_get_rng_seed() {
return radio.random(0x7FFFFFFF);
}
void radio_set_params(float freq, float bw, uint8_t sf, uint8_t cr) {
radio.setFrequency(freq);
radio.setSpreadingFactor(sf);
radio.setBandwidth(bw);
radio.setCodingRate(cr);
}
void radio_set_tx_power(uint8_t dbm) {
radio.setOutputPower(dbm);
}
mesh::LocalIdentity radio_new_identity() {
RadioNoiseListener rng(radio);
return mesh::LocalIdentity(&rng); // create new random identity
}
+20
View File
@@ -0,0 +1,20 @@
#pragma once
#define RADIOLIB_STATIC_ONLY 1
#include <RadioLib.h>
#include <helpers/RadioLibWrappers.h>
#include <helpers/ESP32Board.h>
#include <helpers/CustomSX1262Wrapper.h>
#include <helpers/AutoDiscoverRTCClock.h>
#include <helpers/SensorManager.h>
extern ESP32Board board;
extern WRAPPER_CLASS radio_driver;
extern AutoDiscoverRTCClock rtc_clock;
extern SensorManager sensors;
bool radio_init();
uint32_t radio_get_rng_seed();
void radio_set_params(float freq, float bw, uint8_t sf, uint8_t cr);
void radio_set_tx_power(uint8_t dbm);
mesh::LocalIdentity radio_new_identity();
+13
View File
@@ -17,6 +17,8 @@ build_flags =
-D P_LORA_MISO=19 ; SPI MISO
-D P_LORA_MOSI=27 ; SPI MOSI
-D P_LORA_TX_LED=2 ; LED pin for TX indication
-D PIN_BOARD_SDA=21
-D PIN_BOARD_SCL=22
-D PIN_VBAT_READ=35 ; Battery voltage reading (analog pin)
-D PIN_USER_BTN=0
-D ARDUINO_LOOP_STACK_SIZE=16384
@@ -25,11 +27,22 @@ build_flags =
-D WRAPPER_CLASS=CustomSX1276Wrapper
-D SX127X_CURRENT_LIMIT=120
-D LORA_TX_POWER=20
-D ENV_INCLUDE_AHTX0=1
-D ENV_INCLUDE_BME280=1
-D ENV_INCLUDE_BMP280=1
-D ENV_INCLUDE_INA3221=1
-D ENV_INCLUDE_INA219=1
build_src_filter = ${esp32_base.build_src_filter}
+<../variants/lilygo_tlora_v2_1>
+<helpers/sensors>
lib_deps =
${esp32_base.lib_deps}
adafruit/Adafruit SSD1306 @ ^2.5.13
adafruit/Adafruit INA3221 Library @ ^1.0.1
adafruit/Adafruit INA219 @ ^1.2.3
adafruit/Adafruit AHTX0 @ ^2.0.5
adafruit/Adafruit BME280 Library @ ^2.3.0
adafruit/Adafruit BMP280 Library @ ^2.6.8
; === LILYGO T-LoRa V2.1-1.6 with SX1276 environments ===
[env:LilyGo_TLora_V2_1_1_6_Repeater]
+5 -19
View File
@@ -10,35 +10,21 @@ WRAPPER_CLASS radio_driver(radio, board);
ESP32RTCClock fallback_clock;
AutoDiscoverRTCClock rtc_clock(fallback_clock);
SensorManager sensors;
EnvironmentSensorManager sensors;
#ifdef DISPLAY_CLASS
DISPLAY_CLASS display;
#endif
#ifndef LORA_CR
#define LORA_CR 5
#endif
bool radio_init() {
fallback_clock.begin();
rtc_clock.begin(Wire);
spi.begin(P_LORA_SCLK, P_LORA_MISO, P_LORA_MOSI);
int status = radio.begin(LORA_FREQ, LORA_BW, LORA_SF, LORA_CR, RADIOLIB_SX126X_SYNC_WORD_PRIVATE, LORA_TX_POWER, 8);
if (status != RADIOLIB_ERR_NONE) {
Serial.print("ERROR: radio init failed: ");
Serial.println(status);
return false; // fail
}
#ifdef SX127X_CURRENT_LIMIT
radio.setCurrentLimit(SX127X_CURRENT_LIMIT);
#if defined(P_LORA_SCLK)
return radio.std_init(&spi);
#else
return radio.std_init();
#endif
radio.setCRC(1);
return true; // success
}
uint32_t radio_get_rng_seed() {
+2 -1
View File
@@ -7,6 +7,7 @@
#include <helpers/CustomSX1276Wrapper.h>
#include <helpers/AutoDiscoverRTCClock.h>
#include <helpers/SensorManager.h>
#include <helpers/sensors/EnvironmentSensorManager.h>
#ifdef DISPLAY_CLASS
#include <helpers/ui/SSD1306Display.h>
#endif
@@ -14,7 +15,7 @@
extern LilyGoTLoraBoard board;
extern WRAPPER_CLASS radio_driver;
extern AutoDiscoverRTCClock rtc_clock;
extern SensorManager sensors;
extern EnvironmentSensorManager sensors;
#ifdef DISPLAY_CLASS
extern DISPLAY_CLASS display;
+1 -1
View File
@@ -68,7 +68,7 @@ bool NanoG2Ultra::startOTAUpdate(const char *id, char reply[])
// Set max power. Accepted values are: -40, -30, -20, -16, -12, -8, -4, 0, 4
Bluefruit.setTxPower(4);
// Set the BLE device name
Bluefruit.setName("TECHO_OTA");
Bluefruit.setName("NANO_G2_OTA");
Bluefruit.Periph.setConnectCallback(connect_callback);
Bluefruit.Periph.setDisconnectCallback(disconnect_callback);
+1 -34
View File
@@ -18,43 +18,10 @@ NanoG2UltraSensorManager sensors = NanoG2UltraSensorManager(nmea);
DISPLAY_CLASS display;
#endif
#ifndef LORA_CR
#define LORA_CR 5
#endif
bool radio_init()
{
rtc_clock.begin(Wire);
#ifdef SX126X_DIO3_TCXO_VOLTAGE
float tcxo = SX126X_DIO3_TCXO_VOLTAGE;
#else
float tcxo = 1.6f;
#endif
SPI.setPins(P_LORA_MISO, P_LORA_SCLK, P_LORA_MOSI);
SPI.begin();
int status = radio.begin(LORA_FREQ, LORA_BW, LORA_SF, LORA_CR, RADIOLIB_SX126X_SYNC_WORD_PRIVATE, LORA_TX_POWER, 8, tcxo);
if (status != RADIOLIB_ERR_NONE)
{
Serial.print("ERROR: radio init failed: ");
Serial.println(status);
return false; // fail
}
radio.setCRC(1);
#ifdef SX126X_CURRENT_LIMIT
radio.setCurrentLimit(SX126X_CURRENT_LIMIT);
#endif
#ifdef SX126X_DIO2_AS_RF_SWITCH
radio.setDio2AsRfSwitch(SX126X_DIO2_AS_RF_SWITCH);
#endif
#ifdef SX126X_RX_BOOSTED_GAIN
radio.setRxBoostedGainMode(SX126X_RX_BOOSTED_GAIN);
#endif
return true; // success
return radio.std_init(&SPI);
}
uint32_t radio_get_rng_seed()
+1 -1
View File
@@ -14,7 +14,7 @@ build_flags = ${rp2040_base.build_flags}
-D LORA_TX_POWER=22
-D SX126X_RX_BOOSTED_GAIN=1
build_src_filter = ${rp2040_base.build_src_filter}
+<helpers/rp2040/*.cpp>
+<helpers/rp2040/PicoWBoard.cpp>
+<../variants/picow>
lib_deps = ${rp2040_base.lib_deps}
+1 -36
View File
@@ -12,45 +12,10 @@ VolatileRTCClock fallback_clock;
AutoDiscoverRTCClock rtc_clock(fallback_clock);
SensorManager sensors;
#ifndef LORA_CR
#define LORA_CR 5
#endif
bool radio_init() {
rtc_clock.begin(Wire);
#ifdef SX126X_DIO3_TCXO_VOLTAGE
float tcxo = SX126X_DIO3_TCXO_VOLTAGE;
#else
float tcxo = 1.6f;
#endif
SPI1.setMISO(P_LORA_MISO);
//SPI1.setCS(P_LORA_NSS); // Setting CS results in freeze
SPI1.setSCK(P_LORA_SCLK);
SPI1.setMOSI(P_LORA_MOSI);
SPI1.begin();
int status = radio.begin(LORA_FREQ, LORA_BW, LORA_SF, LORA_CR, RADIOLIB_SX126X_SYNC_WORD_PRIVATE, LORA_TX_POWER, 8, tcxo);
if (status != RADIOLIB_ERR_NONE) {
Serial.print("ERROR: radio init failed: ");
Serial.println(status);
return false; // fail
}
radio.setCRC(1);
#ifdef SX126X_CURRENT_LIMIT
radio.setCurrentLimit(SX126X_CURRENT_LIMIT);
#endif
#ifdef SX126X_DIO2_AS_RF_SWITCH
radio.setDio2AsRfSwitch(SX126X_DIO2_AS_RF_SWITCH);
#endif
#ifdef SX126X_RX_BOOSTED_GAIN
radio.setRxBoostedGainMode(SX126X_RX_BOOSTED_GAIN);
#endif
return true; // success
return radio.std_init(&SPI1);
}
uint32_t radio_get_rng_seed() {
+15 -13
View File
@@ -1,7 +1,7 @@
[Faketec]
extends = nrf52840_base
extends = nrf52_base
board = promicro_nrf52840
build_flags = ${nrf52840_base.build_flags}
build_flags = ${nrf52_base.build_flags}
-I variants/promicro
-D FAKETEC
-D RADIO_CLASS=CustomSX1262
@@ -19,20 +19,22 @@ build_flags = ${nrf52840_base.build_flags}
-D ENV_INCLUDE_GPS=1
-D ENV_INCLUDE_AHTX0=1
-D ENV_INCLUDE_BME280=1
-D ENV_INCLUDE_BMP280=1
-D ENV_INCLUDE_INA3221=1
-D ENV_INCLUDE_INA219=1
build_src_filter = ${nrf52840_base.build_src_filter}
build_src_filter = ${nrf52_base.build_src_filter}
+<helpers/nrf52/PromicroBoard.cpp>
+<helpers/sensors>
+<helpers/sensors>
+<../variants/promicro>
lib_deps= ${nrf52840_base.lib_deps}
lib_deps= ${nrf52_base.lib_deps}
adafruit/Adafruit SSD1306 @ ^2.5.13
adafruit/Adafruit INA3221 Library @ ^1.0.1
adafruit/Adafruit INA219 @ ^1.2.3
adafruit/Adafruit AHTX0 @ ^2.0.5
adafruit/Adafruit BME280 Library @ ^2.3.0
adafruit/Adafruit BME280 Library @ ^2.3.0
adafruit/Adafruit BMP280 Library@^2.6.8
stevemarple/MicroNMEA @ ^2.0.6
[env:Faketec_Repeater]
extends = Faketec
build_src_filter = ${Faketec.build_src_filter}
@@ -116,9 +118,9 @@ lib_deps = ${Faketec.lib_deps}
densaugeo/base64 @ ~1.4.0
[ProMicroLLCC68]
extends = nrf52840_base
extends = nrf52_base
board = promicro_nrf52840
build_flags = ${nrf52840_base.build_flags}
build_flags = ${nrf52_base.build_flags}
-I variants/promicro
-D PROMICROLLCC68
-D RADIO_CLASS=CustomLLCC68
@@ -127,15 +129,15 @@ build_flags = ${nrf52840_base.build_flags}
-D SX126X_CURRENT_LIMIT=140
-D SX126X_RX_BOOSTED_GAIN=1
build_src_filter =
${nrf52840_base.build_src_filter}
${nrf52_base.build_src_filter}
+<helpers/nrf52/PromicroBoard.cpp>
+<helpers/sensors>
+<helpers/sensors>
+<../variants/promicro>
lib_deps= ${nrf52840_base.lib_deps}
lib_deps= ${nrf52_base.lib_deps}
adafruit/Adafruit INA3221 Library @ ^1.0.1
adafruit/Adafruit INA219 @ ^1.2.3
adafruit/Adafruit AHTX0 @ ^2.0.5
adafruit/Adafruit BME280 Library @ ^2.3.0
adafruit/Adafruit BME280 Library @ ^2.3.0
[env:ProMicroLLCC68_Repeater]
extends = ProMicroLLCC68
+1 -41
View File
@@ -2,9 +2,6 @@
#include "target.h"
#include <helpers/ArduinoHelpers.h>
#if ENV_INCLUDE_GPS
#endif
PromicroBoard board;
RADIO_CLASS radio = new Module(P_LORA_NSS, P_LORA_DIO_1, P_LORA_RESET, P_LORA_BUSY, SPI);
@@ -25,47 +22,10 @@ AutoDiscoverRTCClock rtc_clock(fallback_clock);
DISPLAY_CLASS display;
#endif
#ifndef LORA_CR
#define LORA_CR 5
#endif
bool radio_init() {
rtc_clock.begin(Wire);
#ifdef SX126X_DIO3_TCXO_VOLTAGE
float tcxo = SX126X_DIO3_TCXO_VOLTAGE;
#else
float tcxo = 1.6f;
#endif
SPI.setPins(P_LORA_MISO, P_LORA_SCLK, P_LORA_MOSI);
SPI.begin();
radio.setRfSwitchPins(SX126X_RXEN, SX126X_TXEN);
int status = radio.begin(LORA_FREQ, LORA_BW, LORA_SF, LORA_CR, RADIOLIB_SX126X_SYNC_WORD_PRIVATE, LORA_TX_POWER, 8, tcxo);
if (status == RADIOLIB_ERR_SPI_CMD_FAILED || status == RADIOLIB_ERR_SPI_CMD_INVALID) {
#define SX126X_DIO3_TCXO_VOLTAGE (0.0f);
tcxo = SX126X_DIO3_TCXO_VOLTAGE;
status = radio.begin(LORA_FREQ, LORA_BW, LORA_SF, LORA_CR, RADIOLIB_SX126X_SYNC_WORD_PRIVATE, LORA_TX_POWER, 8, tcxo);
}
if (status != RADIOLIB_ERR_NONE) {
Serial.print("ERROR: radio init failed: ");
Serial.println(status);
return false; // fail
}
radio.setCRC(1);
#ifdef SX126X_CURRENT_LIMIT
radio.setCurrentLimit(SX126X_CURRENT_LIMIT);
#endif
#ifdef SX126X_DIO2_AS_RF_SWITCH
radio.setDio2AsRfSwitch(SX126X_DIO2_AS_RF_SWITCH);
#endif
#ifdef SX126X_RX_BOOSTED_GAIN
radio.setRxBoostedGainMode(SX126X_RX_BOOSTED_GAIN);
#endif
return true; // success
return radio.std_init(&SPI);
}
uint32_t radio_get_rng_seed() {
+2 -2
View File
@@ -7,6 +7,8 @@ build_flags = ${stm32_base.build_flags}
-D WRAPPER_CLASS=CustomSTM32WLxWrapper
-D SPI_INTERFACES_COUNT=0
-D RX_BOOSTED_GAIN=true
; -D STM32WL_TCXO_VOLTAGE=1.6 ; defaults to 0 if undef
; -D LORA_TX_POWER=14 ; Defaults to 22 for HP, 14 is for LP version
-I variants/rak3x72
build_src_filter = ${stm32_base.build_src_filter}
+<../variants/rak3x72>
@@ -14,7 +16,6 @@ build_src_filter = ${stm32_base.build_src_filter}
[env:rak3x72-repeater]
extends = rak3x72
build_flags = ${rak3x72.build_flags}
-D LORA_TX_POWER=22
-D ADVERT_NAME='"RAK3x72 Repeater"'
-D ADMIN_PASSWORD='"password"'
build_src_filter = ${rak3x72.build_src_filter}
@@ -24,7 +25,6 @@ build_src_filter = ${rak3x72.build_src_filter}
extends = rak3x72
build_flags = ${rak3x72.build_flags}
; -D FORMAT_FS=true
-D LORA_TX_POWER=22
-D MAX_CONTACTS=100
-D MAX_GROUP_CHANNELS=8
build_src_filter = ${rak3x72.build_src_filter}
+10 -1
View File
@@ -24,12 +24,21 @@ SensorManager sensors;
#define LORA_CR 5
#endif
#ifndef STM32WL_TCXO_VOLTAGE
// TCXO set to 0 for RAK3172
#define STM32WL_TCXO_VOLTAGE 0
#endif
#ifndef LORA_TX_POWER
#define LORA_TX_POWER 22
#endif
bool radio_init() {
// rtc_clock.begin(Wire);
radio.setRfSwitchTable(rfswitch_pins, rfswitch_table);
int status = radio.begin(LORA_FREQ, LORA_BW, LORA_SF, LORA_CR, RADIOLIB_SX126X_SYNC_WORD_PRIVATE, LORA_TX_POWER, 8, 0, 0); // TCXO set to 0 for RAK3172
int status = radio.begin(LORA_FREQ, LORA_BW, LORA_SF, LORA_CR, RADIOLIB_SX126X_SYNC_WORD_PRIVATE, LORA_TX_POWER, 8, STM32WL_TCXO_VOLTAGE, 0);
if (status != RADIOLIB_ERR_NONE) {
Serial.print("ERROR: radio init failed: ");
+6 -2
View File
@@ -18,8 +18,12 @@ public:
}
uint16_t getBattMilliVolts() override {
uint32_t raw = analogRead(PIN_VBAT_READ);
return (ADC_MULTIPLIER * raw) / 1024;
analogReadResolution(12);
uint32_t raw = 0;
for (int i=0; i<8;i++) {
raw += analogRead(PIN_VBAT_READ);
}
return ((double)raw) * ADC_MULTIPLIER / 8 / 4096;
}
};
+28 -1
View File
@@ -23,7 +23,6 @@ lib_deps =
${nrf52840_base.lib_deps}
adafruit/Adafruit SSD1306 @ ^2.5.13
stevemarple/MicroNMEA @ ^2.0.6
sparkfun/SparkFun u-blox GNSS Arduino Library @ ^2.2.27
[env:RAK_4631_Repeater]
extends = rak4631
@@ -41,6 +40,30 @@ build_src_filter = ${rak4631.build_src_filter}
+<helpers/ui/SSD1306Display.cpp>
+<../examples/simple_repeater>
[env:RAK_4631_GPS_Repeater]
extends = rak4631
build_flags =
${rak4631.build_flags}
-D DISPLAY_CLASS=SSD1306Display
-D ADVERT_NAME='"RAK4631 GPS Repeater"'
-D ADVERT_LAT=0.0
-D ADVERT_LON=0.0
-D ADMIN_PASSWORD='"password"'
-D MAX_NEIGHBOURS=8
-D FORCE_GPS_ALIVE=1
-D ENV_INCLUDE_GPS=1
-D ENV_INCLUDE_BME680=1
; -D MESH_PACKET_LOGGING=1
; -D MESH_DEBUG=1
build_src_filter = ${rak4631.build_src_filter}
+<helpers/ui/SSD1306Display.cpp>
+<../examples/simple_repeater>
lib_deps =
${rak4631.lib_deps}
sparkfun/SparkFun u-blox GNSS Arduino Library @ ^2.2.27
https://github.com/boschsensortec/Bosch-BSEC2-Library
https://github.com/boschsensortec/Bosch-BME68x-Library
[env:RAK_4631_room_server]
extends = rak4631
build_flags =
@@ -104,6 +127,7 @@ build_flags =
-D BLE_DEBUG_LOGGING=1
-D OFFLINE_QUEUE_SIZE=256
-D ENV_INCLUDE_GPS=1
-D ENV_INCLUDE_BME680=1
; -D MESH_PACKET_LOGGING=1
; -D MESH_DEBUG=1
build_src_filter = ${rak4631.build_src_filter}
@@ -112,6 +136,9 @@ build_src_filter = ${rak4631.build_src_filter}
+<../examples/companion_radio>
lib_deps =
${rak4631.lib_deps}
sparkfun/SparkFun u-blox GNSS Arduino Library @ ^2.2.27
https://github.com/boschsensortec/Bosch-BSEC2-Library
https://github.com/boschsensortec/Bosch-BME68x-Library
densaugeo/base64 @ ~1.4.0
[env:RAK_4631_terminal_chat]
+236 -66
View File
@@ -19,17 +19,29 @@ RAK4631SensorManager sensors = RAK4631SensorManager(nmea);
RAK4631SensorManager sensors;
#endif
#if ENV_INCLUDE_BME680
#ifndef TELEM_BME680_ADDRESS
#define TELEM_BME680_ADDRESS 0x76 // BME680 environmental sensor I2C address
#endif
#include <bsec2.h>
static Bsec2 BME680;
static float rawPressure = 0;
static float rawTemperature = 0;
static float compTemperature = 0;
static float rawHumidity = 0;
static float compHumidity = 0;
static float readIAQ = 0;
static float readStaticIAQ = 0;
static float readCO2 = 0;
#endif
#ifdef DISPLAY_CLASS
DISPLAY_CLASS display;
#endif
#ifndef LORA_CR
#define LORA_CR 5
#endif
#ifdef MESH_DEBUG
uint32_t deviceOnline = 0x00;
void scanDevices(TwoWire *w)
static void scanDevices(TwoWire *w)
{
uint8_t err, addr;
int nDevices = 0;
@@ -47,6 +59,10 @@ void scanDevices(TwoWire *w)
Serial.println("\tFound RAK12500 GPS Sensor");
deviceOnline |= RAK12500_ONLINE;
break;
case 0x76:
Serial.println("\tFound RAK1906 Environment Sensor");
deviceOnline |= BME680_ONLINE;
break;
default:
Serial.print("\tI2C device found at address 0x");
if (addr < 16) {
@@ -75,35 +91,7 @@ void scanDevices(TwoWire *w)
bool radio_init() {
rtc_clock.begin(Wire);
#ifdef SX126X_DIO3_TCXO_VOLTAGE
float tcxo = SX126X_DIO3_TCXO_VOLTAGE;
#else
float tcxo = 1.6f;
#endif
SPI.setPins(P_LORA_MISO, P_LORA_SCLK, P_LORA_MOSI);
SPI.begin();
int status = radio.begin(LORA_FREQ, LORA_BW, LORA_SF, LORA_CR, RADIOLIB_SX126X_SYNC_WORD_PRIVATE, LORA_TX_POWER, 8, tcxo);
if (status != RADIOLIB_ERR_NONE) {
Serial.print("ERROR: radio init failed: ");
Serial.println(status);
return false; // fail
}
radio.setCRC(1);
#ifdef SX126X_CURRENT_LIMIT
radio.setCurrentLimit(SX126X_CURRENT_LIMIT);
#endif
#ifdef SX126X_DIO2_AS_RF_SWITCH
radio.setDio2AsRfSwitch(SX126X_DIO2_AS_RF_SWITCH);
#endif
#ifdef SX126X_RX_BOOSTED_GAIN
radio.setRxBoostedGainMode(SX126X_RX_BOOSTED_GAIN);
#endif
return true; // success
return radio.std_init(&SPI);
}
uint32_t radio_get_rng_seed() {
@@ -169,7 +157,7 @@ bool RAK4631SensorManager::gpsIsAwake(uint32_t ioPin){
ublox_GNSS.saveConfigSelective(VAL_CFG_SUBSEC_IOPORT);
disStandbyPin = ioPin;
gps_active = true;
gps_present = true;
gps_detected = true;
return true;
}
else
@@ -179,73 +167,255 @@ bool RAK4631SensorManager::gpsIsAwake(uint32_t ioPin){
}
#endif
#if ENV_INCLUDE_BME680
static void checkBMEStatus(Bsec2 bsec) {
if (bsec.status < BSEC_OK)
{
MESH_DEBUG_PRINTLN("BSEC error code : %f", float(bsec.status));
}
else if (bsec.status > BSEC_OK)
{
MESH_DEBUG_PRINTLN("BSEC warning code : %f", float(bsec.status));
}
if (bsec.sensor.status < BME68X_OK)
{
MESH_DEBUG_PRINTLN("BME68X error code : %f", bsec.sensor.status);
}
else if (bsec.sensor.status > BME68X_OK)
{
MESH_DEBUG_PRINTLN("BME68X warning code : %f", bsec.sensor.status);
}
}
static void newDataCallback(const bme68xData data, const bsecOutputs outputs, Bsec2 bsec) {
if (!outputs.nOutputs) {
MESH_DEBUG_PRINTLN("No new data to report out");
return;
}
MESH_DEBUG_PRINTLN("BSEC outputs:\n\tTime stamp = %f", (int) (outputs.output[0].time_stamp / INT64_C(1000000)));
for (uint8_t i = 0; i < outputs.nOutputs; i++) {
const bsecData output = outputs.output[i];
switch (output.sensor_id)
{
case BSEC_OUTPUT_IAQ:
readIAQ = output.signal;
MESH_DEBUG_PRINTLN("\tIAQ = %f", output.signal);
MESH_DEBUG_PRINTLN("\tIAQ accuracy = %f", output.accuracy);
break;
case BSEC_OUTPUT_RAW_TEMPERATURE:
rawTemperature = output.signal;
MESH_DEBUG_PRINTLN("\tTemperature = %f", output.signal);
break;
case BSEC_OUTPUT_RAW_PRESSURE:
rawPressure = output.signal;
MESH_DEBUG_PRINTLN("\tPressure = %f", output.signal);
break;
case BSEC_OUTPUT_RAW_HUMIDITY:
rawHumidity = output.signal;
MESH_DEBUG_PRINTLN("\tHumidity = %f", output.signal);
break;
case BSEC_OUTPUT_RAW_GAS:
MESH_DEBUG_PRINTLN("\tGas resistance = %f", output.signal);
break;
case BSEC_OUTPUT_STABILIZATION_STATUS:
MESH_DEBUG_PRINTLN("\tStabilization status = %f", output.signal);
break;
case BSEC_OUTPUT_RUN_IN_STATUS:
MESH_DEBUG_PRINTLN("\tRun in status = %f", output.signal);
break;
case BSEC_OUTPUT_SENSOR_HEAT_COMPENSATED_TEMPERATURE:
compTemperature = output.signal;
MESH_DEBUG_PRINTLN("\tCompensated temperature = %f", output.signal);
break;
case BSEC_OUTPUT_SENSOR_HEAT_COMPENSATED_HUMIDITY:
compHumidity = output.signal;
MESH_DEBUG_PRINTLN("\tCompensated humidity = %f", output.signal);
break;
case BSEC_OUTPUT_STATIC_IAQ:
readStaticIAQ = output.signal;
MESH_DEBUG_PRINTLN("\tStatic IAQ = %f", output.signal);
break;
case BSEC_OUTPUT_CO2_EQUIVALENT:
readCO2 = output.signal;
MESH_DEBUG_PRINTLN("\tCO2 Equivalent = %f", output.signal);
break;
case BSEC_OUTPUT_BREATH_VOC_EQUIVALENT:
MESH_DEBUG_PRINTLN("\tbVOC equivalent = %f", output.signal);
break;
case BSEC_OUTPUT_GAS_PERCENTAGE:
MESH_DEBUG_PRINTLN("\tGas percentage = %f", output.signal);
break;
case BSEC_OUTPUT_COMPENSATED_GAS:
MESH_DEBUG_PRINTLN("\tCompensated gas = %f", output.signal);
break;
default:
break;
}
}
}
#endif
bool RAK4631SensorManager::begin() {
#ifdef MESH_DEBUG
scanDevices(&Wire);
#endif
#if ENV_INCLUDE_GPS
//search for the correct IO standby pin depending on socket used
if(gpsIsAwake(P_GPS_STANDBY_A)){
MESH_DEBUG_PRINTLN("GPS is on socket A");
}
else if(gpsIsAwake(P_GPS_STANDBY_C)){
MESH_DEBUG_PRINTLN("GPS is on socket C");
}
else if(gpsIsAwake(P_GPS_STANDBY_F)){
MESH_DEBUG_PRINTLN("GPS is on socket F");
}
else{
MESH_DEBUG_PRINTLN("Error: No GPS found on sockets A, C or F");
gps_active = false;
gps_present = false;
return false;
}
#if ENV_INCLUDE_GPS
//search for the correct IO standby pin depending on socket used
if(gpsIsAwake(P_GPS_STANDBY_A)){
MESH_DEBUG_PRINTLN("GPS is on socket A");
}
else if(gpsIsAwake(P_GPS_STANDBY_C)){
MESH_DEBUG_PRINTLN("GPS is on socket C");
}
else if(gpsIsAwake(P_GPS_STANDBY_F)){
MESH_DEBUG_PRINTLN("GPS is on socket F");
}
else{
MESH_DEBUG_PRINTLN("Error: No GPS found on sockets A, C or F");
gps_active = false;
gps_detected = false;
return false;
}
//Now that GPS is found and set up, set to sleep for initial state
stop_gps();
#endif
#ifndef FORCE_GPS_ALIVE
//Now that GPS is found and set up, set to sleep for initial state
stop_gps();
#endif
#endif
#if ENV_INCLUDE_BME680
bsecSensor sensorList[5] = {
BSEC_OUTPUT_IAQ,
// BSEC_OUTPUT_RAW_TEMPERATURE,
BSEC_OUTPUT_RAW_PRESSURE,
// BSEC_OUTPUT_RAW_HUMIDITY,
// BSEC_OUTPUT_RAW_GAS,
// BSEC_OUTPUT_STABILIZATION_STATUS,
// BSEC_OUTPUT_RUN_IN_STATUS,
BSEC_OUTPUT_SENSOR_HEAT_COMPENSATED_TEMPERATURE,
BSEC_OUTPUT_SENSOR_HEAT_COMPENSATED_HUMIDITY,
BSEC_OUTPUT_STATIC_IAQ,
// BSEC_OUTPUT_CO2_EQUIVALENT,
// BSEC_OUTPUT_BREATH_VOC_EQUIVALENT,
// BSEC_OUTPUT_GAS_PERCENTAGE,
// BSEC_OUTPUT_COMPENSATED_GAS
};
if(!BME680.begin(TELEM_BME680_ADDRESS, Wire)){
checkBMEStatus(BME680);
bme680_present = false;
bme680_active = false;
return false;
}
MESH_DEBUG_PRINTLN("Found BME680 at address: %02X", TELEM_BME680_ADDRESS);
bme680_present = true;
bme680_active = true;
if (SAMPLING_RATE == BSEC_SAMPLE_RATE_ULP)
{
BME680.setTemperatureOffset(BSEC_SAMPLE_RATE_ULP);
}
else if (SAMPLING_RATE == BSEC_SAMPLE_RATE_LP)
{
BME680.setTemperatureOffset(TEMP_OFFSET_LP);
}
if (!BME680.updateSubscription(sensorList, ARRAY_LEN(sensorList), SAMPLING_RATE))
{
checkBMEStatus(BME680);
}
BME680.attachCallback(newDataCallback);
#endif
}
#if ENV_INCLUDE_GPS
bool RAK4631SensorManager::querySensors(uint8_t requester_permissions, CayenneLPP& telemetry) {
#ifdef ENV_INCLUDE_GPS
if (requester_permissions & TELEM_PERM_LOCATION && gps_active) { // does requester have permission?
telemetry.addGPS(TELEM_CHANNEL_SELF, node_lat, node_lon, node_altitude);
}
#endif
if (requester_permissions & TELEM_PERM_ENVIRONMENT) {
#if ENV_INCLUDE_BME680
if (bme680_active) {
telemetry.addTemperature(TELEM_CHANNEL_SELF, compTemperature);
telemetry.addRelativeHumidity(TELEM_CHANNEL_SELF, compHumidity);
telemetry.addBarometricPressure(TELEM_CHANNEL_SELF, rawPressure);
telemetry.addTemperature(TELEM_CHANNEL_SELF+1, readIAQ);
telemetry.addRelativeHumidity(TELEM_CHANNEL_SELF+1, readStaticIAQ);
}
#endif
}
return true;
}
void RAK4631SensorManager::loop() {
static long next_update = 0;
#ifdef ENV_INCLUDE_GPS
_nmea->loop();
#endif
if (millis() > next_update && gps_active) {
node_lat = (double)ublox_GNSS.getLatitude()/10000000.;
node_lon = (double)ublox_GNSS.getLongitude()/10000000.;
node_altitude = (double)ublox_GNSS.getAltitude()/1000.;
MESH_DEBUG_PRINT("lat %f lon %f alt %f\r\n", node_lat, node_lon, node_altitude);
if (millis() > next_update) {
#ifdef ENV_INCLUDE_GPS
if(gps_active){
node_lat = (double)ublox_GNSS.getLatitude()/10000000.;
node_lon = (double)ublox_GNSS.getLongitude()/10000000.;
node_altitude = (double)ublox_GNSS.getAltitude()/1000.;
MESH_DEBUG_PRINT("lat %f lon %f alt %f\r\n", node_lat, node_lon, node_altitude);
}
#endif
#ifdef ENV_INCLUDE_BME680
if(bme680_active){
if (!BME680.run()){
checkBMEStatus(BME680);
}
}
#endif
next_update = millis() + 1000;
}
}
int RAK4631SensorManager::getNumSettings() const { return 1; } // just one supported: "gps" (power switch)
int RAK4631SensorManager::getNumSettings() const {
#if ENV_INCLUDE_GPS
return gps_detected ? 1 : 0; // only show GPS setting if GPS is detected
#else
return 0;
#endif
}
const char* RAK4631SensorManager::getSettingName(int i) const {
return i == 0 ? "gps" : NULL;
#if ENV_INCLUDE_GPS
return (gps_detected && i == 0) ? "gps" : NULL;
#else
return NULL;
#endif
}
const char* RAK4631SensorManager::getSettingValue(int i) const {
if (i == 0) {
#if ENV_INCLUDE_GPS
if (gps_detected && i == 0) {
return gps_active ? "1" : "0";
}
#endif
return NULL;
}
bool RAK4631SensorManager::setSettingValue(const char* name, const char* value) {
if (strcmp(name, "gps") == 0) {
#if ENV_INCLUDE_GPS
if (gps_detected && strcmp(name, "gps") == 0) {
if (strcmp(value, "0") == 0) {
stop_gps();
} else {
@@ -253,9 +423,9 @@ bool RAK4631SensorManager::setSettingValue(const char* name, const char* value)
}
return true;
}
#endif
return false; // not supported
}
#endif
mesh::LocalIdentity radio_new_identity() {
RadioNoiseListener rng(radio);
+15 -9
View File
@@ -20,7 +20,7 @@
class RAK4631SensorManager: public SensorManager {
#if ENV_INCLUDE_GPS
bool gps_active = false;
bool gps_present = false;
bool gps_detected = false;
LocationProvider * _nmea;
SFE_UBLOX_GNSS ublox_GNSS;
uint32_t disStandbyPin = 0;
@@ -32,20 +32,26 @@ class RAK4631SensorManager: public SensorManager {
bool gpsIsAwake(uint32_t ioPin);
#endif
#if ENV_INCLUDE_BME680
bool bme680_active = false;
bool bme680_present = false;
#define SAMPLING_RATE BSEC_SAMPLE_RATE_ULP
#endif
public:
#if ENV_INCLUDE_GPS
RAK4631SensorManager(LocationProvider &nmea): _nmea(&nmea) { }
bool querySensors(uint8_t requester_permissions, CayenneLPP& telemetry) override;
void loop() override;
int getNumSettings() const override;
const char* getSettingName(int i) const override;
const char* getSettingValue(int i) const override;
bool setSettingValue(const char* name, const char* value) override;
#else
RAK4631SensorManager() { }
#endif
bool begin() override;
void loop() override;
bool querySensors(uint8_t requester_permissions, CayenneLPP& telemetry) override;
int getNumSettings() const override;
const char* getSettingName(int i) const override;
const char* getSettingValue(int i) const override;
bool setSettingValue(const char* name, const char* value) override;
bool begin() override;
};
extern RAK4631Board board;
+38 -2
View File
@@ -7,7 +7,7 @@ build_flags =
-D STATION_G2
-D RADIO_CLASS=CustomSX1262
-D WRAPPER_CLASS=CustomSX1262Wrapper
-D LORA_TX_POWER=7
-D LORA_TX_POWER=19
; -D P_LORA_TX_LED=35
-D PIN_BOARD_SDA=5
-D PIN_BOARD_SCL=6
@@ -16,9 +16,9 @@ build_flags =
-D SX126X_DIO3_TCXO_VOLTAGE=1.8
-D SX126X_CURRENT_LIMIT=140
; -D SX126X_RX_BOOSTED_GAIN=1 - DO NOT ENABLE THIS!
; https://wiki.uniteng.com/en/meshtastic/station-g2#impact-of-lora-node-dense-areashigh-noise-environments-on-rf-performance
-I src/helpers/ui
-D DISPLAY_CLASS=SH1106Display
; https://wiki.uniteng.com/en/meshtastic/station-g2#impact-of-lora-node-dense-areashigh-noise-environments-on-rf-performance
build_src_filter = ${esp32_base.build_src_filter}
+<../variants/station_g2>
+<helpers/ui/SH1106Display.cpp>
@@ -60,3 +60,39 @@ build_flags =
lib_deps =
${Station_G2.lib_deps}
${esp32_ota.lib_deps}
[env:Station_G2_companion_radio_usb]
extends = Station_G2
build_flags =
${Station_G2.build_flags}
-D DISPLAY_CLASS=SH1106Display
-D MAX_CONTACTS=100
-D MAX_GROUP_CHANNELS=8
; NOTE: DO NOT ENABLE --> -D MESH_PACKET_LOGGING=1
; NOTE: DO NOT ENABLE --> -D MESH_DEBUG=1
build_src_filter = ${Station_G2.build_src_filter}
+<helpers/ui/SH1106Display.cpp>
+<../examples/companion_radio>
lib_deps =
${Station_G2.lib_deps}
densaugeo/base64 @ ~1.4.0
[env:Station_G2_companion_radio_ble]
extends = Station_G2
build_flags =
${Station_G2.build_flags}
-D DISPLAY_CLASS=SH1106Display
-D MAX_CONTACTS=100
-D MAX_GROUP_CHANNELS=8
-D BLE_PIN_CODE=123456
-D BLE_DEBUG_LOGGING=1
-D OFFLINE_QUEUE_SIZE=256
; -D MESH_PACKET_LOGGING=1
; -D MESH_DEBUG=1
build_src_filter = ${Station_G2.build_src_filter}
+<helpers/esp32/*.cpp>
+<helpers/ui/SH1106Display.cpp>
+<../examples/companion_radio>
lib_deps =
${Station_G2.lib_deps}
densaugeo/base64 @ ~1.4.0
+3 -26
View File
@@ -27,36 +27,13 @@ SensorManager sensors;
bool radio_init() {
fallback_clock.begin();
rtc_clock.begin(Wire);
#ifdef SX126X_DIO3_TCXO_VOLTAGE
float tcxo = SX126X_DIO3_TCXO_VOLTAGE;
#else
float tcxo = 1.6f;
#endif
#if defined(P_LORA_SCLK)
spi.begin(P_LORA_SCLK, P_LORA_MISO, P_LORA_MOSI);
return radio.std_init(&spi);
#else
return radio.std_init();
#endif
int status = radio.begin(LORA_FREQ, LORA_BW, LORA_SF, LORA_CR, RADIOLIB_SX126X_SYNC_WORD_PRIVATE, LORA_TX_POWER, 8, tcxo);
if (status != RADIOLIB_ERR_NONE) {
Serial.print("ERROR: radio init failed: ");
Serial.println(status);
return false; // fail
}
radio.setCRC(1);
#ifdef SX126X_CURRENT_LIMIT
radio.setCurrentLimit(SX126X_CURRENT_LIMIT);
#endif
#ifdef SX126X_DIO2_AS_RF_SWITCH
radio.setDio2AsRfSwitch(SX126X_DIO2_AS_RF_SWITCH);
#endif
#ifdef SX126X_RX_BOOSTED_GAIN
radio.setRxBoostedGainMode(SX126X_RX_BOOSTED_GAIN);
#endif
return true; // success
}
uint32_t radio_get_rng_seed() {
+1 -1
View File
@@ -174,7 +174,7 @@ void T1000SensorManager::loop() {
_nmea->loop();
if (millis() > next_gps_update) {
if (_nmea->isValid()) {
if (gps_active && _nmea->isValid()) {
node_lat = ((double)_nmea->getLatitude())/1000000.;
node_lon = ((double)_nmea->getLongitude())/1000000.;
node_altitude = ((double)_nmea->getAltitude()) / 1000.0;
+1 -1
View File
@@ -3,7 +3,7 @@
#define RADIOLIB_STATIC_ONLY 1
#include <RadioLib.h>
#include <helpers/RadioLibWrappers.h>
#include <helpers/nrf52/T1000eBoard.h>
#include "T1000eBoard.h"
#include <helpers/CustomLR1110Wrapper.h>
#include <helpers/ArduinoHelpers.h>
#include <helpers/SensorManager.h>
+9 -9
View File
@@ -15,6 +15,7 @@ board = heltec_t114
board_build.ldscript = boards/nrf52840_s140_v6.ld
build_flags = ${nrf52840_t114.build_flags}
-I variants/t114
-I src/helpers/ui
-DHELTEC_T114
-D P_LORA_TX_LED=35
-D RADIO_CLASS=CustomSX1262
@@ -22,20 +23,27 @@ build_flags = ${nrf52840_t114.build_flags}
-D LORA_TX_POWER=22
-D SX126X_CURRENT_LIMIT=140
-D SX126X_RX_BOOSTED_GAIN=1
-D ST7789
-D DISPLAY_CLASS=ST7789Display
build_src_filter = ${nrf52840_t114.build_src_filter}
+<helpers/*.cpp>
+<helpers/nrf52/T114Board.cpp>
+<../variants/t114>
+<helpers/ui/ST7789Display.cpp>
+<helpers/ui/OLEDDisplay.cpp>
+<helpers/ui/OLEDDisplayFonts.cpp>
lib_deps =
${nrf52840_t114.lib_deps}
stevemarple/MicroNMEA @ ^2.0.6
adafruit/Adafruit GFX Library @ ^1.12.1
debug_tool = jlink
upload_protocol = nrfutil
[env:Heltec_t114_repeater]
extends = Heltec_t114
build_src_filter = ${Heltec_t114.build_src_filter}
+<../examples/simple_repeater/main.cpp>
+<../examples/simple_repeater>
build_flags =
${Heltec_t114.build_flags}
-D ADVERT_NAME='"Heltec_T114 Repeater"'
@@ -64,9 +72,6 @@ build_flags =
extends = Heltec_t114
build_flags =
${Heltec_t114.build_flags}
-I src/helpers/ui
-D ST7789
-D DISPLAY_CLASS=ST7789Display
-D MAX_CONTACTS=100
-D MAX_GROUP_CHANNELS=8
-D BLE_PIN_CODE=123456
@@ -75,14 +80,9 @@ build_flags =
; -D MESH_PACKET_LOGGING=1
; -D MESH_DEBUG=1
build_src_filter = ${Heltec_t114.build_src_filter}
+<helpers/nrf52/T114Board.cpp>
+<helpers/nrf52/SerialBLEInterface.cpp>
+<../examples/companion_radio>
+<helpers/ui/ST7789Display.cpp>
+<helpers/ui/OLEDDisplay.cpp>
+<helpers/ui/OLEDDisplayFonts.cpp>
lib_deps =
adafruit/Adafruit GFX Library @ ^1.12.1
${Heltec_t114.lib_deps}
densaugeo/base64 @ ~1.4.0
+1 -32
View File
@@ -18,41 +18,10 @@ T114SensorManager sensors = T114SensorManager(nmea);
DISPLAY_CLASS display;
#endif
#ifndef LORA_CR
#define LORA_CR 5
#endif
bool radio_init() {
rtc_clock.begin(Wire);
#ifdef SX126X_DIO3_TCXO_VOLTAGE
float tcxo = SX126X_DIO3_TCXO_VOLTAGE;
#else
float tcxo = 1.6f;
#endif
SPI.setPins(P_LORA_MISO, P_LORA_SCLK, P_LORA_MOSI);
SPI.begin();
int status = radio.begin(LORA_FREQ, LORA_BW, LORA_SF, LORA_CR, RADIOLIB_SX126X_SYNC_WORD_PRIVATE, LORA_TX_POWER, 8, tcxo);
if (status != RADIOLIB_ERR_NONE) {
Serial.print("ERROR: radio init failed: ");
Serial.println(status);
return false; // fail
}
radio.setCRC(1);
#ifdef SX126X_CURRENT_LIMIT
radio.setCurrentLimit(SX126X_CURRENT_LIMIT);
#endif
#ifdef SX126X_DIO2_AS_RF_SWITCH
radio.setDio2AsRfSwitch(SX126X_DIO2_AS_RF_SWITCH);
#endif
#ifdef SX126X_RX_BOOSTED_GAIN
radio.setRxBoostedGainMode(SX126X_RX_BOOSTED_GAIN);
#endif
return true; // success
return radio.std_init(&SPI);
}
uint32_t radio_get_rng_seed() {
+1 -32
View File
@@ -18,41 +18,10 @@ TechoSensorManager sensors = TechoSensorManager(nmea);
DISPLAY_CLASS display;
#endif
#ifndef LORA_CR
#define LORA_CR 5
#endif
bool radio_init() {
rtc_clock.begin(Wire);
#ifdef SX126X_DIO3_TCXO_VOLTAGE
float tcxo = SX126X_DIO3_TCXO_VOLTAGE;
#else
float tcxo = 1.6f;
#endif
SPI.setPins(P_LORA_MISO, P_LORA_SCLK, P_LORA_MOSI);
SPI.begin();
int status = radio.begin(LORA_FREQ, LORA_BW, LORA_SF, LORA_CR, RADIOLIB_SX126X_SYNC_WORD_PRIVATE, LORA_TX_POWER, 8, tcxo);
if (status != RADIOLIB_ERR_NONE) {
Serial.print("ERROR: radio init failed: ");
Serial.println(status);
return false; // fail
}
radio.setCRC(1);
#ifdef SX126X_CURRENT_LIMIT
radio.setCurrentLimit(SX126X_CURRENT_LIMIT);
#endif
#ifdef SX126X_DIO2_AS_RF_SWITCH
radio.setDio2AsRfSwitch(SX126X_DIO2_AS_RF_SWITCH);
#endif
#ifdef SX126X_RX_BOOSTED_GAIN
radio.setRxBoostedGainMode(SX126X_RX_BOOSTED_GAIN);
#endif
return true; // success
return radio.std_init(&SPI);
}
uint32_t radio_get_rng_seed() {
+65
View File
@@ -0,0 +1,65 @@
[Tenstar_esp32_C3]
extends = esp32_base
board = esp32-c3-devkitm-1
build_flags =
${esp32_base.build_flags}
-I variants/tenstar_c3
-D ESP32_CPU_FREQ=80
-D LORA_TX_BOOST_PIN=4
-D P_LORA_TX_NEOPIXEL_LED=10
-D PIN_VBAT_READ=1
-D P_LORA_MISO=9
-D P_LORA_SCLK=8
-D P_LORA_MOSI=7
-D P_LORA_DIO_1=2
-D P_LORA_NSS=6
-D P_LORA_RESET=RADIOLIB_NC
-D P_LORA_BUSY=3
; -D PIN_BOARD_SDA=18
; -D PIN_BOARD_SCL=19
-D SX126X_DIO2_AS_RF_SWITCH=true
-D SX126X_DIO3_TCXO_VOLTAGE=1.8
-D SX126X_CURRENT_LIMIT=140
build_src_filter = ${esp32_base.build_src_filter}
+<../variants/tenstar_c3>
[env:Tenstar_C3_Repeater_sx1262]
extends = Tenstar_esp32_C3
build_src_filter = ${Tenstar_esp32_C3.build_src_filter}
+<../examples/simple_repeater/main.cpp>
build_flags =
${Tenstar_esp32_C3.build_flags}
-D RADIO_CLASS=CustomSX1262
-D WRAPPER_CLASS=CustomSX1262Wrapper
-D SX126X_RX_BOOSTED_GAIN=1
-D LORA_TX_POWER=22
-D ADVERT_NAME='"Tenstar C3 Repeater"'
-D ADVERT_LAT=0.0
-D ADVERT_LON=0.0
-D ADMIN_PASSWORD='"password"'
-D MAX_NEIGHBOURS=8
; -D MESH_PACKET_LOGGING=1
; -D MESH_DEBUG=1
lib_deps =
${Tenstar_esp32_C3.lib_deps}
${esp32_ota.lib_deps}
[env:Tenstar_C3_Repeater_sx1268]
extends = Tenstar_esp32_C3
build_src_filter = ${Tenstar_esp32_C3.build_src_filter}
+<../examples/simple_repeater/main.cpp>
build_flags =
${Tenstar_esp32_C3.build_flags}
-D RADIO_CLASS=CustomSX1268
-D WRAPPER_CLASS=CustomSX1268Wrapper
-D LORA_TX_POWER=22
-D ADVERT_NAME='"Tenstar C3 Repeater"'
-D ADVERT_LAT=0.0
-D ADVERT_LON=0.0
-D ADMIN_PASSWORD='"password"'
-D MAX_NEIGHBOURS=8
; -D MESH_PACKET_LOGGING=1
; -D MESH_DEBUG=1
lib_deps =
${Tenstar_esp32_C3.lib_deps}
${esp32_ota.lib_deps}
+48
View File
@@ -0,0 +1,48 @@
#include <Arduino.h>
#include "target.h"
XiaoC3Board board;
#if defined(P_LORA_SCLK)
static SPIClass spi;
RADIO_CLASS radio = new Module(P_LORA_NSS, P_LORA_DIO_1, P_LORA_RESET, P_LORA_BUSY, spi);
#else
RADIO_CLASS radio = new Module(P_LORA_NSS, P_LORA_DIO_1, P_LORA_RESET, P_LORA_BUSY);
#endif
WRAPPER_CLASS radio_driver(radio, board);
ESP32RTCClock fallback_clock;
AutoDiscoverRTCClock rtc_clock(fallback_clock);
SensorManager sensors;
bool radio_init() {
fallback_clock.begin();
rtc_clock.begin(Wire);
#if defined(P_LORA_SCLK)
return radio.std_init(&spi);
#else
return radio.std_init();
#endif
}
uint32_t radio_get_rng_seed() {
return radio.random(0x7FFFFFFF);
}
void radio_set_params(float freq, float bw, uint8_t sf, uint8_t cr) {
radio.setFrequency(freq);
radio.setSpreadingFactor(sf);
radio.setBandwidth(bw);
radio.setCodingRate(cr);
}
void radio_set_tx_power(uint8_t dbm) {
radio.setOutputPower(dbm);
}
mesh::LocalIdentity radio_new_identity() {
RadioNoiseListener rng(radio);
return mesh::LocalIdentity(&rng); // create new random identity
}
+21
View File
@@ -0,0 +1,21 @@
#pragma once
#define RADIOLIB_STATIC_ONLY 1
#include <RadioLib.h>
#include <helpers/RadioLibWrappers.h>
#include <helpers/XiaoC3Board.h>
#include <helpers/CustomSX1262Wrapper.h>
#include <helpers/CustomSX1268Wrapper.h>
#include <helpers/AutoDiscoverRTCClock.h>
#include <helpers/SensorManager.h>
extern XiaoC3Board board;
extern WRAPPER_CLASS radio_driver;
extern AutoDiscoverRTCClock rtc_clock;
extern SensorManager sensors;
bool radio_init();
uint32_t radio_get_rng_seed();
void radio_set_params(float freq, float bw, uint8_t sf, uint8_t cr);
void radio_set_tx_power(uint8_t dbm);
mesh::LocalIdentity radio_new_identity();
+1
View File
@@ -19,6 +19,7 @@ build_flags = ${nrf52840_thinknode_m1.build_flags}
-D RADIO_CLASS=CustomSX1262
-D WRAPPER_CLASS=CustomSX1262Wrapper
-D LORA_TX_POWER=22
-D P_LORA_TX_LED=13
-D SX126X_CURRENT_LIMIT=140
-D SX126X_RX_BOOSTED_GAIN=1
build_src_filter = ${nrf52840_thinknode_m1.build_src_filter}

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