Compare commits

...

120 Commits

Author SHA1 Message Date
Scott Powell
6a093743d3 * ver bump to v1.4.0 2025-03-19 19:32:07 +11:00
Scott Powell
fd55837eec * companion: CMD_SET_DEVICE_PIN now uint32 param, RESP_CODE_DEVICE_INFO now includes ble_pin 2025-03-19 18:21:35 +11:00
Scott Powell
4aeafbd034 * companion: added CMD_SET_DEVICE_PIN 2025-03-19 17:54:55 +11:00
Scott Powell
089ac96f2b * verify() fix moved to Identity class 2025-03-19 17:30:35 +11:00
Scott Powell
4943b388c0 * workaround for Identity::verify() bug. 2025-03-19 14:31:48 +11:00
Scott Powell
69a6d76b87 * experimental workaround for sig verify() bug 2025-03-19 13:54:43 +11:00
Scott Powell
38667dabb1 * refactored platformio.ini, breaking up into variants/*.ini files 2025-03-18 23:57:04 +11:00
Scott Powell
d21274db41 * TBeam: minor refactor. 2025-03-18 21:34:32 +11:00
ripplebiz
c7f791963e Merge pull request #100 from jameshall9327/main
Added Support for the LilyGo TBeam v1.1 and v1.2 with the SX1276
2025-03-18 21:29:38 +11:00
Scott Powell
50b62c9252 * room server: now handles REQ_TYPE_GET_STATUS, replies with ServerStats (same as RepeaterStats, with extra fields: n_posted, n_post_push) 2025-03-18 16:49:40 +11:00
Scott Powell
f08a30cf24 * companion: RESP_CODE_ERR now has err_code byte 2025-03-18 15:27:55 +11:00
ripplebiz
d15630660b Merge pull request #114 from lincomatic/pr-llcc68
Add ProMicroLLCC68 builds
2025-03-18 13:45:03 +11:00
Scott Powell
13679f9ff1 * CMD_SEND_TRACE_PATH, now replies with RESP_CODE_SENT 2025-03-18 00:14:57 +11:00
Scott Powell
691c135c22 * workaround for TRACE packets so they can follow a return path 2025-03-17 19:35:08 +11:00
Scott Powell
807b9bdc19 * companion support for TRACE packets. (CMD_SEND_TRACE_PATH, PUSH_CODE_TRACE_DATA) 2025-03-17 18:15:38 +11:00
Scott Powell
fe4fdeb236 * redesigned TRACE packet structure 2025-03-17 17:56:12 +11:00
Scott Powell
156741e563 Merge branch 'dev' into trace
# Conflicts:
#	examples/companion_radio/main.cpp
2025-03-17 12:18:27 +11:00
lincomatic
bdeec374ef add ProMicroLLCC68 for Faketec w/ LLCC68 2025-03-16 17:48:52 -07:00
lincomatic
0eed29b99e fix compilation error 2025-03-16 16:49:55 -07:00
Scott Powell
25a68f5ca4 * build fix 2025-03-16 22:11:27 +11:00
ripplebiz
6c434328b5 Merge pull request #111 from recrof/dev
added display support for RAK4631
2025-03-16 21:36:19 +11:00
recrof
882377e4d6 fixed: added back pin inits when SDA and SCL are set. 2025-03-16 10:17:04 +01:00
recrof
d525680b71 added display support for RAK4631, removed Wire.begin(int, int) from nrf52 devices, cosmetic changes 2025-03-16 09:07:21 +01:00
ripplebiz
f700fd5a36 Merge pull request #107 from recrof/dev
heltec v2: added display, room server role
2025-03-16 19:04:38 +11:00
Rastislav Vysoky
32436b953e Merge branch 'ripplebiz:dev' into dev 2025-03-16 07:11:53 +01:00
Scott Powell
81bf4f0a08 * companion: SSD1306 display now dynamically detected at runtime. 2025-03-16 13:42:36 +11:00
James Hall
395349d208 Merge branch 'dev' into main 2025-03-15 15:10:17 -04:00
recrof
c691cbae8e heltec v2: added display, room server role 2025-03-15 20:10:07 +01:00
James Hall
aeda218402 Update TBeamBoard.h 2025-03-15 13:09:15 -04:00
James Hall
b6990c73bb Merge branch 'ripplebiz:main' into main 2025-03-15 13:03:49 -04:00
ripplebiz
4113b20b4c Merge pull request #105 from recrof/dev
added display support for t3s3
2025-03-15 23:44:09 +11:00
recrof
7ee81f4f07 added display support for t3s3 2025-03-15 13:07:18 +01:00
Scott Powell
31f8576640 * CMD_SIGN_DATA null check 2025-03-15 22:06:57 +11:00
Scott Powell
6056c303c1 * companion: can now sign arbitrary data (up to 8K) 2025-03-15 21:41:44 +11:00
Scott Powell
9aa2edf9ba Merge branch 'dev' into trace
# Conflicts:
#	examples/companion_radio/main.cpp
#	src/Dispatcher.cpp
2025-03-15 15:12:50 +11:00
Scott Powell
27aa7a7bb0 * minor refactor for RAK_4631 SerialInterface 2025-03-15 14:55:52 +11:00
ripplebiz
06c666843e Merge pull request #90 from oltaco/faketec-support
Faketec support
2025-03-15 14:47:18 +11:00
ripplebiz
f844f9e02a Merge pull request #65 from awolden/awolden/h3-pin-fix
Fix heltec v3.2 pin polarity reversal
2025-03-15 12:09:47 +11:00
James Hall
bc6e4930d9 Cleaned up code 2025-03-14 19:54:46 -04:00
taco
6931887424 remove old unused board.json 2025-03-15 10:54:37 +11:00
James Hall
c2f92534df removed unnecessary defines 2025-03-14 14:27:10 -04:00
James Hall
aca0bcc919 removed unnecessary constants 2025-03-14 14:22:13 -04:00
Scott Powell
6a4b7463ef * some fixes around the powerOff(). Tidy ups 2025-03-14 19:08:41 +11:00
ripplebiz
99b376c512 Merge pull request #87 from fdlamotte/t1000e_ui
enhancement on the UI and support for power off and status_led
2025-03-14 18:52:00 +11:00
taco
fbb879600d MAX_GROUP_CHANNELS=8 for faketec 2025-03-14 15:24:58 +11:00
taco
5632e2771e added conditional to room server radio bringup for supporting RA01sh radio on faketec 2025-03-14 15:22:42 +11:00
James Hall
b41d1a56f6 Delete .vscode/settings.json 2025-03-13 20:42:36 -04:00
James Hall
6d8aa5817b removed pmu flag 2025-03-13 20:41:32 -04:00
James Hall
aca3486f88 Update settings.json 2025-03-13 20:35:44 -04:00
ripplebiz
0fe6f79f3c Merge pull request #94 from LitBomb/patch-5
Update faq.md for new EU and UK frequency, additional steps to setup repeater frequency
2025-03-14 11:29:34 +11:00
ripplebiz
87462b20d5 Update README.md 2025-03-14 09:55:48 +11:00
James Hall
2edbd92b3b Added Support for the LilyGo TBeam v1.2 SX1276 2025-03-13 14:07:54 -04:00
fdlamotte
c62f09d92e Merge branch 'ripplebiz:main' into t1000e_ui 2025-03-13 09:44:10 +01:00
taco
9c3b4dd520 added SX126X_RX_BOOSTED_GAIN=1 to faketec target 2025-03-13 17:46:58 +11:00
oltaco
c8104563a0 Merge branch 'ripplebiz:main' into faketec-support 2025-03-13 16:22:02 +11:00
Scott Powell
658094f654 * ver bump: 1.3.0 2025-03-13 13:46:01 +11:00
Scott Powell
38b9834261 * missing param 2025-03-13 13:32:46 +11:00
uncle lit
6b6534ed79 Update faq.md
update UK and EU frequency to 869.525MHz per Andy and Recrof
add steps to set frequency on repeater after flash and before disconnecting USB cable
2025-03-12 10:45:07 -07:00
oltaco
883f591ccd Merge branch 'ripplebiz:main' into faketec-support 2025-03-12 18:31:37 +11:00
fdlamotte
bb826a2634 Merge branch 'ripplebiz:main' into t1000e_ui 2025-03-11 20:38:52 +01:00
Scott Powell
04d85c687f Merge branch 'main' into dev 2025-03-11 20:09:59 +11:00
ripplebiz
9180e5c65f Merge pull request #83 from fdlamotte/configure-cpu-frequency-at-build-time-for-esp32
Add an ESP32_CPU_FREQ build flag to lower freq
2025-03-11 20:06:28 +11:00
Florent de Lamotte
dc4a139f88 resolve conflict 2025-03-11 09:18:50 +01:00
Florent de Lamotte
4a0f4f4b68 set cpu freq in ESP32Board.h 2025-03-11 09:11:14 +01:00
fdlamotte
d367f7d7bb Merge branch 'ripplebiz:main' into configure-cpu-frequency-at-build-time-for-esp32 2025-03-11 09:01:45 +01:00
Scott Powell
b94fed4e4e * companion: channel names 2025-03-11 17:58:12 +11:00
taco
1a21a08845 updated to MIT licensed board variant 2025-03-11 15:38:37 +11:00
Scott Powell
adf9b24867 * companion: channels now persisted. RESP_CODE_DEVICE_INFO now includes MAX_CONTACTS (div 2) and MAX_GROUP_CHANNELS 2025-03-11 15:31:38 +11:00
Scott Powell
8c68dbb6e9 * Companion: new CMD_GET_CHANNEL, CMD_SET_CHANNEL 2025-03-11 14:50:40 +11:00
Scott Powell
f9b2428dcd * BLE_NAME_PREFIX refactor 2025-03-11 13:25:48 +11:00
Scott Powell
8d12cfc9af Merge branch 'main' into dev 2025-03-11 13:20:52 +11:00
Scott Powell
4175be87ab Merge branch 'main' into dev 2025-03-11 13:19:13 +11:00
ripplebiz
7d572cf4e8 Merge pull request #74 from ddmunhoz/add-bool-meshcore-prefix
add: BLE_NAME_PREFIX flag
2025-03-11 13:02:54 +11:00
ripplebiz
877bef5408 Merge pull request #85 from recrof/dev
Enabled sx1262 boosted RX gain for all supported radios + platformio.ini: Made quoted -D flags more readable
2025-03-11 12:54:44 +11:00
ripplebiz
6fe5f9bed4 Merge pull request #71 from fdlamotte/t1000e_txpower
tx_power can be raised to 22dBm on LR1110
2025-03-11 12:43:26 +11:00
ripplebiz
ce55182752 Merge pull request #88 from LitBomb/patch-4
Update faq.md
2025-03-11 12:40:30 +11:00
taco
92bb6a844f added conditional to radio bringup for RA01-SH support on faketec 2025-03-11 09:34:52 +11:00
taco
c1faaf5e82 build fix to support RTC detection code 2025-03-11 09:34:52 +11:00
taco
027b7d83cb Added logic to companion_radio firmware to hopefully fix the radio bringup for Faketec with RA01-SH. 2025-03-11 09:34:52 +11:00
taco
a57053207f Added defines for SX126X_RXEN, SX126X_TXEN.
Updated build target to enable privkey import/export.
2025-03-11 09:34:52 +11:00
taco
8e793dc55e Faketec board support, including build targets 2025-03-11 09:34:52 +11:00
Florent
4cfdb0ef7c better handling of BTN_USER_PRESSED definition 2025-03-10 22:42:52 +01:00
uncle lit
648cdf6945 Update faq.md
update Canada to use USA frequency
add guide to add nodes to map
add guide to do OTA firmware update for nRF devices
update donation links
general text cleanup
2025-03-10 11:52:39 -07:00
Florent de Lamotte
7bb16cd7f3 enhancement on the UI and support for power off and status_led for t1000e 2025-03-10 18:11:15 +01:00
Scott Powell
5c72969e2c * repeater & room server: new CLI config "flood.max" 2025-03-10 23:28:19 +11:00
recrof
20198c9dbf Merge branch 'dev' of github.com:recrof/MeshCore into dev 2025-03-09 23:07:36 +01:00
recrof
de3f11d16c - Enabled sx1262 boosted RX gain for all supported radios
- Made quoted -D flags more readable
2025-03-09 22:57:31 +01:00
Florent
a706d90598 Add an ESP32_CPU_FREQ build flag to lower freq 2025-03-09 15:49:35 +01:00
ripplebiz
676ba6d066 Merge pull request #81 from recrof/dev
roles: t-echo, t114: +room_server; WSL3: +room_server, +repeater
2025-03-10 00:22:33 +11:00
Scott Powell
2cb742b100 ver bump to 1.2.2 2025-03-09 23:46:03 +11:00
Scott Powell
291b98cd56 updating RadioLib to ver 7.1.2 2025-03-09 23:44:34 +11:00
Scott Powell
a259d27cfe * trying setCRC(1) 2025-03-09 22:15:58 +11:00
Scott Powell
3778c0a8ff * repeater and room server: MESH_PACKET_LOGGING, now dumps RAW: rx packet contents
* Dispatcher: MESH_PACKET_LOGGING,  added " hash={packet-hash}"
2025-03-09 20:36:49 +11:00
Rastislav Vysoky
a16393e2d7 Merge branch 'ripplebiz:dev' into dev 2025-03-09 07:16:50 +01:00
Scott Powell
f77a6944f9 * PUSH_CODE_LOG_RX_DATA: is now just: {snr*4},{rssi},{raw-lora-packet} 2025-03-09 17:04:22 +11:00
Scott Powell
8f609524bd * companion: added new PUSH_CODE_LOG_RX_DATA (0x88) for inspecting all received packets 2025-03-09 15:41:32 +11:00
Scott Powell
c49e6ac37b Merge branch 'main' into dev
# Conflicts:
#	platformio.ini
2025-03-09 14:56:39 +11:00
ripplebiz
6771b0e837 Merge pull request #78 from awolden/awolden/enable-SSD13060-lilygo-tlora
Enable SSD1306 display class for LilyGo_TLora_V2_1_1_6
2025-03-09 14:43:54 +11:00
Alex Wolden
3dea712d37 Fix heltec v3.2 pin polarity reversal 2025-03-08 11:21:19 -08:00
Scott Powell
9b5a294695 * T1000e battery measure fix 2025-03-08 20:18:15 +11:00
Rastislav Vysoky
9844296643 Merge branch 'ripplebiz:dev' into dev 2025-03-08 10:05:27 +01:00
Scott Powell
5acfe52417 * new build option: SX126X_RX_BOOSTED_GAIN 2025-03-08 19:59:07 +11:00
Scott Powell
2889867c4c * Dispatcher: added guard for packet payload size too large 2025-03-08 19:38:36 +11:00
Rastislav Vysoky
b1a5badf98 added room server roles to t114 and t-echo; added repeater and room server roles to WSL3; unified json intendations in /boards 2025-03-08 09:15:51 +01:00
ripplebiz
115deda8e8 Merge pull request #70 from recrof/dev
added new board: Station G2; fix: added t114 and t-echo boards to uf2conv release workflow
2025-03-08 15:10:49 +11:00
Scott Powell
87d4285cf1 * doc updates 2025-03-08 13:40:39 +11:00
Alex Wolden
37652459a1 Enable SSD1306 display class for LilyGo_TLora_V2_1_1_6 2025-03-07 14:30:11 -08:00
Diego Munhoz
a5fb3acc9b add: BLE_NAME_PREFIX flag 2025-03-07 11:41:53 -06:00
Rastislav Vysoky
acac20dc89 Added basic support for Station G2 2025-03-07 15:34:00 +01:00
Florent de Lamotte
708065a0ba tx_power can be raised to 22dBm on LR1110 2025-03-07 13:52:47 +01:00
Rastislav Vysoky
ae7bf7eae2 Merge branch 'ripplebiz:dev' into dev 2025-03-07 13:42:56 +01:00
Rastislav Vysoky
477f2e1d81 fix: added t114 and t-echo boards to uf2conv release workflow 2025-03-07 13:17:46 +01:00
Scott Powell
808d3933c1 Version bump to v1.2.1 2025-03-07 22:01:30 +11:00
Scott Powell
ae8fb5d9b1 * Heltec v3.2 VEXT fix
* Heltec T114 LED fix, (now flashes with LoRa TX)
2025-03-07 21:37:05 +11:00
Scott Powell
790898dbc5 * companion: better incoming ACK processing (match prev attempts) 2025-03-07 15:09:29 +11:00
Scott Powell
e534e1b529 * companion: FIRMWARE_VER_CODE now bumped to 3.
* companion: new RESP_CODE_CONTACT_MSG_RECV_V3, and _CHANNEL_MSG_RECV_V3. (now with packet SNR included)
2025-03-07 14:17:37 +11:00
Scott Powell
544adec2b6 * refactor Packet::_snr to single byte 2025-03-07 12:32:23 +11:00
Scott Powell
b2fcc692ea * TRACE packet logging fix 2025-03-07 12:24:18 +11:00
Scott Powell
b03aac18c0 Merge branch 'dev' into trace
# Conflicts:
#	src/Dispatcher.cpp
#	src/Mesh.cpp
#	src/helpers/BaseChatMesh.cpp
2025-03-07 12:14:26 +11:00
Scott Powell
0db15db625 * new Packet type: PAYLOAD_TYPE_TRACE 2025-02-17 19:22:31 +11:00
61 changed files with 2942 additions and 1170 deletions

View File

@@ -25,10 +25,11 @@ MeshCore provides the ability to create wireless mesh networks, similar to Mesht
## 🚀 How to Get Started
Flash the Firmware: Download the pre-built firmware binary for Heltec V3 and flash it using Adafruit ESPTool.
Install [PlatformIO](https://docs.platformio.org) in Visual Studio Code (optional for developers who want to modify the firmware).
Andy Kirby has published a very useful [intro video](https://www.youtube.com/watch?v=t1qne8uJBAc) which explains the steps for beginners.
For developers, install [PlatformIO](https://docs.platformio.org) in Visual Studio Code.
Download & Open the MeshCore repository.
Select a Sample Application: Choose from chat, ping, repeater, or admin test tools.
Select a Sample Application: Choose from chat, repeater, other example app.
Monitor & Communicate using the Serial Monitor (e.g., Serial USB Terminal on Android).
📁 Included Example Applications
@@ -36,8 +37,6 @@ Monitor & Communicate using the Serial Monitor (e.g., Serial USB Terminal on And
* 📡 Simple Repeater: Extends network coverage by relaying messages.
* 📡 Companion Radio: For use with an external chat app, over BLE or USB.
* 📡 Room Server: A simple BBS server for shared Posts.
* 📡 Ping Client, Ping Server & Client: Basic client/server example.
* 📡 Test Admin: Monitors and manages repeaters remotely.
## 🛠 Hardware Compatibility
@@ -49,10 +48,18 @@ MeshCore is designed for use with:
* LilyGo T3S3
* Heltec T114
* Station G2
* Sensecap T1000e
* Heltec V2
* LilyGo TLora32 v1.6
## 📜 License
MeshCore is open-source software released under the MIT License. You are free to use, modify, and distribute it for personal and commercial projects.
## Contributing
Please submit PR's using 'dev' as the base branch!
For minor changes just submit your PR and I'll try to review it, but for anything more 'impactful' please open an Issue first and start a discussion. Is better to sound out what it is you want to achieve first, and try to come to a consensus on what the best approach is, especially when it impacts the structure or architecture of this codebase.
## 📞 Get Support
Check out the GitHub Issues page to report bugs or request features.

View File

@@ -0,0 +1,78 @@
{
"build": {
"arduino":{
"ldscript": "nrf52840_s140_v6.ld"
},
"core": "nRF5",
"cpu": "cortex-m4",
"extra_flags": "-DARDUINO_NRF52840_FEATHER -DNRF52840_XXAA",
"f_cpu": "64000000L",
"hwids": [
[
"0x239A",
"0x00B3"
],
[
"0x239A",
"0x8029"
],
[
"0x239A",
"0x0029"
],
[
"0x239A",
"0x002A"
],
[
"0x239A",
"0x802A"
]
],
"usb_product": "ProMicro NRF52840",
"mcu": "nrf52840",
"variant": "promicro_nrf52840",
"variants_dir": "variants",
"bsp": {
"name": "adafruit"
},
"softdevice": {
"sd_flags": "-DS140",
"sd_name": "s140",
"sd_version": "6.1.1",
"sd_fwid": "0x00B6"
},
"bootloader": {
"settings_addr": "0xFF000"
}
},
"connectivity": [
"bluetooth"
],
"debug": {
"jlink_device": "nRF52840_xxAA",
"svd_path": "nrf52840.svd"
},
"frameworks": [
"arduino",
"zephyr"
],
"name": "ProMicro NRF52840",
"upload": {
"maximum_ram_size": 248832,
"maximum_size": 815104,
"speed": 115200,
"protocol": "nrfutil",
"protocols": [
"jlink",
"nrfjprog",
"nrfutil",
"stlink"
],
"use_1200bps_touch": true,
"require_upload_port": true,
"wait_for_upload_port": true
},
"url": "https://www.nologo.tech/en/product/otherboard/NRF52840.html",
"vendor": "Nologo"
}

43
boards/station-g2.json Normal file
View File

@@ -0,0 +1,43 @@
{
"build": {
"arduino": {
"ldscript": "esp32s3_out.ld",
"memory_type": "qio_opi"
},
"core": "esp32",
"extra_flags": [
"-DBOARD_HAS_PSRAM",
"-DARDUINO_USB_CDC_ON_BOOT=1",
"-DARDUINO_USB_MODE=0",
"-DARDUINO_RUNNING_CORE=1",
"-DARDUINO_EVENT_RUNNING_CORE=0"
],
"f_cpu": "240000000L",
"f_flash": "80000000L",
"flash_mode": "qio",
"hwids": [["0x303A", "0x1001"]],
"mcu": "esp32s3",
"variant": "esp32s3"
},
"connectivity": [
"wifi"
],
"debug": {
"default_tool": "esp-builtin",
"onboard_tools": ["esp-builtin"],
"openocd_target": "esp32s3.cfg"
},
"frameworks": ["arduino", "espidf"],
"name": "BQ Station G2",
"upload": {
"flash_size": "16MB",
"maximum_ram_size": 327680,
"maximum_size": 16777216,
"use_1200bps_touch": true,
"wait_for_upload_port": true,
"require_upload_port": true,
"speed": 921600
},
"url": "https://wiki.uniteng.com/en/meshtastic/station-g2",
"vendor": "BQ Consulting"
}

View File

@@ -1,62 +1,62 @@
{
"build": {
"arduino": {
"ldscript": "nrf52840_s140_v6.ld"
},
"core": "nRF5",
"cpu": "cortex-m4",
"extra_flags": "-DARDUINO_NRF52840_PCA10056 -DNRF52840_XXAA",
"f_cpu": "64000000L",
"hwids": [
[
"0x239A",
"0x8029"
]
],
"usb_product": "NRF52 DK",
"mcu": "nrf52840",
"variant": "pca10056",
"bsp": {
"name": "adafruit"
},
"softdevice": {
"sd_flags": "-DS140",
"sd_name": "s140",
"sd_version": "6.1.1",
"sd_fwid": "0x00B6"
},
"bootloader": {
"settings_addr": "0xFF000"
}
},
"connectivity": [
"bluetooth"
],
"debug": {
"jlink_device": "nRF52840_xxAA",
"onboard_tools": [
"jlink"
],
"svd_path": "nrf52840.svd"
},
"frameworks": [
"arduino"
],
"name": "LilyGo T-ECHO",
"upload": {
"maximum_ram_size": 248832,
"maximum_size": 815104,
"require_upload_port": true,
"speed": 115200,
"protocol": "jlink",
"protocols": [
"jlink",
"nrfjprog",
"stlink",
"cmsis-dap",
"blackmagic"
]
},
"url": "https://os.mbed.com/platforms/Nordic-nRF52840-DK/",
"vendor": "Nordic"
"build": {
"arduino": {
"ldscript": "nrf52840_s140_v6.ld"
},
"core": "nRF5",
"cpu": "cortex-m4",
"extra_flags": "-DARDUINO_NRF52840_PCA10056 -DNRF52840_XXAA",
"f_cpu": "64000000L",
"hwids": [
[
"0x239A",
"0x8029"
]
],
"usb_product": "NRF52 DK",
"mcu": "nrf52840",
"variant": "pca10056",
"bsp": {
"name": "adafruit"
},
"softdevice": {
"sd_flags": "-DS140",
"sd_name": "s140",
"sd_version": "6.1.1",
"sd_fwid": "0x00B6"
},
"bootloader": {
"settings_addr": "0xFF000"
}
},
"connectivity": [
"bluetooth"
],
"debug": {
"jlink_device": "nRF52840_xxAA",
"onboard_tools": [
"jlink"
],
"svd_path": "nrf52840.svd"
},
"frameworks": [
"arduino"
],
"name": "LilyGo T-ECHO",
"upload": {
"maximum_ram_size": 248832,
"maximum_size": 815104,
"require_upload_port": true,
"speed": 115200,
"protocol": "jlink",
"protocols": [
"jlink",
"nrfjprog",
"stlink",
"cmsis-dap",
"blackmagic"
]
},
"url": "https://os.mbed.com/platforms/Nordic-nRF52840-DK/",
"vendor": "Nordic"
}

View File

@@ -1,45 +1,45 @@
{
"build": {
"arduino": {
"ldscript": "esp32s3_out.ld",
"partitions": "default.csv",
"memory_type": "qio_qspi"
},
"core": "esp32",
"extra_flags": [
"-DARDUINO_LILYGO_T3_S3_V1_X",
"-DBOARD_HAS_PSRAM",
"-DARDUINO_USB_CDC_ON_BOOT=1",
"-DARDUINO_RUNNING_CORE=1",
"-DARDUINO_EVENT_RUNNING_CORE=1",
"-DARDUINO_USB_MODE=1"
],
"f_cpu": "240000000L",
"f_flash": "80000000L",
"flash_mode": "qio",
"mcu": "esp32s3",
"variant": "esp32s3"
"build": {
"arduino": {
"ldscript": "esp32s3_out.ld",
"partitions": "default.csv",
"memory_type": "qio_qspi"
},
"connectivity": [
"wifi"
"core": "esp32",
"extra_flags": [
"-DARDUINO_LILYGO_T3_S3_V1_X",
"-DBOARD_HAS_PSRAM",
"-DARDUINO_USB_CDC_ON_BOOT=1",
"-DARDUINO_RUNNING_CORE=1",
"-DARDUINO_EVENT_RUNNING_CORE=1",
"-DARDUINO_USB_MODE=1"
],
"debug": {
"openocd_target": "esp32s3.cfg"
},
"frameworks": [
"arduino",
"espidf"
],
"name": "LilyGo T3-S3 Radio",
"upload": {
"flash_size": "4MB",
"maximum_ram_size": 327680,
"maximum_size": 4194304,
"use_1200bps_touch": true,
"wait_for_upload_port": true,
"require_upload_port": true,
"speed": 460800
},
"url": "https://www.lilygo.cc",
"vendor": "LilyGo"
"f_cpu": "240000000L",
"f_flash": "80000000L",
"flash_mode": "qio",
"mcu": "esp32s3",
"variant": "esp32s3"
},
"connectivity": [
"wifi"
],
"debug": {
"openocd_target": "esp32s3.cfg"
},
"frameworks": [
"arduino",
"espidf"
],
"name": "LilyGo T3-S3 Radio",
"upload": {
"flash_size": "4MB",
"maximum_ram_size": 327680,
"maximum_size": 4194304,
"use_1200bps_touch": true,
"wait_for_upload_port": true,
"require_upload_port": true,
"speed": 460800
},
"url": "https://www.lilygo.cc",
"vendor": "LilyGo"
}

View File

@@ -57,8 +57,8 @@ build_firmware() {
pio run -t mergebin -e $1
fi
# build .uf2 for RAK_4631 and t1000e
if [[ $1 == *"RAK_4631"* || $1 == *"t1000e"* ]]; then
# build .uf2 for nrf52 boards
if [[ $1 == *"RAK_4631"* || $1 == *"t1000e"* || $1 == *"t114"* || $1 == *"T-Echo"* ]]; then
python bin/uf2conv/uf2conv.py .pio/build/$1/firmware.hex -c -o .pio/build/$1/firmware.uf2 -f 0xADA52840
fi

View File

@@ -1,6 +1,9 @@
# MeshCore-FAQ
A list of frequently-asked questions and answers for MeshCore
The current version of this MeshCore FAQ is at https://github.com/ripplebiz/MeshCore/blob/main/docs/faq.md.
This MeshCore FAQ is also mirrored at https://github.com/LitBomb/MeshCore-FAQ and might have newer updates if pull requests on Scott's MeshCore repo are not approved yet.
author: https://github.com/LitBomb
---
@@ -25,6 +28,8 @@ Anyone is able to build anything they like on top of MeshCore without paying any
Firmware Flasher: https://flasher.meshcore.co.uk/
Phone Client Applications: https://meshcore.co.uk/apps.html
MeshCore Fimrware Github: https://github.com/ripplebiz/MeshCore
NOTE: Andy Kirby has a very useful [intro video](https://www.youtube.com/watch?v=t1qne8uJBAc) for beginners.
You need LoRa hardware devices to run MeshCore firmware as clients or server (repeater and room server).
@@ -78,6 +83,12 @@ If you have two supported devices, and there are not many MeshCore users near yo
If you have two supported devices, and there are other MeshcCore users near by, you can flash one of your devices with BLE Companion firmware, and flash another supported device to repeater firmware. Place the repeater high above ground o extend your MeshCore network's reach.
After you flashed the latest firmware onto your repeater device, keep the device connected to your computer via USB serial, use the console feature on the web flasher and set the frequency for your region or country, so your client can remote administer the rpeater or room server over RF:
`set freq {frequency}`
The repeater and room server CLI reference is here: https://github.com/ripplebiz/MeshCore/wiki/Repeater-&-Room-Server-CLI-Reference
If you have more supported devices, you can use your additional deivces with the room server firmware.
### Q: Does MeshCore cost any money?
@@ -91,10 +102,10 @@ The T-Deck firmware is free to download and most features are available without
### Q: What frequencies are supported by MeshCore?
**A:** It supports the 868MHz range in the UK/EU and the 915MHz range in New Zealand, Australia, and the USA. Countries and regions in these two frequency ranges are also supported. The firmware and client allow users to set their preferred frequency.
- Australia and New Zealand are using **915.8MHz**
- UK and EU are gravitating toward **867.5MHz**
- There are discussions on discord for UK to move to 869.525MHz (https://discord.com/channels/826570251612323860/1330643963501351004/1342554454498742374)
- USA is gravitating toward **910.525MHz**
- Australia and New Zealand are on **915.8MHz**
- UK and EU are on **869.525MHz**
- Canada and USA are on **910.525MHz**
- For other regions and countries, please check your local LoRa frequency
the rest of the radio settings are the same for all frequencies:
- Spread Factor (SF): 10
@@ -126,11 +137,11 @@ MeshCore clients only advertise themselves when the user initiates it. A repeate
### Q: How do you configure a repeater or a room server?
**A:** One of these servers can be administered with one of the options below:
- Connect the server device through a USB serial connection to a computer running Chrome on this site:
<https://googlechromelabs.github.io/serial-terminal/>
- Connect the server device using a USB cable to a computer running Chrome on https://flasher.meshcore.co.uk/, then use the `console` feature to connect to the device
- this is necessary to set the server device's frequency if it doesn't match the frequency for your local region or country
- MeshCore smart device clients have the ability to remotely administer servers.
- A T-Deck running unlocked/registered MeshCore firmware. Remote server administration is enabled through registering your T-Deck with Ripple Radios. It is one of the ways to support MeshCore development. You can register your T-Deck at:
<https://buymeacoffee.com/ripplebiz/e/249834>
- MeshCore smart device clients may have the ability to remotely administer servers in the future.
### Q: Do I need to set the location for a repeater?
**A:** With location set for a repeater, it can show up on a MeshCore map in the future. Set location with the following commands:
@@ -226,12 +237,23 @@ Lowering the spreading factor makes it more difficult for the gateway to receive
So it's balancing act between speed of the transmission and resistance to noise.
things network is mainly focused on LoRaWAN, but the LoRa low-level stuff still checks out for any LoRa project
### Q: What happens when a node learns a route via a mobile repeater, and that repeater is gone?
**A:** If you used to reach a node through a repeater and the repeater is no longer reachable, the client will send the message using the existing (but now broken) known path, the message will fail after 3 retries, and the app will reset the path and send the message as flood on the last retry by default. This can be turned off in settings. If the destination is reachable directly or through another repeater, the new path will be used going forward. Or you can set the path manually if you know a specific repeater to use to reach that destination.
In the case if users are moving around frequently, and the paths are breaking, they just see the phone client retries and revert to flood to attempt to reestablish a path.
### Q: Is MeshCore open source?
**A:** Most of the firmware is freely available. Everything is open source except the T-Deck firmware and Liam's native mobile apps.
- Firmware repo: <https://github.com/ripplebiz/MeshCore>
### Q: How can I support MeshCore?
**A:** Provide your honest feedback on GitHub and on AndyKirby's Discord server <http://discord.com/invite/H62Re4DCeD>. Spread the word of MeshCore to your friends and communities; help them get started with MeshCore. Support MeshCore development at <https://buymeacoffee.com/ripplebiz>.
**A:** Provide your honest feedback on GitHub and on AndyKirby's Discord server <http://discord.com/invite/H62Re4DCeD>. Spread the word of MeshCore to your friends and communities; help them get started with MeshCore. Support Scott's MeshCore development at <https://buymeacoffee.com/ripplebiz>.
Support Liam Cottle's smartphone client development by unlocking the server administration wait gate with in-app purchase
Support Rastislav Vysoky (recrof)'s flasher web site and the map web site development through [PayPal](https://www.paypal.com/donate/?business=DREHF5HM265ES&no_recurring=0&item_name=If+you+enjoy+my+work%2C+you+can+support+me+here%3A&currency_code=EUR) or [Revolut](https://revolut.me/recrof)
### Q: How do I build MeshCore firmware from source?
**A:** See instructions here:
@@ -250,6 +272,12 @@ Javascript: https://github.com/liamcottle/meshcore.js
### Q: Does MeshCore support ATAK
**A:** ATAK is not currently on MeshCore's roadmap.
### Q: How do I add a node to the [MeshCore Map]([url](https://meshcore.co.uk/map.html))
**A:** From the smartphone app, connect to a BLE Companion radio
- To add the BLE Companion radio your smartphone is connected to to the map, tap the `advert` icon, then tap `Advert (To Clipboard)`.
- To add a Repeater or Room Server to the map, tap the 3 dots next to the Repeater or Room Server you want to add to the map, then tap `Share (To Clipboard)`.
- Go to the [MeshCore Map web site]([url](https://meshcore.co.uk/map.html)), tap the plus sign on the lower right corner and paste in the meshcore://... blob, then tap `Add Node`
---
@@ -274,7 +302,74 @@ 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 WiFi and Bluetooth connectivty. 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.
---
## Other Questions:
### Q: How to Update repeater and room server firmware over the air?
**A:** Only nRF-based RAK4631 and Heltec T114 OTA firmware update are verified using nRF smartphone app. Lilygo T-Echo doesn't work currently.
You can update repeater and room server firmware with a bluetooth connection between your smartphone and your LoRa radio using the nRF app.
1. Download the ZIP file for the specific node from the web flasher to your smartphone
2. On the phone client, log on to the repeater as administrator (default password is `password`) to issue the `start ota`command to the repeater or room server to get the device into OTA DFU mode
![image](https://github.com/user-attachments/assets/889bb81b-7214-4a1c-955a-396b5a05d8ad)
1. `start ota` can be initiated from USB serial console on the web flasher page or a T-Deck
4. On the smartphone, download and run the nRF app and scan for Bluetooth devices
5. Connect to the repeater/room server node you want to update
1. nRF app is available on both Android and iOS
**Android continues after the iOS section:**
**iOS continues here:**
5. Once connected successfully, a `DFU` icon ![Pasted image 20250309173039](https://github.com/user-attachments/assets/af7a9f78-8739-4946-b734-02bade9c8e71)
appears in the top right corner of the app![Pasted image 20250309171919](https://github.com/user-attachments/assets/08007ec8-4924-49c1-989f-ca2611e78793)
6. Scroll down to change the `PRN(s)` number:
![Pasted image 20250309190158](https://github.com/user-attachments/assets/11f69cdd-12f3-4696-a6fc-14a78c85fe32)
- For the T114, change the number of packets `(PRN(s)` to 8
- For RAK, it can be 10, but it also works on 8.
7. Click the `DFU` icon ![Pasted image 20250309173039](https://github.com/user-attachments/assets/af7a9f78-8739-4946-b734-02bade9c8e71), select the type of file to upload (choose ZIP), then select the ZIP file that was downloaded earlier from the web flasher
8. The upload process will start now. If everything goes well, the node resets and is flashed successfully.
![Pasted image 20250309190342](https://github.com/user-attachments/assets/a60e25d0-33b8-46cf-af90-20a7d8ac2adb)
**Android steps continues below:**
1. on the top left corner of the nRF Connect app on Android, tap the 3-bar hamburger menu, then `Settings`, then `nRF5 DFU Options`
![Android nRF Hamberger](https://github.com/user-attachments/assets/ea6dfeef-9367-4830-bd70-1441d517c706)
![Android nRF Settings](https://github.com/user-attachments/assets/c63726bf-cecd-4987-be68-afb6358c7190)
![Android nRF DFU Options](https://github.com/user-attachments/assets/b20e872f-5122-41d9-90df-0215cff5fbc9)
2. Change `Number of packets` to `10` for RAK, `8` for Heltec T114
![Android nRF Number of Packets](https://github.com/user-attachments/assets/c092adaf-4cb3-460b-b7ef-8d7f450d602b)
3. Go back to the main screen
4. Your LoRa device should already ben in DFU mode from previous steps
5. tap `SCANNER` and then `SCAN` to find the device you want to update, tap `CONNECT`
![Android nRF Scanner Scan Connect](https://github.com/user-attachments/assets/37218717-f167-48b6-a6ca-93d132ef77ca)
6. On the top left corner of the nRF Connect app, tap the `DFU` icon next to the three dots
![Android nRF DFU](https://github.com/user-attachments/assets/1ec3b818-bf0c-461f-8fdf-37c41a63cafa)
7. Choose `Distribution packet (ZIP)` and then `OK`
![Android nRF Distribution Packet (ZIP)](https://github.com/user-attachments/assets/e65f5616-9793-44f5-95c0-a3eb15aa7152)
8. Choose the firmware file in ZIP formate that you downloaded earlier from the MeshCore web flasher, update will start as soon as you tap the file
![Android nRF FW Updating](https://github.com/user-attachments/assets/0814d123-85ce-4c87-90a7-e1a25dc71900)
9. When the update process is done, the device will disconnect from nRF app and the LoRa device is updated
---

View File

@@ -4,6 +4,10 @@
#define AUTO_OFF_MILLIS 15000 // 15 seconds
#ifndef USER_BTN_PRESSED
#define USER_BTN_PRESSED LOW
#endif
// 'meshcore', 128x13px
static const uint8_t meshcore_logo [] PROGMEM = {
0x3c, 0x01, 0xe3, 0xff, 0xc7, 0xff, 0x8f, 0x03, 0x87, 0xfe, 0x1f, 0xfe, 0x1f, 0xfe, 0x1f, 0xfe,
@@ -21,14 +25,23 @@ 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(const char* node_name, const char* build_date, uint32_t pin_code) {
_prevBtnState = HIGH;
void UITask::begin(DisplayDriver* display, const char* node_name, const char* build_date, uint32_t pin_code) {
_display = display;
_auto_off = millis() + AUTO_OFF_MILLIS;
clearMsgPreview();
_node_name = node_name;
_build_date = build_date;
_pin_code = pin_code;
_display->turnOn();
if (_display != NULL) {
_display->turnOn();
}
}
void UITask::msgRead(int msgcount) {
_msgcount = msgcount;
if (msgcount == 0) {
clearMsgPreview();
}
}
void UITask::clearMsgPreview() {
@@ -36,7 +49,9 @@ void UITask::clearMsgPreview() {
_msg[0] = 0;
}
void UITask::showMsgPreview(uint8_t path_len, const char* from_name, const char* text) {
void UITask::newMsg(uint8_t path_len, const char* from_name, const char* text, int msgcount) {
_msgcount = msgcount;
if (path_len == 0xFF) {
sprintf(_origin, "(F) %s", from_name);
} else {
@@ -44,11 +59,15 @@ void UITask::showMsgPreview(uint8_t path_len, const char* from_name, const char*
}
StrHelper::strncpy(_msg, text, sizeof(_msg));
if (!_display->isOn()) _display->turnOn();
_auto_off = millis() + AUTO_OFF_MILLIS; // extend the auto-off timer
if (_display != NULL) {
if (!_display->isOn()) _display->turnOn();
_auto_off = millis() + AUTO_OFF_MILLIS; // extend the auto-off timer
}
}
void UITask::renderCurrScreen() {
if (_display == NULL) return; // assert() ??
char tmp[80];
if (_origin[0] && _msg[0]) {
// render message preview
@@ -61,9 +80,10 @@ void UITask::renderCurrScreen() {
_display->setCursor(0, 24);
_display->print(_msg);
//_display->setCursor(100, 9); TODO
//_display->setTextSize(2);
//_display->printf("%d", msgs);
_display->setCursor(100, 9);
_display->setTextSize(2);
sprintf(tmp, "%d", _msgcount);
_display->print(tmp);
} else {
// render 'home' screen
_display->drawXbm(0, 0, meshcore_logo, 128, 13);
@@ -87,24 +107,72 @@ void UITask::renderCurrScreen() {
}
}
void UITask::loop() {
if (millis() >= _next_read) {
int btnState = digitalRead(PIN_USER_BTN);
if (btnState != _prevBtnState) {
if (btnState == LOW) { // pressed?
if (_display->isOn()) {
clearMsgPreview();
} else {
_display->turnOn();
}
_auto_off = millis() + AUTO_OFF_MILLIS; // extend auto-off timer
void UITask::userLedHandler() {
#ifdef PIN_STATUS_LED
static int state = 0;
static int next_change = 0;
int cur_time = millis();
if (cur_time > next_change) {
if (state == 0) {
state = 1; // led on, short = unread msg
if (_msgcount > 0) {
next_change = cur_time + 500;
} else {
next_change = cur_time + 2000;
}
} else {
state = 0;
if (_board->getBattMilliVolts() > 3800) {
next_change = cur_time + 2000;
} else {
next_change = cur_time + 4000; // 4s blank if bat level low
}
_prevBtnState = btnState;
}
_next_read = millis() + 100; // 10 reads per second
digitalWrite(PIN_STATUS_LED, state);
}
#endif
}
if (_display->isOn()) {
void UITask::buttonHandler() {
#ifdef PIN_USER_BTN
static int prev_btn_state = !USER_BTN_PRESSED;
static unsigned long btn_state_change_time = 0;
static unsigned long next_read = 0;
int cur_time = millis();
if (cur_time >= next_read) {
int btn_state = digitalRead(PIN_USER_BTN);
if (btn_state != prev_btn_state) {
if (btn_state == USER_BTN_PRESSED) { // pressed?
if (_display != NULL) {
if (_display->isOn()) {
clearMsgPreview();
} else {
_display->turnOn();
}
_auto_off = cur_time + AUTO_OFF_MILLIS; // extend auto-off timer
}
} else { // unpressed ? check pressed time ...
if ((cur_time - btn_state_change_time) > 5000) {
#ifdef PIN_STATUS_LED
digitalWrite(PIN_STATUS_LED, LOW);
delay(10);
#endif
_board->powerOff();
}
}
btn_state_change_time = millis();
prev_btn_state = btn_state;
}
next_read = millis() + 100; // 10 reads per second
}
#endif
}
void UITask::loop() {
buttonHandler();
userLedHandler();
if (_display != NULL && _display->isOn()) {
if (millis() >= _next_refresh) {
_display->startFrame();
renderCurrScreen();

View File

@@ -1,25 +1,37 @@
#pragma once
#include <MeshCore.h>
#include <helpers/ui/DisplayDriver.h>
#include <stddef.h>
class UITask {
DisplayDriver* _display;
unsigned long _next_read, _next_refresh, _auto_off;
int _prevBtnState;
mesh::MainBoard* _board;
unsigned long _next_refresh, _auto_off;
bool _connected;
uint32_t _pin_code;
const char* _node_name;
const char* _build_date;
char _origin[62];
char _msg[80];
int _msgcount;
void renderCurrScreen();
void buttonHandler();
void userLedHandler();
public:
UITask(DisplayDriver& display) : _display(&display) { _next_read = _next_refresh = 0; _connected = false; }
void begin(const char* node_name, const char* build_date, uint32_t pin_code);
UITask(mesh::MainBoard* board) : _board(board), _display(NULL) {
_next_refresh = 0;
_connected = false;
}
void begin(DisplayDriver* display, const char* node_name, const char* build_date, uint32_t pin_code);
void setHasConnection(bool connected) { _connected = connected; }
bool hasDisplay() const { return _display != NULL; }
void clearMsgPreview();
void showMsgPreview(uint8_t path_len, const char* from_name, const char* text);
void msgRead(int msgcount);
void newMsg(uint8_t path_len, const char* from_name, const char* text, int msgcount);
void loop();
};
};

View File

@@ -46,6 +46,10 @@
#define OFFLINE_QUEUE_SIZE 16
#endif
#ifndef BLE_NAME_PREFIX
#define BLE_NAME_PREFIX "MeshCore-"
#endif
#include <helpers/BaseChatMesh.h>
#define SEND_TIMEOUT_BASE_MILLIS 500
@@ -92,17 +96,34 @@
#include <helpers/nrf52/TechoBoard.h>
#include <helpers/CustomSX1262Wrapper.h>
static TechoBoard board;
#elif defined(LILYGO_TBEAM)
#include <helpers/TBeamBoard.h>
#include <helpers/CustomSX1276Wrapper.h>
static TBeamBoard board;
#elif defined(FAKETEC)
#include <helpers/nrf52/faketecBoard.h>
#include <helpers/CustomSX1262Wrapper.h>
#include <helpers/CustomLLCC68Wrapper.h>
static faketecBoard board;
#else
#error "need to provide a 'board' object"
#endif
#ifdef DISPLAY_CLASS
#include "UITask.h"
#include <helpers/ui/SSD1306Display.h>
static DISPLAY_CLASS display;
#define HAS_UI
#endif
#if defined(HAS_UI)
#include "UITask.h"
static UITask ui_task(display);
static UITask ui_task(&board);
#endif
// Believe it or not, this std C function is busted on some platforms!
@@ -117,14 +138,14 @@ static uint32_t _atoi(const char* sp) {
/*------------ Frame Protocol --------------*/
#define FIRMWARE_VER_CODE 2
#define FIRMWARE_VER_CODE 3
#ifndef FIRMWARE_BUILD_DATE
#define FIRMWARE_BUILD_DATE "7 Mar 2025"
#define FIRMWARE_BUILD_DATE "19 Mar 2025"
#endif
#ifndef FIRMWARE_VERSION
#define FIRMWARE_VERSION "v1.2.0"
#define FIRMWARE_VERSION "v1.4.0"
#endif
#define CMD_APP_START 1
@@ -157,6 +178,13 @@ static uint32_t _atoi(const char* sp) {
#define CMD_HAS_CONNECTION 28
#define CMD_LOGOUT 29 // 'Disconnect'
#define CMD_GET_CONTACT_BY_KEY 30
#define CMD_GET_CHANNEL 31
#define CMD_SET_CHANNEL 32
#define CMD_SIGN_START 33
#define CMD_SIGN_DATA 34
#define CMD_SIGN_FINISH 35
#define CMD_SEND_TRACE_PATH 36
#define CMD_SET_DEVICE_PIN 37
#define RESP_CODE_OK 0
#define RESP_CODE_ERR 1
@@ -165,8 +193,8 @@ static uint32_t _atoi(const char* sp) {
#define RESP_CODE_END_OF_CONTACTS 4 // last reply to CMD_GET_CONTACTS
#define RESP_CODE_SELF_INFO 5 // reply to CMD_APP_START
#define RESP_CODE_SENT 6 // reply to CMD_SEND_TXT_MSG
#define RESP_CODE_CONTACT_MSG_RECV 7 // a reply to CMD_SYNC_NEXT_MESSAGE
#define RESP_CODE_CHANNEL_MSG_RECV 8 // a reply to CMD_SYNC_NEXT_MESSAGE
#define RESP_CODE_CONTACT_MSG_RECV 7 // a reply to CMD_SYNC_NEXT_MESSAGE (ver < 3)
#define RESP_CODE_CHANNEL_MSG_RECV 8 // a reply to CMD_SYNC_NEXT_MESSAGE (ver < 3)
#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
@@ -174,6 +202,11 @@ static uint32_t _atoi(const char* sp) {
#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
#define RESP_CODE_CONTACT_MSG_RECV_V3 16 // a reply to CMD_SYNC_NEXT_MESSAGE (ver >= 3)
#define RESP_CODE_CHANNEL_MSG_RECV_V3 17 // a reply to CMD_SYNC_NEXT_MESSAGE (ver >= 3)
#define RESP_CODE_CHANNEL_INFO 18 // a reply to CMD_GET_CHANNEL
#define RESP_CODE_SIGN_START 19
#define RESP_CODE_SIGNATURE 20
// these are _pushed_ to client app at any time
#define PUSH_CODE_ADVERT 0x80
@@ -184,9 +217,20 @@ static uint32_t _atoi(const char* sp) {
#define PUSH_CODE_LOGIN_SUCCESS 0x85
#define PUSH_CODE_LOGIN_FAIL 0x86
#define PUSH_CODE_STATUS_RESPONSE 0x87
#define PUSH_CODE_LOG_RX_DATA 0x88
#define PUSH_CODE_TRACE_DATA 0x89
#define ERR_CODE_UNSUPPORTED_CMD 1
#define ERR_CODE_NOT_FOUND 2
#define ERR_CODE_TABLE_FULL 3
#define ERR_CODE_BAD_STATE 4
#define ERR_CODE_FILE_IO_ERROR 5
#define ERR_CODE_ILLEGAL_ARG 6
/* -------------------------------------------------------------------------------------- */
#define MAX_SIGN_DATA_LEN (8*1024) // 8K
struct NodePrefs { // persisted to file
float airtime_factor;
char node_name[32];
@@ -208,18 +252,17 @@ class MyMesh : public BaseChatMesh {
RADIO_CLASS* _phy;
IdentityStore* _identity_store;
NodePrefs _prefs;
uint32_t expected_ack_crc; // TODO: keep table of expected ACKs
uint32_t pending_login;
uint32_t pending_status;
mesh::GroupChannel* _public;
BaseSerialInterface* _serial;
unsigned long last_msg_sent;
ContactsIterator _iter;
uint32_t _iter_filter_since;
uint32_t _most_recent_lastmod;
uint32_t _active_ble_pin;
bool _iter_started;
uint8_t app_target_ver;
uint8_t* sign_data;
uint32_t sign_data_len;
uint8_t cmd_frame[MAX_FRAME_SIZE+1];
uint8_t out_frame[MAX_FRAME_SIZE+1];
@@ -230,6 +273,14 @@ class MyMesh : public BaseChatMesh {
int offline_queue_len;
Frame offline_queue[OFFLINE_QUEUE_SIZE];
struct AckTableEntry {
unsigned long msg_sent;
uint32_t ack;
};
#define EXPECTED_ACK_TABLE_SIZE 8
AckTableEntry expected_ack_table[EXPECTED_ACK_TABLE_SIZE]; // circular table
int next_ack_idx;
void loadMainIdentity(mesh::RNG& trng) {
if (!_identity_store->load("_main", self_id)) {
self_id = mesh::LocalIdentity(&trng); // create new random identity
@@ -306,6 +357,58 @@ class MyMesh : public BaseChatMesh {
}
}
void loadChannels() {
if (_fs->exists("/channels2")) {
File file = _fs->open("/channels2");
if (file) {
bool full = false;
uint8_t channel_idx = 0;
while (!full) {
ChannelDetails ch;
uint8_t unused[4];
bool success = (file.read(unused, 4) == 4);
success = success && (file.read((uint8_t *) ch.name, 32) == 32);
success = success && (file.read((uint8_t *) ch.channel.secret, 32) == 32);
if (!success) break; // EOF
if (setChannel(channel_idx, ch)) {
channel_idx++;
} else {
full = true;
}
}
file.close();
}
}
}
void saveChannels() {
#if defined(NRF52_PLATFORM)
File file = _fs->open("/channels2", FILE_O_WRITE);
if (file) { file.seek(0); file.truncate(); }
#else
File file = _fs->open("/channels2", "w", true);
#endif
if (file) {
uint8_t channel_idx = 0;
ChannelDetails ch;
uint8_t unused[4];
memset(unused, 0, 4);
while (getChannel(channel_idx, ch)) {
bool success = (file.write(unused, 4) == 4);
success = success && (file.write((uint8_t *) ch.name, 32) == 32);
success = success && (file.write((uint8_t *) ch.channel.secret, 32) == 32);
if (!success) break; // write failed
channel_idx++;
}
file.close();
}
}
int getBlobByKey(const uint8_t key[], int key_len, uint8_t dest_buf[]) override {
char path[64];
char fname[18];
@@ -354,10 +457,11 @@ class MyMesh : public BaseChatMesh {
buf[0] = RESP_CODE_OK;
_serial->writeFrame(buf, 1);
}
void writeErrFrame() {
uint8_t buf[1];
void writeErrFrame(uint8_t err_code) {
uint8_t buf[2];
buf[0] = RESP_CODE_ERR;
_serial->writeFrame(buf, 1);
buf[1] = err_code;
_serial->writeFrame(buf, 2);
}
void writeDisabledFrame() {
@@ -435,6 +539,18 @@ protected:
return (int) ((pow(_prefs.rx_delay_base, 0.85f - score) - 1.0) * air_time);
}
void logRxRaw(float snr, float rssi, const uint8_t raw[], int len) override {
if (_serial->isConnected()) {
int i = 0;
out_frame[i++] = PUSH_CODE_LOG_RX_DATA;
out_frame[i++] = (int8_t)(snr * 4);
out_frame[i++] = (int8_t)(rssi);
memcpy(&out_frame[i], raw, len); i += len;
_serial->writeFrame(out_frame, i);
}
}
void onDiscoveredContact(ContactInfo& contact, bool is_new) override {
if (_serial->isConnected()) {
out_frame[0] = PUSH_CODE_ADVERT;
@@ -456,26 +572,35 @@ protected:
}
bool processAck(const uint8_t *data) override {
// TODO: see if matches any in a table
if (memcmp(data, &expected_ack_crc, 4) == 0) { // got an ACK from recipient
out_frame[0] = PUSH_CODE_SEND_CONFIRMED;
memcpy(&out_frame[1], data, 4);
uint32_t trip_time = _ms->getMillis() - last_msg_sent;
memcpy(&out_frame[5], &trip_time, 4);
_serial->writeFrame(out_frame, 9);
// see if matches any in a table
for (int i = 0; i < EXPECTED_ACK_TABLE_SIZE; i++) {
if (memcmp(data, &expected_ack_table[i].ack, 4) == 0) { // got an ACK from recipient
out_frame[0] = PUSH_CODE_SEND_CONFIRMED;
memcpy(&out_frame[1], data, 4);
uint32_t trip_time = _ms->getMillis() - expected_ack_table[i].msg_sent;
memcpy(&out_frame[5], &trip_time, 4);
_serial->writeFrame(out_frame, 9);
// NOTE: the same ACK can be received multiple times!
expected_ack_crc = 0; // reset our expected hash, now that we have received ACK
return true;
// NOTE: the same ACK can be received multiple times!
expected_ack_table[i].ack = 0; // clear expected hash, now that we have received ACK
return true;
}
}
return checkConnectionsAck(data);
}
void queueMessage(const ContactInfo& from, uint8_t txt_type, uint8_t path_len, uint32_t sender_timestamp, const uint8_t* extra, int extra_len, const char *text) {
void queueMessage(const ContactInfo& from, uint8_t txt_type, mesh::Packet* pkt, uint32_t sender_timestamp, const uint8_t* extra, int extra_len, const char *text) {
int i = 0;
out_frame[i++] = RESP_CODE_CONTACT_MSG_RECV;
if (app_target_ver >= 3) {
out_frame[i++] = RESP_CODE_CONTACT_MSG_RECV_V3;
out_frame[i++] = (int8_t)(pkt->getSNR() * 4);
out_frame[i++] = 0; // reserved1
out_frame[i++] = 0; // reserved2
} else {
out_frame[i++] = RESP_CODE_CONTACT_MSG_RECV;
}
memcpy(&out_frame[i], from.id.pub_key, 6); i += 6; // just 6-byte prefix
out_frame[i++] = path_len;
uint8_t path_len = out_frame[i++] = pkt->isRouteFlood() ? pkt->path_len : 0xFF;
out_frame[i++] = txt_type;
memcpy(&out_frame[i], &sender_timestamp, 4); i += 4;
if (extra_len > 0) {
@@ -495,32 +620,41 @@ protected:
} else {
soundBuzzer();
}
#ifdef DISPLAY_CLASS
ui_task.showMsgPreview(path_len, from.name, text);
#ifdef HAS_UI
ui_task.newMsg(path_len, from.name, text, offline_queue_len);
#endif
}
void onMessageRecv(const ContactInfo& from, uint8_t path_len, uint32_t sender_timestamp, const char *text) override {
void onMessageRecv(const ContactInfo& from, mesh::Packet* pkt, uint32_t sender_timestamp, const char *text) override {
markConnectionActive(from); // in case this is from a server, and we have a connection
queueMessage(from, TXT_TYPE_PLAIN, path_len, sender_timestamp, NULL, 0, text);
queueMessage(from, TXT_TYPE_PLAIN, pkt, sender_timestamp, NULL, 0, text);
}
void onCommandDataRecv(const ContactInfo& from, uint8_t path_len, uint32_t sender_timestamp, const char *text) override {
void onCommandDataRecv(const ContactInfo& from, mesh::Packet* pkt, uint32_t sender_timestamp, const char *text) override {
markConnectionActive(from); // in case this is from a server, and we have a connection
queueMessage(from, TXT_TYPE_CLI_DATA, path_len, sender_timestamp, NULL, 0, text);
queueMessage(from, TXT_TYPE_CLI_DATA, pkt, sender_timestamp, NULL, 0, text);
}
void onSignedMessageRecv(const ContactInfo& from, uint8_t path_len, uint32_t sender_timestamp, const uint8_t *sender_prefix, const char *text) override {
void onSignedMessageRecv(const ContactInfo& from, mesh::Packet* pkt, uint32_t sender_timestamp, const uint8_t *sender_prefix, const char *text) override {
markConnectionActive(from);
saveContacts(); // from.sync_since change needs to be persisted
queueMessage(from, TXT_TYPE_SIGNED_PLAIN, path_len, sender_timestamp, sender_prefix, 4, text);
queueMessage(from, TXT_TYPE_SIGNED_PLAIN, pkt, sender_timestamp, sender_prefix, 4, text);
}
void onChannelMessageRecv(const mesh::GroupChannel& channel, int in_path_len, uint32_t timestamp, const char *text) override {
void onChannelMessageRecv(const mesh::GroupChannel& channel, mesh::Packet* pkt, uint32_t timestamp, const char *text) override {
int i = 0;
out_frame[i++] = RESP_CODE_CHANNEL_MSG_RECV;
out_frame[i++] = 0; // FUTURE: channel_idx (will just be 'public' for now)
out_frame[i++] = in_path_len < 0 ? 0xFF : in_path_len;
if (app_target_ver >= 3) {
out_frame[i++] = RESP_CODE_CHANNEL_MSG_RECV_V3;
out_frame[i++] = (int8_t)(pkt->getSNR() * 4);
out_frame[i++] = 0; // reserved1
out_frame[i++] = 0; // reserved2
} else {
out_frame[i++] = RESP_CODE_CHANNEL_MSG_RECV;
}
out_frame[i++] = findChannelIdx(channel);
uint8_t path_len = out_frame[i++] = pkt->isRouteFlood() ? pkt->path_len : 0xFF;
out_frame[i++] = TXT_TYPE_PLAIN;
memcpy(&out_frame[i], &timestamp, 4); i += 4;
int tlen = strlen(text); // TODO: UTF-8 ??
@@ -537,8 +671,8 @@ protected:
} else {
soundBuzzer();
}
#ifdef DISPLAY_CLASS
ui_task.showMsgPreview(in_path_len < 0 ? 0xFF : in_path_len, "Public", text);
#ifdef HAS_UI
ui_task.newMsg(path_len, "Public", text, offline_queue_len);
#endif
}
@@ -595,6 +729,25 @@ protected:
}
}
void onTraceRecv(mesh::Packet* packet, uint32_t tag, uint32_t auth_code, uint8_t flags, const uint8_t* path_snrs, const uint8_t* path_hashes, uint8_t path_len) override {
int i = 0;
out_frame[i++] = PUSH_CODE_TRACE_DATA;
out_frame[i++] = 0; // reserved
out_frame[i++] = path_len;
out_frame[i++] = flags;
memcpy(&out_frame[i], &tag, 4); i += 4;
memcpy(&out_frame[i], &auth_code, 4); i += 4;
memcpy(&out_frame[i], path_hashes, path_len); i += path_len;
memcpy(&out_frame[i], path_snrs, path_len); i += path_len;
out_frame[i++] = (int8_t)(_radio->getLastSNR() * 4); // extra/final SNR (to this node)
if (_serial->isConnected()) {
_serial->writeFrame(out_frame, i);
} else {
MESH_DEBUG_PRINTLN("onTraceRecv(), data received while app offline");
}
}
uint32_t calcFloodTimeoutMillisFor(uint32_t pkt_airtime_millis) const override {
return SEND_TIMEOUT_BASE_MILLIS + (FLOOD_SEND_TIMEOUT_FACTOR * pkt_airtime_millis);
}
@@ -616,6 +769,8 @@ public:
app_target_ver = 0;
_identity_store = NULL;
pending_login = pending_status = 0;
next_ack_idx = 0;
sign_data = NULL;
// defaults
memset(&_prefs, 0, sizeof(_prefs));
@@ -629,7 +784,7 @@ public:
//_prefs.rx_delay_base = 10.0f; enable once new algo fixed
}
void begin(FILESYSTEM& fs, mesh::RNG& trng) {
void begin(FILESYSTEM& fs, mesh::RNG& trng, bool has_display) {
_fs = &fs;
BaseChatMesh::begin();
@@ -680,8 +835,12 @@ public:
#ifdef BLE_PIN_CODE
if (_prefs.ble_pin == 0) {
#ifdef DISPLAY_CLASS
_active_ble_pin = trng.nextInt(100000, 999999); // random pin each session
#ifdef HAS_UI
if (has_display) {
_active_ble_pin = trng.nextInt(100000, 999999); // random pin each session
} else {
_active_ble_pin = BLE_PIN_CODE; // otherwise static pin
}
#else
_active_ble_pin = BLE_PIN_CODE; // otherwise static pin
#endif
@@ -696,7 +855,8 @@ public:
_fs->mkdir("/bl");
loadContacts();
_public = addChannel(PUBLIC_GROUP_PSK); // pre-configure Andy's public channel
addChannel("Public", PUBLIC_GROUP_PSK); // pre-configure Andy's public channel
loadChannels();
_phy->setFrequency(_prefs.freq);
_phy->setSpreadingFactor(_prefs.sf);
@@ -752,7 +912,9 @@ public:
int i = 0;
out_frame[i++] = RESP_CODE_DEVICE_INFO;
out_frame[i++] = FIRMWARE_VER_CODE;
memset(&out_frame[i], 0, 6); i += 6; // reserved
out_frame[i++] = MAX_CONTACTS / 2; // v3+
out_frame[i++] = MAX_GROUP_CHANNELS; // v3+
memcpy(&out_frame[i], &_prefs.ble_pin, 4); i += 4;
memset(&out_frame[i], 0, 12);
strcpy((char *) &out_frame[i], FIRMWARE_BUILD_DATE); i += 12;
StrHelper::strzcpy((char *) &out_frame[i], board.getManufacturerName(), 40); i += 40;
@@ -803,43 +965,54 @@ public:
uint32_t est_timeout;
text[tlen] = 0; // ensure null
int result;
uint32_t expected_ack;
if (txt_type == TXT_TYPE_CLI_DATA) {
result = sendCommandData(*recipient, msg_timestamp, attempt, text, est_timeout);
expected_ack_crc = 0; // no Ack expected
expected_ack = 0; // no Ack expected
} else {
result = sendMessage(*recipient, msg_timestamp, attempt, text, expected_ack_crc, est_timeout);
result = sendMessage(*recipient, msg_timestamp, attempt, text, expected_ack, est_timeout);
}
// TODO: add expected ACK to table
if (result == MSG_SEND_FAILED) {
writeErrFrame();
writeErrFrame(ERR_CODE_TABLE_FULL);
} else {
last_msg_sent = _ms->getMillis();
if (expected_ack) {
expected_ack_table[next_ack_idx].msg_sent = _ms->getMillis(); // add to circular table
expected_ack_table[next_ack_idx].ack = expected_ack;
next_ack_idx = (next_ack_idx + 1) % EXPECTED_ACK_TABLE_SIZE;
}
out_frame[0] = RESP_CODE_SENT;
out_frame[1] = (result == MSG_SEND_SENT_FLOOD) ? 1 : 0;
memcpy(&out_frame[2], &expected_ack_crc, 4);
memcpy(&out_frame[2], &expected_ack, 4);
memcpy(&out_frame[6], &est_timeout, 4);
_serial->writeFrame(out_frame, 10);
}
} else {
writeErrFrame(); // unknown recipient, or unsuported TXT_TYPE_*
writeErrFrame(recipient == NULL ? ERR_CODE_NOT_FOUND : ERR_CODE_UNSUPPORTED_CMD); // unknown recipient, or unsuported TXT_TYPE_*
}
} else if (cmd_frame[0] == CMD_SEND_CHANNEL_TXT_MSG) { // send GroupChannel msg
int i = 1;
uint8_t txt_type = cmd_frame[i++]; // should be TXT_TYPE_PLAIN
uint8_t channel_idx = cmd_frame[i++]; // reserved future
uint8_t channel_idx = cmd_frame[i++];
uint32_t msg_timestamp;
memcpy(&msg_timestamp, &cmd_frame[i], 4); i += 4;
const char *text = (char *) &cmd_frame[i];
if (txt_type == TXT_TYPE_PLAIN && sendGroupMessage(msg_timestamp, *_public, _prefs.node_name, text, len - i)) { // hard-coded to 'public' channel for now
writeOKFrame();
if (txt_type != TXT_TYPE_PLAIN) {
writeErrFrame(ERR_CODE_UNSUPPORTED_CMD);
} else {
writeErrFrame();
ChannelDetails channel;
bool success = getChannel(channel_idx, channel);
if (success && sendGroupMessage(msg_timestamp, channel.channel, _prefs.node_name, text, len - i)) {
writeOKFrame();
} else {
writeErrFrame(ERR_CODE_NOT_FOUND); // bad channel_idx
}
}
} else if (cmd_frame[0] == CMD_GET_CONTACTS) { // get Contact list
if (_iter_started) {
writeErrFrame(); // iterator is currently busy
writeErrFrame(ERR_CODE_BAD_STATE); // iterator is currently busy
} else {
if (len >= 5) { // has optional 'since' param
memcpy(&_iter_filter_since, &cmd_frame[1], 4);
@@ -878,7 +1051,7 @@ public:
savePrefs();
writeOKFrame();
} else {
writeErrFrame(); // invalid geo coordinate
writeErrFrame(ERR_CODE_ILLEGAL_ARG); // invalid geo coordinate
}
} else if (cmd_frame[0] == CMD_GET_DEVICE_TIME) {
uint8_t reply[5];
@@ -894,7 +1067,7 @@ public:
getRTCClock()->setCurrentTime(secs);
writeOKFrame();
} else {
writeErrFrame();
writeErrFrame(ERR_CODE_ILLEGAL_ARG);
}
} else if (cmd_frame[0] == CMD_SEND_SELF_ADVERT) {
auto pkt = createSelfAdvert(_prefs.node_name, _prefs.node_lat, _prefs.node_lon);
@@ -906,7 +1079,7 @@ public:
}
writeOKFrame();
} else {
writeErrFrame();
writeErrFrame(ERR_CODE_TABLE_FULL);
}
} else if (cmd_frame[0] == CMD_RESET_PATH && len >= 1+32) {
uint8_t* pub_key = &cmd_frame[1];
@@ -917,7 +1090,7 @@ public:
saveContacts();
writeOKFrame();
} else {
writeErrFrame(); // unknown contact
writeErrFrame(ERR_CODE_NOT_FOUND); // unknown contact
}
} else if (cmd_frame[0] == CMD_ADD_UPDATE_CONTACT && len >= 1+32+2+1) {
uint8_t* pub_key = &cmd_frame[1];
@@ -936,7 +1109,7 @@ public:
saveContacts();
writeOKFrame();
} else {
writeErrFrame(); // table is full!
writeErrFrame(ERR_CODE_TABLE_FULL);
}
}
} else if (cmd_frame[0] == CMD_REMOVE_CONTACT) {
@@ -946,15 +1119,19 @@ public:
saveContacts();
writeOKFrame();
} else {
writeErrFrame(); // not found, or unable to remove
writeErrFrame(ERR_CODE_NOT_FOUND); // not found, or unable to remove
}
} else if (cmd_frame[0] == CMD_SHARE_CONTACT) {
uint8_t* pub_key = &cmd_frame[1];
ContactInfo* recipient = lookupContactByPubKey(pub_key, PUB_KEY_SIZE);
if (recipient && shareContactZeroHop(*recipient)) {
writeOKFrame();
if (recipient) {
if (shareContactZeroHop(*recipient)) {
writeOKFrame();
} else {
writeErrFrame(ERR_CODE_TABLE_FULL); // unable to send
}
} else {
writeErrFrame(); // not found, or unable to send
writeErrFrame(ERR_CODE_NOT_FOUND);
}
} else if (cmd_frame[0] == CMD_GET_CONTACT_BY_KEY) {
uint8_t* pub_key = &cmd_frame[1];
@@ -962,7 +1139,7 @@ public:
if (contact) {
writeContactRespFrame(RESP_CODE_CONTACT, *contact);
} else {
writeErrFrame(); // not found
writeErrFrame(ERR_CODE_NOT_FOUND); // not found
}
} else if (cmd_frame[0] == CMD_EXPORT_CONTACT) {
if (len < 1 + PUB_KEY_SIZE) {
@@ -974,7 +1151,7 @@ public:
releasePacket(pkt); // undo the obtainNewPacket()
_serial->writeFrame(out_frame, out_len + 1);
} else {
writeErrFrame(); // Error
writeErrFrame(ERR_CODE_TABLE_FULL); // Error
}
} else {
uint8_t* pub_key = &cmd_frame[1];
@@ -984,19 +1161,22 @@ public:
out_frame[0] = RESP_CODE_EXPORT_CONTACT;
_serial->writeFrame(out_frame, out_len + 1);
} else {
writeErrFrame(); // not found
writeErrFrame(ERR_CODE_NOT_FOUND); // not found
}
}
} else if (cmd_frame[0] == CMD_IMPORT_CONTACT && len > 2+32+64) {
if (importContact(&cmd_frame[1], len - 1)) {
writeOKFrame();
} else {
writeErrFrame();
writeErrFrame(ERR_CODE_ILLEGAL_ARG);
}
} else if (cmd_frame[0] == CMD_SYNC_NEXT_MESSAGE) {
int out_len;
if ((out_len = getFromOfflineQueue(out_frame)) > 0) {
_serial->writeFrame(out_frame, out_len);
#ifdef HAS_UI
ui_task.msgRead(offline_queue_len);
#endif
} else {
out_frame[0] = RESP_CODE_NO_MORE_MESSAGES;
_serial->writeFrame(out_frame, 1);
@@ -1026,11 +1206,11 @@ public:
writeOKFrame();
} else {
MESH_DEBUG_PRINTLN("Error: CMD_SET_RADIO_PARAMS: f=%d, bw=%d, sf=%d, cr=%d", freq, bw, (uint32_t)sf, (uint32_t)cr);
writeErrFrame();
writeErrFrame(ERR_CODE_ILLEGAL_ARG);
}
} else if (cmd_frame[0] == CMD_SET_RADIO_TX_POWER) {
if (cmd_frame[1] > MAX_LORA_TX_POWER) {
writeErrFrame();
writeErrFrame(ERR_CODE_ILLEGAL_ARG);
} else {
_prefs.tx_power_dbm = cmd_frame[1];
savePrefs();
@@ -1071,7 +1251,7 @@ public:
self_id = identity;
writeOKFrame();
} else {
writeErrFrame();
writeErrFrame(ERR_CODE_FILE_IO_ERROR);
}
#else
writeDisabledFrame();
@@ -1086,10 +1266,10 @@ public:
sendDirect(pkt, path, path_len);
writeOKFrame();
} else {
writeErrFrame();
writeErrFrame(ERR_CODE_TABLE_FULL);
}
} else {
writeErrFrame(); // flood, not supported (yet)
writeErrFrame(ERR_CODE_UNSUPPORTED_CMD); // flood, not supported (yet)
}
} else if (cmd_frame[0] == CMD_SEND_LOGIN && len >= 1+PUB_KEY_SIZE) {
uint8_t* pub_key = &cmd_frame[1];
@@ -1100,7 +1280,7 @@ public:
uint32_t est_timeout;
int result = sendLogin(*recipient, password, est_timeout);
if (result == MSG_SEND_FAILED) {
writeErrFrame();
writeErrFrame(ERR_CODE_TABLE_FULL);
} else {
pending_status = 0;
memcpy(&pending_login, recipient->id.pub_key, 4); // match this to onContactResponse()
@@ -1111,7 +1291,7 @@ public:
_serial->writeFrame(out_frame, 10);
}
} else {
writeErrFrame(); // contact not found
writeErrFrame(ERR_CODE_NOT_FOUND); // contact not found
}
} else if (cmd_frame[0] == CMD_SEND_STATUS_REQ && len >= 1+PUB_KEY_SIZE) {
uint8_t* pub_key = &cmd_frame[1];
@@ -1120,7 +1300,7 @@ public:
uint32_t est_timeout;
int result = sendStatusRequest(*recipient, est_timeout);
if (result == MSG_SEND_FAILED) {
writeErrFrame();
writeErrFrame(ERR_CODE_TABLE_FULL);
} else {
pending_login = 0;
memcpy(&pending_status, recipient->id.pub_key, 4); // match this to onContactResponse()
@@ -1131,21 +1311,104 @@ public:
_serial->writeFrame(out_frame, 10);
}
} else {
writeErrFrame(); // contact not found
writeErrFrame(ERR_CODE_NOT_FOUND); // contact not found
}
} else if (cmd_frame[0] == CMD_HAS_CONNECTION && len >= 1+PUB_KEY_SIZE) {
uint8_t* pub_key = &cmd_frame[1];
if (hasConnectionTo(pub_key)) {
writeOKFrame();
} else {
writeErrFrame();
writeErrFrame(ERR_CODE_NOT_FOUND);
}
} else if (cmd_frame[0] == CMD_LOGOUT && len >= 1+PUB_KEY_SIZE) {
uint8_t* pub_key = &cmd_frame[1];
stopConnection(pub_key);
writeOKFrame();
} else if (cmd_frame[0] == CMD_GET_CHANNEL && len >= 2) {
uint8_t channel_idx = cmd_frame[1];
ChannelDetails channel;
if (getChannel(channel_idx, channel)) {
int i = 0;
out_frame[i++] = RESP_CODE_CHANNEL_INFO;
out_frame[i++] = channel_idx;
strcpy((char *)&out_frame[i], channel.name); i += 32;
memcpy(&out_frame[i], channel.channel.secret, 16); i += 16; // NOTE: only 128-bit supported
_serial->writeFrame(out_frame, i);
} else {
writeErrFrame(ERR_CODE_NOT_FOUND);
}
} else if (cmd_frame[0] == CMD_SET_CHANNEL && len >= 2+32+32) {
writeErrFrame(ERR_CODE_UNSUPPORTED_CMD); // not supported (yet)
} else if (cmd_frame[0] == CMD_SET_CHANNEL && len >= 2+32+16) {
uint8_t channel_idx = cmd_frame[1];
ChannelDetails channel;
StrHelper::strncpy(channel.name, (char *) &cmd_frame[2], 32);
memset(channel.channel.secret, 0, sizeof(channel.channel.secret));
memcpy(channel.channel.secret, &cmd_frame[2+32], 16); // NOTE: only 128-bit supported
if (setChannel(channel_idx, channel)) {
saveChannels();
writeOKFrame();
} else {
writeErrFrame(ERR_CODE_NOT_FOUND); // bad channel_idx
}
} else if (cmd_frame[0] == CMD_SIGN_START) {
out_frame[0] = RESP_CODE_SIGN_START;
out_frame[1] = 0; // reserved
uint32_t len = MAX_SIGN_DATA_LEN;
memcpy(&out_frame[2], &len, 4);
_serial->writeFrame(out_frame, 6);
if (sign_data) {
free(sign_data);
}
sign_data = (uint8_t *) malloc(MAX_SIGN_DATA_LEN);
sign_data_len = 0;
} else if (cmd_frame[0] == CMD_SIGN_DATA && len > 1) {
if (sign_data == NULL || sign_data_len + (len - 1) > MAX_SIGN_DATA_LEN) {
writeErrFrame(sign_data == NULL ? ERR_CODE_BAD_STATE : ERR_CODE_TABLE_FULL); // error: too long
} else {
memcpy(&sign_data[sign_data_len], &cmd_frame[1], len - 1);
sign_data_len += (len - 1);
writeOKFrame();
}
} else if (cmd_frame[0] == CMD_SIGN_FINISH) {
if (sign_data) {
self_id.sign(&out_frame[1], sign_data, sign_data_len);
free(sign_data); // don't need sign_data now
sign_data = NULL;
out_frame[0] = RESP_CODE_SIGNATURE;
_serial->writeFrame(out_frame, 1 + SIGNATURE_SIZE);
} else {
writeErrFrame(ERR_CODE_BAD_STATE);
}
} else if (cmd_frame[0] == CMD_SEND_TRACE_PATH && len > 10 && len - 10 < MAX_PATH_SIZE) {
uint32_t tag, auth;
memcpy(&tag, &cmd_frame[1], 4);
memcpy(&auth, &cmd_frame[5], 4);
auto pkt = createTrace(tag, auth, cmd_frame[9]);
if (pkt) {
uint8_t path_len = len - 10;
sendDirect(pkt, &cmd_frame[10], path_len);
uint32_t t = _radio->getEstAirtimeFor(pkt->payload_len + pkt->path_len + 2);
uint32_t est_timeout = calcDirectTimeoutMillisFor(t, path_len);
out_frame[0] = RESP_CODE_SENT;
out_frame[1] = 0;
memcpy(&out_frame[2], &tag, 4);
memcpy(&out_frame[6], &est_timeout, 4);
_serial->writeFrame(out_frame, 10);
} else {
writeErrFrame(ERR_CODE_TABLE_FULL);
}
} else if (cmd_frame[0] == CMD_SET_DEVICE_PIN && len >= 5) {
memcpy(&_prefs.ble_pin, &cmd_frame[1], 4);
savePrefs();
writeOKFrame();
} else {
writeErrFrame();
writeErrFrame(ERR_CODE_UNSUPPORTED_CMD);
MESH_DEBUG_PRINTLN("ERROR: unknown command: %02X", cmd_frame[0]);
}
}
@@ -1177,7 +1440,7 @@ public:
checkConnections();
}
#ifdef DISPLAY_CLASS
#ifdef HAS_UI
ui_task.setHasConnection(_serial->isConnected());
ui_task.loop();
#endif
@@ -1215,6 +1478,9 @@ RADIO_CLASS radio = new Module(P_LORA_NSS, P_LORA_DIO_1, P_LORA_RESET, P_LORA_BU
#elif defined(LILYGO_TLORA)
SPIClass spi;
RADIO_CLASS radio = new Module(P_LORA_NSS, P_LORA_DIO_0, P_LORA_RESET, P_LORA_DIO_1, spi);
#elif defined(LILYGO_TBEAM)
SPIClass spi;
RADIO_CLASS radio = new Module(P_LORA_NSS, P_LORA_DIO_0, P_LORA_RESET, P_LORA_DIO_1, spi);
#elif defined(P_LORA_SCLK)
SPIClass spi;
RADIO_CLASS radio = new Module(P_LORA_NSS, P_LORA_DIO_1, P_LORA_RESET, P_LORA_BUSY, spi);
@@ -1246,49 +1512,78 @@ void setup() {
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 defined(FAKETEC)
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);
}
#endif
if (status != RADIOLIB_ERR_NONE) {
Serial.print("ERROR: radio init failed: ");
Serial.println(status);
halt();
}
radio.setCRC(0);
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
fast_rng.begin(radio.random(0x7FFFFFFF));
RadioNoiseListener trng(radio);
#ifdef HAS_UI
DisplayDriver* disp = NULL;
#ifdef DISPLAY_CLASS
if (display.begin()) {
disp = &display;
}
#endif
#endif
#if defined(NRF52_PLATFORM)
InternalFS.begin();
the_mesh.begin(InternalFS, trng);
the_mesh.begin(InternalFS, trng,
#ifdef HAS_UI
disp != NULL
#else
false
#endif
);
#ifdef BLE_PIN_CODE
char dev_name[32+10];
sprintf(dev_name, "MeshCore-%s", the_mesh.getNodeName());
char dev_name[32+16];
sprintf(dev_name, "%s%s", BLE_NAME_PREFIX, the_mesh.getNodeName());
serial_interface.begin(dev_name, the_mesh.getBLEPin());
#else
pinMode(WB_IO2, OUTPUT);
serial_interface.begin(Serial);
#endif
the_mesh.startInterface(serial_interface);
#elif defined(ESP32)
SPIFFS.begin(true);
the_mesh.begin(SPIFFS, trng);
the_mesh.begin(SPIFFS, trng,
#ifdef HAS_UI
disp != NULL
#else
false
#endif
);
#ifdef WIFI_SSID
WiFi.begin(WIFI_SSID, WIFI_PWD);
serial_interface.begin(TCP_PORT);
#elif defined(BLE_PIN_CODE)
char dev_name[32+10];
sprintf(dev_name, "MeshCore-%s", the_mesh.getNodeName());
char dev_name[32+16];
sprintf(dev_name, "%s%s", BLE_NAME_PREFIX, the_mesh.getNodeName());
serial_interface.begin(dev_name, the_mesh.getBLEPin());
#else
serial_interface.begin(Serial);
@@ -1298,9 +1593,8 @@ void setup() {
#error "need to define filesystem"
#endif
#ifdef DISPLAY_CLASS
display.begin();
ui_task.begin(the_mesh.getNodeName(), FIRMWARE_BUILD_DATE, the_mesh.getBLEPin());
#ifdef HAS_UI
ui_task.begin(disp, the_mesh.getNodeName(), FIRMWARE_BUILD_DATE, the_mesh.getBLEPin());
#endif
}

View File

@@ -22,11 +22,11 @@
/* ------------------------------ Config -------------------------------- */
#ifndef FIRMWARE_BUILD_DATE
#define FIRMWARE_BUILD_DATE "7 Mar 2025"
#define FIRMWARE_BUILD_DATE "19 Mar 2025"
#endif
#ifndef FIRMWARE_VERSION
#define FIRMWARE_VERSION "v1.2.0"
#define FIRMWARE_VERSION "v1.4.0"
#endif
#ifndef LORA_FREQ
@@ -76,10 +76,14 @@
#include <helpers/ESP32Board.h>
#include <helpers/CustomSX1262Wrapper.h>
static ESP32Board board;
#elif defined(LILYGO_TLORA)
#elif defined(LILYGO_TLORA)
#include <helpers/LilyGoTLoraBoard.h>
#include <helpers/CustomSX1276Wrapper.h>
static LilyGoTLoraBoard board;
#elif defined(STATION_G2)
#include <helpers/StationG2Board.h>
#include <helpers/CustomSX1262Wrapper.h>
static StationG2Board board;
#elif defined(RAK_4631)
#include <helpers/nrf52/RAK4631Board.h>
#include <helpers/CustomSX1262Wrapper.h>
@@ -92,6 +96,11 @@
#include <helpers/nrf52/TechoBoard.h>
#include <helpers/CustomSX1262Wrapper.h>
static TechoBoard board;
#elif defined(FAKETEC)
#include <helpers/nrf52/faketecBoard.h>
#include <helpers/CustomSX1262Wrapper.h>
#include <helpers/CustomLLCC68Wrapper.h>
static faketecBoard board;
#else
#error "need to provide a 'board' object"
#endif
@@ -231,7 +240,9 @@ protected:
}
bool allowPacketForward(const mesh::Packet* packet) override {
return !_prefs.disable_fwd;
if (_prefs.disable_fwd) return false;
if (packet->isRouteFlood() && packet->path_len >= _prefs.flood_max) return false;
return true;
}
const char* getLogDateTime() override {
@@ -242,6 +253,15 @@ protected:
return tmp;
}
void logRxRaw(float snr, float rssi, const uint8_t raw[], int len) override {
#if MESH_PACKET_LOGGING
Serial.print(getLogDateTime());
Serial.print(" RAW: ");
mesh::Utils::printHex(Serial, raw, len);
Serial.println();
#endif
}
void logRx(mesh::Packet* pkt, int len, float score) override {
if (_logging) {
File f = openAppend(PACKET_LOG_FILE);
@@ -523,6 +543,7 @@ public:
_prefs.cr = LORA_CR;
_prefs.tx_power_dbm = LORA_TX_POWER;
_prefs.advert_interval = 1; // default to 2 minutes for NEW installs
_prefs.flood_max = 64;
}
CommonCLI* getCLI() { return &_cli; }
@@ -669,6 +690,13 @@ void setup() {
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 defined(FAKETEC)
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);
}
#endif
if (status != RADIOLIB_ERR_NONE) {
delay(5000);
Serial.print("ERROR: radio init failed: ");
@@ -676,15 +704,17 @@ void setup() {
halt();
}
radio.setCRC(0);
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
fast_rng.begin(radio.random(0x7FFFFFFF));

View File

@@ -22,11 +22,11 @@
/* ------------------------------ Config -------------------------------- */
#ifndef FIRMWARE_BUILD_DATE
#define FIRMWARE_BUILD_DATE "7 Mar 2025"
#define FIRMWARE_BUILD_DATE "19 Mar 2025"
#endif
#ifndef FIRMWARE_VERSION
#define FIRMWARE_VERSION "v1.2.0"
#define FIRMWARE_VERSION "v1.4.0"
#endif
#ifndef LORA_FREQ
@@ -59,7 +59,7 @@
#define ADMIN_PASSWORD "password"
#endif
#ifndef MAX_CLIENTS
#ifndef MAX_CLIENTS
#define MAX_CLIENTS 32
#endif
@@ -71,12 +71,16 @@
#include <helpers/HeltecV3Board.h>
#include <helpers/CustomSX1262Wrapper.h>
static HeltecV3Board board;
#elif defined(HELTEC_LORA_V2)
#include <helpers/HeltecV2Board.h>
#include <helpers/CustomSX1276Wrapper.h>
static HeltecV2Board board;
#elif defined(ARDUINO_XIAO_ESP32C3)
#include <helpers/XiaoC3Board.h>
#include <helpers/CustomSX1262Wrapper.h>
#include <helpers/CustomSX1268Wrapper.h>
static XiaoC3Board board;
#elif defined(SEEED_XIAO_S3)
#elif defined(SEEED_XIAO_S3) || defined(LILYGO_T3S3)
#include <helpers/ESP32Board.h>
#include <helpers/CustomSX1262Wrapper.h>
static ESP32Board board;
@@ -84,10 +88,27 @@
#include <helpers/LilyGoTLoraBoard.h>
#include <helpers/CustomSX1276Wrapper.h>
static LilyGoTLoraBoard board;
#elif defined(STATION_G2)
#include <helpers/StationG2Board.h>
#include <helpers/CustomSX1262Wrapper.h>
static StationG2Board board;
#elif defined(RAK_4631)
#include <helpers/nrf52/RAK4631Board.h>
#include <helpers/CustomSX1262Wrapper.h>
static RAK4631Board board;
#elif defined(HELTEC_T114)
#include <helpers/nrf52/T114Board.h>
#include <helpers/CustomSX1262Wrapper.h>
static T114Board board;
#elif defined(LILYGO_TECHO)
#include <helpers/nrf52/TechoBoard.h>
#include <helpers/CustomSX1262Wrapper.h>
static TechoBoard board;
#elif defined(FAKETEC)
#include <helpers/nrf52/faketecBoard.h>
#include <helpers/CustomSX1262Wrapper.h>
#include <helpers/CustomLLCC68Wrapper.h>
static faketecBoard board;
#else
#error "need to provide a 'board' object"
#endif
@@ -141,6 +162,23 @@ struct PostInfo {
#define RESP_SERVER_LOGIN_OK 0 // response to ANON_REQ
struct ServerStats {
uint16_t batt_milli_volts;
uint16_t curr_tx_queue_len;
uint16_t curr_free_queue_len;
int16_t last_rssi;
uint32_t n_packets_recv;
uint32_t n_packets_sent;
uint32_t total_air_time_secs;
uint32_t total_up_time_secs;
uint32_t n_sent_flood, n_sent_direct;
uint32_t n_recv_flood, n_recv_direct;
uint16_t n_full_events;
int16_t last_snr; // x 4
uint16_t n_direct_dups, n_flood_dups;
uint16_t n_posted, n_post_push;
};
class MyMesh : public mesh::Mesh, public CommonCLICallbacks {
RadioLibWrapper* my_radio;
FILESYSTEM* _fs;
@@ -153,6 +191,7 @@ class MyMesh : public mesh::Mesh, public CommonCLICallbacks {
int num_clients;
ClientInfo known_clients[MAX_CLIENTS];
unsigned long next_push;
uint16_t _num_posted, _num_post_pushes;
int next_client_idx; // for round-robin polling
int next_post_idx;
PostInfo posts[MAX_UNSYNCED_POSTS]; // cyclic queue
@@ -199,6 +238,7 @@ class MyMesh : public mesh::Mesh, public CommonCLICallbacks {
next_post_idx = (next_post_idx + 1) % MAX_UNSYNCED_POSTS;
next_push = futureMillis(PUSH_NOTIFY_DELAY_MILLIS);
_num_posted++; // stats
}
void pushPostToClient(ClientInfo* client, PostInfo& post) {
@@ -225,6 +265,7 @@ class MyMesh : public mesh::Mesh, public CommonCLICallbacks {
sendDirect(reply, client->out_path, client->out_path_len);
client->ack_timeout = futureMillis(PUSH_TIMEOUT_BASE + PUSH_ACK_TIMEOUT_FACTOR * (client->out_path_len + 1));
}
_num_post_pushes++; // stats
} else {
client->pending_ack = 0;
MESH_DEBUG_PRINTLN("Unable to push post to client");
@@ -260,12 +301,21 @@ protected:
return _prefs.airtime_factor;
}
void logRxRaw(float snr, float rssi, const uint8_t raw[], int len) override {
#if MESH_PACKET_LOGGING
Serial.print(getLogDateTime());
Serial.print(" RAW: ");
mesh::Utils::printHex(Serial, raw, len);
Serial.println();
#endif
}
int calcRxDelay(float score, uint32_t air_time) const override {
if (_prefs.rx_delay_base <= 0.0f) return 0;
return (int) ((pow(_prefs.rx_delay_base, 0.85f - score) - 1.0) * air_time);
}
const char* getLogDateTime() override {
const char* getLogDateTime() override {
static char tmp[32];
uint32_t now = getRTCClock()->getCurrentTime();
DateTime dt = DateTime(now);
@@ -283,7 +333,9 @@ protected:
}
bool allowPacketForward(const mesh::Packet* packet) override {
return !_prefs.disable_fwd;
if (_prefs.disable_fwd) return false;
if (packet->isRouteFlood() && packet->path_len >= _prefs.flood_max) return false;
return true;
}
void onAnonDataRecv(mesh::Packet* packet, uint8_t type, const mesh::Identity& sender, uint8_t* data, size_t len) override {
@@ -463,33 +515,81 @@ protected:
} else if (type == PAYLOAD_TYPE_REQ && len >= 5) {
uint32_t sender_timestamp;
memcpy(&sender_timestamp, data, 4); // timestamp (by sender's RTC clock - which could be wrong)
if (data[4] == REQ_TYPE_KEEP_ALIVE && packet->isRouteDirect()) { // request type
uint32_t forceSince = 0;
if (len >= 9) { // optional - last post_timestamp client received
memcpy(&forceSince, &data[5], 4); // NOTE: this may be 0, if part of decrypted PADDING!
} else {
memcpy(&data[5], &forceSince, 4); // make sure there are zeroes in payload (for ack_hash calc below)
}
if (forceSince > 0) {
client->sync_since = forceSince; // force-update the 'sync since'
}
if (sender_timestamp < client->last_timestamp) { // prevent replay attacks
MESH_DEBUG_PRINTLN("onPeerDataRecv: possible replay attack detected");
} else {
client->last_timestamp = sender_timestamp;
uint32_t now = getRTCClock()->getCurrentTime();
client->last_activity = now; // <-- THIS will keep client connection alive
client->push_failures = 0; // reset so push can resume (if prev failed)
client->pending_ack = 0;
// TODO: Throttle KEEP_ALIVE requests!
// if client sends too quickly, evict()
if (data[4] == REQ_TYPE_KEEP_ALIVE && packet->isRouteDirect()) { // request type
uint32_t forceSince = 0;
if (len >= 9) { // optional - last post_timestamp client received
memcpy(&forceSince, &data[5], 4); // NOTE: this may be 0, if part of decrypted PADDING!
} else {
memcpy(&data[5], &forceSince, 4); // make sure there are zeroes in payload (for ack_hash calc below)
}
if (forceSince > 0) {
client->sync_since = forceSince; // force-update the 'sync since'
}
// RULE: only send keep_alive response DIRECT!
if (client->out_path_len >= 0) {
uint32_t ack_hash; // calc ACK to prove to sender that we got request
mesh::Utils::sha256((uint8_t *) &ack_hash, 4, data, 9, client->id.pub_key, PUB_KEY_SIZE);
client->pending_ack = 0;
auto reply = createAck(ack_hash);
if (reply) {
sendDirect(reply, client->out_path, client->out_path_len);
// TODO: Throttle KEEP_ALIVE requests!
// if client sends too quickly, evict()
// RULE: only send keep_alive response DIRECT!
if (client->out_path_len >= 0) {
uint32_t ack_hash; // calc ACK to prove to sender that we got request
mesh::Utils::sha256((uint8_t *) &ack_hash, 4, data, 9, client->id.pub_key, PUB_KEY_SIZE);
auto reply = createAck(ack_hash);
if (reply) {
sendDirect(reply, client->out_path, client->out_path_len);
}
}
} else if (data[4] == REQ_TYPE_GET_STATUS) {
ServerStats stats;
stats.batt_milli_volts = board.getBattMilliVolts();
stats.curr_tx_queue_len = _mgr->getOutboundCount();
stats.curr_free_queue_len = _mgr->getFreeCount();
stats.last_rssi = (int16_t) my_radio->getLastRSSI();
stats.n_packets_recv = my_radio->getPacketsRecv();
stats.n_packets_sent = my_radio->getPacketsSent();
stats.total_air_time_secs = getTotalAirTime() / 1000;
stats.total_up_time_secs = _ms->getMillis() / 1000;
stats.n_sent_flood = getNumSentFlood();
stats.n_sent_direct = getNumSentDirect();
stats.n_recv_flood = getNumRecvFlood();
stats.n_recv_direct = getNumRecvDirect();
stats.n_full_events = getNumFullEvents();
stats.last_snr = (int16_t)(my_radio->getLastSNR() * 4);
stats.n_direct_dups = ((SimpleMeshTables *)getTables())->getNumDirectDups();
stats.n_flood_dups = ((SimpleMeshTables *)getTables())->getNumFloodDups();
stats.n_posted = _num_posted;
stats.n_post_push = _num_post_pushes;
now = getRTCClock()->getCurrentTimeUnique();
memcpy(reply_data, &now, 4); // response packets always prefixed with timestamp
memcpy(&reply_data[4], &stats, sizeof(stats));
uint8_t reply_len = 4 + sizeof(stats);
if (packet->isRouteFlood()) {
// let this sender know path TO here, so they can use sendDirect(), and ALSO encode the response
mesh::Packet* path = createPathReturn(client->id, secret, packet->path, packet->path_len,
PAYLOAD_TYPE_RESPONSE, reply_data, reply_len);
if (path) sendFlood(path);
} else {
mesh::Packet* reply = createDatagram(PAYLOAD_TYPE_RESPONSE, client->id, secret, reply_data, reply_len);
if (reply) {
if (client->out_path_len >= 0) { // we have an out_path, so send DIRECT
sendDirect(reply, client->out_path, client->out_path_len);
} else {
sendFlood(reply);
}
}
}
}
}
@@ -525,7 +625,7 @@ protected:
public:
MyMesh(RADIO_CLASS& phy, mesh::MainBoard& board, RadioLibWrapper& radio, mesh::MillisecondClock& ms, mesh::RNG& rng, mesh::RTCClock& rtc, mesh::MeshTables& tables)
: mesh::Mesh(radio, ms, rng, rtc, *new StaticPoolPacketManager(32), tables),
: mesh::Mesh(radio, ms, rng, rtc, *new StaticPoolPacketManager(32), tables),
_phy(&phy), _board(&board), _cli(board, this, &_prefs, this)
{
my_radio = &radio;
@@ -547,6 +647,7 @@ public:
_prefs.tx_power_dbm = LORA_TX_POWER;
_prefs.disable_fwd = 1;
_prefs.advert_interval = 1; // default to 2 minutes for NEW installs
_prefs.flood_max = 64;
#ifdef ROOM_PASSWORD
StrHelper::strncpy(_prefs.guest_password, ROOM_PASSWORD, sizeof(_prefs.guest_password));
#endif
@@ -556,6 +657,7 @@ public:
next_client_idx = 0;
next_push = 0;
memset(posts, 0, sizeof(posts));
_num_posted = _num_post_pushes = 0;
}
CommonCLI* getCLI() { return &_cli; }
@@ -593,7 +695,7 @@ public:
return false;
#endif
}
void sendSelfAdvertisement(int delay_millis) override {
mesh::Packet* pkt = createSelfAdvert();
if (pkt) {
@@ -688,7 +790,7 @@ SimpleMeshTables tables;
#ifdef ESP32
ESP32RTCClock fallback_clock;
#else
VolatileRTCClock fallback_clock;
VolatileRTCClock fallback_clock;
#endif
AutoDiscoverRTCClock rtc_clock(fallback_clock);
@@ -723,6 +825,13 @@ void setup() {
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 defined(FAKETEC)
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);
}
#endif
if (status != RADIOLIB_ERR_NONE) {
delay(5000);
Serial.print("ERROR: radio init failed: ");
@@ -730,15 +839,17 @@ void setup() {
halt();
}
radio.setCRC(0);
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
fast_rng.begin(radio.random(0x7FFFFFFF));
@@ -780,7 +891,7 @@ void loop() {
int len = strlen(command);
while (Serial.available() && len < sizeof(command)-1) {
char c = Serial.read();
if (c != '\n') {
if (c != '\n') {
command[len++] = c;
command[len] = 0;
}

View File

@@ -78,6 +78,11 @@
#include <helpers/nrf52/T1000eBoard.h>
#include <helpers/CustomLR1110Wrapper.h>
static T1000eBoard board;
#elif defined(FAKETEC)
#include <helpers/nrf52/faketecBoard.h>
#include <helpers/CustomSX1262Wrapper.h>
#include <helpers/CustomLLCC68Wrapper.h>
static faketecBoard board;
#else
#error "need to provide a 'board' object"
#endif
@@ -107,7 +112,7 @@ class MyMesh : public BaseChatMesh, ContactVisitor {
FILESYSTEM* _fs;
NodePrefs _prefs;
uint32_t expected_ack_crc;
mesh::GroupChannel* _public;
ChannelDetails* _public;
unsigned long last_msg_sent;
ContactInfo* curr_recipient;
char command[512+10];
@@ -254,8 +259,8 @@ protected:
return false;
}
void onMessageRecv(const ContactInfo& from, uint8_t path_len, uint32_t sender_timestamp, const char *text) override {
Serial.printf("(%s) MSG -> from %s\n", path_len == 0xFF ? "DIRECT" : "FLOOD", from.name);
void onMessageRecv(const ContactInfo& from, mesh::Packet* pkt, uint32_t sender_timestamp, const char *text) override {
Serial.printf("(%s) MSG -> from %s\n", pkt->isRouteDirect() ? "DIRECT" : "FLOOD", from.name);
Serial.printf(" %s\n", text);
if (strcmp(text, "clock sync") == 0) { // special text command
@@ -263,16 +268,16 @@ protected:
}
}
void onCommandDataRecv(const ContactInfo& from, uint8_t path_len, uint32_t sender_timestamp, const char *text) override {
void onCommandDataRecv(const ContactInfo& from, mesh::Packet* pkt, uint32_t sender_timestamp, const char *text) override {
}
void onSignedMessageRecv(const ContactInfo& from, uint8_t path_len, uint32_t sender_timestamp, const uint8_t *sender_prefix, const char *text) override {
void onSignedMessageRecv(const ContactInfo& from, mesh::Packet* pkt, uint32_t sender_timestamp, const uint8_t *sender_prefix, const char *text) override {
}
void onChannelMessageRecv(const mesh::GroupChannel& channel, int in_path_len, uint32_t timestamp, const char *text) override {
if (in_path_len < 0) {
void onChannelMessageRecv(const mesh::GroupChannel& channel, mesh::Packet* pkt, uint32_t timestamp, const char *text) override {
if (pkt->isRouteDirect()) {
Serial.printf("PUBLIC CHANNEL MSG -> (Direct!)\n");
} else {
Serial.printf("PUBLIC CHANNEL MSG -> (Flood) hops %d\n", in_path_len);
Serial.printf("PUBLIC CHANNEL MSG -> (Flood) hops %d\n", pkt->path_len);
}
Serial.printf(" %s\n", text);
}
@@ -337,7 +342,7 @@ public:
}
loadContacts();
_public = addChannel(PUBLIC_GROUP_PSK); // pre-configure Andy's public channel
_public = addChannel("Public", PUBLIC_GROUP_PSK); // pre-configure Andy's public channel
}
void savePrefs() {
@@ -405,7 +410,7 @@ public:
temp[5 + MAX_TEXT_LEN] = 0; // truncate if too long
int len = strlen((char *) &temp[5]);
auto pkt = createGroupDatagram(PAYLOAD_TYPE_GRP_TXT, *_public, temp, 5 + len);
auto pkt = createGroupDatagram(PAYLOAD_TYPE_GRP_TXT, _public->channel, temp, 5 + len);
if (pkt) {
sendFlood(pkt);
Serial.println(" Sent.");
@@ -585,7 +590,7 @@ void setup() {
halt();
}
radio.setCRC(0);
radio.setCRC(1);
#ifdef SX126X_CURRENT_LIMIT
radio.setCurrentLimit(SX126X_CURRENT_LIMIT);

View File

@@ -8,13 +8,17 @@
; Please visit documentation for the other options and examples
; https://docs.platformio.org/page/projectconf.html
[platformio]
extra_configs =
variants/*/platformio.ini
[arduino_base]
framework = arduino
monitor_speed = 115200
lib_deps =
SPI
Wire
jgromes/RadioLib @ ^6.3.0
jgromes/RadioLib @ ^7.1.2
rweather/Crypto @ ^0.4.0
adafruit/RTClib @ ^2.1.3
melopero/Melopero RV3028 @ ^1.1.0
@@ -22,507 +26,21 @@ build_flags = -w -DNDEBUG -DRADIOLIB_STATIC_ONLY=1 -DRADIOLIB_GODMODE=1
-D LORA_FREQ=867.5
-D LORA_BW=250
-D LORA_SF=10
build_src_filter = +<*.cpp> +<helpers/*.cpp>
build_src_filter =
+<*.cpp>
+<helpers/*.cpp>
; ----------------- ESP32 ---------------------
[esp32_base]
extends = arduino_base
platform = espressif32
monitor_filters = esp32_exception_decoder
extra_scripts = merge-bin.py
build_flags = ${arduino_base.build_flags}
; -D ESP32_CPU_FREQ=80 ; change it to your need
build_src_filter = ${arduino_base.build_src_filter}
; ================
[Heltec_lora32_v2]
extends = esp32_base
board = heltec_wifi_lora_32_V2 ; heltec_wifi_lora_32_V2
build_flags =
${esp32_base.build_flags}
-D HELTEC_LORA_V2
-D RADIO_CLASS=CustomSX1276
-D WRAPPER_CLASS=CustomSX1276Wrapper
-D LORA_TX_POWER=20
-D P_LORA_TX_LED=25
build_src_filter = ${esp32_base.build_src_filter}
[env:Heltec_v2_repeater]
extends = Heltec_lora32_v2
build_flags =
${Heltec_lora32_v2.build_flags}
-D ADVERT_NAME="\"Heltec Repeater\""
-D ADVERT_LAT=-37.0
-D ADVERT_LON=145.0
-D ADMIN_PASSWORD="\"password\""
; -D MESH_PACKET_LOGGING=1
; -D MESH_DEBUG=1
build_src_filter = ${Heltec_lora32_v2.build_src_filter} +<../examples/simple_repeater/main.cpp>
[env:Heltec_v2_terminal_chat]
extends = Heltec_lora32_v2
build_flags =
${Heltec_lora32_v2.build_flags}
-D MAX_CONTACTS=100
-D MAX_GROUP_CHANNELS=1
; -D MESH_PACKET_LOGGING=1
; -D MESH_DEBUG=1
build_src_filter = ${Heltec_lora32_v2.build_src_filter} +<../examples/simple_secure_chat/main.cpp>
lib_deps =
${Heltec_lora32_v2.lib_deps}
densaugeo/base64 @ ~1.4.0
[env:Heltec_v2_companion_radio_usb]
extends = Heltec_lora32_v2
build_flags =
${Heltec_lora32_v2.build_flags}
-D MAX_CONTACTS=100
-D MAX_GROUP_CHANNELS=1
; NOTE: DO NOT ENABLE --> -D MESH_PACKET_LOGGING=1
; NOTE: DO NOT ENABLE --> -D MESH_DEBUG=1
build_src_filter = ${Heltec_lora32_v2.build_src_filter} +<helpers/esp32/*.cpp> +<../examples/companion_radio/main.cpp>
lib_deps =
${Heltec_lora32_v2.lib_deps}
densaugeo/base64 @ ~1.4.0
[env:Heltec_v2_companion_radio_ble]
extends = Heltec_lora32_v2
build_flags =
${Heltec_lora32_v2.build_flags}
-D MAX_CONTACTS=100
-D MAX_GROUP_CHANNELS=1
-D BLE_PIN_CODE=123456
-D BLE_DEBUG_LOGGING=1
; -D ENABLE_PRIVATE_KEY_IMPORT=1
; -D ENABLE_PRIVATE_KEY_EXPORT=1
; -D MESH_PACKET_LOGGING=1
; -D MESH_DEBUG=1
build_src_filter = ${Heltec_lora32_v2.build_src_filter} +<helpers/esp32/*.cpp> +<../examples/companion_radio/main.cpp>
lib_deps =
${Heltec_lora32_v2.lib_deps}
densaugeo/base64 @ ~1.4.0
; ================
[Heltec_lora32_v3]
extends = esp32_base
board = esp32-s3-devkitc-1
build_flags =
${esp32_base.build_flags}
-D HELTEC_LORA_V3
-D RADIO_CLASS=CustomSX1262
-D WRAPPER_CLASS=CustomSX1262Wrapper
-D LORA_TX_POWER=22
-D P_LORA_TX_LED=35
-D PIN_BOARD_SDA=17
-D PIN_BOARD_SCL=18
-D PIN_USER_BTN=0
-D SX126X_DIO2_AS_RF_SWITCH=true
-D SX126X_DIO3_TCXO_VOLTAGE=1.8
-D SX126X_CURRENT_LIMIT=130.0f ; for best TX power!
build_src_filter = ${esp32_base.build_src_filter}
lib_deps =
${esp32_base.lib_deps}
adafruit/Adafruit SSD1306 @ ^2.5.13
[env:Heltec_v3_repeater]
extends = Heltec_lora32_v3
build_flags =
${Heltec_lora32_v3.build_flags}
-D DISPLAY_CLASS=SSD1306Display
-D ADVERT_NAME="\"Heltec Repeater\""
-D ADVERT_LAT=-37.0
-D ADVERT_LON=145.0
-D ADMIN_PASSWORD="\"password\""
-D MESH_PACKET_LOGGING=1
; -D MESH_DEBUG=1
build_src_filter = ${Heltec_lora32_v3.build_src_filter} +<helpers/ui/*.cpp> +<../examples/simple_repeater>
[env:Heltec_v3_room_server]
extends = Heltec_lora32_v3
build_src_filter = ${Heltec_lora32_v3.build_src_filter} +<helpers/ui/*.cpp> +<../examples/simple_room_server>
build_flags =
${Heltec_lora32_v3.build_flags}
-D DISPLAY_CLASS=SSD1306Display
-D ADVERT_NAME="\"Heltec Room\""
-D ADVERT_LAT=-37.0
-D ADVERT_LON=145.0
-D ADMIN_PASSWORD="\"password\""
-D ROOM_PASSWORD="\"hello\""
; -D MESH_PACKET_LOGGING=1
; -D MESH_DEBUG=1
[env:Heltec_v3_terminal_chat]
extends = Heltec_lora32_v3
build_flags =
${Heltec_lora32_v3.build_flags}
-D MAX_CONTACTS=100
-D MAX_GROUP_CHANNELS=1
; -D MESH_PACKET_LOGGING=1
; -D MESH_DEBUG=1
build_src_filter = ${Heltec_lora32_v3.build_src_filter} +<../examples/simple_secure_chat/main.cpp>
lib_deps =
${Heltec_lora32_v3.lib_deps}
densaugeo/base64 @ ~1.4.0
[env:Heltec_v3_companion_radio_usb]
extends = Heltec_lora32_v3
build_flags =
${Heltec_lora32_v3.build_flags}
-D MAX_CONTACTS=100
-D MAX_GROUP_CHANNELS=1
-D DISPLAY_CLASS=SSD1306Display
; -D ENABLE_PRIVATE_KEY_IMPORT=1
; -D ENABLE_PRIVATE_KEY_EXPORT=1
; NOTE: DO NOT ENABLE --> -D MESH_PACKET_LOGGING=1
; NOTE: DO NOT ENABLE --> -D MESH_DEBUG=1
build_src_filter = ${Heltec_lora32_v3.build_src_filter} +<helpers/ui/*.cpp> +<../examples/companion_radio>
lib_deps =
${Heltec_lora32_v3.lib_deps}
densaugeo/base64 @ ~1.4.0
[env:Heltec_v3_companion_radio_ble]
extends = Heltec_lora32_v3
build_flags =
${Heltec_lora32_v3.build_flags}
-D MAX_CONTACTS=100
-D MAX_GROUP_CHANNELS=1
-D DISPLAY_CLASS=SSD1306Display
-D BLE_PIN_CODE=0 ; dynamic, random PIN
-D BLE_DEBUG_LOGGING=1
; -D ENABLE_PRIVATE_KEY_IMPORT=1
; -D ENABLE_PRIVATE_KEY_EXPORT=1
; -D MESH_PACKET_LOGGING=1
; -D MESH_DEBUG=1
build_src_filter = ${Heltec_lora32_v3.build_src_filter} +<helpers/ui/*.cpp> +<helpers/esp32/*.cpp> +<../examples/companion_radio>
lib_deps =
${Heltec_lora32_v3.lib_deps}
densaugeo/base64 @ ~1.4.0
[env:Heltec_WSL3_companion_radio_ble]
extends = Heltec_lora32_v3
build_flags =
${Heltec_lora32_v3.build_flags}
-D MAX_CONTACTS=100
-D MAX_GROUP_CHANNELS=1
-D BLE_PIN_CODE=123456
-D BLE_DEBUG_LOGGING=1
; -D ENABLE_PRIVATE_KEY_IMPORT=1
; -D ENABLE_PRIVATE_KEY_EXPORT=1
; -D MESH_PACKET_LOGGING=1
; -D MESH_DEBUG=1
build_src_filter = ${Heltec_lora32_v3.build_src_filter} +<helpers/esp32/*.cpp> +<../examples/companion_radio>
lib_deps =
${Heltec_lora32_v3.lib_deps}
densaugeo/base64 @ ~1.4.0
[env:Heltec_v3_companion_radio_wifi]
extends = Heltec_lora32_v3
build_flags =
${Heltec_lora32_v3.build_flags}
-D MAX_CONTACTS=100
-D MAX_GROUP_CHANNELS=1
-D DISPLAY_CLASS=SSD1306Display
-D WIFI_DEBUG_LOGGING=1
-D WIFI_SSID="\"myssid\""
-D WIFI_PWD="\"mypwd\""
; -D ENABLE_PRIVATE_KEY_IMPORT=1
; -D ENABLE_PRIVATE_KEY_EXPORT=1
; -D MESH_PACKET_LOGGING=1
; -D MESH_DEBUG=1
build_src_filter = ${Heltec_lora32_v3.build_src_filter} +<helpers/ui/*.cpp> +<helpers/esp32/*.cpp> +<../examples/companion_radio>
lib_deps =
${Heltec_lora32_v3.lib_deps}
densaugeo/base64 @ ~1.4.0
; ================
[Xiao_esp32_C3]
extends = esp32_base
board = seeed_xiao_esp32c3
build_flags =
${esp32_base.build_flags}
-D LORA_TX_BOOST_PIN=D3
-D P_LORA_TX_LED=D5
-D PIN_VBAT_READ=D0
-D P_LORA_DIO_1=D2
-D P_LORA_NSS=D4
-D P_LORA_RESET=RADIOLIB_NC
-D P_LORA_BUSY=D1
-D PIN_BOARD_SDA=D6
-D PIN_BOARD_SCL=D7
-D SX126X_DIO2_AS_RF_SWITCH=true
-D SX126X_DIO3_TCXO_VOLTAGE=1.8
-D SX126X_CURRENT_LIMIT=130.0f ; for best TX power!
[env:Xiao_C3_Repeater_sx1262]
extends = Xiao_esp32_C3
build_src_filter = ${Xiao_esp32_C3.build_src_filter} +<../examples/simple_repeater/main.cpp>
build_flags =
${Xiao_esp32_C3.build_flags}
-D RADIO_CLASS=CustomSX1262
-D WRAPPER_CLASS=CustomSX1262Wrapper
-D LORA_TX_POWER=22
-D ADVERT_NAME="\"Xiao Repeater\""
-D ADVERT_LAT=-37.0
-D ADVERT_LON=145.0
-D ADMIN_PASSWORD="\"password\""
; -D MESH_PACKET_LOGGING=1
; -D MESH_DEBUG=1
[env:Xiao_C3_Repeater_sx1268]
extends = Xiao_esp32_C3
build_src_filter = ${Xiao_esp32_C3.build_src_filter} +<../examples/simple_repeater/main.cpp>
build_flags =
${Xiao_esp32_C3.build_flags}
-D RADIO_CLASS=CustomSX1268
-D WRAPPER_CLASS=CustomSX1268Wrapper
-D LORA_TX_POWER=22
-D ADVERT_NAME="\"Xiao Repeater\""
-D ADVERT_LAT=-37.0
-D ADVERT_LON=145.0
-D ADMIN_PASSWORD="\"password\""
; -D MESH_PACKET_LOGGING=1
; -D MESH_DEBUG=1
; =============
[Xiao_S3_WIO]
extends = esp32_base
board = seeed_xiao_esp32s3
board_check = true
board_build.mcu = esp32s3
build_flags = ${esp32_base.build_flags}
-D SEEED_XIAO_S3
-D P_LORA_DIO_1=39
-D P_LORA_NSS=41
-D P_LORA_RESET=42 ; RADIOLIB_NC
-D P_LORA_BUSY=40 ; DIO2 = 38
-D P_LORA_SCLK=7
-D P_LORA_MISO=8
-D P_LORA_MOSI=9
-D SX126X_DIO2_AS_RF_SWITCH=true
-D SX126X_DIO3_TCXO_VOLTAGE=1.8
-D SX126X_CURRENT_LIMIT=130
-D RADIO_CLASS=CustomSX1262
-D WRAPPER_CLASS=CustomSX1262Wrapper
-D LORA_TX_POWER=22
[env:Xiao_S3_WIO_Repeater]
extends = Xiao_S3_WIO
build_src_filter = ${Xiao_S3_WIO.build_src_filter} +<../examples/simple_repeater/main.cpp>
build_flags =
${Xiao_S3_WIO.build_flags}
-D ADVERT_NAME="\"XiaoS3 Repeater\""
-D ADVERT_LAT=-37.0
-D ADVERT_LON=145.0
-D ADMIN_PASSWORD="\"password\""
; -D MESH_PACKET_LOGGING=1
; -D MESH_DEBUG=1
[env:Xiao_S3_WIO_terminal_chat]
extends = Xiao_S3_WIO
build_flags =
${Xiao_S3_WIO.build_flags}
-D MAX_CONTACTS=100
-D MAX_GROUP_CHANNELS=1
; -D MESH_PACKET_LOGGING=1
; -D MESH_DEBUG=1
build_src_filter = ${Xiao_S3_WIO.build_src_filter} +<../examples/simple_secure_chat/main.cpp>
lib_deps =
${Xiao_S3_WIO.lib_deps}
densaugeo/base64 @ ~1.4.0
[env:Xiao_S3_WIO_companion_radio_ble]
extends = Xiao_S3_WIO
build_flags =
${Xiao_S3_WIO.build_flags}
-D MAX_CONTACTS=100
-D MAX_GROUP_CHANNELS=1
-D BLE_PIN_CODE=123456
; -D BLE_DEBUG_LOGGING=1
; -D ENABLE_PRIVATE_KEY_IMPORT=1
; -D ENABLE_PRIVATE_KEY_EXPORT=1
; -D MESH_PACKET_LOGGING=1
; -D MESH_DEBUG=1
build_src_filter = ${Xiao_S3_WIO.build_src_filter} +<helpers/esp32/*.cpp> +<../examples/companion_radio/main.cpp>
lib_deps =
${Xiao_S3_WIO.lib_deps}
densaugeo/base64 @ ~1.4.0
; =============
[LilyGo_TLora_V2_1_1_6]
extends = esp32_base
board = ttgo-lora32-v1 ; LILYGO T-LoRa V2.1-1.6 ESP32 with SX1276
build_unflags = -Os
build_type = release ; Set build type to release
board_build.partitions = min_spiffs.csv ; get around 4mb flash limit
build_flags =
${esp32_base.build_flags}
-Os -ffunction-sections -fdata-sections ; Optimize for size
-D LILYGO_TLORA ; LILYGO T-LoRa V2.1-1.6 ESP32 with SX1276
-D P_LORA_DIO_0=26 ; SX1276 DIO0 interrupt pin
-D P_LORA_DIO_1=33 ; SX1276 DIO1 interrupt pin
-D P_LORA_NSS=18 ; Chip select - SS pin
-D P_LORA_RESET=14 ; Reset pin
-D P_LORA_SCLK=5 ; SPI clock
-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_VBAT_READ=35 ; Battery voltage reading (analog pin)
-D RADIO_CLASS=CustomSX1276
-D ARDUINO_LOOP_STACK_SIZE=16384
-D WRAPPER_CLASS=CustomSX1276Wrapper
-D LORA_TX_POWER=20
; =============
[LilyGo_T3S3_sx1262]
extends = esp32_base
board = t3_s3_v1_x
build_flags = ${esp32_base.build_flags}
-D LILYGO_T3S3
-D P_LORA_DIO_1=33
-D P_LORA_NSS=7
-D P_LORA_RESET=8 ; RADIOLIB_NC
-D P_LORA_BUSY=34
-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 SX126X_DIO2_AS_RF_SWITCH=true
-D SX126X_DIO3_TCXO_VOLTAGE=1.8
-D SX126X_CURRENT_LIMIT=130
-D RADIO_CLASS=CustomSX1262
-D WRAPPER_CLASS=CustomSX1262Wrapper
-D LORA_TX_POWER=22
; === LILYGO T-LoRa V2.1-1.6 with SX1276 environments ===
[env:LilyGo_TLora_V2_1_1_6_Repeater]
extends = LilyGo_TLora_V2_1_1_6
build_src_filter = ${LilyGo_TLora_V2_1_1_6.build_src_filter} +<../examples/simple_repeater/main.cpp>
build_flags =
${LilyGo_TLora_V2_1_1_6.build_flags}
-D ADVERT_NAME="\"TLora-V2.1-1.6 Repeater\""
-D ADVERT_LAT=-37.0
-D ADVERT_LON=145.0
-D ADMIN_PASSWORD="\"password\""
; -D MESH_PACKET_LOGGING=1
; -D MESH_DEBUG=1
; -D CORE_DEBUG_LEVEL=3
[env:LilyGo_TLora_V2_1_1_6_terminal_chat]
extends = LilyGo_TLora_V2_1_1_6
build_flags =
${LilyGo_TLora_V2_1_1_6.build_flags}
-D MAX_CONTACTS=100
-D MAX_GROUP_CHANNELS=1
; -D MESH_PACKET_LOGGING=1
; -D MESH_DEBUG=1
build_src_filter = ${LilyGo_TLora_V2_1_1_6.build_src_filter} +<../examples/simple_secure_chat/main.cpp>
lib_deps =
${LilyGo_TLora_V2_1_1_6.lib_deps}
densaugeo/base64 @ ~1.4.0
[env:LilyGo_TLora_V2_1_1_6_companion_radio_usb]
extends = LilyGo_TLora_V2_1_1_6
build_flags =
${LilyGo_TLora_V2_1_1_6.build_flags}
-D MAX_CONTACTS=100
-D MAX_GROUP_CHANNELS=1
; -D ENABLE_PRIVATE_KEY_IMPORT=1
; -D ENABLE_PRIVATE_KEY_EXPORT=1
; NOTE: DO NOT ENABLE --> -D MESH_PACKET_LOGGING=1
; NOTE: DO NOT ENABLE --> -D MESH_DEBUG=1
build_src_filter = ${LilyGo_TLora_V2_1_1_6.build_src_filter} +<../examples/companion_radio/main.cpp>
lib_deps =
${LilyGo_TLora_V2_1_1_6.lib_deps}
densaugeo/base64 @ ~1.4.0
[env:LilyGo_TLora_V2_1_1_6_companion_radio_ble]
extends = LilyGo_TLora_V2_1_1_6
build_flags =
${LilyGo_TLora_V2_1_1_6.build_flags}
-D MAX_CONTACTS=100
-D MAX_GROUP_CHANNELS=1
-D BLE_PIN_CODE=123456
; -D BLE_DEBUG_LOGGING=1
; -D ENABLE_PRIVATE_KEY_IMPORT=1
; -D ENABLE_PRIVATE_KEY_EXPORT=1
; -D MESH_PACKET_LOGGING=1
; -D MESH_DEBUG=1
build_src_filter = ${LilyGo_TLora_V2_1_1_6.build_src_filter} +<helpers/esp32/*.cpp> +<../examples/companion_radio/main.cpp>
lib_deps =
${LilyGo_TLora_V2_1_1_6.lib_deps}
densaugeo/base64 @ ~1.4.0
[env:LilyGo_TLora_V2_1_1_6_room_server]
extends = LilyGo_TLora_V2_1_1_6
build_src_filter = ${LilyGo_TLora_V2_1_1_6.build_src_filter} +<../examples/simple_room_server/main.cpp>
build_flags =
${LilyGo_TLora_V2_1_1_6.build_flags}
-D ADVERT_NAME="\"TLora-V2.1-1.6 Room\""
-D ADVERT_LAT=-37.0
-D ADVERT_LON=145.0
-D ADMIN_PASSWORD="\"password\""
-D ROOM_PASSWORD="\"hello\""
; -D MESH_PACKET_LOGGING=1
; -D MESH_DEBUG=1
; === LilyGo T3S3 with SX1262 environments ===
[env:LilyGo_T3S3_sx1262_Repeater]
extends = LilyGo_T3S3_sx1262
build_src_filter = ${LilyGo_T3S3_sx1262.build_src_filter} +<../examples/simple_repeater/main.cpp>
build_flags =
${LilyGo_T3S3_sx1262.build_flags}
-D ADVERT_NAME="\"T3S3-1262 Repeater\""
-D ADVERT_LAT=-37.0
-D ADVERT_LON=145.0
-D ADMIN_PASSWORD="\"password\""
; -D MESH_PACKET_LOGGING=1
; -D MESH_DEBUG=1
[env:LilyGo_T3S3_sx1262_terminal_chat]
extends = LilyGo_T3S3_sx1262
build_flags =
${LilyGo_T3S3_sx1262.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_sx1262.build_src_filter} +<../examples/simple_secure_chat/main.cpp>
lib_deps =
${LilyGo_T3S3_sx1262.lib_deps}
densaugeo/base64 @ ~1.4.0
[env:LilyGo_T3S3_sx1262_companion_radio_usb]
extends = LilyGo_T3S3_sx1262
build_flags =
${LilyGo_T3S3_sx1262.build_flags}
-D MAX_CONTACTS=100
-D MAX_GROUP_CHANNELS=1
; -D ENABLE_PRIVATE_KEY_IMPORT=1
; -D ENABLE_PRIVATE_KEY_EXPORT=1
; NOTE: DO NOT ENABLE --> -D MESH_PACKET_LOGGING=1
; NOTE: DO NOT ENABLE --> -D MESH_DEBUG=1
build_src_filter = ${LilyGo_T3S3_sx1262.build_src_filter} +<../examples/companion_radio/main.cpp>
lib_deps =
${LilyGo_T3S3_sx1262.lib_deps}
densaugeo/base64 @ ~1.4.0
[env:LilyGo_T3S3_sx1262_companion_radio_ble]
extends = LilyGo_T3S3_sx1262
build_flags =
${LilyGo_T3S3_sx1262.build_flags}
-D MAX_CONTACTS=100
-D MAX_GROUP_CHANNELS=1
-D BLE_PIN_CODE=123456
-D BLE_DEBUG_LOGGING=1
; -D ENABLE_PRIVATE_KEY_IMPORT=1
; -D ENABLE_PRIVATE_KEY_EXPORT=1
; -D MESH_PACKET_LOGGING=1
; -D MESH_DEBUG=1
build_src_filter = ${LilyGo_T3S3_sx1262.build_src_filter} +<helpers/esp32/*.cpp> +<../examples/companion_radio/main.cpp>
lib_deps =
${LilyGo_T3S3_sx1262.lib_deps}
densaugeo/base64 @ ~1.4.0
; ----------------- NRF52 ---------------------
[nrf52_base]
@@ -538,250 +56,3 @@ lib_deps =
${nrf52_base.lib_deps}
rweather/Crypto @ ^0.4.0
https://github.com/adafruit/Adafruit_nRF52_Arduino
[rak4631]
extends = nrf52840_base
platform = https://github.com/maxgerhardt/platform-nordicnrf52.git#rak
board = wiscore_rak4631
board_check = true
build_src_filter = ${nrf52840_base.build_src_filter} +<helpers/nrf52/*.cpp>
build_flags = ${nrf52840_base.build_flags}
-D RAK_4631
-D RADIO_CLASS=CustomSX1262
-D WRAPPER_CLASS=CustomSX1262Wrapper
-D LORA_TX_POWER=22
-D SX126X_CURRENT_LIMIT=130
[env:RAK_4631_Repeater]
extends = rak4631
build_src_filter = ${rak4631.build_src_filter} +<../examples/simple_repeater/main.cpp>
build_flags =
${rak4631.build_flags}
-D ADVERT_NAME="\"RAK4631 Repeater\""
-D ADVERT_LAT=-37.0
-D ADVERT_LON=145.0
-D ADMIN_PASSWORD="\"password\""
; -D MESH_PACKET_LOGGING=1
; -D MESH_DEBUG=1
[env:RAK_4631_room_server]
extends = rak4631
build_src_filter = ${rak4631.build_src_filter} +<../examples/simple_room_server/main.cpp>
build_flags =
${rak4631.build_flags}
-D ADVERT_NAME="\"Test Room\""
-D ADVERT_LAT=-37.0
-D ADVERT_LON=145.0
-D ADMIN_PASSWORD="\"password\""
-D ROOM_PASSWORD="\"hello\""
; -D MESH_PACKET_LOGGING=1
; -D MESH_DEBUG=1
[env:RAK_4631_terminal_chat]
extends = rak4631
build_flags =
${rak4631.build_flags}
-D MAX_CONTACTS=100
-D MAX_GROUP_CHANNELS=1
-D MESH_PACKET_LOGGING=1
-D MESH_DEBUG=1
build_src_filter = ${rak4631.build_src_filter} +<../examples/simple_secure_chat/main.cpp>
lib_deps =
${rak4631.lib_deps}
densaugeo/base64 @ ~1.4.0
[env:RAK_4631_companion_radio_usb]
extends = rak4631
build_flags =
${rak4631.build_flags}
-D MAX_CONTACTS=100
-D MAX_GROUP_CHANNELS=1
; -D ENABLE_PRIVATE_KEY_IMPORT=1
; -D ENABLE_PRIVATE_KEY_EXPORT=1
; NOTE: DO NOT ENABLE --> -D MESH_PACKET_LOGGING=1
; NOTE: DO NOT ENABLE --> -D MESH_DEBUG=1
build_src_filter = ${rak4631.build_src_filter} +<../examples/companion_radio/main.cpp>
lib_deps =
${rak4631.lib_deps}
densaugeo/base64 @ ~1.4.0
[env:RAK_4631_companion_radio_ble]
extends = rak4631
build_flags =
${rak4631.build_flags}
-D MAX_CONTACTS=100
-D MAX_GROUP_CHANNELS=1
-D BLE_PIN_CODE=123456
-D BLE_DEBUG_LOGGING=1
; -D ENABLE_PRIVATE_KEY_IMPORT=1
; -D ENABLE_PRIVATE_KEY_EXPORT=1
; -D MESH_PACKET_LOGGING=1
; -D MESH_DEBUG=1
build_src_filter = ${rak4631.build_src_filter} +<helpers/nrf52/*.cpp> +<../examples/companion_radio/main.cpp>
lib_deps =
${rak4631.lib_deps}
densaugeo/base64 @ ~1.4.0
; ----------------- NRF52 T1000e---------------------
[nrf52840_t1000e]
extends = nrf52_base
platform_packages = framework-arduinoadafruitnrf52
build_flags = ${nrf52_base.build_flags}
-I src/helpers/nrf52
-I lib/nrf52/s140_nrf52_7.3.0_API/include
-I lib/nrf52/s140_nrf52_7.3.0_API/include/nrf52
lib_ignore =
BluetoothOTA
lvgl
lib5b4
lib_deps =
${nrf52_base.lib_deps}
rweather/Crypto @ ^0.4.0
[t1000-e]
extends = nrf52840_t1000e
board = tracker-t1000-e
board_build.ldscript = boards/nrf52840_s140_v7.ld
build_flags = ${nrf52840_t1000e.build_flags}
-Ivariants/t1000-e
-DT1000_E
-D PIN_USER_BTN=6
-D RADIO_CLASS=CustomLR1110
-D WRAPPER_CLASS=CustomLR1110Wrapper
build_src_filter = ${nrf52840_t1000e.build_src_filter}
+<helpers/*.cpp>
+<helpers/nrf52/T1000eBoard.cpp>
+<../variants/t1000-e>
debug_tool = jlink
upload_protocol = nrfutil
[env:t1000e_companion_radio_ble]
extends = t1000-e
build_flags = ${t1000-e.build_flags}
-D MAX_CONTACTS=100
-D MAX_GROUP_CHANNELS=1
-D BLE_PIN_CODE=123456
-D BLE_DEBUG_LOGGING=1
-D MESH_PACKET_LOGGING=1
-D MESH_DEBUG=1
build_src_filter = ${t1000-e.build_src_filter}
+<helpers/nrf52/SerialBLEInterface.cpp>
+<../examples/companion_radio/*.cpp>
lib_deps = ${t1000-e.lib_deps}
densaugeo/base64 @ ~1.4.0
[nrf52840_t114]
extends = nrf52_base
platform_packages = framework-arduinoadafruitnrf52
build_flags = ${nrf52_base.build_flags}
-I src/helpers/nrf52
-I lib/nrf52/s140_nrf52_6.1.1_API/include
-I lib/nrf52/s140_nrf52_6.1.1_API/include/nrf52
lib_deps =
${nrf52_base.lib_deps}
rweather/Crypto @ ^0.4.0
[Heltec_t114]
extends = nrf52840_t114
board = heltec_t114
board_build.ldscript = boards/nrf52840_s140_v6.ld
build_flags = ${nrf52840_t114.build_flags}
-Ivariants/t114
-DHELTEC_T114
-D RADIO_CLASS=CustomSX1262
-D WRAPPER_CLASS=CustomSX1262Wrapper
-D LORA_TX_POWER=22
-D SX126X_CURRENT_LIMIT=130
build_src_filter = ${nrf52840_t114.build_src_filter}
+<helpers/*.cpp>
+<helpers/nrf52/T114Board.cpp>
+<../variants/t114>
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>
build_flags =
${Heltec_t114.build_flags}
-D ADVERT_NAME="\"Heltec_T114 Repeater\""
-D ADVERT_LAT=-37.0
-D ADVERT_LON=145.0
-D ADMIN_PASSWORD="\"password\""
; -D MESH_PACKET_LOGGING=1
; -D MESH_DEBUG=1
[env:Heltec_t114_companion_radio_ble]
extends = Heltec_t114
build_flags =
${Heltec_t114.build_flags}
-D MAX_CONTACTS=100
-D MAX_GROUP_CHANNELS=1
-D BLE_PIN_CODE=123456
-D BLE_DEBUG_LOGGING=1
; -D ENABLE_PRIVATE_KEY_IMPORT=1
; -D ENABLE_PRIVATE_KEY_EXPORT=1
; -D MESH_PACKET_LOGGING=1
; -D MESH_DEBUG=1
build_src_filter = ${Heltec_t114.build_src_filter} +<helpers/nrf52/*.cpp> +<../examples/companion_radio/main.cpp>
lib_deps =
${Heltec_t114.lib_deps}
densaugeo/base64 @ ~1.4.0
[nrf52840_techo]
extends = nrf52_base
platform_packages = framework-arduinoadafruitnrf52
build_flags = ${nrf52_base.build_flags}
-I src/helpers/nrf52
-I lib/nrf52/s140_nrf52_6.1.1_API/include
-I lib/nrf52/s140_nrf52_6.1.1_API/include/nrf52
lib_deps =
${nrf52_base.lib_deps}
rweather/Crypto @ ^0.4.0
[LilyGo_Techo]
extends = nrf52840_techo
board = t-echo
board_build.ldscript = boards/nrf52840_s140_v6.ld
build_flags = ${nrf52840_techo.build_flags}
-Ivariants/techo
-DLILYGO_TECHO
-D RADIO_CLASS=CustomSX1262
-D WRAPPER_CLASS=CustomSX1262Wrapper
-D LORA_TX_POWER=22
-D SX126X_CURRENT_LIMIT=130
build_src_filter = ${nrf52840_techo.build_src_filter}
+<helpers/*.cpp>
+<helpers/nrf52/TechoBoard.cpp>
+<../variants/techo>
debug_tool = jlink
upload_protocol = nrfutil
[env:LilyGo_T-Echo_repeater]
extends = LilyGo_Techo
build_src_filter = ${LilyGo_Techo.build_src_filter} +<../examples/simple_repeater/main.cpp>
build_flags =
${LilyGo_Techo.build_flags}
-D ADVERT_NAME="\"T-Echo Repeater\""
-D ADVERT_LAT=-37.0
-D ADVERT_LON=145.0
-D ADMIN_PASSWORD="\"password\""
; -D MESH_PACKET_LOGGING=1
; -D MESH_DEBUG=1
[env:LilyGo_T-Echo_companion_radio_ble]
extends = LilyGo_Techo
build_flags =
${LilyGo_Techo.build_flags}
-D MAX_CONTACTS=100
-D MAX_GROUP_CHANNELS=1
-D BLE_PIN_CODE=123456
-D BLE_DEBUG_LOGGING=1
; -D ENABLE_PRIVATE_KEY_IMPORT=1
; -D ENABLE_PRIVATE_KEY_EXPORT=1
; -D MESH_PACKET_LOGGING=1
; -D MESH_DEBUG=1
build_src_filter = ${LilyGo_Techo.build_src_filter} +<helpers/nrf52/*.cpp> +<../examples/companion_radio/main.cpp>
lib_deps =
${LilyGo_Techo.lib_deps}
densaugeo/base64 @ ~1.4.0

View File

@@ -78,9 +78,11 @@ void Dispatcher::checkRecv() {
float score;
uint32_t air_time;
{
uint8_t raw[MAX_TRANS_UNIT];
uint8_t raw[MAX_TRANS_UNIT+1];
int len = _radio->recvRaw(raw, MAX_TRANS_UNIT);
if (len > 0) {
logRxRaw(_radio->getLastSNR(), _radio->getLastRSSI(), raw, len);
pkt = _mgr->allocNew();
if (pkt == NULL) {
MESH_DEBUG_PRINTLN("%s Dispatcher::checkRecv(): WARNING: received data, no unused packets available!", getLogDateTime());
@@ -106,10 +108,17 @@ void Dispatcher::checkRecv() {
memcpy(pkt->path, &raw[i], pkt->path_len); i += pkt->path_len;
pkt->payload_len = len - i; // payload is remainder
memcpy(pkt->payload, &raw[i], pkt->payload_len);
if (pkt->payload_len > sizeof(pkt->payload)) {
MESH_DEBUG_PRINTLN("%s Dispatcher::checkRecv(): packet payload too big, payload_len=%d", getLogDateTime(), (uint32_t)pkt->payload_len);
_mgr->free(pkt); // put back into pool
pkt = NULL;
} else {
memcpy(pkt->payload, &raw[i], pkt->payload_len);
score = _radio->packetScore(_radio->getLastSNR(), len);
air_time = _radio->getEstAirtimeFor(len);
pkt->_snr = _radio->getLastSNR() * 4.0f;
score = _radio->packetScore(_radio->getLastSNR(), len);
air_time = _radio->getEstAirtimeFor(len);
}
}
}
} else {
@@ -121,7 +130,13 @@ void Dispatcher::checkRecv() {
Serial.print(getLogDateTime());
Serial.printf(": RX, len=%d (type=%d, route=%s, payload_len=%d) SNR=%d RSSI=%d score=%d",
2 + pkt->path_len + pkt->payload_len, pkt->getPayloadType(), pkt->isRouteDirect() ? "D" : "F", pkt->payload_len,
(int)_radio->getLastSNR(), (int)_radio->getLastRSSI(), (int)(score*1000));
(int)pkt->getSNR(), (int)_radio->getLastRSSI(), (int)(score*1000));
static uint8_t packet_hash[MAX_HASH_SIZE];
pkt->calculatePacketHash(packet_hash);
Serial.print(" hash=");
mesh::Utils::printHex(Serial, packet_hash, MAX_HASH_SIZE);
if (pkt->getPayloadType() == PAYLOAD_TYPE_PATH || pkt->getPayloadType() == PAYLOAD_TYPE_REQ
|| pkt->getPayloadType() == PAYLOAD_TYPE_RESPONSE || pkt->getPayloadType() == PAYLOAD_TYPE_TXT_MSG) {
Serial.printf(" [%02X -> %02X]\n", (uint32_t)pkt->payload[1], (uint32_t)pkt->payload[0]);
@@ -219,6 +234,7 @@ Packet* Dispatcher::obtainNewPacket() {
n_full_events++;
} else {
pkt->payload_len = pkt->path_len = 0;
pkt->_snr = 0;
}
return pkt;
}

View File

@@ -117,6 +117,8 @@ protected:
virtual DispatcherAction onRecvPacket(Packet* pkt) = 0;
virtual void logRxRaw(float snr, float rssi, const uint8_t raw[], int len) { } // custom hook
virtual void logRx(Packet* packet, int len, float score) { } // hooks for custom logging
virtual void logTx(Packet* packet, int len) { }
virtual void logTxFail(Packet* packet, int len) { }

View File

@@ -2,6 +2,7 @@
#include <string.h>
#define ED25519_NO_SEED 1
#include <ed_25519.h>
#include <Ed25519.h>
namespace mesh {
@@ -14,7 +15,12 @@ Identity::Identity(const char* pub_hex) {
}
bool Identity::verify(const uint8_t* sig, const uint8_t* message, int msg_len) const {
#if 0
// NOTE: memory corruption bug was found in this function!!
return ed25519_verify(sig, message, msg_len, pub_key);
#else
return Ed25519::verify(sig, this->pub_key, message, msg_len);
#endif
}
bool Identity::readFrom(Stream& s) {

View File

@@ -41,6 +41,30 @@ DispatcherAction Mesh::onRecvPacket(Packet* pkt) {
return ACTION_RELEASE;
}
if (pkt->isRouteDirect() && pkt->getPayloadType() == PAYLOAD_TYPE_TRACE) {
if (pkt->path_len < MAX_PATH_SIZE) {
uint8_t i = 0;
uint32_t trace_tag;
memcpy(&trace_tag, &pkt->payload[i], 4); i += 4;
uint32_t auth_code;
memcpy(&auth_code, &pkt->payload[i], 4); i += 4;
uint8_t flags = pkt->payload[i++];
uint8_t len = pkt->payload_len - i;
if (pkt->path_len >= len) { // TRACE has reached end of given path
onTraceRecv(pkt, trace_tag, auth_code, flags, pkt->path, &pkt->payload[i], len);
} else if (self_id.isHashMatch(&pkt->payload[i + pkt->path_len]) && allowPacketForward(pkt) && !_tables->hasSeen(pkt)) {
// append SNR (Not hash!)
pkt->path[pkt->path_len] = (int8_t) (pkt->getSNR()*4);
pkt->path_len += PATH_HASH_SIZE;
uint32_t d = getDirectRetransmitDelay(pkt);
return ACTION_RETRANSMIT_DELAYED(5, d); // schedule with priority 5 (for now), maybe make configurable?
}
}
return ACTION_RELEASE;
}
if (pkt->isRouteDirect() && pkt->path_len >= PATH_HASH_SIZE) {
if (self_id.isHashMatch(pkt->path) && allowPacketForward(pkt)) {
if (_tables->hasSeen(pkt)) return ACTION_RELEASE; // don't retransmit!
@@ -79,7 +103,7 @@ DispatcherAction Mesh::onRecvPacket(Packet* pkt) {
uint8_t src_hash = pkt->payload[i++];
uint8_t* macAndData = &pkt->payload[i]; // MAC + encrypted data
if (i + 2 >= pkt->payload_len) {
if (i + CIPHER_MAC_SIZE >= pkt->payload_len) {
MESH_DEBUG_PRINTLN("%s Mesh::onRecvPacket(): incomplete data packet", getLogDateTime());
} else if (!_tables->hasSeen(pkt)) {
// NOTE: this is a 'first packet wins' impl. When receiving from multiple paths, the first to arrive wins.
@@ -333,7 +357,7 @@ Packet* Mesh::createPathReturn(const uint8_t* dest_hash, const uint8_t* secret,
Packet* Mesh::createDatagram(uint8_t type, const Identity& dest, const uint8_t* secret, const uint8_t* data, size_t data_len) {
if (type == PAYLOAD_TYPE_TXT_MSG || type == PAYLOAD_TYPE_REQ || type == PAYLOAD_TYPE_RESPONSE) {
if (data_len + 2 + CIPHER_BLOCK_SIZE-1 > MAX_PACKET_PAYLOAD) return NULL;
if (data_len + CIPHER_MAC_SIZE + CIPHER_BLOCK_SIZE-1 > MAX_PACKET_PAYLOAD) return NULL;
} else {
return NULL; // invalid type
}
@@ -433,7 +457,28 @@ Packet* Mesh::createRawData(const uint8_t* data, size_t len) {
return packet;
}
Packet* Mesh::createTrace(uint32_t tag, uint32_t auth_code, uint8_t flags) {
Packet* packet = obtainNewPacket();
if (packet == NULL) {
MESH_DEBUG_PRINTLN("%s Mesh::createTrace(): error, packet pool empty", getLogDateTime());
return NULL;
}
packet->header = (PAYLOAD_TYPE_TRACE << PH_TYPE_SHIFT); // ROUTE_TYPE_* set later
memcpy(packet->payload, &tag, 4);
memcpy(&packet->payload[4], &auth_code, 4);
packet->payload[8] = flags;
packet->payload_len = 9; // NOTE: path will be appended to payload[] later
return packet;
}
void Mesh::sendFlood(Packet* packet, uint32_t delay_millis) {
if (packet->getPayloadType() == PAYLOAD_TYPE_TRACE) {
MESH_DEBUG_PRINTLN("%s Mesh::sendFlood(): TRACE type not suspported", getLogDateTime());
return;
}
packet->header &= ~PH_ROUTE_MASK;
packet->header |= ROUTE_TYPE_FLOOD;
packet->path_len = 0;
@@ -455,11 +500,20 @@ void Mesh::sendDirect(Packet* packet, const uint8_t* path, uint8_t path_len, uin
packet->header &= ~PH_ROUTE_MASK;
packet->header |= ROUTE_TYPE_DIRECT;
memcpy(packet->path, path, packet->path_len = path_len);
uint8_t pri;
if (packet->getPayloadType() == PAYLOAD_TYPE_TRACE) { // TRACE packets are different
// for TRACE packets, path is appended to end of PAYLOAD. (path is used for SNR's)
memcpy(&packet->payload[packet->payload_len], path, path_len);
packet->payload_len += path_len;
packet->path_len = 0;
pri = 5; // maybe make this configurable
} else {
memcpy(packet->path, path, packet->path_len = path_len);
pri = 0;
}
_tables->hasSeen(packet); // mark this packet as already sent in case it is rebroadcast back to us
sendPacket(packet, 0, delay_millis);
sendPacket(packet, pri, delay_millis);
}
void Mesh::sendZeroHop(Packet* packet, uint32_t delay_millis) {

View File

@@ -100,9 +100,22 @@ protected:
* \param type one of: PAYLOAD_TYPE_TXT_MSG, PAYLOAD_TYPE_REQ, PAYLOAD_TYPE_RESPONSE
* \param sender_idx index of peer, [0..n) where n is what searchPeersByHash() returned
* \param secret the pre-calculated shared-secret (handy for sending response packet)
* \param data decrypted data from payload
*/
virtual void onPeerDataRecv(Packet* packet, uint8_t type, int sender_idx, const uint8_t* secret, uint8_t* data, size_t len) { }
/**
* \brief A TRACE packet has been received. (and has reached the end of its given path)
* NOTE: this may have been initiated by another node.
* \param tag a random (unique-ish) tag set by initiator
* \param auth_code a code to authenticate the packet
* \param flags zero for now
* \param path_snrs single byte SNR*4 for each hop in the path
* \param path_hashes hashes if each repeater in the path
* \param path_len length of the path_snrs[] and path_hashes[] arrays
*/
virtual void onTraceRecv(Packet* packet, uint32_t tag, uint32_t auth_code, uint8_t flags, const uint8_t* path_snrs, const uint8_t* path_hashes, uint8_t path_len) { }
/**
* \brief A path TO peer (sender_idx) has been received. (also with optional 'extra' data encoded)
* NOTE: these can be received multiple times (per sender), via differen routes
@@ -182,6 +195,7 @@ public:
Packet* createPathReturn(const uint8_t* dest_hash, const uint8_t* secret, const uint8_t* path, uint8_t path_len, uint8_t extra_type, const uint8_t*extra, size_t extra_len);
Packet* createPathReturn(const Identity& dest, const uint8_t* secret, const uint8_t* path, uint8_t path_len, uint8_t extra_type, const uint8_t*extra, size_t extra_len);
Packet* createRawData(const uint8_t* data, size_t len);
Packet* createTrace(uint32_t tag, uint32_t auth_code, uint8_t flags = 0);
/**
* \brief send a locally-generated Packet with flood routing
@@ -197,6 +211,7 @@ public:
* \brief send a locally-generated Packet to just neigbor nodes (zero hops)
*/
void sendZeroHop(Packet* packet, uint32_t delay_millis=0);
};
}

View File

@@ -40,6 +40,7 @@ public:
virtual void onBeforeTransmit() { }
virtual void onAfterTransmit() { }
virtual void reboot() = 0;
virtual void powerOff() { /* no op */ }
virtual uint8_t getStartupReason() const = 0;
virtual bool startOTAUpdate() { return false; } // not supported
};

View File

@@ -10,11 +10,13 @@ Packet::Packet() {
payload_len = 0;
}
void Packet::calculatePacketHash(uint8_t* hash) const {
SHA256 sha;
uint8_t t = getPayloadType();
sha.update(&t, 1);
if (t == PAYLOAD_TYPE_TRACE) {
sha.update(&path_len, sizeof(path_len)); // CAVEAT: TRACE packets can revisit same node on return path
}
sha.update(payload, payload_len);
sha.finalize(hash, MAX_HASH_SIZE);
}

View File

@@ -25,6 +25,7 @@ namespace mesh {
#define PAYLOAD_TYPE_GRP_DATA 0x06 // an (unverified) group datagram (prefixed with channel hash, MAC) (enc data: timestamp, blob)
#define PAYLOAD_TYPE_ANON_REQ 0x07 // generic request (prefixed with dest_hash, ephemeral pub_key, MAC) (enc data: ...)
#define PAYLOAD_TYPE_PATH 0x08 // returned path (prefixed with dest/src hashes, MAC) (enc data: path, extra)
#define PAYLOAD_TYPE_TRACE 0x09 // trace a path, collecting SNI for each hop
//...
#define PAYLOAD_TYPE_RAW_CUSTOM 0x0F // custom packet as raw bytes, for applications with custom encryption, payloads, etc
@@ -44,6 +45,7 @@ public:
uint16_t payload_len, path_len;
uint8_t path[MAX_PATH_SIZE];
uint8_t payload[MAX_PACKET_PAYLOAD];
int8_t _snr;
/**
* \brief calculate the hash of payload + type
@@ -72,6 +74,8 @@ public:
void markDoNotRetransmit() { header = 0xFF; }
bool isMarkedDoNotRetransmit() const { return header == 0xFF; }
float getSNR() const { return ((float)_snr) / 4.0f; }
/**
* \brief save entire packet as a blob
* \param dest (OUT) destination buffer (assumed to be MAX_MTU_SIZE)

View File

@@ -23,7 +23,12 @@ public:
#ifdef LILYGO_T3S3
void begin(HWCDC& serial) { _serial = &serial; }
#elif defined(NRF52_PLATFORM)
void begin(Adafruit_USBD_CDC& serial) { _serial = &serial; }
void begin(Adafruit_USBD_CDC& serial) {
_serial = &serial;
#ifdef RAK_4631
pinMode(WB_IO2, OUTPUT);
#endif
}
#else
void begin(HardwareSerial& serial) { _serial = &serial; }
#endif

View File

@@ -105,7 +105,7 @@ void BaseChatMesh::onPeerDataRecv(mesh::Packet* packet, uint8_t type, int sender
data[len] = 0; // need to make a C string again, with null terminator
if (flags == TXT_TYPE_PLAIN) {
onMessageRecv(from, packet->isRouteFlood() ? packet->path_len : 0xFF, timestamp, (const char *) &data[5]); // let UI know
onMessageRecv(from, packet, timestamp, (const char *) &data[5]); // let UI know
uint32_t ack_hash; // calc truncated hash of the message timestamp + text + sender pub_key, to prove to sender that we got it
mesh::Utils::sha256((uint8_t *) &ack_hash, 4, data, 5 + strlen((char *)&data[5]), from.id.pub_key, PUB_KEY_SIZE);
@@ -126,7 +126,7 @@ void BaseChatMesh::onPeerDataRecv(mesh::Packet* packet, uint8_t type, int sender
}
}
} else if (flags == TXT_TYPE_CLI_DATA) {
onCommandDataRecv(from, packet->isRouteFlood() ? packet->path_len : 0xFF, timestamp, (const char *) &data[5]); // let UI know
onCommandDataRecv(from, packet, timestamp, (const char *) &data[5]); // let UI know
// NOTE: no ack expected for CLI_DATA replies
if (packet->isRouteFlood()) {
@@ -138,7 +138,7 @@ void BaseChatMesh::onPeerDataRecv(mesh::Packet* packet, uint8_t type, int sender
if (timestamp > from.sync_since) { // make sure 'sync_since' is up-to-date
from.sync_since = timestamp;
}
onSignedMessageRecv(from, packet->isRouteFlood() ? packet->path_len : 0xFF, timestamp, &data[5], (const char *) &data[9]); // let UI know
onSignedMessageRecv(from, packet, timestamp, &data[5], (const char *) &data[9]); // let UI know
uint32_t ack_hash; // calc truncated hash of the message timestamp + text + OUR pub_key, to prove to sender that we got it
mesh::Utils::sha256((uint8_t *) &ack_hash, 4, data, 9 + strlen((char *)&data[9]), self_id.pub_key, PUB_KEY_SIZE);
@@ -203,9 +203,9 @@ void BaseChatMesh::onAckRecv(mesh::Packet* packet, uint32_t ack_crc) {
#ifdef MAX_GROUP_CHANNELS
int BaseChatMesh::searchChannelsByHash(const uint8_t* hash, mesh::GroupChannel dest[], int max_matches) {
int n = 0;
for (int i = 0; i < num_channels && n < max_matches; i++) {
if (channels[i].hash[0] == hash[0]) {
dest[n++] = channels[i];
for (int i = 0; i < MAX_GROUP_CHANNELS && n < max_matches; i++) {
if (channels[i].channel.hash[0] == hash[0]) {
dest[n++] = channels[i].channel;
}
}
return n;
@@ -222,7 +222,7 @@ void BaseChatMesh::onGroupDataRecv(mesh::Packet* packet, uint8_t type, const mes
data[len] = 0; // need to make a C string again, with null terminator
// notify UI of this new message
onChannelMessageRecv(channel, packet->isRouteFlood() ? packet->path_len : -1, timestamp, (const char *) &data[5]); // let UI know
onChannelMessageRecv(channel, packet, timestamp, (const char *) &data[5]); // let UI know
}
}
@@ -588,24 +588,61 @@ bool BaseChatMesh::removeContact(ContactInfo& contact) {
#ifdef MAX_GROUP_CHANNELS
#include <base64.hpp>
mesh::GroupChannel* BaseChatMesh::addChannel(const char* psk_base64) {
ChannelDetails* BaseChatMesh::addChannel(const char* name, const char* psk_base64) {
if (num_channels < MAX_GROUP_CHANNELS) {
auto dest = &channels[num_channels];
memset(dest->secret, 0, sizeof(dest->secret));
int len = decode_base64((unsigned char *) psk_base64, strlen(psk_base64), dest->secret);
memset(dest->channel.secret, 0, sizeof(dest->channel.secret));
int len = decode_base64((unsigned char *) psk_base64, strlen(psk_base64), dest->channel.secret);
if (len == 32 || len == 16) {
mesh::Utils::sha256(dest->hash, sizeof(dest->hash), dest->secret, len);
mesh::Utils::sha256(dest->channel.hash, sizeof(dest->channel.hash), dest->channel.secret, len);
StrHelper::strncpy(dest->name, name, sizeof(dest->name));
num_channels++;
return dest;
}
}
return NULL;
}
bool BaseChatMesh::getChannel(int idx, ChannelDetails& dest) {
if (idx >= 0 && idx < MAX_GROUP_CHANNELS) {
dest = channels[idx];
return true;
}
return false;
}
bool BaseChatMesh::setChannel(int idx, const ChannelDetails& src) {
static uint8_t zeroes[] = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 };
if (idx >= 0 && idx < MAX_GROUP_CHANNELS) {
channels[idx] = src;
if (memcmp(&src.channel.secret[16], zeroes, 16) == 0) {
mesh::Utils::sha256(channels[idx].channel.hash, sizeof(channels[idx].channel.hash), src.channel.secret, 16); // 128-bit key
} else {
mesh::Utils::sha256(channels[idx].channel.hash, sizeof(channels[idx].channel.hash), src.channel.secret, 32); // 256-bit key
}
return true;
}
return false;
}
int BaseChatMesh::findChannelIdx(const mesh::GroupChannel& ch) {
for (int i = 0; i < MAX_GROUP_CHANNELS; i++) {
if (memcmp(ch.secret, channels[i].channel.secret, sizeof(ch.secret)) == 0) return i;
}
return -1; // not found
}
#else
mesh::GroupChannel* BaseChatMesh::addChannel(const char* psk_base64) {
ChannelDetails* BaseChatMesh::addChannel(const char* name, const char* psk_base64) {
return NULL; // not supported
}
bool BaseChatMesh::getChannel(int idx, ChannelDetails& dest) {
return false;
}
bool BaseChatMesh::setChannel(int idx, const ChannelDetails& src) {
return false;
}
int BaseChatMesh::findChannelIdx(const mesh::GroupChannel& ch) {
return -1; // not found
}
#endif
ContactsIterator BaseChatMesh::startContactsIterator() {

View File

@@ -61,6 +61,11 @@ struct ConnectionInfo {
uint32_t expected_ack;
};
struct ChannelDetails {
mesh::GroupChannel channel;
char name[32];
};
/**
* \brief abstract Mesh class for common 'chat' client
*/
@@ -74,8 +79,8 @@ class BaseChatMesh : public mesh::Mesh {
int matching_peer_indexes[MAX_SEARCH_RESULTS];
unsigned long txt_send_timeout;
#ifdef MAX_GROUP_CHANNELS
mesh::GroupChannel channels[MAX_GROUP_CHANNELS];
int num_channels;
ChannelDetails channels[MAX_GROUP_CHANNELS];
int num_channels; // only for addChannel()
#endif
mesh::Packet* _pendingLoopback;
uint8_t temp_buf[MAX_TRANS_UNIT];
@@ -89,6 +94,7 @@ protected:
{
num_contacts = 0;
#ifdef MAX_GROUP_CHANNELS
memset(channels, 0, sizeof(channels));
num_channels = 0;
#endif
txt_send_timeout = 0;
@@ -100,13 +106,13 @@ protected:
virtual void onDiscoveredContact(ContactInfo& contact, bool is_new) = 0;
virtual bool processAck(const uint8_t *data) = 0;
virtual void onContactPathUpdated(const ContactInfo& contact) = 0;
virtual void onMessageRecv(const ContactInfo& contact, uint8_t path_len, uint32_t sender_timestamp, const char *text) = 0;
virtual void onCommandDataRecv(const ContactInfo& contact, uint8_t path_len, uint32_t sender_timestamp, const char *text) = 0;
virtual void onSignedMessageRecv(const ContactInfo& contact, uint8_t path_len, uint32_t sender_timestamp, const uint8_t *sender_prefix, const char *text) = 0;
virtual void onMessageRecv(const ContactInfo& contact, mesh::Packet* pkt, uint32_t sender_timestamp, const char *text) = 0;
virtual void onCommandDataRecv(const ContactInfo& contact, mesh::Packet* pkt, uint32_t sender_timestamp, const char *text) = 0;
virtual void onSignedMessageRecv(const ContactInfo& contact, mesh::Packet* pkt, uint32_t sender_timestamp, const uint8_t *sender_prefix, const char *text) = 0;
virtual uint32_t calcFloodTimeoutMillisFor(uint32_t pkt_airtime_millis) const = 0;
virtual uint32_t calcDirectTimeoutMillisFor(uint32_t pkt_airtime_millis, uint8_t path_len) const = 0;
virtual void onSendTimeout() = 0;
virtual void onChannelMessageRecv(const mesh::GroupChannel& channel, int in_path_len, uint32_t timestamp, const char *text) = 0;
virtual void onChannelMessageRecv(const mesh::GroupChannel& channel, mesh::Packet* pkt, uint32_t timestamp, const char *text) = 0;
virtual void onContactResponse(const ContactInfo& contact, const uint8_t* data, uint8_t len) = 0;
// storage concepts, for sub-classes to override/implement
@@ -151,7 +157,10 @@ public:
bool addContact(const ContactInfo& contact);
int getNumContacts() const { return num_contacts; }
ContactsIterator startContactsIterator();
mesh::GroupChannel* addChannel(const char* psk_base64);
ChannelDetails* addChannel(const char* name, const char* psk_base64);
bool getChannel(int idx, ChannelDetails& dest);
bool setChannel(int idx, const ChannelDetails& src);
int findChannelIdx(const mesh::GroupChannel& ch);
void loop();
};

View File

@@ -41,6 +41,7 @@ void CommonCLI::loadPrefs(FILESYSTEM* fs) {
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->flood_max, sizeof(_prefs->flood_max)); // 124
// sanitise bad pref values
_prefs->rx_delay_base = constrain(_prefs->rx_delay_base, 0, 20.0f);
@@ -91,6 +92,7 @@ void CommonCLI::savePrefs(FILESYSTEM* fs) {
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->flood_max, sizeof(_prefs->flood_max)); // 124
file.close();
}
@@ -176,6 +178,8 @@ void CommonCLI::handleCommand(uint32_t sender_timestamp, const char* command, ch
sprintf(reply, "> %s", StrHelper::ftoa(_prefs->rx_delay_base));
} else if (memcmp(config, "txdelay", 7) == 0) {
sprintf(reply, "> %s", StrHelper::ftoa(_prefs->tx_delay_factor));
} else if (memcmp(config, "flood.max", 9) == 0) {
sprintf(reply, "> %d", (uint32_t)_prefs->flood_max);
} else if (memcmp(config, "direct.txdelay", 14) == 0) {
sprintf(reply, "> %s", StrHelper::ftoa(_prefs->direct_tx_delay_factor));
} else if (memcmp(config, "tx", 2) == 0 && (config[2] == 0 || config[2] == ' ')) {
@@ -262,6 +266,15 @@ void CommonCLI::handleCommand(uint32_t sender_timestamp, const char* command, ch
} else {
strcpy(reply, "Error, cannot be negative");
}
} else if (memcmp(config, "flood.max ", 10) == 0) {
uint8_t m = atoi(&config[10]);
if (m <= 64) {
_prefs->flood_max = m;
savePrefs();
strcpy(reply, "OK");
} else {
strcpy(reply, "Error, max 64");
}
} else if (memcmp(config, "direct.txdelay ", 15) == 0) {
float f = atof(&config[15]);
if (f >= 0) {

View File

@@ -23,6 +23,7 @@ struct NodePrefs { // persisted to file
uint8_t reserved1;
uint8_t reserved2;
float bw;
uint8_t flood_max;
};
class CommonCLICallbacks {

View File

@@ -9,7 +9,7 @@ class CustomLLCC68 : public LLCC68 {
CustomLLCC68(Module *mod) : LLCC68(mod) { }
bool isReceiving() {
uint16_t irq = getIrqStatus();
uint16_t irq = getIrqFlags();
bool hasPreamble = (irq & SX126X_IRQ_HEADER_VALID);
return hasPreamble;
}

View File

@@ -9,7 +9,7 @@ class CustomSX1262 : public SX1262 {
CustomSX1262(Module *mod) : SX1262(mod) { }
bool isReceiving() {
uint16_t irq = getIrqStatus();
uint16_t irq = getIrqFlags();
bool hasPreamble = (irq & SX126X_IRQ_HEADER_VALID);
return hasPreamble;
}

View File

@@ -9,7 +9,7 @@ class CustomSX1268 : public SX1268 {
CustomSX1268(Module *mod) : SX1268(mod) { }
bool isReceiving() {
uint16_t irq = getIrqStatus();
uint16_t irq = getIrqFlags();
bool hasPreamble = (irq & SX126X_IRQ_HEADER_VALID);
return hasPreamble;
}

View File

@@ -17,6 +17,10 @@ public:
// for future use, sub-classes SHOULD call this from their begin()
startup_reason = BD_STARTUP_NORMAL;
#ifdef ESP32_CPU_FREQ
setCpuFrequencyMhz(ESP32_CPU_FREQ);
#endif
#ifdef PIN_VBAT_READ
// battery read support
pinMode(PIN_VBAT_READ, INPUT);

View File

@@ -24,12 +24,22 @@
#include <driver/rtc_io.h>
class HeltecV3Board : public ESP32Board {
private:
bool adc_active_state;
public:
void begin() {
ESP32Board::begin();
// Auto-detect correct ADC_CTRL pin polarity (different for boards >3.2)
pinMode(PIN_ADC_CTRL, INPUT);
adc_active_state = !digitalRead(PIN_ADC_CTRL);
pinMode(PIN_ADC_CTRL, OUTPUT);
//pinMode(PIN_VEXT_EN, OUTPUT);
digitalWrite(PIN_ADC_CTRL, !adc_active_state); // Initially inactive
pinMode(PIN_VEXT_EN, OUTPUT);
digitalWrite(PIN_VEXT_EN, LOW); // for V3.2 boards
esp_reset_reason_t reason = esp_reset_reason();
if (reason == ESP_RST_DEEPSLEEP) {
@@ -66,9 +76,14 @@ public:
esp_deep_sleep_start(); // CPU halts here and never returns!
}
void powerOff() override {
// TODO: re-enable this when there is a definite wake-up source pin:
// enterDeepSleep(0);
}
uint16_t getBattMilliVolts() override {
analogReadResolution(10);
digitalWrite(PIN_ADC_CTRL, PIN_ADC_CTRL_ACTIVE);
digitalWrite(PIN_ADC_CTRL, adc_active_state);
uint32_t raw = 0;
for (int i = 0; i < 8; i++) {
@@ -76,7 +91,7 @@ public:
}
raw = raw / 8;
digitalWrite(PIN_ADC_CTRL, PIN_ADC_CTRL_INACTIVE);
digitalWrite(PIN_ADC_CTRL, !adc_active_state);
return (5.2 * (3.3 / 1024.0) * raw) * 1000;
}

View File

@@ -52,10 +52,11 @@ int RadioLibWrapper::recvRaw(uint8_t* bytes, int sz) {
int err = _radio->readData(bytes, len);
if (err != RADIOLIB_ERR_NONE) {
MESH_DEBUG_PRINTLN("RadioLibWrapper: error: readData(%d)", err);
len = 0;
} else {
// Serial.print(" readData() -> "); Serial.println(len);
n_recv++;
}
n_recv++;
}
state = STATE_IDLE; // need another startReceive()
return len;

View File

@@ -0,0 +1,69 @@
#pragma once
#include <Arduino.h>
// LoRa radio module pins for Station G2
#define P_LORA_DIO_1 48
#define P_LORA_NSS 11
#define P_LORA_RESET 21
#define P_LORA_BUSY 47
#define P_LORA_SCLK 12
#define P_LORA_MISO 14
#define P_LORA_MOSI 13
// built-ins
//#define PIN_LED_BUILTIN 35
//#define PIN_VEXT_EN 36
#include "ESP32Board.h"
#include <driver/rtc_io.h>
class StationG2Board : public ESP32Board {
public:
void begin() {
ESP32Board::begin();
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 0;
}
const char* getManufacturerName() const override {
return "Station G2";
}
};

82
src/helpers/TBeamBoard.h Normal file
View File

@@ -0,0 +1,82 @@
#pragma once
#include <Wire.h>
#include <Arduino.h>
#include "XPowersLib.h"
// Defined using AXP2102
#define XPOWERS_CHIP_AXP2101
// 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 {
XPowersAXP2101 power;
public:
void begin() {
ESP32Board::begin();
power.setALDO2Voltage(3300);
power.enableALDO2();
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 0;
}
const char* getManufacturerName() const override {
return "LilyGo T-Beam";
}
};

View File

@@ -6,75 +6,75 @@
static BLEDfu bledfu;
static void connect_callback(uint16_t conn_handle)
{
(void)conn_handle;
MESH_DEBUG_PRINTLN("BLE client connected");
static void connect_callback(uint16_t conn_handle) {
(void)conn_handle;
MESH_DEBUG_PRINTLN("BLE client connected");
}
static void disconnect_callback(uint16_t conn_handle, uint8_t reason)
{
(void)conn_handle;
(void)reason;
static void disconnect_callback(uint16_t conn_handle, uint8_t reason) {
(void)conn_handle;
(void)reason;
MESH_DEBUG_PRINTLN("BLE client disconnected");
MESH_DEBUG_PRINTLN("BLE client disconnected");
}
void RAK4631Board::begin() {
// for future use, sub-classes SHOULD call this from their begin()
startup_reason = BD_STARTUP_NORMAL;
pinMode(PIN_VBAT_READ, INPUT);
#ifdef PIN_USER_BTN
pinMode(PIN_USER_BTN, INPUT_PULLUP);
#endif
#if defined(PIN_BOARD_SDA) && defined(PIN_BOARD_SCL)
Wire.begin(PIN_BOARD_SDA, PIN_BOARD_SCL);
#else
Wire.begin();
Wire.setPins(PIN_BOARD_SDA, PIN_BOARD_SCL)
#endif
Wire.begin();
pinMode(SX126X_POWER_EN, OUTPUT);
digitalWrite(SX126X_POWER_EN, HIGH);
delay(10); // give sx1262 some time to power up
}
bool RAK4631Board::startOTAUpdate() {
// Config the peripheral connection with maximum bandwidth
// more SRAM required by SoftDevice
// Note: All config***() function must be called before begin()
Bluefruit.configPrphBandwidth(BANDWIDTH_MAX);
Bluefruit.configPrphConn(92, BLE_GAP_EVENT_LENGTH_MIN, 16, 16);
// Config the peripheral connection with maximum bandwidth
// more SRAM required by SoftDevice
// Note: All config***() function must be called before begin()
Bluefruit.configPrphBandwidth(BANDWIDTH_MAX);
Bluefruit.configPrphConn(92, BLE_GAP_EVENT_LENGTH_MIN, 16, 16);
Bluefruit.begin(1, 0);
// 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("RAK4631_OTA");
Bluefruit.begin(1, 0);
// 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("RAK4631_OTA");
Bluefruit.Periph.setConnectCallback(connect_callback);
Bluefruit.Periph.setDisconnectCallback(disconnect_callback);
Bluefruit.Periph.setConnectCallback(connect_callback);
Bluefruit.Periph.setDisconnectCallback(disconnect_callback);
// To be consistent OTA DFU should be added first if it exists
bledfu.begin();
// To be consistent OTA DFU should be added first if it exists
bledfu.begin();
// Set up and start advertising
// Advertising packet
Bluefruit.Advertising.addFlags(BLE_GAP_ADV_FLAGS_LE_ONLY_GENERAL_DISC_MODE);
Bluefruit.Advertising.addTxPower();
Bluefruit.Advertising.addName();
// Set up and start advertising
// Advertising packet
Bluefruit.Advertising.addFlags(BLE_GAP_ADV_FLAGS_LE_ONLY_GENERAL_DISC_MODE);
Bluefruit.Advertising.addTxPower();
Bluefruit.Advertising.addName();
/* Start Advertising
- Enable auto advertising if disconnected
- Interval: fast mode = 20 ms, slow mode = 152.5 ms
- Timeout for fast mode is 30 seconds
- Start(timeout) with timeout = 0 will advertise forever (until connected)
/* Start Advertising
- Enable auto advertising if disconnected
- Interval: fast mode = 20 ms, slow mode = 152.5 ms
- Timeout for fast mode is 30 seconds
- Start(timeout) with timeout = 0 will advertise forever (until connected)
For recommended advertising interval
https://developer.apple.com/library/content/qa/qa1931/_index.html
*/
Bluefruit.Advertising.restartOnDisconnect(true);
Bluefruit.Advertising.setInterval(32, 244); // in unit of 0.625 ms
Bluefruit.Advertising.setFastTimeout(30); // number of seconds in fast mode
Bluefruit.Advertising.start(0); // 0 = Don't stop advertising after n seconds
For recommended advertising interval
https://developer.apple.com/library/content/qa/qa1931/_index.html
*/
Bluefruit.Advertising.restartOnDisconnect(true);
Bluefruit.Advertising.setInterval(32, 244); // in unit of 0.625 ms
Bluefruit.Advertising.setFastTimeout(30); // number of seconds in fast mode
Bluefruit.Advertising.start(0); // 0 = Don't stop advertising after n seconds
return true;
}

View File

@@ -4,8 +4,7 @@
#include <bluefruit.h>
void T1000eBoard::begin()
{
void T1000eBoard::begin() {
// for future use, sub-classes SHOULD call this from their begin()
startup_reason = BD_STARTUP_NORMAL;
btn_prev_state = HIGH;
@@ -17,70 +16,68 @@ void T1000eBoard::begin()
#endif
#if defined(PIN_BOARD_SDA) && defined(PIN_BOARD_SCL)
Wire.begin(PIN_BOARD_SDA, PIN_BOARD_SCL);
#else
Wire.begin();
Wire.setPins(PIN_BOARD_SDA, PIN_BOARD_SCL)
#endif
Wire.begin();
delay(10); // give sx1262 some time to power up
}
#if 0
static BLEDfu bledfu;
static void connect_callback(uint16_t conn_handle)
{
(void)conn_handle;
MESH_DEBUG_PRINTLN("BLE client connected");
static void connect_callback(uint16_t conn_handle) {
(void)conn_handle;
MESH_DEBUG_PRINTLN("BLE client connected");
}
static void disconnect_callback(uint16_t conn_handle, uint8_t reason)
{
(void)conn_handle;
(void)reason;
static void disconnect_callback(uint16_t conn_handle, uint8_t reason) {
(void)conn_handle;
(void)reason;
MESH_DEBUG_PRINTLN("BLE client disconnected");
MESH_DEBUG_PRINTLN("BLE client disconnected");
}
bool TrackerT1000eBoard::startOTAUpdate() {
// Config the peripheral connection with maximum bandwidth
// more SRAM required by SoftDevice
// Note: All config***() function must be called before begin()
Bluefruit.configPrphBandwidth(BANDWIDTH_MAX);
Bluefruit.configPrphConn(92, BLE_GAP_EVENT_LENGTH_MIN, 16, 16);
// Config the peripheral connection with maximum bandwidth
// more SRAM required by SoftDevice
// Note: All config***() function must be called before begin()
Bluefruit.configPrphBandwidth(BANDWIDTH_MAX);
Bluefruit.configPrphConn(92, BLE_GAP_EVENT_LENGTH_MIN, 16, 16);
Bluefruit.begin(1, 0);
// 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("T1000E_OTA");
Bluefruit.begin(1, 0);
// 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("T1000E_OTA");
Bluefruit.Periph.setConnectCallback(connect_callback);
Bluefruit.Periph.setDisconnectCallback(disconnect_callback);
Bluefruit.Periph.setConnectCallback(connect_callback);
Bluefruit.Periph.setDisconnectCallback(disconnect_callback);
// To be consistent OTA DFU should be added first if it exists
bledfu.begin();
// To be consistent OTA DFU should be added first if it exists
bledfu.begin();
// Set up and start advertising
// Advertising packet
Bluefruit.Advertising.addFlags(BLE_GAP_ADV_FLAGS_LE_ONLY_GENERAL_DISC_MODE);
Bluefruit.Advertising.addTxPower();
Bluefruit.Advertising.addName();
// Set up and start advertising
// Advertising packet
Bluefruit.Advertising.addFlags(BLE_GAP_ADV_FLAGS_LE_ONLY_GENERAL_DISC_MODE);
Bluefruit.Advertising.addTxPower();
Bluefruit.Advertising.addName();
/* Start Advertising
- Enable auto advertising if disconnected
- Interval: fast mode = 20 ms, slow mode = 152.5 ms
- Timeout for fast mode is 30 seconds
- Start(timeout) with timeout = 0 will advertise forever (until connected)
/* Start Advertising
- Enable auto advertising if disconnected
- Interval: fast mode = 20 ms, slow mode = 152.5 ms
- Timeout for fast mode is 30 seconds
- Start(timeout) with timeout = 0 will advertise forever (until connected)
For recommended advertising interval
https://developer.apple.com/library/content/qa/qa1931/_index.html
*/
Bluefruit.Advertising.restartOnDisconnect(true);
Bluefruit.Advertising.setInterval(32, 244); // in unit of 0.625 ms
Bluefruit.Advertising.setFastTimeout(30); // number of seconds in fast mode
Bluefruit.Advertising.start(0); // 0 = Don't stop advertising after n seconds
For recommended advertising interval
https://developer.apple.com/library/content/qa/qa1931/_index.html
*/
Bluefruit.Advertising.restartOnDisconnect(true);
Bluefruit.Advertising.setInterval(32, 244); // in unit of 0.625 ms
Bluefruit.Advertising.setFastTimeout(30); // number of seconds in fast mode
Bluefruit.Advertising.start(0); // 0 = Don't stop advertising after n seconds
return true;
}

View File

@@ -3,8 +3,6 @@
#include <MeshCore.h>
#include <Arduino.h>
#define HAS_T1000e_POWEROFF
// LoRa and SPI pins
#define P_LORA_DIO_1 (32 + 1) // P1.1
#define P_LORA_NSS (0 + 12) // P0.12
@@ -31,8 +29,13 @@ public:
uint16_t getBattMilliVolts() override {
#ifdef BATTERY_PIN
analogReference(AR_INTERNAL_3_0);
analogReadResolution(12);
float volts = (analogRead(BATTERY_PIN) * ADC_MULTIPLIER * AREF_VOLTAGE) / 4096;
analogReference(AR_DEFAULT); // put back to default
analogReadResolution(10);
return volts * 1000;
#else
return 0;
@@ -56,7 +59,7 @@ public:
return 0;
}
void powerOff() {
void powerOff() override {
#ifdef HAS_GPS
digitalWrite(GPS_VRTC_EN, LOW);
digitalWrite(GPS_RESET, LOW);

View File

@@ -27,9 +27,14 @@ void T114Board::begin() {
pinMode(PIN_VBAT_READ, INPUT);
#if defined(PIN_BOARD_SDA) && defined(PIN_BOARD_SCL)
Wire.begin(PIN_BOARD_SDA, PIN_BOARD_SCL);
#else
Wire.setPins(PIN_BOARD_SDA, PIN_BOARD_SCL)
#endif
Wire.begin();
#ifdef P_LORA_TX_LED
pinMode(P_LORA_TX_LED, OUTPUT);
digitalWrite(P_LORA_TX_LED, HIGH);
#endif
pinMode(SX126X_POWER_EN, OUTPUT);

View File

@@ -28,6 +28,15 @@ public:
void begin();
uint8_t getStartupReason() const override { return startup_reason; }
#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
#define BATTERY_SAMPLES 8
uint16_t getBattMilliVolts() override {

View File

@@ -6,14 +6,12 @@
static BLEDfu bledfu;
static void connect_callback(uint16_t conn_handle)
{
static void connect_callback(uint16_t conn_handle) {
(void)conn_handle;
MESH_DEBUG_PRINTLN("BLE client connected");
}
static void disconnect_callback(uint16_t conn_handle, uint8_t reason)
{
static void disconnect_callback(uint16_t conn_handle, uint8_t reason) {
(void)conn_handle;
(void)reason;
@@ -27,11 +25,11 @@ void TechoBoard::begin() {
pinMode(PIN_VBAT_READ, INPUT);
#if defined(PIN_BOARD_SDA) && defined(PIN_BOARD_SCL)
Wire.begin(PIN_BOARD_SDA, PIN_BOARD_SCL);
#else
Wire.begin();
Wire.setPins(PIN_BOARD_SDA, PIN_BOARD_SCL)
#endif
Wire.begin();
pinMode(SX126X_POWER_EN, OUTPUT);
digitalWrite(SX126X_POWER_EN, HIGH);
delay(10); // give sx1262 some time to power up

View File

@@ -0,0 +1,61 @@
#include <Arduino.h>
#include "faketecBoard.h"
#include <bluefruit.h>
#include <Wire.h>
static BLEDfu bledfu;
static void connect_callback(uint16_t conn_handle) {
(void)conn_handle;
MESH_DEBUG_PRINTLN("BLE client connected");
}
static void disconnect_callback(uint16_t conn_handle, uint8_t reason) {
(void)conn_handle;
(void)reason;
MESH_DEBUG_PRINTLN("BLE client disconnected");
}
bool faketecBoard::startOTAUpdate() {
// Config the peripheral connection with maximum bandwidth
// more SRAM required by SoftDevice
// Note: All config***() function must be called before begin()
Bluefruit.configPrphBandwidth(BANDWIDTH_MAX);
Bluefruit.configPrphConn(92, BLE_GAP_EVENT_LENGTH_MIN, 16, 16);
Bluefruit.begin(1, 0);
// 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("Faketec_OTA");
Bluefruit.Periph.setConnectCallback(connect_callback);
Bluefruit.Periph.setDisconnectCallback(disconnect_callback);
// To be consistent OTA DFU should be added first if it exists
bledfu.begin();
// Set up and start advertising
// Advertising packet
Bluefruit.Advertising.addFlags(BLE_GAP_ADV_FLAGS_LE_ONLY_GENERAL_DISC_MODE);
Bluefruit.Advertising.addTxPower();
Bluefruit.Advertising.addName();
/* Start Advertising
- Enable auto advertising if disconnected
- Interval: fast mode = 20 ms, slow mode = 152.5 ms
- Timeout for fast mode is 30 seconds
- Start(timeout) with timeout = 0 will advertise forever (until connected)
For recommended advertising interval
https://developer.apple.com/library/content/qa/qa1931/_index.html
*/
Bluefruit.Advertising.restartOnDisconnect(true);
Bluefruit.Advertising.setInterval(32, 244); // in unit of 0.625 ms
Bluefruit.Advertising.setFastTimeout(30); // number of seconds in fast mode
Bluefruit.Advertising.start(0); // 0 = Don't stop advertising after n seconds
return true;
}

View File

@@ -0,0 +1,69 @@
#pragma once
#include <MeshCore.h>
#include <Arduino.h>
#include <Wire.h>
#define P_LORA_NSS 13 //P1.13 45
#define P_LORA_DIO_1 11 //P0.10 10
#define P_LORA_RESET 10 //P0.09 9
#define P_LORA_BUSY 16 //P0.29 29
#define P_LORA_MISO 15 //P0.02 2
#define P_LORA_SCLK 12 //P1.11 43
#define P_LORA_MOSI 14 //P1.15 47
#define SX126X_POWER_EN 21 //P0.13 13
#define SX126X_RXEN 2 //P0.17
#define SX126X_TXEN RADIOLIB_NC
#define SX126X_DIO2_AS_RF_SWITCH true
#define SX126X_DIO3_TCXO_VOLTAGE (1.8f)
#define PIN_VBAT_READ 17
#define ADC_MULTIPLIER (1.815f) // dependent on voltage divider resistors. TODO: more accurate battery tracking
class faketecBoard : public mesh::MainBoard {
protected:
uint8_t startup_reason;
public:
void begin() {
// for future use, sub-classes SHOULD call this from their begin()
startup_reason = BD_STARTUP_NORMAL;
pinMode(PIN_VBAT_READ, INPUT);
#if defined(PIN_BOARD_SDA) && defined(PIN_BOARD_SCL)
Wire.setPins(PIN_BOARD_SDA, PIN_BOARD_SCL)
#endif
Wire.begin();
pinMode(SX126X_POWER_EN, OUTPUT);
digitalWrite(SX126X_POWER_EN, HIGH);
delay(10); // give sx1262 some time to power up
}
uint8_t getStartupReason() const override { return startup_reason; }
#define BATTERY_SAMPLES 8
uint16_t getBattMilliVolts() override {
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);
}
const char* getManufacturerName() const override {
return "Faketec DIY";
}
void reboot() override {
NVIC_SystemReset();
}
bool startOTAUpdate() override;
};

View File

@@ -1,7 +1,13 @@
#include "SSD1306Display.h"
bool SSD1306Display::i2c_probe(TwoWire& wire, uint8_t addr) {
wire.beginTransmission(addr);
uint8_t error = wire.endTransmission();
return (error == 0);
}
bool SSD1306Display::begin() {
return display.begin(SSD1306_SWITCHCAPVCC, DISPLAY_ADDRESS, true, false);
return display.begin(SSD1306_SWITCHCAPVCC, DISPLAY_ADDRESS, true, false) && i2c_probe(Wire, DISPLAY_ADDRESS);
}
void SSD1306Display::turnOn() {

View File

@@ -3,6 +3,7 @@
#include "DisplayDriver.h"
#include <Wire.h>
#include <Adafruit_GFX.h>
#define SSD1306_NO_SPLASH
#include <Adafruit_SSD1306.h>
#ifndef PIN_OLED_RESET
@@ -18,6 +19,7 @@ class SSD1306Display : public DisplayDriver {
bool _isOn;
uint8_t _color;
bool i2c_probe(TwoWire& wire, uint8_t addr);
public:
SSD1306Display() : DisplayDriver(128, 64), display(128, 64, &Wire, PIN_OLED_RESET) { _isOn = false; }
bool begin();

View File

@@ -0,0 +1,101 @@
[Heltec_lora32_v2]
extends = esp32_base
board = heltec_wifi_lora_32_V2 ; heltec_wifi_lora_32_V2
build_flags =
${esp32_base.build_flags}
-D HELTEC_LORA_V2
-D PIN_BOARD_SDA=4
-D PIN_BOARD_SCL=15
-D PIN_USER_BTN=0
-D PIN_OLED_RESET=16
-D RADIO_CLASS=CustomSX1276
-D WRAPPER_CLASS=CustomSX1276Wrapper
-D LORA_TX_POWER=20
-D P_LORA_TX_LED=25
build_src_filter = ${esp32_base.build_src_filter}
lib_deps =
${esp32_base.lib_deps}
adafruit/Adafruit SSD1306 @ ^2.5.13
[env:Heltec_v2_repeater]
extends = Heltec_lora32_v2
build_flags =
${Heltec_lora32_v2.build_flags}
-D DISPLAY_CLASS=SSD1306Display
-D ADVERT_NAME='"Heltec Repeater"'
-D ADVERT_LAT=-37.0
-D ADVERT_LON=145.0
-D ADMIN_PASSWORD='"password"'
; -D MESH_PACKET_LOGGING=1
; -D MESH_DEBUG=1
build_src_filter = ${Heltec_lora32_v2.build_src_filter}
+<../examples/simple_repeater>
+<helpers/ui/*.cpp>
[env:Heltec_v2_room_server]
extends = Heltec_lora32_v2
build_flags =
${Heltec_lora32_v2.build_flags}
-D DISPLAY_CLASS=SSD1306Display
-D ADVERT_NAME='"Heltec Room"'
-D ADVERT_LAT=-37.0
-D ADVERT_LON=145.0
-D ADMIN_PASSWORD='"password"'
-D ROOM_PASSWORD='"hello"'
; -D MESH_PACKET_LOGGING=1
; -D MESH_DEBUG=1
build_src_filter = ${Heltec_lora32_v2.build_src_filter}
+<helpers/ui/*.cpp>
+<../examples/simple_room_server>
[env:Heltec_v2_terminal_chat]
extends = Heltec_lora32_v2
build_flags =
${Heltec_lora32_v2.build_flags}
-D MAX_CONTACTS=100
-D MAX_GROUP_CHANNELS=1
; -D MESH_PACKET_LOGGING=1
; -D MESH_DEBUG=1
build_src_filter = ${Heltec_lora32_v2.build_src_filter}
+<../examples/simple_secure_chat/main.cpp>
lib_deps =
${Heltec_lora32_v2.lib_deps}
densaugeo/base64 @ ~1.4.0
[env:Heltec_v2_companion_radio_usb]
extends = Heltec_lora32_v2
build_flags =
${Heltec_lora32_v2.build_flags}
-D DISPLAY_CLASS=SSD1306Display
-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 = ${Heltec_lora32_v2.build_src_filter}
+<helpers/esp32/*.cpp>
+<helpers/ui/*.cpp>
+<../examples/companion_radio>
lib_deps =
${Heltec_lora32_v2.lib_deps}
densaugeo/base64 @ ~1.4.0
[env:Heltec_v2_companion_radio_ble]
extends = Heltec_lora32_v2
build_flags =
${Heltec_lora32_v2.build_flags}
-D DISPLAY_CLASS=SSD1306Display
-D MAX_CONTACTS=100
-D MAX_GROUP_CHANNELS=8
-D BLE_PIN_CODE=0
-D BLE_DEBUG_LOGGING=1
; -D ENABLE_PRIVATE_KEY_IMPORT=1
; -D ENABLE_PRIVATE_KEY_EXPORT=1
; -D MESH_PACKET_LOGGING=1
; -D MESH_DEBUG=1
build_src_filter = ${Heltec_lora32_v2.build_src_filter}
+<helpers/esp32/*.cpp>
+<helpers/ui/*.cpp>
+<../examples/companion_radio>
lib_deps =
${Heltec_lora32_v2.lib_deps}
densaugeo/base64 @ ~1.4.0

View File

@@ -0,0 +1,173 @@
[Heltec_lora32_v3]
extends = esp32_base
board = esp32-s3-devkitc-1
build_flags =
${esp32_base.build_flags}
-D HELTEC_LORA_V3
-D RADIO_CLASS=CustomSX1262
-D WRAPPER_CLASS=CustomSX1262Wrapper
-D LORA_TX_POWER=22
-D P_LORA_TX_LED=35
-D PIN_BOARD_SDA=17
-D PIN_BOARD_SCL=18
-D PIN_USER_BTN=0
-D SX126X_DIO2_AS_RF_SWITCH=true
-D SX126X_DIO3_TCXO_VOLTAGE=1.8
-D SX126X_CURRENT_LIMIT=130.0f ; for best TX power!
-D SX126X_RX_BOOSTED_GAIN=1
build_src_filter = ${esp32_base.build_src_filter}
lib_deps =
${esp32_base.lib_deps}
adafruit/Adafruit SSD1306 @ ^2.5.13
[env:Heltec_v3_repeater]
extends = Heltec_lora32_v3
build_flags =
${Heltec_lora32_v3.build_flags}
-D DISPLAY_CLASS=SSD1306Display
-D ADVERT_NAME='"Heltec Repeater"'
-D ADVERT_LAT=-37.0
-D ADVERT_LON=145.0
-D ADMIN_PASSWORD='"password"'
-D MESH_PACKET_LOGGING=1
; -D MESH_DEBUG=1
build_src_filter = ${Heltec_lora32_v3.build_src_filter}
+<helpers/ui/*.cpp>
+<../examples/simple_repeater>
[env:Heltec_v3_room_server]
extends = Heltec_lora32_v3
build_flags =
${Heltec_lora32_v3.build_flags}
-D DISPLAY_CLASS=SSD1306Display
-D ADVERT_NAME='"Heltec Room"'
-D ADVERT_LAT=-37.0
-D ADVERT_LON=145.0
-D ADMIN_PASSWORD='"password"'
-D ROOM_PASSWORD='"hello"'
; -D MESH_PACKET_LOGGING=1
; -D MESH_DEBUG=1
build_src_filter = ${Heltec_lora32_v3.build_src_filter}
+<helpers/ui/*.cpp>
+<../examples/simple_room_server>
[env:Heltec_v3_terminal_chat]
extends = Heltec_lora32_v3
build_flags =
${Heltec_lora32_v3.build_flags}
-D MAX_CONTACTS=100
-D MAX_GROUP_CHANNELS=1
; -D MESH_PACKET_LOGGING=1
; -D MESH_DEBUG=1
build_src_filter = ${Heltec_lora32_v3.build_src_filter}
+<../examples/simple_secure_chat/main.cpp>
lib_deps =
${Heltec_lora32_v3.lib_deps}
densaugeo/base64 @ ~1.4.0
[env:Heltec_v3_companion_radio_usb]
extends = Heltec_lora32_v3
build_flags =
${Heltec_lora32_v3.build_flags}
-D MAX_CONTACTS=100
-D MAX_GROUP_CHANNELS=8
-D DISPLAY_CLASS=SSD1306Display
; -D ENABLE_PRIVATE_KEY_IMPORT=1
; -D ENABLE_PRIVATE_KEY_EXPORT=1
; NOTE: DO NOT ENABLE --> -D MESH_PACKET_LOGGING=1
; NOTE: DO NOT ENABLE --> -D MESH_DEBUG=1
build_src_filter = ${Heltec_lora32_v3.build_src_filter}
+<helpers/ui/*.cpp>
+<../examples/companion_radio>
lib_deps =
${Heltec_lora32_v3.lib_deps}
densaugeo/base64 @ ~1.4.0
[env:Heltec_v3_companion_radio_ble]
extends = Heltec_lora32_v3
build_flags =
${Heltec_lora32_v3.build_flags}
-D MAX_CONTACTS=100
-D MAX_GROUP_CHANNELS=8
-D DISPLAY_CLASS=SSD1306Display
-D BLE_PIN_CODE=0 ; dynamic, random PIN
-D BLE_DEBUG_LOGGING=1
; -D ENABLE_PRIVATE_KEY_IMPORT=1
; -D ENABLE_PRIVATE_KEY_EXPORT=1
; -D MESH_PACKET_LOGGING=1
; -D MESH_DEBUG=1
build_src_filter = ${Heltec_lora32_v3.build_src_filter}
+<helpers/ui/*.cpp>
+<helpers/esp32/*.cpp>
+<../examples/companion_radio>
lib_deps =
${Heltec_lora32_v3.lib_deps}
densaugeo/base64 @ ~1.4.0
[env:Heltec_v3_companion_radio_wifi]
extends = Heltec_lora32_v3
build_flags =
${Heltec_lora32_v3.build_flags}
-D MAX_CONTACTS=100
-D MAX_GROUP_CHANNELS=8
-D DISPLAY_CLASS=SSD1306Display
-D WIFI_DEBUG_LOGGING=1
-D WIFI_SSID='"myssid"'
-D WIFI_PWD='"mypwd"'
; -D ENABLE_PRIVATE_KEY_IMPORT=1
; -D ENABLE_PRIVATE_KEY_EXPORT=1
; -D MESH_PACKET_LOGGING=1
; -D MESH_DEBUG=1
build_src_filter = ${Heltec_lora32_v3.build_src_filter}
+<helpers/ui/*.cpp>
+<helpers/esp32/*.cpp>
+<../examples/companion_radio>
lib_deps =
${Heltec_lora32_v3.lib_deps}
densaugeo/base64 @ ~1.4.0
[env:Heltec_WSL3_repeater]
extends = Heltec_lora32_v3
build_flags =
${Heltec_lora32_v3.build_flags}
-D ADVERT_NAME='"Heltec Repeater"'
-D ADVERT_LAT=-37.0
-D ADVERT_LON=145.0
-D ADMIN_PASSWORD='"password"'
-D MESH_PACKET_LOGGING=1
; -D MESH_DEBUG=1
build_src_filter = ${Heltec_lora32_v3.build_src_filter}
+<../examples/simple_repeater>
[env:Heltec_WSL3_room_server]
extends = Heltec_lora32_v3
build_src_filter = ${Heltec_lora32_v3.build_src_filter}
+<../examples/simple_room_server>
build_flags =
${Heltec_lora32_v3.build_flags}
-D ADVERT_NAME='"Heltec Room"'
-D ADVERT_LAT=-37.0
-D ADVERT_LON=145.0
-D ADMIN_PASSWORD='"password"'
-D ROOM_PASSWORD='"hello"'
; -D MESH_PACKET_LOGGING=1
; -D MESH_DEBUG=1
[env:Heltec_WSL3_companion_radio_ble]
extends = Heltec_lora32_v3
build_flags =
${Heltec_lora32_v3.build_flags}
-D MAX_CONTACTS=100
-D MAX_GROUP_CHANNELS=8
-D BLE_PIN_CODE=123456
-D BLE_DEBUG_LOGGING=1
; -D ENABLE_PRIVATE_KEY_IMPORT=1
; -D ENABLE_PRIVATE_KEY_EXPORT=1
; -D MESH_PACKET_LOGGING=1
; -D MESH_DEBUG=1
build_src_filter = ${Heltec_lora32_v3.build_src_filter}
+<helpers/esp32/*.cpp>
+<../examples/companion_radio>
lib_deps =
${Heltec_lora32_v3.lib_deps}
densaugeo/base64 @ ~1.4.0

View File

@@ -0,0 +1,116 @@
[LilyGo_T3S3_sx1262]
extends = esp32_base
board = t3_s3_v1_x
build_flags =
${esp32_base.build_flags}
-D LILYGO_T3S3
-D P_LORA_DIO_1=33
-D P_LORA_NSS=7
-D P_LORA_RESET=8 ; RADIOLIB_NC
-D P_LORA_BUSY=34
-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 P_LORA_TX_LED=37
-D PIN_OLED_RESET=21
-D SX126X_DIO2_AS_RF_SWITCH=true
-D SX126X_DIO3_TCXO_VOLTAGE=1.8
-D SX126X_CURRENT_LIMIT=130
-D RADIO_CLASS=CustomSX1262
-D WRAPPER_CLASS=CustomSX1262Wrapper
-D LORA_TX_POWER=22
-D SX126X_RX_BOOSTED_GAIN=1
build_src_filter = ${esp32_base.build_src_filter}
lib_deps =
${esp32_base.lib_deps}
adafruit/Adafruit SSD1306 @ ^2.5.13
; === LilyGo T3S3 with SX1262 environments ===
[env:LilyGo_T3S3_sx1262_Repeater]
extends = LilyGo_T3S3_sx1262
build_flags =
${LilyGo_T3S3_sx1262.build_flags}
-D DISPLAY_CLASS=SSD1306Display
-D ADVERT_NAME='"T3S3-1262 Repeater"'
-D ADVERT_LAT=-37.0
-D ADVERT_LON=145.0
-D ADMIN_PASSWORD='"password"'
; -D MESH_PACKET_LOGGING=1
; -D MESH_DEBUG=1
build_src_filter = ${LilyGo_T3S3_sx1262.build_src_filter}
+<helpers/ui/*.cpp>
+<../examples/simple_repeater>
[env:LilyGo_T3S3_sx1262_terminal_chat]
extends = LilyGo_T3S3_sx1262
build_flags =
${LilyGo_T3S3_sx1262.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_sx1262.build_src_filter}
+<../examples/simple_secure_chat/main.cpp>
lib_deps =
${LilyGo_T3S3_sx1262.lib_deps}
densaugeo/base64 @ ~1.4.0
[env:LilyGo_T3S3_sx1262_room_server]
extends = LilyGo_T3S3_sx1262
build_flags =
${LilyGo_T3S3_sx1262.build_flags}
-D DISPLAY_CLASS=SSD1306Display
-D ADVERT_NAME='"T3S3-1262 Room"'
-D ADVERT_LAT=-37.0
-D ADVERT_LON=145.0
-D ADMIN_PASSWORD='"password"'
-D ROOM_PASSWORD='"hello"'
; -D MESH_PACKET_LOGGING=1
; -D MESH_DEBUG=1
build_src_filter = ${LilyGo_T3S3_sx1262.build_src_filter}
+<helpers/ui/*.cpp>
+<../examples/simple_room_server>
[env:LilyGo_T3S3_sx1262_companion_radio_usb]
extends = LilyGo_T3S3_sx1262
build_flags =
${LilyGo_T3S3_sx1262.build_flags}
-D DISPLAY_CLASS=SSD1306Display
-D MAX_CONTACTS=100
-D MAX_GROUP_CHANNELS=8
; -D ENABLE_PRIVATE_KEY_IMPORT=1
; -D ENABLE_PRIVATE_KEY_EXPORT=1
; NOTE: DO NOT ENABLE --> -D MESH_PACKET_LOGGING=1
; NOTE: DO NOT ENABLE --> -D MESH_DEBUG=1
build_src_filter = ${LilyGo_T3S3_sx1262.build_src_filter}
+<helpers/ui/*.cpp>
+<../examples/companion_radio>
lib_deps =
${LilyGo_T3S3_sx1262.lib_deps}
densaugeo/base64 @ ~1.4.0
[env:LilyGo_T3S3_sx1262_companion_radio_ble]
extends = LilyGo_T3S3_sx1262
build_flags =
${LilyGo_T3S3_sx1262.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 ENABLE_PRIVATE_KEY_IMPORT=1
; -D ENABLE_PRIVATE_KEY_EXPORT=1
; -D MESH_PACKET_LOGGING=1
; -D MESH_DEBUG=1
build_src_filter = ${LilyGo_T3S3_sx1262.build_src_filter}
+<helpers/esp32/*.cpp>
+<helpers/ui/*.cpp>
+<../examples/companion_radio>
lib_deps =
${LilyGo_T3S3_sx1262.lib_deps}
densaugeo/base64 @ ~1.4.0

View File

@@ -0,0 +1,36 @@
[LilyGo_TBeam]
extends = esp32_base
board = ttgo-t-beam
build_flags =
${esp32_base.build_flags}
-D LILYGO_TBEAM
-D RADIO_CLASS=CustomSX1276
-D WRAPPER_CLASS=CustomSX1276Wrapper
-D LORA_TX_POWER=20
-D P_LORA_TX_LED=4
build_src_filter = ${esp32_base.build_src_filter}
board_build.partitions = min_spiffs.csv ; get around 4mb flash limit
[env:Tbeam_companion_radio_ble]
extends = LilyGo_TBeam
board_build.upload.maximum_ram_size=2000000
build_flags =
${LilyGo_TBeam.build_flags}
-D MAX_CONTACTS=100
-D MAX_GROUP_CHANNELS=1
-D BLE_PIN_CODE=123456
-D BLE_DEBUG_LOGGING=1
-D MESH_PACKET_LOGGING=1
-D MESH_DEBUG=1
-D RADIOLIB_DEBUG_BASIC=1
; -D ENABLE_PRIVATE_KEY_IMPORT=1
; -D ENABLE_PRIVATE_KEY_EXPORT=1
; -D MESH_PACKET_LOGGING=1
; -D MESH_DEBUG=1
build_src_filter = ${LilyGo_TBeam.build_src_filter}
+<helpers/esp32/*.cpp>
+<../examples/companion_radio/main.cpp>
lib_deps =
${LilyGo_TBeam.lib_deps}
densaugeo/base64 @ ~1.4.0
lewisxhe/XPowersLib@^0.2.7

View File

@@ -0,0 +1,111 @@
[LilyGo_TLora_V2_1_1_6]
extends = esp32_base
board = ttgo-lora32-v1 ; LILYGO T-LoRa V2.1-1.6 ESP32 with SX1276
build_unflags = -Os
build_type = release ; Set build type to release
board_build.partitions = min_spiffs.csv ; get around 4mb flash limit
build_flags =
${esp32_base.build_flags}
-Os -ffunction-sections -fdata-sections ; Optimize for size
-D LILYGO_TLORA ; LILYGO T-LoRa V2.1-1.6 ESP32 with SX1276
-D P_LORA_DIO_0=26 ; SX1276 DIO0 interrupt pin
-D P_LORA_DIO_1=33 ; SX1276 DIO1 interrupt pin
-D P_LORA_NSS=18 ; Chip select - SS pin
-D P_LORA_RESET=14 ; Reset pin
-D P_LORA_SCLK=5 ; SPI clock
-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_VBAT_READ=35 ; Battery voltage reading (analog pin)
-D PIN_USER_BTN=0
-D RADIO_CLASS=CustomSX1276
-D ARDUINO_LOOP_STACK_SIZE=16384
-D DISPLAY_CLASS=SSD1306Display
-D WRAPPER_CLASS=CustomSX1276Wrapper
-D LORA_TX_POWER=20
lib_deps =
${esp32_base.lib_deps}
adafruit/Adafruit SSD1306 @ ^2.5.13
; === LILYGO T-LoRa V2.1-1.6 with SX1276 environments ===
[env:LilyGo_TLora_V2_1_1_6_Repeater]
extends = LilyGo_TLora_V2_1_1_6
build_src_filter = ${LilyGo_TLora_V2_1_1_6.build_src_filter}
+<helpers/ui/*.cpp>
+<../examples/simple_repeater>
build_flags =
${LilyGo_TLora_V2_1_1_6.build_flags}
-D ADVERT_NAME='"TLora-V2.1-1.6 Repeater"'
-D ADVERT_LAT=-37.0
-D ADVERT_LON=145.0
-D ADMIN_PASSWORD='"password"'
; -D MESH_PACKET_LOGGING=1
; -D MESH_DEBUG=1
; -D CORE_DEBUG_LEVEL=3
[env:LilyGo_TLora_V2_1_1_6_terminal_chat]
extends = LilyGo_TLora_V2_1_1_6
build_flags =
${LilyGo_TLora_V2_1_1_6.build_flags}
-D MAX_CONTACTS=100
-D MAX_GROUP_CHANNELS=8
; -D MESH_PACKET_LOGGING=1
; -D MESH_DEBUG=1
build_src_filter = ${LilyGo_TLora_V2_1_1_6.build_src_filter}
+<helpers/ui/*.cpp>
+<../examples/simple_repeater>
lib_deps =
${LilyGo_TLora_V2_1_1_6.lib_deps}
densaugeo/base64 @ ~1.4.0
[env:LilyGo_TLora_V2_1_1_6_companion_radio_usb]
extends = LilyGo_TLora_V2_1_1_6
build_flags =
${LilyGo_TLora_V2_1_1_6.build_flags}
-D MAX_CONTACTS=100
-D MAX_GROUP_CHANNELS=8
; -D ENABLE_PRIVATE_KEY_IMPORT=1
; -D ENABLE_PRIVATE_KEY_EXPORT=1
; NOTE: DO NOT ENABLE --> -D MESH_PACKET_LOGGING=1
; NOTE: DO NOT ENABLE --> -D MESH_DEBUG=1
build_src_filter = ${LilyGo_TLora_V2_1_1_6.build_src_filter}
+<helpers/ui/*.cpp>
+<../examples/companion_radio>
lib_deps =
${LilyGo_TLora_V2_1_1_6.lib_deps}
densaugeo/base64 @ ~1.4.0
[env:LilyGo_TLora_V2_1_1_6_companion_radio_ble]
extends = LilyGo_TLora_V2_1_1_6
build_flags =
${LilyGo_TLora_V2_1_1_6.build_flags}
-D MAX_CONTACTS=100
-D MAX_GROUP_CHANNELS=8
-D BLE_PIN_CODE=123456
; -D BLE_DEBUG_LOGGING=1
; -D ENABLE_PRIVATE_KEY_IMPORT=1
; -D ENABLE_PRIVATE_KEY_EXPORT=1
; -D MESH_PACKET_LOGGING=1
; -D MESH_DEBUG=1
build_src_filter = ${LilyGo_TLora_V2_1_1_6.build_src_filter}
+<helpers/esp32/*.cpp>
+<helpers/ui/*.cpp>
+<../examples/companion_radio>
lib_deps =
${LilyGo_TLora_V2_1_1_6.lib_deps}
densaugeo/base64 @ ~1.4.0
[env:LilyGo_TLora_V2_1_1_6_room_server]
extends = LilyGo_TLora_V2_1_1_6
build_src_filter = ${LilyGo_TLora_V2_1_1_6.build_src_filter}
+<helpers/ui/*.cpp>
+<../examples/simple_room_server>
build_flags =
${LilyGo_TLora_V2_1_1_6.build_flags}
-D ADVERT_NAME='"TLora-V2.1-1.6 Room"'
-D ADVERT_LAT=-37.0
-D ADVERT_LON=145.0
-D ADMIN_PASSWORD='"password"'
-D ROOM_PASSWORD='"hello"'
; -D MESH_PACKET_LOGGING=1
; -D MESH_DEBUG=1

View File

@@ -0,0 +1,173 @@
[faketec]
extends = nrf52840_base
board = promicro_nrf52840
build_src_filter = ${nrf52840_base.build_src_filter} +<helpers/nrf52/faketecBoard.cpp>
build_flags = ${nrf52840_base.build_flags}
-D FAKETEC
-D RADIO_CLASS=CustomSX1262
-D WRAPPER_CLASS=CustomSX1262Wrapper
-D LORA_TX_POWER=22
-D SX126X_CURRENT_LIMIT=130
-D SX126X_RX_BOOSTED_GAIN=1
[env:Faketec_Repeater]
extends = faketec
build_src_filter = ${faketec.build_src_filter} +<../examples/simple_repeater/main.cpp>
build_flags =
${faketec.build_flags}
-D ADVERT_NAME="\"Faketec Repeater\""
-D ADVERT_LAT=-37.0
-D ADVERT_LON=145.0
-D ADMIN_PASSWORD="\"password\""
; -D MESH_PACKET_LOGGING=1
; -D MESH_DEBUG=1
lib_deps =
${faketec.lib_deps}
adafruit/RTClib @ ^2.1.3
[env:Faketec_room_server]
extends = faketec
build_src_filter = ${faketec.build_src_filter} +<../examples/simple_room_server/main.cpp>
build_flags =
${faketec.build_flags}
-D ADVERT_NAME="\"Test Room\""
-D ADVERT_LAT=-37.0
-D ADVERT_LON=145.0
-D ADMIN_PASSWORD="\"password\""
-D ROOM_PASSWORD="\"hello\""
; -D MESH_PACKET_LOGGING=1
; -D MESH_DEBUG=1
lib_deps =
${faketec.lib_deps}
adafruit/RTClib @ ^2.1.3
[env:Faketec_terminal_chat]
extends = faketec
build_flags =
${faketec.build_flags}
-D MAX_CONTACTS=100
-D MAX_GROUP_CHANNELS=1
; -D MESH_PACKET_LOGGING=1
; -D MESH_DEBUG=1
build_src_filter = ${faketec.build_src_filter} +<../examples/simple_secure_chat/main.cpp>
lib_deps =
${faketec.lib_deps}
densaugeo/base64 @ ~1.4.0
adafruit/RTClib @ ^2.1.3
[env:Faketec_companion_radio_usb]
extends = faketec
build_flags =
${faketec.build_flags}
-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 = ${faketec.build_src_filter} +<../examples/companion_radio/main.cpp>
lib_deps =
${faketec.lib_deps}
adafruit/RTClib @ ^2.1.3
densaugeo/base64 @ ~1.4.0
[env:Faketec_companion_radio_ble]
extends = faketec
build_flags =
${faketec.build_flags}
-D MAX_CONTACTS=100
-D MAX_GROUP_CHANNELS=8
-D BLE_PIN_CODE=123456
-D BLE_DEBUG_LOGGING=1
-D ENABLE_PRIVATE_KEY_EXPORT=1
-D ENABLE_PRIVATE_KEY_IMPORT=1
; -D MESH_PACKET_LOGGING=1
; -D MESH_DEBUG=1
build_src_filter = ${faketec.build_src_filter} +<helpers/nrf52/SerialBLEInterface.cpp> +<../examples/companion_radio/main.cpp>
lib_deps =
${faketec.lib_deps}
adafruit/RTClib @ ^2.1.3
densaugeo/base64 @ ~1.4.0
[ProMicroLLCC68]
extends = nrf52840_base
board = promicro_nrf52840
build_src_filter = ${nrf52840_base.build_src_filter} +<helpers/nrf52/faketecBoard.cpp>
build_flags = ${nrf52840_base.build_flags}
-D FAKETEC
-D RADIO_CLASS=CustomLLCC68
-D WRAPPER_CLASS=CustomLLCC68Wrapper
-D LORA_TX_POWER=22
-D SX126X_CURRENT_LIMIT=130
-D SX126X_RX_BOOSTED_GAIN=1
[env:ProMicroLLCC68_Repeater]
extends = ProMicroLLCC68
build_src_filter = ${ProMicroLLCC68.build_src_filter} +<../examples/simple_repeater/main.cpp>
build_flags =
${ProMicroLLCC68.build_flags}
-D ADVERT_NAME="\"ProMicroLLCC68 Repeater\""
-D ADMIN_PASSWORD="\"password\""
; -D MESH_PACKET_LOGGING=1
; -D MESH_DEBUG=1
lib_deps =
${ProMicroLLCC68.lib_deps}
adafruit/RTClib @ ^2.1.3
[env:ProMicroLLCC68_room_server]
extends = ProMicroLLCC68
build_src_filter = ${ProMicroLLCC68.build_src_filter} +<../examples/simple_room_server/main.cpp>
build_flags =
${ProMicroLLCC68.build_flags}
-D ADVERT_NAME="\"ProMicroLLCC68 Room\""
-D ADMIN_PASSWORD="\"password\""
-D ROOM_PASSWORD="\"hello\""
; -D MESH_PACKET_LOGGING=1
; -D MESH_DEBUG=1
lib_deps =
${ProMicroLLCC68.lib_deps}
adafruit/RTClib @ ^2.1.3
[env:ProMicroLLCC68_terminal_chat]
extends = ProMicroLLCC68
build_flags =
${ProMicroLLCC68.build_flags}
-D MAX_CONTACTS=100
-D MAX_GROUP_CHANNELS=1
; -D MESH_PACKET_LOGGING=1
; -D MESH_DEBUG=1
build_src_filter = ${ProMicroLLCC68.build_src_filter} +<../examples/simple_secure_chat/main.cpp>
lib_deps =
${ProMicroLLCC68.lib_deps}
densaugeo/base64 @ ~1.4.0
adafruit/RTClib @ ^2.1.3
[env:ProMicroLLCC68_companion_radio_usb]
extends = ProMicroLLCC68
build_flags =
${ProMicroLLCC68.build_flags}
-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 = ${ProMicroLLCC68.build_src_filter} +<../examples/companion_radio/main.cpp>
lib_deps =
${ProMicroLLCC68.lib_deps}
adafruit/RTClib @ ^2.1.3
densaugeo/base64 @ ~1.4.0
[env:ProMicroLLCC68_companion_radio_ble]
extends = ProMicroLLCC68
build_flags =
${ProMicroLLCC68.build_flags}
-D MAX_CONTACTS=100
-D MAX_GROUP_CHANNELS=8
-D BLE_PIN_CODE=123456
-D BLE_DEBUG_LOGGING=1
-D ENABLE_PRIVATE_KEY_EXPORT=1
-D ENABLE_PRIVATE_KEY_IMPORT=1
; -D MESH_PACKET_LOGGING=1
; -D MESH_DEBUG=1
build_src_filter = ${ProMicroLLCC68.build_src_filter} +<helpers/nrf52/SerialBLEInterface.cpp> +<../examples/companion_radio/main.cpp>
lib_deps =
${ProMicroLLCC68.lib_deps}
adafruit/RTClib @ ^2.1.3
densaugeo/base64 @ ~1.4.0

View File

@@ -0,0 +1,15 @@
#include "variant.h"
#include "wiring_constants.h"
#include "wiring_digital.h"
const uint32_t g_ADigitalPinMap[] = {
8, 6, 17, 20, 22, 24, 32, 11, 36, 38,
9, 10, 43, 45, 47, 2, 29, 31,
33, 34, 37,
13, 15
};
void initVariant()
{
}

View File

@@ -0,0 +1,82 @@
/*
* variant.h
* Copyright (C) 2023 Seeed K.K.
* MIT License
*/
#pragma once
#include "WVariant.h"
////////////////////////////////////////////////////////////////////////////////
// Low frequency clock source
#define VARIANT_MCK (64000000ul)
//#define USE_LFXO // 32.768 kHz crystal oscillator
#define USE_LFRC // 32.768 kHz RC oscillator
////////////////////////////////////////////////////////////////////////////////
// Power
#define PIN_EXT_VCC (21)
#define EXT_VCC (PIN_EXT_VCC)
#define BATTERY_PIN (17)
#define ADC_RESOLUTION 12
////////////////////////////////////////////////////////////////////////////////
// Number of pins
#define PINS_COUNT (23)
#define NUM_DIGITAL_PINS (23)
#define NUM_ANALOG_INPUTS (3)
#define NUM_ANALOG_OUTPUTS (0)
////////////////////////////////////////////////////////////////////////////////
// UART pin definition
#define PIN_SERIAL1_TX (1)
#define PIN_SERIAL1_RX (0)
////////////////////////////////////////////////////////////////////////////////
// I2C pin definition
#define WIRE_INTERFACES_COUNT 2
#define PIN_WIRE_SDA (6)
#define PIN_WIRE_SCL (7)
#define PIN_WIRE1_SDA (13)
#define PIN_WIRE1_SCL (14)
////////////////////////////////////////////////////////////////////////////////
// SPI pin definition
#define SPI_INTERFACES_COUNT 2
#define PIN_SPI_SCK (2)
#define PIN_SPI_MISO (3)
#define PIN_SPI_MOSI (4)
#define PIN_SPI_NSS (5)
#define PIN_SPI1_SCK (18)
#define PIN_SPI1_MISO (19)
#define PIN_SPI1_MOSI (20)
////////////////////////////////////////////////////////////////////////////////
// Builtin LEDs
#define PIN_LED (22)
#define LED_PIN PIN_LED
#define LED_BLUE PIN_LED
#define LED_BUILTIN PIN_LED
#define LED_STATE_ON 1
////////////////////////////////////////////////////////////////////////////////
// Builtin buttons
#define PIN_BUTTON1 (6)
#define BUTTON_PIN PIN_BUTTON1

View File

@@ -0,0 +1,102 @@
[rak4631]
extends = nrf52840_base
platform = https://github.com/maxgerhardt/platform-nordicnrf52.git#rak
board = wiscore_rak4631
board_check = true
build_flags = ${nrf52840_base.build_flags}
-D RAK_4631
-D PIN_USER_BTN=9
-D RADIO_CLASS=CustomSX1262
-D WRAPPER_CLASS=CustomSX1262Wrapper
-D LORA_TX_POWER=22
-D SX126X_CURRENT_LIMIT=130
-D SX126X_RX_BOOSTED_GAIN=1
build_src_filter = ${nrf52840_base.build_src_filter}
+<helpers/nrf52/*.cpp>
lib_deps =
${nrf52840_base.lib_deps}
adafruit/Adafruit SSD1306 @ ^2.5.13
[env:RAK_4631_Repeater]
extends = rak4631
build_flags =
${rak4631.build_flags}
-D DISPLAY_CLASS=SSD1306Display
-D ADVERT_NAME='"RAK4631 Repeater"'
-D ADVERT_LAT=-37.0
-D ADVERT_LON=145.0
-D ADMIN_PASSWORD='"password"'
; -D MESH_PACKET_LOGGING=1
; -D MESH_DEBUG=1
build_src_filter = ${rak4631.build_src_filter}
+<helpers/ui/*.cpp>
+<../examples/simple_repeater>
[env:RAK_4631_room_server]
extends = rak4631
build_flags =
${rak4631.build_flags}
-D DISPLAY_CLASS=SSD1306Display
-D ADVERT_NAME='"Test Room"'
-D ADVERT_LAT=-37.0
-D ADVERT_LON=145.0
-D ADMIN_PASSWORD='"password"'
-D ROOM_PASSWORD='"hello"'
; -D MESH_PACKET_LOGGING=1
; -D MESH_DEBUG=1
build_src_filter = ${rak4631.build_src_filter}
+<helpers/ui/*.cpp>
+<../examples/simple_room_server>
[env:RAK_4631_companion_radio_usb]
extends = rak4631
build_flags =
${rak4631.build_flags}
-D DISPLAY_CLASS=SSD1306Display
-D MAX_CONTACTS=100
-D MAX_GROUP_CHANNELS=8
; -D ENABLE_PRIVATE_KEY_IMPORT=1
; -D ENABLE_PRIVATE_KEY_EXPORT=1
; NOTE: DO NOT ENABLE --> -D MESH_PACKET_LOGGING=1
; NOTE: DO NOT ENABLE --> -D MESH_DEBUG=1
build_src_filter = ${rak4631.build_src_filter}
+<helpers/ui/*.cpp>
+<../examples/companion_radio>
lib_deps =
${rak4631.lib_deps}
densaugeo/base64 @ ~1.4.0
[env:RAK_4631_companion_radio_ble]
extends = rak4631
build_flags =
${rak4631.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 ENABLE_PRIVATE_KEY_IMPORT=1
; -D ENABLE_PRIVATE_KEY_EXPORT=1
; -D MESH_PACKET_LOGGING=1
; -D MESH_DEBUG=1
build_src_filter = ${rak4631.build_src_filter}
+<helpers/ui/*.cpp>
+<helpers/nrf52/*.cpp>
+<../examples/companion_radio>
lib_deps =
${rak4631.lib_deps}
densaugeo/base64 @ ~1.4.0
[env:RAK_4631_terminal_chat]
extends = rak4631
build_flags =
${rak4631.build_flags}
-D MAX_CONTACTS=100
-D MAX_GROUP_CHANNELS=1
-D MESH_PACKET_LOGGING=1
-D MESH_DEBUG=1
build_src_filter = ${rak4631.build_src_filter}
+<../examples/simple_secure_chat/main.cpp>
lib_deps =
${rak4631.lib_deps}
densaugeo/base64 @ ~1.4.0

View File

@@ -0,0 +1,49 @@
[Station_G2]
extends = esp32_base
board = station-g2
build_flags =
${esp32_base.build_flags}
-D STATION_G2
-D RADIO_CLASS=CustomSX1262
-D WRAPPER_CLASS=CustomSX1262Wrapper
-D LORA_TX_POWER=7
; -D P_LORA_TX_LED=35
; -D PIN_BOARD_SDA=5
; -D PIN_BOARD_SCL=6
-D PIN_USER_BTN=0
-D SX126X_DIO2_AS_RF_SWITCH=true
-D SX126X_DIO3_TCXO_VOLTAGE=1.8
-D SX126X_CURRENT_LIMIT=130.0f ; for best TX power!
; -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
build_src_filter = ${esp32_base.build_src_filter}
lib_deps =
${esp32_base.lib_deps}
[env:Station_G2_repeater]
extends = Station_G2
build_flags =
${Station_G2.build_flags}
-D ADVERT_NAME='"Station G2 Repeater"'
-D ADVERT_LAT=-37.0
-D ADVERT_LON=145.0
-D ADMIN_PASSWORD='"password"'
-D MESH_PACKET_LOGGING=1
; -D MESH_DEBUG=1
build_src_filter = ${Station_G2.build_src_filter}
+<../examples/simple_repeater>
[env:Station_G2_room_server]
extends = Station_G2
build_src_filter = ${Station_G2.build_src_filter}
+<../examples/simple_room_server>
build_flags =
${Station_G2.build_flags}
-D ADVERT_NAME='"Station G2 Room"'
-D ADVERT_LAT=-37.0
-D ADVERT_LON=145.0
-D ADMIN_PASSWORD='"password"'
-D ROOM_PASSWORD='"hello"'
; -D MESH_PACKET_LOGGING=1
; -D MESH_DEBUG=1

View File

@@ -0,0 +1,51 @@
; ----------------- NRF52 T1000e---------------------
[nrf52840_t1000e]
extends = nrf52_base
platform_packages = framework-arduinoadafruitnrf52
build_flags = ${nrf52_base.build_flags}
-I src/helpers/nrf52
-I lib/nrf52/s140_nrf52_7.3.0_API/include
-I lib/nrf52/s140_nrf52_7.3.0_API/include/nrf52
lib_ignore =
BluetoothOTA
lvgl
lib5b4
lib_deps =
${nrf52_base.lib_deps}
rweather/Crypto @ ^0.4.0
[t1000-e]
extends = nrf52840_t1000e
board = tracker-t1000-e
board_build.ldscript = boards/nrf52840_s140_v7.ld
build_flags = ${nrf52840_t1000e.build_flags}
-Ivariants/t1000-e
-D T1000_E
-D PIN_USER_BTN=6
-D USER_BTN_PRESSED=HIGH
-D PIN_STATUS_LED=24
-D RADIO_CLASS=CustomLR1110
-D WRAPPER_CLASS=CustomLR1110Wrapper
-D MAX_LORA_TX_POWER=22
build_src_filter = ${nrf52840_t1000e.build_src_filter}
+<helpers/*.cpp>
+<helpers/nrf52/T1000eBoard.cpp>
+<../variants/t1000-e>
debug_tool = jlink
upload_protocol = nrfutil
[env:t1000e_companion_radio_ble]
extends = t1000-e
build_flags = ${t1000-e.build_flags}
-D MAX_CONTACTS=100
-D MAX_GROUP_CHANNELS=8
-D BLE_PIN_CODE=123456
-D BLE_DEBUG_LOGGING=1
-D MESH_PACKET_LOGGING=1
-D MESH_DEBUG=1
-D HAS_UI
build_src_filter = ${t1000-e.build_src_filter}
+<helpers/nrf52/SerialBLEInterface.cpp>
+<../examples/companion_radio/*.cpp>
lib_deps = ${t1000-e.lib_deps}
densaugeo/base64 @ ~1.4.0

View File

@@ -0,0 +1,76 @@
[nrf52840_t114]
extends = nrf52_base
platform_packages = framework-arduinoadafruitnrf52
build_flags = ${nrf52_base.build_flags}
-I src/helpers/nrf52
-I lib/nrf52/s140_nrf52_6.1.1_API/include
-I lib/nrf52/s140_nrf52_6.1.1_API/include/nrf52
lib_deps =
${nrf52_base.lib_deps}
rweather/Crypto @ ^0.4.0
[Heltec_t114]
extends = nrf52840_t114
board = heltec_t114
board_build.ldscript = boards/nrf52840_s140_v6.ld
build_flags = ${nrf52840_t114.build_flags}
-Ivariants/t114
-DHELTEC_T114
-D P_LORA_TX_LED=35
-D RADIO_CLASS=CustomSX1262
-D WRAPPER_CLASS=CustomSX1262Wrapper
-D LORA_TX_POWER=22
-D SX126X_CURRENT_LIMIT=130
-D SX126X_RX_BOOSTED_GAIN=1
build_src_filter = ${nrf52840_t114.build_src_filter}
+<helpers/*.cpp>
+<helpers/nrf52/T114Board.cpp>
+<../variants/t114>
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>
build_flags =
${Heltec_t114.build_flags}
-D ADVERT_NAME='"Heltec_T114 Repeater"'
-D ADVERT_LAT=-37.0
-D ADVERT_LON=145.0
-D ADMIN_PASSWORD='"password"'
; -D MESH_PACKET_LOGGING=1
; -D MESH_DEBUG=1
[env:Heltec_t114_room_server]
extends = Heltec_t114
build_src_filter = ${Heltec_t114.build_src_filter}
+<../examples/simple_room_server>
build_flags =
${Heltec_t114.build_flags}
-D ADVERT_NAME='"Heltec_T114 Room"'
-D ADVERT_LAT=-37.0
-D ADVERT_LON=145.0
-D ADMIN_PASSWORD='"password"'
-D ROOM_PASSWORD='"hello"'
; -D MESH_PACKET_LOGGING=1
; -D MESH_DEBUG=1
[env:Heltec_t114_companion_radio_ble]
extends = Heltec_t114
build_flags =
${Heltec_t114.build_flags}
-D MAX_CONTACTS=100
-D MAX_GROUP_CHANNELS=8
-D BLE_PIN_CODE=123456
-D BLE_DEBUG_LOGGING=1
; -D ENABLE_PRIVATE_KEY_IMPORT=1
; -D ENABLE_PRIVATE_KEY_EXPORT=1
; -D MESH_PACKET_LOGGING=1
; -D MESH_DEBUG=1
build_src_filter = ${Heltec_t114.build_src_filter}
+<helpers/nrf52/*.cpp>
+<../examples/companion_radio/main.cpp>
lib_deps =
${Heltec_t114.lib_deps}
densaugeo/base64 @ ~1.4.0

View File

@@ -11,6 +11,4 @@ const uint32_t g_ADigitalPinMap[] = {
void initVariant()
{
pinMode(LED_BUILTIN, OUTPUT);
ledOff(LED_BUILTIN);
}

View File

@@ -0,0 +1,72 @@
[nrf52840_techo]
extends = nrf52_base
platform_packages = framework-arduinoadafruitnrf52
build_flags = ${nrf52_base.build_flags}
-I src/helpers/nrf52
-I lib/nrf52/s140_nrf52_6.1.1_API/include
-I lib/nrf52/s140_nrf52_6.1.1_API/include/nrf52
lib_deps =
${nrf52_base.lib_deps}
rweather/Crypto @ ^0.4.0
[LilyGo_Techo]
extends = nrf52840_techo
board = t-echo
board_build.ldscript = boards/nrf52840_s140_v6.ld
build_flags = ${nrf52840_techo.build_flags}
-Ivariants/techo
-DLILYGO_TECHO
-D RADIO_CLASS=CustomSX1262
-D WRAPPER_CLASS=CustomSX1262Wrapper
-D LORA_TX_POWER=22
-D SX126X_CURRENT_LIMIT=130
-D SX126X_RX_BOOSTED_GAIN=1
build_src_filter = ${nrf52840_techo.build_src_filter}
+<helpers/*.cpp>
+<helpers/nrf52/TechoBoard.cpp>
+<../variants/techo>
debug_tool = jlink
upload_protocol = nrfutil
[env:LilyGo_T-Echo_repeater]
extends = LilyGo_Techo
build_src_filter = ${LilyGo_Techo.build_src_filter} +<../examples/simple_repeater/main.cpp>
build_flags =
${LilyGo_Techo.build_flags}
-D ADVERT_NAME='"T-Echo Repeater"'
-D ADVERT_LAT=-37.0
-D ADVERT_LON=145.0
-D ADMIN_PASSWORD='"password"'
; -D MESH_PACKET_LOGGING=1
; -D MESH_DEBUG=1
[env:LilyGo_T-Echo_room_server]
extends = LilyGo_Techo
build_src_filter = ${LilyGo_Techo.build_src_filter} +<../examples/simple_room_server/main.cpp>
build_flags =
${LilyGo_Techo.build_flags}
-D ADVERT_NAME='"T-Echo Room"'
-D ADVERT_LAT=-37.0
-D ADVERT_LON=145.0
-D ADMIN_PASSWORD='"password"'
; -D MESH_PACKET_LOGGING=1
; -D MESH_DEBUG=1
[env:LilyGo_T-Echo_companion_radio_ble]
extends = LilyGo_Techo
build_flags =
${LilyGo_Techo.build_flags}
-D MAX_CONTACTS=100
-D MAX_GROUP_CHANNELS=8
-D BLE_PIN_CODE=123456
-D BLE_DEBUG_LOGGING=1
; -D ENABLE_PRIVATE_KEY_IMPORT=1
; -D ENABLE_PRIVATE_KEY_EXPORT=1
; -D MESH_PACKET_LOGGING=1
; -D MESH_DEBUG=1
build_src_filter = ${LilyGo_Techo.build_src_filter}
+<helpers/nrf52/*.cpp>
+<../examples/companion_radio/main.cpp>
lib_deps =
${LilyGo_Techo.lib_deps}
densaugeo/base64 @ ~1.4.0

View File

@@ -0,0 +1,50 @@
[Xiao_esp32_C3]
extends = esp32_base
board = seeed_xiao_esp32c3
build_flags =
${esp32_base.build_flags}
-D LORA_TX_BOOST_PIN=D3
-D P_LORA_TX_LED=D5
-D PIN_VBAT_READ=D0
-D P_LORA_DIO_1=D2
-D P_LORA_NSS=D4
-D P_LORA_RESET=RADIOLIB_NC
-D P_LORA_BUSY=D1
-D PIN_BOARD_SDA=D6
-D PIN_BOARD_SCL=D7
-D SX126X_DIO2_AS_RF_SWITCH=true
-D SX126X_DIO3_TCXO_VOLTAGE=1.8
-D SX126X_CURRENT_LIMIT=130.0f ; for best TX power!
[env:Xiao_C3_Repeater_sx1262]
extends = Xiao_esp32_C3
build_src_filter = ${Xiao_esp32_C3.build_src_filter}
+<../examples/simple_repeater/main.cpp>
build_flags =
${Xiao_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='"Xiao Repeater"'
-D ADVERT_LAT=-37.0
-D ADVERT_LON=145.0
-D ADMIN_PASSWORD='"password"'
; -D MESH_PACKET_LOGGING=1
; -D MESH_DEBUG=1
[env:Xiao_C3_Repeater_sx1268]
extends = Xiao_esp32_C3
build_src_filter = ${Xiao_esp32_C3.build_src_filter}
+<../examples/simple_repeater/main.cpp>
build_flags =
${Xiao_esp32_C3.build_flags}
-D RADIO_CLASS=CustomSX1268
-D WRAPPER_CLASS=CustomSX1268Wrapper
-D LORA_TX_POWER=22
-D ADVERT_NAME='"Xiao Repeater"'
-D ADVERT_LAT=-37.0
-D ADVERT_LON=145.0
-D ADMIN_PASSWORD='"password"'
; -D MESH_PACKET_LOGGING=1
; -D MESH_DEBUG=1

View File

@@ -0,0 +1,67 @@
[Xiao_S3_WIO]
extends = esp32_base
board = seeed_xiao_esp32s3
board_check = true
board_build.mcu = esp32s3
build_flags = ${esp32_base.build_flags}
-D SEEED_XIAO_S3
-D P_LORA_DIO_1=39
-D P_LORA_NSS=41
-D P_LORA_RESET=42 ; RADIOLIB_NC
-D P_LORA_BUSY=40 ; DIO2 = 38
-D P_LORA_SCLK=7
-D P_LORA_MISO=8
-D P_LORA_MOSI=9
-D SX126X_DIO2_AS_RF_SWITCH=true
-D SX126X_DIO3_TCXO_VOLTAGE=1.8
-D SX126X_CURRENT_LIMIT=130
-D RADIO_CLASS=CustomSX1262
-D WRAPPER_CLASS=CustomSX1262Wrapper
-D LORA_TX_POWER=22
-D SX126X_RX_BOOSTED_GAIN=1
[env:Xiao_S3_WIO_Repeater]
extends = Xiao_S3_WIO
build_src_filter = ${Xiao_S3_WIO.build_src_filter}
+<../examples/simple_repeater/main.cpp>
build_flags =
${Xiao_S3_WIO.build_flags}
-D ADVERT_NAME='"XiaoS3 Repeater"'
-D ADVERT_LAT=-37.0
-D ADVERT_LON=145.0
-D ADMIN_PASSWORD='"password"'
; -D MESH_PACKET_LOGGING=1
; -D MESH_DEBUG=1
[env:Xiao_S3_WIO_terminal_chat]
extends = Xiao_S3_WIO
build_flags =
${Xiao_S3_WIO.build_flags}
-D MAX_CONTACTS=100
-D MAX_GROUP_CHANNELS=8
; -D MESH_PACKET_LOGGING=1
; -D MESH_DEBUG=1
build_src_filter = ${Xiao_S3_WIO.build_src_filter}
+<../examples/simple_secure_chat/main.cpp>
lib_deps =
${Xiao_S3_WIO.lib_deps}
densaugeo/base64 @ ~1.4.0
[env:Xiao_S3_WIO_companion_radio_ble]
extends = Xiao_S3_WIO
build_flags =
${Xiao_S3_WIO.build_flags}
-D MAX_CONTACTS=100
-D MAX_GROUP_CHANNELS=8
-D BLE_PIN_CODE=123456
; -D BLE_DEBUG_LOGGING=1
; -D ENABLE_PRIVATE_KEY_IMPORT=1
; -D ENABLE_PRIVATE_KEY_EXPORT=1
; -D MESH_PACKET_LOGGING=1
; -D MESH_DEBUG=1
build_src_filter = ${Xiao_S3_WIO.build_src_filter}
+<helpers/esp32/*.cpp>
+<../examples/companion_radio/main.cpp>
lib_deps =
${Xiao_S3_WIO.lib_deps}
densaugeo/base64 @ ~1.4.0