Compare commits

..

36 Commits

Author SHA1 Message Date
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
Ben Meadors
dd720f2fe6 Tweak 2022-08-11 19:23:51 -05:00
Ben Meadors
808fef7e91 Update main_matrix.yml 2022-08-11 18:50:02 -05:00
Ben Meadors
70e6dc3c67 chmod 2022-08-11 17:54:48 -05:00
Ben Meadors
279149e40f version.properties bump 2022-08-11 17:35:32 -05:00
Ben Meadors
4588995fba Chmod bump_version 2022-08-11 16:30:22 -05:00
Ben Meadors
11ae248c5e Update main_matrix.yml 2022-08-11 16:19:27 -05:00
Ben Meadors
a0a5147c42 Update main_matrix.yml 2022-08-11 15:58:16 -05:00
Ben Meadors
b8aac2c5b6 Create bump_version.py 2022-08-11 15:27:44 -05:00
Ben Meadors
de22f20876 Turn region screen back on (#1621) 2022-08-11 14:24:35 -05:00
Ben Meadors
9b5211dc65 Syntax 2022-08-11 09:03:18 -05:00
Ben Meadors
0b4fb72d58 Guard the assets (#1618)
* Guard the assets

* Indicated legacy build-all

* Hopefully fixed
2022-08-11 08:56:38 -05:00
76 changed files with 1176 additions and 2117 deletions

View File

@@ -6,6 +6,7 @@ on:
paths-ignore:
- "**.md"
- "**.yml"
- "version.properties"
# Note: This is different from "pull_request". Need to specify ref when doing checkouts.
pull_request_target:
@@ -380,6 +381,11 @@ jobs:
# For diagnostics
- name: Show artifacts
run: ls -lR
- name: Device scripts permissions
run: |
chmod +x ./output/device-install.sh
chmod +x ./output/device-update.sh
- name: Zip firmware
run: zip -j -r ./firmware-${{ steps.version.outputs.version }}.zip ./output
@@ -403,17 +409,51 @@ jobs:
artifacts-dir: pr
artifacts: ./firmware-${{ steps.version.outputs.version }}.zip
- name: Verify version.properties change
uses: tj-actions/verify-changed-files@v10.1
id: verify-changed-files
release-artifacts:
runs-on: ubuntu-latest
if: ${{ github.event_name == 'workflow_dispatch' }}
needs: [gather-artifacts, after-checks]
steps:
- name: Checkout
uses: actions/checkout@v2
- name: Setup Python
uses: actions/setup-python@v2
with:
files: |
version.properties
python-version: 3.x
- name: Get release version string
run: echo "::set-output name=version::$(./bin/buildinfo.py long)"
id: version
- uses: actions/download-artifact@v2
with:
name: firmware-${{ steps.version.outputs.version }}
path: ./output
- name: Device scripts permissions
run: |
chmod +x ./output/device-install.sh
chmod +x ./output/device-update.sh
- name: Zip firmware
run: zip -j -r ./firmware-${{ steps.version.outputs.version }}.zip ./output
- uses: actions/download-artifact@v2
with:
name: debug-elfs-${{ steps.version.outputs.version }}.zip
path: ./elfs
- name: Zip Elfs
run: zip -j -r ./debug-elfs-${{ steps.version.outputs.version }}.zip ./elfs
# For diagnostics
- name: Show artifacts
run: ls -lR
- name: Create release
uses: actions/create-release@v1
id: create_release
if: contains(steps.verify-changed-files.outputs.changed_files, 'version.properties') && ${{ github.event_name != 'pull_request_target' && github.event_name != 'pull_request' }}
with:
draft: true
prerelease: true
@@ -426,7 +466,6 @@ jobs:
- name: Add bins to release
uses: actions/upload-release-asset@v1
if: contains(steps.verify-changed-files.outputs.changed_files, 'version.properties') && ${{ github.event_name != 'pull_request_target' && github.event_name != 'pull_request' }}
env:
GITHUB_TOKEN: ${{ github.token }}
with:
@@ -435,17 +474,8 @@ jobs:
asset_name: firmware-${{ steps.version.outputs.version }}.zip
asset_content_type: application/zip
- uses: actions/download-artifact@v2
with:
name: debug-elfs-${{ steps.version.outputs.version }}.zip
path: ./elfs
- name: Zip Elfs
run: zip -j -r ./debug-elfs-${{ steps.version.outputs.version }}.zip ./elfs
- name: Add debug elfs to release
uses: actions/upload-release-asset@v1
if: contains(steps.verify-changed-files.outputs.changed_files, 'version.properties') && ${{ github.event_name != 'pull_request_target' && github.event_name != 'pull_request' }}
env:
GITHUB_TOKEN: ${{ github.token }}
with:
@@ -453,3 +483,14 @@ jobs:
asset_path: ./debug-elfs-${{ steps.version.outputs.version }}.zip
asset_name: debug-elfs-${{ steps.version.outputs.version }}.zip
asset_content_type: application/zip
- name: Bump version.properties
run: >-
bin/bump_version.py
- name: Create version.properties pull request
uses: peter-evans/create-pull-request@v3
with:
add-paths: |
version.properties

View File

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

16
bin/bump_version.py Executable file
View File

@@ -0,0 +1,16 @@
#!/usr/bin/env python
"""Bump the version number"""
lines = None
with open('version.properties', 'r', encoding='utf-8') as f:
lines = f.readlines()
with open('version.properties', 'w', encoding='utf-8') as f:
for line in lines:
if line.lstrip().startswith("build = "):
words = line.split(" = ")
ver = f'build = {int(words[1]) + 1}'
f.write(f'{ver}\n')
else:
f.write(line)

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 write_flash 0x1000 system-info.bin
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%
) else (
@@ -39,4 +39,4 @@ IF EXIST %FILENAME% (
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"
"$PYTHON" -m esptool erase_flash
"$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}
else
echo "Invalid file: ${FILENAME}"

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

@@ -29,11 +29,9 @@ IF "__%FILENAME%__" == "____" (
IF EXIST %FILENAME% (
echo Trying to flash update %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 (
echo "Invalid file: %FILENAME%"
goto HELP
)
:EOF
:EOF

View File

@@ -45,8 +45,6 @@ shift "$((OPTIND-1))"
if [ -f "${FILENAME}" ]; then
echo "Trying to flash update ${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
echo "Invalid file: ${FILENAME}"
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
nvs, data, nvs, 0x9000, 0x5000,
otadata, data, ota, 0xe000, 0x2000,
app0, app, ota_0, 0x10000, 0x1c0000,
app1, app, ota_1, 0x1d0000,0x1c0000,
spiffs, data, spiffs, 0x390000,0x070000,
app0, app, ota_0, 0x10000, 0x2A0000,
spiffs, data, spiffs, 0x2B0000,0x150000,
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.1
;default_envs = m5stack-coreink
;default_envs = rak4631
extra_configs = variants/*/platformio.ini
@@ -79,8 +80,6 @@ lib_deps =
lib_deps =
adafruit/Adafruit BusIO@^1.11.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 BME280 Library@^2.2.2
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.
# 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
# -DUSE_NEW_ESP32_BLUETOOTH will enable the new NimBLE C++ api
build_flags =
${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
-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 =
${arduino_base.lib_deps}
${networking_base.lib_deps}
@@ -184,4 +182,24 @@ lib_ignore =
lib_deps =
${arduino_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 <OneButton.h>
#ifdef ARCH_ESP32
#include "nimble/BluetoothUtil.h"
#endif
namespace concurrency
{
/**

View File

@@ -240,6 +240,7 @@ Fsm powerFSM(&stateBOOT);
void PowerFSM_setup()
{
bool isRouter = (config.device.role == Config_DeviceConfig_Role_Router ? 1 : 0);
uint32_t screenOnSecs = config.display.screen_on_secs ? config.display.screen_on_secs : default_screen_on_secs;
bool hasPower = isPowered();
DEBUG_MSG("PowerFSM init, USB power=%d\n", hasPower);
@@ -251,8 +252,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
// light sleep we _always_ transition to NB or dark and
powerFSM.add_transition(&stateLS, isRouter ? &stateNB : &stateDARK, EVENT_PACKET_FOR_PHONE, NULL,
"Received packet, exiting light sleep");
powerFSM.add_transition(&stateLS, isRouter ? &stateNB : &stateDARK, EVENT_PACKET_FOR_PHONE, NULL, "Received packet, exiting light sleep");
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
@@ -261,8 +261,7 @@ void PowerFSM_setup()
powerFSM.add_transition(&stateDARK, &stateON, EVENT_PRESS, NULL, "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(&stateSERIAL, &stateSERIAL, EVENT_PRESS, screenPress,
"Press"); // Allow button to work while in serial API
powerFSM.add_transition(&stateSERIAL, &stateSERIAL, EVENT_PRESS, screenPress, "Press"); // Allow button to work while in serial API
// Handle critically low power battery by forcing deep sleep
powerFSM.add_transition(&stateBOOT, &stateSDS, EVENT_LOW_BATTERY, NULL, "LowBat");
@@ -333,10 +332,7 @@ void PowerFSM_setup()
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_timed_transition(&stateON, &stateDARK,
config.display.screen_on_secs ? config.display.screen_on_secs
: 60 * 1000 * 10,
NULL, "Screen-on timeout");
powerFSM.add_timed_transition(&stateON, &stateDARK, screenOnSecs, NULL, "Screen-on timeout");
// On most boards we use light-sleep to be our main state, but on NRF52 we just stay in DARK
State *lowPowerState = &stateLS;
@@ -348,17 +344,12 @@ void PowerFSM_setup()
// See: https://github.com/meshtastic/Meshtastic-device/issues/1071
if (isRouter || config.power.is_power_saving) {
powerFSM.add_timed_transition(&stateNB, &stateLS,
config.power.min_wake_secs ? config.power.min_wake_secs
: default_min_wake_secs * 1000,
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;
uint32_t minWakeSecs = config.power.min_wake_secs ? config.power.min_wake_secs : default_min_wake_secs * 1000;
uint32_t waitBluetoothSecs = config.power.wait_bluetooth_secs ? config.power.wait_bluetooth_secs : default_wait_bluetooth_secs * 1000;
powerFSM.add_timed_transition(&stateNB, &stateLS, minWakeSecs, NULL, "Min wake timeout");
powerFSM.add_timed_transition(&stateDARK, &stateLS, waitBluetoothSecs, NULL, "Bluetooth timeout");
meshSds = config.power.mesh_sds_timeout_secs ? config.power.mesh_sds_timeout_secs : default_mesh_sds_timeout_secs;
} else {

View File

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

View File

@@ -12,10 +12,6 @@ class RedirectablePrint : public Print
{
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
bool isContinuationMessage = false;

View File

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

View File

@@ -81,7 +81,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
// #define DISABLE_NTP
// Disable the welcome screen and allow
#define DISABLE_WELCOME_UNSET
//#define DISABLE_WELCOME_UNSET
// -----------------------------------------------------------------------------
// OLED & Input

View File

@@ -228,26 +228,17 @@ static void drawSSLScreen(OLEDDisplay *display, OLEDDisplayUiState *state, int16
// Used when booting without a region set
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) {
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 * 3 - 3, "Meshtastic Android, iOS,");
display->drawString(x, y + FONT_HEIGHT_SMALL * 4 - 3, "Flasher or CLI client.");
} 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 * 3 - 3, "for more information.");
display->drawString(x, y + FONT_HEIGHT_SMALL * 4 - 3, "");
@@ -299,8 +290,13 @@ static void drawFrameBluetooth(OLEDDisplay *display, OLEDDisplayUiState *state,
display->drawString(64 + x, FONT_HEIGHT_SMALL + y + 2, "Enter this code");
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);
char buf[30];
const char *name = "Name: ";
@@ -317,6 +313,14 @@ static void drawFrameShutdown(OLEDDisplay *display, OLEDDisplayUiState *state, i
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)
{
display->setTextAlignment(TEXT_ALIGN_CENTER);
@@ -329,9 +333,6 @@ static void drawFrameFirmware(OLEDDisplay *display, OLEDDisplayUiState *state, i
} else {
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
@@ -1042,6 +1043,9 @@ int32_t Screen::runOnce()
case Cmd::START_SHUTDOWN_SCREEN:
handleShutdownScreen();
break;
case Cmd::START_REBOOT_SCREEN:
handleRebootScreen();
break;
default:
DEBUG_MSG("BUG: invalid cmd\n");
}
@@ -1234,6 +1238,18 @@ void Screen::handleShutdownScreen()
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()
{
DEBUG_MSG("showing firmware screen\n");

View File

@@ -20,6 +20,7 @@ class Screen
void forceDisplay() {}
void startBluetoothPinScreen(uint32_t pin) {}
void stopBluetoothPinScreen() {}
void startRebootScreen() {}
};
}
@@ -167,6 +168,13 @@ class Screen : public concurrency::OSThread
enqueueCmd(cmd);
}
void startRebootScreen()
{
ScreenCmd cmd;
cmd.cmd = Cmd::START_REBOOT_SCREEN;
enqueueCmd(cmd);
}
/// Stops showing the bluetooth PIN screen.
void stopBluetoothPinScreen() { enqueueCmd(ScreenCmd{.cmd = Cmd::STOP_BLUETOOTH_PIN_SCREEN}); }
@@ -280,6 +288,7 @@ class Screen : public concurrency::OSThread
void handlePrint(const char *text);
void handleStartFirmwareUpdateScreen();
void handleShutdownScreen();
void handleRebootScreen();
/// Rebuilds our list of frames (screens) to default ones.
void setFrames();

View File

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

View File

@@ -16,6 +16,10 @@
#include "modules/PositionModule.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.
It is implemented with a FreeRTos queue (wrapped with a little RTQueue class) of pointers to MeshPacket protobufs (which were

View File

@@ -150,14 +150,18 @@ void NodeDB::installDefaultConfig()
config.has_position = true;
config.has_power = true;
config.has_wifi = true;
config.has_bluetooth = true;
config.lora.region = Config_LoRaConfig_RegionCode_Unset;
config.lora.modem_preset = Config_LoRaConfig_ModemPreset_LongFast;
resetRadioConfig();
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;
config.bluetooth.mode = screen_found ? Config_BluetoothConfig_PairingMode_RandomPin : Config_BluetoothConfig_PairingMode_FixedPin;
// for backward compat, default position flags are ALT+MSL
config.position.position_flags =
(Config_PositionConfig_PositionFlags_POS_ALTITUDE | Config_PositionConfig_PositionFlags_POS_ALT_MSL);
config.position.position_flags = (Config_PositionConfig_PositionFlags_POS_ALTITUDE | Config_PositionConfig_PositionFlags_POS_ALT_MSL);
}
void NodeDB::installDefaultModuleConfig()
@@ -452,6 +456,7 @@ void NodeDB::saveToDisk()
config.has_position = true;
config.has_power = true;
config.has_wifi = true;
config.has_bluetooth = true;
saveProto(configFileName, LocalConfig_size, sizeof(LocalConfig), LocalConfig_fields, &config);
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 DEVICESTATE_CUR_VER 14
#define DEVICESTATE_CUR_VER 15
#define DEVICESTATE_MIN_VER DEVICESTATE_CUR_VER
extern DeviceState devicestate;
@@ -179,12 +179,11 @@ extern NodeDB nodeDB;
#define default_sds_secs 365 * 24 * 60 * 60
#define default_ls_secs IF_ROUTER(24 * 60 * 60, 5 * 60)
#define default_min_wake_secs 10
#define default_screen_on_secs 60 * 1000 * 10
inline uint32_t getIntervalOrDefaultMs(uint32_t interval)
{
if (interval > 0)
return interval * 1000;
if (interval > 0) return interval * 1000;
return default_broadcast_interval_secs * 1000;
}

View File

@@ -116,13 +116,11 @@ bool PhoneAPI::handleToRadio(const uint8_t *buf, size_t bufLength)
*/
size_t PhoneAPI::getFromRadio(uint8_t *buf)
{
DEBUG_MSG("getFromRadio, state=%d\n", state);
if (!available()) {
// DEBUG_MSG("getFromRadio, !available\n");
// DEBUG_MSG("PhoneAPI::getFromRadio, !available\n");
return 0;
}
DEBUG_MSG("getFromRadio, state=%d\n", state);
// In case we send a FromRadio packet
memset(&fromRadioScratch, 0, sizeof(fromRadioScratch));
@@ -189,15 +187,18 @@ size_t PhoneAPI::getFromRadio(uint8_t *buf)
fromRadioScratch.config.which_payloadVariant = Config_lora_tag;
fromRadioScratch.config.payloadVariant.lora = config.lora;
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.
// 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).
config_state++;
// 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;
config_state = ModuleConfig_mqtt_tag;
}
@@ -275,7 +276,10 @@ size_t PhoneAPI::getFromRadio(uint8_t *buf)
return 0;
}
void PhoneAPI::handleDisconnect() {}
void PhoneAPI::handleDisconnect()
{
DEBUG_MSG("PhoneAPI disconnect\n");
}
void PhoneAPI::releasePhonePacket()
{
@@ -291,35 +295,28 @@ void PhoneAPI::releasePhonePacket()
bool PhoneAPI::available()
{
switch (state) {
case STATE_SEND_NOTHING:
return false;
case STATE_SEND_MY_INFO:
return true;
case STATE_SEND_CONFIG:
return true;
case STATE_SEND_MODULECONFIG:
return true;
case STATE_SEND_NODEINFO:
if (!nodeInfoForPhone)
nodeInfoForPhone = nodeDB.readNextInfo();
return true; // Always say we have something, because we might need to advance our state machine
case STATE_SEND_COMPLETE_ID:
return true;
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;
case STATE_SEND_NOTHING:
return false;
case STATE_SEND_MY_INFO:
return true;
case STATE_SEND_CONFIG:
return true;
case STATE_SEND_MODULECONFIG:
return true;
case STATE_SEND_NODEINFO:
if (!nodeInfoForPhone)
nodeInfoForPhone = nodeDB.readNextInfo();
return true; // Always say we have something, because we might need to advance our state machine
case STATE_SEND_COMPLETE_ID:
return true;
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:
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
// Unregisters our observer. A closed connection **can** be reopened by calling init again.
virtual void close();
/**
* Handle a ToRadio protobuf
* @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; }
void setInitialState() { state = STATE_SEND_MY_INFO; }
/// emit a debugging log character, FIXME - implement
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)
{
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

View File

@@ -67,6 +67,12 @@ bool ReliableRouter::shouldFilterReceived(MeshPacket *p)
sendAckNak(Routing_Error_NONE, getFrom(p), p->id, p->channel);
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);
@@ -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
if (ackId || nakId) {
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);
} else {
DEBUG_MSG("Received a nak for 0x%x, stopping retransmissions\n", nakId);

View File

@@ -21,7 +21,8 @@ typedef enum _AdminMessage_ConfigType {
AdminMessage_ConfigType_POWER_CONFIG = 2,
AdminMessage_ConfigType_WIFI_CONFIG = 3,
AdminMessage_ConfigType_DISPLAY_CONFIG = 4,
AdminMessage_ConfigType_LORA_CONFIG = 5
AdminMessage_ConfigType_LORA_CONFIG = 5,
AdminMessage_ConfigType_BLUETOOTH_CONFIG = 6
} AdminMessage_ConfigType;
typedef enum _AdminMessage_ModuleConfigType {
@@ -88,30 +89,12 @@ typedef struct _AdminMessage {
bool exit_simulator;
/* Tell the node to reboot in this many seconds (or <0 to cancel reboot) */
int32_t reboot_seconds;
/* Get the Canned Message Module message part1 in the response to this message. */
bool get_canned_message_module_part1_request;
/* TODO: REPLACE */
char get_canned_message_module_part1_response[201];
/* Get the Canned Message Module message part2 in the response to this message. */
bool get_canned_message_module_part2_request;
/* 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];
/* Get the Canned Message Module messages in the response to this message. */
bool get_canned_message_module_messages_request;
/* Get the Canned Message Module messages in the response to this message. */
char get_canned_message_module_messages_response[201];
/* Set the Canned Message Module messages text. */
char set_canned_message_module_messages[201];
/* Tell the node to shutdown in this many seconds (or <0 to cancel shutdown) */
int32_t shutdown_seconds;
/* Request the node to send device metadata (firmware, protobuf version, etc) */
@@ -124,8 +107,8 @@ typedef struct _AdminMessage {
/* Helper constants for enums */
#define _AdminMessage_ConfigType_MIN AdminMessage_ConfigType_DEVICE_CONFIG
#define _AdminMessage_ConfigType_MAX AdminMessage_ConfigType_LORA_CONFIG
#define _AdminMessage_ConfigType_ARRAYSIZE ((AdminMessage_ConfigType)(AdminMessage_ConfigType_LORA_CONFIG+1))
#define _AdminMessage_ConfigType_MAX AdminMessage_ConfigType_BLUETOOTH_CONFIG
#define _AdminMessage_ConfigType_ARRAYSIZE ((AdminMessage_ConfigType)(AdminMessage_ConfigType_BLUETOOTH_CONFIG+1))
#define _AdminMessage_ModuleConfigType_MIN AdminMessage_ModuleConfigType_MQTT_CONFIG
#define _AdminMessage_ModuleConfigType_MAX AdminMessage_ModuleConfigType_CANNEDMSG_CONFIG
@@ -160,18 +143,9 @@ extern "C" {
#define AdminMessage_confirm_set_radio_tag 33
#define AdminMessage_exit_simulator_tag 34
#define AdminMessage_reboot_seconds_tag 35
#define AdminMessage_get_canned_message_module_part1_request_tag 36
#define AdminMessage_get_canned_message_module_part1_response_tag 37
#define AdminMessage_get_canned_message_module_part2_request_tag 38
#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_get_canned_message_module_messages_request_tag 36
#define AdminMessage_get_canned_message_module_messages_response_tag 37
#define AdminMessage_set_canned_message_module_messages_tag 44
#define AdminMessage_shutdown_seconds_tag 51
#define AdminMessage_get_device_metadata_request_tag 52
#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,exit_simulator,exit_simulator), 34) \
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, STRING, (variant,get_canned_message_module_part1_response,get_canned_message_module_part1_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,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, 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_messages_response,get_canned_message_module_messages_response), 37) \
X(a, STATIC, ONEOF, STRING, (variant,set_canned_message_module_messages,set_canned_message_module_messages), 44) \
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, 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.
#endif
PB_BIND(CannedMessageModuleConfig, CannedMessageModuleConfig, 2)
PB_BIND(CannedMessageModuleConfig, CannedMessageModuleConfig, AUTO)

View File

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

View File

@@ -92,7 +92,19 @@ typedef enum _Config_LoRaConfig_ModemPreset {
Config_LoRaConfig_ModemPreset_ShortFast = 6
} 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 */
typedef struct _Config_BluetoothConfig {
bool enabled;
Config_BluetoothConfig_PairingMode mode;
uint32_t fixed_pin;
} Config_BluetoothConfig;
typedef struct _Config_DeviceConfig {
Config_DeviceConfig_Role role;
bool serial_disabled;
@@ -160,6 +172,7 @@ typedef struct _Config {
Config_WiFiConfig wifi;
Config_DisplayConfig display;
Config_LoRaConfig lora;
Config_BluetoothConfig bluetooth;
} payloadVariant;
} Config;
@@ -193,6 +206,10 @@ typedef struct _Config {
#define _Config_LoRaConfig_ModemPreset_MAX Config_LoRaConfig_ModemPreset_ShortFast
#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
extern "C" {
@@ -206,6 +223,7 @@ extern "C" {
#define Config_WiFiConfig_init_default {0, _Config_WiFiConfig_WiFiMode_MIN, "", ""}
#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_BluetoothConfig_init_default {0, _Config_BluetoothConfig_PairingMode_MIN, 0}
#define Config_init_zero {0, {Config_DeviceConfig_init_zero}}
#define Config_DeviceConfig_init_zero {_Config_DeviceConfig_Role_MIN, 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_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_BluetoothConfig_init_zero {0, _Config_BluetoothConfig_PairingMode_MIN, 0}
/* 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_serial_disabled_tag 2
#define Config_DeviceConfig_factory_reset_tag 3
@@ -260,6 +282,7 @@ extern "C" {
#define Config_wifi_tag 4
#define Config_display_tag 5
#define Config_lora_tag 6
#define Config_bluetooth_tag 7
/* Struct field encoding specification for nanopb */
#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,wifi,payloadVariant.wifi), 4) \
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_DEFAULT NULL
#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_display_MSGTYPE Config_DisplayConfig
#define Config_payloadVariant_lora_MSGTYPE Config_LoRaConfig
#define Config_payloadVariant_bluetooth_MSGTYPE Config_BluetoothConfig
#define Config_DeviceConfig_FIELDLIST(X, a) \
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_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_DeviceConfig_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_DisplayConfig_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 */
#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_DisplayConfig_fields &Config_DisplayConfig_msg
#define Config_LoRaConfig_fields &Config_LoRaConfig_msg
#define Config_BluetoothConfig_fields &Config_BluetoothConfig_msg
/* Maximum encoded size of messages (where known) */
#define Config_BluetoothConfig_size 10
#define Config_DeviceConfig_size 42
#define Config_DisplayConfig_size 16
#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) */
#define ChannelFile_size 630
#define DeviceState_size 23994
#define DeviceState_size 22218
#define OEMStore_size 2106
#ifdef __cplusplus

View File

@@ -31,6 +31,9 @@ typedef struct _LocalConfig {
/* The part of the config that is specific to the Lora Radio */
bool has_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
incompatible changes This integer is set at build time and is private to
NodeDB.cpp in the device code. */
@@ -71,9 +74,9 @@ extern "C" {
#endif
/* 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 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}
/* Field tags (for use in manual encoding/decoding) */
@@ -83,7 +86,8 @@ extern "C" {
#define LocalConfig_wifi_tag 4
#define LocalConfig_display_tag 5
#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_serial_tag 2
#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, display, 5) \
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_DEFAULT NULL
#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_display_MSGTYPE Config_DisplayConfig
#define LocalConfig_lora_MSGTYPE Config_LoRaConfig
#define LocalConfig_bluetooth_MSGTYPE Config_BluetoothConfig
#define LocalModuleConfig_FIELDLIST(X, a) \
X(a, STATIC, OPTIONAL, MESSAGE, mqtt, 1) \
@@ -138,7 +144,7 @@ extern const pb_msgdesc_t LocalModuleConfig_msg;
#define LocalModuleConfig_fields &LocalModuleConfig_msg
/* Maximum encoded size of messages (where known) */
#define LocalConfig_size 321
#define LocalConfig_size 333
#define LocalModuleConfig_size 268
#ifdef __cplusplus

View File

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

View File

@@ -245,24 +245,38 @@ typedef struct _Compressed {
Compressed_data_t data;
} Compressed;
/* Location of a waypoint to associate with a message */
typedef struct _Location {
/* Id of the location */
uint32_t id;
/* latitude_i */
int32_t latitude_i;
/* longitude_i */
int32_t longitude_i;
/* Time the location is to expire (epoch) */
uint32_t expire;
/* If true, only allow the original sender to update the location. */
bool locked;
/* Name of the location - max 30 chars */
char name[30];
/* *
Description of the location - max 100 chars */
char description[100];
} Location;
typedef PB_BYTES_ARRAY_T(237) Data_payload_t;
/* (Formerly called SubPacket)
The payload portion fo a packet, this is the actual bytes that are sent
inside a radio packet (because from/to are broken out by the comms library) */
typedef struct _Data {
/* Formerly named typ and of type Type */
PortNum portnum;
/* TODO: REPLACE */
Data_payload_t payload;
/* Not normally used, but for testing a sender can request that recipient
responds in kind (i.e. if it received a position, it should unicast back it's position).
Note: that if you set this on a broadcast you will receive many replies. */
bool want_response;
/* The address of the destination node.
This field is is filled in by the mesh radio device software, application
layer software should never need it.
RouteDiscovery messages _must_ populate this.
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.
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.
Also, "long_name" should be their licence number. */
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;
typedef PB_BYTES_ARRAY_T(237) Data_payload_t;
/* (Formerly called SubPacket)
The payload portion fo a packet, this is the actual bytes that are sent
inside a radio packet (because from/to are broken out by the comms library) */
typedef struct _Data {
/* Formerly named typ and of type Type */
PortNum portnum;
/* TODO: REPLACE */
Data_payload_t payload;
/* Not normally used, but for testing a sender can request that recipient
responds in kind (i.e. if it received a position, it should unicast back it's position).
Note: that if you set this on a broadcast you will receive many replies. */
bool want_response;
/* The address of the destination node.
This field is is filled in by the mesh radio device software, application
layer software should never need it.
RouteDiscovery messages _must_ populate this.
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;
/* 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;
/* Waypoint message, used to share arbitrary locations across the mesh */
typedef struct _Waypoint {
/* Id of the waypoint */
uint32_t id;
/* latitude_i */
int32_t latitude_i;
/* longitude_i */
int32_t longitude_i;
/* Time the waypoint is to expire (epoch) */
uint32_t expire;
/* If true, only allow the original sender to update the waypoint. */
bool locked;
/* Name of the waypoint - max 30 chars */
char name[30];
/* *
Description of the waypoint - max 100 chars */
char description[100];
} Waypoint;
typedef PB_BYTES_ARRAY_T(256) MeshPacket_encrypted_t;
/* A packet envelope sent/received over the mesh
@@ -630,6 +566,56 @@ typedef struct _MeshPacket {
MeshPacket_Delayed delayed;
} 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.
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,
@@ -738,11 +724,11 @@ extern "C" {
/* 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 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 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 Location_init_default {0, 0, 0, 0, 0, "", ""}
#define Data_init_default {_PortNum_MIN, {0, {0}}, 0, 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 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}
@@ -752,11 +738,11 @@ extern "C" {
#define ToRadio_PeerInfo_init_default {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 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 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 Location_init_zero {0, 0, 0, 0, 0, "", ""}
#define Data_init_zero {_PortNum_MIN, {0, {0}}, 0, 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 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}
@@ -769,13 +755,14 @@ extern "C" {
/* Field tags (for use in manual encoding/decoding) */
#define Compressed_portnum_tag 1
#define Compressed_data_tag 2
#define Location_id_tag 1
#define Location_latitude_i_tag 2
#define Location_longitude_i_tag 3
#define Location_expire_tag 4
#define Location_locked_tag 5
#define Location_name_tag 6
#define Location_description_tag 7
#define Data_portnum_tag 1
#define Data_payload_tag 2
#define Data_want_response_tag 3
#define Data_dest_tag 4
#define Data_source_tag 5
#define Data_request_id_tag 6
#define Data_reply_id_tag 7
#define Data_emoji_tag 8
#define LogRecord_message_tag 1
#define LogRecord_time_tag 2
#define LogRecord_source_tag 3
@@ -827,27 +814,13 @@ extern "C" {
#define User_macaddr_tag 4
#define User_hw_model_tag 6
#define User_is_licensed_tag 7
#define User_tx_power_dbm_tag 10
#define User_ant_gain_dbi_tag 11
#define User_ant_azimuth_tag 12
#define Data_portnum_tag 1
#define Data_payload_tag 2
#define Data_want_response_tag 3
#define Data_dest_tag 4
#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 Waypoint_id_tag 1
#define Waypoint_latitude_i_tag 2
#define Waypoint_longitude_i_tag 3
#define Waypoint_expire_tag 4
#define Waypoint_locked_tag 5
#define Waypoint_name_tag 6
#define Waypoint_description_tag 7
#define MeshPacket_from_tag 1
#define MeshPacket_to_tag 2
#define MeshPacket_channel_tag 3
@@ -861,6 +834,15 @@ extern "C" {
#define MeshPacket_priority_tag 12
#define MeshPacket_rx_rssi_tag 13
#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_my_info_tag 3
#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, FIXED_LENGTH_BYTES, macaddr, 4) \
X(a, STATIC, SINGULAR, UENUM, hw_model, 6) \
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)
X(a, STATIC, SINGULAR, BOOL, is_licensed, 7)
#define User_CALLBACK 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, request_id, 6) \
X(a, STATIC, SINGULAR, FIXED32, reply_id, 7) \
X(a, STATIC, SINGULAR, FIXED32, emoji, 8) \
X(a, STATIC, OPTIONAL, MESSAGE, location, 9)
X(a, STATIC, SINGULAR, FIXED32, emoji, 8)
#define Data_CALLBACK 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, SFIXED32, latitude_i, 2) \
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, STRING, name, 6) \
X(a, STATIC, SINGULAR, STRING, description, 7)
#define Location_CALLBACK NULL
#define Location_DEFAULT NULL
#define Waypoint_CALLBACK NULL
#define Waypoint_DEFAULT NULL
#define MeshPacket_FIELDLIST(X, a) \
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 Routing_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 NodeInfo_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 Routing_fields &Routing_msg
#define Data_fields &Data_msg
#define Location_fields &Location_msg
#define Waypoint_fields &Waypoint_msg
#define MeshPacket_fields &MeshPacket_msg
#define NodeInfo_fields &NodeInfo_msg
#define MyNodeInfo_fields &MyNodeInfo_msg
@@ -1087,19 +1064,19 @@ extern const pb_msgdesc_t Compressed_msg;
/* Maximum encoded size of messages (where known) */
#define Compressed_size 243
#define Data_size 429
#define FromRadio_size 489
#define Location_size 156
#define Data_size 270
#define FromRadio_size 330
#define LogRecord_size 81
#define MeshPacket_size 480
#define MeshPacket_size 321
#define MyNodeInfo_size 197
#define NodeInfo_size 281
#define NodeInfo_size 263
#define Position_size 142
#define RouteDiscovery_size 40
#define Routing_size 42
#define ToRadio_PeerInfo_size 8
#define ToRadio_size 483
#define User_size 95
#define ToRadio_size 324
#define User_size 77
#define Waypoint_size 156
#ifdef __cplusplus
} /* extern "C" */

View File

@@ -72,7 +72,7 @@ typedef struct _ModuleConfig_ExternalNotificationConfig {
} ModuleConfig_ExternalNotificationConfig;
typedef struct _ModuleConfig_MQTTConfig {
bool disabled;
bool enabled;
char address[32];
char username[32];
char password[32];
@@ -187,7 +187,7 @@ extern "C" {
#define ModuleConfig_ExternalNotificationConfig_active_tag 4
#define ModuleConfig_ExternalNotificationConfig_alert_message_tag 5
#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_username_tag 3
#define ModuleConfig_MQTTConfig_password_tag 4
@@ -240,7 +240,7 @@ X(a, STATIC, ONEOF, MESSAGE, (payloadVariant,canned_message,payloadVariant
#define ModuleConfig_payloadVariant_canned_message_MSGTYPE ModuleConfig_CannedMessageConfig
#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, username, 3) \
X(a, STATIC, SINGULAR, STRING, password, 4) \

View File

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

View File

@@ -170,80 +170,94 @@ void AdminModule::handleSetOwner(const User &o)
void AdminModule::handleSetConfig(const Config &c)
{
bool requiresReboot = false;
switch (c.which_payloadVariant) {
case Config_device_tag:
DEBUG_MSG("Setting config: Device\n");
config.has_device = true;
config.device = c.payloadVariant.device;
break;
case Config_position_tag:
DEBUG_MSG("Setting config: Position\n");
config.has_position = true;
config.position = c.payloadVariant.position;
break;
case Config_power_tag:
DEBUG_MSG("Setting config: Power\n");
config.has_power = true;
config.power = c.payloadVariant.power;
break;
case Config_wifi_tag:
DEBUG_MSG("Setting config: WiFi\n");
config.has_wifi = true;
config.wifi = c.payloadVariant.wifi;
break;
case Config_display_tag:
DEBUG_MSG("Setting config: Display\n");
config.has_display = true;
config.display = c.payloadVariant.display;
break;
case Config_lora_tag:
DEBUG_MSG("Setting config: LoRa\n");
config.has_lora = true;
config.lora = c.payloadVariant.lora;
break;
case Config_device_tag:
DEBUG_MSG("Setting config: Device\n");
config.has_device = true;
config.device = c.payloadVariant.device;
break;
case Config_position_tag:
DEBUG_MSG("Setting config: Position\n");
config.has_position = true;
config.position = c.payloadVariant.position;
break;
case Config_power_tag:
DEBUG_MSG("Setting config: Power\n");
config.has_power = true;
config.power = c.payloadVariant.power;
break;
case Config_wifi_tag:
DEBUG_MSG("Setting config: WiFi\n");
config.has_wifi = true;
config.wifi = c.payloadVariant.wifi;
break;
case Config_display_tag:
DEBUG_MSG("Setting config: Display\n");
config.has_display = true;
config.display = c.payloadVariant.display;
break;
case Config_lora_tag:
DEBUG_MSG("Setting config: LoRa\n");
config.has_lora = true;
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();
// 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)
{
switch (c.which_payloadVariant) {
case ModuleConfig_mqtt_tag:
DEBUG_MSG("Setting module config: MQTT\n");
moduleConfig.has_mqtt = true;
moduleConfig.mqtt = c.payloadVariant.mqtt;
break;
case ModuleConfig_serial_tag:
DEBUG_MSG("Setting module config: Serial\n");
moduleConfig.has_serial = true;
moduleConfig.serial = c.payloadVariant.serial;
break;
case ModuleConfig_external_notification_tag:
DEBUG_MSG("Setting module config: External Notification\n");
moduleConfig.has_external_notification = true;
moduleConfig.external_notification = c.payloadVariant.external_notification;
break;
case ModuleConfig_store_forward_tag:
DEBUG_MSG("Setting module config: Store & Forward\n");
moduleConfig.has_store_forward = true;
moduleConfig.store_forward = c.payloadVariant.store_forward;
break;
case ModuleConfig_range_test_tag:
DEBUG_MSG("Setting module config: Range Test\n");
moduleConfig.has_range_test = true;
moduleConfig.range_test = c.payloadVariant.range_test;
break;
case ModuleConfig_telemetry_tag:
DEBUG_MSG("Setting module config: Telemetry\n");
moduleConfig.has_telemetry = true;
moduleConfig.telemetry = c.payloadVariant.telemetry;
break;
case ModuleConfig_canned_message_tag:
DEBUG_MSG("Setting module config: Canned Message\n");
moduleConfig.has_canned_message = true;
moduleConfig.canned_message = c.payloadVariant.canned_message;
break;
case ModuleConfig_mqtt_tag:
DEBUG_MSG("Setting module config: MQTT\n");
moduleConfig.has_mqtt = true;
moduleConfig.mqtt = c.payloadVariant.mqtt;
break;
case ModuleConfig_serial_tag:
DEBUG_MSG("Setting module config: Serial\n");
moduleConfig.has_serial = true;
moduleConfig.serial = c.payloadVariant.serial;
break;
case ModuleConfig_external_notification_tag:
DEBUG_MSG("Setting module config: External Notification\n");
moduleConfig.has_external_notification = true;
moduleConfig.external_notification = c.payloadVariant.external_notification;
break;
case ModuleConfig_store_forward_tag:
DEBUG_MSG("Setting module config: Store & Forward\n");
moduleConfig.has_store_forward = true;
moduleConfig.store_forward = c.payloadVariant.store_forward;
break;
case ModuleConfig_range_test_tag:
DEBUG_MSG("Setting module config: Range Test\n");
moduleConfig.has_range_test = true;
moduleConfig.range_test = c.payloadVariant.range_test;
break;
case ModuleConfig_telemetry_tag:
DEBUG_MSG("Setting module config: Telemetry\n");
moduleConfig.has_telemetry = true;
moduleConfig.telemetry = c.payloadVariant.telemetry;
break;
case ModuleConfig_canned_message_tag:
DEBUG_MSG("Setting module config: Canned Message\n");
moduleConfig.has_canned_message = true;
moduleConfig.canned_message = c.payloadVariant.canned_message;
break;
}
service.reloadConfig();
@@ -309,8 +323,12 @@ void AdminModule::handleGetConfig(const MeshPacket &req, const uint32_t configTy
res.get_config_response.which_payloadVariant = Config_lora_tag;
res.get_config_response.payloadVariant.lora = config.lora;
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.
// 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).

View File

@@ -46,16 +46,14 @@ CannedMessageModule::CannedMessageModule()
*
* @return int Returns the number of messages found.
*/
// FIXME: This is just one set of messages now
int CannedMessageModule::splitConfiguredMessages()
{
int messageIndex = 0;
int i = 0;
// collect all the message parts
strcpy(this->messageStore, cannedMessageModuleConfig.messagesPart1);
strcat(this->messageStore, cannedMessageModuleConfig.messagesPart2);
strcat(this->messageStore, cannedMessageModuleConfig.messagesPart3);
strcat(this->messageStore, cannedMessageModuleConfig.messagesPart4);
strcpy(this->messageStore, cannedMessageModuleConfig.messages);
// The first message points to the beginning of the store.
this->messages[messageIndex++] = this->messageStore;
@@ -294,10 +292,7 @@ bool CannedMessageModule::saveProtoForModule()
*/
void CannedMessageModule::installDefaultCannedMessageModuleConfig()
{
memset(cannedMessageModuleConfig.messagesPart1, 0, sizeof(cannedMessageModuleConfig.messagesPart1));
memset(cannedMessageModuleConfig.messagesPart2, 0, sizeof(cannedMessageModuleConfig.messagesPart2));
memset(cannedMessageModuleConfig.messagesPart3, 0, sizeof(cannedMessageModuleConfig.messagesPart3));
memset(cannedMessageModuleConfig.messagesPart4, 0, sizeof(cannedMessageModuleConfig.messagesPart4));
memset(cannedMessageModuleConfig.messages, 0, sizeof(cannedMessageModuleConfig.messages));
}
/**
@@ -315,51 +310,15 @@ AdminMessageHandleResult CannedMessageModule::handleAdminMessageForModule(const
AdminMessageHandleResult result;
switch (request->which_variant) {
case AdminMessage_get_canned_message_module_part1_request_tag:
DEBUG_MSG("Client is getting radio canned message part1\n");
this->handleGetCannedMessageModulePart1(mp, response);
case AdminMessage_get_canned_message_module_messages_request_tag:
DEBUG_MSG("Client is getting radio canned messages\n");
this->handleGetCannedMessageModuleMessages(mp, response);
result = AdminMessageHandleResult::HANDLED_WITH_RESPONSE;
break;
case AdminMessage_get_canned_message_module_part2_request_tag:
DEBUG_MSG("Client is getting radio canned message part2\n");
this->handleGetCannedMessageModulePart2(mp, response);
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);
case AdminMessage_set_canned_message_module_messages_tag:
DEBUG_MSG("Client is setting radio canned messages\n");
this->handleSetCannedMessageModuleMessages(request->set_canned_message_module_messages);
result = AdminMessageHandleResult::HANDLED;
break;
@@ -370,49 +329,23 @@ AdminMessageHandleResult CannedMessageModule::handleAdminMessageForModule(const
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);
response->which_variant = AdminMessage_get_canned_message_module_part1_response_tag;
strcpy(response->get_canned_message_module_part1_response, cannedMessageModuleConfig.messagesPart1);
response->which_variant = AdminMessage_get_canned_message_module_messages_response_tag;
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;
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)
void CannedMessageModule::handleSetCannedMessageModuleMessages(const char *from_msg)
{
int changed = 0;
if (*from_msg) {
changed |= strcmp(cannedMessageModuleConfig.messagesPart1, from_msg);
strcpy(cannedMessageModuleConfig.messagesPart1, from_msg);
changed |= strcmp(cannedMessageModuleConfig.messages, from_msg);
strcpy(cannedMessageModuleConfig.messages, 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

View File

@@ -39,15 +39,8 @@ class CannedMessageModule :
void eventDown();
void eventSelect();
void handleGetCannedMessageModulePart1(const MeshPacket &req, AdminMessage *response);
void handleGetCannedMessageModulePart2(const MeshPacket &req, AdminMessage *response);
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);
void handleGetCannedMessageModuleMessages(const MeshPacket &req, AdminMessage *response);
void handleSetCannedMessageModuleMessages(const char *from_msg);
protected:

View File

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

View File

@@ -6,15 +6,15 @@
#include "input/facesKbI2cImpl.h"
#include "modules/AdminModule.h"
#include "modules/CannedMessageModule.h"
#include "modules/ExternalNotificationModule.h"
#include "modules/NodeInfoModule.h"
#include "modules/PositionModule.h"
#include "modules/RemoteHardwareModule.h"
#include "modules/ReplyModule.h"
#include "modules/RoutingModule.h"
#include "modules/TextMessageModule.h"
#include "modules/Telemetry/DeviceTelemetry.h"
#include "modules/WaypointModule.h"
#if HAS_TELEMETRY
#include "modules/Telemetry/DeviceTelemetry.h"
#include "modules/Telemetry/EnvironmentTelemetry.h"
#endif
#ifdef ARCH_ESP32
@@ -22,7 +22,9 @@
#include "modules/esp32/SerialModule.h"
#include "modules/esp32/StoreForwardModule.h"
#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)
*/
@@ -34,6 +36,7 @@ void setupModules()
adminModule = new AdminModule();
nodeInfoModule = new NodeInfoModule();
positionModule = new PositionModule();
waypointModule = new WaypointModule();
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
@@ -70,6 +73,8 @@ void setupModules()
storeForwardModule = new StoreForwardModule();
new RangeTestModule();
#elif defined(ARCH_NRF52)
new ExternalNotificationModule();
#endif
// 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")
{
isPromiscuous = true; // We always want to update our nodedb, even if we are sniffing on others
setIntervalFromNow(30 *
1000); // Send our initial owner announcement 30 seconds after we start (to give network time to setup)
setIntervalFromNow(30 * 1000); // Send our initial owner announcement 30 seconds after we start (to give network time to setup)
}
int32_t NodeInfoModule::runOnce()
@@ -69,6 +68,5 @@ int32_t NodeInfoModule::runOnce()
DEBUG_MSG("Sending our nodeinfo to mesh (wantReplies=%d)\n", requestReplies);
sendOurNodeInfo(NODENUM_BROADCAST, requestReplies); // Send our info (don't request replies)
return config.position.position_broadcast_secs ? config.position.position_broadcast_secs
: default_broadcast_interval_secs * 1000;
return default_broadcast_interval_secs * 1000;
}

View File

@@ -6,7 +6,7 @@
#include <typeinfo>
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;
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

@@ -175,9 +175,7 @@ bool MQTT::wantsLink() const
{
bool hasChannel = false;
if (moduleConfig.mqtt.disabled) {
// DEBUG_MSG("MQTT disabled...\n");
} else {
if (moduleConfig.mqtt.enabled) {
// No need for link if no channel needed it
size_t numChan = channels.getNumChannels();
for (size_t i = 0; i < numChan; i++) {

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,226 @@
#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()
{
NimBLEAdvertising *pAdvertising = NimBLEDevice::getAdvertising();
return bleServer && (bleServer->getConnectedCount() > 0 || pAdvertising->isAdvertising());
}
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
//
#ifndef HAS_BLUETOOTH
#define HAS_BLUETOOTH 1
#endif
#ifndef HAS_WIFI
#define HAS_WIFI 1
#endif

View File

@@ -1,15 +1,10 @@
#include "BluetoothSoftwareUpdate.h"
#include "PowerFSM.h"
#include "configuration.h"
#include "esp_task_wdt.h"
#include "main.h"
#ifdef USE_NEW_ESP32_BLUETOOTH
#include "ESP32Bluetooth.h"
#include "nimble/NimbleBluetooth.h"
#include "mesh/http/WiFiAPClient.h"
#else
#include "nimble/BluetoothUtil.h"
#endif
#include "sleep.h"
#include "target_specific.h"
@@ -19,41 +14,26 @@
#include <nvs.h>
#include <nvs_flash.h>
#ifdef USE_NEW_ESP32_BLUETOOTH
ESP32Bluetooth *esp32Bluetooth;
#endif
NimbleBluetooth *nimbleBluetooth;
void getMacAddr(uint8_t *dmac)
{
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) {
if (!isWifiAvailable()) {
if (!esp32Bluetooth) {
esp32Bluetooth = new ESP32Bluetooth();
if (!isWifiAvailable() && config.bluetooth.enabled == true) {
if (!nimbleBluetooth) {
nimbleBluetooth = new NimbleBluetooth();
}
if (on) {
esp32Bluetooth->setup();
if (on && !nimbleBluetooth->isActive()) {
nimbleBluetooth->setup();
} else {
esp32Bluetooth->shutdown();
nimbleBluetooth->shutdown();
}
}
}
#endif
void esp32Setup()
{
@@ -123,7 +103,6 @@ Periodic axpDebugOutput(axpDebugRead);
void esp32Loop()
{
esp_task_wdt_reset(); // service our app level watchdog
//loopBLE();
// for debug printing
// radio.radioIf.canSleep();

View File

@@ -23,6 +23,7 @@ static uint8_t fromRadioBytes[FromRadio_size];
static uint8_t toRadioBytes[ToRadio_size];
static bool bleConnected;
static uint16_t connectionHandle;
class BluetoothPhoneAPI : public PhoneAPI
{
@@ -39,13 +40,14 @@ class BluetoothPhoneAPI : public PhoneAPI
/// Check the current underlying physical link to see if the client is currently connected
virtual bool checkIsConnected() override {
return bleConnected;
BLEConnection *connection = Bluefruit.Connection(connectionHandle);
return connection->connected();
}
};
static BluetoothPhoneAPI *bluetoothPhoneAPI;
void connect_callback(uint16_t conn_handle)
void onConnect(uint16_t conn_handle)
{
// Get the reference to current connection
BLEConnection *connection = Bluefruit.Connection(conn_handle);
@@ -62,7 +64,7 @@ void connect_callback(uint16_t conn_handle)
* @param conn_handle connection where this event happens
* @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
bleConnected = false;
@@ -70,7 +72,7 @@ void disconnect_callback(uint16_t conn_handle, uint8_t 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
DEBUG_MSG("CCCD Updated: %u\n", cccd_value);
@@ -126,16 +128,12 @@ static void authorizeRead(uint16_t conn_hdl)
/**
* 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 the read is long, we will get multiple authorize invocations - we only populate data on the first
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
// or make empty if the queue is empty
fromRadio.write(fromRadioBytes, numBytes);
@@ -145,7 +143,7 @@ void fromRadioAuthorizeCb(uint16_t conn_hdl, BLECharacteristic *chr, ble_gatts_e
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);
@@ -155,7 +153,7 @@ void toRadioWriteCb(uint16_t conn_hdl, BLECharacteristic *chr, uint8_t *data, ui
/**
* 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");
@@ -172,44 +170,39 @@ void setupMeshService(void)
// any characteristic(s) within that service definition.. Calling .begin() on
// a BLECharacteristic will cause it to be added to the last BLEService that
// 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.setPermission(SECMODE_OPEN, SECMODE_NO_ACCESS); // FIXME, secure this!!!
fromNum.setFixedLen(
0); // Variable len (either 0 or 4) FIXME consider changing protocol so it is fixed 4 byte len, where 0 means empty
fromNum.setPermission(secMode, SECMODE_NO_ACCESS); // FIXME, secure this!!!
fromNum.setFixedLen(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.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
// fromNum.setReadAuthorizeCallback(fromNumAuthorizeCb);
fromNum.write32(0); // Provide default fromNum of 0
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.setPermission(SECMODE_OPEN, SECMODE_NO_ACCESS); // FIXME secure this!
fromRadio.setPermission(secMode, SECMODE_NO_ACCESS);
fromRadio.setMaxLen(sizeof(fromRadioBytes));
fromRadio.setReadAuthorizeCallback(
fromRadioAuthorizeCb,
false); // We don't call this callback via the adafruit queue, because we can safely run in the BLE context
fromRadio.setReadAuthorizeCallback(onFromRadioAuthorize, 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
// for two copies
fromRadio.begin();
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.setMaxLen(512);
toRadio.setBuffer(toRadioBytes, sizeof(toRadioBytes));
toRadio.setWriteCallback(
toRadioWriteCb,
false); // We don't call this callback via the adafruit queue, because we can safely run in the BLE context
// We don't call this callback via the adafruit queue, because we can safely run in the BLE context
toRadio.setWriteCallback(onToRadioWrite, false);
toRadio.begin();
}
// FIXME, turn off soft device access for debugging
static bool isSoftDeviceAllowed = true;
static uint32_t configuredPasskey;
void NRF52Bluetooth::shutdown()
{
@@ -221,8 +214,9 @@ void NRF52Bluetooth::shutdown()
void NRF52Bluetooth::setup()
{
// Initialise the Bluefruit module
DEBUG_MSG("Initialise the Bluefruit nRF52 module\n");
DEBUG_MSG("Initialize the Bluefruit nRF52 module\n");
Bluefruit.autoConnLed(false);
Bluefruit.configPrphBandwidth(BANDWIDTH_MAX);
Bluefruit.begin();
// Clear existing data.
@@ -230,17 +224,31 @@ void NRF52Bluetooth::setup()
Bluefruit.Advertising.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!)
Bluefruit.setName(getDeviceName());
// Set the connect/disconnect callback handlers
Bluefruit.Periph.setConnectCallback(connect_callback);
Bluefruit.Periph.setDisconnectCallback(disconnect_callback);
Bluefruit.Periph.setConnectCallback(onConnect);
Bluefruit.Periph.setDisconnectCallback(onDisconnect);
// 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();
@@ -249,7 +257,6 @@ void NRF52Bluetooth::setup()
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
@@ -258,7 +265,8 @@ void NRF52Bluetooth::setup()
setupMeshService();
// Supposedly debugging works with soft device if you disable advertising
if (isSoftDeviceAllowed) {
if (isSoftDeviceAllowed)
{
// Setup the advertising packet(s)
DEBUG_MSG("Setting up the advertising payload(s)\n");
startAdv();
@@ -282,3 +290,36 @@ void NRF52Bluetooth::clearBonds()
Bluefruit.Periph.clearBonds();
Bluefruit.Central.clearBonds();
}
void NRF52Bluetooth::onConnectionSecured(uint16_t conn_handle)
{
DEBUG_MSG("BLE connection secured\n");
//bluetoothPhoneAPI->setInitialState();
}
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 shutdown();
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
//
#ifndef HAS_BLUETOOTH
#define HAS_BLUETOOTH 1
#endif
#ifndef HAS_SCREEN
#define HAS_SCREEN 1
#endif

View File

@@ -7,6 +7,7 @@
#include <stdio.h>
#include <Adafruit_nRFCrypto.h>
// #include <Adafruit_USBD_Device.h>
#include "NodeDB.h"
#include "NRF52Bluetooth.h"
#include "error.h"
@@ -68,7 +69,7 @@ static const bool useSoftDevice = true; // Set to false for easier debugging
void setBluetoothEnable(bool on)
{
if (on != bleOn) {
if (on != bleOn && config.bluetooth.enabled == true) {
if (on) {
if (!nrf52Bluetooth) {
if (!useSoftDevice)
@@ -81,9 +82,8 @@ void setBluetoothEnable(bool on)
initBrownout();
}
}
} else {
if (nrf52Bluetooth)
nrf52Bluetooth->shutdown();
} else if (nrf52Bluetooth) {
nrf52Bluetooth->shutdown();
}
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/uart.h>
#include "nimble/BluetoothUtil.h"
esp_sleep_source_t wakeCause; // the reason we booted this time
#endif

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]
major = 1
minor = 3
build = 36
build = 39