Compare commits

..

41 Commits

Author SHA1 Message Date
Ben Meadors
e87ecc210a Wifi enabled plumbed in (#1677)
* Wifi enabled

* Wifi requires reboot

* Increment DEVICESTATE_CUR_VER
2022-09-06 14:06:44 -05:00
Vladislav Osmanov
cb3010b58c OLED Cyrillic Support for v1.3 (#1640)
* Extended ASCII codes and cyrillic support

(cherry picked from commit e977840805)

* Fixed `ё`, `Ё` letters

(cherry picked from commit 2f4a2ccb2f)

* Fixed `customFontTableLookup` execution flow

(cherry picked from commit 377f909f36)

* [OLED] Specifying the language by defining it in `platformio.ini`

(cherry picked from commit ddd8132b24)

* [OLED] localization guide

(cherry picked from commit a3267c886f)

* [OLED] Cyrillic support

Localization guide has been moved to https://github.com/meshtastic/Meshtastic/tree/master/docs/developers/Firmware

https://meshtastic.org/docs/developers/Firmware/oled-l10n-guide

Co-authored-by: Thomas Göttgens <tgoettgens@gmail.com>
Co-authored-by: Ben Meadors <benmmeadors@gmail.com>
2022-09-04 15:00:10 -05:00
Ben Meadors
285ba9639e Fix screen on secs (#1673)
* Fix screen on secs

* getIntervalOrDefaultMs

* Display correction

* Paren
2022-09-03 22:10:11 -05:00
Ben Meadors
84e438f72f Mqtt json_enabled (#1672)
* Payload variants

* Waypoints and fixes

* Remove json send to mesh. I think protobuf messages already do that

* whoops

* Added json_enabled mqtt config
2022-09-03 14:06:10 -05:00
lewis he
8fb8212434 i2cScan probe adds another ssd1306 subclass new to output logs correctly (#1671) 2022-09-03 07:26:49 -05:00
Neil Hao
70e1a208d5 'snow_screen_hotfix' (#1670) 2022-09-02 19:43:33 -05:00
Ben Meadors
9d3cac7cdb MQTT Json Payload variants (#1667)
* Payload variants

* Waypoints and fixes

* Remove json send to mesh. I think protobuf messages already do that

* whoops
2022-09-01 17:54:24 -05:00
Thomas Göttgens
221843e176 Merge pull request #1663 from lewisxhe/master 2022-08-30 20:27:41 +02:00
lewishe
1922034c44 Add t-beam sx1268 support 2022-08-30 11:59:57 +08:00
Ben Meadors
7f586f7099 Better logging and cleanup (#1662) 2022-08-29 07:31:02 -05:00
lewis he
0efa1b25c5 Add t-echo sx1268 support (#1657) 2022-08-29 07:26:17 -05:00
Tom
fd27a40edb Reboot after factory reset (#1653)
Co-authored-by: Ben Meadors <benmmeadors@gmail.com>
2022-08-25 12:07:20 -05:00
Ben Meadors
1013aff9b6 Screen changes and fixes (#1651)
* Fixed bluetooth reinit bug

* Remove screen transition ms

* Whoops

* hasScreen is smarter now

* Oops
2022-08-25 11:25:05 -05:00
Ben Meadors
d7e5eb4d22 Upgrade unishox-2 to 1.0.3 (#1650) 2022-08-25 07:12:38 -05:00
Ben Meadors
9a03b2e49d Same as NodeDB position_broadcast_secs bug but different (#1645)
* intervalMs
2022-08-24 17:29:09 -05:00
github-actions[bot]
e7831f13c5 [create-pull-request] automated change (#1641)
Co-authored-by: thebentern <thebentern@users.noreply.github.com>
2022-08-24 17:28:43 -05:00
Ben Meadors
ddc3727155 Fixed NRF52 bluetooth 2022-08-23 14:03:10 -05:00
Ben Meadors
ef9bfc9104 Enable external notification module for nrf52 2022-08-23 13:16:20 -05:00
Ben Meadors
3bb645d4fe Fixed huge nodeinfo bug 2022-08-23 13:12:41 -05:00
Ben Meadors
8f99258fc4 Update main_matrix.yml 2022-08-22 18:31:56 -05:00
Ben Meadors
b54073a8a1 Bluetooth mode unification and behavior tweaks (#1636)
* Esp32 bluetooth modes

* Comment

* Gutting bluetooth

* Cleanup

* Security

* Testing

* NRF bluetooth security

* Reboot on saved lora or bluetooth settings

* Cleanup

* Fixes

* Stub for platforms without screens

* Fixed just-works in esp32

* Cleanup

* Display device name in boot screen

* Added waypoint module routing

* chmod

* Words

* Protos

* Backing out partition changes for testing

* Revert "Backing out partition changes for testing"

This reverts commit 191ed6489c.

* Chmod PR artifacts

* Trying setInitialState again

* Revert "Trying setInitialState again"

This reverts commit 703eac7277.

* External notification module

* Cleanup

* Pin display formatting
2022-08-22 16:41:23 -05:00
Ben Meadors
c85e9f53c7 Chmod PR artifacts 2022-08-20 12:53:34 -05:00
Ben Meadors
4cfc229e77 Update device-update.sh 2022-08-19 13:35:54 -05:00
Ben Meadors
bbd7c5063d Removed ota erasure 2022-08-19 13:34:41 -05:00
Ben Meadors
05df849a6d Repartitioned 2022-08-19 13:33:58 -05:00
Ben Meadors
ccbc01a753 Repartitioned 2022-08-19 13:33:02 -05:00
Sacha Weatherstone
d6d936b5d2 Remove OTA partition (#1635) 2022-08-18 16:19:32 -05:00
Ben Meadors
b028af0d82 Bluetooth modes (#1633)
* Formatting and comments

* Esp32 bluetooth modes

* Comment
2022-08-16 20:42:43 -05:00
Ben Meadors
86d3759f55 New bluetooth config protos and canned messages consolidation (#1632)
* Bluetooth and canned messages refactor

* More can of worms messages

* Set has_bluetooth and default pin

* Defaults
2022-08-15 21:06:55 -05:00
majbthrd
aadaf332cf add stm32wl5e platform and wio-e5 variant (#1631)
Co-authored-by: Peter Lawrence <12226419+majbthrd@users.noreply.github.com>
Co-authored-by: Ben Meadors <benmmeadors@gmail.com>
2022-08-15 07:54:45 -05:00
Ben Meadors
4dea95d03f Update version.properties 2022-08-14 20:22:52 -05:00
Ben Meadors
1253abd138 Syntax error 2022-08-14 15:56:55 -05:00
Ben Meadors
80e3cee006 NimBLE enhanced logging (do not merge) (#1629)
* Change log level to debug

* Don't reinit active bluetooth services

* Chmod +x before zip and adding to release
2022-08-14 15:27:21 -05:00
Ben Meadors
ca9113ad05 Update version.properties 2022-08-14 15:16:47 -05:00
GUVWAF
63c8f15d38 Resend implicit ACK for a repeated broadcast (#1628) 2022-08-13 10:09:43 -05:00
Ben Meadors
73a1ea59f4 Update BMP280Sensor.cpp (#1627) 2022-08-12 20:11:32 -05:00
Ben Meadors
97712a9dc4 Update ESP32Bluetooth.cpp (#1625)
* Update ESP32Bluetooth.cpp

* Update ESP32Bluetooth.h
2022-08-12 14:14:14 -05:00
Ben Meadors
20e43fcf34 Update version.properties 2022-08-12 13:55:02 -05:00
majbthrd
f66c8572b4 use fixed-size buffer in RedirectablePrint::vprintf() (#1622)
Co-authored-by: Peter Lawrence <12226419+majbthrd@users.noreply.github.com>
Co-authored-by: Garth Vander Houwen <garthvh@yahoo.com>
Co-authored-by: Ben Meadors <benmmeadors@gmail.com>
2022-08-12 13:41:16 -05:00
Ben Meadors
64f852e3f7 Update main_matrix.yml 2022-08-12 07:21:20 -05:00
Ben Meadors
ea90e4d2de Update main_matrix.yml 2022-08-12 07:04:36 -05:00
87 changed files with 1751 additions and 2201 deletions

View File

@@ -6,6 +6,7 @@ on:
paths-ignore: paths-ignore:
- "**.md" - "**.md"
- "**.yml" - "**.yml"
- "version.properties"
# Note: This is different from "pull_request". Need to specify ref when doing checkouts. # Note: This is different from "pull_request". Need to specify ref when doing checkouts.
pull_request_target: pull_request_target:
@@ -380,6 +381,11 @@ jobs:
# For diagnostics # For diagnostics
- name: Show artifacts - name: Show artifacts
run: ls -lR run: ls -lR
- name: Device scripts permissions
run: |
chmod +x ./output/device-install.sh
chmod +x ./output/device-update.sh
- name: Zip firmware - name: Zip firmware
run: zip -j -r ./firmware-${{ steps.version.outputs.version }}.zip ./output run: zip -j -r ./firmware-${{ steps.version.outputs.version }}.zip ./output
@@ -424,6 +430,11 @@ jobs:
with: with:
name: firmware-${{ steps.version.outputs.version }} name: firmware-${{ steps.version.outputs.version }}
path: ./output path: ./output
- name: Device scripts permissions
run: |
chmod +x ./output/device-install.sh
chmod +x ./output/device-update.sh
- name: Zip firmware - name: Zip firmware
run: zip -j -r ./firmware-${{ steps.version.outputs.version }}.zip ./output run: zip -j -r ./firmware-${{ steps.version.outputs.version }}.zip ./output
@@ -473,17 +484,13 @@ jobs:
asset_name: debug-elfs-${{ steps.version.outputs.version }}.zip asset_name: debug-elfs-${{ steps.version.outputs.version }}.zip
asset_content_type: application/zip asset_content_type: application/zip
- name: Bump version - name: Bump version.properties
run: >- run: >-
bin/bump_version.py bin/bump_version.py
- name: Commit updated version.py - name: Create version.properties pull request
id: commit_updated uses: peter-evans/create-pull-request@v3
run: | with:
git config --global user.name 'github-actions' add-paths: |
git config --global user.email 'bot@noreply.github.com' version.properties
git remote set-url origin https://x-access-token:${{ secrets.GITHUB_TOKEN }}@github.com/${{ github.repository }}
git add version.properties
git commit -m "bump version" && git push || echo "No changes to commit"
git log -n 1 --pretty=format:"%H" | tail -n 1 | awk '{print "::set-output name=sha::"$0}'

View File

@@ -52,7 +52,8 @@
"shared_mutex": "cpp", "shared_mutex": "cpp",
"iostream": "cpp", "iostream": "cpp",
"esp_nimble_hci.h": "c", "esp_nimble_hci.h": "c",
"map": "cpp" "map": "cpp",
"random": "cpp"
}, },
"cSpell.words": [ "cSpell.words": [
"Blox", "Blox",

4
bin/device-install.bat Normal file → Executable file
View File

@@ -31,7 +31,7 @@ IF EXIST %FILENAME% (
%PYTHON% -m esptool --baud 115200 erase_flash %PYTHON% -m esptool --baud 115200 erase_flash
%PYTHON% -m esptool --baud 115200 write_flash 0x1000 system-info.bin %PYTHON% -m esptool --baud 115200 write_flash 0x1000 system-info.bin
for %%f in (littlefs-*.bin) do ( for %%f in (littlefs-*.bin) do (
%PYTHON% -m esptool --baud 115200 write_flash 0x00390000 %%f %PYTHON% -m esptool --baud 115200 write_flash 0x2B0000 %%f
) )
%PYTHON% -m esptool --baud 115200 write_flash 0x10000 %FILENAME% %PYTHON% -m esptool --baud 115200 write_flash 0x10000 %FILENAME%
) else ( ) else (
@@ -39,4 +39,4 @@ IF EXIST %FILENAME% (
goto HELP goto HELP
) )
:EOF :EOF

View File

@@ -48,7 +48,7 @@ if [ -f "${FILENAME}" ]; then
echo "Trying to flash ${FILENAME}, but first erasing and writing system information" echo "Trying to flash ${FILENAME}, but first erasing and writing system information"
"$PYTHON" -m esptool erase_flash "$PYTHON" -m esptool erase_flash
"$PYTHON" -m esptool write_flash 0x1000 system-info.bin "$PYTHON" -m esptool write_flash 0x1000 system-info.bin
"$PYTHON" -m esptool write_flash 0x00390000 littlefs-*.bin "$PYTHON" -m esptool write_flash 0x2B0000 littlefs-*.bin
"$PYTHON" -m esptool write_flash 0x10000 ${FILENAME} "$PYTHON" -m esptool write_flash 0x10000 ${FILENAME}
else else
echo "Invalid file: ${FILENAME}" echo "Invalid file: ${FILENAME}"

4
bin/device-update.bat Normal file → Executable file
View File

@@ -29,11 +29,9 @@ IF "__%FILENAME%__" == "____" (
IF EXIST %FILENAME% ( IF EXIST %FILENAME% (
echo Trying to flash update %FILENAME% echo Trying to flash update %FILENAME%
%PYTHON% -m esptool --baud 115200 write_flash 0x10000 %FILENAME% %PYTHON% -m esptool --baud 115200 write_flash 0x10000 %FILENAME%
echo Erasing the otadata partition, which will turn off flash flippy-flop and force the first image to be used
%PYTHON% -m esptool --baud 115200 erase_region 0xe000 0x2000
) else ( ) else (
echo "Invalid file: %FILENAME%" echo "Invalid file: %FILENAME%"
goto HELP goto HELP
) )
:EOF :EOF

View File

@@ -45,8 +45,6 @@ shift "$((OPTIND-1))"
if [ -f "${FILENAME}" ]; then if [ -f "${FILENAME}" ]; then
echo "Trying to flash update ${FILENAME}." echo "Trying to flash update ${FILENAME}."
$PYTHON -m esptool --baud 115200 write_flash 0x10000 ${FILENAME} $PYTHON -m esptool --baud 115200 write_flash 0x10000 ${FILENAME}
echo "Erasing the otadata partition, which will turn off flash flippy-flop and force the first image to be used"
$PYTHON -m esptool --baud 115200 erase_region 0xe000 0x2000
else else
echo "Invalid file: ${FILENAME}" echo "Invalid file: ${FILENAME}"
show_help show_help

31
boards/generic_wl5e.json Normal file
View File

@@ -0,0 +1,31 @@
{
"build": {
"core": "stm32",
"cpu": "cortex-m4",
"extra_flags": "-DSTM32WLxx -DSTM32WLE5xx -DARDUINO_GENERIC_WLE5CCUX",
"f_cpu": "48000000L",
"mcu": "stm32wle5ccu",
"variant": "STM32WLxx/WL54CCU_WL55CCU_WLE4C(8-B-C)U_WLE5C(8-B-C)U",
"product_line": "STM32WLE5xx"
},
"debug": {
"default_tools": [
"stlink"
],
"jlink_device": "STM32WLE5CC",
"openocd_target": "stm32wlx",
"svd_path": "STM32WLE5_CM4.svd"
},
"frameworks": ["arduino"],
"name": "BB-STM32WL",
"upload": {
"maximum_ram_size": 65536,
"maximum_size": 262144,
"protocol": "cmsis-dap",
"protocols": [
"cmsis-dap"
]
},
"url": "https://www.st.com/en/microcontrollers-microprocessors/stm32wl-series.html",
"vendor": "ST"
}

View File

@@ -3,6 +3,5 @@
# Name, Type, SubType, Offset, Size, Flags # Name, Type, SubType, Offset, Size, Flags
nvs, data, nvs, 0x9000, 0x5000, nvs, data, nvs, 0x9000, 0x5000,
otadata, data, ota, 0xe000, 0x2000, otadata, data, ota, 0xe000, 0x2000,
app0, app, ota_0, 0x10000, 0x1c0000, app0, app, ota_0, 0x10000, 0x2A0000,
app1, app, ota_1, 0x1d0000,0x1c0000, spiffs, data, spiffs, 0x2B0000,0x150000,
spiffs, data, spiffs, 0x390000,0x070000,
1 # FIXME! using the genpartitions based table doesn't work on TTGO so for now I stay with my old memory map
3 # Name, Type, SubType, Offset, Size, Flags
4 nvs, data, nvs, 0x9000, 0x5000,
5 otadata, data, ota, 0xe000, 0x2000,
6 app0, app, ota_0, 0x10000, 0x1c0000, app0, app, ota_0, 0x10000, 0x2A0000,
7 app1, app, ota_1, 0x1d0000,0x1c0000, spiffs, data, spiffs, 0x2B0000,0x150000,
spiffs, data, spiffs, 0x390000,0x070000,

View File

@@ -21,6 +21,7 @@ default_envs = tbeam
;default_envs = meshtastic-diy-v1 ;default_envs = meshtastic-diy-v1
;default_envs = meshtastic-diy-v1.1 ;default_envs = meshtastic-diy-v1.1
;default_envs = m5stack-coreink ;default_envs = m5stack-coreink
;default_envs = rak4631
extra_configs = variants/*/platformio.ini extra_configs = variants/*/platformio.ini
@@ -79,8 +80,6 @@ lib_deps =
lib_deps = lib_deps =
adafruit/Adafruit BusIO@^1.11.4 adafruit/Adafruit BusIO@^1.11.4
adafruit/Adafruit Unified Sensor@^1.1.4 adafruit/Adafruit Unified Sensor@^1.1.4
paulstoffregen/OneWire@^2.3.5
robtillaart/DS18B20@^0.1.11
adafruit/Adafruit BMP280 Library@^2.6.3 adafruit/Adafruit BMP280 Library@^2.6.3
adafruit/Adafruit BME280 Library@^2.2.2 adafruit/Adafruit BME280 Library@^2.2.2
adafruit/Adafruit BME680 Library@^2.0.1 adafruit/Adafruit BME680 Library@^2.0.1
@@ -99,11 +98,10 @@ debug_init_break = tbreak setup
# Remove -DMYNEWT_VAL_BLE_HS_LOG_LVL=LOG_LEVEL_CRITICAL for low level BLE logging. # Remove -DMYNEWT_VAL_BLE_HS_LOG_LVL=LOG_LEVEL_CRITICAL for low level BLE logging.
# See library directory for BLE logging possible values: .pio/libdeps/tbeam/NimBLE-Arduino/src/log_common/log_common.h # See library directory for BLE logging possible values: .pio/libdeps/tbeam/NimBLE-Arduino/src/log_common/log_common.h
# This overrides the BLE logging default of LOG_LEVEL_INFO (1) from: .pio/libdeps/tbeam/NimBLE-Arduino/src/esp_nimble_cfg.h # This overrides the BLE logging default of LOG_LEVEL_INFO (1) from: .pio/libdeps/tbeam/NimBLE-Arduino/src/esp_nimble_cfg.h
# -DUSE_NEW_ESP32_BLUETOOTH will enable the new NimBLE C++ api
build_flags = build_flags =
${arduino_base.build_flags} -Wall -Wextra -Isrc/platform/esp32 -lnimble -std=c++11 ${arduino_base.build_flags} -Wall -Wextra -Isrc/platform/esp32 -lnimble -std=c++11
-DLOG_LOCAL_LEVEL=ESP_LOG_DEBUG -DCORE_DEBUG_LEVEL=ARDUHAL_LOG_LEVEL_DEBUG -DMYNEWT_VAL_BLE_HS_LOG_LVL=LOG_LEVEL_CRITICAL -DLOG_LOCAL_LEVEL=ESP_LOG_DEBUG -DCORE_DEBUG_LEVEL=ARDUHAL_LOG_LEVEL_DEBUG -DMYNEWT_VAL_BLE_HS_LOG_LVL=LOG_LEVEL_CRITICAL
-DAXP_DEBUG_PORT=Serial -DUSE_NEW_ESP32_BLUETOOTH -DCONFIG_BT_NIMBLE_ENABLED -DCONFIG_NIMBLE_CPP_LOG_LEVEL=1 -DAXP_DEBUG_PORT=Serial -DCONFIG_BT_NIMBLE_ENABLED -DCONFIG_NIMBLE_CPP_LOG_LEVEL=2 -DCONFIG_BT_NIMBLE_MAX_CCCDS=20
lib_deps = lib_deps =
${arduino_base.lib_deps} ${arduino_base.lib_deps}
${networking_base.lib_deps} ${networking_base.lib_deps}
@@ -184,4 +182,24 @@ lib_ignore =
lib_deps = lib_deps =
${arduino_base.lib_deps} ${arduino_base.lib_deps}
${environmental_base.lib_deps} ${environmental_base.lib_deps}
https://github.com/kokke/tiny-AES-c.git https://github.com/kokke/tiny-AES-c.git
[stm32wl5e_base]
platform = ststm32
board = generic_wl5e
framework = arduino
build_type = debug
build_flags =
${arduino_base.build_flags}
-Isrc/platform/stm32wl -g
-DHAL_SUBGHZ_MODULE_ENABLED
# Arduino/PlatformIO framework-arduinoststm32 package does not presently have SUBGHZSPI support
# -DPIN_SPI_MOSI=PINSUBGHZSPIMOSI -DPIN_SPI_MISO=PINSUBGHZSPIMISO -DPIN_SPI_SCK=PINSUBGHZSPISCK
build_src_filter =
${arduino_base.build_src_filter} -<platform/esp32/> -<nimble/> -<mesh/wifi/> -<mesh/http/> -<modules/esp32> -<mqtt/> -<graphics> -<input> -<buzz> -<modules/Telemetry> -<platform/nrf52> -<platform/portduino> -<platform/rp2040>
lib_deps =
${env.lib_deps}
https://github.com/jgromes/RadioLib.git
https://github.com/kokke/tiny-AES-c.git
lib_ignore =
mathertel/OneButton@^2.0.3

View File

@@ -7,10 +7,6 @@
#include "power.h" #include "power.h"
#include <OneButton.h> #include <OneButton.h>
#ifdef ARCH_ESP32
#include "nimble/BluetoothUtil.h"
#endif
namespace concurrency namespace concurrency
{ {
/** /**

View File

@@ -51,8 +51,7 @@ static uint32_t secsSlept;
static void lsEnter() static void lsEnter()
{ {
DEBUG_MSG("lsEnter begin, ls_secs=%u\n", DEBUG_MSG("lsEnter begin, ls_secs=%u\n", config.power.ls_secs > 0 ? config.power.ls_secs : default_ls_secs);
config.power.ls_secs ? config.power.ls_secs : default_ls_secs);
screen->setOn(false); screen->setOn(false);
secsSlept = 0; // How long have we been sleeping this time secsSlept = 0; // How long have we been sleeping this time
@@ -66,7 +65,7 @@ static void lsIdle()
#ifdef ARCH_ESP32 #ifdef ARCH_ESP32
// Do we have more sleeping to do? // Do we have more sleeping to do?
if (secsSlept < config.power.ls_secs ? config.power.ls_secs : default_ls_secs * 1000) { if (secsSlept < config.power.ls_secs ? config.power.ls_secs : default_ls_secs) {
// Briefly come out of sleep long enough to blink the led once every few seconds // Briefly come out of sleep long enough to blink the led once every few seconds
uint32_t sleepTime = 30; uint32_t sleepTime = 30;
@@ -200,8 +199,7 @@ static void onEnter()
uint32_t now = millis(); uint32_t now = millis();
if (now - lastPingMs > if ((now - lastPingMs) > 30 * 1000) { // if more than a minute since our last press, ask node we are looking at to update their state
30 * 1000) { // if more than a minute since our last press, ask node we are looking at to update their state
if (displayedNodeNum) if (displayedNodeNum)
service.sendNetworkPing(displayedNodeNum, true); // Refresh the currently displayed node service.sendNetworkPing(displayedNodeNum, true); // Refresh the currently displayed node
lastPingMs = now; lastPingMs = now;
@@ -251,8 +249,7 @@ void PowerFSM_setup()
// We need this transition, because we might not transition if we were waiting to enter light-sleep, because when we wake from // We need this transition, because we might not transition if we were waiting to enter light-sleep, because when we wake from
// light sleep we _always_ transition to NB or dark and // light sleep we _always_ transition to NB or dark and
powerFSM.add_transition(&stateLS, isRouter ? &stateNB : &stateDARK, EVENT_PACKET_FOR_PHONE, NULL, powerFSM.add_transition(&stateLS, isRouter ? &stateNB : &stateDARK, EVENT_PACKET_FOR_PHONE, NULL, "Received packet, exiting light sleep");
"Received packet, exiting light sleep");
powerFSM.add_transition(&stateNB, &stateNB, EVENT_PACKET_FOR_PHONE, NULL, "Received packet, resetting win wake"); powerFSM.add_transition(&stateNB, &stateNB, EVENT_PACKET_FOR_PHONE, NULL, "Received packet, resetting win wake");
// Handle press events - note: we ignore button presses when in API mode // Handle press events - note: we ignore button presses when in API mode
@@ -261,8 +258,7 @@ void PowerFSM_setup()
powerFSM.add_transition(&stateDARK, &stateON, EVENT_PRESS, NULL, "Press"); powerFSM.add_transition(&stateDARK, &stateON, EVENT_PRESS, NULL, "Press");
powerFSM.add_transition(&statePOWER, &statePOWER, EVENT_PRESS, screenPress, "Press"); powerFSM.add_transition(&statePOWER, &statePOWER, EVENT_PRESS, screenPress, "Press");
powerFSM.add_transition(&stateON, &stateON, EVENT_PRESS, screenPress, "Press"); // reenter On to restart our timers powerFSM.add_transition(&stateON, &stateON, EVENT_PRESS, screenPress, "Press"); // reenter On to restart our timers
powerFSM.add_transition(&stateSERIAL, &stateSERIAL, EVENT_PRESS, screenPress, powerFSM.add_transition(&stateSERIAL, &stateSERIAL, EVENT_PRESS, screenPress, "Press"); // Allow button to work while in serial API
"Press"); // Allow button to work while in serial API
// Handle critically low power battery by forcing deep sleep // Handle critically low power battery by forcing deep sleep
powerFSM.add_transition(&stateBOOT, &stateSDS, EVENT_LOW_BATTERY, NULL, "LowBat"); powerFSM.add_transition(&stateBOOT, &stateSDS, EVENT_LOW_BATTERY, NULL, "LowBat");
@@ -333,10 +329,7 @@ void PowerFSM_setup()
powerFSM.add_transition(&stateDARK, &stateON, EVENT_FIRMWARE_UPDATE, NULL, "Got firmware update"); powerFSM.add_transition(&stateDARK, &stateON, EVENT_FIRMWARE_UPDATE, NULL, "Got firmware update");
powerFSM.add_transition(&stateON, &stateON, EVENT_FIRMWARE_UPDATE, NULL, "Got firmware update"); powerFSM.add_transition(&stateON, &stateON, EVENT_FIRMWARE_UPDATE, NULL, "Got firmware update");
powerFSM.add_timed_transition(&stateON, &stateDARK, powerFSM.add_timed_transition(&stateON, &stateDARK, getConfiguredOrDefaultMs(config.display.screen_on_secs, default_screen_on_secs), NULL, "Screen-on timeout");
config.display.screen_on_secs ? config.display.screen_on_secs
: 60 * 1000 * 10,
NULL, "Screen-on timeout");
// On most boards we use light-sleep to be our main state, but on NRF52 we just stay in DARK // On most boards we use light-sleep to be our main state, but on NRF52 we just stay in DARK
State *lowPowerState = &stateLS; State *lowPowerState = &stateLS;
@@ -348,17 +341,9 @@ void PowerFSM_setup()
// See: https://github.com/meshtastic/Meshtastic-device/issues/1071 // See: https://github.com/meshtastic/Meshtastic-device/issues/1071
if (isRouter || config.power.is_power_saving) { if (isRouter || config.power.is_power_saving) {
powerFSM.add_timed_transition(&stateNB, &stateLS, powerFSM.add_timed_transition(&stateNB, &stateLS, getConfiguredOrDefaultMs(config.power.min_wake_secs, default_min_wake_secs), NULL, "Min wake timeout");
config.power.min_wake_secs ? config.power.min_wake_secs powerFSM.add_timed_transition(&stateDARK, &stateLS, getConfiguredOrDefaultMs(config.power.wait_bluetooth_secs, default_wait_bluetooth_secs), NULL, "Bluetooth timeout");
: default_min_wake_secs * 1000, meshSds = config.power.mesh_sds_timeout_secs ? config.power.mesh_sds_timeout_secs : default_mesh_sds_timeout_secs;
NULL, "Min wake timeout");
powerFSM.add_timed_transition(&stateDARK, &stateLS,
config.power.wait_bluetooth_secs
? config.power.wait_bluetooth_secs
: default_wait_bluetooth_secs * 1000,
NULL, "Bluetooth timeout");
meshSds = config.power.mesh_sds_timeout_secs ? config.power.mesh_sds_timeout_secs
: default_mesh_sds_timeout_secs;
} else { } else {

View File

@@ -38,20 +38,13 @@ size_t RedirectablePrint::write(uint8_t c)
size_t RedirectablePrint::vprintf(const char *format, va_list arg) size_t RedirectablePrint::vprintf(const char *format, va_list arg)
{ {
va_list copy; va_list copy;
static char printBuf[160];
va_copy(copy, arg); va_copy(copy, arg);
int len = vsnprintf(printBuf, printBufLen, format, copy); int len = vsnprintf(printBuf, sizeof(printBuf), format, copy);
va_end(copy); va_end(copy);
if (len < 0) {
va_end(arg); if (len < 0) return 0;
return 0;
};
if (len >= (int)printBufLen) {
delete[] printBuf;
printBufLen *= 2;
printBuf = new char[printBufLen];
len = vsnprintf(printBuf, printBufLen, format, arg);
}
len = Print::write(printBuf, len); len = Print::write(printBuf, len);
return len; return len;

View File

@@ -12,10 +12,6 @@ class RedirectablePrint : public Print
{ {
Print *dest; Print *dest;
/// We dynamically grow this scratch buffer if necessary
char *printBuf = new char[64];
size_t printBufLen = 64;
/// Used to allow multiple logDebug messages to appear on a single log line /// Used to allow multiple logDebug messages to appear on a single log line
bool isContinuationMessage = false; bool isContinuationMessage = false;

View File

@@ -14,4 +14,5 @@ enum class Cmd {
STOP_BOOT_SCREEN, STOP_BOOT_SCREEN,
PRINT, PRINT,
START_SHUTDOWN_SCREEN, START_SHUTDOWN_SCREEN,
START_REBOOT_SCREEN,
}; };

View File

@@ -45,7 +45,7 @@ uint8_t oled_probe(byte addr)
if (r == 0x08 || r == 0x00) { if (r == 0x08 || r == 0x00) {
o_probe = 2; // SH1106 o_probe = 2; // SH1106
} else if ( r == 0x03 || r == 0x06 || r == 0x07) { } else if ( r == 0x03 || r == 0x04 || r == 0x06 || r == 0x07) {
o_probe = 1; // SSD1306 o_probe = 1; // SSD1306
} }
c++; c++;

View File

@@ -44,6 +44,10 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#include "mesh/http/WiFiAPClient.h" #include "mesh/http/WiFiAPClient.h"
#endif #endif
#ifdef OLED_RU
#include "fonts/OLEDDisplayFontsRU.h"
#endif
using namespace meshtastic; /** @todo remove */ using namespace meshtastic; /** @todo remove */
extern bool loadProto(const char *filename, size_t protoSize, size_t objSize, const pb_msgdesc_t *fields, void *dest_struct); extern bool loadProto(const char *filename, size_t protoSize, size_t objSize, const pb_msgdesc_t *fields, void *dest_struct);
@@ -100,7 +104,11 @@ static uint16_t displayWidth, displayHeight;
#define FONT_MEDIUM ArialMT_Plain_24 #define FONT_MEDIUM ArialMT_Plain_24
#define FONT_LARGE ArialMT_Plain_24 #define FONT_LARGE ArialMT_Plain_24
#else #else
#ifdef OLED_RU
#define FONT_SMALL ArialMT_Plain_10_RU
#else
#define FONT_SMALL ArialMT_Plain_10 #define FONT_SMALL ArialMT_Plain_10
#endif
#define FONT_MEDIUM ArialMT_Plain_16 #define FONT_MEDIUM ArialMT_Plain_16
#define FONT_LARGE ArialMT_Plain_24 #define FONT_LARGE ArialMT_Plain_24
#endif #endif
@@ -112,9 +120,6 @@ static uint16_t displayWidth, displayHeight;
#define getStringCenteredX(s) ((SCREEN_WIDTH - display->getStringWidth(s)) / 2) #define getStringCenteredX(s) ((SCREEN_WIDTH - display->getStringWidth(s)) / 2)
#ifndef SCREEN_TRANSITION_MSECS
#define SCREEN_TRANSITION_MSECS 300
#endif
/** /**
* Draw the icon with extra info printed around the corners * Draw the icon with extra info printed around the corners
@@ -228,26 +233,17 @@ static void drawSSLScreen(OLEDDisplay *display, OLEDDisplayUiState *state, int16
// Used when booting without a region set // Used when booting without a region set
static void drawWelcomeScreen(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y) static void drawWelcomeScreen(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y)
{ {
display->setFont(FONT_SMALL);
display->setTextAlignment(TEXT_ALIGN_CENTER);
display->drawString(64 + x, y, "//\\ E S H T /\\ S T / C");
display->drawString(64 + x, y + FONT_HEIGHT_SMALL, getDeviceName());
display->setTextAlignment(TEXT_ALIGN_LEFT);
if ((millis() / 10000) % 2) { if ((millis() / 10000) % 2) {
display->setFont(FONT_SMALL);
display->setTextAlignment(TEXT_ALIGN_CENTER);
display->drawString(64 + x, y, "//\\ E S H T /\\ S T / C");
display->setTextAlignment(TEXT_ALIGN_LEFT);
display->drawString(x, y + FONT_HEIGHT_SMALL * 2 - 3, "Set the region using the"); display->drawString(x, y + FONT_HEIGHT_SMALL * 2 - 3, "Set the region using the");
display->drawString(x, y + FONT_HEIGHT_SMALL * 3 - 3, "Meshtastic Android, iOS,"); display->drawString(x, y + FONT_HEIGHT_SMALL * 3 - 3, "Meshtastic Android, iOS,");
display->drawString(x, y + FONT_HEIGHT_SMALL * 4 - 3, "Flasher or CLI client."); display->drawString(x, y + FONT_HEIGHT_SMALL * 4 - 3, "Flasher or CLI client.");
} else { } else {
display->setFont(FONT_SMALL);
display->setTextAlignment(TEXT_ALIGN_CENTER);
display->drawString(64 + x, y, "//\\ E S H T /\\ S T / C");
display->setTextAlignment(TEXT_ALIGN_LEFT);
display->drawString(x, y + FONT_HEIGHT_SMALL * 2 - 3, "Visit meshtastic.org"); display->drawString(x, y + FONT_HEIGHT_SMALL * 2 - 3, "Visit meshtastic.org");
display->drawString(x, y + FONT_HEIGHT_SMALL * 3 - 3, "for more information."); display->drawString(x, y + FONT_HEIGHT_SMALL * 3 - 3, "for more information.");
display->drawString(x, y + FONT_HEIGHT_SMALL * 4 - 3, ""); display->drawString(x, y + FONT_HEIGHT_SMALL * 4 - 3, "");
@@ -299,8 +295,13 @@ static void drawFrameBluetooth(OLEDDisplay *display, OLEDDisplayUiState *state,
display->drawString(64 + x, FONT_HEIGHT_SMALL + y + 2, "Enter this code"); display->drawString(64 + x, FONT_HEIGHT_SMALL + y + 2, "Enter this code");
display->setFont(FONT_LARGE); display->setFont(FONT_LARGE);
display->drawString(64 + x, 26 + y, btPIN);
auto displayPin = new String(btPIN);
display->setTextAlignment(TEXT_ALIGN_LEFT);
display->drawString(12 + x, 26 + y, displayPin->substring(0, 3));
display->drawString(72 + x, 26 + y, displayPin->substring(3, 6));
display->setTextAlignment(TEXT_ALIGN_CENTER);
display->setFont(FONT_SMALL); display->setFont(FONT_SMALL);
char buf[30]; char buf[30];
const char *name = "Name: "; const char *name = "Name: ";
@@ -317,6 +318,14 @@ static void drawFrameShutdown(OLEDDisplay *display, OLEDDisplayUiState *state, i
display->drawString(64 + x, 26 + y, "Shutting down..."); display->drawString(64 + x, 26 + y, "Shutting down...");
} }
static void drawFrameReboot(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y)
{
display->setTextAlignment(TEXT_ALIGN_CENTER);
display->setFont(FONT_MEDIUM);
display->drawString(64 + x, 26 + y, "Rebooting...");
}
static void drawFrameFirmware(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y) static void drawFrameFirmware(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y)
{ {
display->setTextAlignment(TEXT_ALIGN_CENTER); display->setTextAlignment(TEXT_ALIGN_CENTER);
@@ -329,9 +338,6 @@ static void drawFrameFirmware(OLEDDisplay *display, OLEDDisplayUiState *state, i
} else { } else {
display->drawString(64 + x, FONT_HEIGHT_SMALL + y + 2, "Please wait . . "); display->drawString(64 + x, FONT_HEIGHT_SMALL + y + 2, "Please wait . . ");
} }
// display->setFont(FONT_LARGE);
// display->drawString(64 + x, 26 + y, btPIN);
} }
/// Draw the last text message we received /// Draw the last text message we received
@@ -901,7 +907,7 @@ void Screen::setup()
displayWidth = dispdev.width(); displayWidth = dispdev.width();
displayHeight = dispdev.height(); displayHeight = dispdev.height();
ui.setTimePerTransition(SCREEN_TRANSITION_MSECS); ui.setTimePerTransition(0);
ui.setIndicatorPosition(BOTTOM); ui.setIndicatorPosition(BOTTOM);
// Defines where the first frame is located in the bar. // Defines where the first frame is located in the bar.
@@ -1042,6 +1048,9 @@ int32_t Screen::runOnce()
case Cmd::START_SHUTDOWN_SCREEN: case Cmd::START_SHUTDOWN_SCREEN:
handleShutdownScreen(); handleShutdownScreen();
break; break;
case Cmd::START_REBOOT_SCREEN:
handleRebootScreen();
break;
default: default:
DEBUG_MSG("BUG: invalid cmd\n"); DEBUG_MSG("BUG: invalid cmd\n");
} }
@@ -1065,10 +1074,6 @@ int32_t Screen::runOnce()
DEBUG_MSG("Setting idle framerate\n"); DEBUG_MSG("Setting idle framerate\n");
targetFramerate = IDLE_FRAMERATE; targetFramerate = IDLE_FRAMERATE;
#ifdef ARCH_ESP32
setCPUFast(false); // Turn up the CPU to improve screen animations
#endif
ui.setTargetFPS(targetFramerate); ui.setTargetFPS(targetFramerate);
forceDisplay(); forceDisplay();
} }
@@ -1234,6 +1239,18 @@ void Screen::handleShutdownScreen()
setFastFramerate(); setFastFramerate();
} }
void Screen::handleRebootScreen()
{
DEBUG_MSG("showing reboot screen\n");
showingNormalScreen = false;
static FrameCallback rebootFrames[] = {drawFrameReboot};
ui.disableAllIndicators();
ui.setFrames(rebootFrames, 1);
setFastFramerate();
}
void Screen::handleStartFirmwareUpdateScreen() void Screen::handleStartFirmwareUpdateScreen()
{ {
DEBUG_MSG("showing firmware screen\n"); DEBUG_MSG("showing firmware screen\n");
@@ -1297,10 +1314,6 @@ void Screen::setFastFramerate()
// We are about to start a transition so speed up fps // We are about to start a transition so speed up fps
targetFramerate = SCREEN_TRANSITION_FRAMERATE; targetFramerate = SCREEN_TRANSITION_FRAMERATE;
#ifdef ARCH_ESP32
setCPUFast(true); // Turn up the CPU to improve screen animations
#endif
ui.setTargetFPS(targetFramerate); ui.setTargetFPS(targetFramerate);
setInterval(0); // redraw ASAP setInterval(0); // redraw ASAP
runASAP = true; runASAP = true;

View File

@@ -20,6 +20,7 @@ class Screen
void forceDisplay() {} void forceDisplay() {}
void startBluetoothPinScreen(uint32_t pin) {} void startBluetoothPinScreen(uint32_t pin) {}
void stopBluetoothPinScreen() {} void stopBluetoothPinScreen() {}
void startRebootScreen() {}
}; };
} }
@@ -167,6 +168,13 @@ class Screen : public concurrency::OSThread
enqueueCmd(cmd); enqueueCmd(cmd);
} }
void startRebootScreen()
{
ScreenCmd cmd;
cmd.cmd = Cmd::START_REBOOT_SCREEN;
enqueueCmd(cmd);
}
/// Stops showing the bluetooth PIN screen. /// Stops showing the bluetooth PIN screen.
void stopBluetoothPinScreen() { enqueueCmd(ScreenCmd{.cmd = Cmd::STOP_BLUETOOTH_PIN_SCREEN}); } void stopBluetoothPinScreen() { enqueueCmd(ScreenCmd{.cmd = Cmd::STOP_BLUETOOTH_PIN_SCREEN}); }
@@ -204,7 +212,7 @@ class Screen : public concurrency::OSThread
uint8_t last = LASTCHAR; // get last char uint8_t last = LASTCHAR; // get last char
LASTCHAR = ch; LASTCHAR = ch;
switch (last) { // conversion depnding on first UTF8-character switch (last) { // conversion depending on first UTF8-character
case 0xC2: { case 0xC2: {
SKIPREST = false; SKIPREST = false;
return (uint8_t)ch; return (uint8_t)ch;
@@ -213,10 +221,23 @@ class Screen : public concurrency::OSThread
SKIPREST = false; SKIPREST = false;
return (uint8_t)(ch | 0xC0); return (uint8_t)(ch | 0xC0);
} }
// map UTF-8 cyrillic chars to it Windows-1251 (CP-1251) ASCII codes
// note: in this case we must use compatible font - provided ArialMT_Plain_10/16/24 by 'ThingPulse/esp8266-oled-ssd1306' library
// have empty chars for non-latin ASCII symbols
case 0xD0: {
SKIPREST = false;
if (ch == 129) return (uint8_t)(168); // Ё
if (ch > 143 && ch < 192) return (uint8_t)(ch + 48);
}
case 0xD1: {
SKIPREST = false;
if (ch == 145) return (uint8_t)(184); // ё
if (ch > 127 && ch < 144) return (uint8_t)(ch + 112);
}
} }
// We want to strip out prefix chars for two-byte char formats // We want to strip out prefix chars for two-byte char formats
if (ch == 0xC2 || ch == 0xC3 || ch == 0x82) if (ch == 0xC2 || ch == 0xC3 || ch == 0x82 || ch == 0xD0 || ch == 0xD1)
return (uint8_t)0; return (uint8_t)0;
// If we already returned an unconvertable-character symbol for this unconvertable-character sequence, return NULs for the // If we already returned an unconvertable-character symbol for this unconvertable-character sequence, return NULs for the
@@ -280,6 +301,7 @@ class Screen : public concurrency::OSThread
void handlePrint(const char *text); void handlePrint(const char *text);
void handleStartFirmwareUpdateScreen(); void handleStartFirmwareUpdateScreen();
void handleShutdownScreen(); void handleShutdownScreen();
void handleRebootScreen();
/// Rebuilds our list of frames (screens) to default ones. /// Rebuilds our list of frames (screens) to default ones.
void setFrames(); void setFrames();

View File

@@ -0,0 +1,426 @@
#include "OLEDDisplayFontsRU.h"
// Font generated or edited with the glyphEditor
const uint8_t ArialMT_Plain_10_RU[] PROGMEM = {
0x0A, // Width: 10
0x0D, // Height: 13
0x20, // First char: 32
0xE0, // Number of chars: 224
// Jump Table:
0xFF, 0xFF, 0x00, 0x0A, // 32
0x00, 0x00, 0x04, 0x03, // 33
0x00, 0x04, 0x05, 0x04, // 34
0x00, 0x09, 0x09, 0x06, // 35
0x00, 0x12, 0x0A, 0x06, // 36
0x00, 0x1C, 0x10, 0x09, // 37
0x00, 0x2C, 0x0E, 0x08, // 38
0x00, 0x3A, 0x01, 0x02, // 39
0x00, 0x3B, 0x06, 0x04, // 40
0x00, 0x41, 0x06, 0x04, // 41
0x00, 0x47, 0x05, 0x04, // 42
0x00, 0x4C, 0x09, 0x06, // 43
0x00, 0x55, 0x04, 0x03, // 44
0x00, 0x59, 0x03, 0x03, // 45
0x00, 0x5C, 0x04, 0x03, // 46
0x00, 0x60, 0x05, 0x04, // 47
0x00, 0x65, 0x0A, 0x06, // 48
0x00, 0x6F, 0x08, 0x05, // 49
0x00, 0x77, 0x0A, 0x06, // 50
0x00, 0x81, 0x0A, 0x06, // 51
0x00, 0x8B, 0x0B, 0x07, // 52
0x00, 0x96, 0x0A, 0x06, // 53
0x00, 0xA0, 0x0A, 0x06, // 54
0x00, 0xAA, 0x09, 0x06, // 55
0x00, 0xB3, 0x0A, 0x06, // 56
0x00, 0xBD, 0x0A, 0x06, // 57
0x00, 0xC7, 0x04, 0x03, // 58
0x00, 0xCB, 0x04, 0x03, // 59
0x00, 0xCF, 0x0A, 0x06, // 60
0x00, 0xD9, 0x09, 0x06, // 61
0x00, 0xE2, 0x09, 0x06, // 62
0x00, 0xEB, 0x0B, 0x07, // 63
0x00, 0xF6, 0x14, 0x0B, // 64
0x01, 0x0A, 0x0E, 0x08, // 65
0x01, 0x18, 0x0C, 0x07, // 66
0x01, 0x24, 0x0C, 0x07, // 67
0x01, 0x30, 0x0B, 0x07, // 68
0x01, 0x3B, 0x0C, 0x07, // 69
0x01, 0x47, 0x09, 0x06, // 70
0x01, 0x50, 0x0D, 0x08, // 71
0x01, 0x5D, 0x0C, 0x07, // 72
0x01, 0x69, 0x04, 0x03, // 73
0x01, 0x6D, 0x08, 0x05, // 74
0x01, 0x75, 0x0E, 0x08, // 75
0x01, 0x83, 0x0C, 0x07, // 76
0x01, 0x8F, 0x10, 0x09, // 77
0x01, 0x9F, 0x0C, 0x07, // 78
0x01, 0xAB, 0x0E, 0x08, // 79
0x01, 0xB9, 0x0B, 0x07, // 80
0x01, 0xC4, 0x0E, 0x08, // 81
0x01, 0xD2, 0x0C, 0x07, // 82
0x01, 0xDE, 0x0C, 0x07, // 83
0x01, 0xEA, 0x0B, 0x07, // 84
0x01, 0xF5, 0x0C, 0x07, // 85
0x02, 0x01, 0x0D, 0x08, // 86
0x02, 0x0E, 0x11, 0x0A, // 87
0x02, 0x1F, 0x0E, 0x08, // 88
0x02, 0x2D, 0x0D, 0x08, // 89
0x02, 0x3A, 0x0C, 0x07, // 90
0x02, 0x46, 0x06, 0x04, // 91
0x02, 0x4C, 0x06, 0x04, // 92
0x02, 0x52, 0x04, 0x03, // 93
0x02, 0x56, 0x09, 0x06, // 94
0x02, 0x5F, 0x0C, 0x07, // 95
0x02, 0x6B, 0x03, 0x03, // 96
0x02, 0x6E, 0x0A, 0x06, // 97
0x02, 0x78, 0x0A, 0x06, // 98
0x02, 0x82, 0x0A, 0x06, // 99
0x02, 0x8C, 0x0A, 0x06, // 100
0x02, 0x96, 0x0A, 0x06, // 101
0x02, 0xA0, 0x05, 0x04, // 102
0x02, 0xA5, 0x0A, 0x06, // 103
0x02, 0xAF, 0x0A, 0x06, // 104
0x02, 0xB9, 0x04, 0x03, // 105
0x02, 0xBD, 0x04, 0x03, // 106
0x02, 0xC1, 0x08, 0x05, // 107
0x02, 0xC9, 0x04, 0x03, // 108
0x02, 0xCD, 0x10, 0x09, // 109
0x02, 0xDD, 0x0A, 0x06, // 110
0x02, 0xE7, 0x0A, 0x06, // 111
0x02, 0xF1, 0x0A, 0x06, // 112
0x02, 0xFB, 0x0A, 0x06, // 113
0x03, 0x05, 0x05, 0x04, // 114
0x03, 0x0A, 0x08, 0x05, // 115
0x03, 0x12, 0x06, 0x04, // 116
0x03, 0x18, 0x0A, 0x06, // 117
0x03, 0x22, 0x09, 0x06, // 118
0x03, 0x2B, 0x0E, 0x08, // 119
0x03, 0x39, 0x0A, 0x06, // 120
0x03, 0x43, 0x09, 0x06, // 121
0x03, 0x4C, 0x0A, 0x06, // 122
0x03, 0x56, 0x06, 0x04, // 123
0x03, 0x5C, 0x04, 0x03, // 124
0x03, 0x60, 0x05, 0x04, // 125
0x03, 0x65, 0x09, 0x06, // 126
0xFF, 0xFF, 0x00, 0x0A, // 127
0xFF, 0xFF, 0x00, 0x0A, // 128
0xFF, 0xFF, 0x00, 0x0A, // 129
0xFF, 0xFF, 0x00, 0x0A, // 130
0xFF, 0xFF, 0x00, 0x0A, // 131
0xFF, 0xFF, 0x00, 0x0A, // 132
0xFF, 0xFF, 0x00, 0x0A, // 133
0xFF, 0xFF, 0x00, 0x0A, // 134
0xFF, 0xFF, 0x00, 0x0A, // 135
0xFF, 0xFF, 0x00, 0x0A, // 136
0xFF, 0xFF, 0x00, 0x0A, // 137
0xFF, 0xFF, 0x00, 0x0A, // 138
0xFF, 0xFF, 0x00, 0x0A, // 139
0xFF, 0xFF, 0x00, 0x0A, // 140
0xFF, 0xFF, 0x00, 0x0A, // 141
0xFF, 0xFF, 0x00, 0x0A, // 142
0xFF, 0xFF, 0x00, 0x0A, // 143
0xFF, 0xFF, 0x00, 0x0A, // 144
0xFF, 0xFF, 0x00, 0x0A, // 145
0xFF, 0xFF, 0x00, 0x0A, // 146
0xFF, 0xFF, 0x00, 0x0A, // 147
0xFF, 0xFF, 0x00, 0x0A, // 148
0xFF, 0xFF, 0x00, 0x0A, // 149
0xFF, 0xFF, 0x00, 0x0A, // 150
0xFF, 0xFF, 0x00, 0x0A, // 151
0xFF, 0xFF, 0x00, 0x0A, // 152
0xFF, 0xFF, 0x00, 0x0A, // 153
0xFF, 0xFF, 0x00, 0x0A, // 154
0xFF, 0xFF, 0x00, 0x0A, // 155
0xFF, 0xFF, 0x00, 0x0A, // 156
0xFF, 0xFF, 0x00, 0x0A, // 157
0xFF, 0xFF, 0x00, 0x0A, // 158
0xFF, 0xFF, 0x00, 0x0A, // 159
0xFF, 0xFF, 0x00, 0x0A, // 160
0x03, 0x6E, 0x04, 0x03, // 161
0x03, 0x72, 0x0A, 0x06, // 162
0x03, 0x7C, 0x0C, 0x07, // 163
0x03, 0x88, 0x0A, 0x06, // 164
0x03, 0x92, 0x0A, 0x06, // 165
0x03, 0x9C, 0x04, 0x03, // 166
0x03, 0xA0, 0x0A, 0x06, // 167
0x03, 0xAA, 0x0C, 0x07, // 168
0x03, 0xB6, 0x0D, 0x08, // 169
0x03, 0xC3, 0x07, 0x05, // 170
0x03, 0xCA, 0x0A, 0x06, // 171
0x03, 0xD4, 0x09, 0x06, // 172
0x03, 0xDD, 0x03, 0x03, // 173
0x03, 0xE0, 0x0D, 0x08, // 174
0x03, 0xED, 0x0B, 0x07, // 175
0x03, 0xF8, 0x07, 0x05, // 176
0x03, 0xFF, 0x0A, 0x06, // 177
0x04, 0x09, 0x05, 0x04, // 178
0x04, 0x0E, 0x05, 0x04, // 179
0x04, 0x13, 0x05, 0x04, // 180
0x04, 0x18, 0x0A, 0x06, // 181
0x04, 0x22, 0x09, 0x06, // 182
0x04, 0x2B, 0x03, 0x03, // 183
0x04, 0x2E, 0x0B, 0x07, // 184
0x04, 0x39, 0x0B, 0x07, // 185
0x04, 0x44, 0x07, 0x05, // 186
0x04, 0x4B, 0x0A, 0x06, // 187
0x04, 0x55, 0x10, 0x09, // 188
0x04, 0x65, 0x10, 0x09, // 189
0x04, 0x75, 0x10, 0x09, // 190
0x04, 0x85, 0x0A, 0x06, // 191
0x04, 0x8F, 0x0C, 0x07, // 192
0x04, 0x9B, 0x0C, 0x07, // 193
0x04, 0xA7, 0x0C, 0x07, // 194
0x04, 0xB3, 0x0B, 0x07, // 195
0x04, 0xBE, 0x0C, 0x07, // 196
0x04, 0xCA, 0x0C, 0x07, // 197
0x04, 0xD6, 0x0C, 0x07, // 198
0x04, 0xE2, 0x0C, 0x07, // 199
0x04, 0xEE, 0x0C, 0x07, // 200
0x04, 0xFA, 0x0C, 0x07, // 201
0x05, 0x06, 0x0C, 0x07, // 202
0x05, 0x12, 0x0C, 0x07, // 203
0x05, 0x1E, 0x0C, 0x07, // 204
0x05, 0x2A, 0x0C, 0x07, // 205
0x05, 0x36, 0x0C, 0x07, // 206
0x05, 0x42, 0x0C, 0x07, // 207
0x05, 0x4E, 0x0B, 0x07, // 208
0x05, 0x59, 0x0C, 0x07, // 209
0x05, 0x65, 0x0B, 0x07, // 210
0x05, 0x70, 0x0C, 0x07, // 211
0x05, 0x7C, 0x0B, 0x07, // 212
0x05, 0x87, 0x0C, 0x07, // 213
0x05, 0x93, 0x0C, 0x07, // 214
0x05, 0x9F, 0x0C, 0x07, // 215
0x05, 0xAB, 0x0C, 0x07, // 216
0x05, 0xB7, 0x0E, 0x08, // 217
0x05, 0xC5, 0x0C, 0x07, // 218
0x05, 0xD1, 0x0C, 0x07, // 219
0x05, 0xDD, 0x0C, 0x07, // 220
0x05, 0xE9, 0x0C, 0x07, // 221
0x05, 0xF5, 0x0C, 0x07, // 222
0x06, 0x01, 0x0C, 0x07, // 223
0x06, 0x0D, 0x0C, 0x07, // 224
0x06, 0x19, 0x0C, 0x07, // 225
0x06, 0x25, 0x0C, 0x07, // 226
0x06, 0x31, 0x0B, 0x07, // 227
0x06, 0x3C, 0x0C, 0x07, // 228
0x06, 0x48, 0x0B, 0x07, // 229
0x06, 0x53, 0x0C, 0x07, // 230
0x06, 0x5F, 0x0C, 0x07, // 231
0x06, 0x6B, 0x0C, 0x07, // 232
0x06, 0x77, 0x0C, 0x07, // 233
0x06, 0x83, 0x0C, 0x07, // 234
0x06, 0x8F, 0x0C, 0x07, // 235
0x06, 0x9B, 0x0C, 0x07, // 236
0x06, 0xA7, 0x0C, 0x07, // 237
0x06, 0xB3, 0x0C, 0x07, // 238
0x06, 0xBF, 0x0C, 0x07, // 239
0x06, 0xCB, 0x0B, 0x07, // 240
0x06, 0xD6, 0x0C, 0x07, // 241
0x06, 0xE2, 0x0B, 0x07, // 242
0x06, 0xED, 0x0C, 0x07, // 243
0x06, 0xF9, 0x0B, 0x07, // 244
0x07, 0x04, 0x0C, 0x07, // 245
0x07, 0x10, 0x0C, 0x07, // 246
0x07, 0x1C, 0x0C, 0x07, // 247
0x07, 0x28, 0x0C, 0x07, // 248
0x07, 0x34, 0x0E, 0x08, // 249
0x07, 0x42, 0x0C, 0x07, // 250
0x07, 0x4E, 0x0C, 0x07, // 251
0x07, 0x5A, 0x0C, 0x07, // 252
0x07, 0x66, 0x0C, 0x07, // 253
0x07, 0x72, 0x0C, 0x07, // 254
0x07, 0x7E, 0x0C, 0x07, // 255
// Font Data:
0x00, 0x00, 0xF8, 0x02, // 33
0x38, 0x00, 0x00, 0x00, 0x38, // 34
0xA0, 0x03, 0xE0, 0x00, 0xB8, 0x03, 0xE0, 0x00, 0xB8, // 35
0x30, 0x01, 0x28, 0x02, 0xF8, 0x07, 0x48, 0x02, 0x90, 0x01, // 36
0x00, 0x00, 0x30, 0x00, 0x48, 0x00, 0x30, 0x03, 0xC0, 0x00, 0xB0, 0x01, 0x48, 0x02, 0x80, 0x01, // 37
0x80, 0x01, 0x50, 0x02, 0x68, 0x02, 0xA8, 0x02, 0x18, 0x01, 0x80, 0x03, 0x80, 0x02, // 38
0x38, // 39
0xE0, 0x03, 0x10, 0x04, 0x08, 0x08, // 40
0x08, 0x08, 0x10, 0x04, 0xE0, 0x03, // 41
0x28, 0x00, 0x18, 0x00, 0x28, // 42
0x40, 0x00, 0x40, 0x00, 0xF0, 0x01, 0x40, 0x00, 0x40, // 43
0x00, 0x00, 0x00, 0x06, // 44
0x80, 0x00, 0x80, // 45
0x00, 0x00, 0x00, 0x02, // 46
0x00, 0x03, 0xE0, 0x00, 0x18, // 47
0xF0, 0x01, 0x08, 0x02, 0x08, 0x02, 0x08, 0x02, 0xF0, 0x01, // 48
0x00, 0x00, 0x20, 0x00, 0x10, 0x00, 0xF8, 0x03, // 49
0x10, 0x02, 0x08, 0x03, 0x88, 0x02, 0x48, 0x02, 0x30, 0x02, // 50
0x10, 0x01, 0x08, 0x02, 0x48, 0x02, 0x48, 0x02, 0xB0, 0x01, // 51
0xC0, 0x00, 0xA0, 0x00, 0x90, 0x00, 0x88, 0x00, 0xF8, 0x03, 0x80, // 52
0x60, 0x01, 0x38, 0x02, 0x28, 0x02, 0x28, 0x02, 0xC8, 0x01, // 53
0xF0, 0x01, 0x28, 0x02, 0x28, 0x02, 0x28, 0x02, 0xD0, 0x01, // 54
0x08, 0x00, 0x08, 0x03, 0xC8, 0x00, 0x38, 0x00, 0x08, // 55
0xB0, 0x01, 0x48, 0x02, 0x48, 0x02, 0x48, 0x02, 0xB0, 0x01, // 56
0x70, 0x01, 0x88, 0x02, 0x88, 0x02, 0x88, 0x02, 0xF0, 0x01, // 57
0x00, 0x00, 0x20, 0x02, // 58
0x00, 0x00, 0x20, 0x06, // 59
0x00, 0x00, 0x40, 0x00, 0xA0, 0x00, 0xA0, 0x00, 0x10, 0x01, // 60
0xA0, 0x00, 0xA0, 0x00, 0xA0, 0x00, 0xA0, 0x00, 0xA0, // 61
0x00, 0x00, 0x10, 0x01, 0xA0, 0x00, 0xA0, 0x00, 0x40, // 62
0x10, 0x00, 0x08, 0x00, 0x08, 0x00, 0xC8, 0x02, 0x48, 0x00, 0x30, // 63
0x00, 0x00, 0xC0, 0x03, 0x30, 0x04, 0xD0, 0x09, 0x28, 0x0A, 0x28, 0x0A, 0xC8, 0x0B, 0x68, 0x0A, 0x10, 0x05, 0xE0, 0x04, // 64
0x00, 0x02, 0xC0, 0x01, 0xB0, 0x00, 0x88, 0x00, 0xB0, 0x00, 0xC0, 0x01, 0x00, 0x02, // 65
0x00, 0x00, 0xF8, 0x03, 0x48, 0x02, 0x48, 0x02, 0x48, 0x02, 0xF0, 0x01, // 66
0x00, 0x00, 0xF0, 0x01, 0x08, 0x02, 0x08, 0x02, 0x08, 0x02, 0x10, 0x01, // 67
0x00, 0x00, 0xF8, 0x03, 0x08, 0x02, 0x08, 0x02, 0x10, 0x01, 0xE0, // 68
0x00, 0x00, 0xF8, 0x03, 0x48, 0x02, 0x48, 0x02, 0x48, 0x02, 0x48, 0x02, // 69
0x00, 0x00, 0xF8, 0x03, 0x48, 0x00, 0x48, 0x00, 0x08, // 70
0x00, 0x00, 0xE0, 0x00, 0x10, 0x01, 0x08, 0x02, 0x48, 0x02, 0x50, 0x01, 0xC0, // 71
0x00, 0x00, 0xF8, 0x03, 0x40, 0x00, 0x40, 0x00, 0x40, 0x00, 0xF8, 0x03, // 72
0x00, 0x00, 0xF8, 0x03, // 73
0x00, 0x03, 0x00, 0x02, 0x00, 0x02, 0xF8, 0x01, // 74
0x00, 0x00, 0xF8, 0x03, 0x80, 0x00, 0x60, 0x00, 0x90, 0x00, 0x08, 0x01, 0x00, 0x02, // 75
0x00, 0x00, 0xF8, 0x03, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, // 76
0x00, 0x00, 0xF8, 0x03, 0x30, 0x00, 0xC0, 0x01, 0x00, 0x02, 0xC0, 0x01, 0x30, 0x00, 0xF8, 0x03, // 77
0x00, 0x00, 0xF8, 0x03, 0x30, 0x00, 0x40, 0x00, 0x80, 0x01, 0xF8, 0x03, // 78
0x00, 0x00, 0xF0, 0x01, 0x08, 0x02, 0x08, 0x02, 0x08, 0x02, 0x08, 0x02, 0xF0, 0x01, // 79
0x00, 0x00, 0xF8, 0x03, 0x48, 0x00, 0x48, 0x00, 0x48, 0x00, 0x30, // 80
0x00, 0x00, 0xF0, 0x01, 0x08, 0x02, 0x08, 0x02, 0x08, 0x03, 0x08, 0x03, 0xF0, 0x02, // 81
0x00, 0x00, 0xF8, 0x03, 0x48, 0x00, 0x48, 0x00, 0xC8, 0x00, 0x30, 0x03, // 82
0x00, 0x00, 0x30, 0x01, 0x48, 0x02, 0x48, 0x02, 0x48, 0x02, 0x90, 0x01, // 83
0x00, 0x00, 0x08, 0x00, 0x08, 0x00, 0xF8, 0x03, 0x08, 0x00, 0x08, // 84
0x00, 0x00, 0xF8, 0x01, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0xF8, 0x01, // 85
0x08, 0x00, 0x70, 0x00, 0x80, 0x01, 0x00, 0x02, 0x80, 0x01, 0x70, 0x00, 0x08, // 86
0x18, 0x00, 0xE0, 0x01, 0x00, 0x02, 0xF0, 0x01, 0x08, 0x00, 0xF0, 0x01, 0x00, 0x02, 0xE0, 0x01, 0x18, // 87
0x00, 0x02, 0x08, 0x01, 0x90, 0x00, 0x60, 0x00, 0x90, 0x00, 0x08, 0x01, 0x00, 0x02, // 88
0x08, 0x00, 0x10, 0x00, 0x20, 0x00, 0xC0, 0x03, 0x20, 0x00, 0x10, 0x00, 0x08, // 89
0x08, 0x03, 0x88, 0x02, 0xC8, 0x02, 0x68, 0x02, 0x38, 0x02, 0x18, 0x02, // 90
0x00, 0x00, 0xF8, 0x0F, 0x08, 0x08, // 91
0x18, 0x00, 0xE0, 0x00, 0x00, 0x03, // 92
0x08, 0x08, 0xF8, 0x0F, // 93
0x40, 0x00, 0x30, 0x00, 0x08, 0x00, 0x30, 0x00, 0x40, // 94
0x00, 0x08, 0x00, 0x08, 0x00, 0x08, 0x00, 0x08, 0x00, 0x08, 0x00, 0x08, // 95
0x08, 0x00, 0x10, // 96
0x00, 0x00, 0x00, 0x03, 0xA0, 0x02, 0xA0, 0x02, 0xE0, 0x03, // 97
0x00, 0x00, 0xF8, 0x03, 0x20, 0x02, 0x20, 0x02, 0xC0, 0x01, // 98
0x00, 0x00, 0xC0, 0x01, 0x20, 0x02, 0x20, 0x02, 0x40, 0x01, // 99
0x00, 0x00, 0xC0, 0x01, 0x20, 0x02, 0x20, 0x02, 0xF8, 0x03, // 100
0x00, 0x00, 0xC0, 0x01, 0xA0, 0x02, 0xA0, 0x02, 0xC0, 0x02, // 101
0x20, 0x00, 0xF0, 0x03, 0x28, // 102
0x00, 0x00, 0xC0, 0x05, 0x20, 0x0A, 0x20, 0x0A, 0xE0, 0x07, // 103
0x00, 0x00, 0xF8, 0x03, 0x20, 0x00, 0x20, 0x00, 0xC0, 0x03, // 104
0x00, 0x00, 0xE8, 0x03, // 105
0x00, 0x08, 0xE8, 0x07, // 106
0xF8, 0x03, 0x80, 0x00, 0xC0, 0x01, 0x20, 0x02, // 107
0x00, 0x00, 0xF8, 0x03, // 108
0x00, 0x00, 0xE0, 0x03, 0x20, 0x00, 0x20, 0x00, 0xE0, 0x03, 0x20, 0x00, 0x20, 0x00, 0xC0, 0x03, // 109
0x00, 0x00, 0xE0, 0x03, 0x20, 0x00, 0x20, 0x00, 0xC0, 0x03, // 110
0x00, 0x00, 0xC0, 0x01, 0x20, 0x02, 0x20, 0x02, 0xC0, 0x01, // 111
0x00, 0x00, 0xE0, 0x0F, 0x20, 0x02, 0x20, 0x02, 0xC0, 0x01, // 112
0x00, 0x00, 0xC0, 0x01, 0x20, 0x02, 0x20, 0x02, 0xE0, 0x0F, // 113
0x00, 0x00, 0xE0, 0x03, 0x20, // 114
0x40, 0x02, 0xA0, 0x02, 0xA0, 0x02, 0x20, 0x01, // 115
0x20, 0x00, 0xF8, 0x03, 0x20, 0x02, // 116
0x00, 0x00, 0xE0, 0x01, 0x00, 0x02, 0x00, 0x02, 0xE0, 0x03, // 117
0x20, 0x00, 0xC0, 0x01, 0x00, 0x02, 0xC0, 0x01, 0x20, // 118
0xE0, 0x01, 0x00, 0x02, 0xC0, 0x01, 0x20, 0x00, 0xC0, 0x01, 0x00, 0x02, 0xE0, 0x01, // 119
0x20, 0x02, 0x40, 0x01, 0x80, 0x00, 0x40, 0x01, 0x20, 0x02, // 120
0x20, 0x00, 0xC0, 0x09, 0x00, 0x06, 0xC0, 0x01, 0x20, // 121
0x20, 0x02, 0x20, 0x03, 0xA0, 0x02, 0x60, 0x02, 0x20, 0x02, // 122
0x80, 0x00, 0x78, 0x0F, 0x08, 0x08, // 123
0x00, 0x00, 0xF8, 0x0F, // 124
0x08, 0x08, 0x78, 0x0F, 0x80, // 125
0xC0, 0x00, 0x40, 0x00, 0xC0, 0x00, 0x80, 0x00, 0xC0, // 126
0x00, 0x00, 0xA0, 0x0F, // 161
0x00, 0x00, 0xC0, 0x01, 0xA0, 0x0F, 0x78, 0x02, 0x40, 0x01, // 162
0x40, 0x02, 0x70, 0x03, 0xC8, 0x02, 0x48, 0x02, 0x08, 0x02, 0x10, 0x02, // 163
0x00, 0x00, 0xE0, 0x01, 0x20, 0x01, 0x20, 0x01, 0xE0, 0x01, // 164
0x48, 0x01, 0x70, 0x01, 0xC0, 0x03, 0x70, 0x01, 0x48, 0x01, // 165
0x00, 0x00, 0x38, 0x0F, // 166
0xD0, 0x04, 0x28, 0x09, 0x48, 0x09, 0x48, 0x0A, 0x90, 0x05, // 167
0x00, 0x00, 0xE0, 0x03, 0xA8, 0x02, 0xA0, 0x02, 0xA8, 0x02, 0x20, 0x02, // 168
0xE0, 0x00, 0x10, 0x01, 0x48, 0x02, 0xA8, 0x02, 0xA8, 0x02, 0x10, 0x01, 0xE0, // 169
0x68, 0x00, 0x68, 0x00, 0x68, 0x00, 0x78, // 170
0x00, 0x00, 0x80, 0x01, 0x40, 0x02, 0x80, 0x01, 0x40, 0x02, // 171
0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0xE0, // 172
0x80, 0x00, 0x80, // 173
0xE0, 0x00, 0x10, 0x01, 0xE8, 0x02, 0x68, 0x02, 0xC8, 0x02, 0x10, 0x01, 0xE0, // 174
0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, // 175
0x00, 0x00, 0x38, 0x00, 0x28, 0x00, 0x38, // 176
0x40, 0x02, 0x40, 0x02, 0xF0, 0x03, 0x40, 0x02, 0x40, 0x02, // 177
0x48, 0x00, 0x68, 0x00, 0x58, // 178
0x48, 0x00, 0x58, 0x00, 0x68, // 179
0x00, 0x00, 0x10, 0x00, 0x08, // 180
0x00, 0x00, 0xE0, 0x0F, 0x00, 0x02, 0x00, 0x02, 0xE0, 0x03, // 181
0x70, 0x00, 0xF8, 0x0F, 0x08, 0x00, 0xF8, 0x0F, 0x08, // 182
0x00, 0x00, 0x40, // 183
0x00, 0x00, 0xC0, 0x01, 0xA8, 0x02, 0xA0, 0x02, 0xA8, 0x02, 0xC0, // 184
0x00, 0x00, 0xF0, 0x03, 0x40, 0x00, 0x80, 0x00, 0xF8, 0x03, 0x08, // 185
0x30, 0x00, 0x48, 0x00, 0x48, 0x00, 0x30, // 186
0x00, 0x00, 0x40, 0x02, 0x80, 0x01, 0x40, 0x02, 0x80, 0x01, // 187
0x00, 0x00, 0x10, 0x02, 0x78, 0x01, 0xC0, 0x00, 0x20, 0x01, 0x90, 0x01, 0xC8, 0x03, 0x00, 0x01, // 188
0x00, 0x00, 0x10, 0x02, 0x78, 0x01, 0x80, 0x00, 0x60, 0x00, 0x50, 0x02, 0x48, 0x03, 0xC0, 0x02, // 189
0x48, 0x00, 0x58, 0x00, 0x68, 0x03, 0x80, 0x00, 0x60, 0x01, 0x90, 0x01, 0xC8, 0x03, 0x00, 0x01, // 190
0x00, 0x00, 0x00, 0x06, 0x00, 0x09, 0xA0, 0x09, 0x00, 0x04, // 191
0x00, 0x00, 0xF0, 0x03, 0x88, 0x00, 0x88, 0x00, 0x88, 0x00, 0xF0, 0x03, // 192
0x00, 0x00, 0xF8, 0x03, 0x48, 0x02, 0x48, 0x02, 0x48, 0x02, 0x88, 0x01, // 193
0x00, 0x00, 0xF8, 0x03, 0x48, 0x02, 0x48, 0x02, 0x48, 0x02, 0xB0, 0x01, // 194
0x00, 0x00, 0xF8, 0x03, 0x08, 0x00, 0x08, 0x00, 0x08, 0x00, 0x18, // 195
0x00, 0x00, 0x00, 0x02, 0xFC, 0x03, 0x04, 0x02, 0xFC, 0x03, 0x00, 0x02, // 196
0x00, 0x00, 0xF8, 0x03, 0x48, 0x02, 0x48, 0x02, 0x48, 0x02, 0x08, 0x02, // 197
0x00, 0x00, 0xB8, 0x03, 0x40, 0x00, 0xF8, 0x03, 0x40, 0x00, 0xB8, 0x03, // 198
0x00, 0x00, 0x08, 0x02, 0x48, 0x02, 0x48, 0x02, 0x48, 0x02, 0xB0, 0x01, // 199
0x00, 0x00, 0xF8, 0x03, 0x80, 0x00, 0x40, 0x00, 0x20, 0x00, 0xF8, 0x03, // 200
0x00, 0x00, 0xE0, 0x03, 0x08, 0x01, 0x90, 0x00, 0x48, 0x00, 0xE0, 0x03, // 201
0x00, 0x00, 0xF8, 0x03, 0x40, 0x00, 0xA0, 0x00, 0x10, 0x01, 0x08, 0x02, // 202
0x00, 0x00, 0x00, 0x02, 0xF0, 0x01, 0x08, 0x00, 0x08, 0x00, 0xF8, 0x03, // 203
0x00, 0x00, 0xF8, 0x03, 0x10, 0x00, 0x60, 0x00, 0x10, 0x00, 0xF8, 0x03, // 204
0x00, 0x00, 0xF8, 0x03, 0x40, 0x00, 0x40, 0x00, 0x40, 0x00, 0xF8, 0x03, // 205
0x00, 0x00, 0xF0, 0x01, 0x08, 0x02, 0x08, 0x02, 0x08, 0x02, 0xF0, 0x01, // 206
0x00, 0x00, 0xF8, 0x03, 0x08, 0x00, 0x08, 0x00, 0x08, 0x00, 0xF8, 0x03, // 207
0x00, 0x00, 0xF8, 0x03, 0x48, 0x00, 0x48, 0x00, 0x48, 0x00, 0x30, // 208
0x00, 0x00, 0xF0, 0x01, 0x08, 0x02, 0x08, 0x02, 0x08, 0x02, 0x10, 0x01, // 209
0x00, 0x00, 0x08, 0x00, 0x08, 0x00, 0xF8, 0x03, 0x08, 0x00, 0x08, // 210
0x00, 0x00, 0x38, 0x00, 0x40, 0x02, 0x40, 0x02, 0x40, 0x02, 0xF8, 0x01, // 211
0x00, 0x00, 0x70, 0x00, 0x88, 0x00, 0xF8, 0x03, 0x88, 0x00, 0x70, // 212
0x00, 0x00, 0x18, 0x03, 0xA0, 0x00, 0x40, 0x00, 0xA0, 0x00, 0x18, 0x03, // 213
0x00, 0x00, 0xF8, 0x03, 0x00, 0x02, 0x00, 0x02, 0xF8, 0x03, 0x00, 0x02, // 214
0x00, 0x00, 0x38, 0x00, 0x40, 0x00, 0x40, 0x00, 0x40, 0x00, 0xF8, 0x03, // 215
0x00, 0x00, 0xF8, 0x03, 0x00, 0x02, 0xF8, 0x03, 0x00, 0x02, 0xF8, 0x03, // 216
0x00, 0x00, 0xF8, 0x03, 0x00, 0x02, 0xF8, 0x03, 0x00, 0x02, 0xF8, 0x03, 0x00, 0x06, // 217
0x00, 0x00, 0x08, 0x00, 0xF8, 0x03, 0x40, 0x02, 0x40, 0x02, 0x80, 0x01, // 218
0x00, 0x00, 0xF8, 0x03, 0x40, 0x02, 0x40, 0x02, 0x80, 0x01, 0xF8, 0x03, // 219
0x00, 0x00, 0xF8, 0x03, 0x40, 0x02, 0x40, 0x02, 0x40, 0x02, 0x80, 0x01, // 220
0x00, 0x00, 0x10, 0x01, 0x08, 0x02, 0x48, 0x02, 0x48, 0x02, 0xF0, 0x01, // 221
0x00, 0x00, 0xF8, 0x03, 0x40, 0x00, 0xF0, 0x01, 0x08, 0x02, 0xF0, 0x01, // 222
0x00, 0x00, 0x30, 0x02, 0x48, 0x01, 0xC8, 0x00, 0x48, 0x00, 0xF8, 0x03, // 223
0x00, 0x00, 0x00, 0x01, 0xA0, 0x02, 0xA0, 0x02, 0xA0, 0x02, 0xC0, 0x03, // 224
0x00, 0x00, 0xE0, 0x01, 0x50, 0x02, 0x50, 0x02, 0x48, 0x02, 0x88, 0x01, // 225
0x00, 0x00, 0xE0, 0x03, 0xA0, 0x02, 0xA0, 0x02, 0xA0, 0x02, 0x40, 0x01, // 226
0x00, 0x00, 0xE0, 0x03, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x60, // 227
0x00, 0x00, 0x00, 0x02, 0xC0, 0x03, 0x20, 0x02, 0xE0, 0x03, 0x00, 0x02, // 228
0x00, 0x00, 0xC0, 0x01, 0xA0, 0x02, 0xA0, 0x02, 0xA0, 0x02, 0xC0, // 229
0x00, 0x00, 0x60, 0x03, 0x80, 0x00, 0xE0, 0x03, 0x80, 0x00, 0x60, 0x03, // 230
0x00, 0x00, 0x20, 0x02, 0xA0, 0x02, 0xA0, 0x02, 0xA0, 0x02, 0x40, 0x01, // 231
0x00, 0x00, 0xE0, 0x03, 0x00, 0x01, 0x80, 0x00, 0x40, 0x00, 0xE0, 0x03, // 232
0x00, 0x00, 0xE0, 0x03, 0x00, 0x01, 0x98, 0x00, 0x40, 0x00, 0xE0, 0x03, // 233
0x00, 0x00, 0xE0, 0x03, 0x80, 0x00, 0x80, 0x00, 0x40, 0x01, 0x20, 0x02, // 234
0x00, 0x00, 0x00, 0x02, 0xC0, 0x01, 0x20, 0x00, 0x20, 0x00, 0xE0, 0x03, // 235
0x00, 0x00, 0xE0, 0x03, 0x40, 0x00, 0x80, 0x00, 0x40, 0x00, 0xE0, 0x03, // 236
0x00, 0x00, 0xE0, 0x03, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0xE0, 0x03, // 237
0x00, 0x00, 0xC0, 0x01, 0x20, 0x02, 0x20, 0x02, 0x20, 0x02, 0xC0, 0x01, // 238
0x00, 0x00, 0xE0, 0x03, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0xE0, 0x03, // 239
0x00, 0x00, 0xE0, 0x03, 0xA0, 0x00, 0xA0, 0x00, 0xA0, 0x00, 0x40, // 240
0x00, 0x00, 0xC0, 0x01, 0x20, 0x02, 0x20, 0x02, 0x20, 0x02, 0x40, 0x02, // 241
0x00, 0x00, 0x20, 0x00, 0x20, 0x00, 0xE0, 0x03, 0x20, 0x00, 0x20, // 242
0x00, 0x00, 0x60, 0x00, 0x80, 0x02, 0x80, 0x02, 0x80, 0x02, 0xE0, 0x01, // 243
0x00, 0x00, 0xC0, 0x00, 0x20, 0x01, 0xE0, 0x03, 0x20, 0x01, 0xC0, // 244
0x00, 0x00, 0x20, 0x02, 0x40, 0x01, 0x80, 0x00, 0x40, 0x01, 0x20, 0x02, // 245
0x00, 0x00, 0xE0, 0x03, 0x00, 0x02, 0x00, 0x02, 0xE0, 0x03, 0x00, 0x02, // 246
0x00, 0x00, 0x60, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0xE0, 0x03, // 247
0x00, 0x00, 0xE0, 0x03, 0x00, 0x02, 0xE0, 0x03, 0x00, 0x02, 0xE0, 0x03, // 248
0x00, 0x00, 0xE0, 0x03, 0x00, 0x02, 0xE0, 0x03, 0x00, 0x02, 0xE0, 0x03, 0x00, 0x06, // 249
0x00, 0x00, 0x20, 0x00, 0xE0, 0x03, 0x80, 0x02, 0x80, 0x02, 0x00, 0x01, // 250
0x00, 0x00, 0xE0, 0x03, 0x80, 0x02, 0x80, 0x02, 0x00, 0x01, 0xE0, 0x03, // 251
0x00, 0x00, 0xE0, 0x03, 0x80, 0x02, 0x80, 0x02, 0x80, 0x02, 0x00, 0x01, // 252
0x00, 0x00, 0x40, 0x01, 0x20, 0x02, 0xA0, 0x02, 0xA0, 0x02, 0xC0, 0x01, // 253
0x00, 0x00, 0xE0, 0x03, 0x80, 0x00, 0xC0, 0x01, 0x20, 0x02, 0xC0, 0x01, // 254
0x00, 0x00, 0x40, 0x02, 0xA0, 0x01, 0xA0, 0x00, 0xA0, 0x00, 0xE0, 0x03, // 255
};

View File

@@ -0,0 +1,11 @@
#ifndef OLEDDISPLAYFONTSRU_h
#define OLEDDISPLAYFONTSRU_h
#ifdef ARDUINO
#include <Arduino.h>
#elif __MBED__
#define PROGMEM
#endif
extern const uint8_t ArialMT_Plain_10_RU[] PROGMEM;
#endif

View File

@@ -33,13 +33,7 @@
#ifdef ARCH_ESP32 #ifdef ARCH_ESP32
#include "mesh/http/WebServer.h" #include "mesh/http/WebServer.h"
#include "nimble/NimbleBluetooth.h"
#ifdef USE_NEW_ESP32_BLUETOOTH
#include "platform/esp32/ESP32Bluetooth.h"
#else
#include "nimble/BluetoothUtil.h"
#endif
#endif #endif
#if HAS_WIFI #if HAS_WIFI

View File

@@ -16,6 +16,10 @@
#include "modules/PositionModule.h" #include "modules/PositionModule.h"
#include "power.h" #include "power.h"
#ifdef ARCH_ESP32
#include "nimble/NimbleBluetooth.h"
#endif
/* /*
receivedPacketQueue - this is a queue of messages we've received from the mesh, which we are keeping to deliver to the phone. receivedPacketQueue - this is a queue of messages we've received from the mesh, which we are keeping to deliver to the phone.
It is implemented with a FreeRTos queue (wrapped with a little RTQueue class) of pointers to MeshPacket protobufs (which were It is implemented with a FreeRTos queue (wrapped with a little RTQueue class) of pointers to MeshPacket protobufs (which were

View File

@@ -112,6 +112,13 @@ bool NodeDB::resetRadioConfig()
// Update the global myRegion // Update the global myRegion
initRegion(); initRegion();
if (didFactoryReset) {
config.device.factory_reset = false;
DEBUG_MSG("Rebooting due to factory reset");
screen->startRebootScreen();
rebootAtMsec = millis() + (5 * 1000);
}
return didFactoryReset; return didFactoryReset;
} }
@@ -122,6 +129,7 @@ bool NodeDB::factoryReset()
rmDir("/prefs"); rmDir("/prefs");
// second, install default state (this will deal with the duplicate mac address issue) // second, install default state (this will deal with the duplicate mac address issue)
installDefaultDeviceState(); installDefaultDeviceState();
installDefaultConfig();
// third, write to disk // third, write to disk
saveToDisk(); saveToDisk();
#ifdef ARCH_ESP32 #ifdef ARCH_ESP32
@@ -150,14 +158,23 @@ void NodeDB::installDefaultConfig()
config.has_position = true; config.has_position = true;
config.has_power = true; config.has_power = true;
config.has_wifi = true; config.has_wifi = true;
config.has_bluetooth = true;
config.lora.region = Config_LoRaConfig_RegionCode_Unset; config.lora.region = Config_LoRaConfig_RegionCode_Unset;
config.lora.modem_preset = Config_LoRaConfig_ModemPreset_LongFast; config.lora.modem_preset = Config_LoRaConfig_ModemPreset_LongFast;
resetRadioConfig(); resetRadioConfig();
strncpy(config.device.ntp_server, "0.pool.ntp.org", 32); strncpy(config.device.ntp_server, "0.pool.ntp.org", 32);
// FIXME: Default to bluetooth capability of platform as default
config.bluetooth.enabled = true;
config.bluetooth.fixed_pin = defaultBLEPin;
#if defined(ST7735_CS) || defined(USE_EINK) || defined(ILI9341_DRIVER)
bool hasScreen = true;
#else
bool hasScreen = screen_found;
#endif
config.bluetooth.mode = hasScreen ? Config_BluetoothConfig_PairingMode_RandomPin : Config_BluetoothConfig_PairingMode_FixedPin;
// for backward compat, default position flags are ALT+MSL // for backward compat, default position flags are ALT+MSL
config.position.position_flags = config.position.position_flags = (Config_PositionConfig_PositionFlags_POS_ALTITUDE | Config_PositionConfig_PositionFlags_POS_ALT_MSL);
(Config_PositionConfig_PositionFlags_POS_ALTITUDE | Config_PositionConfig_PositionFlags_POS_ALT_MSL);
} }
void NodeDB::installDefaultModuleConfig() void NodeDB::installDefaultModuleConfig()
@@ -452,6 +469,7 @@ void NodeDB::saveToDisk()
config.has_position = true; config.has_position = true;
config.has_power = true; config.has_power = true;
config.has_wifi = true; config.has_wifi = true;
config.has_bluetooth = true;
saveProto(configFileName, LocalConfig_size, sizeof(LocalConfig), LocalConfig_fields, &config); saveProto(configFileName, LocalConfig_size, sizeof(LocalConfig), LocalConfig_fields, &config);
moduleConfig.has_canned_message = true; moduleConfig.has_canned_message = true;

View File

@@ -13,7 +13,7 @@ DeviceState versions used to be defined in the .proto file but really only this
#define here. #define here.
*/ */
#define DEVICESTATE_CUR_VER 14 #define DEVICESTATE_CUR_VER 16
#define DEVICESTATE_MIN_VER DEVICESTATE_CUR_VER #define DEVICESTATE_MIN_VER DEVICESTATE_CUR_VER
extern DeviceState devicestate; extern DeviceState devicestate;
@@ -179,15 +179,20 @@ extern NodeDB nodeDB;
#define default_sds_secs 365 * 24 * 60 * 60 #define default_sds_secs 365 * 24 * 60 * 60
#define default_ls_secs IF_ROUTER(24 * 60 * 60, 5 * 60) #define default_ls_secs IF_ROUTER(24 * 60 * 60, 5 * 60)
#define default_min_wake_secs 10 #define default_min_wake_secs 10
#define default_screen_on_secs 60 * 10
inline uint32_t getConfiguredOrDefaultMs(uint32_t configuredInterval)
inline uint32_t getIntervalOrDefaultMs(uint32_t interval)
{ {
if (interval > 0) if (configuredInterval > 0) return configuredInterval * 1000;
return interval * 1000;
return default_broadcast_interval_secs * 1000; return default_broadcast_interval_secs * 1000;
} }
inline uint32_t getConfiguredOrDefaultMs(uint32_t configuredInterval, uint32_t defaultInterval)
{
if (configuredInterval > 0) return configuredInterval * 1000;
return defaultInterval * 1000;
}
/** The current change # for radio settings. Starts at 0 on boot and any time the radio settings /** The current change # for radio settings. Starts at 0 on boot and any time the radio settings
* might have changed is incremented. Allows others to detect they might now be on a new channel. * might have changed is incremented. Allows others to detect they might now be on a new channel.
*/ */

View File

@@ -84,10 +84,10 @@ bool PhoneAPI::handleToRadio(const uint8_t *buf, size_t bufLength)
case ToRadio_want_config_id_tag: case ToRadio_want_config_id_tag:
config_nonce = toRadioScratch.want_config_id; config_nonce = toRadioScratch.want_config_id;
DEBUG_MSG("Client wants config, nonce=%u\n", config_nonce); DEBUG_MSG("Client wants config, nonce=%u\n", config_nonce);
handleStartConfig(); handleStartConfig();
break; break;
case ToRadio_disconnect_tag: case ToRadio_disconnect_tag:
DEBUG_MSG("Disconnecting from phone\n");
close(); close();
break; break;
default: default:
@@ -117,21 +117,20 @@ bool PhoneAPI::handleToRadio(const uint8_t *buf, size_t bufLength)
size_t PhoneAPI::getFromRadio(uint8_t *buf) size_t PhoneAPI::getFromRadio(uint8_t *buf)
{ {
if (!available()) { if (!available()) {
// DEBUG_MSG("getFromRadio, !available\n"); DEBUG_MSG("getFromRadio=not available\n");
return 0; return 0;
} }
DEBUG_MSG("getFromRadio, state=%d\n", state);
// In case we send a FromRadio packet // In case we send a FromRadio packet
memset(&fromRadioScratch, 0, sizeof(fromRadioScratch)); memset(&fromRadioScratch, 0, sizeof(fromRadioScratch));
// Advance states as needed // Advance states as needed
switch (state) { switch (state) {
case STATE_SEND_NOTHING: case STATE_SEND_NOTHING:
DEBUG_MSG("getFromRadio=STATE_SEND_NOTHING\n");
break; break;
case STATE_SEND_MY_INFO: case STATE_SEND_MY_INFO:
DEBUG_MSG("getFromRadio=STATE_SEND_MY_INFO\n");
// If the user has specified they don't want our node to share its location, make sure to tell the phone // If the user has specified they don't want our node to share its location, make sure to tell the phone
// app not to send locations on our behalf. // app not to send locations on our behalf.
myNodeInfo.has_gps = gps && gps->isConnected(); // Update with latest GPS connect info myNodeInfo.has_gps = gps && gps->isConnected(); // Update with latest GPS connect info
@@ -143,6 +142,7 @@ size_t PhoneAPI::getFromRadio(uint8_t *buf)
break; break;
case STATE_SEND_NODEINFO: { case STATE_SEND_NODEINFO: {
DEBUG_MSG("getFromRadio=STATE_SEND_NODEINFO\n");
const NodeInfo *info = nodeInfoForPhone; const NodeInfo *info = nodeInfoForPhone;
nodeInfoForPhone = NULL; // We just consumed a nodeinfo, will need a new one next time nodeInfoForPhone = NULL; // We just consumed a nodeinfo, will need a new one next time
@@ -162,6 +162,7 @@ size_t PhoneAPI::getFromRadio(uint8_t *buf)
} }
case STATE_SEND_CONFIG: case STATE_SEND_CONFIG:
DEBUG_MSG("getFromRadio=STATE_SEND_CONFIG\n");
fromRadioScratch.which_payloadVariant = FromRadio_config_tag; fromRadioScratch.which_payloadVariant = FromRadio_config_tag;
switch (config_state) { switch (config_state) {
case Config_device_tag: case Config_device_tag:
@@ -189,21 +190,25 @@ size_t PhoneAPI::getFromRadio(uint8_t *buf)
fromRadioScratch.config.which_payloadVariant = Config_lora_tag; fromRadioScratch.config.which_payloadVariant = Config_lora_tag;
fromRadioScratch.config.payloadVariant.lora = config.lora; fromRadioScratch.config.payloadVariant.lora = config.lora;
break; break;
case Config_bluetooth_tag:
fromRadioScratch.config.which_payloadVariant = Config_bluetooth_tag;
fromRadioScratch.config.payloadVariant.bluetooth = config.bluetooth;
break;
} }
// NOTE: The phone app needs to know the ls_secs value so it can properly expect sleep behavior. // NOTE: The phone app needs to know the ls_secs value so it can properly expect sleep behavior.
// So even if we internally use 0 to represent 'use default' we still need to send the value we are // So even if we internally use 0 to represent 'use default' we still need to send the value we are
// using to the app (so that even old phone apps work with new device loads). // using to the app (so that even old phone apps work with new device loads).
config_state++; config_state++;
// Advance when we have sent all of our config objects // Advance when we have sent all of our config objects
if (config_state > Config_lora_tag) { if (config_state > Config_bluetooth_tag) {
state = STATE_SEND_MODULECONFIG; state = STATE_SEND_MODULECONFIG;
config_state = ModuleConfig_mqtt_tag; config_state = ModuleConfig_mqtt_tag;
} }
break; break;
case STATE_SEND_MODULECONFIG: case STATE_SEND_MODULECONFIG:
DEBUG_MSG("getFromRadio=STATE_SEND_MODULECONFIG\n");
fromRadioScratch.which_payloadVariant = FromRadio_moduleConfig_tag; fromRadioScratch.which_payloadVariant = FromRadio_moduleConfig_tag;
switch (config_state) { switch (config_state) {
case ModuleConfig_mqtt_tag: case ModuleConfig_mqtt_tag:
@@ -241,6 +246,7 @@ size_t PhoneAPI::getFromRadio(uint8_t *buf)
break; break;
case STATE_SEND_COMPLETE_ID: case STATE_SEND_COMPLETE_ID:
DEBUG_MSG("getFromRadio=STATE_SEND_COMPLETE_ID\n");
fromRadioScratch.which_payloadVariant = FromRadio_config_complete_id_tag; fromRadioScratch.which_payloadVariant = FromRadio_config_complete_id_tag;
fromRadioScratch.config_complete_id = config_nonce; fromRadioScratch.config_complete_id = config_nonce;
config_nonce = 0; config_nonce = 0;
@@ -249,6 +255,7 @@ size_t PhoneAPI::getFromRadio(uint8_t *buf)
case STATE_SEND_PACKETS: case STATE_SEND_PACKETS:
// Do we have a message from the mesh? // Do we have a message from the mesh?
DEBUG_MSG("getFromRadio=STATE_SEND_PACKETS\n");
if (packetForPhone) { if (packetForPhone) {
printPacket("phone downloaded packet", packetForPhone); printPacket("phone downloaded packet", packetForPhone);
@@ -275,7 +282,10 @@ size_t PhoneAPI::getFromRadio(uint8_t *buf)
return 0; return 0;
} }
void PhoneAPI::handleDisconnect() {} void PhoneAPI::handleDisconnect()
{
DEBUG_MSG("PhoneAPI disconnect\n");
}
void PhoneAPI::releasePhonePacket() void PhoneAPI::releasePhonePacket()
{ {
@@ -291,35 +301,27 @@ void PhoneAPI::releasePhonePacket()
bool PhoneAPI::available() bool PhoneAPI::available()
{ {
switch (state) { switch (state) {
case STATE_SEND_NOTHING: case STATE_SEND_NOTHING:
return false; return false;
case STATE_SEND_MY_INFO:
case STATE_SEND_MY_INFO: return true;
return true; case STATE_SEND_CONFIG:
return true;
case STATE_SEND_CONFIG: case STATE_SEND_MODULECONFIG:
return true; return true;
case STATE_SEND_NODEINFO:
case STATE_SEND_MODULECONFIG: if (!nodeInfoForPhone)
return true; nodeInfoForPhone = nodeDB.readNextInfo();
return true; // Always say we have something, because we might need to advance our state machine
case STATE_SEND_NODEINFO: case STATE_SEND_COMPLETE_ID:
if (!nodeInfoForPhone) return true;
nodeInfoForPhone = nodeDB.readNextInfo(); case STATE_SEND_PACKETS: {
return true; // Always say we have something, because we might need to advance our state machine if (!packetForPhone)
packetForPhone = service.getForPhone();
case STATE_SEND_COMPLETE_ID: bool hasPacket = !!packetForPhone;
return true; DEBUG_MSG("available hasPacket=%d\n", hasPacket);
return hasPacket;
case STATE_SEND_PACKETS: {
// Try to pull a new packet from the service (if we haven't already)
if (!packetForPhone)
packetForPhone = service.getForPhone();
bool hasPacket = !!packetForPhone;
// DEBUG_MSG("available hasPacket=%d\n", hasPacket);
return hasPacket;
} }
default: default:
assert(0); // unexpected state - FIXME, make an error code and reboot assert(0); // unexpected state - FIXME, make an error code and reboot
} }

View File

@@ -59,7 +59,7 @@ class PhoneAPI
// Call this when the client drops the connection, resets the state to STATE_SEND_NOTHING // Call this when the client drops the connection, resets the state to STATE_SEND_NOTHING
// Unregisters our observer. A closed connection **can** be reopened by calling init again. // Unregisters our observer. A closed connection **can** be reopened by calling init again.
virtual void close(); virtual void close();
/** /**
* Handle a ToRadio protobuf * Handle a ToRadio protobuf
* @return true true if a packet was queued for sending (so that caller can yield) * @return true true if a packet was queued for sending (so that caller can yield)
@@ -81,6 +81,8 @@ class PhoneAPI
bool isConnected() { return state != STATE_SEND_NOTHING; } bool isConnected() { return state != STATE_SEND_NOTHING; }
void setInitialState() { state = STATE_SEND_MY_INFO; }
/// emit a debugging log character, FIXME - implement /// emit a debugging log character, FIXME - implement
void debugOut(char c) { } void debugOut(char c) { }

View File

@@ -43,6 +43,10 @@ RadioLibInterface::RadioLibInterface(RADIOLIB_PIN_TYPE cs, RADIOLIB_PIN_TYPE irq
: NotifiedWorkerThread("RadioIf"), module(cs, irq, rst, busy, spi, spiSettings), iface(_iface) : NotifiedWorkerThread("RadioIf"), module(cs, irq, rst, busy, spi, spiSettings), iface(_iface)
{ {
instance = this; instance = this;
#if defined(ARCH_STM32WL) && defined(USE_SX1262)
module.setCb_digitalWrite(stm32wl_emulate_digitalWrite);
module.setCb_digitalRead(stm32wl_emulate_digitalRead);
#endif
} }
#ifdef ARCH_ESP32 #ifdef ARCH_ESP32

View File

@@ -67,6 +67,12 @@ bool ReliableRouter::shouldFilterReceived(MeshPacket *p)
sendAckNak(Routing_Error_NONE, getFrom(p), p->id, p->channel); sendAckNak(Routing_Error_NONE, getFrom(p), p->id, p->channel);
DEBUG_MSG("acking a repeated want_ack packet\n"); DEBUG_MSG("acking a repeated want_ack packet\n");
} }
} else if (wasSeenRecently(p, false) && p->hop_limit == HOP_RELIABLE) {
// retransmission on broadcast has hop_limit still equal to HOP_RELIABLE
DEBUG_MSG("Resending implicit ack for a repeated floodmsg\n");
MeshPacket *tosend = packetPool.allocCopy(*p);
tosend->hop_limit--; // bump down the hop count
Router::send(tosend);
} }
return FloodingRouter::shouldFilterReceived(p); return FloodingRouter::shouldFilterReceived(p);
@@ -106,7 +112,7 @@ void ReliableRouter::sniffReceived(const MeshPacket *p, const Routing *c)
// We intentionally don't check wasSeenRecently, because it is harmless to delete non existent retransmission records // We intentionally don't check wasSeenRecently, because it is harmless to delete non existent retransmission records
if (ackId || nakId) { if (ackId || nakId) {
if (ackId) { if (ackId) {
DEBUG_MSG("Received a ack for 0x%x, stopping retransmissions\n", ackId); DEBUG_MSG("Received an ack for 0x%x, stopping retransmissions\n", ackId);
stopRetransmission(p->to, ackId); stopRetransmission(p->to, ackId);
} else { } else {
DEBUG_MSG("Received a nak for 0x%x, stopping retransmissions\n", nakId); DEBUG_MSG("Received a nak for 0x%x, stopping retransmissions\n", nakId);

View File

@@ -851,9 +851,11 @@ int readBit(const char *in, int bit_no) {
int read8bitCode(const char *in, int len, int bit_no) { int read8bitCode(const char *in, int len, int bit_no) {
int bit_pos = bit_no & 0x07; int bit_pos = bit_no & 0x07;
int char_pos = bit_no >> 3; int char_pos = bit_no >> 3;
len >>= 3;
byte code = (((byte)in[char_pos]) << bit_pos); byte code = (((byte)in[char_pos]) << bit_pos);
if (bit_no + bit_pos < len) { char_pos++;
code |= ((byte)in[++char_pos]) >> (8 - bit_pos); if (char_pos < len) {
code |= ((byte)in[char_pos]) >> (8 - bit_pos);
} else } else
code |= (0xFF >> (8 - bit_pos)); code |= (0xFF >> (8 - bit_pos));
return code; return code;
@@ -1033,31 +1035,37 @@ int decodeRepeat(const char *in, int len, char *out, int olen, int ol, int *bit_
if (prev_lines) { if (prev_lines) {
int32_t dict_len = readCount(in, bit_no, len) + NICE_LEN; int32_t dict_len = readCount(in, bit_no, len) + NICE_LEN;
if (dict_len < NICE_LEN) if (dict_len < NICE_LEN)
return ol; return -1;
int32_t dist = readCount(in, bit_no, len); int32_t dist = readCount(in, bit_no, len);
if (dist < 0) if (dist < 0)
return ol; return -1;
int32_t ctx = readCount(in, bit_no, len); int32_t ctx = readCount(in, bit_no, len);
if (ctx < 0) if (ctx < 0)
return ol; return -1;
struct us_lnk_lst *cur_line = prev_lines; struct us_lnk_lst *cur_line = prev_lines;
const int left = olen - ol; const int left = olen - ol;
while (ctx--) while (ctx-- && cur_line)
cur_line = cur_line->previous; cur_line = cur_line->previous;
if (cur_line == NULL)
return -1;
if (left <= 0) return olen + 1; if (left <= 0) return olen + 1;
if (dist >= strlen(cur_line->data))
return -1;
memmove(out + ol, cur_line->data + dist, min_of(left, dict_len)); memmove(out + ol, cur_line->data + dist, min_of(left, dict_len));
if (left < dict_len) return olen + 1; if (left < dict_len) return olen + 1;
ol += dict_len; ol += dict_len;
} else { } else {
int32_t dict_len = readCount(in, bit_no, len) + NICE_LEN; int32_t dict_len = readCount(in, bit_no, len) + NICE_LEN;
if (dict_len < NICE_LEN) if (dict_len < NICE_LEN)
return ol; return -1;
int32_t dist = readCount(in, bit_no, len) + NICE_LEN - 1; int32_t dist = readCount(in, bit_no, len) + NICE_LEN - 1;
if (dist < NICE_LEN - 1) if (dist < NICE_LEN - 1)
return ol; return -1;
const int32_t left = olen - ol; const int32_t left = olen - ol;
//printf("Decode len: %d, dist: %d\n", dict_len - NICE_LEN, dist - NICE_LEN + 1); //printf("Decode len: %d, dist: %d\n", dict_len - NICE_LEN, dist - NICE_LEN + 1);
if (left <= 0) return olen + 1; if (left <= 0) return olen + 1;
if (ol - dist < 0)
return -1;
memmove(out + ol, out + ol - dist, min_of(left, dict_len)); memmove(out + ol, out + ol - dist, min_of(left, dict_len));
if (left < dict_len) return olen + 1; if (left < dict_len) return olen + 1;
ol += dict_len; ol += dict_len;
@@ -1119,7 +1127,10 @@ int unishox2_decompress_lines(const char *in, int len, UNISHOX_API_OUT_AND_LEN(c
continue; continue;
} }
if (h == USX_DICT) { if (h == USX_DICT) {
DEC_OUTPUT_CHARS(olen, ol = decodeRepeat(in, len, out, olen, ol, &bit_no, prev_lines)); int rpt_ret = decodeRepeat(in, len, out, olen, ol, &bit_no, prev_lines);
if (rpt_ret < 0)
return ol; // if we break here it will only break out of switch
DEC_OUTPUT_CHARS(olen, ol = rpt_ret);
h = dstate; h = dstate;
continue; continue;
} }
@@ -1191,7 +1202,10 @@ int unishox2_decompress_lines(const char *in, int len, UNISHOX_API_OUT_AND_LEN(c
} }
} else } else
if (h == USX_DICT) { if (h == USX_DICT) {
DEC_OUTPUT_CHARS(olen, ol = decodeRepeat(in, len, out, olen, ol, &bit_no, prev_lines)); int rpt_ret = decodeRepeat(in, len, out, olen, ol, &bit_no, prev_lines);
if (rpt_ret < 0)
break;
DEC_OUTPUT_CHARS(olen, ol = rpt_ret);
continue; continue;
} else } else
if (h == USX_DELTA) { if (h == USX_DELTA) {
@@ -1208,12 +1222,21 @@ int unishox2_decompress_lines(const char *in, int len, UNISHOX_API_OUT_AND_LEN(c
} }
if (h == USX_NUM && v == 0) { if (h == USX_NUM && v == 0) {
int idx = getStepCodeIdx(in, len, &bit_no, 5); int idx = getStepCodeIdx(in, len, &bit_no, 5);
if (idx == 99)
break;
if (idx == 0) { if (idx == 0) {
idx = getStepCodeIdx(in, len, &bit_no, 4); idx = getStepCodeIdx(in, len, &bit_no, 4);
if (idx >= 5)
break;
int32_t rem = readCount(in, &bit_no, len); int32_t rem = readCount(in, &bit_no, len);
if (rem < 0) if (rem < 0)
break; break;
rem = (int)strlen(usx_templates[idx]) - rem; if (usx_templates[idx] == NULL)
break;
size_t tlen = strlen(usx_templates[idx]);
if (rem > tlen)
break;
rem = tlen - rem;
int eof = 0; int eof = 0;
for (int j = 0; j < rem; j++) { for (int j = 0; j < rem; j++) {
char c_t = usx_templates[idx][j]; char c_t = usx_templates[idx][j];

View File

@@ -21,7 +21,8 @@ typedef enum _AdminMessage_ConfigType {
AdminMessage_ConfigType_POWER_CONFIG = 2, AdminMessage_ConfigType_POWER_CONFIG = 2,
AdminMessage_ConfigType_WIFI_CONFIG = 3, AdminMessage_ConfigType_WIFI_CONFIG = 3,
AdminMessage_ConfigType_DISPLAY_CONFIG = 4, AdminMessage_ConfigType_DISPLAY_CONFIG = 4,
AdminMessage_ConfigType_LORA_CONFIG = 5 AdminMessage_ConfigType_LORA_CONFIG = 5,
AdminMessage_ConfigType_BLUETOOTH_CONFIG = 6
} AdminMessage_ConfigType; } AdminMessage_ConfigType;
typedef enum _AdminMessage_ModuleConfigType { typedef enum _AdminMessage_ModuleConfigType {
@@ -88,30 +89,12 @@ typedef struct _AdminMessage {
bool exit_simulator; bool exit_simulator;
/* Tell the node to reboot in this many seconds (or <0 to cancel reboot) */ /* Tell the node to reboot in this many seconds (or <0 to cancel reboot) */
int32_t reboot_seconds; int32_t reboot_seconds;
/* Get the Canned Message Module message part1 in the response to this message. */ /* Get the Canned Message Module messages in the response to this message. */
bool get_canned_message_module_part1_request; bool get_canned_message_module_messages_request;
/* TODO: REPLACE */ /* Get the Canned Message Module messages in the response to this message. */
char get_canned_message_module_part1_response[201]; char get_canned_message_module_messages_response[201];
/* Get the Canned Message Module message part2 in the response to this message. */ /* Set the Canned Message Module messages text. */
bool get_canned_message_module_part2_request; char set_canned_message_module_messages[201];
/* TODO: REPLACE */
char get_canned_message_module_part2_response[201];
/* Get the Canned Message Module message part3 in the response to this message. */
bool get_canned_message_module_part3_request;
/* TODO: REPLACE */
char get_canned_message_module_part3_response[201];
/* Get the Canned Message Module message part4 in the response to this message. */
bool get_canned_message_module_part4_request;
/* TODO: REPLACE */
char get_canned_message_module_part4_response[201];
/* Set the canned message module part 1 text. */
char set_canned_message_module_part1[201];
/* Set the canned message module part 2 text. */
char set_canned_message_module_part2[201];
/* Set the canned message module part 3 text. */
char set_canned_message_module_part3[201];
/* Set the canned message module part 4 text. */
char set_canned_message_module_part4[201];
/* Tell the node to shutdown in this many seconds (or <0 to cancel shutdown) */ /* Tell the node to shutdown in this many seconds (or <0 to cancel shutdown) */
int32_t shutdown_seconds; int32_t shutdown_seconds;
/* Request the node to send device metadata (firmware, protobuf version, etc) */ /* Request the node to send device metadata (firmware, protobuf version, etc) */
@@ -124,8 +107,8 @@ typedef struct _AdminMessage {
/* Helper constants for enums */ /* Helper constants for enums */
#define _AdminMessage_ConfigType_MIN AdminMessage_ConfigType_DEVICE_CONFIG #define _AdminMessage_ConfigType_MIN AdminMessage_ConfigType_DEVICE_CONFIG
#define _AdminMessage_ConfigType_MAX AdminMessage_ConfigType_LORA_CONFIG #define _AdminMessage_ConfigType_MAX AdminMessage_ConfigType_BLUETOOTH_CONFIG
#define _AdminMessage_ConfigType_ARRAYSIZE ((AdminMessage_ConfigType)(AdminMessage_ConfigType_LORA_CONFIG+1)) #define _AdminMessage_ConfigType_ARRAYSIZE ((AdminMessage_ConfigType)(AdminMessage_ConfigType_BLUETOOTH_CONFIG+1))
#define _AdminMessage_ModuleConfigType_MIN AdminMessage_ModuleConfigType_MQTT_CONFIG #define _AdminMessage_ModuleConfigType_MIN AdminMessage_ModuleConfigType_MQTT_CONFIG
#define _AdminMessage_ModuleConfigType_MAX AdminMessage_ModuleConfigType_CANNEDMSG_CONFIG #define _AdminMessage_ModuleConfigType_MAX AdminMessage_ModuleConfigType_CANNEDMSG_CONFIG
@@ -160,18 +143,9 @@ extern "C" {
#define AdminMessage_confirm_set_radio_tag 33 #define AdminMessage_confirm_set_radio_tag 33
#define AdminMessage_exit_simulator_tag 34 #define AdminMessage_exit_simulator_tag 34
#define AdminMessage_reboot_seconds_tag 35 #define AdminMessage_reboot_seconds_tag 35
#define AdminMessage_get_canned_message_module_part1_request_tag 36 #define AdminMessage_get_canned_message_module_messages_request_tag 36
#define AdminMessage_get_canned_message_module_part1_response_tag 37 #define AdminMessage_get_canned_message_module_messages_response_tag 37
#define AdminMessage_get_canned_message_module_part2_request_tag 38 #define AdminMessage_set_canned_message_module_messages_tag 44
#define AdminMessage_get_canned_message_module_part2_response_tag 39
#define AdminMessage_get_canned_message_module_part3_request_tag 40
#define AdminMessage_get_canned_message_module_part3_response_tag 41
#define AdminMessage_get_canned_message_module_part4_request_tag 42
#define AdminMessage_get_canned_message_module_part4_response_tag 43
#define AdminMessage_set_canned_message_module_part1_tag 44
#define AdminMessage_set_canned_message_module_part2_tag 45
#define AdminMessage_set_canned_message_module_part3_tag 46
#define AdminMessage_set_canned_message_module_part4_tag 47
#define AdminMessage_shutdown_seconds_tag 51 #define AdminMessage_shutdown_seconds_tag 51
#define AdminMessage_get_device_metadata_request_tag 52 #define AdminMessage_get_device_metadata_request_tag 52
#define AdminMessage_get_device_metadata_response_tag 53 #define AdminMessage_get_device_metadata_response_tag 53
@@ -197,18 +171,9 @@ X(a, STATIC, ONEOF, BOOL, (variant,confirm_set_channel,confirm_set_chan
X(a, STATIC, ONEOF, BOOL, (variant,confirm_set_radio,confirm_set_radio), 33) \ X(a, STATIC, ONEOF, BOOL, (variant,confirm_set_radio,confirm_set_radio), 33) \
X(a, STATIC, ONEOF, BOOL, (variant,exit_simulator,exit_simulator), 34) \ X(a, STATIC, ONEOF, BOOL, (variant,exit_simulator,exit_simulator), 34) \
X(a, STATIC, ONEOF, INT32, (variant,reboot_seconds,reboot_seconds), 35) \ X(a, STATIC, ONEOF, INT32, (variant,reboot_seconds,reboot_seconds), 35) \
X(a, STATIC, ONEOF, BOOL, (variant,get_canned_message_module_part1_request,get_canned_message_module_part1_request), 36) \ X(a, STATIC, ONEOF, BOOL, (variant,get_canned_message_module_messages_request,get_canned_message_module_messages_request), 36) \
X(a, STATIC, ONEOF, STRING, (variant,get_canned_message_module_part1_response,get_canned_message_module_part1_response), 37) \ X(a, STATIC, ONEOF, STRING, (variant,get_canned_message_module_messages_response,get_canned_message_module_messages_response), 37) \
X(a, STATIC, ONEOF, BOOL, (variant,get_canned_message_module_part2_request,get_canned_message_module_part2_request), 38) \ X(a, STATIC, ONEOF, STRING, (variant,set_canned_message_module_messages,set_canned_message_module_messages), 44) \
X(a, STATIC, ONEOF, STRING, (variant,get_canned_message_module_part2_response,get_canned_message_module_part2_response), 39) \
X(a, STATIC, ONEOF, BOOL, (variant,get_canned_message_module_part3_request,get_canned_message_module_part3_request), 40) \
X(a, STATIC, ONEOF, STRING, (variant,get_canned_message_module_part3_response,get_canned_message_module_part3_response), 41) \
X(a, STATIC, ONEOF, BOOL, (variant,get_canned_message_module_part4_request,get_canned_message_module_part4_request), 42) \
X(a, STATIC, ONEOF, STRING, (variant,get_canned_message_module_part4_response,get_canned_message_module_part4_response), 43) \
X(a, STATIC, ONEOF, STRING, (variant,set_canned_message_module_part1,set_canned_message_module_part1), 44) \
X(a, STATIC, ONEOF, STRING, (variant,set_canned_message_module_part2,set_canned_message_module_part2), 45) \
X(a, STATIC, ONEOF, STRING, (variant,set_canned_message_module_part3,set_canned_message_module_part3), 46) \
X(a, STATIC, ONEOF, STRING, (variant,set_canned_message_module_part4,set_canned_message_module_part4), 47) \
X(a, STATIC, ONEOF, INT32, (variant,shutdown_seconds,shutdown_seconds), 51) \ X(a, STATIC, ONEOF, INT32, (variant,shutdown_seconds,shutdown_seconds), 51) \
X(a, STATIC, ONEOF, UINT32, (variant,get_device_metadata_request,get_device_metadata_request), 52) \ X(a, STATIC, ONEOF, UINT32, (variant,get_device_metadata_request,get_device_metadata_request), 52) \
X(a, STATIC, ONEOF, MESSAGE, (variant,get_device_metadata_response,get_device_metadata_response), 53) X(a, STATIC, ONEOF, MESSAGE, (variant,get_device_metadata_response,get_device_metadata_response), 53)

View File

@@ -6,7 +6,7 @@
#error Regenerate this file with the current version of nanopb generator. #error Regenerate this file with the current version of nanopb generator.
#endif #endif
PB_BIND(CannedMessageModuleConfig, CannedMessageModuleConfig, 2) PB_BIND(CannedMessageModuleConfig, CannedMessageModuleConfig, AUTO)

View File

@@ -13,13 +13,7 @@
/* Canned message module configuration. */ /* Canned message module configuration. */
typedef struct _CannedMessageModuleConfig { typedef struct _CannedMessageModuleConfig {
/* Predefined messages for canned message module separated by '|' characters. */ /* Predefined messages for canned message module separated by '|' characters. */
char messagesPart1[201]; char messages[201];
/* TODO: REPLACE */
char messagesPart2[201];
/* TODO: REPLACE */
char messagesPart3[201];
/* TODO: REPLACE */
char messagesPart4[201];
} CannedMessageModuleConfig; } CannedMessageModuleConfig;
@@ -28,21 +22,15 @@ extern "C" {
#endif #endif
/* Initializer values for message structs */ /* Initializer values for message structs */
#define CannedMessageModuleConfig_init_default {"", "", "", ""} #define CannedMessageModuleConfig_init_default {""}
#define CannedMessageModuleConfig_init_zero {"", "", "", ""} #define CannedMessageModuleConfig_init_zero {""}
/* Field tags (for use in manual encoding/decoding) */ /* Field tags (for use in manual encoding/decoding) */
#define CannedMessageModuleConfig_messagesPart1_tag 11 #define CannedMessageModuleConfig_messages_tag 1
#define CannedMessageModuleConfig_messagesPart2_tag 12
#define CannedMessageModuleConfig_messagesPart3_tag 13
#define CannedMessageModuleConfig_messagesPart4_tag 14
/* Struct field encoding specification for nanopb */ /* Struct field encoding specification for nanopb */
#define CannedMessageModuleConfig_FIELDLIST(X, a) \ #define CannedMessageModuleConfig_FIELDLIST(X, a) \
X(a, STATIC, SINGULAR, STRING, messagesPart1, 11) \ X(a, STATIC, SINGULAR, STRING, messages, 1)
X(a, STATIC, SINGULAR, STRING, messagesPart2, 12) \
X(a, STATIC, SINGULAR, STRING, messagesPart3, 13) \
X(a, STATIC, SINGULAR, STRING, messagesPart4, 14)
#define CannedMessageModuleConfig_CALLBACK NULL #define CannedMessageModuleConfig_CALLBACK NULL
#define CannedMessageModuleConfig_DEFAULT NULL #define CannedMessageModuleConfig_DEFAULT NULL
@@ -52,7 +40,7 @@ extern const pb_msgdesc_t CannedMessageModuleConfig_msg;
#define CannedMessageModuleConfig_fields &CannedMessageModuleConfig_msg #define CannedMessageModuleConfig_fields &CannedMessageModuleConfig_msg
/* Maximum encoded size of messages (where known) */ /* Maximum encoded size of messages (where known) */
#define CannedMessageModuleConfig_size 812 #define CannedMessageModuleConfig_size 203
#ifdef __cplusplus #ifdef __cplusplus
} /* extern "C" */ } /* extern "C" */

View File

@@ -27,6 +27,10 @@ PB_BIND(Config_DisplayConfig, Config_DisplayConfig, AUTO)
PB_BIND(Config_LoRaConfig, Config_LoRaConfig, 2) PB_BIND(Config_LoRaConfig, Config_LoRaConfig, 2)
PB_BIND(Config_BluetoothConfig, Config_BluetoothConfig, AUTO)

View File

@@ -92,7 +92,19 @@ typedef enum _Config_LoRaConfig_ModemPreset {
Config_LoRaConfig_ModemPreset_ShortFast = 6 Config_LoRaConfig_ModemPreset_ShortFast = 6
} Config_LoRaConfig_ModemPreset; } Config_LoRaConfig_ModemPreset;
typedef enum _Config_BluetoothConfig_PairingMode {
Config_BluetoothConfig_PairingMode_RandomPin = 0,
Config_BluetoothConfig_PairingMode_FixedPin = 1,
Config_BluetoothConfig_PairingMode_NoPin = 2
} Config_BluetoothConfig_PairingMode;
/* Struct definitions */ /* Struct definitions */
typedef struct _Config_BluetoothConfig {
bool enabled;
Config_BluetoothConfig_PairingMode mode;
uint32_t fixed_pin;
} Config_BluetoothConfig;
typedef struct _Config_DeviceConfig { typedef struct _Config_DeviceConfig {
Config_DeviceConfig_Role role; Config_DeviceConfig_Role role;
bool serial_disabled; bool serial_disabled;
@@ -160,6 +172,7 @@ typedef struct _Config {
Config_WiFiConfig wifi; Config_WiFiConfig wifi;
Config_DisplayConfig display; Config_DisplayConfig display;
Config_LoRaConfig lora; Config_LoRaConfig lora;
Config_BluetoothConfig bluetooth;
} payloadVariant; } payloadVariant;
} Config; } Config;
@@ -193,6 +206,10 @@ typedef struct _Config {
#define _Config_LoRaConfig_ModemPreset_MAX Config_LoRaConfig_ModemPreset_ShortFast #define _Config_LoRaConfig_ModemPreset_MAX Config_LoRaConfig_ModemPreset_ShortFast
#define _Config_LoRaConfig_ModemPreset_ARRAYSIZE ((Config_LoRaConfig_ModemPreset)(Config_LoRaConfig_ModemPreset_ShortFast+1)) #define _Config_LoRaConfig_ModemPreset_ARRAYSIZE ((Config_LoRaConfig_ModemPreset)(Config_LoRaConfig_ModemPreset_ShortFast+1))
#define _Config_BluetoothConfig_PairingMode_MIN Config_BluetoothConfig_PairingMode_RandomPin
#define _Config_BluetoothConfig_PairingMode_MAX Config_BluetoothConfig_PairingMode_NoPin
#define _Config_BluetoothConfig_PairingMode_ARRAYSIZE ((Config_BluetoothConfig_PairingMode)(Config_BluetoothConfig_PairingMode_NoPin+1))
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
@@ -206,6 +223,7 @@ extern "C" {
#define Config_WiFiConfig_init_default {0, _Config_WiFiConfig_WiFiMode_MIN, "", ""} #define Config_WiFiConfig_init_default {0, _Config_WiFiConfig_WiFiMode_MIN, "", ""}
#define Config_DisplayConfig_init_default {0, _Config_DisplayConfig_GpsCoordinateFormat_MIN, 0, 0} #define Config_DisplayConfig_init_default {0, _Config_DisplayConfig_GpsCoordinateFormat_MIN, 0, 0}
#define Config_LoRaConfig_init_default {0, _Config_LoRaConfig_ModemPreset_MIN, 0, 0, 0, 0, _Config_LoRaConfig_RegionCode_MIN, 0, 0, 0, {0, 0, 0}} #define Config_LoRaConfig_init_default {0, _Config_LoRaConfig_ModemPreset_MIN, 0, 0, 0, 0, _Config_LoRaConfig_RegionCode_MIN, 0, 0, 0, {0, 0, 0}}
#define Config_BluetoothConfig_init_default {0, _Config_BluetoothConfig_PairingMode_MIN, 0}
#define Config_init_zero {0, {Config_DeviceConfig_init_zero}} #define Config_init_zero {0, {Config_DeviceConfig_init_zero}}
#define Config_DeviceConfig_init_zero {_Config_DeviceConfig_Role_MIN, 0, 0, 0, ""} #define Config_DeviceConfig_init_zero {_Config_DeviceConfig_Role_MIN, 0, 0, 0, ""}
#define Config_PositionConfig_init_zero {0, 0, 0, 0, 0, 0, 0} #define Config_PositionConfig_init_zero {0, 0, 0, 0, 0, 0, 0}
@@ -213,8 +231,12 @@ extern "C" {
#define Config_WiFiConfig_init_zero {0, _Config_WiFiConfig_WiFiMode_MIN, "", ""} #define Config_WiFiConfig_init_zero {0, _Config_WiFiConfig_WiFiMode_MIN, "", ""}
#define Config_DisplayConfig_init_zero {0, _Config_DisplayConfig_GpsCoordinateFormat_MIN, 0, 0} #define Config_DisplayConfig_init_zero {0, _Config_DisplayConfig_GpsCoordinateFormat_MIN, 0, 0}
#define Config_LoRaConfig_init_zero {0, _Config_LoRaConfig_ModemPreset_MIN, 0, 0, 0, 0, _Config_LoRaConfig_RegionCode_MIN, 0, 0, 0, {0, 0, 0}} #define Config_LoRaConfig_init_zero {0, _Config_LoRaConfig_ModemPreset_MIN, 0, 0, 0, 0, _Config_LoRaConfig_RegionCode_MIN, 0, 0, 0, {0, 0, 0}}
#define Config_BluetoothConfig_init_zero {0, _Config_BluetoothConfig_PairingMode_MIN, 0}
/* Field tags (for use in manual encoding/decoding) */ /* Field tags (for use in manual encoding/decoding) */
#define Config_BluetoothConfig_enabled_tag 1
#define Config_BluetoothConfig_mode_tag 2
#define Config_BluetoothConfig_fixed_pin_tag 3
#define Config_DeviceConfig_role_tag 1 #define Config_DeviceConfig_role_tag 1
#define Config_DeviceConfig_serial_disabled_tag 2 #define Config_DeviceConfig_serial_disabled_tag 2
#define Config_DeviceConfig_factory_reset_tag 3 #define Config_DeviceConfig_factory_reset_tag 3
@@ -260,6 +282,7 @@ extern "C" {
#define Config_wifi_tag 4 #define Config_wifi_tag 4
#define Config_display_tag 5 #define Config_display_tag 5
#define Config_lora_tag 6 #define Config_lora_tag 6
#define Config_bluetooth_tag 7
/* Struct field encoding specification for nanopb */ /* Struct field encoding specification for nanopb */
#define Config_FIELDLIST(X, a) \ #define Config_FIELDLIST(X, a) \
@@ -268,7 +291,8 @@ X(a, STATIC, ONEOF, MESSAGE, (payloadVariant,position,payloadVariant.posit
X(a, STATIC, ONEOF, MESSAGE, (payloadVariant,power,payloadVariant.power), 3) \ X(a, STATIC, ONEOF, MESSAGE, (payloadVariant,power,payloadVariant.power), 3) \
X(a, STATIC, ONEOF, MESSAGE, (payloadVariant,wifi,payloadVariant.wifi), 4) \ X(a, STATIC, ONEOF, MESSAGE, (payloadVariant,wifi,payloadVariant.wifi), 4) \
X(a, STATIC, ONEOF, MESSAGE, (payloadVariant,display,payloadVariant.display), 5) \ X(a, STATIC, ONEOF, MESSAGE, (payloadVariant,display,payloadVariant.display), 5) \
X(a, STATIC, ONEOF, MESSAGE, (payloadVariant,lora,payloadVariant.lora), 6) X(a, STATIC, ONEOF, MESSAGE, (payloadVariant,lora,payloadVariant.lora), 6) \
X(a, STATIC, ONEOF, MESSAGE, (payloadVariant,bluetooth,payloadVariant.bluetooth), 7)
#define Config_CALLBACK NULL #define Config_CALLBACK NULL
#define Config_DEFAULT NULL #define Config_DEFAULT NULL
#define Config_payloadVariant_device_MSGTYPE Config_DeviceConfig #define Config_payloadVariant_device_MSGTYPE Config_DeviceConfig
@@ -277,6 +301,7 @@ X(a, STATIC, ONEOF, MESSAGE, (payloadVariant,lora,payloadVariant.lora),
#define Config_payloadVariant_wifi_MSGTYPE Config_WiFiConfig #define Config_payloadVariant_wifi_MSGTYPE Config_WiFiConfig
#define Config_payloadVariant_display_MSGTYPE Config_DisplayConfig #define Config_payloadVariant_display_MSGTYPE Config_DisplayConfig
#define Config_payloadVariant_lora_MSGTYPE Config_LoRaConfig #define Config_payloadVariant_lora_MSGTYPE Config_LoRaConfig
#define Config_payloadVariant_bluetooth_MSGTYPE Config_BluetoothConfig
#define Config_DeviceConfig_FIELDLIST(X, a) \ #define Config_DeviceConfig_FIELDLIST(X, a) \
X(a, STATIC, SINGULAR, UENUM, role, 1) \ X(a, STATIC, SINGULAR, UENUM, role, 1) \
@@ -341,6 +366,13 @@ X(a, STATIC, REPEATED, UINT32, ignore_incoming, 103)
#define Config_LoRaConfig_CALLBACK NULL #define Config_LoRaConfig_CALLBACK NULL
#define Config_LoRaConfig_DEFAULT NULL #define Config_LoRaConfig_DEFAULT NULL
#define Config_BluetoothConfig_FIELDLIST(X, a) \
X(a, STATIC, SINGULAR, BOOL, enabled, 1) \
X(a, STATIC, SINGULAR, UENUM, mode, 2) \
X(a, STATIC, SINGULAR, UINT32, fixed_pin, 3)
#define Config_BluetoothConfig_CALLBACK NULL
#define Config_BluetoothConfig_DEFAULT NULL
extern const pb_msgdesc_t Config_msg; extern const pb_msgdesc_t Config_msg;
extern const pb_msgdesc_t Config_DeviceConfig_msg; extern const pb_msgdesc_t Config_DeviceConfig_msg;
extern const pb_msgdesc_t Config_PositionConfig_msg; extern const pb_msgdesc_t Config_PositionConfig_msg;
@@ -348,6 +380,7 @@ extern const pb_msgdesc_t Config_PowerConfig_msg;
extern const pb_msgdesc_t Config_WiFiConfig_msg; extern const pb_msgdesc_t Config_WiFiConfig_msg;
extern const pb_msgdesc_t Config_DisplayConfig_msg; extern const pb_msgdesc_t Config_DisplayConfig_msg;
extern const pb_msgdesc_t Config_LoRaConfig_msg; extern const pb_msgdesc_t Config_LoRaConfig_msg;
extern const pb_msgdesc_t Config_BluetoothConfig_msg;
/* Defines for backwards compatibility with code written before nanopb-0.4.0 */ /* Defines for backwards compatibility with code written before nanopb-0.4.0 */
#define Config_fields &Config_msg #define Config_fields &Config_msg
@@ -357,8 +390,10 @@ extern const pb_msgdesc_t Config_LoRaConfig_msg;
#define Config_WiFiConfig_fields &Config_WiFiConfig_msg #define Config_WiFiConfig_fields &Config_WiFiConfig_msg
#define Config_DisplayConfig_fields &Config_DisplayConfig_msg #define Config_DisplayConfig_fields &Config_DisplayConfig_msg
#define Config_LoRaConfig_fields &Config_LoRaConfig_msg #define Config_LoRaConfig_fields &Config_LoRaConfig_msg
#define Config_BluetoothConfig_fields &Config_BluetoothConfig_msg
/* Maximum encoded size of messages (where known) */ /* Maximum encoded size of messages (where known) */
#define Config_BluetoothConfig_size 10
#define Config_DeviceConfig_size 42 #define Config_DeviceConfig_size 42
#define Config_DisplayConfig_size 16 #define Config_DisplayConfig_size 16
#define Config_LoRaConfig_size 67 #define Config_LoRaConfig_size 67

View File

@@ -165,7 +165,7 @@ extern const pb_msgdesc_t OEMStore_msg;
/* Maximum encoded size of messages (where known) */ /* Maximum encoded size of messages (where known) */
#define ChannelFile_size 630 #define ChannelFile_size 630
#define DeviceState_size 23994 #define DeviceState_size 22218
#define OEMStore_size 2106 #define OEMStore_size 2106
#ifdef __cplusplus #ifdef __cplusplus

View File

@@ -31,6 +31,9 @@ typedef struct _LocalConfig {
/* The part of the config that is specific to the Lora Radio */ /* The part of the config that is specific to the Lora Radio */
bool has_lora; bool has_lora;
Config_LoRaConfig lora; Config_LoRaConfig lora;
/* The part of the config that is specific to the Bluetooth settings */
bool has_bluetooth;
Config_BluetoothConfig bluetooth;
/* A version integer used to invalidate old save files when we make /* A version integer used to invalidate old save files when we make
incompatible changes This integer is set at build time and is private to incompatible changes This integer is set at build time and is private to
NodeDB.cpp in the device code. */ NodeDB.cpp in the device code. */
@@ -71,9 +74,9 @@ extern "C" {
#endif #endif
/* Initializer values for message structs */ /* Initializer values for message structs */
#define LocalConfig_init_default {false, Config_DeviceConfig_init_default, false, Config_PositionConfig_init_default, false, Config_PowerConfig_init_default, false, Config_WiFiConfig_init_default, false, Config_DisplayConfig_init_default, false, Config_LoRaConfig_init_default, 0} #define LocalConfig_init_default {false, Config_DeviceConfig_init_default, false, Config_PositionConfig_init_default, false, Config_PowerConfig_init_default, false, Config_WiFiConfig_init_default, false, Config_DisplayConfig_init_default, false, Config_LoRaConfig_init_default, false, Config_BluetoothConfig_init_default, 0}
#define LocalModuleConfig_init_default {false, ModuleConfig_MQTTConfig_init_default, false, ModuleConfig_SerialConfig_init_default, false, ModuleConfig_ExternalNotificationConfig_init_default, false, ModuleConfig_StoreForwardConfig_init_default, false, ModuleConfig_RangeTestConfig_init_default, false, ModuleConfig_TelemetryConfig_init_default, false, ModuleConfig_CannedMessageConfig_init_default, 0} #define LocalModuleConfig_init_default {false, ModuleConfig_MQTTConfig_init_default, false, ModuleConfig_SerialConfig_init_default, false, ModuleConfig_ExternalNotificationConfig_init_default, false, ModuleConfig_StoreForwardConfig_init_default, false, ModuleConfig_RangeTestConfig_init_default, false, ModuleConfig_TelemetryConfig_init_default, false, ModuleConfig_CannedMessageConfig_init_default, 0}
#define LocalConfig_init_zero {false, Config_DeviceConfig_init_zero, false, Config_PositionConfig_init_zero, false, Config_PowerConfig_init_zero, false, Config_WiFiConfig_init_zero, false, Config_DisplayConfig_init_zero, false, Config_LoRaConfig_init_zero, 0} #define LocalConfig_init_zero {false, Config_DeviceConfig_init_zero, false, Config_PositionConfig_init_zero, false, Config_PowerConfig_init_zero, false, Config_WiFiConfig_init_zero, false, Config_DisplayConfig_init_zero, false, Config_LoRaConfig_init_zero, false, Config_BluetoothConfig_init_zero, 0}
#define LocalModuleConfig_init_zero {false, ModuleConfig_MQTTConfig_init_zero, false, ModuleConfig_SerialConfig_init_zero, false, ModuleConfig_ExternalNotificationConfig_init_zero, false, ModuleConfig_StoreForwardConfig_init_zero, false, ModuleConfig_RangeTestConfig_init_zero, false, ModuleConfig_TelemetryConfig_init_zero, false, ModuleConfig_CannedMessageConfig_init_zero, 0} #define LocalModuleConfig_init_zero {false, ModuleConfig_MQTTConfig_init_zero, false, ModuleConfig_SerialConfig_init_zero, false, ModuleConfig_ExternalNotificationConfig_init_zero, false, ModuleConfig_StoreForwardConfig_init_zero, false, ModuleConfig_RangeTestConfig_init_zero, false, ModuleConfig_TelemetryConfig_init_zero, false, ModuleConfig_CannedMessageConfig_init_zero, 0}
/* Field tags (for use in manual encoding/decoding) */ /* Field tags (for use in manual encoding/decoding) */
@@ -83,7 +86,8 @@ extern "C" {
#define LocalConfig_wifi_tag 4 #define LocalConfig_wifi_tag 4
#define LocalConfig_display_tag 5 #define LocalConfig_display_tag 5
#define LocalConfig_lora_tag 6 #define LocalConfig_lora_tag 6
#define LocalConfig_version_tag 7 #define LocalConfig_bluetooth_tag 7
#define LocalConfig_version_tag 8
#define LocalModuleConfig_mqtt_tag 1 #define LocalModuleConfig_mqtt_tag 1
#define LocalModuleConfig_serial_tag 2 #define LocalModuleConfig_serial_tag 2
#define LocalModuleConfig_external_notification_tag 3 #define LocalModuleConfig_external_notification_tag 3
@@ -101,7 +105,8 @@ X(a, STATIC, OPTIONAL, MESSAGE, power, 3) \
X(a, STATIC, OPTIONAL, MESSAGE, wifi, 4) \ X(a, STATIC, OPTIONAL, MESSAGE, wifi, 4) \
X(a, STATIC, OPTIONAL, MESSAGE, display, 5) \ X(a, STATIC, OPTIONAL, MESSAGE, display, 5) \
X(a, STATIC, OPTIONAL, MESSAGE, lora, 6) \ X(a, STATIC, OPTIONAL, MESSAGE, lora, 6) \
X(a, STATIC, SINGULAR, UINT32, version, 7) X(a, STATIC, OPTIONAL, MESSAGE, bluetooth, 7) \
X(a, STATIC, SINGULAR, UINT32, version, 8)
#define LocalConfig_CALLBACK NULL #define LocalConfig_CALLBACK NULL
#define LocalConfig_DEFAULT NULL #define LocalConfig_DEFAULT NULL
#define LocalConfig_device_MSGTYPE Config_DeviceConfig #define LocalConfig_device_MSGTYPE Config_DeviceConfig
@@ -110,6 +115,7 @@ X(a, STATIC, SINGULAR, UINT32, version, 7)
#define LocalConfig_wifi_MSGTYPE Config_WiFiConfig #define LocalConfig_wifi_MSGTYPE Config_WiFiConfig
#define LocalConfig_display_MSGTYPE Config_DisplayConfig #define LocalConfig_display_MSGTYPE Config_DisplayConfig
#define LocalConfig_lora_MSGTYPE Config_LoRaConfig #define LocalConfig_lora_MSGTYPE Config_LoRaConfig
#define LocalConfig_bluetooth_MSGTYPE Config_BluetoothConfig
#define LocalModuleConfig_FIELDLIST(X, a) \ #define LocalModuleConfig_FIELDLIST(X, a) \
X(a, STATIC, OPTIONAL, MESSAGE, mqtt, 1) \ X(a, STATIC, OPTIONAL, MESSAGE, mqtt, 1) \
@@ -138,8 +144,8 @@ extern const pb_msgdesc_t LocalModuleConfig_msg;
#define LocalModuleConfig_fields &LocalModuleConfig_msg #define LocalModuleConfig_fields &LocalModuleConfig_msg
/* Maximum encoded size of messages (where known) */ /* Maximum encoded size of messages (where known) */
#define LocalConfig_size 321 #define LocalConfig_size 333
#define LocalModuleConfig_size 268 #define LocalModuleConfig_size 270
#ifdef __cplusplus #ifdef __cplusplus
} /* extern "C" */ } /* extern "C" */

View File

@@ -21,7 +21,7 @@ PB_BIND(Routing, Routing, AUTO)
PB_BIND(Data, Data, 2) PB_BIND(Data, Data, 2)
PB_BIND(Location, Location, AUTO) PB_BIND(Waypoint, Waypoint, AUTO)
PB_BIND(MeshPacket, MeshPacket, 2) PB_BIND(MeshPacket, MeshPacket, 2)

View File

@@ -245,24 +245,38 @@ typedef struct _Compressed {
Compressed_data_t data; Compressed_data_t data;
} Compressed; } Compressed;
/* Location of a waypoint to associate with a message */ typedef PB_BYTES_ARRAY_T(237) Data_payload_t;
typedef struct _Location { /* (Formerly called SubPacket)
/* Id of the location */ The payload portion fo a packet, this is the actual bytes that are sent
uint32_t id; inside a radio packet (because from/to are broken out by the comms library) */
/* latitude_i */ typedef struct _Data {
int32_t latitude_i; /* Formerly named typ and of type Type */
/* longitude_i */ PortNum portnum;
int32_t longitude_i; /* TODO: REPLACE */
/* Time the location is to expire (epoch) */ Data_payload_t payload;
uint32_t expire; /* Not normally used, but for testing a sender can request that recipient
/* If true, only allow the original sender to update the location. */ responds in kind (i.e. if it received a position, it should unicast back it's position).
bool locked; Note: that if you set this on a broadcast you will receive many replies. */
/* Name of the location - max 30 chars */ bool want_response;
char name[30]; /* The address of the destination node.
/* * This field is is filled in by the mesh radio device software, application
Description of the location - max 100 chars */ layer software should never need it.
char description[100]; RouteDiscovery messages _must_ populate this.
} Location; Other message types might need to if they are doing multihop routing. */
uint32_t dest;
/* The address of the original sender for this message.
This field should _only_ be populated for reliable multihop packets (to keep
packets small). */
uint32_t source;
/* Only used in routing or response messages.
Indicates the original message ID that this message is reporting failure on. (formerly called original_id) */
uint32_t request_id;
/* If set, this message is intened to be a reply to a previously sent message with the defined id. */
uint32_t reply_id;
/* Defaults to false. If true, then what is in the payload should be treated as an emoji like giving
a message a heart or poop emoji. */
uint32_t emoji;
} Data;
/* Debug output from the device. /* Debug output from the device.
To minimize the size of records inside the device code, if a time/source/level is not set To minimize the size of records inside the device code, if a time/source/level is not set
@@ -459,104 +473,26 @@ typedef struct _User {
If this user is a licensed operator, set this flag. If this user is a licensed operator, set this flag.
Also, "long_name" should be their licence number. */ Also, "long_name" should be their licence number. */
bool is_licensed; bool is_licensed;
/* Transmit power at antenna connector, in decibel-milliwatt
An optional self-reported value useful in network planning, discovery
and positioning - along with ant_gain_dbi and ant_azimuth below */
uint32_t tx_power_dbm;
/* Antenna gain (applicable to both Tx and Rx), in decibel-isotropic */
uint32_t ant_gain_dbi;
/* Directional antenna true azimuth *if applicable*, in degrees (0-360)
Only applicable in case of stationary nodes with a directional antenna
Zero = not applicable (mobile or omni) or not specified
(use a value of 360 to indicate an antenna azimuth of zero degrees) */
uint32_t ant_azimuth;
} User; } User;
typedef PB_BYTES_ARRAY_T(237) Data_payload_t; /* Waypoint message, used to share arbitrary locations across the mesh */
/* (Formerly called SubPacket) typedef struct _Waypoint {
The payload portion fo a packet, this is the actual bytes that are sent /* Id of the waypoint */
inside a radio packet (because from/to are broken out by the comms library) */ uint32_t id;
typedef struct _Data { /* latitude_i */
/* Formerly named typ and of type Type */ int32_t latitude_i;
PortNum portnum; /* longitude_i */
/* TODO: REPLACE */ int32_t longitude_i;
Data_payload_t payload; /* Time the waypoint is to expire (epoch) */
/* Not normally used, but for testing a sender can request that recipient uint32_t expire;
responds in kind (i.e. if it received a position, it should unicast back it's position). /* If true, only allow the original sender to update the waypoint. */
Note: that if you set this on a broadcast you will receive many replies. */ bool locked;
bool want_response; /* Name of the waypoint - max 30 chars */
/* The address of the destination node. char name[30];
This field is is filled in by the mesh radio device software, application /* *
layer software should never need it. Description of the waypoint - max 100 chars */
RouteDiscovery messages _must_ populate this. char description[100];
Other message types might need to if they are doing multihop routing. */ } Waypoint;
uint32_t dest;
/* The address of the original sender for this message.
This field should _only_ be populated for reliable multihop packets (to keep
packets small). */
uint32_t source;
/* Only used in routing or response messages.
Indicates the original message ID that this message is reporting failure on. (formerly called original_id) */
uint32_t request_id;
/* If set, this message is intened to be a reply to a previously sent message with the defined id. */
uint32_t reply_id;
/* Defaults to false. If true, then what is in the payload should be treated as an emoji like giving
a message a heart or poop emoji. */
uint32_t emoji;
/* Location structure */
bool has_location;
Location location;
} Data;
/* The bluetooth to device link:
Old BTLE protocol docs from TODO, merge in above and make real docs...
use protocol buffers, and NanoPB
messages from device to phone:
POSITION_UPDATE (..., time)
TEXT_RECEIVED(from, text, time)
OPAQUE_RECEIVED(from, payload, time) (for signal messages or other applications)
messages from phone to device:
SET_MYID(id, human readable long, human readable short) (send down the unique ID
string used for this node, a human readable string shown for that id, and a very
short human readable string suitable for oled screen) SEND_OPAQUE(dest, payload)
(for signal messages or other applications) SEND_TEXT(dest, text) Get all
nodes() (returns list of nodes, with full info, last time seen, loc, battery
level etc) SET_CONFIG (switches device to a new set of radio params and
preshared key, drops all existing nodes, force our node to rejoin this new group)
Full information about a node on the mesh */
typedef struct _NodeInfo {
/* The node number */
uint32_t num;
/* The user info for this node */
bool has_user;
User user;
/* This position data. Note: before 1.2.14 we would also store the last time we've heard from this node in position.time, that is no longer true.
Position.time now indicates the last time we received a POSITION from that node. */
bool has_position;
Position position;
/* Returns the Signal-to-noise ratio (SNR) of the last received message,
as measured by the receiver. Return SNR of the last received message in dB */
float snr;
/* Set to indicate the last time we received a packet from this node */
uint32_t last_heard;
/* The latest device metrics for the node. */
bool has_device_metrics;
DeviceMetrics device_metrics;
} NodeInfo;
/* A Routing control Data packet handled by the routing module */
typedef struct _Routing {
pb_size_t which_variant;
union {
/* A route request going from the requester */
RouteDiscovery route_request;
/* A route reply */
RouteDiscovery route_reply;
/* A failure in delivering a message (usually used for routing control messages, but might be provided
in addition to ack.fail_id to provide details on the type of failure). */
Routing_Error error_reason;
};
} Routing;
typedef PB_BYTES_ARRAY_T(256) MeshPacket_encrypted_t; typedef PB_BYTES_ARRAY_T(256) MeshPacket_encrypted_t;
/* A packet envelope sent/received over the mesh /* A packet envelope sent/received over the mesh
@@ -630,6 +566,56 @@ typedef struct _MeshPacket {
MeshPacket_Delayed delayed; MeshPacket_Delayed delayed;
} MeshPacket; } MeshPacket;
/* The bluetooth to device link:
Old BTLE protocol docs from TODO, merge in above and make real docs...
use protocol buffers, and NanoPB
messages from device to phone:
POSITION_UPDATE (..., time)
TEXT_RECEIVED(from, text, time)
OPAQUE_RECEIVED(from, payload, time) (for signal messages or other applications)
messages from phone to device:
SET_MYID(id, human readable long, human readable short) (send down the unique ID
string used for this node, a human readable string shown for that id, and a very
short human readable string suitable for oled screen) SEND_OPAQUE(dest, payload)
(for signal messages or other applications) SEND_TEXT(dest, text) Get all
nodes() (returns list of nodes, with full info, last time seen, loc, battery
level etc) SET_CONFIG (switches device to a new set of radio params and
preshared key, drops all existing nodes, force our node to rejoin this new group)
Full information about a node on the mesh */
typedef struct _NodeInfo {
/* The node number */
uint32_t num;
/* The user info for this node */
bool has_user;
User user;
/* This position data. Note: before 1.2.14 we would also store the last time we've heard from this node in position.time, that is no longer true.
Position.time now indicates the last time we received a POSITION from that node. */
bool has_position;
Position position;
/* Returns the Signal-to-noise ratio (SNR) of the last received message,
as measured by the receiver. Return SNR of the last received message in dB */
float snr;
/* Set to indicate the last time we received a packet from this node */
uint32_t last_heard;
/* The latest device metrics for the node. */
bool has_device_metrics;
DeviceMetrics device_metrics;
} NodeInfo;
/* A Routing control Data packet handled by the routing module */
typedef struct _Routing {
pb_size_t which_variant;
union {
/* A route request going from the requester */
RouteDiscovery route_request;
/* A route reply */
RouteDiscovery route_reply;
/* A failure in delivering a message (usually used for routing control messages, but might be provided
in addition to ack.fail_id to provide details on the type of failure). */
Routing_Error error_reason;
};
} Routing;
/* Packets from the radio to the phone will appear on the fromRadio characteristic. /* Packets from the radio to the phone will appear on the fromRadio characteristic.
It will support READ and NOTIFY. When a new packet arrives the device will BLE notify? It will support READ and NOTIFY. When a new packet arrives the device will BLE notify?
It will sit in that descriptor until consumed by the phone, It will sit in that descriptor until consumed by the phone,
@@ -738,11 +724,11 @@ extern "C" {
/* Initializer values for message structs */ /* Initializer values for message structs */
#define Position_init_default {0, 0, 0, 0, _Position_LocSource_MIN, _Position_AltSource_MIN, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} #define Position_init_default {0, 0, 0, 0, _Position_LocSource_MIN, _Position_AltSource_MIN, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
#define User_init_default {"", "", "", {0}, _HardwareModel_MIN, 0, 0, 0, 0} #define User_init_default {"", "", "", {0}, _HardwareModel_MIN, 0}
#define RouteDiscovery_init_default {0, {0, 0, 0, 0, 0, 0, 0, 0}} #define RouteDiscovery_init_default {0, {0, 0, 0, 0, 0, 0, 0, 0}}
#define Routing_init_default {0, {RouteDiscovery_init_default}} #define Routing_init_default {0, {RouteDiscovery_init_default}}
#define Data_init_default {_PortNum_MIN, {0, {0}}, 0, 0, 0, 0, 0, 0, false, Location_init_default} #define Data_init_default {_PortNum_MIN, {0, {0}}, 0, 0, 0, 0, 0, 0}
#define Location_init_default {0, 0, 0, 0, 0, "", ""} #define Waypoint_init_default {0, 0, 0, 0, 0, "", ""}
#define MeshPacket_init_default {0, 0, 0, 0, {Data_init_default}, 0, 0, 0, 0, 0, _MeshPacket_Priority_MIN, 0, _MeshPacket_Delayed_MIN} #define MeshPacket_init_default {0, 0, 0, 0, {Data_init_default}, 0, 0, 0, 0, 0, _MeshPacket_Priority_MIN, 0, _MeshPacket_Delayed_MIN}
#define NodeInfo_init_default {0, false, User_init_default, false, Position_init_default, 0, 0, false, DeviceMetrics_init_default} #define NodeInfo_init_default {0, false, User_init_default, false, Position_init_default, 0, 0, false, DeviceMetrics_init_default}
#define MyNodeInfo_init_default {0, 0, "", _CriticalErrorCode_MIN, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0, 0, 0, 0, 0, 0}, 0, {0, 0, 0, 0, 0, 0, 0, 0}, 0, 0, 0} #define MyNodeInfo_init_default {0, 0, "", _CriticalErrorCode_MIN, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0, 0, 0, 0, 0, 0}, 0, {0, 0, 0, 0, 0, 0, 0, 0}, 0, 0, 0}
@@ -752,11 +738,11 @@ extern "C" {
#define ToRadio_PeerInfo_init_default {0, 0} #define ToRadio_PeerInfo_init_default {0, 0}
#define Compressed_init_default {_PortNum_MIN, {0, {0}}} #define Compressed_init_default {_PortNum_MIN, {0, {0}}}
#define Position_init_zero {0, 0, 0, 0, _Position_LocSource_MIN, _Position_AltSource_MIN, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} #define Position_init_zero {0, 0, 0, 0, _Position_LocSource_MIN, _Position_AltSource_MIN, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
#define User_init_zero {"", "", "", {0}, _HardwareModel_MIN, 0, 0, 0, 0} #define User_init_zero {"", "", "", {0}, _HardwareModel_MIN, 0}
#define RouteDiscovery_init_zero {0, {0, 0, 0, 0, 0, 0, 0, 0}} #define RouteDiscovery_init_zero {0, {0, 0, 0, 0, 0, 0, 0, 0}}
#define Routing_init_zero {0, {RouteDiscovery_init_zero}} #define Routing_init_zero {0, {RouteDiscovery_init_zero}}
#define Data_init_zero {_PortNum_MIN, {0, {0}}, 0, 0, 0, 0, 0, 0, false, Location_init_zero} #define Data_init_zero {_PortNum_MIN, {0, {0}}, 0, 0, 0, 0, 0, 0}
#define Location_init_zero {0, 0, 0, 0, 0, "", ""} #define Waypoint_init_zero {0, 0, 0, 0, 0, "", ""}
#define MeshPacket_init_zero {0, 0, 0, 0, {Data_init_zero}, 0, 0, 0, 0, 0, _MeshPacket_Priority_MIN, 0, _MeshPacket_Delayed_MIN} #define MeshPacket_init_zero {0, 0, 0, 0, {Data_init_zero}, 0, 0, 0, 0, 0, _MeshPacket_Priority_MIN, 0, _MeshPacket_Delayed_MIN}
#define NodeInfo_init_zero {0, false, User_init_zero, false, Position_init_zero, 0, 0, false, DeviceMetrics_init_zero} #define NodeInfo_init_zero {0, false, User_init_zero, false, Position_init_zero, 0, 0, false, DeviceMetrics_init_zero}
#define MyNodeInfo_init_zero {0, 0, "", _CriticalErrorCode_MIN, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0, 0, 0, 0, 0, 0}, 0, {0, 0, 0, 0, 0, 0, 0, 0}, 0, 0, 0} #define MyNodeInfo_init_zero {0, 0, "", _CriticalErrorCode_MIN, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0, 0, 0, 0, 0, 0}, 0, {0, 0, 0, 0, 0, 0, 0, 0}, 0, 0, 0}
@@ -769,13 +755,14 @@ extern "C" {
/* Field tags (for use in manual encoding/decoding) */ /* Field tags (for use in manual encoding/decoding) */
#define Compressed_portnum_tag 1 #define Compressed_portnum_tag 1
#define Compressed_data_tag 2 #define Compressed_data_tag 2
#define Location_id_tag 1 #define Data_portnum_tag 1
#define Location_latitude_i_tag 2 #define Data_payload_tag 2
#define Location_longitude_i_tag 3 #define Data_want_response_tag 3
#define Location_expire_tag 4 #define Data_dest_tag 4
#define Location_locked_tag 5 #define Data_source_tag 5
#define Location_name_tag 6 #define Data_request_id_tag 6
#define Location_description_tag 7 #define Data_reply_id_tag 7
#define Data_emoji_tag 8
#define LogRecord_message_tag 1 #define LogRecord_message_tag 1
#define LogRecord_time_tag 2 #define LogRecord_time_tag 2
#define LogRecord_source_tag 3 #define LogRecord_source_tag 3
@@ -827,27 +814,13 @@ extern "C" {
#define User_macaddr_tag 4 #define User_macaddr_tag 4
#define User_hw_model_tag 6 #define User_hw_model_tag 6
#define User_is_licensed_tag 7 #define User_is_licensed_tag 7
#define User_tx_power_dbm_tag 10 #define Waypoint_id_tag 1
#define User_ant_gain_dbi_tag 11 #define Waypoint_latitude_i_tag 2
#define User_ant_azimuth_tag 12 #define Waypoint_longitude_i_tag 3
#define Data_portnum_tag 1 #define Waypoint_expire_tag 4
#define Data_payload_tag 2 #define Waypoint_locked_tag 5
#define Data_want_response_tag 3 #define Waypoint_name_tag 6
#define Data_dest_tag 4 #define Waypoint_description_tag 7
#define Data_source_tag 5
#define Data_request_id_tag 6
#define Data_reply_id_tag 7
#define Data_emoji_tag 8
#define Data_location_tag 9
#define NodeInfo_num_tag 1
#define NodeInfo_user_tag 2
#define NodeInfo_position_tag 3
#define NodeInfo_snr_tag 4
#define NodeInfo_last_heard_tag 5
#define NodeInfo_device_metrics_tag 6
#define Routing_route_request_tag 1
#define Routing_route_reply_tag 2
#define Routing_error_reason_tag 3
#define MeshPacket_from_tag 1 #define MeshPacket_from_tag 1
#define MeshPacket_to_tag 2 #define MeshPacket_to_tag 2
#define MeshPacket_channel_tag 3 #define MeshPacket_channel_tag 3
@@ -861,6 +834,15 @@ extern "C" {
#define MeshPacket_priority_tag 12 #define MeshPacket_priority_tag 12
#define MeshPacket_rx_rssi_tag 13 #define MeshPacket_rx_rssi_tag 13
#define MeshPacket_delayed_tag 15 #define MeshPacket_delayed_tag 15
#define NodeInfo_num_tag 1
#define NodeInfo_user_tag 2
#define NodeInfo_position_tag 3
#define NodeInfo_snr_tag 4
#define NodeInfo_last_heard_tag 5
#define NodeInfo_device_metrics_tag 6
#define Routing_route_request_tag 1
#define Routing_route_reply_tag 2
#define Routing_error_reason_tag 3
#define FromRadio_id_tag 1 #define FromRadio_id_tag 1
#define FromRadio_my_info_tag 3 #define FromRadio_my_info_tag 3
#define FromRadio_node_info_tag 4 #define FromRadio_node_info_tag 4
@@ -908,10 +890,7 @@ X(a, STATIC, SINGULAR, STRING, long_name, 2) \
X(a, STATIC, SINGULAR, STRING, short_name, 3) \ X(a, STATIC, SINGULAR, STRING, short_name, 3) \
X(a, STATIC, SINGULAR, FIXED_LENGTH_BYTES, macaddr, 4) \ X(a, STATIC, SINGULAR, FIXED_LENGTH_BYTES, macaddr, 4) \
X(a, STATIC, SINGULAR, UENUM, hw_model, 6) \ X(a, STATIC, SINGULAR, UENUM, hw_model, 6) \
X(a, STATIC, SINGULAR, BOOL, is_licensed, 7) \ X(a, STATIC, SINGULAR, BOOL, is_licensed, 7)
X(a, STATIC, SINGULAR, UINT32, tx_power_dbm, 10) \
X(a, STATIC, SINGULAR, UINT32, ant_gain_dbi, 11) \
X(a, STATIC, SINGULAR, UINT32, ant_azimuth, 12)
#define User_CALLBACK NULL #define User_CALLBACK NULL
#define User_DEFAULT NULL #define User_DEFAULT NULL
@@ -937,13 +916,11 @@ X(a, STATIC, SINGULAR, FIXED32, dest, 4) \
X(a, STATIC, SINGULAR, FIXED32, source, 5) \ X(a, STATIC, SINGULAR, FIXED32, source, 5) \
X(a, STATIC, SINGULAR, FIXED32, request_id, 6) \ X(a, STATIC, SINGULAR, FIXED32, request_id, 6) \
X(a, STATIC, SINGULAR, FIXED32, reply_id, 7) \ X(a, STATIC, SINGULAR, FIXED32, reply_id, 7) \
X(a, STATIC, SINGULAR, FIXED32, emoji, 8) \ X(a, STATIC, SINGULAR, FIXED32, emoji, 8)
X(a, STATIC, OPTIONAL, MESSAGE, location, 9)
#define Data_CALLBACK NULL #define Data_CALLBACK NULL
#define Data_DEFAULT NULL #define Data_DEFAULT NULL
#define Data_location_MSGTYPE Location
#define Location_FIELDLIST(X, a) \ #define Waypoint_FIELDLIST(X, a) \
X(a, STATIC, SINGULAR, UINT32, id, 1) \ X(a, STATIC, SINGULAR, UINT32, id, 1) \
X(a, STATIC, SINGULAR, SFIXED32, latitude_i, 2) \ X(a, STATIC, SINGULAR, SFIXED32, latitude_i, 2) \
X(a, STATIC, SINGULAR, SFIXED32, longitude_i, 3) \ X(a, STATIC, SINGULAR, SFIXED32, longitude_i, 3) \
@@ -951,8 +928,8 @@ X(a, STATIC, SINGULAR, UINT32, expire, 4) \
X(a, STATIC, SINGULAR, BOOL, locked, 5) \ X(a, STATIC, SINGULAR, BOOL, locked, 5) \
X(a, STATIC, SINGULAR, STRING, name, 6) \ X(a, STATIC, SINGULAR, STRING, name, 6) \
X(a, STATIC, SINGULAR, STRING, description, 7) X(a, STATIC, SINGULAR, STRING, description, 7)
#define Location_CALLBACK NULL #define Waypoint_CALLBACK NULL
#define Location_DEFAULT NULL #define Waypoint_DEFAULT NULL
#define MeshPacket_FIELDLIST(X, a) \ #define MeshPacket_FIELDLIST(X, a) \
X(a, STATIC, SINGULAR, FIXED32, from, 1) \ X(a, STATIC, SINGULAR, FIXED32, from, 1) \
@@ -1059,7 +1036,7 @@ extern const pb_msgdesc_t User_msg;
extern const pb_msgdesc_t RouteDiscovery_msg; extern const pb_msgdesc_t RouteDiscovery_msg;
extern const pb_msgdesc_t Routing_msg; extern const pb_msgdesc_t Routing_msg;
extern const pb_msgdesc_t Data_msg; extern const pb_msgdesc_t Data_msg;
extern const pb_msgdesc_t Location_msg; extern const pb_msgdesc_t Waypoint_msg;
extern const pb_msgdesc_t MeshPacket_msg; extern const pb_msgdesc_t MeshPacket_msg;
extern const pb_msgdesc_t NodeInfo_msg; extern const pb_msgdesc_t NodeInfo_msg;
extern const pb_msgdesc_t MyNodeInfo_msg; extern const pb_msgdesc_t MyNodeInfo_msg;
@@ -1075,7 +1052,7 @@ extern const pb_msgdesc_t Compressed_msg;
#define RouteDiscovery_fields &RouteDiscovery_msg #define RouteDiscovery_fields &RouteDiscovery_msg
#define Routing_fields &Routing_msg #define Routing_fields &Routing_msg
#define Data_fields &Data_msg #define Data_fields &Data_msg
#define Location_fields &Location_msg #define Waypoint_fields &Waypoint_msg
#define MeshPacket_fields &MeshPacket_msg #define MeshPacket_fields &MeshPacket_msg
#define NodeInfo_fields &NodeInfo_msg #define NodeInfo_fields &NodeInfo_msg
#define MyNodeInfo_fields &MyNodeInfo_msg #define MyNodeInfo_fields &MyNodeInfo_msg
@@ -1087,19 +1064,19 @@ extern const pb_msgdesc_t Compressed_msg;
/* Maximum encoded size of messages (where known) */ /* Maximum encoded size of messages (where known) */
#define Compressed_size 243 #define Compressed_size 243
#define Data_size 429 #define Data_size 270
#define FromRadio_size 489 #define FromRadio_size 330
#define Location_size 156
#define LogRecord_size 81 #define LogRecord_size 81
#define MeshPacket_size 480 #define MeshPacket_size 321
#define MyNodeInfo_size 197 #define MyNodeInfo_size 197
#define NodeInfo_size 281 #define NodeInfo_size 263
#define Position_size 142 #define Position_size 142
#define RouteDiscovery_size 40 #define RouteDiscovery_size 40
#define Routing_size 42 #define Routing_size 42
#define ToRadio_PeerInfo_size 8 #define ToRadio_PeerInfo_size 8
#define ToRadio_size 483 #define ToRadio_size 324
#define User_size 95 #define User_size 77
#define Waypoint_size 156
#ifdef __cplusplus #ifdef __cplusplus
} /* extern "C" */ } /* extern "C" */

View File

@@ -4,7 +4,6 @@
#ifndef PB_MODULE_CONFIG_PB_H_INCLUDED #ifndef PB_MODULE_CONFIG_PB_H_INCLUDED
#define PB_MODULE_CONFIG_PB_H_INCLUDED #define PB_MODULE_CONFIG_PB_H_INCLUDED
#include <pb.h> #include <pb.h>
#include "telemetry.pb.h"
#if PB_PROTO_HEADER_VERSION != 40 #if PB_PROTO_HEADER_VERSION != 40
#error Regenerate this file with the current version of nanopb generator. #error Regenerate this file with the current version of nanopb generator.
@@ -72,11 +71,12 @@ typedef struct _ModuleConfig_ExternalNotificationConfig {
} ModuleConfig_ExternalNotificationConfig; } ModuleConfig_ExternalNotificationConfig;
typedef struct _ModuleConfig_MQTTConfig { typedef struct _ModuleConfig_MQTTConfig {
bool disabled; bool enabled;
char address[32]; char address[32];
char username[32]; char username[32];
char password[32]; char password[32];
bool encryption_enabled; bool encryption_enabled;
bool json_enabled;
} ModuleConfig_MQTTConfig; } ModuleConfig_MQTTConfig;
typedef struct _ModuleConfig_RangeTestConfig { typedef struct _ModuleConfig_RangeTestConfig {
@@ -153,7 +153,7 @@ extern "C" {
/* Initializer values for message structs */ /* Initializer values for message structs */
#define ModuleConfig_init_default {0, {ModuleConfig_MQTTConfig_init_default}} #define ModuleConfig_init_default {0, {ModuleConfig_MQTTConfig_init_default}}
#define ModuleConfig_MQTTConfig_init_default {0, "", "", "", 0} #define ModuleConfig_MQTTConfig_init_default {0, "", "", "", 0, 0}
#define ModuleConfig_SerialConfig_init_default {0, 0, 0, 0, _ModuleConfig_SerialConfig_Serial_Baud_MIN, 0, _ModuleConfig_SerialConfig_Serial_Mode_MIN} #define ModuleConfig_SerialConfig_init_default {0, 0, 0, 0, _ModuleConfig_SerialConfig_Serial_Baud_MIN, 0, _ModuleConfig_SerialConfig_Serial_Mode_MIN}
#define ModuleConfig_ExternalNotificationConfig_init_default {0, 0, 0, 0, 0, 0} #define ModuleConfig_ExternalNotificationConfig_init_default {0, 0, 0, 0, 0, 0}
#define ModuleConfig_StoreForwardConfig_init_default {0, 0, 0, 0, 0} #define ModuleConfig_StoreForwardConfig_init_default {0, 0, 0, 0, 0}
@@ -161,7 +161,7 @@ extern "C" {
#define ModuleConfig_TelemetryConfig_init_default {0, 0, 0, 0, 0} #define ModuleConfig_TelemetryConfig_init_default {0, 0, 0, 0, 0}
#define ModuleConfig_CannedMessageConfig_init_default {0, 0, 0, 0, _ModuleConfig_CannedMessageConfig_InputEventChar_MIN, _ModuleConfig_CannedMessageConfig_InputEventChar_MIN, _ModuleConfig_CannedMessageConfig_InputEventChar_MIN, 0, 0, "", 0} #define ModuleConfig_CannedMessageConfig_init_default {0, 0, 0, 0, _ModuleConfig_CannedMessageConfig_InputEventChar_MIN, _ModuleConfig_CannedMessageConfig_InputEventChar_MIN, _ModuleConfig_CannedMessageConfig_InputEventChar_MIN, 0, 0, "", 0}
#define ModuleConfig_init_zero {0, {ModuleConfig_MQTTConfig_init_zero}} #define ModuleConfig_init_zero {0, {ModuleConfig_MQTTConfig_init_zero}}
#define ModuleConfig_MQTTConfig_init_zero {0, "", "", "", 0} #define ModuleConfig_MQTTConfig_init_zero {0, "", "", "", 0, 0}
#define ModuleConfig_SerialConfig_init_zero {0, 0, 0, 0, _ModuleConfig_SerialConfig_Serial_Baud_MIN, 0, _ModuleConfig_SerialConfig_Serial_Mode_MIN} #define ModuleConfig_SerialConfig_init_zero {0, 0, 0, 0, _ModuleConfig_SerialConfig_Serial_Baud_MIN, 0, _ModuleConfig_SerialConfig_Serial_Mode_MIN}
#define ModuleConfig_ExternalNotificationConfig_init_zero {0, 0, 0, 0, 0, 0} #define ModuleConfig_ExternalNotificationConfig_init_zero {0, 0, 0, 0, 0, 0}
#define ModuleConfig_StoreForwardConfig_init_zero {0, 0, 0, 0, 0} #define ModuleConfig_StoreForwardConfig_init_zero {0, 0, 0, 0, 0}
@@ -187,11 +187,12 @@ extern "C" {
#define ModuleConfig_ExternalNotificationConfig_active_tag 4 #define ModuleConfig_ExternalNotificationConfig_active_tag 4
#define ModuleConfig_ExternalNotificationConfig_alert_message_tag 5 #define ModuleConfig_ExternalNotificationConfig_alert_message_tag 5
#define ModuleConfig_ExternalNotificationConfig_alert_bell_tag 6 #define ModuleConfig_ExternalNotificationConfig_alert_bell_tag 6
#define ModuleConfig_MQTTConfig_disabled_tag 1 #define ModuleConfig_MQTTConfig_enabled_tag 1
#define ModuleConfig_MQTTConfig_address_tag 2 #define ModuleConfig_MQTTConfig_address_tag 2
#define ModuleConfig_MQTTConfig_username_tag 3 #define ModuleConfig_MQTTConfig_username_tag 3
#define ModuleConfig_MQTTConfig_password_tag 4 #define ModuleConfig_MQTTConfig_password_tag 4
#define ModuleConfig_MQTTConfig_encryption_enabled_tag 5 #define ModuleConfig_MQTTConfig_encryption_enabled_tag 5
#define ModuleConfig_MQTTConfig_json_enabled_tag 6
#define ModuleConfig_RangeTestConfig_enabled_tag 1 #define ModuleConfig_RangeTestConfig_enabled_tag 1
#define ModuleConfig_RangeTestConfig_sender_tag 2 #define ModuleConfig_RangeTestConfig_sender_tag 2
#define ModuleConfig_RangeTestConfig_save_tag 3 #define ModuleConfig_RangeTestConfig_save_tag 3
@@ -240,11 +241,12 @@ X(a, STATIC, ONEOF, MESSAGE, (payloadVariant,canned_message,payloadVariant
#define ModuleConfig_payloadVariant_canned_message_MSGTYPE ModuleConfig_CannedMessageConfig #define ModuleConfig_payloadVariant_canned_message_MSGTYPE ModuleConfig_CannedMessageConfig
#define ModuleConfig_MQTTConfig_FIELDLIST(X, a) \ #define ModuleConfig_MQTTConfig_FIELDLIST(X, a) \
X(a, STATIC, SINGULAR, BOOL, disabled, 1) \ X(a, STATIC, SINGULAR, BOOL, enabled, 1) \
X(a, STATIC, SINGULAR, STRING, address, 2) \ X(a, STATIC, SINGULAR, STRING, address, 2) \
X(a, STATIC, SINGULAR, STRING, username, 3) \ X(a, STATIC, SINGULAR, STRING, username, 3) \
X(a, STATIC, SINGULAR, STRING, password, 4) \ X(a, STATIC, SINGULAR, STRING, password, 4) \
X(a, STATIC, SINGULAR, BOOL, encryption_enabled, 5) X(a, STATIC, SINGULAR, BOOL, encryption_enabled, 5) \
X(a, STATIC, SINGULAR, BOOL, json_enabled, 6)
#define ModuleConfig_MQTTConfig_CALLBACK NULL #define ModuleConfig_MQTTConfig_CALLBACK NULL
#define ModuleConfig_MQTTConfig_DEFAULT NULL #define ModuleConfig_MQTTConfig_DEFAULT NULL
@@ -331,12 +333,12 @@ extern const pb_msgdesc_t ModuleConfig_CannedMessageConfig_msg;
/* Maximum encoded size of messages (where known) */ /* Maximum encoded size of messages (where known) */
#define ModuleConfig_CannedMessageConfig_size 49 #define ModuleConfig_CannedMessageConfig_size 49
#define ModuleConfig_ExternalNotificationConfig_size 20 #define ModuleConfig_ExternalNotificationConfig_size 20
#define ModuleConfig_MQTTConfig_size 103 #define ModuleConfig_MQTTConfig_size 105
#define ModuleConfig_RangeTestConfig_size 10 #define ModuleConfig_RangeTestConfig_size 10
#define ModuleConfig_SerialConfig_size 26 #define ModuleConfig_SerialConfig_size 26
#define ModuleConfig_StoreForwardConfig_size 22 #define ModuleConfig_StoreForwardConfig_size 22
#define ModuleConfig_TelemetryConfig_size 18 #define ModuleConfig_TelemetryConfig_size 18
#define ModuleConfig_size 105 #define ModuleConfig_size 107
#ifdef __cplusplus #ifdef __cplusplus
} /* extern "C" */ } /* extern "C" */

View File

@@ -48,7 +48,8 @@ typedef enum _PortNum {
PortNum_ADMIN_APP = 6, PortNum_ADMIN_APP = 6,
/* Compressed TEXT_MESSAGE payloads. */ /* Compressed TEXT_MESSAGE payloads. */
PortNum_TEXT_MESSAGE_COMPRESSED_APP = 7, PortNum_TEXT_MESSAGE_COMPRESSED_APP = 7,
/* Waypoint payloads. */ /* Waypoint payloads.
Payload is a [Waypoint](/docs/developers/protobufs/api#waypoint) message */
PortNum_WAYPOINT_APP = 8, PortNum_WAYPOINT_APP = 8,
/* Provides a 'ping' service that replies to any packet it receives. /* Provides a 'ping' service that replies to any packet it receives.
Also serves as a small example module. */ Also serves as a small example module. */

View File

@@ -62,7 +62,7 @@ static int32_t reconnectWiFi()
const char *wifiName = config.wifi.ssid; const char *wifiName = config.wifi.ssid;
const char *wifiPsw = config.wifi.psk; const char *wifiPsw = config.wifi.psk;
if (needReconnect && !WiFi.isConnected()) { if (config.wifi.enabled && needReconnect && !WiFi.isConnected()) {
// if (radioConfig.has_preferences && needReconnect && !WiFi.isConnected()) { // if (radioConfig.has_preferences && needReconnect && !WiFi.isConnected()) {
if (!*wifiPsw) // Treat empty password as no password if (!*wifiPsw) // Treat empty password as no password
@@ -184,7 +184,7 @@ bool initWifi(bool forceSoftAP)
{ {
forcedSoftAP = forceSoftAP; forcedSoftAP = forceSoftAP;
if ((config.wifi.ssid[0]) || forceSoftAP) { if (config.wifi.enabled && ((config.wifi.ssid[0]) || forceSoftAP)) {
// if ((radioConfig.has_preferences && config.wifi.ssid[0]) || forceSoftAP) { // if ((radioConfig.has_preferences && config.wifi.ssid[0]) || forceSoftAP) {
const char *wifiName = config.wifi.ssid; const char *wifiName = config.wifi.ssid;
const char *wifiPsw = config.wifi.psk; const char *wifiPsw = config.wifi.psk;

View File

@@ -170,80 +170,95 @@ void AdminModule::handleSetOwner(const User &o)
void AdminModule::handleSetConfig(const Config &c) void AdminModule::handleSetConfig(const Config &c)
{ {
bool requiresReboot = false;
switch (c.which_payloadVariant) { switch (c.which_payloadVariant) {
case Config_device_tag: case Config_device_tag:
DEBUG_MSG("Setting config: Device\n"); DEBUG_MSG("Setting config: Device\n");
config.has_device = true; config.has_device = true;
config.device = c.payloadVariant.device; config.device = c.payloadVariant.device;
break; break;
case Config_position_tag: case Config_position_tag:
DEBUG_MSG("Setting config: Position\n"); DEBUG_MSG("Setting config: Position\n");
config.has_position = true; config.has_position = true;
config.position = c.payloadVariant.position; config.position = c.payloadVariant.position;
break; break;
case Config_power_tag: case Config_power_tag:
DEBUG_MSG("Setting config: Power\n"); DEBUG_MSG("Setting config: Power\n");
config.has_power = true; config.has_power = true;
config.power = c.payloadVariant.power; config.power = c.payloadVariant.power;
break; break;
case Config_wifi_tag: case Config_wifi_tag:
DEBUG_MSG("Setting config: WiFi\n"); DEBUG_MSG("Setting config: WiFi\n");
config.has_wifi = true; config.has_wifi = true;
config.wifi = c.payloadVariant.wifi; config.wifi = c.payloadVariant.wifi;
break; requiresReboot = true;
case Config_display_tag: break;
DEBUG_MSG("Setting config: Display\n"); case Config_display_tag:
config.has_display = true; DEBUG_MSG("Setting config: Display\n");
config.display = c.payloadVariant.display; config.has_display = true;
break; config.display = c.payloadVariant.display;
case Config_lora_tag: break;
DEBUG_MSG("Setting config: LoRa\n"); case Config_lora_tag:
config.has_lora = true; DEBUG_MSG("Setting config: LoRa\n");
config.lora = c.payloadVariant.lora; config.has_lora = true;
break; config.lora = c.payloadVariant.lora;
requiresReboot = true;
break;
case Config_bluetooth_tag:
DEBUG_MSG("Setting config: Bluetooth\n");
config.has_bluetooth = true;
config.bluetooth = c.payloadVariant.bluetooth;
requiresReboot = true;
break;
} }
service.reloadConfig(); service.reloadConfig();
// Reboot 5 seconds after a config that requires rebooting is set
if (requiresReboot) {
DEBUG_MSG("Rebooting due to config changes\n");
screen->startRebootScreen();
rebootAtMsec = millis() + (5 * 1000);
}
} }
void AdminModule::handleSetModuleConfig(const ModuleConfig &c) void AdminModule::handleSetModuleConfig(const ModuleConfig &c)
{ {
switch (c.which_payloadVariant) { switch (c.which_payloadVariant) {
case ModuleConfig_mqtt_tag: case ModuleConfig_mqtt_tag:
DEBUG_MSG("Setting module config: MQTT\n"); DEBUG_MSG("Setting module config: MQTT\n");
moduleConfig.has_mqtt = true; moduleConfig.has_mqtt = true;
moduleConfig.mqtt = c.payloadVariant.mqtt; moduleConfig.mqtt = c.payloadVariant.mqtt;
break; break;
case ModuleConfig_serial_tag: case ModuleConfig_serial_tag:
DEBUG_MSG("Setting module config: Serial\n"); DEBUG_MSG("Setting module config: Serial\n");
moduleConfig.has_serial = true; moduleConfig.has_serial = true;
moduleConfig.serial = c.payloadVariant.serial; moduleConfig.serial = c.payloadVariant.serial;
break; break;
case ModuleConfig_external_notification_tag: case ModuleConfig_external_notification_tag:
DEBUG_MSG("Setting module config: External Notification\n"); DEBUG_MSG("Setting module config: External Notification\n");
moduleConfig.has_external_notification = true; moduleConfig.has_external_notification = true;
moduleConfig.external_notification = c.payloadVariant.external_notification; moduleConfig.external_notification = c.payloadVariant.external_notification;
break; break;
case ModuleConfig_store_forward_tag: case ModuleConfig_store_forward_tag:
DEBUG_MSG("Setting module config: Store & Forward\n"); DEBUG_MSG("Setting module config: Store & Forward\n");
moduleConfig.has_store_forward = true; moduleConfig.has_store_forward = true;
moduleConfig.store_forward = c.payloadVariant.store_forward; moduleConfig.store_forward = c.payloadVariant.store_forward;
break; break;
case ModuleConfig_range_test_tag: case ModuleConfig_range_test_tag:
DEBUG_MSG("Setting module config: Range Test\n"); DEBUG_MSG("Setting module config: Range Test\n");
moduleConfig.has_range_test = true; moduleConfig.has_range_test = true;
moduleConfig.range_test = c.payloadVariant.range_test; moduleConfig.range_test = c.payloadVariant.range_test;
break; break;
case ModuleConfig_telemetry_tag: case ModuleConfig_telemetry_tag:
DEBUG_MSG("Setting module config: Telemetry\n"); DEBUG_MSG("Setting module config: Telemetry\n");
moduleConfig.has_telemetry = true; moduleConfig.has_telemetry = true;
moduleConfig.telemetry = c.payloadVariant.telemetry; moduleConfig.telemetry = c.payloadVariant.telemetry;
break; break;
case ModuleConfig_canned_message_tag: case ModuleConfig_canned_message_tag:
DEBUG_MSG("Setting module config: Canned Message\n"); DEBUG_MSG("Setting module config: Canned Message\n");
moduleConfig.has_canned_message = true; moduleConfig.has_canned_message = true;
moduleConfig.canned_message = c.payloadVariant.canned_message; moduleConfig.canned_message = c.payloadVariant.canned_message;
break; break;
} }
service.reloadConfig(); service.reloadConfig();
@@ -309,8 +324,12 @@ void AdminModule::handleGetConfig(const MeshPacket &req, const uint32_t configTy
res.get_config_response.which_payloadVariant = Config_lora_tag; res.get_config_response.which_payloadVariant = Config_lora_tag;
res.get_config_response.payloadVariant.lora = config.lora; res.get_config_response.payloadVariant.lora = config.lora;
break; break;
case AdminMessage_ConfigType_BLUETOOTH_CONFIG:
DEBUG_MSG("Getting config: Bluetooth\n");
res.get_config_response.which_payloadVariant = Config_bluetooth_tag;
res.get_config_response.payloadVariant.bluetooth = config.bluetooth;
break;
} }
// NOTE: The phone app needs to know the ls_secs value so it can properly expect sleep behavior. // NOTE: The phone app needs to know the ls_secs value so it can properly expect sleep behavior.
// So even if we internally use 0 to represent 'use default' we still need to send the value we are // So even if we internally use 0 to represent 'use default' we still need to send the value we are
// using to the app (so that even old phone apps work with new device loads). // using to the app (so that even old phone apps work with new device loads).

View File

@@ -46,16 +46,14 @@ CannedMessageModule::CannedMessageModule()
* *
* @return int Returns the number of messages found. * @return int Returns the number of messages found.
*/ */
// FIXME: This is just one set of messages now
int CannedMessageModule::splitConfiguredMessages() int CannedMessageModule::splitConfiguredMessages()
{ {
int messageIndex = 0; int messageIndex = 0;
int i = 0; int i = 0;
// collect all the message parts // collect all the message parts
strcpy(this->messageStore, cannedMessageModuleConfig.messagesPart1); strcpy(this->messageStore, cannedMessageModuleConfig.messages);
strcat(this->messageStore, cannedMessageModuleConfig.messagesPart2);
strcat(this->messageStore, cannedMessageModuleConfig.messagesPart3);
strcat(this->messageStore, cannedMessageModuleConfig.messagesPart4);
// The first message points to the beginning of the store. // The first message points to the beginning of the store.
this->messages[messageIndex++] = this->messageStore; this->messages[messageIndex++] = this->messageStore;
@@ -294,10 +292,7 @@ bool CannedMessageModule::saveProtoForModule()
*/ */
void CannedMessageModule::installDefaultCannedMessageModuleConfig() void CannedMessageModule::installDefaultCannedMessageModuleConfig()
{ {
memset(cannedMessageModuleConfig.messagesPart1, 0, sizeof(cannedMessageModuleConfig.messagesPart1)); memset(cannedMessageModuleConfig.messages, 0, sizeof(cannedMessageModuleConfig.messages));
memset(cannedMessageModuleConfig.messagesPart2, 0, sizeof(cannedMessageModuleConfig.messagesPart2));
memset(cannedMessageModuleConfig.messagesPart3, 0, sizeof(cannedMessageModuleConfig.messagesPart3));
memset(cannedMessageModuleConfig.messagesPart4, 0, sizeof(cannedMessageModuleConfig.messagesPart4));
} }
/** /**
@@ -315,51 +310,15 @@ AdminMessageHandleResult CannedMessageModule::handleAdminMessageForModule(const
AdminMessageHandleResult result; AdminMessageHandleResult result;
switch (request->which_variant) { switch (request->which_variant) {
case AdminMessage_get_canned_message_module_part1_request_tag: case AdminMessage_get_canned_message_module_messages_request_tag:
DEBUG_MSG("Client is getting radio canned message part1\n"); DEBUG_MSG("Client is getting radio canned messages\n");
this->handleGetCannedMessageModulePart1(mp, response); this->handleGetCannedMessageModuleMessages(mp, response);
result = AdminMessageHandleResult::HANDLED_WITH_RESPONSE; result = AdminMessageHandleResult::HANDLED_WITH_RESPONSE;
break; break;
case AdminMessage_get_canned_message_module_part2_request_tag: case AdminMessage_set_canned_message_module_messages_tag:
DEBUG_MSG("Client is getting radio canned message part2\n"); DEBUG_MSG("Client is setting radio canned messages\n");
this->handleGetCannedMessageModulePart2(mp, response); this->handleSetCannedMessageModuleMessages(request->set_canned_message_module_messages);
result = AdminMessageHandleResult::HANDLED_WITH_RESPONSE;
break;
case AdminMessage_get_canned_message_module_part3_request_tag:
DEBUG_MSG("Client is getting radio canned message part3\n");
this->handleGetCannedMessageModulePart3(mp, response);
result = AdminMessageHandleResult::HANDLED_WITH_RESPONSE;
break;
case AdminMessage_get_canned_message_module_part4_request_tag:
DEBUG_MSG("Client is getting radio canned message part4\n");
this->handleGetCannedMessageModulePart4(mp, response);
result = AdminMessageHandleResult::HANDLED_WITH_RESPONSE;
break;
case AdminMessage_set_canned_message_module_part1_tag:
DEBUG_MSG("Client is setting radio canned message part 1\n");
this->handleSetCannedMessageModulePart1(request->set_canned_message_module_part1);
result = AdminMessageHandleResult::HANDLED;
break;
case AdminMessage_set_canned_message_module_part2_tag:
DEBUG_MSG("Client is setting radio canned message part 2\n");
this->handleSetCannedMessageModulePart2(request->set_canned_message_module_part2);
result = AdminMessageHandleResult::HANDLED;
break;
case AdminMessage_set_canned_message_module_part3_tag:
DEBUG_MSG("Client is setting radio canned message part 3\n");
this->handleSetCannedMessageModulePart3(request->set_canned_message_module_part3);
result = AdminMessageHandleResult::HANDLED;
break;
case AdminMessage_set_canned_message_module_part4_tag:
DEBUG_MSG("Client is setting radio canned message part 4\n");
this->handleSetCannedMessageModulePart4(request->set_canned_message_module_part4);
result = AdminMessageHandleResult::HANDLED; result = AdminMessageHandleResult::HANDLED;
break; break;
@@ -370,49 +329,23 @@ AdminMessageHandleResult CannedMessageModule::handleAdminMessageForModule(const
return result; return result;
} }
void CannedMessageModule::handleGetCannedMessageModulePart1(const MeshPacket &req, AdminMessage *response) void CannedMessageModule::handleGetCannedMessageModuleMessages(const MeshPacket &req, AdminMessage *response)
{ {
DEBUG_MSG("*** handleGetCannedMessageModulePart1\n"); DEBUG_MSG("*** handleGetCannedMessageModuleMessages\n");
assert(req.decoded.want_response); assert(req.decoded.want_response);
response->which_variant = AdminMessage_get_canned_message_module_part1_response_tag; response->which_variant = AdminMessage_get_canned_message_module_messages_response_tag;
strcpy(response->get_canned_message_module_part1_response, cannedMessageModuleConfig.messagesPart1); strcpy(response->get_canned_message_module_messages_response, cannedMessageModuleConfig.messages);
} }
void CannedMessageModule::handleGetCannedMessageModulePart2(const MeshPacket &req, AdminMessage *response)
{
DEBUG_MSG("*** handleGetCannedMessageModulePart2\n");
assert(req.decoded.want_response);
response->which_variant = AdminMessage_get_canned_message_module_part2_response_tag; void CannedMessageModule::handleSetCannedMessageModuleMessages(const char *from_msg)
strcpy(response->get_canned_message_module_part2_response, cannedMessageModuleConfig.messagesPart2);
}
void CannedMessageModule::handleGetCannedMessageModulePart3(const MeshPacket &req, AdminMessage *response)
{
DEBUG_MSG("*** handleGetCannedMessageModulePart3\n");
assert(req.decoded.want_response);
response->which_variant = AdminMessage_get_canned_message_module_part3_response_tag;
strcpy(response->get_canned_message_module_part3_response, cannedMessageModuleConfig.messagesPart3);
}
void CannedMessageModule::handleGetCannedMessageModulePart4(const MeshPacket &req, AdminMessage *response)
{
DEBUG_MSG("*** handleGetCannedMessageModulePart4\n");
assert(req.decoded.want_response);
response->which_variant = AdminMessage_get_canned_message_module_part4_response_tag;
strcpy(response->get_canned_message_module_part4_response, cannedMessageModuleConfig.messagesPart4);
}
void CannedMessageModule::handleSetCannedMessageModulePart1(const char *from_msg)
{ {
int changed = 0; int changed = 0;
if (*from_msg) { if (*from_msg) {
changed |= strcmp(cannedMessageModuleConfig.messagesPart1, from_msg); changed |= strcmp(cannedMessageModuleConfig.messages, from_msg);
strcpy(cannedMessageModuleConfig.messagesPart1, from_msg); strcpy(cannedMessageModuleConfig.messages, from_msg);
DEBUG_MSG("*** from_msg.text:%s\n", from_msg); DEBUG_MSG("*** from_msg.text:%s\n", from_msg);
} }
@@ -421,45 +354,4 @@ void CannedMessageModule::handleSetCannedMessageModulePart1(const char *from_msg
} }
} }
void CannedMessageModule::handleSetCannedMessageModulePart2(const char *from_msg)
{
int changed = 0;
if (*from_msg) {
changed |= strcmp(cannedMessageModuleConfig.messagesPart2, from_msg);
strcpy(cannedMessageModuleConfig.messagesPart2, from_msg);
}
if (changed) {
this->saveProtoForModule();
}
}
void CannedMessageModule::handleSetCannedMessageModulePart3(const char *from_msg)
{
int changed = 0;
if (*from_msg) {
changed |= strcmp(cannedMessageModuleConfig.messagesPart3, from_msg);
strcpy(cannedMessageModuleConfig.messagesPart3, from_msg);
}
if (changed) {
this->saveProtoForModule();
}
}
void CannedMessageModule::handleSetCannedMessageModulePart4(const char *from_msg)
{
int changed = 0;
if (*from_msg) {
changed |= strcmp(cannedMessageModuleConfig.messagesPart4, from_msg);
strcpy(cannedMessageModuleConfig.messagesPart4, from_msg);
}
if (changed) {
this->saveProtoForModule();
}
}
#endif #endif

View File

@@ -39,15 +39,8 @@ class CannedMessageModule :
void eventDown(); void eventDown();
void eventSelect(); void eventSelect();
void handleGetCannedMessageModulePart1(const MeshPacket &req, AdminMessage *response); void handleGetCannedMessageModuleMessages(const MeshPacket &req, AdminMessage *response);
void handleGetCannedMessageModulePart2(const MeshPacket &req, AdminMessage *response); void handleSetCannedMessageModuleMessages(const char *from_msg);
void handleGetCannedMessageModulePart3(const MeshPacket &req, AdminMessage *response);
void handleGetCannedMessageModulePart4(const MeshPacket &req, AdminMessage *response);
void handleSetCannedMessageModulePart1(const char *from_msg);
void handleSetCannedMessageModulePart2(const char *from_msg);
void handleSetCannedMessageModulePart3(const char *from_msg);
void handleSetCannedMessageModulePart4(const char *from_msg);
protected: protected:

View File

@@ -116,7 +116,6 @@ ExternalNotificationModule::ExternalNotificationModule()
// restrict to the admin channel for rx // restrict to the admin channel for rx
boundChannel = Channels::gpioChannel; boundChannel = Channels::gpioChannel;
#ifdef ARCH_ESP32
#ifdef EXT_NOTIFY_OUT #ifdef EXT_NOTIFY_OUT
/* /*
@@ -149,12 +148,10 @@ ExternalNotificationModule::ExternalNotificationModule()
enabled = false; enabled = false;
} }
#endif #endif
#endif
} }
ProcessMessage ExternalNotificationModule::handleReceived(const MeshPacket &mp) ProcessMessage ExternalNotificationModule::handleReceived(const MeshPacket &mp)
{ {
#ifdef ARCH_ESP32
#ifdef EXT_NOTIFY_OUT #ifdef EXT_NOTIFY_OUT
if (moduleConfig.external_notification.enabled) { if (moduleConfig.external_notification.enabled) {
@@ -182,8 +179,6 @@ ProcessMessage ExternalNotificationModule::handleReceived(const MeshPacket &mp)
} else { } else {
DEBUG_MSG("External Notification Module Disabled\n"); DEBUG_MSG("External Notification Module Disabled\n");
} }
#endif
#endif #endif
return ProcessMessage::CONTINUE; // Let others look at this message also if they want return ProcessMessage::CONTINUE; // Let others look at this message also if they want

View File

@@ -6,15 +6,15 @@
#include "input/facesKbI2cImpl.h" #include "input/facesKbI2cImpl.h"
#include "modules/AdminModule.h" #include "modules/AdminModule.h"
#include "modules/CannedMessageModule.h" #include "modules/CannedMessageModule.h"
#include "modules/ExternalNotificationModule.h"
#include "modules/NodeInfoModule.h" #include "modules/NodeInfoModule.h"
#include "modules/PositionModule.h" #include "modules/PositionModule.h"
#include "modules/RemoteHardwareModule.h" #include "modules/RemoteHardwareModule.h"
#include "modules/ReplyModule.h" #include "modules/ReplyModule.h"
#include "modules/RoutingModule.h" #include "modules/RoutingModule.h"
#include "modules/TextMessageModule.h" #include "modules/TextMessageModule.h"
#include "modules/Telemetry/DeviceTelemetry.h" #include "modules/WaypointModule.h"
#if HAS_TELEMETRY #if HAS_TELEMETRY
#include "modules/Telemetry/DeviceTelemetry.h"
#include "modules/Telemetry/EnvironmentTelemetry.h" #include "modules/Telemetry/EnvironmentTelemetry.h"
#endif #endif
#ifdef ARCH_ESP32 #ifdef ARCH_ESP32
@@ -22,7 +22,9 @@
#include "modules/esp32/SerialModule.h" #include "modules/esp32/SerialModule.h"
#include "modules/esp32/StoreForwardModule.h" #include "modules/esp32/StoreForwardModule.h"
#endif #endif
#if defined(ARCH_ESP32) || defined(ARCH_NRF52)
#include "modules/ExternalNotificationModule.h"
#endif
/** /**
* Create module instances here. If you are adding a new module, you must 'new' it here (or somewhere else) * Create module instances here. If you are adding a new module, you must 'new' it here (or somewhere else)
*/ */
@@ -34,6 +36,7 @@ void setupModules()
adminModule = new AdminModule(); adminModule = new AdminModule();
nodeInfoModule = new NodeInfoModule(); nodeInfoModule = new NodeInfoModule();
positionModule = new PositionModule(); positionModule = new PositionModule();
waypointModule = new WaypointModule();
textMessageModule = new TextMessageModule(); textMessageModule = new TextMessageModule();
// Note: if the rest of meshtastic doesn't need to explicitly use your module, you do not need to assign the instance // Note: if the rest of meshtastic doesn't need to explicitly use your module, you do not need to assign the instance
@@ -70,6 +73,8 @@ void setupModules()
storeForwardModule = new StoreForwardModule(); storeForwardModule = new StoreForwardModule();
new RangeTestModule(); new RangeTestModule();
#elif defined(ARCH_NRF52)
new ExternalNotificationModule();
#endif #endif
// NOTE! This module must be added LAST because it likes to check for replies from other modules and avoid sending extra acks // NOTE! This module must be added LAST because it likes to check for replies from other modules and avoid sending extra acks

View File

@@ -54,8 +54,7 @@ NodeInfoModule::NodeInfoModule()
: ProtobufModule("nodeinfo", PortNum_NODEINFO_APP, User_fields), concurrency::OSThread("NodeInfoModule") : ProtobufModule("nodeinfo", PortNum_NODEINFO_APP, User_fields), concurrency::OSThread("NodeInfoModule")
{ {
isPromiscuous = true; // We always want to update our nodedb, even if we are sniffing on others isPromiscuous = true; // We always want to update our nodedb, even if we are sniffing on others
setIntervalFromNow(30 * setIntervalFromNow(30 * 1000); // Send our initial owner announcement 30 seconds after we start (to give network time to setup)
1000); // Send our initial owner announcement 30 seconds after we start (to give network time to setup)
} }
int32_t NodeInfoModule::runOnce() int32_t NodeInfoModule::runOnce()
@@ -69,6 +68,5 @@ int32_t NodeInfoModule::runOnce()
DEBUG_MSG("Sending our nodeinfo to mesh (wantReplies=%d)\n", requestReplies); DEBUG_MSG("Sending our nodeinfo to mesh (wantReplies=%d)\n", requestReplies);
sendOurNodeInfo(NODENUM_BROADCAST, requestReplies); // Send our info (don't request replies) sendOurNodeInfo(NODENUM_BROADCAST, requestReplies); // Send our info (don't request replies)
return config.position.position_broadcast_secs ? config.position.position_broadcast_secs return default_broadcast_interval_secs * 1000;
: default_broadcast_interval_secs * 1000;
} }

View File

@@ -129,9 +129,8 @@ int32_t PositionModule::runOnce()
// We limit our GPS broadcasts to a max rate // We limit our GPS broadcasts to a max rate
uint32_t now = millis(); uint32_t now = millis();
if (lastGpsSend == 0 || now - lastGpsSend >= config.position.position_broadcast_secs uint32_t intervalMs = config.position.position_broadcast_secs > 0 ? config.position.position_broadcast_secs * 1000 : default_broadcast_interval_secs * 1000;
? config.position.position_broadcast_secs if (lastGpsSend == 0 || (now - lastGpsSend) >= intervalMs) {
: default_broadcast_interval_secs * 1000) {
// Only send packets if the channel is less than 40% utilized. // Only send packets if the channel is less than 40% utilized.
if (airTime->channelUtilizationPercent() < 40) { if (airTime->channelUtilizationPercent() < 40) {

View File

@@ -21,7 +21,7 @@ int32_t DeviceTelemetryModule::runOnce()
sendOurTelemetry(); sendOurTelemetry();
// OSThread library. Multiply the preference value by 1000 to convert seconds to miliseconds // OSThread library. Multiply the preference value by 1000 to convert seconds to miliseconds
return getIntervalOrDefaultMs(moduleConfig.telemetry.device_update_interval); return getConfiguredOrDefaultMs(moduleConfig.telemetry.device_update_interval);
#endif #endif
} }

View File

@@ -97,7 +97,7 @@ int32_t EnvironmentTelemetryModule::runOnce()
return DEFAULT_SENSOR_MINIMUM_WAIT_TIME_BETWEEN_READS; return DEFAULT_SENSOR_MINIMUM_WAIT_TIME_BETWEEN_READS;
} }
} }
return getIntervalOrDefaultMs(moduleConfig.telemetry.environment_update_interval); return getConfiguredOrDefaultMs(moduleConfig.telemetry.environment_update_interval);
#endif #endif
} }

View File

@@ -6,7 +6,7 @@
#include <typeinfo> #include <typeinfo>
BMP280Sensor::BMP280Sensor() : BMP280Sensor::BMP280Sensor() :
TelemetrySensor(TelemetrySensorType_BME280, "BMP280") TelemetrySensor(TelemetrySensorType_BMP280, "BMP280")
{ {
} }
@@ -27,4 +27,4 @@ bool BMP280Sensor::getMetrics(Telemetry *measurement) {
measurement->variant.environment_metrics.barometric_pressure = bmp280.readPressure() / 100.0F; measurement->variant.environment_metrics.barometric_pressure = bmp280.readPressure() / 100.0F;
return true; return true;
} }

View File

@@ -0,0 +1,17 @@
#include "configuration.h"
#include "WaypointModule.h"
#include "NodeDB.h"
#include "PowerFSM.h"
WaypointModule *waypointModule;
ProcessMessage WaypointModule::handleReceived(const MeshPacket &mp)
{
auto &p = mp.decoded;
DEBUG_MSG("Received waypoint msg from=0x%0x, id=0x%x, msg=%.*s\n", mp.from, mp.id, p.payload.size, p.payload.bytes);
notifyObservers(&mp);
return ProcessMessage::CONTINUE; // Let others look at this message also if they want
}

View File

@@ -0,0 +1,25 @@
#pragma once
#include "SinglePortModule.h"
#include "Observer.h"
/**
* Waypoint message handling for meshtastic
*/
class WaypointModule : public SinglePortModule, public Observable<const MeshPacket *>
{
public:
/** Constructor
* name is for debugging output
*/
WaypointModule() : SinglePortModule("waypoint", PortNum_WAYPOINT_APP) {}
protected:
/** Called to handle a particular incoming message
@return ProcessMessage::STOP if you've guaranteed you've handled this message and no other handlers should be considered for it
*/
virtual ProcessMessage handleReceived(const MeshPacket &mp) override;
};
extern WaypointModule *waypointModule;

View File

@@ -27,7 +27,7 @@ void MQTT::onPublish(char *topic, byte *payload, unsigned int length)
{ {
// parsing ServiceEnvelope // parsing ServiceEnvelope
ServiceEnvelope e = ServiceEnvelope_init_default; ServiceEnvelope e = ServiceEnvelope_init_default;
if (!pb_decode_from_bytes(payload, length, ServiceEnvelope_fields, &e)) { if (moduleConfig.mqtt.json_enabled && !pb_decode_from_bytes(payload, length, ServiceEnvelope_fields, &e)) {
// check if this is a json payload message // check if this is a json payload message
using namespace json11; using namespace json11;
@@ -44,17 +44,18 @@ void MQTT::onPublish(char *topic, byte *payload, unsigned int length)
if (json["sender"].string_value().compare(owner.id) != 0) { if (json["sender"].string_value().compare(owner.id) != 0) {
std::string jsonPayloadStr = json["payload"].dump(); std::string jsonPayloadStr = json["payload"].dump();
DEBUG_MSG("Received json payload %s, length %u\n", jsonPayloadStr.c_str(), jsonPayloadStr.length()); DEBUG_MSG("Received json payload %s, length %u\n", jsonPayloadStr.c_str(), jsonPayloadStr.length());
// FIXME Not sure we need to be doing this
// construct protobuf data packet using TEXT_MESSAGE, send it to the mesh // construct protobuf data packet using TEXT_MESSAGE, send it to the mesh
MeshPacket *p = router->allocForSending(); // MeshPacket *p = router->allocForSending();
p->decoded.portnum = PortNum_TEXT_MESSAGE_APP; // p->decoded.portnum = PortNum_TEXT_MESSAGE_APP;
if (jsonPayloadStr.length() <= sizeof(p->decoded.payload.bytes)) { // if (jsonPayloadStr.length() <= sizeof(p->decoded.payload.bytes)) {
memcpy(p->decoded.payload.bytes, jsonPayloadStr.c_str(), jsonPayloadStr.length()); // memcpy(p->decoded.payload.bytes, jsonPayloadStr.c_str(), jsonPayloadStr.length());
p->decoded.payload.size = jsonPayloadStr.length(); // p->decoded.payload.size = jsonPayloadStr.length();
MeshPacket *packet = packetPool.allocCopy(*p); // MeshPacket *packet = packetPool.allocCopy(*p);
service.sendToMesh(packet, RX_SRC_LOCAL); // service.sendToMesh(packet, RX_SRC_LOCAL);
} else { // } else {
DEBUG_MSG("Received MQTT json payload too long, dropping\n"); // DEBUG_MSG("Received MQTT json payload too long, dropping\n");
} // }
} else { } else {
DEBUG_MSG("Ignoring downlink message we originally sent.\n"); DEBUG_MSG("Ignoring downlink message we originally sent.\n");
} }
@@ -175,9 +176,7 @@ bool MQTT::wantsLink() const
{ {
bool hasChannel = false; bool hasChannel = false;
if (moduleConfig.mqtt.disabled) { if (moduleConfig.mqtt.enabled) {
// DEBUG_MSG("MQTT disabled...\n");
} else {
// No need for link if no channel needed it // No need for link if no channel needed it
size_t numChan = channels.getNumChannels(); size_t numChan = channels.getNumChannels();
for (size_t i = 0; i < numChan; i++) { for (size_t i = 0; i < numChan; i++) {
@@ -239,13 +238,15 @@ void MQTT::onSend(const MeshPacket &mp, ChannelIndex chIndex)
pubSub.publish(topic.c_str(), bytes, numBytes, false); pubSub.publish(topic.c_str(), bytes, numBytes, false);
// handle json topic if (moduleConfig.mqtt.json_enabled) {
using namespace json11; // handle json topic
auto jsonString = this->downstreamPacketToJson((MeshPacket *)&mp); using namespace json11;
if (jsonString.length() != 0) { auto jsonString = this->downstreamPacketToJson((MeshPacket *)&mp);
String topicJson = jsonTopic + channelId + "/" + owner.id; if (jsonString.length() != 0) {
DEBUG_MSG("publish json message to %s, %u bytes: %s\n", topicJson.c_str(), jsonString.length(), jsonString.c_str()); String topicJson = jsonTopic + channelId + "/" + owner.id;
pubSub.publish(topicJson.c_str(), jsonString.c_str(), false); DEBUG_MSG("publish json message to %s, %u bytes: %s\n", topicJson.c_str(), jsonString.length(), jsonString.c_str());
pubSub.publish(topicJson.c_str(), jsonString.c_str(), false);
}
} }
} }
} }
@@ -291,7 +292,14 @@ String MQTT::downstreamPacketToJson(MeshPacket *mp)
memset(&scratch, 0, sizeof(scratch)); memset(&scratch, 0, sizeof(scratch));
if (pb_decode_from_bytes(mp->decoded.payload.bytes, mp->decoded.payload.size, &Telemetry_msg, &scratch)) { if (pb_decode_from_bytes(mp->decoded.payload.bytes, mp->decoded.payload.size, &Telemetry_msg, &scratch)) {
decoded = &scratch; decoded = &scratch;
if (decoded->which_variant == Telemetry_environment_metrics_tag) { if (decoded->which_variant == Telemetry_device_metrics_tag) {
msgPayload = Json::object{
{"battery_level", (int)decoded->variant.device_metrics.battery_level},
{"voltage", decoded->variant.device_metrics.voltage},
{"channel_utilization", decoded->variant.device_metrics.channel_utilization},
{"air_util_tx", decoded->variant.device_metrics.air_util_tx},
};
} else if (decoded->which_variant == Telemetry_environment_metrics_tag) {
msgPayload = Json::object{ msgPayload = Json::object{
{"temperature", decoded->variant.environment_metrics.temperature}, {"temperature", decoded->variant.environment_metrics.temperature},
{"relative_humidity", decoded->variant.environment_metrics.relative_humidity}, {"relative_humidity", decoded->variant.environment_metrics.relative_humidity},
@@ -314,10 +322,12 @@ String MQTT::downstreamPacketToJson(MeshPacket *mp)
memset(&scratch, 0, sizeof(scratch)); memset(&scratch, 0, sizeof(scratch));
if (pb_decode_from_bytes(mp->decoded.payload.bytes, mp->decoded.payload.size, &User_msg, &scratch)) { if (pb_decode_from_bytes(mp->decoded.payload.bytes, mp->decoded.payload.size, &User_msg, &scratch)) {
decoded = &scratch; decoded = &scratch;
msgPayload = Json::object{{"id", decoded->id}, msgPayload = Json::object{
{"longname", decoded->long_name}, {"id", decoded->id},
{"shortname", decoded->short_name}, {"longname", decoded->long_name},
{"hardware", decoded->hw_model}}; {"shortname", decoded->short_name},
{"hardware", decoded->hw_model}
};
} else } else
DEBUG_MSG("Error decoding protobuf for nodeinfo message!\n"); DEBUG_MSG("Error decoding protobuf for nodeinfo message!\n");
@@ -333,7 +343,36 @@ String MQTT::downstreamPacketToJson(MeshPacket *mp)
if (pb_decode_from_bytes(mp->decoded.payload.bytes, mp->decoded.payload.size, &Position_msg, &scratch)) { if (pb_decode_from_bytes(mp->decoded.payload.bytes, mp->decoded.payload.size, &Position_msg, &scratch)) {
decoded = &scratch; decoded = &scratch;
msgPayload = Json::object{ msgPayload = Json::object{
{"latitude_i", decoded->latitude_i}, {"longitude_i", decoded->longitude_i}, {"altitude", decoded->altitude}}; {"time", (int)decoded->time},
{"pos_timestamp", (int)decoded->pos_timestamp},
{"latitude_i", decoded->latitude_i},
{"longitude_i", decoded->longitude_i},
{"altitude", decoded->altitude}
};
} else {
DEBUG_MSG("Error decoding protobuf for position message!\n");
}
};
break;
}
case PortNum_WAYPOINT_APP: {
msgType = "position";
Waypoint scratch;
Waypoint *decoded = NULL;
if (mp->which_payloadVariant == MeshPacket_decoded_tag) {
memset(&scratch, 0, sizeof(scratch));
if (pb_decode_from_bytes(mp->decoded.payload.bytes, mp->decoded.payload.size, &Waypoint_msg, &scratch)) {
decoded = &scratch;
msgPayload = Json::object{
{"id", (int)decoded->id},
{"name", decoded->name},
{"description", decoded->description},
{"expire", (int)decoded->expire},
{"locked", decoded->locked},
{"latitude_i", decoded->latitude_i},
{"longitude_i", decoded->longitude_i},
};
} else { } else {
DEBUG_MSG("Error decoding protobuf for position message!\n"); DEBUG_MSG("Error decoding protobuf for position message!\n");
} }
@@ -346,14 +385,16 @@ String MQTT::downstreamPacketToJson(MeshPacket *mp)
} }
// assemble the final jsonObj // assemble the final jsonObj
Json jsonObj = Json::object{{"id", Json((int)mp->id)}, Json jsonObj = Json::object{
{"timestamp", Json((int)mp->rx_time)}, {"id", Json((int)mp->id)},
{"to", Json((int)mp->to)}, {"timestamp", Json((int)mp->rx_time)},
{"from", Json((int)mp->from)}, {"to", Json((int)mp->to)},
{"channel", Json((int)mp->channel)}, {"from", Json((int)mp->from)},
{"type", msgType.c_str()}, {"channel", Json((int)mp->channel)},
{"sender", owner.id}, {"type", msgType.c_str()},
{"payload", msgPayload}}; {"sender", owner.id},
{"payload", msgPayload}
};
// serialize and return it // serialize and return it
static std::string jsonStr = jsonObj.dump(); static std::string jsonStr = jsonObj.dump();

View File

@@ -1,662 +0,0 @@
#ifndef USE_NEW_ESP32_BLUETOOTH
#include "BluetoothUtil.h"
#include "BluetoothSoftwareUpdate.h"
#include "NimbleBluetoothAPI.h"
#include "PhoneAPI.h"
#include "PowerFSM.h"
#include "configuration.h"
#include "esp_bt.h"
#include "host/util/util.h"
#include "main.h"
#include "nimble/NimbleDefs.h"
#include "services/gap/ble_svc_gap.h"
#include "services/gatt/ble_svc_gatt.h"
#include "sleep.h"
#include <WiFi.h>
#ifdef ARCH_ESP32
#include "mesh/http/WiFiAPClient.h"
#include <nvs_flash.h>
#endif
static bool pinShowing;
static uint32_t doublepressed;
static bool bluetoothActive;
//put the wider device into a bluetooth pairing mode, and show the pin on screen.
//called in this file only
static void startCb(uint32_t pin)
{
pinShowing = true;
powerFSM.trigger(EVENT_BLUETOOTH_PAIR);
screen->startBluetoothPinScreen(pin);
};
//pairing has ended
//called in this file only
static void stopCb()
{
if (pinShowing) {
pinShowing = false;
screen->stopBluetoothPinScreen();
}
};
static uint8_t own_addr_type;
// Force arduino to keep ble data around
extern "C" bool btInUse()
{
return true;
}
/// Given a level between 0-100, update the BLE attribute
void updateBatteryLevel(uint8_t level)
{
// FIXME
}
//shutdown the bluetooth and tear down all the data structures. to prevent memory leaks
//called here only
void deinitBLE()
{
if (bluetoothActive) {
bluetoothActive = false;
// DEBUG_MSG("Shutting down bluetooth\n");
// ble_gatts_show_local();
// FIXME - do we need to dealloc things? - what needs to stay alive across light sleep?
auto ret = nimble_port_stop();
assert(ret == ESP_OK);
nimble_port_deinit(); // teardown nimble datastructures
// DEBUG_MSG("BLE port_deinit done\n");
ret = esp_nimble_hci_and_controller_deinit();
assert(ret == ESP_OK);
// DEBUG_MSG("BLE task exiting\n");
DEBUG_MSG("Done shutting down bluetooth\n");
}
}
void loopBLE()
{
// FIXME
}
extern "C" void ble_store_config_init(void);
/// Print a macaddr - bytes are sometimes stored in reverse order
//called here only
static void print_addr(const uint8_t v[], bool isReversed = true)
{
const int macaddrlen = 6;
for (int i = 0; i < macaddrlen; i++) {
DEBUG_MSG("%02x%c", v[isReversed ? macaddrlen - i : i], (i == macaddrlen - 1) ? '\n' : ':');
}
}
/**
* Logs information about a connection to the console.
* called here only
*/
static void print_conn_desc(struct ble_gap_conn_desc *desc)
{
DEBUG_MSG("handle=%d our_ota_addr_type=%d our_ota_addr=", desc->conn_handle, desc->our_ota_addr.type);
print_addr(desc->our_ota_addr.val);
DEBUG_MSG(" our_id_addr_type=%d our_id_addr=", desc->our_id_addr.type);
print_addr(desc->our_id_addr.val);
DEBUG_MSG(" peer_ota_addr_type=%d peer_ota_addr=", desc->peer_ota_addr.type);
print_addr(desc->peer_ota_addr.val);
DEBUG_MSG(" peer_id_addr_type=%d peer_id_addr=", desc->peer_id_addr.type);
print_addr(desc->peer_id_addr.val);
DEBUG_MSG(" conn_itvl=%d conn_latency=%d supervision_timeout=%d "
"encrypted=%d authenticated=%d bonded=%d\n",
desc->conn_itvl, desc->conn_latency, desc->supervision_timeout, desc->sec_state.encrypted,
desc->sec_state.authenticated, desc->sec_state.bonded);
}
static void advertise();
/**
* The nimble host executes this callback when a GAP event occurs. The
* application associates a GAP event callback with each connection that forms.
* bleprph uses the same callback for all connections.
*
* @param event The type of event being signalled.
* @param ctxt Various information pertaining to the event.
* @param arg Application-specified argument; unused by
* bleprph.
*
* @return 0 if the application successfully handled the
* event; nonzero on failure. The semantics
* of the return code is specific to the
* particular GAP event being signalled.
*/
static int gap_event(struct ble_gap_event *event, void *arg)
{
struct ble_gap_conn_desc desc;
int rc;
uint32_t now = millis();
switch (event->type) {
case BLE_GAP_EVENT_CONNECT:
/* A new connection was established or a connection attempt failed. */
DEBUG_MSG("connection %s; status=%d ", event->connect.status == 0 ? "established" : "failed", event->connect.status);
if (event->connect.status == 0) {
rc = ble_gap_conn_find(event->connect.conn_handle, &desc);
assert(rc == 0);
print_conn_desc(&desc);
curConnectionHandle = event->connect.conn_handle;
}
DEBUG_MSG("\n");
if (event->connect.status != 0) {
/* Connection failed; resume advertising. */
advertise();
}
return 0;
case BLE_GAP_EVENT_DISCONNECT:
DEBUG_MSG("disconnect; reason=%d ", event->disconnect.reason);
print_conn_desc(&event->disconnect.conn);
DEBUG_MSG("\n");
curConnectionHandle = -1;
/* Connection terminated; resume advertising. */
advertise();
return 0;
case BLE_GAP_EVENT_CONN_UPDATE:
/* The central has updated the connection parameters. */
DEBUG_MSG("connection updated; status=%d ", event->conn_update.status);
rc = ble_gap_conn_find(event->conn_update.conn_handle, &desc);
assert(rc == 0);
print_conn_desc(&desc);
DEBUG_MSG("\n");
return 0;
case BLE_GAP_EVENT_ADV_COMPLETE:
DEBUG_MSG("advertise complete; reason=%d", event->adv_complete.reason);
advertise();
return 0;
case BLE_GAP_EVENT_ENC_CHANGE:
/* Encryption has been enabled or disabled for this connection. */
DEBUG_MSG("encryption change event; status=%d ", event->enc_change.status);
rc = ble_gap_conn_find(event->enc_change.conn_handle, &desc);
assert(rc == 0);
print_conn_desc(&desc);
DEBUG_MSG("\n");
// Remove our custom PIN request screen.
stopCb();
return 0;
case BLE_GAP_EVENT_SUBSCRIBE:
DEBUG_MSG("subscribe event; conn_handle=%d attr_handle=%d "
"reason=%d prevn=%d curn=%d previ=%d curi=%d\n",
event->subscribe.conn_handle, event->subscribe.attr_handle, event->subscribe.reason,
event->subscribe.prev_notify, event->subscribe.cur_notify, event->subscribe.prev_indicate,
event->subscribe.cur_indicate);
return 0;
case BLE_GAP_EVENT_MTU:
DEBUG_MSG("mtu update event; conn_handle=%d cid=%d mtu=%d\n", event->mtu.conn_handle, event->mtu.channel_id,
event->mtu.value);
return 0;
case BLE_GAP_EVENT_REPEAT_PAIRING:
DEBUG_MSG("repeat pairing event; conn_handle=%d "
"cur_key_sz=%d cur_auth=%d cur_sc=%d "
"new_key_sz=%d new_auth=%d new_sc=%d "
"new_bonding=%d\n",
event->repeat_pairing.conn_handle, event->repeat_pairing.cur_key_size, event->repeat_pairing.cur_authenticated,
event->repeat_pairing.cur_sc, event->repeat_pairing.new_key_size, event->repeat_pairing.new_authenticated,
event->repeat_pairing.new_sc, event->repeat_pairing.new_bonding);
/* We already have a bond with the peer, but it is attempting to
* establish a new secure link. This app sacrifices security for
* convenience: just throw away the old bond and accept the new link.
*/
/* Delete the old bond. */
rc = ble_gap_conn_find(event->repeat_pairing.conn_handle, &desc);
assert(rc == 0);
ble_store_util_delete_peer(&desc.peer_id_addr);
/* Return BLE_GAP_REPEAT_PAIRING_RETRY to indicate that the host should
* continue with the pairing operation.
*/
return BLE_GAP_REPEAT_PAIRING_RETRY;
case BLE_GAP_EVENT_PASSKEY_ACTION:
DEBUG_MSG("PASSKEY_ACTION_EVENT started \n");
struct ble_sm_io pkey = {0};
if (event->passkey.params.action == BLE_SM_IOACT_DISP) {
pkey.action = event->passkey.params.action;
DEBUG_MSG("dp: %d now:%d\n", doublepressed, now);
if (doublepressed > 0 && (doublepressed + (30 * 1000)) > now) {
DEBUG_MSG("User has overridden passkey or no display available\n");
pkey.passkey = defaultBLEPin;
} else {
DEBUG_MSG("Using random passkey\n");
pkey.passkey = random(
100000, 999999); // This is the passkey to be entered on peer - we pick a number >100,000 to ensure 6 digits
}
DEBUG_MSG("*** Enter passkey %d on the peer side ***\n", pkey.passkey);
startCb(pkey.passkey);
rc = ble_sm_inject_io(event->passkey.conn_handle, &pkey);
DEBUG_MSG("ble_sm_inject_io result: %d\n", rc);
} else {
DEBUG_MSG("FIXME - unexpected auth type %d\n", event->passkey.params.action);
}
return 0;
}
return 0;
}
/**
* Enables advertising with the following parameters:
* o General discoverable mode.
* o Undirected connectable mode.
*
* Called here only
*/
static void advertise(void)
{
/**
* Set the advertisement data included in our advertisements:
* o Flags (indicates advertisement type and other general info).
* o Advertising tx power.
* o Device name.
* o 16-bit service UUIDs (alert notifications).
*/
struct ble_hs_adv_fields adv_fields;
memset(&adv_fields, 0, sizeof adv_fields);
/* Advertise two flags:
* o Discoverability in forthcoming advertisement (general)
* o BLE-only (BR/EDR unsupported).
*/
adv_fields.flags = BLE_HS_ADV_F_DISC_GEN | BLE_HS_ADV_F_BREDR_UNSUP;
/* Indicate that the TX power level field should be included; have the
* stack fill this value automatically. This is done by assigning the
* special value BLE_HS_ADV_TX_PWR_LVL_AUTO.
*/
adv_fields.tx_pwr_lvl_is_present = 1;
adv_fields.tx_pwr_lvl = BLE_HS_ADV_TX_PWR_LVL_AUTO;
const char *name = ble_svc_gap_device_name();
adv_fields.name = (uint8_t *)name;
adv_fields.name_len = strlen(name);
adv_fields.name_is_complete = 1;
auto rc = ble_gap_adv_set_fields(&adv_fields);
if (rc != 0) {
DEBUG_MSG("error setting advertisement data; rc=%d\n", rc);
return;
}
// add scan response fields
struct ble_hs_adv_fields scan_fields;
memset(&scan_fields, 0, sizeof scan_fields);
scan_fields.uuids128 = const_cast<ble_uuid128_t *>(&mesh_service_uuid);
scan_fields.num_uuids128 = 1;
scan_fields.uuids128_is_complete = 1;
rc = ble_gap_adv_rsp_set_fields(&scan_fields);
if (rc != 0) {
DEBUG_MSG("error setting scan response data; rc=%d\n", rc);
return;
}
/* Begin advertising. */
struct ble_gap_adv_params adv_params;
memset(&adv_params, 0, sizeof adv_params);
adv_params.conn_mode = BLE_GAP_CONN_MODE_UND;
adv_params.disc_mode = BLE_GAP_DISC_MODE_GEN;
// FIXME - use RPA for first parameter
rc = ble_gap_adv_start(own_addr_type, NULL, BLE_HS_FOREVER, &adv_params, gap_event, NULL);
if (rc != 0) {
DEBUG_MSG("error enabling advertisement; rc=%d\n", rc);
return;
}
}
//callback
//doesn't do anything
static void on_reset(int reason)
{
// 19 == BLE_HS_ETIMEOUT_HCI
DEBUG_MSG("Resetting state; reason=%d\n", reason);
}
//callback
//
static void on_sync(void)
{
int rc;
rc = ble_hs_util_ensure_addr(0);
assert(rc == 0);
/* Figure out address to use while advertising (no privacy for now) */
rc = ble_hs_id_infer_auto(0, &own_addr_type);
if (rc != 0) {
DEBUG_MSG("error determining address type; rc=%d\n", rc);
return;
}
/* Printing ADDR */
uint8_t addr_val[6] = {0};
int isPrivate = 0;
rc = ble_hs_id_copy_addr(own_addr_type, addr_val, &isPrivate);
assert(rc == 0);
DEBUG_MSG("BLE advertisting type=%d, Private=%d, Device Address: ", own_addr_type, isPrivate);
print_addr(addr_val);
DEBUG_MSG("\n");
/* Begin advertising. */
advertise();
}
//do the bluetooth tasks
static void ble_host_task(void *param)
{
DEBUG_MSG("BLE task running\n");
nimble_port_run(); // This function will return only when nimble_port_stop() is executed.
// DEBUG_MSG("BLE run complete\n");
nimble_port_freertos_deinit(); // delete the task
}
//saves the stream handles when characteristics are successfully registered
void gatt_svr_register_cb(struct ble_gatt_register_ctxt *ctxt, void *arg)
{
char buf[BLE_UUID_STR_LEN];
switch (ctxt->op) {
case BLE_GATT_REGISTER_OP_SVC:
DEBUG_MSG("registered service %s with handle=%d\n", ble_uuid_to_str(ctxt->svc.svc_def->uuid, buf), ctxt->svc.handle);
break;
case BLE_GATT_REGISTER_OP_CHR:
/* DEBUG_MSG("registering characteristic %s with "
"def_handle=%d val_handle=%d\n",
ble_uuid_to_str(ctxt->chr.chr_def->uuid, buf), ctxt->chr.def_handle, ctxt->chr.val_handle); */
if (ctxt->chr.chr_def->uuid == &fromnum_uuid.u) {
fromNumValHandle = ctxt->chr.val_handle;
// DEBUG_MSG("FromNum handle %d\n", fromNumValHandle);
}
if (ctxt->chr.chr_def->uuid == &update_result_uuid.u) {
updateResultHandle = ctxt->chr.val_handle;
// DEBUG_MSG("update result handle %d\n", updateResultHandle);
}
break;
case BLE_GATT_REGISTER_OP_DSC:
DEBUG_MSG("registering descriptor %s with handle=%d\n", ble_uuid_to_str(ctxt->dsc.dsc_def->uuid, buf), ctxt->dsc.handle);
break;
default:
assert(0);
break;
}
}
/**
* A helper function that implements simple read and write handling for a uint32_t
*
* If a read, the provided value will be returned over bluetooth. If a write, the value from the received packet
* will be written into the variable.
*
* used a few places
*/
int chr_readwrite32le(uint32_t *v, struct ble_gatt_access_ctxt *ctxt)
{
uint8_t le[4];
if (ctxt->op == BLE_GATT_ACCESS_OP_READ_CHR) {
DEBUG_MSG("BLE reading a uint32\n");
put_le32(le, *v);
auto rc = os_mbuf_append(ctxt->om, le, sizeof(le));
assert(rc == 0);
} else if (ctxt->op == BLE_GATT_ACCESS_OP_WRITE_CHR) {
uint16_t len = 0;
auto rc = ble_hs_mbuf_to_flat(ctxt->om, le, sizeof(le), &len);
assert(rc == 0);
if (len < sizeof(le)) {
DEBUG_MSG("Error: wrongsized write32\n");
*v = 0;
return BLE_ATT_ERR_UNLIKELY;
} else {
*v = get_le32(le);
DEBUG_MSG("BLE writing a uint32\n");
}
} else {
DEBUG_MSG("Unexpected readwrite32 op\n");
return BLE_ATT_ERR_UNLIKELY;
}
return 0; // success
}
/**
* A helper for readwrite access to an array of bytes (with no endian conversion)
*/
int chr_readwrite8(uint8_t *v, size_t vlen, struct ble_gatt_access_ctxt *ctxt)
{
if (ctxt->op == BLE_GATT_ACCESS_OP_READ_CHR) {
DEBUG_MSG("BLE reading bytes\n");
auto rc = os_mbuf_append(ctxt->om, v, vlen);
assert(rc == 0);
} else if (ctxt->op == BLE_GATT_ACCESS_OP_WRITE_CHR) {
uint16_t len = 0;
auto rc = ble_hs_mbuf_to_flat(ctxt->om, v, vlen, &len);
assert(rc == 0);
if (len < vlen) {
DEBUG_MSG("Error: wrongsized write\n");
return BLE_ATT_ERR_UNLIKELY;
} else {
DEBUG_MSG("BLE writing bytes\n");
}
} else {
DEBUG_MSG("Unexpected readwrite8 op\n");
return BLE_ATT_ERR_UNLIKELY;
}
return 0; // success
}
void disablePin()
{
DEBUG_MSG("User Override, disabling bluetooth pin requirement\n");
// keep track of when it was pressed, so we know it was within X seconds
// Flash the LED
setLed(true);
delay(100);
setLed(false);
delay(100);
setLed(true);
delay(100);
setLed(false);
delay(100);
setLed(true);
delay(100);
setLed(false);
doublepressed = millis();
}
// This should go somewhere else.
void clearNVS()
{
#ifdef ARCH_ESP32
// As soon as the LED flashing from double click is done, immediately do a tripple click to
// erase nvs memory.
if (doublepressed > (millis() - 2000)) {
DEBUG_MSG("Clearing NVS memory\n");
// This will erase ble pairings, ssl key and persistent preferences.
nvs_flash_erase();
DEBUG_MSG("Restarting...\n");
ESP.restart();
}
#endif
}
// This routine is called multiple times, once each time we come back from sleep
void reinitBluetooth()
{
auto isFirstTime = !bluetoothPhoneAPI;
DEBUG_MSG("Starting bluetooth\n");
if (isFirstTime) {
bluetoothPhoneAPI = new BluetoothPhoneAPI();
}
// FIXME - if waking from light sleep, only esp_nimble_hci_init?
auto res = esp_nimble_hci_and_controller_init(); // : esp_nimble_hci_init();
// DEBUG_MSG("BLE result %d\n", res);
assert(res == ESP_OK);
nimble_port_init();
ble_att_set_preferred_mtu(512);
res = ble_gatts_reset(); // Teardown the service tables, so the next restart assigns the same handle numbers
assert(res == ESP_OK);
/* Initialize the NimBLE host configuration. */
ble_hs_cfg.reset_cb = on_reset;
ble_hs_cfg.sync_cb = on_sync;
ble_hs_cfg.gatts_register_cb = gatt_svr_register_cb;
ble_hs_cfg.store_status_cb = ble_store_util_status_rr;
ble_hs_cfg.sm_io_cap = BLE_SM_IO_CAP_DISP_ONLY;
ble_hs_cfg.sm_bonding = 1;
ble_hs_cfg.sm_mitm = 1;
ble_hs_cfg.sm_sc = 1;
// per https://github.com/espressif/esp-idf/issues/5530#issuecomment-652933685
ble_hs_cfg.sm_our_key_dist = BLE_SM_PAIR_KEY_DIST_ID | BLE_SM_PAIR_KEY_DIST_ENC;
ble_hs_cfg.sm_their_key_dist = BLE_SM_PAIR_KEY_DIST_ID | BLE_SM_PAIR_KEY_DIST_ENC;
// add standard GAP services
ble_svc_gap_init();
ble_svc_gatt_init();
res = ble_gatts_count_cfg(gatt_svr_svcs); // assigns handles? see docstring for note about clearing the handle list
// before calling SLEEP SUPPORT
assert(res == 0);
res = ble_gatts_add_svcs(gatt_svr_svcs);
assert(res == 0);
reinitUpdateService();
/* Set the default device name. */
res = ble_svc_gap_device_name_set(getDeviceName());
assert(res == 0);
/* XXX Need to have template for store */
ble_store_config_init();
nimble_port_freertos_init(ble_host_task);
bluetoothActive = true;
}
bool bluetoothOn;
// Enable/disable bluetooth.
void setBluetoothEnable(bool on)
{
if (on != bluetoothOn) {
DEBUG_MSG("Setting bluetooth enable=%d\n", on);
bluetoothOn = on;
if (on) {
if (!isWifiAvailable()) {
Serial.printf("Pre BT: %u heap size\n", ESP.getFreeHeap());
// ESP_ERROR_CHECK( heap_trace_start(HEAP_TRACE_LEAKS) );
reinitBluetooth();
}
} else {
// shutdown wifi
deinitWifi();
// We have to totally teardown our bluetooth objects to prevent leaks
deinitBLE();
Serial.printf("Shutdown BT: %u heap size\n", ESP.getFreeHeap());
// ESP_ERROR_CHECK( heap_trace_stop() );
// heap_trace_dump();
}
}
}
#if 0
static BLECharacteristic *batteryLevelC;
/**
* Create a battery level service
*/
BLEService *createBatteryService(BLEServer *server)
{
// Create the BLE Service
BLEService *pBattery = server->createService(BLEUUID((uint16_t)0x180F));
batteryLevelC = new BLECharacteristic(BLEUUID((uint16_t)ESP_GATT_UUID_BATTERY_LEVEL),
BLECharacteristic::PROPERTY_READ | BLECharacteristic::PROPERTY_NOTIFY);
addWithDesc(pBattery, batteryLevelC, "Percentage 0 - 100");
batteryLevelC->addDescriptor(addBLEDescriptor(new BLE2902())); // Needed so clients can request notification
// I don't think we need to advertise this? and some phones only see the first thing advertised anyways...
// server->getAdvertising()->addServiceUUID(pBattery->getUUID());
pBattery->start();
return pBattery;
}
/**
* Update the battery level we are currently telling clients.
* level should be a pct between 0 and 100
*/
void updateBatteryLevel(uint8_t level)
{
if (batteryLevelC) {
DEBUG_MSG("set BLE battery level %u\n", level);
batteryLevelC->setValue(&level, 1);
batteryLevelC->notify();
}
}
// Note: these callbacks might be coming in from a different thread.
BLEServer *serve = initBLE(, , getDeviceName(), HW_VENDOR, optstr(APP_VERSION),
optstr(HW_VERSION)); // FIXME, use a real name based on the macaddr
#endif
#endif //#ifndef USE_NEW_ESP32_BLUETOOTH

View File

@@ -1,35 +0,0 @@
#ifndef USE_NEW_ESP32_BLUETOOTH
#pragma once
#include <functional>
/// We only allow one BLE connection at a time
extern int16_t curConnectionHandle;
// TODO(girts): create a class for the bluetooth utils helpers?
using StartBluetoothPinScreenCallback = std::function<void(uint32_t pass_key)>;
using StopBluetoothPinScreenCallback = std::function<void(void)>;
/// Given a level between 0-100, update the BLE attribute
void updateBatteryLevel(uint8_t level);
void deinitBLE();
void loopBLE();
void reinitBluetooth();
void disablePin();
void clearNVS();
/**
* A helper function that implements simple read and write handling for a uint32_t
*
* If a read, the provided value will be returned over bluetooth. If a write, the value from the received packet
* will be written into the variable.
*/
int chr_readwrite32le(uint32_t *v, struct ble_gatt_access_ctxt *ctxt);
/**
* A helper for readwrite access to an array of bytes (with no endian conversion)
*/
int chr_readwrite8(uint8_t *v, size_t vlen, struct ble_gatt_access_ctxt *ctxt);
#endif //#ifndef USE_NEW_ESP32_BLUETOOTH

View File

@@ -0,0 +1,225 @@
#include "configuration.h"
#include "NimbleBluetooth.h"
#include "BluetoothCommon.h"
#include "PowerFSM.h"
#include "sleep.h"
#include "main.h"
#include "mesh/PhoneAPI.h"
#include "mesh/mesh-pb-constants.h"
#include <NimBLEDevice.h>
NimBLECharacteristic *fromNumCharacteristic;
NimBLEServer *bleServer;
static bool passkeyShowing;
static uint32_t doublepressed;
class BluetoothPhoneAPI : public PhoneAPI
{
/**
* Subclasses can use this as a hook to provide custom notifications for their transport (i.e. bluetooth notifies)
*/
virtual void onNowHasData(uint32_t fromRadioNum)
{
PhoneAPI::onNowHasData(fromRadioNum);
DEBUG_MSG("BLE notify fromNum\n");
uint8_t val[4];
put_le32(val, fromRadioNum);
fromNumCharacteristic->setValue(val, sizeof(val));
fromNumCharacteristic->notify();
}
/// Check the current underlying physical link to see if the client is currently connected
virtual bool checkIsConnected()
{
return bleServer && bleServer->getConnectedCount() > 0;
}
};
static BluetoothPhoneAPI *bluetoothPhoneAPI;
/**
* Subclasses can use this as a hook to provide custom notifications for their transport (i.e. bluetooth notifies)
*/
class NimbleBluetoothToRadioCallback : public NimBLECharacteristicCallbacks
{
virtual void onWrite(NimBLECharacteristic *pCharacteristic) {
DEBUG_MSG("To Radio onwrite\n");
auto val = pCharacteristic->getValue();
bluetoothPhoneAPI->handleToRadio(val.data(), val.length());
}
};
class NimbleBluetoothFromRadioCallback : public NimBLECharacteristicCallbacks
{
virtual void onRead(NimBLECharacteristic *pCharacteristic) {
DEBUG_MSG("From Radio onread\n");
uint8_t fromRadioBytes[FromRadio_size];
size_t numBytes = bluetoothPhoneAPI->getFromRadio(fromRadioBytes);
std::string fromRadioByteString(fromRadioBytes, fromRadioBytes + numBytes);
pCharacteristic->setValue(fromRadioByteString);
}
};
class NimbleBluetoothServerCallback : public NimBLEServerCallbacks
{
virtual uint32_t onPassKeyRequest() {
uint32_t passkey = config.bluetooth.fixed_pin;
if (doublepressed > 0 && (doublepressed + (30 * 1000)) > millis()) {
DEBUG_MSG("User has set BLE pairing mode to fixed-pin\n");
config.bluetooth.mode = Config_BluetoothConfig_PairingMode_FixedPin;
nodeDB.saveToDisk();
} else if (config.bluetooth.mode == Config_BluetoothConfig_PairingMode_RandomPin) {
DEBUG_MSG("Using random passkey\n");
// This is the passkey to be entered on peer - we pick a number >100,000 to ensure 6 digits
passkey = random(100000, 999999);
}
DEBUG_MSG("*** Enter passkey %d on the peer side ***\n", passkey);
powerFSM.trigger(EVENT_BLUETOOTH_PAIR);
screen->startBluetoothPinScreen(passkey);
passkeyShowing = true;
return passkey;
}
virtual void onAuthenticationComplete(ble_gap_conn_desc *desc)
{
DEBUG_MSG("BLE authentication complete\n");
if (passkeyShowing) {
passkeyShowing = false;
screen->stopBluetoothPinScreen();
}
// bluetoothPhoneAPI->setInitialState();
}
virtual void onDisconnect(NimBLEServer* pServer, ble_gap_conn_desc *desc)
{
DEBUG_MSG("BLE disconnect\n");
}
};
static NimbleBluetoothToRadioCallback *toRadioCallbacks;
static NimbleBluetoothFromRadioCallback *fromRadioCallbacks;
void NimbleBluetooth::shutdown()
{
// Shutdown bluetooth for minimum power draw
DEBUG_MSG("Disable bluetooth\n");
//Bluefruit.Advertising.stop();
NimBLEAdvertising *pAdvertising = NimBLEDevice::getAdvertising();
pAdvertising->reset();
pAdvertising->stop();
}
bool NimbleBluetooth::isActive()
{
return bleServer;
}
void NimbleBluetooth::setup()
{
// Uncomment for testing
// NimbleBluetooth::clearBonds();
DEBUG_MSG("Initialise the NimBLE bluetooth module\n");
NimBLEDevice::init(getDeviceName());
NimBLEDevice::setPower(ESP_PWR_LVL_P9);
if (config.bluetooth.mode != Config_BluetoothConfig_PairingMode_NoPin) {
NimBLEDevice::setSecurityAuth(true, true, true);
NimBLEDevice::setSecurityIOCap(BLE_HS_IO_DISPLAY_ONLY);
}
bleServer = NimBLEDevice::createServer();
NimbleBluetoothServerCallback *serverCallbacks = new NimbleBluetoothServerCallback();
bleServer->setCallbacks(serverCallbacks, true);
setupService();
startAdvertising();
}
void NimbleBluetooth::setupService()
{
NimBLEService *bleService = bleServer->createService(MESH_SERVICE_UUID);
NimBLECharacteristic *ToRadioCharacteristic;
NimBLECharacteristic *FromRadioCharacteristic;
// Define the characteristics that the app is looking for
if (config.bluetooth.mode == Config_BluetoothConfig_PairingMode_NoPin) {
ToRadioCharacteristic = bleService->createCharacteristic(TORADIO_UUID, NIMBLE_PROPERTY::WRITE);
FromRadioCharacteristic = bleService->createCharacteristic(FROMRADIO_UUID, NIMBLE_PROPERTY::READ);
fromNumCharacteristic = bleService->createCharacteristic(FROMNUM_UUID, NIMBLE_PROPERTY::NOTIFY | NIMBLE_PROPERTY::READ);
}
else {
ToRadioCharacteristic = bleService->createCharacteristic(TORADIO_UUID, NIMBLE_PROPERTY::WRITE | NIMBLE_PROPERTY::WRITE_AUTHEN | NIMBLE_PROPERTY::WRITE_ENC);
FromRadioCharacteristic = bleService->createCharacteristic(FROMRADIO_UUID, NIMBLE_PROPERTY::READ | NIMBLE_PROPERTY::READ_AUTHEN | NIMBLE_PROPERTY::READ_ENC);
fromNumCharacteristic = bleService->createCharacteristic(FROMNUM_UUID, NIMBLE_PROPERTY::NOTIFY | NIMBLE_PROPERTY::READ | NIMBLE_PROPERTY::READ_AUTHEN | NIMBLE_PROPERTY::READ_ENC);
}
bluetoothPhoneAPI = new BluetoothPhoneAPI();
toRadioCallbacks = new NimbleBluetoothToRadioCallback();
ToRadioCharacteristic->setCallbacks(toRadioCallbacks);
fromRadioCallbacks = new NimbleBluetoothFromRadioCallback();
FromRadioCharacteristic->setCallbacks(fromRadioCallbacks);
bleService->start();
}
void NimbleBluetooth::startAdvertising()
{
NimBLEAdvertising *pAdvertising = NimBLEDevice::getAdvertising();
pAdvertising->reset();
pAdvertising->addServiceUUID(MESH_SERVICE_UUID);
pAdvertising->start(0);
}
/// Given a level between 0-100, update the BLE attribute
void updateBatteryLevel(uint8_t level)
{
//blebas.write(level);
}
void NimbleBluetooth::clearBonds()
{
DEBUG_MSG("Clearing bluetooth bonds!\n");
NimBLEDevice::deleteAllBonds();
}
void clearNVS()
{
NimBLEDevice::deleteAllBonds();
#ifdef ARCH_ESP32
ESP.restart();
#endif
}
void disablePin()
{
DEBUG_MSG("User Override, disabling bluetooth pin requirement\n");
// keep track of when it was pressed, so we know it was within X seconds
// Flash the LED
setLed(true);
delay(100);
setLed(false);
delay(100);
setLed(true);
delay(100);
setLed(false);
delay(100);
setLed(true);
delay(100);
setLed(false);
doublepressed = millis();
}

View File

@@ -0,0 +1,18 @@
#pragma once
class NimbleBluetooth
{
public:
void setup();
void shutdown();
void clearBonds();
bool isActive();
private:
void setupService();
void startAdvertising();
};
void setBluetoothEnable(bool on);
void clearNVS();
void disablePin();

View File

@@ -1,75 +0,0 @@
#ifndef USE_NEW_ESP32_BLUETOOTH
#include "NimbleBluetoothAPI.h"
#include "PhoneAPI.h"
#include "configuration.h"
#include "nimble/BluetoothUtil.h"
#include "nimble/NimbleDefs.h"
// This scratch buffer is used for various bluetooth reads/writes - but it is safe because only one bt operation can be in
// proccess at once
static uint8_t trBytes[FromRadio_size < ToRadio_size ? ToRadio_size : FromRadio_size];
static uint32_t fromNum;
uint16_t fromNumValHandle;
/// We only allow one BLE connection at a time
int16_t curConnectionHandle = -1;
PhoneAPI *bluetoothPhoneAPI;
void BluetoothPhoneAPI::onNowHasData(uint32_t fromRadioNum)
{
PhoneAPI::onNowHasData(fromRadioNum);
fromNum = fromRadioNum;
if (curConnectionHandle >= 0 && fromNumValHandle) {
DEBUG_MSG("BLE notify fromNum\n");
auto res = ble_gattc_notify(curConnectionHandle, fromNumValHandle);
assert(res == 0);
} else {
DEBUG_MSG("No BLE notify\n");
}
}
bool BluetoothPhoneAPI::checkIsConnected() {
return curConnectionHandle >= 0;
}
int toradio_callback(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt *ctxt, void *arg)
{
auto om = ctxt->om;
uint16_t len = 0;
auto rc = ble_hs_mbuf_to_flat(om, trBytes, sizeof(trBytes), &len);
if (rc != 0) {
return BLE_ATT_ERR_UNLIKELY;
}
/// DEBUG_MSG("toRadioWriteCb data %p, len %u\n", trBytes, len);
bluetoothPhoneAPI->handleToRadio(trBytes, len);
return 0;
}
int fromradio_callback(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt *ctxt, void *arg)
{
size_t numBytes = bluetoothPhoneAPI->getFromRadio(trBytes);
DEBUG_MSG("BLE fromRadio called omlen=%d, ourlen=%d\n", OS_MBUF_PKTLEN(ctxt->om),
numBytes); // the normal case has omlen 1 here
// Someone is going to read our value as soon as this callback returns. So fill it with the next message in the queue
// or make empty if the queue is empty
auto rc = os_mbuf_append(ctxt->om, trBytes, numBytes);
assert(rc == 0);
return 0; // success
}
int fromnum_callback(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt *ctxt, void *arg)
{
return chr_readwrite32le(&fromNum, ctxt);
}
#endif //#ifndef USE_NEW_ESP32_BLUETOOTH

View File

@@ -1,23 +0,0 @@
#ifndef USE_NEW_ESP32_BLUETOOTH
#pragma once
#include "PhoneAPI.h"
extern uint16_t fromNumValHandle;
class BluetoothPhoneAPI : public PhoneAPI
{
protected:
/**
* Subclasses can use this as a hook to provide custom notifications for their transport (i.e. bluetooth notifies)
*/
virtual void onNowHasData(uint32_t fromRadioNum) override;
/// Check the current underlying physical link to see if the client is currently connected
virtual bool checkIsConnected() override;
};
extern PhoneAPI *bluetoothPhoneAPI;
#endif //#ifndef USE_NEW_ESP32_BLUETOOTH

View File

@@ -1,50 +0,0 @@
#ifndef USE_NEW_ESP32_BLUETOOTH
#include "NimbleDefs.h"
// NRF52 wants these constants as byte arrays
// Generated here https://yupana-engineering.com/online-uuid-to-c-array-converter - but in REVERSE BYTE ORDER
const ble_uuid128_t mesh_service_uuid =
BLE_UUID128_INIT(0xfd, 0xea, 0x73, 0xe2, 0xca, 0x5d, 0xa8, 0x9f, 0x1f, 0x46, 0xa8, 0x15, 0x18, 0xb2, 0xa1, 0x6b);
static const ble_uuid128_t toradio_uuid =
BLE_UUID128_INIT(0xe7, 0x01, 0x44, 0x12, 0x66, 0x78, 0xdd, 0xa1, 0xad, 0x4d, 0x9e, 0x12, 0xd2, 0x76, 0x5c, 0xf7);
static const ble_uuid128_t fromradio_uuid =
BLE_UUID128_INIT(0xd5, 0x54, 0xe4, 0xc5, 0x25, 0xc5, 0x31, 0xa5, 0x55, 0x4a, 0x02, 0xee, 0xc2, 0xbc, 0xa2, 0x8b);
const ble_uuid128_t fromnum_uuid =
BLE_UUID128_INIT(0x53, 0x44, 0xe3, 0x47, 0x75, 0xaa, 0x70, 0xa6, 0x66, 0x4f, 0x00, 0xa8, 0x8c, 0xa1, 0x9d, 0xed);
const struct ble_gatt_svc_def gatt_svr_svcs[] = {
{
/*** Service: Security test. */
.type = BLE_GATT_SVC_TYPE_PRIMARY,
.uuid = &mesh_service_uuid.u,
.characteristics =
(struct ble_gatt_chr_def[]){{
.uuid = &toradio_uuid.u,
.access_cb = toradio_callback,
.flags = BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_WRITE_AUTHEN,
},
{
.uuid = &fromradio_uuid.u,
.access_cb = fromradio_callback,
.flags = BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_READ_AUTHEN,
},
{
.uuid = &fromnum_uuid.u,
.access_cb = fromnum_callback,
.flags = BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_READ_AUTHEN | BLE_GATT_CHR_F_NOTIFY,
},
{
0, /* No more characteristics in this service. */
}},
},
{
0, /* No more services. */
},
};
#endif //#ifndef USE_NEW_ESP32_BLUETOOTH

View File

@@ -1,35 +0,0 @@
#ifndef USE_NEW_ESP32_BLUETOOTH
#pragma once
// Keep nimble #defs from messing up the build
#ifndef max
#define max max
#define min min
#endif
#include "esp_nimble_hci.h"
#include "host/ble_hs.h"
#include "host/ble_uuid.h"
#include "nimble/nimble_port.h"
#include "nimble/nimble_port_freertos.h"
#ifdef __cplusplus
extern "C" {
#endif
int toradio_callback(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt *ctxt, void *arg);
int fromradio_callback(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt *ctxt, void *arg);
int fromnum_callback(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt *ctxt, void *arg);
extern const struct ble_gatt_svc_def gatt_svr_svcs[];
extern const ble_uuid128_t mesh_service_uuid, fromnum_uuid;
#ifdef __cplusplus
};
#endif
#endif //#ifndef USE_NEW_ESP32_BLUETOOTH

View File

@@ -1,160 +0,0 @@
#ifndef USE_NEW_ESP32_BLUETOOTH
#include <Arduino.h>
#include "../concurrency/LockGuard.h"
#include "../graphics/Screen.h"
#include "../main.h"
#include "BluetoothSoftwareUpdate.h"
#include "NodeDB.h"
#include "PowerFSM.h"
#include "RadioLibInterface.h"
#include "configuration.h"
#include "nimble/BluetoothUtil.h"
#include <CRC32.h>
#include <Update.h>
int16_t updateResultHandle = -1;
static CRC32 crc;
static uint32_t updateExpectedSize, updateActualSize;
static uint8_t update_result;
static uint8_t update_region;
static concurrency::Lock *updateLock;
/// Handle writes & reads to total size
int update_size_callback(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt *ctxt, void *arg)
{
concurrency::LockGuard g(updateLock);
// Check if there is enough to OTA Update
chr_readwrite32le(&updateExpectedSize, ctxt);
if (ctxt->op == BLE_GATT_ACCESS_OP_WRITE_CHR && updateExpectedSize != 0) {
updateActualSize = 0;
crc.reset();
if (Update.isRunning())
Update.abort();
bool canBegin = Update.begin(updateExpectedSize, update_region);
DEBUG_MSG("Setting region %d update size %u, result %d\n", update_region, updateExpectedSize, canBegin);
if (!canBegin) {
// Indicate failure by forcing the size to 0 (client will read it back)
updateExpectedSize = 0;
} else {
// This totally breaks abstraction to up up into the app layer for this, but quick hack to make sure we only
// talk to one service during the sw update.
// DEBUG_MSG("FIXME, crufty shutdown of mesh bluetooth for sw update.");
// void stopMeshBluetoothService();
// stopMeshBluetoothService();
screen->startFirmwareUpdateScreen();
if (RadioLibInterface::instance)
RadioLibInterface::instance->disable(); // FIXME, nasty hack - the RF95 ISR/SPI code on ESP32 can fail while we
// are writing flash - shut the radio off during updates
}
}
return 0;
}
#define MAX_BLOCKSIZE_FOR_BT 512
/// Handle writes to data
int update_data_callback(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt *ctxt, void *arg)
{
concurrency::LockGuard g(updateLock);
static uint8_t
data[MAX_BLOCKSIZE_FOR_BT]; // we temporarily copy here because I'm worried that a fast sender might be able overwrite srcbuf
uint16_t len = 0;
auto rc = ble_hs_mbuf_to_flat(ctxt->om, data, sizeof(data), &len);
assert(rc == 0);
// DEBUG_MSG("Writing %u\n", len);
crc.update(data, len);
Update.write(data, len);
updateActualSize += len;
powerFSM.trigger(EVENT_FIRMWARE_UPDATE);
return 0;
}
/// Handle writes to crc32
int update_crc32_callback(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt *ctxt, void *arg)
{
concurrency::LockGuard g(updateLock);
uint32_t expectedCRC = 0;
chr_readwrite32le(&expectedCRC, ctxt);
uint32_t actualCRC = crc.finalize();
DEBUG_MSG("expected CRC %u\n", expectedCRC);
uint8_t result = 0xff;
if (updateActualSize != updateExpectedSize) {
DEBUG_MSG("Expected %u bytes, but received %u bytes!\n", updateExpectedSize, updateActualSize);
result = 0xe1; // FIXME, use real error codes
} else if (actualCRC != expectedCRC) // Check the CRC before asking the update to happen.
{
DEBUG_MSG("Invalid CRC! expected=%u, actual=%u\n", expectedCRC, actualCRC);
result = 0xe0; // FIXME, use real error codes
} else {
if (Update.end()) {
if (update_region == U_SPIFFS) {
DEBUG_MSG("Filesystem updated!\n");
nodeDB.saveToDisk(); // Since we just wiped the filesystem, we need to save our current state
} else {
DEBUG_MSG("Appload updated, rebooting in 5 seconds!\n");
rebootAtMsec = millis() + 5000;
}
} else {
DEBUG_MSG("Error Occurred. Error #: %d\n", Update.getError());
}
result = Update.getError();
}
if (RadioLibInterface::instance)
RadioLibInterface::instance->startReceive(); // Resume radio
assert(updateResultHandle >= 0);
update_result = result;
DEBUG_MSG("BLE notify update result\n");
auto res = ble_gattc_notify(curConnectionHandle, updateResultHandle);
assert(res == 0);
return 0;
}
int update_result_callback(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt *ctxt, void *arg)
{
return chr_readwrite8(&update_result, sizeof(update_result), ctxt);
}
int update_region_callback(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt *ctxt, void *arg)
{
return chr_readwrite8(&update_region, sizeof(update_region), ctxt);
}
/*
See bluetooth-api.md
*/
void reinitUpdateService()
{
if (!updateLock)
updateLock = new concurrency::Lock();
auto res = ble_gatts_count_cfg(gatt_update_svcs); // assigns handles? see docstring for note about clearing the handle list
// before calling SLEEP SUPPORT
assert(res == 0);
res = ble_gatts_add_svcs(gatt_update_svcs);
assert(res == 0);
}
#endif //#ifndef USE_NEW_ESP32_BLUETOOTH

View File

@@ -1,29 +0,0 @@
#ifndef USE_NEW_ESP32_BLUETOOTH
#pragma once
#include "nimble/NimbleDefs.h"
void reinitUpdateService();
#ifdef __cplusplus
extern "C" {
#endif
int update_size_callback(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt *ctxt, void *arg);
int update_data_callback(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt *ctxt, void *arg);
int update_result_callback(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt *ctxt, void *arg);
int update_crc32_callback(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt *ctxt, void *arg);
int update_region_callback(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt *ctxt, void *arg);
extern const struct ble_gatt_svc_def gatt_update_svcs[];
extern const ble_uuid128_t update_result_uuid, update_region_uuid;
extern int16_t updateResultHandle;
#ifdef __cplusplus
};
#endif
#endif //#ifndef USE_NEW_ESP32_BLUETOOTH

View File

@@ -1,264 +0,0 @@
#ifdef USE_NEW_ESP32_BLUETOOTH
#include "configuration.h"
#include "ESP32Bluetooth.h"
#include "BluetoothCommon.h"
#include "PowerFSM.h"
#include "sleep.h"
#include "main.h"
#include "mesh/PhoneAPI.h"
#include "mesh/mesh-pb-constants.h"
#include <NimBLEDevice.h>
//static BLEService meshBleService = BLEService(BLEUuid(MESH_SERVICE_UUID_16));
//static BLECharacteristic fromNum = BLECharacteristic(BLEUuid(FROMNUM_UUID_16));
//static BLECharacteristic fromRadio = BLECharacteristic(BLEUuid(FROMRADIO_UUID_16));
//static BLECharacteristic toRadio = BLECharacteristic(BLEUuid(TORADIO_UUID_16));
//static BLEDis bledis; // DIS (Device Information Service) helper class instance
//static BLEBas blebas; // BAS (Battery Service) helper class instance
//static BLEDfu bledfu; // DFU software update helper service
// This scratch buffer is used for various bluetooth reads/writes - but it is safe because only one bt operation can be in
// proccess at once
// static uint8_t trBytes[_max(_max(_max(_max(ToRadio_size, RadioConfig_size), User_size), MyNodeInfo_size), FromRadio_size)];
static uint8_t fromRadioBytes[FromRadio_size];
NimBLECharacteristic *FromNumCharacteristic;
NimBLEServer *bleServer;
static bool passkeyShowing;
static uint32_t doublepressed;
/**
* Subclasses can use this as a hook to provide custom notifications for their transport (i.e. bluetooth notifies)
*/
void BluetoothPhoneAPI::onNowHasData(uint32_t fromRadioNum)
{
PhoneAPI::onNowHasData(fromRadioNum);
DEBUG_MSG("BLE notify fromNum\n");
//fromNum.notify32(fromRadioNum);
uint8_t val[4];
put_le32(val, fromRadioNum);
std::string fromNumByteString(&val[0], &val[0] + sizeof(val));
FromNumCharacteristic->setValue(fromNumByteString);
FromNumCharacteristic->notify();
}
/// Check the current underlying physical link to see if the client is currently connected
bool BluetoothPhoneAPI::checkIsConnected() {
if (bleServer && bleServer->getConnectedCount() > 0) {
return true;
}
return false;
}
PhoneAPI *bluetoothPhoneAPI;
class ESP32BluetoothToRadioCallback : public NimBLECharacteristicCallbacks {
virtual void onWrite(NimBLECharacteristic *pCharacteristic) {
DEBUG_MSG("To Radio onwrite\n");
auto val = pCharacteristic->getValue();
bluetoothPhoneAPI->handleToRadio(val.data(), val.length());
}
};
class ESP32BluetoothFromRadioCallback : public NimBLECharacteristicCallbacks {
virtual void onRead(NimBLECharacteristic *pCharacteristic) {
DEBUG_MSG("From Radio onread\n");
size_t numBytes = bluetoothPhoneAPI->getFromRadio(fromRadioBytes);
std::string fromRadioByteString(fromRadioBytes, fromRadioBytes + numBytes);
pCharacteristic->setValue(fromRadioByteString);
}
};
class ESP32BluetoothServerCallback : public NimBLEServerCallbacks {
virtual uint32_t onPassKeyRequest() {
uint32_t passkey = 0;
if (doublepressed > 0 && (doublepressed + (30 * 1000)) > millis()) {
DEBUG_MSG("User has overridden passkey\n");
passkey = defaultBLEPin;
} else {
DEBUG_MSG("Using random passkey\n");
passkey = random(
100000, 999999); // This is the passkey to be entered on peer - we pick a number >100,000 to ensure 6 digits
}
DEBUG_MSG("*** Enter passkey %d on the peer side ***\n", passkey);
powerFSM.trigger(EVENT_BLUETOOTH_PAIR);
screen->startBluetoothPinScreen(passkey);
passkeyShowing = true;
return passkey;
}
virtual void onAuthenticationComplete(ble_gap_conn_desc *desc) {
DEBUG_MSG("BLE authentication complete\n");
if (passkeyShowing) {
passkeyShowing = false;
screen->stopBluetoothPinScreen();
}
}
virtual void onDisconnect(NimBLEServer* pServer, ble_gap_conn_desc *desc) {
DEBUG_MSG("BLE disconnect\n");
}
};
static ESP32BluetoothToRadioCallback *toRadioCallbacks;
static ESP32BluetoothFromRadioCallback *fromRadioCallbacks;
void ESP32Bluetooth::shutdown()
{
// Shutdown bluetooth for minimum power draw
DEBUG_MSG("Disable bluetooth\n");
//Bluefruit.Advertising.stop();
NimBLEAdvertising *pAdvertising = NimBLEDevice::getAdvertising();
pAdvertising->reset();
pAdvertising->stop();
}
void ESP32Bluetooth::setup()
{
// Initialise the Bluefruit module
DEBUG_MSG("Initialise the ESP32 bluetooth module\n");
//Bluefruit.autoConnLed(false);
//Bluefruit.begin();
// Set the advertised device name (keep it short!)
//Bluefruit.setName(getDeviceName());
// Set the connect/disconnect callback handlers
//Bluefruit.Periph.setConnectCallback(connect_callback);
//Bluefruit.Periph.setDisconnectCallback(disconnect_callback);
// Configure and Start the Device Information Service
DEBUG_MSG("Configuring the Device Information Service\n");
// FIXME, we should set a mfg string based on our HW_VENDOR enum
// bledis.setManufacturer(HW_VENDOR);
//bledis.setModel(optstr(HW_VERSION));
//bledis.setFirmwareRev(optstr(APP_VERSION));
//bledis.begin();
// Start the BLE Battery Service and set it to 100%
//DEBUG_MSG("Configuring the Battery Service\n");
//blebas.begin();
//blebas.write(0); // Unknown battery level for now
//bledfu.begin(); // Install the DFU helper
// Setup the Heart Rate Monitor service using
// BLEService and BLECharacteristic classes
DEBUG_MSG("Configuring the Mesh bluetooth service\n");
//setupMeshService();
// Supposedly debugging works with soft device if you disable advertising
//if (isSoftDeviceAllowed) {
// Setup the advertising packet(s)
// DEBUG_MSG("Setting up the advertising payload(s)\n");
// startAdv();
// DEBUG_MSG("Advertising\n");
//}
//NimBLEDevice::deleteAllBonds();
NimBLEDevice::init(getDeviceName());
NimBLEDevice::setPower(ESP_PWR_LVL_P9);
NimBLEDevice::setSecurityAuth(true, true, true);
NimBLEDevice::setSecurityIOCap(BLE_HS_IO_DISPLAY_ONLY);
bleServer = NimBLEDevice::createServer();
ESP32BluetoothServerCallback *serverCallbacks = new ESP32BluetoothServerCallback();
bleServer->setCallbacks(serverCallbacks, true);
NimBLEService *bleService = bleServer->createService(MESH_SERVICE_UUID);
//NimBLECharacteristic *pNonSecureCharacteristic = bleService->createCharacteristic("1234", NIMBLE_PROPERTY::READ );
//NimBLECharacteristic *pSecureCharacteristic = bleService->createCharacteristic("1235", NIMBLE_PROPERTY::READ | NIMBLE_PROPERTY::READ_ENC | NIMBLE_PROPERTY::READ_AUTHEN);
//define the characteristics that the app is looking for
NimBLECharacteristic *ToRadioCharacteristic = bleService->createCharacteristic(TORADIO_UUID, NIMBLE_PROPERTY::WRITE | NIMBLE_PROPERTY::WRITE_AUTHEN | NIMBLE_PROPERTY::WRITE_ENC);
NimBLECharacteristic *FromRadioCharacteristic = bleService->createCharacteristic(FROMRADIO_UUID, NIMBLE_PROPERTY::READ | NIMBLE_PROPERTY::READ_AUTHEN | NIMBLE_PROPERTY::READ_ENC);
FromNumCharacteristic = bleService->createCharacteristic(FROMNUM_UUID, NIMBLE_PROPERTY::NOTIFY | NIMBLE_PROPERTY::READ | NIMBLE_PROPERTY::READ_AUTHEN | NIMBLE_PROPERTY::READ_ENC);
bluetoothPhoneAPI = new BluetoothPhoneAPI();
toRadioCallbacks = new ESP32BluetoothToRadioCallback();
ToRadioCharacteristic->setCallbacks(toRadioCallbacks);
fromRadioCallbacks = new ESP32BluetoothFromRadioCallback();
FromRadioCharacteristic->setCallbacks(fromRadioCallbacks);
//uint8_t val[4];
//uint32_t zero = 0;
//put_le32(val, zero);
//std::string fromNumByteString(&val[0], &val[0] + sizeof(val));
//FromNumCharacteristic->setValue(fromNumByteString);
bleService->start();
//pNonSecureCharacteristic->setValue("Hello Non Secure BLE");
//pSecureCharacteristic->setValue("Hello Secure BLE");
//FromRadioCharacteristic->setValue("FromRadioString");
//ToRadioCharacteristic->setCallbacks()
NimBLEAdvertising *pAdvertising = NimBLEDevice::getAdvertising();
pAdvertising->reset();
pAdvertising->addServiceUUID(MESH_SERVICE_UUID);
pAdvertising->start(0);
}
/// Given a level between 0-100, update the BLE attribute
void updateBatteryLevel(uint8_t level)
{
//blebas.write(level);
}
void ESP32Bluetooth::clearBonds()
{
DEBUG_MSG("Clearing bluetooth bonds!\n");
//bond_print_list(BLE_GAP_ROLE_PERIPH);
//bond_print_list(BLE_GAP_ROLE_CENTRAL);
//Bluefruit.Periph.clearBonds();
//Bluefruit.Central.clearBonds();
NimBLEDevice::deleteAllBonds();
}
void clearNVS() {
NimBLEDevice::deleteAllBonds();
ESP.restart();
}
void disablePin() {
DEBUG_MSG("User Override, disabling bluetooth pin requirement\n");
// keep track of when it was pressed, so we know it was within X seconds
// Flash the LED
setLed(true);
delay(100);
setLed(false);
delay(100);
setLed(true);
delay(100);
setLed(false);
delay(100);
setLed(true);
delay(100);
setLed(false);
doublepressed = millis();
}
#endif

View File

@@ -1,33 +0,0 @@
#ifdef USE_NEW_ESP32_BLUETOOTH
#pragma once
extern uint16_t fromNumValHandle;
class BluetoothPhoneAPI : public PhoneAPI
{
protected:
/**
* Subclasses can use this as a hook to provide custom notifications for their transport (i.e. bluetooth notifies)
*/
virtual void onNowHasData(uint32_t fromRadioNum) override;
/// Check the current underlying physical link to see if the client is currently connected
virtual bool checkIsConnected() override;
};
extern PhoneAPI *bluetoothPhoneAPI;
class ESP32Bluetooth
{
public:
void setup();
void shutdown();
void clearBonds();
};
void setBluetoothEnable(bool on);
void clearNVS();
void disablePin();
#endif

View File

@@ -1,73 +0,0 @@
#ifndef USE_NEW_ESP32_BLUETOOTH
#include "BluetoothSoftwareUpdate.h"
// NRF52 wants these constants as byte arrays
// Generated here https://yupana-engineering.com/online-uuid-to-c-array-converter - but in REVERSE BYTE ORDER
// "cb0b9a0b-a84c-4c0d-bdbb-442e3144ee30"
const ble_uuid128_t update_service_uuid =
BLE_UUID128_INIT(0x30, 0xee, 0x44, 0x31, 0x2e, 0x44, 0xbb, 0xbd, 0x0d, 0x4c, 0x4c, 0xa8, 0x0b, 0x9a, 0x0b, 0xcb);
// "e74dd9c0-a301-4a6f-95a1-f0e1dbea8e1e" write|read
const ble_uuid128_t update_size_uuid =
BLE_UUID128_INIT(0x1e, 0x8e, 0xea, 0xdb, 0xe1, 0xf0, 0xa1, 0x95, 0x6f, 0x4a, 0x01, 0xa3, 0xc0, 0xd9, 0x4d, 0xe7);
// "e272ebac-d463-4b98-bc84-5cc1a39ee517" write
const ble_uuid128_t update_data_uuid =
BLE_UUID128_INIT(0x17, 0xe5, 0x9e, 0xa3, 0xc1, 0x5c, 0x84, 0xbc, 0x98, 0x4b, 0x63, 0xd4, 0xac, 0xeb, 0x72, 0xe2);
// "4826129c-c22a-43a3-b066-ce8f0d5bacc6" write
const ble_uuid128_t update_crc32_uuid =
BLE_UUID128_INIT(0xc6, 0xac, 0x5b, 0x0d, 0x8f, 0xce, 0x66, 0xb0, 0xa3, 0x43, 0x2a, 0xc2, 0x9c, 0x12, 0x26, 0x48);
// "5e134862-7411-4424-ac4a-210937432c77" read|notify
const ble_uuid128_t update_result_uuid =
BLE_UUID128_INIT(0x77, 0x2c, 0x43, 0x37, 0x09, 0x21, 0x4a, 0xac, 0x24, 0x44, 0x11, 0x74, 0x62, 0x48, 0x13, 0x5e);
// "5e134862-7411-4424-ac4a-210937432c67" write
const ble_uuid128_t update_region_uuid =
BLE_UUID128_INIT(0x67, 0x2c, 0x43, 0x37, 0x09, 0x21, 0x4a, 0xac, 0x24, 0x44, 0x11, 0x74, 0x62, 0x48, 0x13, 0x5e);
const struct ble_gatt_svc_def gatt_update_svcs[] = {
{
/*** Service: Security test. */
.type = BLE_GATT_SVC_TYPE_PRIMARY,
.uuid = &update_service_uuid.u,
.characteristics =
(struct ble_gatt_chr_def[]){{
.uuid = &update_size_uuid.u,
.access_cb = update_size_callback,
.flags = BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_WRITE_AUTHEN | BLE_GATT_CHR_F_READ |
BLE_GATT_CHR_F_READ_AUTHEN,
},
{
.uuid = &update_data_uuid.u,
.access_cb = update_data_callback,
.flags = BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_WRITE_AUTHEN,
},
{
.uuid = &update_crc32_uuid.u,
.access_cb = update_crc32_callback,
.flags = BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_WRITE_AUTHEN,
},
{
.uuid = &update_result_uuid.u,
.access_cb = update_result_callback,
.flags = BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_READ_AUTHEN | BLE_GATT_CHR_F_NOTIFY,
},
{
.uuid = &update_region_uuid.u,
.access_cb = update_region_callback,
.flags = BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_WRITE_AUTHEN,
},
{
0, /* No more characteristics in this service. */
}},
},
{
0, /* No more services. */
},
};
#endif //#ifndef USE_NEW_ESP32_BLUETOOTH

View File

@@ -6,6 +6,9 @@
// defaults for ESP32 architecture // defaults for ESP32 architecture
// //
#ifndef HAS_BLUETOOTH
#define HAS_BLUETOOTH 1
#endif
#ifndef HAS_WIFI #ifndef HAS_WIFI
#define HAS_WIFI 1 #define HAS_WIFI 1
#endif #endif

View File

@@ -1,15 +1,10 @@
#include "BluetoothSoftwareUpdate.h"
#include "PowerFSM.h" #include "PowerFSM.h"
#include "configuration.h" #include "configuration.h"
#include "esp_task_wdt.h" #include "esp_task_wdt.h"
#include "main.h" #include "main.h"
#ifdef USE_NEW_ESP32_BLUETOOTH #include "nimble/NimbleBluetooth.h"
#include "ESP32Bluetooth.h"
#include "mesh/http/WiFiAPClient.h" #include "mesh/http/WiFiAPClient.h"
#else
#include "nimble/BluetoothUtil.h"
#endif
#include "sleep.h" #include "sleep.h"
#include "target_specific.h" #include "target_specific.h"
@@ -19,41 +14,26 @@
#include <nvs.h> #include <nvs.h>
#include <nvs_flash.h> #include <nvs_flash.h>
#ifdef USE_NEW_ESP32_BLUETOOTH NimbleBluetooth *nimbleBluetooth;
ESP32Bluetooth *esp32Bluetooth;
#endif
void getMacAddr(uint8_t *dmac) void getMacAddr(uint8_t *dmac)
{ {
assert(esp_efuse_mac_get_default(dmac) == ESP_OK); assert(esp_efuse_mac_get_default(dmac) == ESP_OK);
} }
/*
static void printBLEinfo() {
int dev_num = esp_ble_get_bond_device_num();
esp_ble_bond_dev_t *dev_list = (esp_ble_bond_dev_t *)malloc(sizeof(esp_ble_bond_dev_t) * dev_num);
esp_ble_get_bond_device_list(&dev_num, dev_list);
for (int i = 0; i < dev_num; i++) {
// esp_ble_remove_bond_device(dev_list[i].bd_addr);
}
} */
#ifdef USE_NEW_ESP32_BLUETOOTH
void setBluetoothEnable(bool on) { void setBluetoothEnable(bool on) {
if (!isWifiAvailable()) { if (!isWifiAvailable() && config.bluetooth.enabled == true) {
if (!esp32Bluetooth) { if (!nimbleBluetooth) {
esp32Bluetooth = new ESP32Bluetooth(); nimbleBluetooth = new NimbleBluetooth();
} }
if (on) { if (on && !nimbleBluetooth->isActive()) {
esp32Bluetooth->setup(); nimbleBluetooth->setup();
} else { } else if (!on) {
esp32Bluetooth->shutdown(); nimbleBluetooth->shutdown();
} }
} }
} }
#endif
void esp32Setup() void esp32Setup()
{ {
@@ -123,7 +103,6 @@ Periodic axpDebugOutput(axpDebugRead);
void esp32Loop() void esp32Loop()
{ {
esp_task_wdt_reset(); // service our app level watchdog esp_task_wdt_reset(); // service our app level watchdog
//loopBLE();
// for debug printing // for debug printing
// radio.radioIf.canSleep(); // radio.radioIf.canSleep();

View File

@@ -22,7 +22,7 @@ static BLEDfu bledfu; // DFU software update helper service
static uint8_t fromRadioBytes[FromRadio_size]; static uint8_t fromRadioBytes[FromRadio_size];
static uint8_t toRadioBytes[ToRadio_size]; static uint8_t toRadioBytes[ToRadio_size];
static bool bleConnected; static uint16_t connectionHandle;
class BluetoothPhoneAPI : public PhoneAPI class BluetoothPhoneAPI : public PhoneAPI
{ {
@@ -39,22 +39,23 @@ class BluetoothPhoneAPI : public PhoneAPI
/// Check the current underlying physical link to see if the client is currently connected /// Check the current underlying physical link to see if the client is currently connected
virtual bool checkIsConnected() override { virtual bool checkIsConnected() override {
return bleConnected; BLEConnection *connection = Bluefruit.Connection(connectionHandle);
return connection->connected();
} }
}; };
static BluetoothPhoneAPI *bluetoothPhoneAPI; static BluetoothPhoneAPI *bluetoothPhoneAPI;
void connect_callback(uint16_t conn_handle) void onConnect(uint16_t conn_handle)
{ {
// Get the reference to current connection // Get the reference to current connection
BLEConnection *connection = Bluefruit.Connection(conn_handle); BLEConnection *connection = Bluefruit.Connection(conn_handle);
connectionHandle = conn_handle;
char central_name[32] = {0}; char central_name[32] = {0};
connection->getPeerName(central_name, sizeof(central_name)); connection->getPeerName(central_name, sizeof(central_name));
DEBUG_MSG("BLE Connected to %s\n", central_name); DEBUG_MSG("BLE Connected to %s\n", central_name);
bleConnected = true;
} }
/** /**
@@ -62,15 +63,13 @@ void connect_callback(uint16_t conn_handle)
* @param conn_handle connection where this event happens * @param conn_handle connection where this event happens
* @param reason is a BLE_HCI_STATUS_CODE which can be found in ble_hci.h * @param reason is a BLE_HCI_STATUS_CODE which can be found in ble_hci.h
*/ */
void disconnect_callback(uint16_t conn_handle, uint8_t reason) void onDisconnect(uint16_t conn_handle, uint8_t reason)
{ {
// FIXME - we currently assume only one active connection // FIXME - we currently assume only one active connection
bleConnected = false;
DEBUG_MSG("BLE Disconnected, reason = 0x%x\n", reason); DEBUG_MSG("BLE Disconnected, reason = 0x%x\n", reason);
} }
void cccd_callback(uint16_t conn_hdl, BLECharacteristic *chr, uint16_t cccd_value) void onCccd(uint16_t conn_hdl, BLECharacteristic *chr, uint16_t cccd_value)
{ {
// Display the raw request packet // Display the raw request packet
DEBUG_MSG("CCCD Updated: %u\n", cccd_value); DEBUG_MSG("CCCD Updated: %u\n", cccd_value);
@@ -126,16 +125,12 @@ static void authorizeRead(uint16_t conn_hdl)
/** /**
* client is starting read, pull the bytes from our API class * client is starting read, pull the bytes from our API class
*/ */
void fromRadioAuthorizeCb(uint16_t conn_hdl, BLECharacteristic *chr, ble_gatts_evt_read_t *request) void onFromRadioAuthorize(uint16_t conn_hdl, BLECharacteristic *chr, ble_gatts_evt_read_t *request)
{ {
if (request->offset == 0) { if (request->offset == 0) {
// If the read is long, we will get multiple authorize invocations - we only populate data on the first // If the read is long, we will get multiple authorize invocations - we only populate data on the first
size_t numBytes = bluetoothPhoneAPI->getFromRadio(fromRadioBytes); size_t numBytes = bluetoothPhoneAPI->getFromRadio(fromRadioBytes);
// DEBUG_MSG("fromRadioAuthorizeCb numBytes=%u\n", numBytes);
// if (numBytes >= 2) DEBUG_MSG("fromRadio bytes %x %x\n", fromRadioBytes[0], fromRadioBytes[1]);
// Someone is going to read our value as soon as this callback returns. So fill it with the next message in the queue // Someone is going to read our value as soon as this callback returns. So fill it with the next message in the queue
// or make empty if the queue is empty // or make empty if the queue is empty
fromRadio.write(fromRadioBytes, numBytes); fromRadio.write(fromRadioBytes, numBytes);
@@ -145,7 +140,7 @@ void fromRadioAuthorizeCb(uint16_t conn_hdl, BLECharacteristic *chr, ble_gatts_e
authorizeRead(conn_hdl); authorizeRead(conn_hdl);
} }
void toRadioWriteCb(uint16_t conn_hdl, BLECharacteristic *chr, uint8_t *data, uint16_t len) void onToRadioWrite(uint16_t conn_hdl, BLECharacteristic *chr, uint8_t *data, uint16_t len)
{ {
DEBUG_MSG("toRadioWriteCb data %p, len %u\n", data, len); DEBUG_MSG("toRadioWriteCb data %p, len %u\n", data, len);
@@ -155,7 +150,7 @@ void toRadioWriteCb(uint16_t conn_hdl, BLECharacteristic *chr, uint8_t *data, ui
/** /**
* client is starting read, pull the bytes from our API class * client is starting read, pull the bytes from our API class
*/ */
void fromNumAuthorizeCb(uint16_t conn_hdl, BLECharacteristic *chr, ble_gatts_evt_read_t *request) void onFromNumAuthorize(uint16_t conn_hdl, BLECharacteristic *chr, ble_gatts_evt_read_t *request)
{ {
DEBUG_MSG("fromNumAuthorizeCb\n"); DEBUG_MSG("fromNumAuthorizeCb\n");
@@ -172,44 +167,39 @@ void setupMeshService(void)
// any characteristic(s) within that service definition.. Calling .begin() on // any characteristic(s) within that service definition.. Calling .begin() on
// a BLECharacteristic will cause it to be added to the last BLEService that // a BLECharacteristic will cause it to be added to the last BLEService that
// was 'begin()'ed! // was 'begin()'ed!
auto secMode = config.bluetooth.mode == Config_BluetoothConfig_PairingMode_NoPin ? SECMODE_OPEN : SECMODE_ENC_NO_MITM;
fromNum.setProperties(CHR_PROPS_NOTIFY | CHR_PROPS_READ); fromNum.setProperties(CHR_PROPS_NOTIFY | CHR_PROPS_READ);
fromNum.setPermission(SECMODE_OPEN, SECMODE_NO_ACCESS); // FIXME, secure this!!! fromNum.setPermission(secMode, SECMODE_NO_ACCESS); // FIXME, secure this!!!
fromNum.setFixedLen( fromNum.setFixedLen(0); // Variable len (either 0 or 4) FIXME consider changing protocol so it is fixed 4 byte len, where 0 means empty
0); // Variable len (either 0 or 4) FIXME consider changing protocol so it is fixed 4 byte len, where 0 means empty
fromNum.setMaxLen(4); fromNum.setMaxLen(4);
fromNum.setCccdWriteCallback(cccd_callback); // Optionally capture CCCD updates fromNum.setCccdWriteCallback(onCccd); // Optionally capture CCCD updates
// We don't yet need to hook the fromNum auth callback // We don't yet need to hook the fromNum auth callback
// fromNum.setReadAuthorizeCallback(fromNumAuthorizeCb); // fromNum.setReadAuthorizeCallback(fromNumAuthorizeCb);
fromNum.write32(0); // Provide default fromNum of 0 fromNum.write32(0); // Provide default fromNum of 0
fromNum.begin(); fromNum.begin();
// uint8_t hrmdata[2] = {0b00000110, 0x40}; // Set the characteristic to use 8-bit values, with the sensor connected and
// detected
// hrmc.write(hrmdata, 2);
fromRadio.setProperties(CHR_PROPS_READ); fromRadio.setProperties(CHR_PROPS_READ);
fromRadio.setPermission(SECMODE_OPEN, SECMODE_NO_ACCESS); // FIXME secure this! fromRadio.setPermission(secMode, SECMODE_NO_ACCESS);
fromRadio.setMaxLen(sizeof(fromRadioBytes)); fromRadio.setMaxLen(sizeof(fromRadioBytes));
fromRadio.setReadAuthorizeCallback( fromRadio.setReadAuthorizeCallback(onFromRadioAuthorize, false); // We don't call this callback via the adafruit queue, because we can safely run in the BLE context
fromRadioAuthorizeCb,
false); // We don't call this callback via the adafruit queue, because we can safely run in the BLE context
fromRadio.setBuffer(fromRadioBytes, sizeof(fromRadioBytes)); // we preallocate our fromradio buffer so we won't waste space fromRadio.setBuffer(fromRadioBytes, sizeof(fromRadioBytes)); // we preallocate our fromradio buffer so we won't waste space
// for two copies // for two copies
fromRadio.begin(); fromRadio.begin();
toRadio.setProperties(CHR_PROPS_WRITE); toRadio.setProperties(CHR_PROPS_WRITE);
toRadio.setPermission(SECMODE_OPEN, SECMODE_OPEN); // FIXME secure this! toRadio.setPermission(secMode, secMode); // FIXME secure this!
toRadio.setFixedLen(0); toRadio.setFixedLen(0);
toRadio.setMaxLen(512); toRadio.setMaxLen(512);
toRadio.setBuffer(toRadioBytes, sizeof(toRadioBytes)); toRadio.setBuffer(toRadioBytes, sizeof(toRadioBytes));
toRadio.setWriteCallback( // We don't call this callback via the adafruit queue, because we can safely run in the BLE context
toRadioWriteCb, toRadio.setWriteCallback(onToRadioWrite, false);
false); // We don't call this callback via the adafruit queue, because we can safely run in the BLE context
toRadio.begin(); toRadio.begin();
} }
// FIXME, turn off soft device access for debugging // FIXME, turn off soft device access for debugging
static bool isSoftDeviceAllowed = true; static bool isSoftDeviceAllowed = true;
static uint32_t configuredPasskey;
void NRF52Bluetooth::shutdown() void NRF52Bluetooth::shutdown()
{ {
@@ -221,8 +211,9 @@ void NRF52Bluetooth::shutdown()
void NRF52Bluetooth::setup() void NRF52Bluetooth::setup()
{ {
// Initialise the Bluefruit module // Initialise the Bluefruit module
DEBUG_MSG("Initialise the Bluefruit nRF52 module\n"); DEBUG_MSG("Initialize the Bluefruit nRF52 module\n");
Bluefruit.autoConnLed(false); Bluefruit.autoConnLed(false);
Bluefruit.configPrphBandwidth(BANDWIDTH_MAX);
Bluefruit.begin(); Bluefruit.begin();
// Clear existing data. // Clear existing data.
@@ -230,17 +221,31 @@ void NRF52Bluetooth::setup()
Bluefruit.Advertising.clearData(); Bluefruit.Advertising.clearData();
Bluefruit.ScanResponse.clearData(); Bluefruit.ScanResponse.clearData();
if (config.bluetooth.mode != Config_BluetoothConfig_PairingMode_NoPin) {
configuredPasskey = config.bluetooth.mode == Config_BluetoothConfig_PairingMode_FixedPin ?
config.bluetooth.fixed_pin : random(100000, 999999);
auto pinString = std::to_string(configuredPasskey);
DEBUG_MSG("Bluetooth pin set to '%i'\n", configuredPasskey);
Bluefruit.Security.setPIN(pinString.c_str());
Bluefruit.Security.setIOCaps(true, false, false);
Bluefruit.Security.setPairPasskeyCallback(NRF52Bluetooth::onPairingPasskey);
Bluefruit.Security.setPairCompleteCallback(NRF52Bluetooth::onPairingCompleted);
Bluefruit.Security.setSecuredCallback(NRF52Bluetooth::onConnectionSecured);
meshBleService.setPermission(SECMODE_ENC_WITH_MITM, SECMODE_ENC_WITH_MITM);
}
else {
Bluefruit.Security.setIOCaps(false, false, false);
meshBleService.setPermission(SECMODE_OPEN, SECMODE_OPEN);
}
// Set the advertised device name (keep it short!) // Set the advertised device name (keep it short!)
Bluefruit.setName(getDeviceName()); Bluefruit.setName(getDeviceName());
// Set the connect/disconnect callback handlers // Set the connect/disconnect callback handlers
Bluefruit.Periph.setConnectCallback(connect_callback); Bluefruit.Periph.setConnectCallback(onConnect);
Bluefruit.Periph.setDisconnectCallback(disconnect_callback); Bluefruit.Periph.setDisconnectCallback(onDisconnect);
// Configure and Start the Device Information Service // Configure and Start the Device Information Service
DEBUG_MSG("Configuring the Device Information Service\n"); DEBUG_MSG("Configuring the Device Information Service\n");
// FIXME, we should set a mfg string based on our HW_VENDOR enum
// bledis.setManufacturer(HW_VENDOR);
bledis.setModel(optstr(HW_VERSION)); bledis.setModel(optstr(HW_VERSION));
bledis.setFirmwareRev(optstr(APP_VERSION)); bledis.setFirmwareRev(optstr(APP_VERSION));
bledis.begin(); bledis.begin();
@@ -249,7 +254,6 @@ void NRF52Bluetooth::setup()
DEBUG_MSG("Configuring the Battery Service\n"); DEBUG_MSG("Configuring the Battery Service\n");
blebas.begin(); blebas.begin();
blebas.write(0); // Unknown battery level for now blebas.write(0); // Unknown battery level for now
bledfu.begin(); // Install the DFU helper bledfu.begin(); // Install the DFU helper
// Setup the Heart Rate Monitor service using // Setup the Heart Rate Monitor service using
@@ -258,7 +262,8 @@ void NRF52Bluetooth::setup()
setupMeshService(); setupMeshService();
// Supposedly debugging works with soft device if you disable advertising // Supposedly debugging works with soft device if you disable advertising
if (isSoftDeviceAllowed) { if (isSoftDeviceAllowed)
{
// Setup the advertising packet(s) // Setup the advertising packet(s)
DEBUG_MSG("Setting up the advertising payload(s)\n"); DEBUG_MSG("Setting up the advertising payload(s)\n");
startAdv(); startAdv();
@@ -282,3 +287,35 @@ void NRF52Bluetooth::clearBonds()
Bluefruit.Periph.clearBonds(); Bluefruit.Periph.clearBonds();
Bluefruit.Central.clearBonds(); Bluefruit.Central.clearBonds();
} }
void NRF52Bluetooth::onConnectionSecured(uint16_t conn_handle)
{
DEBUG_MSG("BLE connection secured\n");
}
bool NRF52Bluetooth::onPairingPasskey(uint16_t conn_handle, uint8_t const passkey[6], bool match_request)
{
DEBUG_MSG("BLE pairing process started with passkey %.3s %.3s\n", passkey, passkey+3);
screen->startBluetoothPinScreen(configuredPasskey);
if (match_request)
{
uint32_t start_time = millis();
while(millis() < start_time + 30000)
{
if (!Bluefruit.connected(conn_handle)) break;
}
}
DEBUG_MSG("BLE passkey pairing: match_request=%i\n", match_request);
return true;
}
void NRF52Bluetooth::onPairingCompleted(uint16_t conn_handle, uint8_t auth_status)
{
if (auth_status == BLE_GAP_SEC_STATUS_SUCCESS)
DEBUG_MSG("BLE pairing success\n");
else
DEBUG_MSG("BLE pairing failed\n");
screen->stopBluetoothPinScreen();
}

View File

@@ -6,5 +6,10 @@ class NRF52Bluetooth
void setup(); void setup();
void shutdown(); void shutdown();
void clearBonds(); void clearBonds();
};
private:
static void onConnectionSecured(uint16_t conn_handle);
void convertToUint8(uint8_t target[4], uint32_t source);
static bool onPairingPasskey(uint16_t conn_handle, uint8_t const passkey[6], bool match_request);
static void onPairingCompleted(uint16_t conn_handle, uint8_t auth_status);
};

View File

@@ -5,7 +5,9 @@
// //
// defaults for NRF52 architecture // defaults for NRF52 architecture
// //
#ifndef HAS_BLUETOOTH
#define HAS_BLUETOOTH 1
#endif
#ifndef HAS_SCREEN #ifndef HAS_SCREEN
#define HAS_SCREEN 1 #define HAS_SCREEN 1
#endif #endif

View File

@@ -7,6 +7,7 @@
#include <stdio.h> #include <stdio.h>
#include <Adafruit_nRFCrypto.h> #include <Adafruit_nRFCrypto.h>
// #include <Adafruit_USBD_Device.h> // #include <Adafruit_USBD_Device.h>
#include "NodeDB.h"
#include "NRF52Bluetooth.h" #include "NRF52Bluetooth.h"
#include "error.h" #include "error.h"
@@ -68,7 +69,7 @@ static const bool useSoftDevice = true; // Set to false for easier debugging
void setBluetoothEnable(bool on) void setBluetoothEnable(bool on)
{ {
if (on != bleOn) { if (on != bleOn && config.bluetooth.enabled == true) {
if (on) { if (on) {
if (!nrf52Bluetooth) { if (!nrf52Bluetooth) {
if (!useSoftDevice) if (!useSoftDevice)
@@ -81,9 +82,8 @@ void setBluetoothEnable(bool on)
initBrownout(); initBrownout();
} }
} }
} else { } else if (nrf52Bluetooth) {
if (nrf52Bluetooth) nrf52Bluetooth->shutdown();
nrf52Bluetooth->shutdown();
} }
bleOn = on; bleOn = on;
} }

View File

@@ -0,0 +1,36 @@
#include "configuration.h"
#include "CryptoEngine.h"
#include "aes.hpp"
class STM32WLCryptoEngine : public CryptoEngine
{
public:
STM32WLCryptoEngine() {}
~STM32WLCryptoEngine() {}
/**
* Encrypt a packet
*
* @param bytes is updated in place
*/
virtual void encrypt(uint32_t fromNode, uint64_t packetNum, size_t numBytes, uint8_t *bytes) override
{
if (key.length > 0) {
AES_ctx ctx;
initNonce(fromNode, packetNum);
AES_init_ctx_iv(&ctx, key.bytes, nonce);
AES_CTR_xcrypt_buffer(&ctx, bytes, numBytes);
}
}
virtual void decrypt(uint32_t fromNode, uint64_t packetNum, size_t numBytes, uint8_t *bytes) override
{
// For CTR, the implementation is the same
encrypt(fromNode, packetNum, numBytes, bytes);
}
private:
};
CryptoEngine *crypto = new STM32WLCryptoEngine();

View File

@@ -0,0 +1,31 @@
#pragma once
#define ARCH_STM32WL
//
// defaults for STM32WL architecture
//
//
// set HW_VENDOR
//
#ifndef HW_VENDOR
#define HW_VENDOR HardwareModel_PRIVATE_HW
#endif
#ifdef __cplusplus
extern "C" {
#endif
void stm32wl_emulate_digitalWrite(long unsigned int pin, long unsigned int value);
int stm32wl_emulate_digitalRead(long unsigned int pin);
#ifdef __cplusplus
}
#endif
/* virtual pins for stm32wl_emulate_digitalWrite() / stm32wl_emulate_digitalRead() to recognize */
#define SX126X_CS 1000
#define SX126X_DIO1 1001
#define SX126X_RESET 1003
#define SX126X_BUSY 1004

View File

@@ -0,0 +1,67 @@
#include <stdbool.h>
#include "architecture.h"
#include "stm32wlxx.h"
#include "stm32wlxx_hal.h"
void HardFault_Handler(void)
{
asm("bkpt");
}
void stm32wl_emulate_digitalWrite(long unsigned int pin, long unsigned int value)
{
switch (pin)
{
case SX126X_CS: /* active low */
if (value)
LL_PWR_UnselectSUBGHZSPI_NSS();
else
LL_PWR_SelectSUBGHZSPI_NSS();
break;
case SX126X_RESET: /* active low */
if (value)
LL_RCC_RF_DisableReset();
else
{
LL_RCC_RF_EnableReset();
LL_RCC_HSE_EnableTcxo();
LL_RCC_HSE_Enable();
while (!LL_RCC_HSE_IsReady());
}
break;
default:
asm("bkpt");
break;
}
}
static bool irq_happened;
void SUBGHZ_Radio_IRQHandler(void)
{
NVIC_DisableIRQ(SUBGHZ_Radio_IRQn);
irq_happened = true;
}
int stm32wl_emulate_digitalRead(long unsigned int pin)
{
int outcome = 0;
switch (pin)
{
case SX126X_BUSY:
// return ((LL_PWR_IsActiveFlag_RFBUSYMS() & LL_PWR_IsActiveFlag_RFBUSYS()) == 1UL);
outcome = LL_PWR_IsActiveFlag_RFBUSYS();
break;
case SX126X_DIO1:
default:
NVIC_ClearPendingIRQ(SUBGHZ_Radio_IRQn);
irq_happened = false;
NVIC_EnableIRQ(SUBGHZ_Radio_IRQn);
for (int i = 0; i < 64; i++) asm("nop");
outcome = irq_happened;
break;
}
return outcome;
}

View File

@@ -0,0 +1,27 @@
#include <stm32wle5xx.h>
#include <stm32wlxx_hal.h>
#include "configuration.h"
#include "RTC.h"
void setBluetoothEnable(bool on) {}
void playStartMelody() {}
void updateBatteryLevel(uint8_t level) {}
void getMacAddr(uint8_t *dmac)
{
for (int i = 0; i < 6; i++)
dmac[i] = i;
}
void cpuDeepSleep(uint64_t msecToWake) {}
/* pacify libc_nano */
extern "C" {
int _gettimeofday( struct timeval *tv, void *tzvp )
{
return -1;
}
}

View File

@@ -16,8 +16,6 @@
#include <driver/rtc_io.h> #include <driver/rtc_io.h>
#include <driver/uart.h> #include <driver/uart.h>
#include "nimble/BluetoothUtil.h"
esp_sleep_source_t wakeCause; // the reason we booted this time esp_sleep_source_t wakeCause; // the reason we booted this time
#endif #endif

View File

@@ -6,6 +6,7 @@ build_flags =
${esp32_base.build_flags} ${esp32_base.build_flags}
-D DIY_V1 -D DIY_V1
-D EBYTE_E22 -D EBYTE_E22
-D OLED_RU
-I variants/diy/v1 -I variants/diy/v1
; Meshtastic DIY v1.1 new schematic based on ESP32-WROOM-32 & SX1262/SX1268 modules ; Meshtastic DIY v1.1 new schematic based on ESP32-WROOM-32 & SX1262/SX1268 modules
@@ -16,4 +17,17 @@ build_flags =
${esp32_base.build_flags} ${esp32_base.build_flags}
-D DIY_V1 -D DIY_V1
-D EBYTE_E22 -D EBYTE_E22
-I variants/diy/v1_1 -D OLED_RU
-I variants/diy/v1_1
; Port to Disaster Radio's ESP32-v3 Dev Board
[env:meshtastic-dr-dev]
extends = esp32_base
board = esp32doit-devkit-v1
board_upload.maximum_size = 4194304
board_upload.maximum_ram_size = 532480
build_flags =
${esp32_base.build_flags}
-D DR_DEV
-D EBYTE_E22
-I variants/diy/dr-dev

View File

@@ -39,5 +39,4 @@
#define SCREEN_ROTATE #define SCREEN_ROTATE
// LCD screens are slow, so slowdown the wipe so it looks better // LCD screens are slow, so slowdown the wipe so it looks better
#define SCREEN_TRANSITION_MSECS 1
#define SCREEN_TRANSITION_FRAMERATE 1 // fps #define SCREEN_TRANSITION_FRAMERATE 1 // fps

View File

@@ -28,3 +28,5 @@
// code) // code)
#endif #endif
// different screen
#define USE_SH1106

View File

@@ -126,7 +126,6 @@ static const uint8_t AREF = PIN_AREF;
#define SCREEN_MIRROR #define SCREEN_MIRROR
// LCD screens are slow, so slowdown the wipe so it looks better // LCD screens are slow, so slowdown the wipe so it looks better
#define SCREEN_TRANSITION_MSECS 1000
#define SCREEN_TRANSITION_FRAMERATE 10 // fps #define SCREEN_TRANSITION_FRAMERATE 10 // fps
/* /*

View File

@@ -124,6 +124,7 @@ External serial flash WP25R1635FZUIL0
*/ */
#define USE_SX1262 #define USE_SX1262
#define USE_SX1268
#define SX126X_CS (0 + 24) // FIXME - we really should define LORA_CS instead #define SX126X_CS (0 + 24) // FIXME - we really should define LORA_CS instead
#define SX126X_DIO1 (0 + 20) #define SX126X_DIO1 (0 + 20)
// Note DIO2 is attached internally to the module to an analog switch for TX/RX switching // Note DIO2 is attached internally to the module to an analog switch for TX/RX switching
@@ -158,9 +159,6 @@ External serial flash WP25R1635FZUIL0
#define USE_EINK #define USE_EINK
// No screen wipes on eink
#define SCREEN_TRANSITION_MSECS 0
#define PIN_SPI1_MISO \ #define PIN_SPI1_MISO \
(32 + 7) // FIXME not really needed, but for now the SPI code requires something to be defined, pick an used GPIO (32 + 7) // FIXME not really needed, but for now the SPI code requires something to be defined, pick an used GPIO
#define PIN_SPI1_MOSI PIN_EINK_MOSI #define PIN_SPI1_MOSI PIN_EINK_MOSI

View File

@@ -14,6 +14,7 @@
// not found then probe for SX1262 // not found then probe for SX1262
#define USE_RF95 #define USE_RF95
#define USE_SX1262 #define USE_SX1262
#define USE_SX1268
#define LORA_DIO0 26 // a No connect on the SX1262 module #define LORA_DIO0 26 // a No connect on the SX1262 module
#define LORA_RESET 23 #define LORA_RESET 23

View File

@@ -0,0 +1,4 @@
[env:wio-e5]
extends = stm32wl5e_base
build_flags = ${stm32wl5e_base.build_flags} -Ivariants/wio-e5 -DHAL_DAC_MODULE_ONLY
-DSERIAL_UART_INSTANCE=1 -DPIN_SERIAL_RX=PB7 -DPIN_SERIAL_TX=PB6

29
variants/wio-e5/variant.h Normal file
View File

@@ -0,0 +1,29 @@
/*
Wio-E5 mini (formerly LoRa-E5 mini)
https://www.seeedstudio.com/LoRa-E5-mini-STM32WLE5JC-p-4869.html
https://www.seeedstudio.com/LoRa-E5-Wireless-Module-p-4745.html
*/
/*
This variant is a work in progress.
Do not expect a working Meshtastic device with this target.
*/
#ifndef _VARIANT_WIOE5_
#define _VARIANT_WIOE5_
//Arduino/PlatformIO support for SUBGHZSPI is not currently available
//#define USE_SX1262
#ifdef USE_SX1262
#define HAS_RADIO 1
/* module only transmits through RFO_HP */
#define SX126X_RXEN PA5
#define SX126X_TXEN PA4
/* TCXO fed by internal LDO option behind PB0 pin */
#define SX126X_E22
#endif
#endif

View File

@@ -1,4 +1,4 @@
[VERSION] [VERSION]
major = 1 major = 1
minor = 3 minor = 3
build = 36 build = 40