From 047df76373dfa2ea4d644d82cc3aed9de31e16c3 Mon Sep 17 00:00:00 2001 From: Kevin Hester Date: Sat, 16 Jan 2021 09:53:38 +0800 Subject: [PATCH 001/258] move rev 0.1 of the ttgo eink board to eink0.1 --- boards/{eink.json => eink0.1.json} | 2 +- platformio.ini | 12 ++++++------ src/graphics/EInkDisplay.cpp | 1 - variants/{eink => eink0.1}/variant.cpp | 0 variants/{eink => eink0.1}/variant.h | 0 5 files changed, 7 insertions(+), 8 deletions(-) rename boards/{eink.json => eink0.1.json} (97%) rename variants/{eink => eink0.1}/variant.cpp (100%) rename variants/{eink => eink0.1}/variant.h (100%) diff --git a/boards/eink.json b/boards/eink0.1.json similarity index 97% rename from boards/eink.json rename to boards/eink0.1.json index e2414b23f..1c5614896 100644 --- a/boards/eink.json +++ b/boards/eink0.1.json @@ -15,7 +15,7 @@ ], "usb_product": "TTGO_eink", "mcu": "nrf52840", - "variant": "eink", + "variant": "eink0.1", "variants_dir": "variants", "bsp": { "name": "adafruit" diff --git a/platformio.ini b/platformio.ini index 34667d2ca..be9bd710e 100644 --- a/platformio.ini +++ b/platformio.ini @@ -9,7 +9,7 @@ ; https://docs.platformio.org/page/projectconf.html [platformio] -default_envs = linux # lora-relay-v1 # nrf52840dk-geeksville # linux # or if you'd like to change the default to something like lora-relay-v1 put that here +default_envs = eink0.1 # lora-relay-v1 # nrf52840dk-geeksville # linux # or if you'd like to change the default to something like lora-relay-v1 put that here ;default_envs = heltec # lora-relay-v1 # nrf52840dk-geeksville # linux # or if you'd like to change the default to something like lora-relay-v1 put that here [common] @@ -247,15 +247,15 @@ src_filter = ${nrf52_base.src_filter} +<../variants/ppr1> lib_deps = ${arduino_base.lib_deps} -; Prototype eink/nrf52840/sx1262 device -[env:eink] +; First prototype eink/nrf52840/sx1262 device +[env:eink0.1] extends = nrf52_base -board = eink +board = eink0.1 # add our variants files to the include and src paths # define build flags for the TFT_eSPI library -build_flags = ${nrf52_base.build_flags} -Ivariants/eink +build_flags = ${nrf52_base.build_flags} -Ivariants/eink0.1 -DBUSY_PIN=3 -DRST_PIN=2 -DDC_PIN=28 -DCS_PIN=30 -src_filter = ${nrf52_base.src_filter} +<../variants/eink> +src_filter = ${nrf52_base.src_filter} +<../variants/eink0.1> lib_deps = ${arduino_base.lib_deps} https://github.com/geeksville/EPD_Libraries.git diff --git a/src/graphics/EInkDisplay.cpp b/src/graphics/EInkDisplay.cpp index 0d5e8307f..2b530c0cb 100644 --- a/src/graphics/EInkDisplay.cpp +++ b/src/graphics/EInkDisplay.cpp @@ -4,7 +4,6 @@ #include "EInkDisplay.h" #include "SPILock.h" #include "epd1in54.h" // Screen specific library -#include "graphics/configs.h" #include #include // Graphics library and Sprite class diff --git a/variants/eink/variant.cpp b/variants/eink0.1/variant.cpp similarity index 100% rename from variants/eink/variant.cpp rename to variants/eink0.1/variant.cpp diff --git a/variants/eink/variant.h b/variants/eink0.1/variant.h similarity index 100% rename from variants/eink/variant.h rename to variants/eink0.1/variant.h From 51d0d0d6c573050892af0d52230b6a64f22b59a1 Mon Sep 17 00:00:00 2001 From: Kevin Hester Date: Sat, 16 Jan 2021 09:57:55 +0800 Subject: [PATCH 002/258] begin new ttgo eink board --- boards/eink.json | 61 +++++++++ platformio.ini | 16 ++- variants/eink/variant.cpp | 44 +++++++ variants/eink/variant.h | 256 ++++++++++++++++++++++++++++++++++++++ 4 files changed, 376 insertions(+), 1 deletion(-) create mode 100644 boards/eink.json create mode 100644 variants/eink/variant.cpp create mode 100644 variants/eink/variant.h diff --git a/boards/eink.json b/boards/eink.json new file mode 100644 index 000000000..e2414b23f --- /dev/null +++ b/boards/eink.json @@ -0,0 +1,61 @@ +{ + "build": { + "arduino": { + "ldscript": "nrf52840_s140_v6.ld" + }, + "core": "nRF5", + "cpu": "cortex-m4", + "extra_flags": "-DARDUINO_NRF52840_TTGO_EINK -DNRF52840_XXAA", + "f_cpu": "64000000L", + "hwids": [ + [ + "0x239A", + "0x4405" + ] + ], + "usb_product": "TTGO_eink", + "mcu": "nrf52840", + "variant": "eink", + "variants_dir": "variants", + "bsp": { + "name": "adafruit" + }, + "softdevice": { + "sd_flags": "-DS140", + "sd_name": "s140", + "sd_version": "6.1.1", + "sd_fwid": "0x00B6" + }, + "bootloader": { + "settings_addr": "0xFF000" + } + }, + "connectivity": [ + "bluetooth" + ], + "debug": { + "jlink_device": "nRF52840_xxAA", + "onboard_tools": [ + "jlink" + ], + "svd_path": "nrf52840.svd" + }, + "frameworks": [ + "arduino" + ], + "name": "TTGO eink (Adafruit BSP)", + "upload": { + "maximum_ram_size": 248832, + "maximum_size": 815104, + "require_upload_port": true, + "speed": 115200, + "protocol": "jlink", + "protocols": [ + "jlink", + "nrfjprog", + "stlink" + ] + }, + "url": "FIXME", + "vendor": "TTGO" +} \ No newline at end of file diff --git a/platformio.ini b/platformio.ini index be9bd710e..d43b1fd17 100644 --- a/platformio.ini +++ b/platformio.ini @@ -9,7 +9,7 @@ ; https://docs.platformio.org/page/projectconf.html [platformio] -default_envs = eink0.1 # lora-relay-v1 # nrf52840dk-geeksville # linux # or if you'd like to change the default to something like lora-relay-v1 put that here +default_envs = eink # lora-relay-v1 # nrf52840dk-geeksville # linux # or if you'd like to change the default to something like lora-relay-v1 put that here ;default_envs = heltec # lora-relay-v1 # nrf52840dk-geeksville # linux # or if you'd like to change the default to something like lora-relay-v1 put that here [common] @@ -247,6 +247,20 @@ src_filter = ${nrf52_base.src_filter} +<../variants/ppr1> lib_deps = ${arduino_base.lib_deps} +; First prototype eink/nrf52840/sx1262 device +[env:eink] +extends = nrf52_base +board = eink +# add our variants files to the include and src paths +# define build flags for the TFT_eSPI library +build_flags = ${nrf52_base.build_flags} -Ivariants/eink + -DBUSY_PIN=3 -DRST_PIN=2 -DDC_PIN=28 -DCS_PIN=30 +src_filter = ${nrf52_base.src_filter} +<../variants/eink> +lib_deps = + ${arduino_base.lib_deps} + https://github.com/geeksville/EPD_Libraries.git + TFT_eSPI + ; First prototype eink/nrf52840/sx1262 device [env:eink0.1] extends = nrf52_base diff --git a/variants/eink/variant.cpp b/variants/eink/variant.cpp new file mode 100644 index 000000000..cae079b74 --- /dev/null +++ b/variants/eink/variant.cpp @@ -0,0 +1,44 @@ +/* + Copyright (c) 2014-2015 Arduino LLC. All right reserved. + Copyright (c) 2016 Sandeep Mistry All right reserved. + Copyright (c) 2018, Adafruit Industries (adafruit.com) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include "variant.h" +#include "nrf.h" +#include "wiring_constants.h" +#include "wiring_digital.h" + +const uint32_t g_ADigitalPinMap[] = { + // P0 - pins 0 and 1 are hardwired for xtal and should never be enabled + 0xff, 0xff, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, + + // P1 + 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47}; + +void initVariant() +{ + // LED1 & LED2 + pinMode(PIN_LED1, OUTPUT); + ledOff(PIN_LED1); + + pinMode(PIN_LED2, OUTPUT); + ledOff(PIN_LED2); + + pinMode(PIN_LED3, OUTPUT); + ledOff(PIN_LED3); +} diff --git a/variants/eink/variant.h b/variants/eink/variant.h new file mode 100644 index 000000000..6e3fedd67 --- /dev/null +++ b/variants/eink/variant.h @@ -0,0 +1,256 @@ +/* + Copyright (c) 2014-2015 Arduino LLC. All right reserved. + Copyright (c) 2016 Sandeep Mistry All right reserved. + Copyright (c) 2018, Adafruit Industries (adafruit.com) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the GNU Lesser General Public License for more details. + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef _VARIANT_TTGO_EINK_V1_ +#define _VARIANT_TTGO_EINK_V1_ + +/** Master clock frequency */ +#define VARIANT_MCK (64000000ul) + +#define USE_LFXO // Board uses 32khz crystal for LF + +/* +@geeksville eink TODO: + +soonish: +DONE hook cdc acm device to debug output +DONE fix bootloader to use two buttons - remove bootloader hacks +DONE get second button working in app load +DONE use tp_ser_io as a button, it goes high when pressed unify eink display classes +fix display width and height +clean up eink drawing to not have the nasty timeout hack +measure current draws +DONE put eink to sleep when we think the screen is off +enable gps sleep mode +turn off txco on lora? +make screen.adjustBrightness() a nop on eink screens + +later: +enable flash on qspi. +fix floating point SEGGER printf on nrf52 - see "new NMEA GPS pos" +add factory/power on self test + +feedback to give: + +* bootloader is finished + +* the capacitive touch sensor works, though I'm not sure what use you are intending for it + +* remove ipx connector for nfc, instead use two caps and loop traces on the back of the board as an antenna? + +* the i2c RTC seems to talk fine on the i2c bus. However, I'm not sure of the utility of that part. Instead I'd be in favor of +the following: + +* move BAT1 to power the GPS VBACKUP instead per page 6 of the Air530 datasheet. And remove the i2c RTC entirely. + +* remove the cp2014 chip. + +* I've made the serial flash chip work, but if you do a new spin of the board I recommend: +connect pin 3 and pin 7 of U4 to spare GPIOs on the processor (instead of their current connections), +This would allow using 4 bit wide interface mode to the serial flash - doubling the transfer speed! see example here: +https://infocenter.nordicsemi.com/topic/ug_nrf52840_dk/UG/nrf52840_DK/hw_external_memory.html?cp=4_0_4_7_4 +Once again - I'm glad you added that external flash chip. + +* Power measurements +When powered by 4V battery + +CPU on, lora radio RX mode, bluetooth enabled, GPS trying to lock. total draw 43mA +CPU on, lora radio RX mode, bluetooth enabled, GPS super low power sleep mode. Total draw 20mA +CPU on, lora radio TX mode, bluetooth enabled, GPS super low power sleep mode. Total draw 132mA + +Note: power consumption while connected via BLE to a phone almost identical. + +Note: eink display for all tests was in sleep mode most of the time. Current draw during the brief periods while the eink was being drawn was not +measured (but it was low). + +Note: Turning off EINK PWR_ON produces no noticeable power savings over just putting the eink display into sleep mode. + +*/ + +/*---------------------------------------------------------------------------- + * Headers + *----------------------------------------------------------------------------*/ + +#include "WVariant.h" + +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus + +// Number of pins defined in PinDescription array +#define PINS_COUNT (48) +#define NUM_DIGITAL_PINS (48) +#define NUM_ANALOG_INPUTS (1) +#define NUM_ANALOG_OUTPUTS (0) + +// LEDs +#define PIN_LED1 (0 + 13) // green (but red on my prototype) +#define PIN_LED2 (0 + 15) // blue (but red on my prototype) +#define PIN_LED3 (0 + 14) // red (not functional on my prototype) + +#define LED_RED PIN_LED3 +#define LED_GREEN PIN_LED1 +#define LED_BLUE PIN_LED2 + +#define LED_BUILTIN LED_GREEN +#define LED_CONN PIN_BLUE + +#define LED_STATE_ON 0 // State when LED is lit +#define LED_INVERTED 1 + +/* + * Buttons + */ +#define PIN_BUTTON1 (32 + 10) +#define PIN_BUTTON2 (0 + 18) // 0.18 is labeled on the board as RESET but we configure it in the bootloader as a regular GPIO + +/* + * Analog pins + */ +#define PIN_A0 (4) // Battery ADC + +#define BATTERY_PIN PIN_A0 + +static const uint8_t A0 = PIN_A0; + +#define ADC_RESOLUTION 14 + +#define PIN_NFC1 (9) +#define PIN_NFC2 (10) + +/* + * Serial interfaces + */ + +/* +No longer populated on PCB +*/ +//#define PIN_SERIAL2_RX (0 + 6) +//#define PIN_SERIAL2_TX (0 + 8) +// #define PIN_SERIAL2_EN (0 + 17) + +/** + Wire Interfaces + */ +#define WIRE_INTERFACES_COUNT 1 + +#define PIN_WIRE_SDA (26) // Not connected on board? +#define PIN_WIRE_SCL (27) + +/* touch sensor, active high */ + +#define TP_SER_IO (0 + 11) + +#define PIN_RTC_INT (0 + 16) // Interrupt from the PCF8563 RTC + +/* +External serial flash WP25R1635FZUIL0 +*/ + +// QSPI Pins +#define PIN_QSPI_SCK (32 + 14) +#define PIN_QSPI_CS (32 + 15) +#define PIN_QSPI_IO0 (32 + 12) // MOSI if using two bit interface +#define PIN_QSPI_IO1 (32 + 13) // MISO if using two bit interface +//#define PIN_QSPI_IO2 22 // WP if using two bit interface (i.e. not used) +//#define PIN_QSPI_IO3 23 // HOLD if using two bit interface (i.e. not used) + +// On-board QSPI Flash +#define EXTERNAL_FLASH_DEVICES MX25R1635F +#define EXTERNAL_FLASH_USE_QSPI + +/* + * Lora radio + */ + +#define SX1262_CS (0 + 24) // FIXME - we really should define LORA_CS instead +#define SX1262_DIO1 (0 + 20) +// Note DIO2 is attached internally to the module to an analog switch for TX/RX switching +#define SX1262_DIO3 \ + (0 + 21) // This is used as an *output* from the sx1262 and connected internally to power the tcxo, do not drive from the main + // CPU? +#define SX1262_BUSY (0 + 17) +#define SX1262_RESET (0 + 25) +#define SX1262_E22 // Not really an E22 but TTGO seems to be trying to clone that +// Internally the TTGO module hooks the SX1262-DIO2 in to control the TX/RX switch (which is the default for the sx1262interface +// code) + +// #define LORA_DISABLE_SENDING // Define this to disable transmission for testing (power testing etc...) + +/* + * eink display pins + */ + +#define PIN_EINK_EN (32 + 11) +#define PIN_EINK_CS (0 + 30) +#define PIN_EINK_BUSY (0 + 3) +#define PIN_EINK_DC (0 + 28) +#define PIN_EINK_RES (0 + 2) +#define PIN_EINK_SCLK (0 + 31) +#define PIN_EINK_MOSI (0 + 29) // also called SDI + +// Controls power for the eink display - Board power is enabled either by VBUS from USB or the CPU asserting PWR_ON +// FIXME - I think this is actually just the board power enable - it enables power to the CPU also +#define PIN_EINK_PWR_ON (0 + 12) + +#define HAS_EINK + +// No screen wipes on eink +#define SCREEN_TRANSITION_MSECS 0 + +#define PIN_SPI1_MISO \ + (32 + 7) // FIXME not really needed, but for now the SPI code requires something to be defined, pick an used GPIO +#define PIN_SPI1_MOSI PIN_EINK_MOSI +#define PIN_SPI1_SCK PIN_EINK_SCLK + +/* + * Air530 GPS pins + */ + +#define PIN_GPS_WAKE (32 + 2) // An output to wake GPS, low means allow sleep, high means force wake +#define PIN_GPS_PPS (32 + 4) // Pulse per second input from the GPS +#define PIN_GPS_TX (32 + 9) // This is for bits going TOWARDS the CPU +#define PIN_GPS_RX (32 + 8) // This is for bits going TOWARDS the GPS + +#define HAS_AIR530_GPS + +#define PIN_SERIAL1_RX PIN_GPS_TX +#define PIN_SERIAL1_TX PIN_GPS_RX + +/* + * SPI Interfaces + */ +#define SPI_INTERFACES_COUNT 2 + +// For LORA, spi 0 +#define PIN_SPI_MISO (0 + 23) +#define PIN_SPI_MOSI (0 + 22) +#define PIN_SPI_SCK (0 + 19) + +// To debug via the segger JLINK console rather than the CDC-ACM serial device +// #define USE_SEGGER + +#ifdef __cplusplus +} +#endif + +/*---------------------------------------------------------------------------- + * Arduino objects - C++ only + *----------------------------------------------------------------------------*/ + +#endif From 2684257e7ecd8dfd82cb13aad62e83cce029f0f1 Mon Sep 17 00:00:00 2001 From: Kevin Hester Date: Sat, 16 Jan 2021 09:59:43 +0800 Subject: [PATCH 003/258] update protobufs --- proto | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/proto b/proto index dfe7bc121..4c62d8e53 160000 --- a/proto +++ b/proto @@ -1 +1 @@ -Subproject commit dfe7bc1217a00c23eecb9dfcf1d56fe95ebddc3b +Subproject commit 4c62d8e53696074d7c368518afd9d564df374fcf From f110225173a77326aac029321cdb6491bfa640f6 Mon Sep 17 00:00:00 2001 From: Kevin Hester Date: Sat, 16 Jan 2021 10:34:46 +0800 Subject: [PATCH 004/258] Update variant file and qspi flash programming settings for new ttgoeink Note: bin/qspi-flash-test.sh contains a script you can use for basic bench programming and testing of the serial spi flash over SWD --- bin/qspi-flash-test.sh | 2 +- nrf52/ttgo_eink_qpsi.ini | 21 ++++------- nrf52/ttgo_eink_qpsi0.1.ini | 69 +++++++++++++++++++++++++++++++++++++ variants/eink/variant.h | 9 ++--- 4 files changed, 82 insertions(+), 19 deletions(-) create mode 100644 nrf52/ttgo_eink_qpsi0.1.ini diff --git a/bin/qspi-flash-test.sh b/bin/qspi-flash-test.sh index 7fc186b5d..6c03635dd 100755 --- a/bin/qspi-flash-test.sh +++ b/bin/qspi-flash-test.sh @@ -1,6 +1,6 @@ # You probably don't need this - it is a basic test of the serial flash on the TTGO eink board -nrfjprog -qspiini nrf52/ttgo_eink_qpsi.ini --qspieraseall +nrfjprog --qspiini nrf52/ttgo_eink_qpsi.ini --qspieraseall nrfjprog --qspiini nrf52/ttgo_eink_qpsi.ini --memwr 0x12000000 --val 0xdeadbeef --verify nrfjprog --qspiini nrf52/ttgo_eink_qpsi.ini --readqspi spi.hex objdump -s spi.hex | less diff --git a/nrf52/ttgo_eink_qpsi.ini b/nrf52/ttgo_eink_qpsi.ini index d477db8ef..053c86755 100644 --- a/nrf52/ttgo_eink_qpsi.ini +++ b/nrf52/ttgo_eink_qpsi.ini @@ -8,10 +8,10 @@ MemSize = 0x200000 ; Define the desired ReadMode. Valid options are FASTREAD, READ2O, READ2IO, READ4O and READ4IO -ReadMode = READ2IO +ReadMode = READ4IO ; Define the desired WriteMode. Valid options are PP, PP2O, PP4O and PP4IO -WriteMode = PP +WriteMode = PP4IO ; Define the desired AddressMode. Valid options are BIT24 and BIT32 AddressMode = BIT24 @@ -38,12 +38,10 @@ DIO0Pin = 12 DIO0Port = 1 DIO1Pin = 13 DIO1Port = 1 - -;These two pins are not connected, but we must name something -DIO2Pin = 3 -DIO2Port = 1 +DIO2Pin = 7 +DIO2Port = 0 DIO3Pin = 5 -DIO3Port = 1 +DIO3Port = 0 ; Define the Index of the Write In Progress (WIP) bit in the status register. Valid options are in the range of 0 to 7. WIPIndex = 0 @@ -57,13 +55,8 @@ PPSize = PAGE256 ; Numbers can be given in decimal, hex (starting with either 0x or 0X) and binary (starting with either 0b or 0B) formats. ; The custom instructions will be executed in the order found. -; This example includes two commands, first a WREN (WRite ENable) and then a WRSR (WRite Satus Register) enabling the Quad Operation and the High Performance -; mode for the MX25R6435F memory present in the nRF52840 DK. -;InitializationCustomInstruction = 0x06 -;InitializationCustomInstruction = 0x01, [0x40, 0, 0x2] - ; For MX25R1635F on TTGO board, only two data lines are connected -; This example includes two commands, first a WREN (WRite ENable) and then a WRSR (WRite Satus Register) disabling Quad Operation and the High Performance +; This example includes two commands, first a WREN (WRite ENable) and then a WRSR (WRite Satus Register) enabling Quad Operation and the High Performance ; mode. For normal operation you might want low power mode instead. InitializationCustomInstruction = 0x06 -InitializationCustomInstruction = 0x01, [0x00, 0, 0x2] +InitializationCustomInstruction = 0x01, [0x40, 0, 0x2] diff --git a/nrf52/ttgo_eink_qpsi0.1.ini b/nrf52/ttgo_eink_qpsi0.1.ini new file mode 100644 index 000000000..d477db8ef --- /dev/null +++ b/nrf52/ttgo_eink_qpsi0.1.ini @@ -0,0 +1,69 @@ +; nrfjprog.exe configuration file. + +; Note: QSPI flash is mapped into memory at address 0x12000000 + +[DEFAULT_CONFIGURATION] +; Define the capacity of the flash memory device in bytes. Set to 0 if no external memory device is present in your board. +; MX25R1635F is 16Mbit/2Mbyte +MemSize = 0x200000 + +; Define the desired ReadMode. Valid options are FASTREAD, READ2O, READ2IO, READ4O and READ4IO +ReadMode = READ2IO + +; Define the desired WriteMode. Valid options are PP, PP2O, PP4O and PP4IO +WriteMode = PP + +; Define the desired AddressMode. Valid options are BIT24 and BIT32 +AddressMode = BIT24 + +; Define the desired Frequency. Valid options are M2, M4, M8, M16 and M32 +Frequency = M16 + +; Define the desired SPI mode. Valid options are MODE0 and MODE3 +SpiMode = MODE0 + +; Define the desired SckDelay. Valid options are in the range 0 to 255 +SckDelay = 0x80 + +; Define the desired IO level for DIO2 and DIO3 during a custom instruction. Valid options are LEVEL_HIGH and LEVEL_LOW +CustomInstructionIO2Level = LEVEL_LOW +CustomInstructionIO3Level = LEVEL_HIGH + +; Define the assigned pins for the QSPI peripheral. Valid options are those existing in your device +CSNPin = 15 +CSNPort = 1 +SCKPin = 14 +SCKPort = 1 +DIO0Pin = 12 +DIO0Port = 1 +DIO1Pin = 13 +DIO1Port = 1 + +;These two pins are not connected, but we must name something +DIO2Pin = 3 +DIO2Port = 1 +DIO3Pin = 5 +DIO3Port = 1 + +; Define the Index of the Write In Progress (WIP) bit in the status register. Valid options are in the range of 0 to 7. +WIPIndex = 0 + +; Define page size for commands. Valid sizes are PAGE256 and PAGE512. +PPSize = PAGE256 + +; Custom instructions to send to the external memory after initialization. Format is instruction code plus data to send in between optional brakets. +; These instructions will be executed each time the qspi peripheral is initiated by nrfjprog. +; To improve execution speed on consecutive interations with QSPI, you can run nrfjprog once with custom initialization, and then comment out the lines below. +; Numbers can be given in decimal, hex (starting with either 0x or 0X) and binary (starting with either 0b or 0B) formats. +; The custom instructions will be executed in the order found. + +; This example includes two commands, first a WREN (WRite ENable) and then a WRSR (WRite Satus Register) enabling the Quad Operation and the High Performance +; mode for the MX25R6435F memory present in the nRF52840 DK. +;InitializationCustomInstruction = 0x06 +;InitializationCustomInstruction = 0x01, [0x40, 0, 0x2] + +; For MX25R1635F on TTGO board, only two data lines are connected +; This example includes two commands, first a WREN (WRite ENable) and then a WRSR (WRite Satus Register) disabling Quad Operation and the High Performance +; mode. For normal operation you might want low power mode instead. +InitializationCustomInstruction = 0x06 +InitializationCustomInstruction = 0x01, [0x00, 0, 0x2] diff --git a/variants/eink/variant.h b/variants/eink/variant.h index 6e3fedd67..dad11f5b0 100644 --- a/variants/eink/variant.h +++ b/variants/eink/variant.h @@ -149,7 +149,7 @@ No longer populated on PCB */ #define WIRE_INTERFACES_COUNT 1 -#define PIN_WIRE_SDA (26) // Not connected on board? +#define PIN_WIRE_SDA (26) #define PIN_WIRE_SCL (27) /* touch sensor, active high */ @@ -167,8 +167,8 @@ External serial flash WP25R1635FZUIL0 #define PIN_QSPI_CS (32 + 15) #define PIN_QSPI_IO0 (32 + 12) // MOSI if using two bit interface #define PIN_QSPI_IO1 (32 + 13) // MISO if using two bit interface -//#define PIN_QSPI_IO2 22 // WP if using two bit interface (i.e. not used) -//#define PIN_QSPI_IO3 23 // HOLD if using two bit interface (i.e. not used) +#define PIN_QSPI_IO2 (0 + 7) // WP if using two bit interface (i.e. not used) +#define PIN_QSPI_IO3 (0 + 5) // HOLD if using two bit interface (i.e. not used) // On-board QSPI Flash #define EXTERNAL_FLASH_DEVICES MX25R1635F @@ -223,7 +223,8 @@ External serial flash WP25R1635FZUIL0 */ #define PIN_GPS_WAKE (32 + 2) // An output to wake GPS, low means allow sleep, high means force wake -#define PIN_GPS_PPS (32 + 4) // Pulse per second input from the GPS +// Seems to be missing on this new board +// #define PIN_GPS_PPS (32 + 4) // Pulse per second input from the GPS #define PIN_GPS_TX (32 + 9) // This is for bits going TOWARDS the CPU #define PIN_GPS_RX (32 + 8) // This is for bits going TOWARDS the GPS From 4faff3ec6f7b33a3cc12d04f6e64fd9a3aea0a4b Mon Sep 17 00:00:00 2001 From: Kevin Hester Date: Sat, 16 Jan 2021 11:41:18 +0800 Subject: [PATCH 005/258] cope with bogus NMEA gps --- src/gps/NMEAGPS.cpp | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/src/gps/NMEAGPS.cpp b/src/gps/NMEAGPS.cpp index 6a707bd8f..bd58b5254 100644 --- a/src/gps/NMEAGPS.cpp +++ b/src/gps/NMEAGPS.cpp @@ -47,6 +47,8 @@ The Unix epoch (or Unix time or POSIX time or Unix timestamp) is the number of s t.tm_mon = d.month() - 1; t.tm_year = d.year() - 1900; t.tm_isdst = false; + DEBUG_MSG("NMEA GPS time %d\n", t.tm_sec); + perhapsSetRTC(RTCQualityGPS, t); return true; @@ -87,11 +89,17 @@ bool NMEAGPS::lookForLocation() auto loc = reader.location.value(); latitude = toDegInt(loc.lat); longitude = toDegInt(loc.lng); - foundLocation = true; - // expect gps pos lat=37.520825, lon=-122.309162, alt=158 - DEBUG_MSG("new NMEA GPS pos lat=%f, lon=%f, alt=%d, hdop=%g, heading=%f\n", latitude * 1e-7, longitude * 1e-7, altitude, - dop * 1e-2, heading * 1e-5); + // Some GPSes (Air530) seem to send a zero longitude when the current fix is bogus + if(longitude == 0) + DEBUG_MSG("Ignoring bogus NMEA position\n"); + else { + foundLocation = true; + + // expect gps pos lat=37.520825, lon=-122.309162, alt=158 + DEBUG_MSG("new NMEA GPS pos lat=%f, lon=%f, alt=%d, hdop=%g, heading=%f\n", latitude * 1e-7, longitude * 1e-7, altitude, + dop * 1e-2, heading * 1e-5); + } } return foundLocation; From a0dd051511545e4d3022be486b9a5af02eb3e98c Mon Sep 17 00:00:00 2001 From: Kevin Hester Date: Sat, 16 Jan 2021 11:41:28 +0800 Subject: [PATCH 006/258] turn off eink backlight --- src/graphics/EInkDisplay.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/graphics/EInkDisplay.cpp b/src/graphics/EInkDisplay.cpp index 2b530c0cb..44d38f22d 100644 --- a/src/graphics/EInkDisplay.cpp +++ b/src/graphics/EInkDisplay.cpp @@ -122,7 +122,8 @@ bool EInkDisplay::connect() #endif #ifdef PIN_EINK_EN - digitalWrite(PIN_EINK_EN, HIGH); + // backlight power, HIGH is backlight on, LOW is off + digitalWrite(PIN_EINK_EN, LOW); pinMode(PIN_EINK_EN, OUTPUT); #endif From 3a2c17998ed096136e0dd934a6885ac7864e5367 Mon Sep 17 00:00:00 2001 From: Kevin Hester Date: Sat, 16 Jan 2021 11:41:50 +0800 Subject: [PATCH 007/258] turn off nrf52 ble while debugging --- src/nrf52/main-nrf52.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/nrf52/main-nrf52.cpp b/src/nrf52/main-nrf52.cpp index a1a96f3b9..8b7bb65b9 100644 --- a/src/nrf52/main-nrf52.cpp +++ b/src/nrf52/main-nrf52.cpp @@ -51,7 +51,7 @@ void getMacAddr(uint8_t *dmac) NRF52Bluetooth *nrf52Bluetooth; static bool bleOn = false; -static const bool enableBle = true; // Set to false for easier debugging +static const bool enableBle = false; // Set to false for easier debugging void setBluetoothEnable(bool on) { From d1f0be215bd35da25a586d3a3078e6d7c79bdd3b Mon Sep 17 00:00:00 2001 From: Kevin Hester Date: Sat, 16 Jan 2021 11:42:06 +0800 Subject: [PATCH 008/258] eink leds seem a bit busted --- variants/eink/variant.h | 12 ++++++------ variants/eink0.1/variant.h | 4 ++-- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/variants/eink/variant.h b/variants/eink/variant.h index dad11f5b0..bd71de3c5 100644 --- a/variants/eink/variant.h +++ b/variants/eink/variant.h @@ -16,8 +16,8 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -#ifndef _VARIANT_TTGO_EINK_V1_ -#define _VARIANT_TTGO_EINK_V1_ +#ifndef _VARIANT_TTGO_EINK_V1_0_ +#define _VARIANT_TTGO_EINK_V1_0_ /** Master clock frequency */ #define VARIANT_MCK (64000000ul) @@ -99,9 +99,9 @@ extern "C" { #define NUM_ANALOG_OUTPUTS (0) // LEDs -#define PIN_LED1 (0 + 13) // green (but red on my prototype) -#define PIN_LED2 (0 + 15) // blue (but red on my prototype) -#define PIN_LED3 (0 + 14) // red (not functional on my prototype) +#define PIN_LED1 (0 + 13) // red (confirmed on 1.0 board) +#define PIN_LED2 (0 + 14) // blue (seems busted!) +#define PIN_LED3 (0 + 15) // green (seems busted!) #define LED_RED PIN_LED3 #define LED_GREEN PIN_LED1 @@ -196,7 +196,7 @@ External serial flash WP25R1635FZUIL0 * eink display pins */ -#define PIN_EINK_EN (32 + 11) +#define PIN_EINK_EN (32 + 11) // Note: this is really just backlight power #define PIN_EINK_CS (0 + 30) #define PIN_EINK_BUSY (0 + 3) #define PIN_EINK_DC (0 + 28) diff --git a/variants/eink0.1/variant.h b/variants/eink0.1/variant.h index 6e3fedd67..1b30ca21c 100644 --- a/variants/eink0.1/variant.h +++ b/variants/eink0.1/variant.h @@ -16,8 +16,8 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -#ifndef _VARIANT_TTGO_EINK_V1_ -#define _VARIANT_TTGO_EINK_V1_ +#ifndef _VARIANT_TTGO_EINK_V0_1_ +#define _VARIANT_TTGO_EINK_V0_1_ /** Master clock frequency */ #define VARIANT_MCK (64000000ul) From d1be7cf14215adfd245c792c1782d1e12a596d99 Mon Sep 17 00:00:00 2001 From: Kevin Hester Date: Sat, 16 Jan 2021 12:55:51 +0800 Subject: [PATCH 009/258] improve hardfault handler --- src/nrf52/hardfault.cpp | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/src/nrf52/hardfault.cpp b/src/nrf52/hardfault.cpp index 67180c833..c1a82d6ae 100644 --- a/src/nrf52/hardfault.cpp +++ b/src/nrf52/hardfault.cpp @@ -16,8 +16,14 @@ static void printUsageErrorMsg(uint32_t cfsr) cfsr >>= SCB_CFSR_USGFAULTSR_Pos; // right shift to lsb if ((cfsr & (1 << 9)) != 0) FAULT_MSG("Divide by zero\n"); - if ((cfsr & (1 << 8)) != 0) + else if ((cfsr & (1 << 8)) != 0) FAULT_MSG("Unaligned\n"); + else if ((cfsr & (1 << 1)) != 0) + FAULT_MSG("Invalid state\n"); + else if ((cfsr & (1 << 0)) != 0) + FAULT_MSG("Invalid instruction\n"); + else + FAULT_MSG("FIXME add to printUsageErrorMsg!\n"); } static void printBusErrorMsg(uint32_t cfsr) @@ -71,8 +77,9 @@ extern "C" void HardFault_Impl(uint32_t stack[]) FAULT_MSG("Done with fault report - Waiting to reboot\n"); asm volatile("bkpt #01"); // Enter the debugger if one is connected - while (1) - ; + + // Don't spin, so that the debugger will let the user step to next instruction + // while (1) ; } extern "C" void HardFault_Handler(void) From fd9ffbbb881073531f6aa011bd89f4ce87432fe5 Mon Sep 17 00:00:00 2001 From: Kevin Hester Date: Sat, 16 Jan 2021 13:05:33 +0800 Subject: [PATCH 010/258] fix charging indication for dumb battery sensors --- src/Power.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Power.cpp b/src/Power.cpp index 3d185cb2d..82e88f8cc 100644 --- a/src/Power.cpp +++ b/src/Power.cpp @@ -83,7 +83,7 @@ class AnalogBatteryLevel : public HasBatteryLevel /// If we see a battery voltage higher than physics allows - assume charger is pumping /// in power - virtual bool isVBUSPlug() { return getBattVoltage() > chargingVolt; } + virtual bool isVBUSPlug() { return getBattVoltage() > 1000 * chargingVolt; } /// Assume charging if we have a battery and external power is connected. /// we can't be smart enough to say 'full'? From 79dad8ec8c8dfe4bb749dd9bffdd7f3506755cd1 Mon Sep 17 00:00:00 2001 From: Andrew Mark Date: Tue, 19 Jan 2021 18:21:54 -0800 Subject: [PATCH 011/258] Set critical error and reboot when radio fails to generate tx IRQ --- src/mesh/NodeDB.cpp | 7 +++++++ src/mesh/RadioLibInterface.cpp | 10 ++++++++++ src/mesh/generated/mesh.pb.h | 3 ++- 3 files changed, 19 insertions(+), 1 deletion(-) diff --git a/src/mesh/NodeDB.cpp b/src/mesh/NodeDB.cpp index dc13bc423..42ce71ea7 100644 --- a/src/mesh/NodeDB.cpp +++ b/src/mesh/NodeDB.cpp @@ -7,6 +7,7 @@ #include "CryptoEngine.h" #include "FSCommon.h" #include "GPS.h" +#include "main.h" #include "MeshRadio.h" #include "NodeDB.h" #include "PacketHistory.h" @@ -583,8 +584,14 @@ NodeInfo *NodeDB::getOrCreateNode(NodeNum n) /// Record an error that should be reported via analytics void recordCriticalError(CriticalErrorCode code, uint32_t address) { + // Print error to screen and serial port + String lcd = String("Critical error ") + code + "!\n"; + screen->print(lcd.c_str()); DEBUG_MSG("NOTE! Recording critical error %d, address=%x\n", code, address); + + // Record error to DB myNodeInfo.error_code = code; myNodeInfo.error_address = address; myNodeInfo.error_count++; + } diff --git a/src/mesh/RadioLibInterface.cpp b/src/mesh/RadioLibInterface.cpp index 0266614af..f0eb53b2c 100644 --- a/src/mesh/RadioLibInterface.cpp +++ b/src/mesh/RadioLibInterface.cpp @@ -3,6 +3,7 @@ #include "NodeDB.h" #include "SPILock.h" #include "mesh-pb-constants.h" +#include "error.h" #include #include #include @@ -67,9 +68,18 @@ bool RadioLibInterface::canSendImmediately() bool busyTx = sendingPacket != NULL; bool busyRx = isReceiving && isActivelyReceiving(); + if (busyTx || busyRx) { if (busyTx) DEBUG_MSG("Can not send yet, busyTx\n"); + // If we've been trying to send the same packet more than one minute and we haven't gotten a + // TX IRQ from the radio, the radio is probably broken. + if (busyTx && (millis() - lastTxStart > 60000)){ + DEBUG_MSG("Hardware Failure! busyTx for more than 60s\n"); + recordCriticalError(CriticalErrorCode_TransmitFailed); + if (busyTx && (millis() - lastTxStart > 65000)) // After 5s more, reboot + ESP.restart(); + } if (busyRx) DEBUG_MSG("Can not send yet, busyRx\n"); return false; diff --git a/src/mesh/generated/mesh.pb.h b/src/mesh/generated/mesh.pb.h index 815fb2e26..50ae14a6a 100644 --- a/src/mesh/generated/mesh.pb.h +++ b/src/mesh/generated/mesh.pb.h @@ -76,7 +76,8 @@ typedef enum _CriticalErrorCode { CriticalErrorCode_Unspecified = 4, CriticalErrorCode_UBloxInitFailed = 5, CriticalErrorCode_NoAXP192 = 6, - CriticalErrorCode_InvalidRadioSetting = 7 + CriticalErrorCode_InvalidRadioSetting = 7, + CriticalErrorCode_TransmitFailed = 8 } CriticalErrorCode; typedef enum _ChannelSettings_ModemConfig { From dd511588a2f29328cc7141901eddfcd1ed713806 Mon Sep 17 00:00:00 2001 From: Andrew Mark Date: Tue, 19 Jan 2021 20:13:19 -0800 Subject: [PATCH 012/258] Oops, let's only try to reboot ESP32 when there's an ESP32 --- src/mesh/RadioLibInterface.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/mesh/RadioLibInterface.cpp b/src/mesh/RadioLibInterface.cpp index f0eb53b2c..f2fafef76 100644 --- a/src/mesh/RadioLibInterface.cpp +++ b/src/mesh/RadioLibInterface.cpp @@ -77,8 +77,10 @@ bool RadioLibInterface::canSendImmediately() if (busyTx && (millis() - lastTxStart > 60000)){ DEBUG_MSG("Hardware Failure! busyTx for more than 60s\n"); recordCriticalError(CriticalErrorCode_TransmitFailed); +#ifndef NO_ESP32 if (busyTx && (millis() - lastTxStart > 65000)) // After 5s more, reboot ESP.restart(); +#endif } if (busyRx) DEBUG_MSG("Can not send yet, busyRx\n"); From a8480d1eaf53c9aed2b5e8632e43a0b22d45a104 Mon Sep 17 00:00:00 2001 From: IZ1IVA <75425638+IZ1IVA@users.noreply.github.com> Date: Mon, 25 Jan 2021 16:11:24 +0100 Subject: [PATCH 013/258] Update radio-settings.md Added data-rates --- docs/radio-settings.md | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/docs/radio-settings.md b/docs/radio-settings.md index 2bf9ccda1..7af9d79e0 100644 --- a/docs/radio-settings.md +++ b/docs/radio-settings.md @@ -28,3 +28,14 @@ The maximum output power for North America is +30 dBm ERP. The band is from 902 to 928 MHz. It mentions channel number and its respective channel frequency. All the 13 channels are separated by 2.16 MHz with respect to the adjacent channels. Channel zero starts at 903.08 MHz center frequency. + +## Data-rates + +Various data-rates are selectable when configuring a channel and are inversely proportional to the theoretical range of the devices: + +| Channel setting | Data-rate | +|----------------------------|----------------------| +| Short range (but fast) | 21.875 kbps | +| Medium range (but fast) | 5.469 kbps | +| Long range (but slower) | 0.275 kbps | +| Very long range (but slow) | 0.183 kbps (default) | From 6f6dd2291efecaf9e90a2fdcae3686793254f8a7 Mon Sep 17 00:00:00 2001 From: Kevin Hester Date: Thu, 28 Jan 2021 10:30:00 +0800 Subject: [PATCH 014/258] fix typo --- docs/software/crypto.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/software/crypto.md b/docs/software/crypto.md index cd9f28889..1ee7c6d5d 100644 --- a/docs/software/crypto.md +++ b/docs/software/crypto.md @@ -13,7 +13,7 @@ the project developers are not cryptography experts. Therefore we ask two things Based on comments from reviewers (see below), here's some tips for usage of these radios. So you can know the level of protection offered: * It is pretty likely that the AES256 security is implemented 'correctly' and an observer will not be able to decode your messages. -* Warning: If an attacker is able to get one of the radios in their position, they could either a) extract the channel key from that device or b) use that radio to listen to new communications. +* Warning: If an attacker is able to get one of the radios in their posession, they could either a) extract the channel key from that device or b) use that radio to listen to new communications. * Warning: If an attacker is able to get the "Channel QR code/URL" that you share with others - that attacker could then be able to read any messages sent on the channel (either tomorrow or in the past - if they kept a raw copy of those broadcast packets) Possible future areas of work (if there is enough interest - post in our [forum](https://meshtastic.discourse.group) if you want this): @@ -48,4 +48,4 @@ I'm assuming that meshtastic is being used to hike in places where someone capab * I think the bigger encryption question is "what does the encryption need to do"? As it stands, an attacker who has yet to capture any of the devices cannot reasonably capture text or location data. An attacker who captures any device in the channel/mesh can read everything going to that device, everything stored on that device, and any other communication within the channel that they captured in encrypted form. If that capability basically matches your expectations, it is suitable for whatever adventures this was intended for, then, based on information publicly available or widely disclosed, the encryption is good. If those properties are distressing (like, device history is deliberately limited and you don't want a device captured today to endanger the information sent over the channel yesterday) we could talk about ways to achieve that (most likely synchronizing time and replacing the key with its own SHA256 every X hours, and ensuring the old key is not retained unnecessarily). * Two other things to keep in mind are that AES-CTR does not itself provide authenticity (e.g. an attacker can flip bits in replaying data and scramble the resulting plaintext), and that the current scheme gives some hints about transmission in the size. So, if you worry about an adversary deliberately messing-up messages or knowing the length of a text message, it looks like those might be possible. -I'm guessing that the network behaves somewhat like a store-and-forward network - or, at least, that the goal is to avoid establishing a two-way connection to transmit data. I'm afraid I haven't worked with mesh networks much, but remember studying them briefly in school about ten years ago. \ No newline at end of file +I'm guessing that the network behaves somewhat like a store-and-forward network - or, at least, that the goal is to avoid establishing a two-way connection to transmit data. I'm afraid I haven't worked with mesh networks much, but remember studying them briefly in school about ten years ago. From 6a593e01e1a812ef5e32eb6818b05b1466b5465f Mon Sep 17 00:00:00 2001 From: Kevin Hester Date: Thu, 28 Jan 2021 10:30:24 +0800 Subject: [PATCH 015/258] notes on eink1.0 --- docs/software/TODO.md | 21 +++++++++++++++++++++ variants/eink/variant.h | 2 ++ 2 files changed, 23 insertions(+) diff --git a/docs/software/TODO.md b/docs/software/TODO.md index 69f225917..f6df164b0 100644 --- a/docs/software/TODO.md +++ b/docs/software/TODO.md @@ -2,6 +2,27 @@ You probably don't care about this section - skip to the next one. +eink: + +* new battery level sensing +* measure current draw +* DONE: fix backlight +* USB is busted because of power enable mode? +* OHH BME280! THAT IS GREAT! +* make new screen work, ask for datasheet +* say I think you could ship this +* leds seem busted +* usb doesn't stay connected +* check GPS works +* check GPS fast locking +* send email about variants & faster flash programming - https://github.com/geeksville/Meshtastic-esp32/commit/f110225173a77326aac029321cdb6491bfa640f6 +* send PR for bootloader +* fix nrf52 time/date +* send new master bin file +* send email about low power mode problems +* support new flash chip in appload, possibly use low power mode +* swbug! stuck busy tx occurred! + For app cleanup: * use structured logging to kep logs in ram. Also send logs as packets to api clients diff --git a/variants/eink/variant.h b/variants/eink/variant.h index bd71de3c5..4cdb33e45 100644 --- a/variants/eink/variant.h +++ b/variants/eink/variant.h @@ -243,6 +243,8 @@ External serial flash WP25R1635FZUIL0 #define PIN_SPI_MOSI (0 + 22) #define PIN_SPI_SCK (0 + 19) +#define PIN_PWR_EN (0 + 6) + // To debug via the segger JLINK console rather than the CDC-ACM serial device // #define USE_SEGGER From 2561742683f62881c5b675e409a60c5af575d214 Mon Sep 17 00:00:00 2001 From: Jm Date: Wed, 27 Jan 2021 18:56:09 -0800 Subject: [PATCH 016/258] #664 - Blink the LED when we enter disablePin() --- src/nimble/BluetoothUtil.cpp | 35 +++++++++++++++++++++++------------ 1 file changed, 23 insertions(+), 12 deletions(-) diff --git a/src/nimble/BluetoothUtil.cpp b/src/nimble/BluetoothUtil.cpp index f5f1f77ec..1416453b1 100644 --- a/src/nimble/BluetoothUtil.cpp +++ b/src/nimble/BluetoothUtil.cpp @@ -10,6 +10,7 @@ #include "nimble/NimbleDefs.h" #include "services/gap/ble_svc_gap.h" #include "services/gatt/ble_svc_gatt.h" +#include "sleep.h" #include #include @@ -226,16 +227,14 @@ static int gap_event(struct ble_gap_event *event, void *arg) 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("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 { + 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 + 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); @@ -395,7 +394,6 @@ void gatt_svr_register_cb(struct ble_gatt_register_ctxt *ctxt, void *arg) } } - /** * A helper function that implements simple read and write handling for a uint32_t * @@ -449,8 +447,7 @@ int chr_readwrite8(uint8_t *v, size_t vlen, struct ble_gatt_access_ctxt *ctxt) if (len < vlen) { DEBUG_MSG("Error: wrongsized write\n"); return BLE_ATT_ERR_UNLIKELY; - } - else { + } else { DEBUG_MSG("BLE writing bytes\n"); } } else { @@ -465,7 +462,21 @@ 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 - doublepressed = millis(); + + // 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 routine is called multiple times, once each time we come back from sleep @@ -549,7 +560,7 @@ void setBluetoothEnable(bool on) firstTime = 0; } else { #ifndef NO_ESP32 - initWifi(0); + initWifi(0); #endif } } else { From eff0c1fe892e9b70f4bb4b889aedda31495dd627 Mon Sep 17 00:00:00 2001 From: Jm Date: Wed, 27 Jan 2021 19:18:16 -0800 Subject: [PATCH 017/258] #654 - Partial work for the LED/Speaker. Framework is done. Just need to blink a few things and update protobufs. --- src/plugins/ExternalNotificationPlugin.cpp | 108 +++++++++++++++++++++ src/plugins/ExternalNotificationPlugin.h | 43 ++++++++ src/plugins/Plugins.cpp | 5 +- 3 files changed, 154 insertions(+), 2 deletions(-) create mode 100644 src/plugins/ExternalNotificationPlugin.cpp create mode 100644 src/plugins/ExternalNotificationPlugin.h diff --git a/src/plugins/ExternalNotificationPlugin.cpp b/src/plugins/ExternalNotificationPlugin.cpp new file mode 100644 index 000000000..f2cee7cf7 --- /dev/null +++ b/src/plugins/ExternalNotificationPlugin.cpp @@ -0,0 +1,108 @@ +#include "ExternalNotificationPlugin.h" +#include "MeshService.h" +#include "NodeDB.h" +#include "RTC.h" +#include "Router.h" +#include "configuration.h" +#include + +#include + +/* + + bool ext_notification_plugin_enabled = 126; + uint32 ext_notification_plugin_output_ms = 127; + uint32 ext_notification_plugin_output = 128; + bool ext_notification_plugin_active = 129; + bool ext_notification_plugin_alert_message = 130; + bool ext_notification_plugin_alert_bell = 131; + +*/ + +ExternalNotificationPlugin *externalNotificationPlugin; +ExternalNotificationPluginRadio *externalNotificationPluginRadio; + +ExternalNotificationPlugin::ExternalNotificationPlugin() : concurrency::OSThread("ExternalNotificationPlugin") {} + +int32_t ExternalNotificationPlugin::runOnce() +{ +#ifndef NO_ESP32 + + /* + Uncomment the preferences below if you want to use the plugin + without having to configure it from the PythonAPI or WebUI. + */ + + // radioConfig.preferences.externalnotificationplugin_enabled = 1; + // radioConfig.preferences.externalnotificationplugin_mode = 1; + + if (0) { + + if (firstTime) { + + DEBUG_MSG("Initializing External Notification Plugin\n"); + + externalNotificationPluginRadio = new ExternalNotificationPluginRadio(); + + firstTime = 0; + + } else { + /* + + 1) If GPIO is turned on ... + 2) Check the timer. If the timer has elapsed more time than + our set limit, turn the GPIO off. + + */ + } + + return (25); + } else { + DEBUG_MSG("External Notification Plugin Disabled\n"); + + return (INT32_MAX); + } + +#endif +} + +// -------- + +MeshPacket *ExternalNotificationPluginRadio::allocReply() +{ + + auto reply = allocDataPacket(); // Allocate a packet for sending + + return reply; +} + +bool ExternalNotificationPluginRadio::handleReceived(const MeshPacket &mp) +{ +#ifndef NO_ESP32 + + if (0) { + + auto &p = mp.decoded.data; + + if (mp.from != nodeDB.getNodeNum()) { + + /* + TODO: If ext_notification_plugin_alert_bell is true and we see a bell character, trigger an external notification. + */ + // TODO: Check p.payload.bytes to see if it contains a bell character. If it does, trigger an external notifcation. + + /* + TODO: If ext_notification_plugin_alert_message is true, trigger an external notification. + */ + // TODO: On received packet, blink the LED. + + } + + } else { + DEBUG_MSG("External Notification Plugin Disabled\n"); + } + +#endif + + return true; // Let others look at this message also if they want +} diff --git a/src/plugins/ExternalNotificationPlugin.h b/src/plugins/ExternalNotificationPlugin.h new file mode 100644 index 000000000..b8eeffe40 --- /dev/null +++ b/src/plugins/ExternalNotificationPlugin.h @@ -0,0 +1,43 @@ +#pragma once + +#include "SinglePortPlugin.h" +#include "concurrency/OSThread.h" +#include "configuration.h" +#include +#include + + +class ExternalNotificationPlugin : private concurrency::OSThread +{ + bool firstTime = 1; + + public: + ExternalNotificationPlugin(); + + protected: + virtual int32_t runOnce(); +}; + +extern ExternalNotificationPlugin *externalNotificationPlugin; + +/* + * Radio interface for ExternalNotificationPlugin + * + */ +class ExternalNotificationPluginRadio : public SinglePortPlugin +{ + + public: + ExternalNotificationPluginRadio() : SinglePortPlugin("ExternalNotificationPluginRadio", PortNum_TEXT_MESSAGE_APP) {} + + protected: + virtual MeshPacket *allocReply(); + + /** Called to handle a particular incoming message + + @return true if you've guaranteed you've handled this message and no other handlers should be considered for it + */ + virtual bool handleReceived(const MeshPacket &mp); +}; + +extern ExternalNotificationPluginRadio *externalNotificationPluginRadio; \ No newline at end of file diff --git a/src/plugins/Plugins.cpp b/src/plugins/Plugins.cpp index 096b9cf5d..90a1b554f 100644 --- a/src/plugins/Plugins.cpp +++ b/src/plugins/Plugins.cpp @@ -1,3 +1,4 @@ +#include "plugins/ExternalNotificationPlugin.h" #include "plugins/NodeInfoPlugin.h" #include "plugins/PositionPlugin.h" #include "plugins/RemoteHardwarePlugin.h" @@ -23,7 +24,7 @@ void setupPlugins() #ifndef NO_ESP32 // Only run on an esp32 based device. - new SerialPlugin(); // Maintained by MC Hamster (Jm Casler) jm@casler.org + new SerialPlugin(); // Maintained by MC Hamster (Jm Casler) jm@casler.org + new ExternalNotificationPlugin(); // Maintained by MC Hamster (Jm Casler) jm@casler.org #endif - } \ No newline at end of file From 2246564279ad41265a2b5e8a51d14036b1bb479a Mon Sep 17 00:00:00 2001 From: Jm Date: Wed, 27 Jan 2021 20:06:39 -0800 Subject: [PATCH 018/258] #654 - Small changes. --- src/plugins/ExternalNotificationPlugin.cpp | 38 ++++++++++++++++++++-- src/plugins/ExternalNotificationPlugin.h | 3 ++ 2 files changed, 39 insertions(+), 2 deletions(-) diff --git a/src/plugins/ExternalNotificationPlugin.cpp b/src/plugins/ExternalNotificationPlugin.cpp index f2cee7cf7..fe5a57aeb 100644 --- a/src/plugins/ExternalNotificationPlugin.cpp +++ b/src/plugins/ExternalNotificationPlugin.cpp @@ -36,7 +36,7 @@ int32_t ExternalNotificationPlugin::runOnce() // radioConfig.preferences.externalnotificationplugin_enabled = 1; // radioConfig.preferences.externalnotificationplugin_mode = 1; - if (0) { + if (1) { if (firstTime) { @@ -46,6 +46,16 @@ int32_t ExternalNotificationPlugin::runOnce() firstTime = 0; + // Set the direction of a pin + pinMode(13, OUTPUT); + + // if ext_notification_plugin_active + if (1) { + setExternalOff(); + } else { + setExternalOn(); + } + } else { /* @@ -66,6 +76,27 @@ int32_t ExternalNotificationPlugin::runOnce() #endif } +void ExternalNotificationPlugin::setExternalOn() +{ + // if ext_notification_plugin_active + if (1) { + digitalWrite(13, true); + + } else { + digitalWrite(13, false); + } +} + +void ExternalNotificationPlugin::setExternalOff() +{ + // if ext_notification_plugin_active + if (1) { + digitalWrite(13, false); + } else { + digitalWrite(13, true); + } +} + // -------- MeshPacket *ExternalNotificationPluginRadio::allocReply() @@ -80,7 +111,7 @@ bool ExternalNotificationPluginRadio::handleReceived(const MeshPacket &mp) { #ifndef NO_ESP32 - if (0) { + if (1) { auto &p = mp.decoded.data; @@ -95,6 +126,9 @@ bool ExternalNotificationPluginRadio::handleReceived(const MeshPacket &mp) TODO: If ext_notification_plugin_alert_message is true, trigger an external notification. */ // TODO: On received packet, blink the LED. + externalNotificationPlugin->setExternalOn(); + delay(500); + externalNotificationPlugin->setExternalOff(); } diff --git a/src/plugins/ExternalNotificationPlugin.h b/src/plugins/ExternalNotificationPlugin.h index b8eeffe40..544748341 100644 --- a/src/plugins/ExternalNotificationPlugin.h +++ b/src/plugins/ExternalNotificationPlugin.h @@ -14,6 +14,9 @@ class ExternalNotificationPlugin : private concurrency::OSThread public: ExternalNotificationPlugin(); + void setExternalOn(); + void setExternalOff(); + protected: virtual int32_t runOnce(); }; From 5e303f8a1f7b7993210555a43d365ab7d7154c82 Mon Sep 17 00:00:00 2001 From: Jm Casler Date: Wed, 27 Jan 2021 21:20:18 -0800 Subject: [PATCH 019/258] #654 - Work in progress. Needs testing, non-blocking alert and integration with configuration --- src/plugins/ExternalNotificationPlugin.cpp | 71 +++++++++++++++------- src/plugins/ExternalNotificationPlugin.h | 2 + 2 files changed, 50 insertions(+), 23 deletions(-) diff --git a/src/plugins/ExternalNotificationPlugin.cpp b/src/plugins/ExternalNotificationPlugin.cpp index fe5a57aeb..95164d42a 100644 --- a/src/plugins/ExternalNotificationPlugin.cpp +++ b/src/plugins/ExternalNotificationPlugin.cpp @@ -10,15 +10,30 @@ /* +This plugin supports: + https://github.com/meshtastic/Meshtastic-device/issues/654 + + bool ext_notification_plugin_enabled = 126; - uint32 ext_notification_plugin_output_ms = 127; - uint32 ext_notification_plugin_output = 128; bool ext_notification_plugin_active = 129; bool ext_notification_plugin_alert_message = 130; bool ext_notification_plugin_alert_bell = 131; + uint32 ext_notification_plugin_output = 128; + + + uint32 ext_notification_plugin_output_ms = 127; */ +#define EXT_NOTIFICATION_PLUGIN_ENABLED 1 +#define EXT_NOTIFICATION_PLUGIN_ACTIVE 1 +#define EXT_NOTIFICATION_PLUGIN_ALERT_MESSAGE 1 +#define EXT_NOTIFICATION_PLUGIN_ALERT_BELL 1 +#define EXT_NOTIFICATION_PLUGIN_OUTPUT 13 +#define EXT_NOTIFICATION_PLUGIN_OUTPUT_MS 100 + +#define ASCII_BELL 0x07 + ExternalNotificationPlugin *externalNotificationPlugin; ExternalNotificationPluginRadio *externalNotificationPluginRadio; @@ -36,7 +51,7 @@ int32_t ExternalNotificationPlugin::runOnce() // radioConfig.preferences.externalnotificationplugin_enabled = 1; // radioConfig.preferences.externalnotificationplugin_mode = 1; - if (1) { + if (EXT_NOTIFICATION_PLUGIN_ENABLED) { if (firstTime) { @@ -47,10 +62,10 @@ int32_t ExternalNotificationPlugin::runOnce() firstTime = 0; // Set the direction of a pin - pinMode(13, OUTPUT); + pinMode(EXT_NOTIFICATION_PLUGIN_OUTPUT, OUTPUT); // if ext_notification_plugin_active - if (1) { + if (EXT_NOTIFICATION_PLUGIN_ACTIVE) { setExternalOff(); } else { setExternalOn(); @@ -78,22 +93,26 @@ int32_t ExternalNotificationPlugin::runOnce() void ExternalNotificationPlugin::setExternalOn() { + externalCurrentState = 1; + // if ext_notification_plugin_active - if (1) { - digitalWrite(13, true); + if (EXT_NOTIFICATION_PLUGIN_ACTIVE) { + digitalWrite(EXT_NOTIFICATION_PLUGIN_OUTPUT, true); } else { - digitalWrite(13, false); + digitalWrite(EXT_NOTIFICATION_PLUGIN_OUTPUT, false); } } void ExternalNotificationPlugin::setExternalOff() { + externalCurrentState = 0; + // if ext_notification_plugin_active - if (1) { - digitalWrite(13, false); + if (EXT_NOTIFICATION_PLUGIN_ACTIVE) { + digitalWrite(EXT_NOTIFICATION_PLUGIN_OUTPUT, false); } else { - digitalWrite(13, true); + digitalWrite(EXT_NOTIFICATION_PLUGIN_OUTPUT, true); } } @@ -111,25 +130,31 @@ bool ExternalNotificationPluginRadio::handleReceived(const MeshPacket &mp) { #ifndef NO_ESP32 - if (1) { + if (EXT_NOTIFICATION_PLUGIN_ENABLED) { auto &p = mp.decoded.data; if (mp.from != nodeDB.getNodeNum()) { - /* - TODO: If ext_notification_plugin_alert_bell is true and we see a bell character, trigger an external notification. - */ - // TODO: Check p.payload.bytes to see if it contains a bell character. If it does, trigger an external notifcation. + if (EXT_NOTIFICATION_PLUGIN_ALERT_BELL) { + for (int i = 0; i < p.payload.size; i++) { + if (p.payload.bytes[i] == ASCII_BELL) { + externalNotificationPlugin->setExternalOn(); - /* - TODO: If ext_notification_plugin_alert_message is true, trigger an external notification. - */ - // TODO: On received packet, blink the LED. - externalNotificationPlugin->setExternalOn(); - delay(500); - externalNotificationPlugin->setExternalOff(); + // TODO: Make this non-blocking. + delay(EXT_NOTIFICATION_PLUGIN_OUTPUT_MS); + externalNotificationPlugin->setExternalOff(); + } + } + } + if (EXT_NOTIFICATION_PLUGIN_ALERT_MESSAGE) { + externalNotificationPlugin->setExternalOn(); + + // TODO: Make this non-blocking. + delay(EXT_NOTIFICATION_PLUGIN_OUTPUT_MS); + externalNotificationPlugin->setExternalOff(); + } } } else { diff --git a/src/plugins/ExternalNotificationPlugin.h b/src/plugins/ExternalNotificationPlugin.h index 544748341..ff36c2a77 100644 --- a/src/plugins/ExternalNotificationPlugin.h +++ b/src/plugins/ExternalNotificationPlugin.h @@ -10,12 +10,14 @@ class ExternalNotificationPlugin : private concurrency::OSThread { bool firstTime = 1; + bool externalCurrentState = 0; public: ExternalNotificationPlugin(); void setExternalOn(); void setExternalOff(); + void getExternal(); protected: virtual int32_t runOnce(); From c524732849305ea3fe9c163f953600ce1fdd2e45 Mon Sep 17 00:00:00 2001 From: Jm Casler Date: Wed, 27 Jan 2021 21:35:07 -0800 Subject: [PATCH 020/258] #654 - Non blocking call to toggle the output. --- src/plugins/ExternalNotificationPlugin.cpp | 23 ++++++++-------------- src/plugins/ExternalNotificationPlugin.h | 1 + 2 files changed, 9 insertions(+), 15 deletions(-) diff --git a/src/plugins/ExternalNotificationPlugin.cpp b/src/plugins/ExternalNotificationPlugin.cpp index 95164d42a..74334d01e 100644 --- a/src/plugins/ExternalNotificationPlugin.cpp +++ b/src/plugins/ExternalNotificationPlugin.cpp @@ -12,7 +12,7 @@ This plugin supports: https://github.com/meshtastic/Meshtastic-device/issues/654 - + bool ext_notification_plugin_enabled = 126; bool ext_notification_plugin_active = 129; @@ -72,13 +72,13 @@ int32_t ExternalNotificationPlugin::runOnce() } } else { - /* + if (externalCurrentState) { - 1) If GPIO is turned on ... - 2) Check the timer. If the timer has elapsed more time than - our set limit, turn the GPIO off. - - */ + // TODO: Test this part. Don't know if this should be greater than or less than. + if (externalTurnedOn + EXT_NOTIFICATION_PLUGIN_OUTPUT_MS < millis()) { + setExternalOff(); + } + } } return (25); @@ -94,6 +94,7 @@ int32_t ExternalNotificationPlugin::runOnce() void ExternalNotificationPlugin::setExternalOn() { externalCurrentState = 1; + externalTurnedOn = millis(); // if ext_notification_plugin_active if (EXT_NOTIFICATION_PLUGIN_ACTIVE) { @@ -140,20 +141,12 @@ bool ExternalNotificationPluginRadio::handleReceived(const MeshPacket &mp) for (int i = 0; i < p.payload.size; i++) { if (p.payload.bytes[i] == ASCII_BELL) { externalNotificationPlugin->setExternalOn(); - - // TODO: Make this non-blocking. - delay(EXT_NOTIFICATION_PLUGIN_OUTPUT_MS); - externalNotificationPlugin->setExternalOff(); } } } if (EXT_NOTIFICATION_PLUGIN_ALERT_MESSAGE) { externalNotificationPlugin->setExternalOn(); - - // TODO: Make this non-blocking. - delay(EXT_NOTIFICATION_PLUGIN_OUTPUT_MS); - externalNotificationPlugin->setExternalOff(); } } diff --git a/src/plugins/ExternalNotificationPlugin.h b/src/plugins/ExternalNotificationPlugin.h index ff36c2a77..6de72fda6 100644 --- a/src/plugins/ExternalNotificationPlugin.h +++ b/src/plugins/ExternalNotificationPlugin.h @@ -11,6 +11,7 @@ class ExternalNotificationPlugin : private concurrency::OSThread { bool firstTime = 1; bool externalCurrentState = 0; + uint32_t externalTurnedOn = 0; public: ExternalNotificationPlugin(); From c81d090464ca9d69bda47f4ad4835650082bd93f Mon Sep 17 00:00:00 2001 From: Kevin Hester Date: Fri, 29 Jan 2021 10:14:36 +0800 Subject: [PATCH 021/258] someone added storerequest app? --- proto | 2 +- src/mesh/generated/deviceonly.pb.h | 2 +- src/mesh/generated/mesh.pb.h | 40 +++++++++++++++++++++++------- src/mesh/generated/portnums.pb.h | 1 + 4 files changed, 34 insertions(+), 11 deletions(-) diff --git a/proto b/proto index 855da8701..c9ad10d7e 160000 --- a/proto +++ b/proto @@ -1 +1 @@ -Subproject commit 855da8701edbb19818069ad8545d5b9f030bb33f +Subproject commit c9ad10d7e2f7f465dc477e98d6ec9d3b7059336c diff --git a/src/mesh/generated/deviceonly.pb.h b/src/mesh/generated/deviceonly.pb.h index c3e556669..a6388af96 100644 --- a/src/mesh/generated/deviceonly.pb.h +++ b/src/mesh/generated/deviceonly.pb.h @@ -80,7 +80,7 @@ extern const pb_msgdesc_t DeviceState_msg; #define DeviceState_fields &DeviceState_msg /* Maximum encoded size of messages (where known) */ -#define DeviceState_size 6206 +#define DeviceState_size 6239 #ifdef __cplusplus } /* extern "C" */ diff --git a/src/mesh/generated/mesh.pb.h b/src/mesh/generated/mesh.pb.h index 50ae14a6a..a13d7de56 100644 --- a/src/mesh/generated/mesh.pb.h +++ b/src/mesh/generated/mesh.pb.h @@ -57,6 +57,7 @@ typedef enum _ChargeCurrent { typedef enum _GpsOperation { GpsOperation_GpsOpUnset = 0, + GpsOperation_GpsOpStationary = 1, GpsOperation_GpsOpMobile = 2, GpsOperation_GpsOpTimeOnly = 3, GpsOperation_GpsOpDisabled = 4 @@ -183,6 +184,13 @@ typedef struct _RadioConfig_UserPreferences { uint32_t serialplugin_rxd; uint32_t serialplugin_txd; uint32_t serialplugin_timeout; + uint32_t serialplugin_mode; + bool ext_notification_plugin_enabled; + uint32_t ext_notification_plugin_output_ms; + uint32_t ext_notification_plugin_output; + bool ext_notification_plugin_active; + bool ext_notification_plugin_alert_message; + bool ext_notification_plugin_alert_bell; } RadioConfig_UserPreferences; typedef struct _RouteDiscovery { @@ -305,8 +313,8 @@ typedef struct _ToRadio { #define _LocationSharing_ARRAYSIZE ((LocationSharing)(LocationSharing_LocDisabled+1)) #define _CriticalErrorCode_MIN CriticalErrorCode_None -#define _CriticalErrorCode_MAX CriticalErrorCode_InvalidRadioSetting -#define _CriticalErrorCode_ARRAYSIZE ((CriticalErrorCode)(CriticalErrorCode_InvalidRadioSetting+1)) +#define _CriticalErrorCode_MAX CriticalErrorCode_TransmitFailed +#define _CriticalErrorCode_ARRAYSIZE ((CriticalErrorCode)(CriticalErrorCode_TransmitFailed+1)) #define _ChannelSettings_ModemConfig_MIN ChannelSettings_ModemConfig_Bw125Cr45Sf128 #define _ChannelSettings_ModemConfig_MAX ChannelSettings_ModemConfig_Bw125Cr48Sf4096 @@ -330,7 +338,7 @@ extern "C" { #define MeshPacket_init_default {0, 0, 0, {SubPacket_init_default}, 0, 0, 0, 0, 0, 0} #define ChannelSettings_init_default {0, _ChannelSettings_ModemConfig_MIN, {0, {0}}, "", 0, 0, 0, 0, 0, 0, 0} #define RadioConfig_init_default {false, RadioConfig_UserPreferences_init_default, false, ChannelSettings_init_default} -#define RadioConfig_UserPreferences_init_default {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, "", "", 0, _RegionCode_MIN, _ChargeCurrent_MIN, _LocationSharing_MIN, _GpsOperation_MIN, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0}, 0, 0, 0, 0, 0} +#define RadioConfig_UserPreferences_init_default {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, "", "", 0, _RegionCode_MIN, _ChargeCurrent_MIN, _LocationSharing_MIN, _GpsOperation_MIN, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0}, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} #define NodeInfo_init_default {0, false, User_init_default, false, Position_init_default, 0, 0} #define MyNodeInfo_init_default {0, 0, 0, "", "", "", _CriticalErrorCode_MIN, 0, 0, 0, 0, 0, 0, 0} #define LogRecord_init_default {"", 0, "", _LogRecord_Level_MIN} @@ -344,7 +352,7 @@ extern "C" { #define MeshPacket_init_zero {0, 0, 0, {SubPacket_init_zero}, 0, 0, 0, 0, 0, 0} #define ChannelSettings_init_zero {0, _ChannelSettings_ModemConfig_MIN, {0, {0}}, "", 0, 0, 0, 0, 0, 0, 0} #define RadioConfig_init_zero {false, RadioConfig_UserPreferences_init_zero, false, ChannelSettings_init_zero} -#define RadioConfig_UserPreferences_init_zero {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, "", "", 0, _RegionCode_MIN, _ChargeCurrent_MIN, _LocationSharing_MIN, _GpsOperation_MIN, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0}, 0, 0, 0, 0, 0} +#define RadioConfig_UserPreferences_init_zero {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, "", "", 0, _RegionCode_MIN, _ChargeCurrent_MIN, _LocationSharing_MIN, _GpsOperation_MIN, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0}, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} #define NodeInfo_init_zero {0, false, User_init_zero, false, Position_init_zero, 0, 0} #define MyNodeInfo_init_zero {0, 0, 0, "", "", "", _CriticalErrorCode_MIN, 0, 0, 0, 0, 0, 0, 0} #define LogRecord_init_zero {"", 0, "", _LogRecord_Level_MIN} @@ -418,6 +426,13 @@ extern "C" { #define RadioConfig_UserPreferences_serialplugin_rxd_tag 122 #define RadioConfig_UserPreferences_serialplugin_txd_tag 123 #define RadioConfig_UserPreferences_serialplugin_timeout_tag 124 +#define RadioConfig_UserPreferences_serialplugin_mode_tag 125 +#define RadioConfig_UserPreferences_ext_notification_plugin_enabled_tag 126 +#define RadioConfig_UserPreferences_ext_notification_plugin_output_ms_tag 127 +#define RadioConfig_UserPreferences_ext_notification_plugin_output_tag 128 +#define RadioConfig_UserPreferences_ext_notification_plugin_active_tag 129 +#define RadioConfig_UserPreferences_ext_notification_plugin_alert_message_tag 130 +#define RadioConfig_UserPreferences_ext_notification_plugin_alert_bell_tag 131 #define RouteDiscovery_route_tag 2 #define User_id_tag 1 #define User_long_name_tag 2 @@ -585,7 +600,14 @@ X(a, STATIC, SINGULAR, BOOL, serialplugin_enabled, 120) \ X(a, STATIC, SINGULAR, BOOL, serialplugin_echo, 121) \ X(a, STATIC, SINGULAR, UINT32, serialplugin_rxd, 122) \ X(a, STATIC, SINGULAR, UINT32, serialplugin_txd, 123) \ -X(a, STATIC, SINGULAR, UINT32, serialplugin_timeout, 124) +X(a, STATIC, SINGULAR, UINT32, serialplugin_timeout, 124) \ +X(a, STATIC, SINGULAR, UINT32, serialplugin_mode, 125) \ +X(a, STATIC, SINGULAR, BOOL, ext_notification_plugin_enabled, 126) \ +X(a, STATIC, SINGULAR, UINT32, ext_notification_plugin_output_ms, 127) \ +X(a, STATIC, SINGULAR, UINT32, ext_notification_plugin_output, 128) \ +X(a, STATIC, SINGULAR, BOOL, ext_notification_plugin_active, 129) \ +X(a, STATIC, SINGULAR, BOOL, ext_notification_plugin_alert_message, 130) \ +X(a, STATIC, SINGULAR, BOOL, ext_notification_plugin_alert_bell, 131) #define RadioConfig_UserPreferences_CALLBACK NULL #define RadioConfig_UserPreferences_DEFAULT NULL @@ -697,13 +719,13 @@ extern const pb_msgdesc_t ToRadio_msg; #define SubPacket_size 275 #define MeshPacket_size 320 #define ChannelSettings_size 95 -#define RadioConfig_size 349 -#define RadioConfig_UserPreferences_size 249 +#define RadioConfig_size 382 +#define RadioConfig_UserPreferences_size 282 #define NodeInfo_size 132 #define MyNodeInfo_size 106 #define LogRecord_size 81 -#define FromRadio_size 358 -#define ToRadio_size 353 +#define FromRadio_size 391 +#define ToRadio_size 386 #ifdef __cplusplus } /* extern "C" */ diff --git a/src/mesh/generated/portnums.pb.h b/src/mesh/generated/portnums.pb.h index 91c988fdc..99df1222d 100644 --- a/src/mesh/generated/portnums.pb.h +++ b/src/mesh/generated/portnums.pb.h @@ -19,6 +19,7 @@ typedef enum _PortNum { PortNum_REPLY_APP = 32, PortNum_IP_TUNNEL_APP = 33, PortNum_SERIAL_APP = 64, + PortNum_STORE_REQUEST_APP = 65, PortNum_PRIVATE_APP = 256, PortNum_ATAK_FORWARDER = 257 } PortNum; From 7f077258400ce081c6eff6dd99c78e64ffee3927 Mon Sep 17 00:00:00 2001 From: Kevin Hester Date: Fri, 29 Jan 2021 10:15:48 +0800 Subject: [PATCH 022/258] make improperly sized AES128/256 keys non fatal, instead pad with zeros Fixes rebooting the board if someone specifies an invalid key --- src/mesh/NodeDB.cpp | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/src/mesh/NodeDB.cpp b/src/mesh/NodeDB.cpp index 42ce71ea7..ea79e6ccb 100644 --- a/src/mesh/NodeDB.cpp +++ b/src/mesh/NodeDB.cpp @@ -180,10 +180,14 @@ bool NodeDB::resetRadioConfig() channelSettings.psk.size = 1; } - // Convert the short single byte variants of psk into variant that can be used more generally + memset(activePSK, 0, sizeof(activePSK)); // In case the user provided a short key, we want to pad the rest with zeros memcpy(activePSK, channelSettings.psk.bytes, channelSettings.psk.size); activePSKSize = channelSettings.psk.size; - if (activePSKSize == 1) { + if(activePSKSize == 0) + DEBUG_MSG("Warning: User disabled encryption\n"); + else if (activePSKSize == 1) { + // Convert the short single byte variants of psk into variant that can be used more generally + uint8_t pskIndex = activePSK[0]; DEBUG_MSG("Expanding short PSK #%d\n", pskIndex); if (pskIndex == 0) @@ -195,6 +199,16 @@ bool NodeDB::resetRadioConfig() uint8_t *last = activePSK + sizeof(defaultpsk) - 1; *last = *last + pskIndex - 1; // index of 1 means no change vs defaultPSK } + } else if(activePSKSize < 16) { + // Error! The user specified only the first few bits of an AES128 key. So by convention we just pad the rest of the key + // with zeros + DEBUG_MSG("Warning: User provided a too short AES128 key - padding\n"); + activePSKSize = 16; + } else if(activePSKSize < 32 && activePSKSize != 16) { + // Error! The user specified only the first few bits of an AES256 key. So by convention we just pad the rest of the key + // with zeros + DEBUG_MSG("Warning: User provided a too short AES256 key - padding\n"); + activePSKSize = 32; } // Tell our crypto engine about the psk From c6f34c59b4c91247a869d1c6a394218000fb5e86 Mon Sep 17 00:00:00 2001 From: Kevin Hester Date: Fri, 29 Jan 2021 13:26:08 +0800 Subject: [PATCH 023/258] Update to logo by @thepoweroftwo --- .gitmodules | 3 ++ bin/gen-images.sh | 19 +++++++++++ {images => deprecated}/icon-18dp.png | Bin {images => deprecated}/icon-24px.svg | 0 {images => deprecated}/icon.png | Bin design | 1 + images/genfiles.sh | 11 ------ src/graphics/img/icon.xbm | 49 ++++++++++----------------- 8 files changed, 41 insertions(+), 42 deletions(-) create mode 100755 bin/gen-images.sh rename {images => deprecated}/icon-18dp.png (100%) rename {images => deprecated}/icon-24px.svg (100%) rename {images => deprecated}/icon.png (100%) create mode 160000 design delete mode 100755 images/genfiles.sh diff --git a/.gitmodules b/.gitmodules index 785c573a4..4f9bb6b77 100644 --- a/.gitmodules +++ b/.gitmodules @@ -4,3 +4,6 @@ [submodule "sdk-nrfxlib"] path = sdk-nrfxlib url = https://github.com/nrfconnect/sdk-nrfxlib.git +[submodule "design"] + path = design + url = https://github.com/meshtastic/meshtastic-design.git diff --git a/bin/gen-images.sh b/bin/gen-images.sh new file mode 100755 index 000000000..c4335718e --- /dev/null +++ b/bin/gen-images.sh @@ -0,0 +1,19 @@ + + +set -e + +# regen the design bins first +cd design +bin/generate-pngs.sh +cd .. + +# assumes 50 wide, 28 high +convert design/logo/png/Mesh_Logo_Black_Small.png -background white -alpha Background src/graphics/img/icon.xbm + +inkscape --batch-process -o images/compass.png -w 48 -h 48 images/location_searching-24px.svg +convert compass.png -background white -alpha Background src/graphics/img/compass.xbm + +inkscape --batch-process -o images/face.png -w 13 -h 13 images/face-24px.svg + +inkscape --batch-process -o images/pin.png -w 13 -h 13 images/room-24px.svg +convert pin.png -background white -alpha Background src/graphics/img/pin.xbm diff --git a/images/icon-18dp.png b/deprecated/icon-18dp.png similarity index 100% rename from images/icon-18dp.png rename to deprecated/icon-18dp.png diff --git a/images/icon-24px.svg b/deprecated/icon-24px.svg similarity index 100% rename from images/icon-24px.svg rename to deprecated/icon-24px.svg diff --git a/images/icon.png b/deprecated/icon.png similarity index 100% rename from images/icon.png rename to deprecated/icon.png diff --git a/design b/design new file mode 160000 index 000000000..73ba05cee --- /dev/null +++ b/design @@ -0,0 +1 @@ +Subproject commit 73ba05ceef8beff81eb546a0b9e8ecad03a1216d diff --git a/images/genfiles.sh b/images/genfiles.sh deleted file mode 100755 index bc14f6e8e..000000000 --- a/images/genfiles.sh +++ /dev/null @@ -1,11 +0,0 @@ -# using height of 50 to have 14 pixels beneath icon for text -inkscape -z -e icon.png -w 50 -h 50 icon-24px.svg -convert icon.png -background white -alpha Background ../src/icon.xbm - -inkscape -z -e compass.png -w 48 -h 48 location_searching-24px.svg -convert compass.png -background white -alpha Background ../src/compass.xbm - -inkscape -z -e face.png -w 13 -h 13 face-24px.svg - -inkscape -z -e pin.png -w 13 -h 13 room-24px.svg -convert pin.png -background white -alpha Background ../src/pin.xbm diff --git a/src/graphics/img/icon.xbm b/src/graphics/img/icon.xbm index d7394c8e7..2b698e4c9 100644 --- a/src/graphics/img/icon.xbm +++ b/src/graphics/img/icon.xbm @@ -1,33 +1,20 @@ #define icon_width 50 -#define icon_height 50 +#define icon_height 28 static char icon_bits[] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0xFC, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x80, 0xFF, - 0xFF, 0x07, 0x00, 0x00, 0x00, 0xE0, 0xFF, 0xFF, 0x1F, 0x00, 0x00, 0x00, - 0xF0, 0xFF, 0xFF, 0x3F, 0x00, 0x00, 0x00, 0xFC, 0xFF, 0xFF, 0xFF, 0x00, - 0x00, 0x00, 0xFE, 0x0F, 0xC0, 0xFF, 0x01, 0x00, 0x00, 0xFF, 0x03, 0x00, - 0xFF, 0x03, 0x00, 0x80, 0xFF, 0x00, 0x00, 0xFC, 0x07, 0x00, 0xC0, 0x3F, - 0xE0, 0x1F, 0xF0, 0x0F, 0x00, 0xC0, 0x1F, 0xFC, 0xFF, 0xE0, 0x0F, 0x00, - 0xE0, 0x0F, 0xFF, 0xFF, 0xC3, 0x1F, 0x00, 0xF0, 0x87, 0xFF, 0xFF, 0x87, - 0x3F, 0x00, 0xF0, 0xC3, 0xFF, 0xFF, 0x0F, 0x3F, 0x00, 0xF8, 0xE3, 0x7F, - 0xF8, 0x1F, 0x7F, 0x00, 0xF8, 0xF1, 0x0F, 0xC0, 0x3F, 0x7E, 0x00, 0xF8, - 0xF1, 0x07, 0x80, 0x3F, 0x7E, 0x00, 0xFC, 0xF8, 0x03, 0x00, 0x7F, 0xFC, - 0x00, 0xFC, 0xF8, 0x81, 0x07, 0x7E, 0xFC, 0x00, 0x7C, 0xF8, 0xE0, 0x1F, - 0x7C, 0xF8, 0x00, 0x7C, 0xFC, 0xF0, 0x3F, 0xFC, 0xF8, 0x00, 0x7C, 0xFC, - 0xF0, 0x3F, 0xFC, 0xF8, 0x00, 0x7C, 0x7C, 0xF8, 0x7F, 0xF8, 0xF8, 0x00, - 0x7C, 0x7C, 0xF8, 0x7F, 0xF8, 0xF8, 0x00, 0x00, 0x00, 0xF8, 0x7F, 0x00, - 0x00, 0x00, 0x00, 0x00, 0xF8, 0x7F, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, - 0x3F, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0x3F, 0x00, 0x00, 0x00, 0x00, - 0x00, 0xE0, 0x1F, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x0F, 0x00, 0x00, - 0x00, 0x00, 0x00, 0xC0, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x0F, - 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xC0, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x0F, 0x00, 0x00, 0x00, - 0x00, 0x00, 0xC0, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0x1F, 0x00, - 0x00, 0x00, 0x00, 0x00, 0xF0, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, - 0x7F, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFC, 0xFF, 0x00, 0x00, 0x00, 0x00, - 0x00, 0xFE, 0xFF, 0x01, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFC, 0x03, 0x00, - 0x00, 0x00, 0x80, 0x7F, 0xF8, 0x07, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xF0, - 0x03, 0x00, 0x00, 0x00, 0x00, 0x1E, 0xE0, 0x01, 0x00, 0x00, 0x00, 0x00, - 0x0C, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, }; + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x03, 0x00, 0x03, + 0x00, 0x00, 0x00, 0x80, 0x07, 0xC0, 0x07, 0x00, 0x00, 0x00, 0xC0, 0x1F, + 0xC0, 0x0F, 0x00, 0x00, 0x00, 0xE0, 0x0F, 0xE0, 0x0F, 0x00, 0x00, 0x00, + 0xE0, 0x0F, 0xF0, 0x1F, 0x00, 0x00, 0x00, 0xF0, 0x07, 0xF0, 0x3F, 0x00, + 0x00, 0x00, 0xF8, 0x03, 0xF8, 0x7F, 0x00, 0x00, 0x00, 0xF8, 0x03, 0xFC, + 0x7F, 0x00, 0x00, 0x00, 0xFC, 0x01, 0xFC, 0xFE, 0x00, 0x00, 0x00, 0xFE, + 0x00, 0xFE, 0xFC, 0x01, 0x00, 0x00, 0xFE, 0x00, 0x7F, 0xFC, 0x01, 0x00, + 0x00, 0x7F, 0x00, 0x3F, 0xF8, 0x03, 0x00, 0x80, 0x3F, 0x80, 0x3F, 0xF0, + 0x07, 0x00, 0x80, 0x3F, 0xC0, 0x1F, 0xF0, 0x07, 0x00, 0xC0, 0x1F, 0xC0, + 0x0F, 0xE0, 0x0F, 0x00, 0xE0, 0x0F, 0xE0, 0x0F, 0xC0, 0x1F, 0x00, 0xE0, + 0x0F, 0xF0, 0x07, 0x80, 0x1F, 0x00, 0xF0, 0x07, 0xF8, 0x03, 0x80, 0x3F, + 0x00, 0xF8, 0x03, 0xF8, 0x03, 0x00, 0x7F, 0x00, 0xFC, 0x03, 0xFC, 0x01, + 0x00, 0x7E, 0x00, 0xFC, 0x01, 0xFE, 0x00, 0x00, 0xFE, 0x00, 0xFE, 0x00, + 0xFE, 0x00, 0x00, 0xFC, 0x01, 0x7E, 0x00, 0x7F, 0x00, 0x00, 0xF8, 0x01, + 0x7E, 0x00, 0x3E, 0x00, 0x00, 0xF8, 0x01, 0x38, 0x00, 0x3C, 0x00, 0x00, + 0x70, 0x00, 0x10, 0x00, 0x10, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, }; From 85752b0fc79018fa3c84c01c9df79417fe4181f8 Mon Sep 17 00:00:00 2001 From: Jm Date: Thu, 28 Jan 2021 23:02:00 -0800 Subject: [PATCH 024/258] #654 - Fixed problem with class namespaces. --- src/plugins/ExternalNotificationPlugin.cpp | 32 +++++++++++----------- src/plugins/ExternalNotificationPlugin.h | 4 +-- 2 files changed, 17 insertions(+), 19 deletions(-) diff --git a/src/plugins/ExternalNotificationPlugin.cpp b/src/plugins/ExternalNotificationPlugin.cpp index 74334d01e..3f759b7f2 100644 --- a/src/plugins/ExternalNotificationPlugin.cpp +++ b/src/plugins/ExternalNotificationPlugin.cpp @@ -25,12 +25,12 @@ This plugin supports: */ -#define EXT_NOTIFICATION_PLUGIN_ENABLED 1 -#define EXT_NOTIFICATION_PLUGIN_ACTIVE 1 +#define EXT_NOTIFICATION_PLUGIN_ENABLED 0 +#define EXT_NOTIFICATION_PLUGIN_ACTIVE 0 #define EXT_NOTIFICATION_PLUGIN_ALERT_MESSAGE 1 -#define EXT_NOTIFICATION_PLUGIN_ALERT_BELL 1 +#define EXT_NOTIFICATION_PLUGIN_ALERT_BELL 0 #define EXT_NOTIFICATION_PLUGIN_OUTPUT 13 -#define EXT_NOTIFICATION_PLUGIN_OUTPUT_MS 100 +#define EXT_NOTIFICATION_PLUGIN_OUTPUT_MS 1000 #define ASCII_BELL 0x07 @@ -39,6 +39,9 @@ ExternalNotificationPluginRadio *externalNotificationPluginRadio; ExternalNotificationPlugin::ExternalNotificationPlugin() : concurrency::OSThread("ExternalNotificationPlugin") {} +bool externalCurrentState = 0; +uint32_t externalTurnedOn = 0; + int32_t ExternalNotificationPlugin::runOnce() { #ifndef NO_ESP32 @@ -57,10 +60,6 @@ int32_t ExternalNotificationPlugin::runOnce() DEBUG_MSG("Initializing External Notification Plugin\n"); - externalNotificationPluginRadio = new ExternalNotificationPluginRadio(); - - firstTime = 0; - // Set the direction of a pin pinMode(EXT_NOTIFICATION_PLUGIN_OUTPUT, OUTPUT); @@ -71,11 +70,17 @@ int32_t ExternalNotificationPlugin::runOnce() setExternalOn(); } + externalNotificationPluginRadio = new ExternalNotificationPluginRadio(); + + firstTime = 0; + } else { + // DEBUG_MSG("EN Loop\n"); if (externalCurrentState) { // TODO: Test this part. Don't know if this should be greater than or less than. if (externalTurnedOn + EXT_NOTIFICATION_PLUGIN_OUTPUT_MS < millis()) { + DEBUG_MSG("Turning off external notification\n"); setExternalOff(); } } @@ -119,14 +124,6 @@ void ExternalNotificationPlugin::setExternalOff() // -------- -MeshPacket *ExternalNotificationPluginRadio::allocReply() -{ - - auto reply = allocDataPacket(); // Allocate a packet for sending - - return reply; -} - bool ExternalNotificationPluginRadio::handleReceived(const MeshPacket &mp) { #ifndef NO_ESP32 @@ -134,8 +131,10 @@ bool ExternalNotificationPluginRadio::handleReceived(const MeshPacket &mp) if (EXT_NOTIFICATION_PLUGIN_ENABLED) { auto &p = mp.decoded.data; + //DEBUG_MSG("Processing handleReceived\n"); if (mp.from != nodeDB.getNodeNum()) { + DEBUG_MSG("handleReceived from some other device\n"); if (EXT_NOTIFICATION_PLUGIN_ALERT_BELL) { for (int i = 0; i < p.payload.size; i++) { @@ -146,6 +145,7 @@ bool ExternalNotificationPluginRadio::handleReceived(const MeshPacket &mp) } if (EXT_NOTIFICATION_PLUGIN_ALERT_MESSAGE) { + //DEBUG_MSG("Turning on alert\n"); externalNotificationPlugin->setExternalOn(); } } diff --git a/src/plugins/ExternalNotificationPlugin.h b/src/plugins/ExternalNotificationPlugin.h index 6de72fda6..a9ef58d04 100644 --- a/src/plugins/ExternalNotificationPlugin.h +++ b/src/plugins/ExternalNotificationPlugin.h @@ -10,8 +10,6 @@ class ExternalNotificationPlugin : private concurrency::OSThread { bool firstTime = 1; - bool externalCurrentState = 0; - uint32_t externalTurnedOn = 0; public: ExternalNotificationPlugin(); @@ -37,7 +35,7 @@ class ExternalNotificationPluginRadio : public SinglePortPlugin ExternalNotificationPluginRadio() : SinglePortPlugin("ExternalNotificationPluginRadio", PortNum_TEXT_MESSAGE_APP) {} protected: - virtual MeshPacket *allocReply(); + //virtual MeshPacket *allocReply(); /** Called to handle a particular incoming message From 9e736ab0d7505310df3e88afc9c1bb5c2196fca3 Mon Sep 17 00:00:00 2001 From: Jm Date: Thu, 28 Jan 2021 23:16:10 -0800 Subject: [PATCH 025/258] #654 Fix gpio initilization --- src/plugins/ExternalNotificationPlugin.cpp | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/src/plugins/ExternalNotificationPlugin.cpp b/src/plugins/ExternalNotificationPlugin.cpp index 3f759b7f2..e2f95f1aa 100644 --- a/src/plugins/ExternalNotificationPlugin.cpp +++ b/src/plugins/ExternalNotificationPlugin.cpp @@ -27,7 +27,7 @@ This plugin supports: #define EXT_NOTIFICATION_PLUGIN_ENABLED 0 #define EXT_NOTIFICATION_PLUGIN_ACTIVE 0 -#define EXT_NOTIFICATION_PLUGIN_ALERT_MESSAGE 1 +#define EXT_NOTIFICATION_PLUGIN_ALERT_MESSAGE 0 #define EXT_NOTIFICATION_PLUGIN_ALERT_BELL 0 #define EXT_NOTIFICATION_PLUGIN_OUTPUT 13 #define EXT_NOTIFICATION_PLUGIN_OUTPUT_MS 1000 @@ -63,19 +63,14 @@ int32_t ExternalNotificationPlugin::runOnce() // Set the direction of a pin pinMode(EXT_NOTIFICATION_PLUGIN_OUTPUT, OUTPUT); - // if ext_notification_plugin_active - if (EXT_NOTIFICATION_PLUGIN_ACTIVE) { - setExternalOff(); - } else { - setExternalOn(); - } + // Turn off the pin + setExternalOff(); externalNotificationPluginRadio = new ExternalNotificationPluginRadio(); firstTime = 0; } else { - // DEBUG_MSG("EN Loop\n"); if (externalCurrentState) { // TODO: Test this part. Don't know if this should be greater than or less than. @@ -131,7 +126,7 @@ bool ExternalNotificationPluginRadio::handleReceived(const MeshPacket &mp) if (EXT_NOTIFICATION_PLUGIN_ENABLED) { auto &p = mp.decoded.data; - //DEBUG_MSG("Processing handleReceived\n"); + // DEBUG_MSG("Processing handleReceived\n"); if (mp.from != nodeDB.getNodeNum()) { DEBUG_MSG("handleReceived from some other device\n"); @@ -145,7 +140,7 @@ bool ExternalNotificationPluginRadio::handleReceived(const MeshPacket &mp) } if (EXT_NOTIFICATION_PLUGIN_ALERT_MESSAGE) { - //DEBUG_MSG("Turning on alert\n"); + // DEBUG_MSG("Turning on alert\n"); externalNotificationPlugin->setExternalOn(); } } From aee81c8dcdfc02fc4b3f72ae079e8d1712a873b2 Mon Sep 17 00:00:00 2001 From: Jm Date: Fri, 29 Jan 2021 19:35:03 -0800 Subject: [PATCH 026/258] #654 - Add comments on what the config does --- src/plugins/ExternalNotificationPlugin.cpp | 42 ++++++++++++++-------- 1 file changed, 27 insertions(+), 15 deletions(-) diff --git a/src/plugins/ExternalNotificationPlugin.cpp b/src/plugins/ExternalNotificationPlugin.cpp index e2f95f1aa..4ada9798b 100644 --- a/src/plugins/ExternalNotificationPlugin.cpp +++ b/src/plugins/ExternalNotificationPlugin.cpp @@ -49,10 +49,31 @@ int32_t ExternalNotificationPlugin::runOnce() /* Uncomment the preferences below if you want to use the plugin without having to configure it from the PythonAPI or WebUI. - */ - // radioConfig.preferences.externalnotificationplugin_enabled = 1; - // radioConfig.preferences.externalnotificationplugin_mode = 1; + EXT_NOTIFICATION_PLUGIN_ENABLED + 0 = Disabled (Default) + 1 = Enabled + + EXT_NOTIFICATION_PLUGIN_ACTIVE + 0 = Active Low (Default) + 1 = Active High + + EXT_NOTIFICATION_PLUGIN_ALERT_MESSAGE + 0 = Disabled (Default) + 1 = Alert when a text message comes + + EXT_NOTIFICATION_PLUGIN_ALERT_BELL + 0 = Disabled (Default) + 1 = Alert when the bell character is received + + EXT_NOTIFICATION_PLUGIN_OUTPUT + GPIO of the output. (Default = 13) + + EXT_NOTIFICATION_PLUGIN_OUTPUT_MS + Amount of time in ms for the alert. Default is 1000. + + + */ if (EXT_NOTIFICATION_PLUGIN_ENABLED) { @@ -73,7 +94,7 @@ int32_t ExternalNotificationPlugin::runOnce() } else { if (externalCurrentState) { - // TODO: Test this part. Don't know if this should be greater than or less than. + // If the output is turned on, turn it back off after the given period of time. if (externalTurnedOn + EXT_NOTIFICATION_PLUGIN_OUTPUT_MS < millis()) { DEBUG_MSG("Turning off external notification\n"); setExternalOff(); @@ -97,12 +118,7 @@ void ExternalNotificationPlugin::setExternalOn() externalTurnedOn = millis(); // if ext_notification_plugin_active - if (EXT_NOTIFICATION_PLUGIN_ACTIVE) { - digitalWrite(EXT_NOTIFICATION_PLUGIN_OUTPUT, true); - - } else { - digitalWrite(EXT_NOTIFICATION_PLUGIN_OUTPUT, false); - } + digitalWrite(EXT_NOTIFICATION_PLUGIN_OUTPUT, (EXT_NOTIFICATION_PLUGIN_ACTIVE ? true : false)); } void ExternalNotificationPlugin::setExternalOff() @@ -110,11 +126,7 @@ void ExternalNotificationPlugin::setExternalOff() externalCurrentState = 0; // if ext_notification_plugin_active - if (EXT_NOTIFICATION_PLUGIN_ACTIVE) { - digitalWrite(EXT_NOTIFICATION_PLUGIN_OUTPUT, false); - } else { - digitalWrite(EXT_NOTIFICATION_PLUGIN_OUTPUT, true); - } + digitalWrite(EXT_NOTIFICATION_PLUGIN_OUTPUT, (EXT_NOTIFICATION_PLUGIN_ACTIVE ? false : true)); } // -------- From c0e2ec8decf4df3d5d01d5a2b5e14cf293ff9442 Mon Sep 17 00:00:00 2001 From: Kevin Hester Date: Sat, 30 Jan 2021 21:23:03 +0800 Subject: [PATCH 027/258] 1.1.34 --- version.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version.properties b/version.properties index 556f3f840..dd592ccf0 100644 --- a/version.properties +++ b/version.properties @@ -1,4 +1,4 @@ [VERSION] major = 1 minor = 1 -build = 33 +build = 34 From 6cef3e41e72dfb6d0123835bee5a2741a5567421 Mon Sep 17 00:00:00 2001 From: Jm Date: Sat, 30 Jan 2021 09:17:40 -0800 Subject: [PATCH 028/258] Update comments and use radioConfig --- src/plugins/ExternalNotificationPlugin.cpp | 98 +++++++++++----------- 1 file changed, 51 insertions(+), 47 deletions(-) diff --git a/src/plugins/ExternalNotificationPlugin.cpp b/src/plugins/ExternalNotificationPlugin.cpp index 4ada9798b..5774707ad 100644 --- a/src/plugins/ExternalNotificationPlugin.cpp +++ b/src/plugins/ExternalNotificationPlugin.cpp @@ -14,21 +14,32 @@ This plugin supports: https://github.com/meshtastic/Meshtastic-device/issues/654 - bool ext_notification_plugin_enabled = 126; - bool ext_notification_plugin_active = 129; - bool ext_notification_plugin_alert_message = 130; - bool ext_notification_plugin_alert_bell = 131; - uint32 ext_notification_plugin_output = 128; + radioConfig.preferences.ext_notification_plugin_enabled + 0 = Disabled (Default) + 1 = Enabled + radioConfig.preferences.ext_notification_plugin_active + 0 = Active Low (Default) + 1 = Active High - uint32 ext_notification_plugin_output_ms = 127; + radioConfig.preferences.ext_notification_plugin_alert_message + 0 = Disabled (Default) + 1 = Alert when a text message comes + + radioConfig.preferences.ext_notification_plugin_alert_bell + 0 = Disabled (Default) + 1 = Alert when the bell character is received + + radioConfig.preferences.ext_notification_plugin_output + GPIO of the output. (Default = 13) + + radioConfig.preferences.ext_notification_plugin_output_ms + Amount of time in ms for the alert. Default is 1000. */ -#define EXT_NOTIFICATION_PLUGIN_ENABLED 0 -#define EXT_NOTIFICATION_PLUGIN_ACTIVE 0 -#define EXT_NOTIFICATION_PLUGIN_ALERT_MESSAGE 0 -#define EXT_NOTIFICATION_PLUGIN_ALERT_BELL 0 + +// Default configurations #define EXT_NOTIFICATION_PLUGIN_OUTPUT 13 #define EXT_NOTIFICATION_PLUGIN_OUTPUT_MS 1000 @@ -49,40 +60,27 @@ int32_t ExternalNotificationPlugin::runOnce() /* Uncomment the preferences below if you want to use the plugin without having to configure it from the PythonAPI or WebUI. - - EXT_NOTIFICATION_PLUGIN_ENABLED - 0 = Disabled (Default) - 1 = Enabled - - EXT_NOTIFICATION_PLUGIN_ACTIVE - 0 = Active Low (Default) - 1 = Active High - - EXT_NOTIFICATION_PLUGIN_ALERT_MESSAGE - 0 = Disabled (Default) - 1 = Alert when a text message comes - - EXT_NOTIFICATION_PLUGIN_ALERT_BELL - 0 = Disabled (Default) - 1 = Alert when the bell character is received - - EXT_NOTIFICATION_PLUGIN_OUTPUT - GPIO of the output. (Default = 13) - - EXT_NOTIFICATION_PLUGIN_OUTPUT_MS - Amount of time in ms for the alert. Default is 1000. - - */ - if (EXT_NOTIFICATION_PLUGIN_ENABLED) { + // radioConfig.preferences.ext_notification_plugin_enabled = 1; + // radioConfig.preferences.ext_notification_plugin_alert_message = 1; + + // radioConfig.preferences.ext_notification_plugin_active = 1; + // radioConfig.preferences.ext_notification_plugin_alert_bell = 1; + // radioConfig.preferences.ext_notification_plugin_output_ms = 1000; + // radioConfig.preferences.ext_notification_plugin_output = 13; + + if (radioConfig.preferences.ext_notification_plugin_enabled) { if (firstTime) { DEBUG_MSG("Initializing External Notification Plugin\n"); // Set the direction of a pin - pinMode(EXT_NOTIFICATION_PLUGIN_OUTPUT, OUTPUT); + pinMode((radioConfig.preferences.ext_notification_plugin_output + ? radioConfig.preferences.ext_notification_plugin_output + : EXT_NOTIFICATION_PLUGIN_OUTPUT), + OUTPUT); // Turn off the pin setExternalOff(); @@ -95,7 +93,10 @@ int32_t ExternalNotificationPlugin::runOnce() if (externalCurrentState) { // If the output is turned on, turn it back off after the given period of time. - if (externalTurnedOn + EXT_NOTIFICATION_PLUGIN_OUTPUT_MS < millis()) { + if (externalTurnedOn + (radioConfig.preferences.ext_notification_plugin_output_ms + ? radioConfig.preferences.ext_notification_plugin_output_ms + : EXT_NOTIFICATION_PLUGIN_OUTPUT_MS) < + millis()) { DEBUG_MSG("Turning off external notification\n"); setExternalOff(); } @@ -117,16 +118,18 @@ void ExternalNotificationPlugin::setExternalOn() externalCurrentState = 1; externalTurnedOn = millis(); - // if ext_notification_plugin_active - digitalWrite(EXT_NOTIFICATION_PLUGIN_OUTPUT, (EXT_NOTIFICATION_PLUGIN_ACTIVE ? true : false)); + digitalWrite((radioConfig.preferences.ext_notification_plugin_output ? radioConfig.preferences.ext_notification_plugin_output + : EXT_NOTIFICATION_PLUGIN_OUTPUT), + (radioConfig.preferences.ext_notification_plugin_active ? true : false)); } void ExternalNotificationPlugin::setExternalOff() { externalCurrentState = 0; - // if ext_notification_plugin_active - digitalWrite(EXT_NOTIFICATION_PLUGIN_OUTPUT, (EXT_NOTIFICATION_PLUGIN_ACTIVE ? false : true)); + digitalWrite((radioConfig.preferences.ext_notification_plugin_output ? radioConfig.preferences.ext_notification_plugin_output + : EXT_NOTIFICATION_PLUGIN_OUTPUT), + (radioConfig.preferences.ext_notification_plugin_active ? false : true)); } // -------- @@ -135,15 +138,16 @@ bool ExternalNotificationPluginRadio::handleReceived(const MeshPacket &mp) { #ifndef NO_ESP32 - if (EXT_NOTIFICATION_PLUGIN_ENABLED) { + if (radioConfig.preferences.ext_notification_plugin_enabled) { auto &p = mp.decoded.data; - // DEBUG_MSG("Processing handleReceived\n"); if (mp.from != nodeDB.getNodeNum()) { - DEBUG_MSG("handleReceived from some other device\n"); - if (EXT_NOTIFICATION_PLUGIN_ALERT_BELL) { + // TODO: This may be a problem if messages are sent in unicide, but I'm not sure if it will. + // Need to know if and how this could be a problem. + if (radioConfig.preferences.ext_notification_plugin_alert_bell) { + DEBUG_MSG("externalNotificationPlugin - Notification Bell\n"); for (int i = 0; i < p.payload.size; i++) { if (p.payload.bytes[i] == ASCII_BELL) { externalNotificationPlugin->setExternalOn(); @@ -151,8 +155,8 @@ bool ExternalNotificationPluginRadio::handleReceived(const MeshPacket &mp) } } - if (EXT_NOTIFICATION_PLUGIN_ALERT_MESSAGE) { - // DEBUG_MSG("Turning on alert\n"); + if (radioConfig.preferences.ext_notification_plugin_alert_message) { + DEBUG_MSG("externalNotificationPlugin - Notification Plugin\n"); externalNotificationPlugin->setExternalOn(); } } From 3162f74945a4e15b45d7e7585d419d01c8213d6e Mon Sep 17 00:00:00 2001 From: Jm Casler Date: Sat, 30 Jan 2021 09:32:04 -0800 Subject: [PATCH 029/258] Create External Notification documentation. --- docs/software/plugins/ExternalNotification.md | 67 +++++++++++++++++++ 1 file changed, 67 insertions(+) create mode 100644 docs/software/plugins/ExternalNotification.md diff --git a/docs/software/plugins/ExternalNotification.md b/docs/software/plugins/ExternalNotification.md new file mode 100644 index 000000000..2afb52d42 --- /dev/null +++ b/docs/software/plugins/ExternalNotification.md @@ -0,0 +1,67 @@ +Documentation for ExternalNotification Plugin + +# Configuration + +These are the settings that can be configured. + + ext_notification_plugin_enabled + Is the plugin enabled? + + 0 = Disabled (Default) + 1 = Enabled + + ext_notification_plugin_active + Is your external circuit triggered when our GPIO is low or high? + + 0 = Active Low (Default) + 1 = Active High + + ext_notification_plugin_alert_message + Do you want to be notified on an incoming message? + + 0 = Disabled (Default) + 1 = Alert when a text message comes + + ext_notification_plugin_alert_bell + Do you want to be notified on an incoming bell? + + 0 = Disabled (Default) + 1 = Alert when the bell character is received + + ext_notification_plugin_output + What GPIO is your external circuit attached? + + GPIO of the output. (Default = 13) + + ext_notification_plugin_output_ms + How long do you want us to trigger your external circuit? + + Amount of time in ms for the alert. Default is 1000. + + +# Usage Notes + +For basic usage, start with: + + ext_notification_plugin_enabled = 1 + ext_notification_plugin_alert_message = 1 + +Depending on how your external configured is configured, you may need to set the active state to true. + + ext_notification_plugin_active = 1 + +# External Hardware + +Be mindful of the max current sink and source of the esp32 GPIO. The easiest devices to interface with would be either an LED or Active Buzzer. + + +# Known Problems + +* This won't directly support an passive (normal) speaker as it does not generate any audio wave forms. +* This currently only supports the esp32. Other targets may be possible, I just don't have to test with. + +# Need more help? + +Go to the Meshtastic Discourse Group if you have any questions or to share how you have used this. + +https://meshtastic.discourse.group From f45ffc8773d0330e525a057a6446f79a75dcdfb3 Mon Sep 17 00:00:00 2001 From: Jm Casler Date: Sat, 30 Jan 2021 09:32:44 -0800 Subject: [PATCH 030/258] Rename documentation --- .../{ExternalNotification.md => ExternalNotificationPlugin.md} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename docs/software/plugins/{ExternalNotification.md => ExternalNotificationPlugin.md} (100%) diff --git a/docs/software/plugins/ExternalNotification.md b/docs/software/plugins/ExternalNotificationPlugin.md similarity index 100% rename from docs/software/plugins/ExternalNotification.md rename to docs/software/plugins/ExternalNotificationPlugin.md From 7129a19f3533956cae46d7e4af32a6bb677f0319 Mon Sep 17 00:00:00 2001 From: Jm Date: Sat, 30 Jan 2021 09:36:17 -0800 Subject: [PATCH 031/258] #654 Add reference to documentation --- src/plugins/ExternalNotificationPlugin.cpp | 41 ++++++++++++---------- 1 file changed, 23 insertions(+), 18 deletions(-) diff --git a/src/plugins/ExternalNotificationPlugin.cpp b/src/plugins/ExternalNotificationPlugin.cpp index 5774707ad..b4f3c801c 100644 --- a/src/plugins/ExternalNotificationPlugin.cpp +++ b/src/plugins/ExternalNotificationPlugin.cpp @@ -10,31 +10,36 @@ /* -This plugin supports: - https://github.com/meshtastic/Meshtastic-device/issues/654 + Documentation: + https://github.com/mc-hamster/Meshtastic-device/blob/master/docs/software/plugins/ExternalNotificationPlugin.md + + This plugin supports: + https://github.com/meshtastic/Meshtastic-device/issues/654 - radioConfig.preferences.ext_notification_plugin_enabled - 0 = Disabled (Default) - 1 = Enabled + Quick reference: - radioConfig.preferences.ext_notification_plugin_active - 0 = Active Low (Default) - 1 = Active High + radioConfig.preferences.ext_notification_plugin_enabled + 0 = Disabled (Default) + 1 = Enabled - radioConfig.preferences.ext_notification_plugin_alert_message - 0 = Disabled (Default) - 1 = Alert when a text message comes + radioConfig.preferences.ext_notification_plugin_active + 0 = Active Low (Default) + 1 = Active High - radioConfig.preferences.ext_notification_plugin_alert_bell - 0 = Disabled (Default) - 1 = Alert when the bell character is received + radioConfig.preferences.ext_notification_plugin_alert_message + 0 = Disabled (Default) + 1 = Alert when a text message comes - radioConfig.preferences.ext_notification_plugin_output - GPIO of the output. (Default = 13) + radioConfig.preferences.ext_notification_plugin_alert_bell + 0 = Disabled (Default) + 1 = Alert when the bell character is received - radioConfig.preferences.ext_notification_plugin_output_ms - Amount of time in ms for the alert. Default is 1000. + radioConfig.preferences.ext_notification_plugin_output + GPIO of the output. (Default = 13) + + radioConfig.preferences.ext_notification_plugin_output_ms + Amount of time in ms for the alert. Default is 1000. */ From 5df08410e78c38782578bd7dce20346dfba7bb4e Mon Sep 17 00:00:00 2001 From: Jm Casler Date: Sat, 30 Jan 2021 09:39:40 -0800 Subject: [PATCH 032/258] Create SerialPlugin.md --- docs/software/plugins/SerialPlugin.md | 40 +++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) create mode 100644 docs/software/plugins/SerialPlugin.md diff --git a/docs/software/plugins/SerialPlugin.md b/docs/software/plugins/SerialPlugin.md new file mode 100644 index 000000000..bce84653c --- /dev/null +++ b/docs/software/plugins/SerialPlugin.md @@ -0,0 +1,40 @@ +# SerialPlugin + +A simple interface to send messages over the mesh network by sending strings +over a serial port. + +Default is to use RX GPIO 16 and TX GPIO 17. + + +# Basic Usage: + + 1) Enable the plugin by setting serialplugin_enabled to 1. + 2) Set the pins (serialplugin_rxd / serialplugin_rxd) for your preferred RX and TX GPIO pins. + On tbeam, recommend to use: + RXD 35 + TXD 15 + 3) Set serialplugin_timeout to the amount of time to wait before we consider + your packet as "done". + 4) (Optional) In SerialPlugin.h set the port to PortNum_TEXT_MESSAGE_APP if you want to + send messages to/from the general text message channel. + 5) Connect to your device over the serial interface at 38400 8N1. + 6) Send a packet up to 240 bytes in length. This will get relayed over the mesh network. + 7) (Optional) Set serialplugin_echo to 1 and any message you send out will be echoed back + to your device. + +# TODO (in this order): + +* Define a verbose RX mode to report on mesh and packet infomration. + - This won't happen any time soon. + +# Known Problems + + * Until the plugin is initilized by the startup sequence, the TX pin is in a floating + state. Device connected to that pin may see this as "noise". + * Will not work on NRF and the Linux device targets. + +# Need help? + +Need help with this plugin? Post your question on the Meshtastic Discourse: + +https://meshtastic.discourse.group From 133a7ff166a1216e612c31e3bae8ef0aef374537 Mon Sep 17 00:00:00 2001 From: Jm Casler Date: Sat, 30 Jan 2021 09:46:26 -0800 Subject: [PATCH 033/258] Added more notes. --- .../software/plugins/ExternalNotificationPlugin.md | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/docs/software/plugins/ExternalNotificationPlugin.md b/docs/software/plugins/ExternalNotificationPlugin.md index 2afb52d42..dda95e4c4 100644 --- a/docs/software/plugins/ExternalNotificationPlugin.md +++ b/docs/software/plugins/ExternalNotificationPlugin.md @@ -1,4 +1,4 @@ -Documentation for ExternalNotification Plugin +The ExternalNotification Plugin will allow you to connect a speaker, LED or other device to notify you when a message has been received from the mesh network. # Configuration @@ -44,9 +44,9 @@ These are the settings that can be configured. For basic usage, start with: ext_notification_plugin_enabled = 1 - ext_notification_plugin_alert_message = 1 + ext_notification_plugin_alert_message = 1 -Depending on how your external configured is configured, you may need to set the active state to true. +Depending on how your external cirtcuit configured is configured, you may need to set the active state to true. ext_notification_plugin_active = 1 @@ -54,11 +54,19 @@ Depending on how your external configured is configured, you may need to set the Be mindful of the max current sink and source of the esp32 GPIO. The easiest devices to interface with would be either an LED or Active Buzzer. +Ideas for external hardware: + +* LED +* Active Buzzer +* Flame thrower +* Strobe Light +* Siren # Known Problems * This won't directly support an passive (normal) speaker as it does not generate any audio wave forms. * This currently only supports the esp32. Other targets may be possible, I just don't have to test with. +* This plugin only monitors text messages. We won't trigger on any other packet types. # Need more help? From 092af0f9f9b48272a367bb0062ff62fa88b4b7ae Mon Sep 17 00:00:00 2001 From: Jm Casler Date: Sat, 30 Jan 2021 09:50:19 -0800 Subject: [PATCH 034/258] Update to doc to add info on the bell character --- docs/software/plugins/ExternalNotificationPlugin.md | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/docs/software/plugins/ExternalNotificationPlugin.md b/docs/software/plugins/ExternalNotificationPlugin.md index dda95e4c4..de9f33ad5 100644 --- a/docs/software/plugins/ExternalNotificationPlugin.md +++ b/docs/software/plugins/ExternalNotificationPlugin.md @@ -49,6 +49,18 @@ For basic usage, start with: Depending on how your external cirtcuit configured is configured, you may need to set the active state to true. ext_notification_plugin_active = 1 + +## Alert Types + +We support being alerted on two events: + +1) Incoming Text Message + +2) Incoming Text Message that contains the ascii bell character. At present, only the Python API can send an ascii bell character, but more support may be added in the future. + +### Bell Character + +The bell character is ASCII 0x07. Include 0x07 anywhere in the text message and with ext_notification_plugin_alert_bell enabled, we will issue an external notification. # External Hardware From 242bcc835391079562b012e7d6bb01d01d6356c3 Mon Sep 17 00:00:00 2001 From: Jm Date: Sat, 30 Jan 2021 09:52:21 -0800 Subject: [PATCH 035/258] Update documentation location to the main mesthastic repo --- src/plugins/ExternalNotificationPlugin.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/ExternalNotificationPlugin.cpp b/src/plugins/ExternalNotificationPlugin.cpp index b4f3c801c..505eff7d1 100644 --- a/src/plugins/ExternalNotificationPlugin.cpp +++ b/src/plugins/ExternalNotificationPlugin.cpp @@ -11,7 +11,7 @@ /* Documentation: - https://github.com/mc-hamster/Meshtastic-device/blob/master/docs/software/plugins/ExternalNotificationPlugin.md + https://github.com/meshtastic/Meshtastic-device/blob/master/docs/software/plugins/ExternalNotificationPlugin.md This plugin supports: https://github.com/meshtastic/Meshtastic-device/issues/654 From 48b38ed94bd16872b64a957d01f21df88d078464 Mon Sep 17 00:00:00 2001 From: Jm Casler Date: Sat, 30 Jan 2021 17:21:54 -0800 Subject: [PATCH 036/258] Update documentation --- docs/software/plugins/ExternalNotificationPlugin.md | 2 ++ docs/software/plugins/SerialPlugin.md | 2 +- docs/software/plugins/StoreRequestPlugin.md | 6 ++++++ 3 files changed, 9 insertions(+), 1 deletion(-) create mode 100644 docs/software/plugins/StoreRequestPlugin.md diff --git a/docs/software/plugins/ExternalNotificationPlugin.md b/docs/software/plugins/ExternalNotificationPlugin.md index de9f33ad5..c0814b6c3 100644 --- a/docs/software/plugins/ExternalNotificationPlugin.md +++ b/docs/software/plugins/ExternalNotificationPlugin.md @@ -1,3 +1,5 @@ +# About + The ExternalNotification Plugin will allow you to connect a speaker, LED or other device to notify you when a message has been received from the mesh network. # Configuration diff --git a/docs/software/plugins/SerialPlugin.md b/docs/software/plugins/SerialPlugin.md index bce84653c..acd777e35 100644 --- a/docs/software/plugins/SerialPlugin.md +++ b/docs/software/plugins/SerialPlugin.md @@ -1,4 +1,4 @@ -# SerialPlugin +# About A simple interface to send messages over the mesh network by sending strings over a serial port. diff --git a/docs/software/plugins/StoreRequestPlugin.md b/docs/software/plugins/StoreRequestPlugin.md new file mode 100644 index 000000000..239a00de8 --- /dev/null +++ b/docs/software/plugins/StoreRequestPlugin.md @@ -0,0 +1,6 @@ +# About + + + +# Running notes + From 487b8c6e9ed4625b1a6849759d647ff0eb3d5d3a Mon Sep 17 00:00:00 2001 From: Jm Casler Date: Sun, 31 Jan 2021 09:12:01 -0800 Subject: [PATCH 037/258] #668 Initial work for Store & Forward Plugin --- docs/software/plugins/StoreRequestPlugin.md | 15 ++ src/plugins/StoreForwardPlugin.cpp | 148 ++++++++++++++++++++ src/plugins/StoreForwardPlugin.h | 54 +++++++ 3 files changed, 217 insertions(+) create mode 100644 src/plugins/StoreForwardPlugin.cpp create mode 100644 src/plugins/StoreForwardPlugin.h diff --git a/docs/software/plugins/StoreRequestPlugin.md b/docs/software/plugins/StoreRequestPlugin.md index 239a00de8..571ac4ed6 100644 --- a/docs/software/plugins/StoreRequestPlugin.md +++ b/docs/software/plugins/StoreRequestPlugin.md @@ -1,6 +1,21 @@ # About + This is a work in progress and is not yet available. +The Store Request Plugin is an implementation of a Store and Forward system to enable resilient messaging in the event that a client device is disconnected from the main network. + +Because of the increased network traffic for this overhead, it's not adviced to use this if you are duty cycle limited for your airtime usage nor is it adviced to use this for SF12. # Running notes +This will only work on nodes that are designated as a Router. + +Initial Requirements: + +* Must be installed on a router node. +* * This is an artificial limitation, but is in place to enforce best practices. +* * Router nodes are intended to be always online. If this plugin misses any messages, the reliability of the stored messages will be reduced +* Esp32 Processor based device with external PSRAM. (tbeam v1.0 and tbeamv1.1, maybe others) + +Initial Features +* \ No newline at end of file diff --git a/src/plugins/StoreForwardPlugin.cpp b/src/plugins/StoreForwardPlugin.cpp new file mode 100644 index 000000000..c40c35109 --- /dev/null +++ b/src/plugins/StoreForwardPlugin.cpp @@ -0,0 +1,148 @@ +#include "StoreForwardPlugin.h" +#include "MeshService.h" +#include "NodeDB.h" +#include "RTC.h" +#include "Router.h" +#include "configuration.h" +#include + +#include + +#define STORE_RECORDS 10 +#define BYTES_PER_RECORDS 512 + +struct sfRecord +{ + uint8_t bytes[BYTES_PER_RECORDS]; + uint32_t timestamp; // Time the packet was received +}; + +struct sfRecord records[STORE_RECORDS]; + +#define STOREFORWARDPLUGIN_ENABLED 1 + +StoreForwardPlugin *storeForwardPlugin; +StoreForwardPluginRadio *storeForwardPluginRadio; + +StoreForwardPlugin::StoreForwardPlugin() : concurrency::OSThread("SerialPlugin") {} + +// char serialStringChar[Constants_DATA_PAYLOAD_LEN]; + +int32_t StoreForwardPlugin::runOnce() +{ +#ifndef NO_ESP32 + + if (STOREFORWARDPLUGIN_ENABLED) { + + if (firstTime) { + + // Interface with the serial peripheral from in here. + DEBUG_MSG("Initializing Store & Forward Plugin\n"); + + // Router + if (radioConfig.preferences.is_router) { + if (ESP.getPsramSize()) { + if (ESP.getFreePsram() <= 1024 * 1024) { + // Do the startup here + + } else { + DEBUG_MSG("Device has less than 1M of PSRAM free. Aborting startup.\n"); + DEBUG_MSG("Store & Forward Plugin - Aborting Startup.\n"); + + return (INT32_MAX); + } + + } else { + DEBUG_MSG("Device doesn't have PSRAM.\n"); + DEBUG_MSG("Store & Forward Plugin - Aborting Startup.\n"); + + return (INT32_MAX); + } + + // Non-Router + } else { + + } + + storeForwardPluginRadio = new StoreForwardPluginRadio(); + + firstTime = 0; + + } else { + // TBD + } + + return (10); + } else { + DEBUG_MSG("Store & Forward Plugin - Disabled\n"); + + return (INT32_MAX); + } + +#endif +} + +MeshPacket *StoreForwardPluginRadio::allocReply() +{ + + auto reply = allocDataPacket(); // Allocate a packet for sending + + return reply; +} + +void StoreForwardPluginRadio::sendPayload(NodeNum dest, bool wantReplies) +{ + MeshPacket *p = allocReply(); + p->to = dest; + p->decoded.want_response = wantReplies; + + //p->want_ack = SERIALPLUGIN_ACK; + + // p->decoded.data.payload.size = strlen(serialStringChar); // You must specify how many bytes are in the reply + // memcpy(p->decoded.data.payload.bytes, serialStringChar, p->decoded.data.payload.size); + + service.sendToMesh(p); +} + +bool StoreForwardPluginRadio::handleReceived(const MeshPacket &mp) +{ +#ifndef NO_ESP32 + + if (STOREFORWARDPLUGIN_ENABLED) { + + auto &p = mp.decoded.data; + // DEBUG_MSG("Received text msg self=0x%0x, from=0x%0x, to=0x%0x, id=%d, msg=%.*s\n", + // nodeDB.getNodeNum(), mp.from, mp.to, mp.id, p.payload.size, p.payload.bytes); + + if (mp.from == nodeDB.getNodeNum()) { + + /* + * If radioConfig.preferences.serialplugin_echo is true, then echo the packets that are sent out back to the TX + * of the serial interface. + */ + if (radioConfig.preferences.serialplugin_echo) { + + // For some reason, we get the packet back twice when we send out of the radio. + // TODO: need to find out why. + if (lastRxID != mp.id) { + lastRxID = mp.id; + // DEBUG_MSG("* * Message came this device\n"); + // Serial2.println("* * Message came this device"); + Serial2.printf("%s", p.payload.bytes); + } + } + + } else { + // DEBUG_MSG("* * Message came from the mesh\n"); + // Serial2.println("* * Message came from the mesh"); + Serial2.printf("%s", p.payload.bytes); + } + + } else { + DEBUG_MSG("Serial Plugin Disabled\n"); + } + +#endif + + return true; // Let others look at this message also if they want +} diff --git a/src/plugins/StoreForwardPlugin.h b/src/plugins/StoreForwardPlugin.h new file mode 100644 index 000000000..e9dac9b45 --- /dev/null +++ b/src/plugins/StoreForwardPlugin.h @@ -0,0 +1,54 @@ +#pragma once + +#include "SinglePortPlugin.h" +#include "concurrency/OSThread.h" +#include "configuration.h" +#include +#include + +class StoreForwardPlugin : private concurrency::OSThread +{ + bool firstTime = 1; + + public: + StoreForwardPlugin(); + + protected: + virtual int32_t runOnce(); +}; + +extern StoreForwardPlugin *storeForwardPlugin; + +/* + * Radio interface for SerialPlugin + * + */ +class StoreForwardPluginRadio : public SinglePortPlugin +{ + uint32_t lastRxID; + + public: + /* + TODO: Switch this to PortNum_SERIAL_APP once the change is able to be merged back here + from the main code. + */ + + // SerialPluginRadio() : SinglePortPlugin("SerialPluginRadio", PortNum_TEXT_MESSAGE_APP) {} + StoreForwardPluginRadio() : SinglePortPlugin("SerialPluginRadio", PortNum_SERIAL_APP) {} + + /** + * Send our payload into the mesh + */ + void sendPayload(NodeNum dest = NODENUM_BROADCAST, bool wantReplies = false); + + protected: + virtual MeshPacket *allocReply(); + + /** Called to handle a particular incoming message + + @return true if you've guaranteed you've handled this message and no other handlers should be considered for it + */ + virtual bool handleReceived(const MeshPacket &mp); +}; + +extern StoreForwardPluginRadio *storeForwardPluginRadio; \ No newline at end of file From e8c6fccd633f801045a417054115025a4be1fb0d Mon Sep 17 00:00:00 2001 From: Jm Casler Date: Sun, 31 Jan 2021 09:12:36 -0800 Subject: [PATCH 038/258] #671 Range Test Plugin Initial work for Range Test Plugin --- src/plugins/Plugins.cpp | 11 +++- src/plugins/RangeTestPlugin.cpp | 103 ++++++++++++++++++++++++++++++++ src/plugins/RangeTestPlugin.h | 49 +++++++++++++++ 3 files changed, 161 insertions(+), 2 deletions(-) create mode 100644 src/plugins/RangeTestPlugin.cpp create mode 100644 src/plugins/RangeTestPlugin.h diff --git a/src/plugins/Plugins.cpp b/src/plugins/Plugins.cpp index 90a1b554f..93487ac7a 100644 --- a/src/plugins/Plugins.cpp +++ b/src/plugins/Plugins.cpp @@ -1,9 +1,11 @@ #include "plugins/ExternalNotificationPlugin.h" #include "plugins/NodeInfoPlugin.h" #include "plugins/PositionPlugin.h" +#include "plugins/RangeTestPlugin.h" #include "plugins/RemoteHardwarePlugin.h" #include "plugins/ReplyPlugin.h" #include "plugins/SerialPlugin.h" +#include "plugins/StoreForwardPlugin.h" #include "plugins/TextMessagePlugin.h" /** @@ -24,7 +26,12 @@ void setupPlugins() #ifndef NO_ESP32 // Only run on an esp32 based device. - new SerialPlugin(); // Maintained by MC Hamster (Jm Casler) jm@casler.org - new ExternalNotificationPlugin(); // Maintained by MC Hamster (Jm Casler) jm@casler.org + /* + Maintained by MC Hamster (Jm Casler) jm@casler.org + */ + new SerialPlugin(); + new ExternalNotificationPlugin(); + new StoreForwardPlugin(); + new RangeTestPlugin(); #endif } \ No newline at end of file diff --git a/src/plugins/RangeTestPlugin.cpp b/src/plugins/RangeTestPlugin.cpp new file mode 100644 index 000000000..1b8f80f31 --- /dev/null +++ b/src/plugins/RangeTestPlugin.cpp @@ -0,0 +1,103 @@ +#include "RangeTestPlugin.h" +#include "MeshService.h" +#include "NodeDB.h" +#include "RTC.h" +#include "Router.h" +#include "configuration.h" +#include + +#include + +#define RANGETESTPLUGIN_ENABLED 1 +#define RANGETESTPLUGIN_SENDER 0 + +RangeTestPlugin *rangeTestPlugin; +RangeTestPluginRadio *rangeTestPluginRadio; + +RangeTestPlugin::RangeTestPlugin() : concurrency::OSThread("RangeTestPlugin") {} + +// char serialStringChar[Constants_DATA_PAYLOAD_LEN]; + +int32_t RangeTestPlugin::runOnce() +{ +#ifndef NO_ESP32 + + if (RANGETESTPLUGIN_ENABLED) { + + if (firstTime) { + + // Interface with the serial peripheral from in here. + DEBUG_MSG("Initializing Range Test Plugin\n"); + + rangeTestPluginRadio = new RangeTestPluginRadio(); + + firstTime = 0; + + } else { + // TBD + } + + return (10); + } else { + DEBUG_MSG("Range Test Plugin - Disabled\n"); + + return (INT32_MAX); + } + +#endif +} + +MeshPacket *RangeTestPluginRadio::allocReply() +{ + + auto reply = allocDataPacket(); // Allocate a packet for sending + + return reply; +} + +void RangeTestPluginRadio::sendPayload(NodeNum dest, bool wantReplies) +{ + MeshPacket *p = allocReply(); + p->to = dest; + p->decoded.want_response = wantReplies; + + service.sendToMesh(p); +} + +bool RangeTestPluginRadio::handleReceived(const MeshPacket &mp) +{ +#ifndef NO_ESP32 + + if (RANGETESTPLUGIN_ENABLED) { + + auto &p = mp.decoded.data; + // DEBUG_MSG("Received text msg self=0x%0x, from=0x%0x, to=0x%0x, id=%d, msg=%.*s\n", + // nodeDB.getNodeNum(), mp.from, mp.to, mp.id, p.payload.size, p.payload.bytes); + + if (mp.from != nodeDB.getNodeNum()) { + + // DEBUG_MSG("* * Message came from the mesh\n"); + // Serial2.println("* * Message came from the mesh"); + Serial2.printf("%s", p.payload.bytes); + p.payload.size; + gpsStatus->getLatitude(); + gpsStatus->getLongitude(); + gpsStatus->getHasLock(); + gpsStatus->getDOP(); + mp.rx_snr; + mp.hop_limit; + mp.decoded.position.latitude_i; + mp.decoded.position.longitude_i; + + + + } + + } else { + DEBUG_MSG("Range Test Plugin Disabled\n"); + } + +#endif + + return true; // Let others look at this message also if they want +} diff --git a/src/plugins/RangeTestPlugin.h b/src/plugins/RangeTestPlugin.h new file mode 100644 index 000000000..f66744dbd --- /dev/null +++ b/src/plugins/RangeTestPlugin.h @@ -0,0 +1,49 @@ +#pragma once + +#include "SinglePortPlugin.h" +#include "concurrency/OSThread.h" +#include "configuration.h" +#include +#include + +class RangeTestPlugin : private concurrency::OSThread +{ + bool firstTime = 1; + + public: + RangeTestPlugin(); + + protected: + virtual int32_t runOnce(); +}; + +extern RangeTestPlugin *rangeTestPlugin; + +/* + * Radio interface for RangeTestPlugin + * + */ +class RangeTestPluginRadio : public SinglePortPlugin +{ + uint32_t lastRxID; + + public: + + RangeTestPluginRadio() : SinglePortPlugin("RangeTestPluginRadio", PortNum_TEXT_MESSAGE_APP) {} + + /** + * Send our payload into the mesh + */ + void sendPayload(NodeNum dest = NODENUM_BROADCAST, bool wantReplies = false); + + protected: + virtual MeshPacket *allocReply(); + + /** Called to handle a particular incoming message + + @return true if you've guaranteed you've handled this message and no other handlers should be considered for it + */ + virtual bool handleReceived(const MeshPacket &mp); +}; + +extern RangeTestPluginRadio *rangeTestPluginRadio; \ No newline at end of file From c00173dbd2d09a73e63eba1042bead70aafa63f8 Mon Sep 17 00:00:00 2001 From: Jm Casler Date: Sun, 31 Jan 2021 18:20:08 -0800 Subject: [PATCH 039/258] partial work --- src/plugins/RangeTestPlugin.cpp | 34 +++++++++++++++++++++++++++------ 1 file changed, 28 insertions(+), 6 deletions(-) diff --git a/src/plugins/RangeTestPlugin.cpp b/src/plugins/RangeTestPlugin.cpp index 1b8f80f31..ffe98458c 100644 --- a/src/plugins/RangeTestPlugin.cpp +++ b/src/plugins/RangeTestPlugin.cpp @@ -5,11 +5,16 @@ #include "Router.h" #include "configuration.h" #include - #include +//#include +//#include +//#include + +//#undef str + #define RANGETESTPLUGIN_ENABLED 1 -#define RANGETESTPLUGIN_SENDER 0 +#define RANGETESTPLUGIN_SENDER 20000 RangeTestPlugin *rangeTestPlugin; RangeTestPluginRadio *rangeTestPluginRadio; @@ -34,10 +39,21 @@ int32_t RangeTestPlugin::runOnce() firstTime = 0; } else { + + // If sender + if (RANGETESTPLUGIN_SENDER) { + + return (RANGETESTPLUGIN_SENDER); + + // Otherwise, we're a receiver. + } else { + + rangeTestPluginRadio->sendPayload(); + return (500); + } // TBD } - return (10); } else { DEBUG_MSG("Range Test Plugin - Disabled\n"); @@ -61,6 +77,15 @@ void RangeTestPluginRadio::sendPayload(NodeNum dest, bool wantReplies) p->to = dest; p->decoded.want_response = wantReplies; + p->want_ack = true; + + uint16_t packetSequence = 123456; + static char heartbeatString[20]; + snprintf(heartbeatString, sizeof(heartbeatString), "Seq: %d%%", packetSequence); + + p->decoded.data.payload.size = strlen(heartbeatString); // You must specify how many bytes are in the reply + memcpy(p->decoded.data.payload.bytes, heartbeatString, p->decoded.data.payload.size); + service.sendToMesh(p); } @@ -88,9 +113,6 @@ bool RangeTestPluginRadio::handleReceived(const MeshPacket &mp) mp.hop_limit; mp.decoded.position.latitude_i; mp.decoded.position.longitude_i; - - - } } else { From e9affb50d210f164df2eaef433d76f6c39afb8bd Mon Sep 17 00:00:00 2001 From: Jm Date: Tue, 2 Feb 2021 17:34:50 -0800 Subject: [PATCH 040/258] #674 add support for lora32 v1.3 --- platformio.ini | 7 +++++++ src/configuration.h | 27 +++++++++++++++++++++++++++ 2 files changed, 34 insertions(+) diff --git a/platformio.ini b/platformio.ini index 9e3b123db..fc94967b5 100644 --- a/platformio.ini +++ b/platformio.ini @@ -10,6 +10,7 @@ [platformio] ;default_envs = tbeam +;default_envs = tlora-v1.3 ;default_envs = tbeam0.7 ;default_envs = heltec ;default_envs = tlora-v1 @@ -149,6 +150,12 @@ board = ttgo-lora32-v1 build_flags = ${esp32_base.build_flags} -D TLORA_V1 +[env:tlora-v1.3] +extends = esp32_base +board = ttgo-lora32-v1 +build_flags = + ${esp32_base.build_flags} -D TLORA_V1_3 + ; note: the platformio definition for lora32-v2 seems stale, it is missing a pins_arduino.h file, therefore I don't think it works [env:tlora-v2] extends = esp32_base diff --git a/src/configuration.h b/src/configuration.h index 79d1009ca..267420878 100644 --- a/src/configuration.h +++ b/src/configuration.h @@ -309,6 +309,33 @@ along with this program. If not, see . #define LORA_DIO1 35 // Not really used #define LORA_DIO2 34 // Not really used +#elif defined(TLORA_V1_3) +// This string must exactly match the case used in release file names or the android updater won't work +#define HW_VENDOR "tlora-v1-3" + +#undef GPS_RX_PIN +#undef GPS_TX_PIN +#define GPS_RX_PIN 36 +#define GPS_TX_PIN 13 // per @eugene + +#define BATTERY_PIN 35 // A battery voltage measurement pin, voltage divider connected here to measure battery voltage + +#define I2C_SDA 4 // I2C pins for this board +#define I2C_SCL 15 + +#define RESET_OLED 16 // If defined, this pin will be used to reset the display controller + +#define VEXT_ENABLE 21 // active low, powers the oled display and the lora antenna boost +#define LED_PIN 25 // If defined we will blink this LED +#define BUTTON_PIN 36 +#define BUTTON_NEED_PULLUP + +#define USE_RF95 +#define LORA_DIO0 26 // a No connect on the SX1262 module +#define LORA_RESET 14 +#define LORA_DIO1 35 // Not really used +#define LORA_DIO2 34 // Not really used + #elif defined(TLORA_V2_1_16) // This string must exactly match the case used in release file names or the android updater won't work #define HW_VENDOR "tlora-v2-1-1.6" From 5661e5dad6cddc867f361250fdd14ecbc2a335b9 Mon Sep 17 00:00:00 2001 From: Jm Casler Date: Tue, 2 Feb 2021 22:43:24 -0800 Subject: [PATCH 041/258] Update radio-settings.md --- docs/radio-settings.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/docs/radio-settings.md b/docs/radio-settings.md index 7af9d79e0..76060b351 100644 --- a/docs/radio-settings.md +++ b/docs/radio-settings.md @@ -33,9 +33,9 @@ Channel zero starts at 903.08 MHz center frequency. Various data-rates are selectable when configuring a channel and are inversely proportional to the theoretical range of the devices: -| Channel setting | Data-rate | -|----------------------------|----------------------| -| Short range (but fast) | 21.875 kbps | -| Medium range (but fast) | 5.469 kbps | -| Long range (but slower) | 0.275 kbps | -| Very long range (but slow) | 0.183 kbps (default) | +| Channel setting | Alt Channel Name | Data-rate | SF | Symbols | Coding Rate | Bandwidth | +|----------------------------|------------------|----------------------|--------------|-------------------------| +| Short range (but fast) | Short Fast | 21.875 kbps | 7 | 128 | 4/5 | 125 | +| Medium range (but fast) | Medium | 5.469 kbps | 7 | 512 | 4/5 | 500 | +| Long range (but slower) | Long Alt | 0.275 kbps | 9 | 512 | 4/8 | 31 | +| Very long range (but slow) | Long Slow | 0.183 kbps (default) | 12 | 4096 | 4/8 | 125 | From 8a68ae0d044511f4236c631507d2954ba2f5168c Mon Sep 17 00:00:00 2001 From: Jm Casler Date: Tue, 2 Feb 2021 22:47:16 -0800 Subject: [PATCH 042/258] Update radio-settings.md --- docs/radio-settings.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docs/radio-settings.md b/docs/radio-settings.md index 76060b351..5c94fe9cf 100644 --- a/docs/radio-settings.md +++ b/docs/radio-settings.md @@ -39,3 +39,7 @@ Various data-rates are selectable when configuring a channel and are inversely p | Medium range (but fast) | Medium | 5.469 kbps | 7 | 512 | 4/5 | 500 | | Long range (but slower) | Long Alt | 0.275 kbps | 9 | 512 | 4/8 | 31 | | Very long range (but slow) | Long Slow | 0.183 kbps (default) | 12 | 4096 | 4/8 | 125 | + +Other radio settings can be configured by using the Python API. An easy calculator of other bit rates is: + +https://unsigned.io/understanding-lora-parameters/ \ No newline at end of file From 0c6c189028c72e789f744f65d6b32f99b4626cf5 Mon Sep 17 00:00:00 2001 From: Jm Casler Date: Tue, 2 Feb 2021 23:01:05 -0800 Subject: [PATCH 043/258] Update to radio-settings.md --- docs/radio-settings.md | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/docs/radio-settings.md b/docs/radio-settings.md index 5c94fe9cf..ad90b9fd0 100644 --- a/docs/radio-settings.md +++ b/docs/radio-settings.md @@ -33,13 +33,14 @@ Channel zero starts at 903.08 MHz center frequency. Various data-rates are selectable when configuring a channel and are inversely proportional to the theoretical range of the devices: -| Channel setting | Alt Channel Name | Data-rate | SF | Symbols | Coding Rate | Bandwidth | -|----------------------------|------------------|----------------------|--------------|-------------------------| -| Short range (but fast) | Short Fast | 21.875 kbps | 7 | 128 | 4/5 | 125 | -| Medium range (but fast) | Medium | 5.469 kbps | 7 | 512 | 4/5 | 500 | -| Long range (but slower) | Long Alt | 0.275 kbps | 9 | 512 | 4/8 | 31 | -| Very long range (but slow) | Long Slow | 0.183 kbps (default) | 12 | 4096 | 4/8 | 125 | +| Channel setting | Alt Channel Name | Data-rate | SF / Symbols | Coding Rate | Bandwidth | +|:---------------------------|:-----------------|:---------------------|:-------------|:------------|:----------| +| Short range (but fast) | Short Fast | 21.875 kbps | 7 / 128 | 4/5 | 125 | +| Medium range (but fast) | Medium | 5.469 kbps | 7 / 512 | 4/5 | 500 | +| Long range (but slower) | Long Alt | 0.275 kbps | 9 / 512 | 4/8 | 31 | +| Very long range (but slow) | Long Slow | 0.183 kbps (default) | 12 / 4096 | 4/8 | 125 | Other radio settings can be configured by using the Python API. An easy calculator of other bit rates is: -https://unsigned.io/understanding-lora-parameters/ \ No newline at end of file +[Lora Parameters](https://unsigned.io/understanding-lora-parameters/) + From 324627482aba9ac85551286be18e3fa7e34d3b1c Mon Sep 17 00:00:00 2001 From: Jm Casler Date: Tue, 2 Feb 2021 23:57:25 -0800 Subject: [PATCH 044/258] Update radio-settings.md --- docs/radio-settings.md | 39 +++++++++++++++++++++++++++++++++++++-- 1 file changed, 37 insertions(+), 2 deletions(-) diff --git a/docs/radio-settings.md b/docs/radio-settings.md index ad90b9fd0..9968ee27e 100644 --- a/docs/radio-settings.md +++ b/docs/radio-settings.md @@ -31,7 +31,23 @@ Channel zero starts at 903.08 MHz center frequency. ## Data-rates -Various data-rates are selectable when configuring a channel and are inversely proportional to the theoretical range of the devices: +Various data-rates are selectable when configuring a channel and are inversely proportional to the theoretical range of the devices. + +Considerations: + +* Spreading Factor +* * Each step up in Spreading Factor dobules the airtime to transmit. +* * Each step up in Spreading Factor adds about 2.5db extra link budget. +* Bandwidth +* * Each doubling of the bandwidth is almost 3db less link budget. +* Coding Rate +* * Increasing coding rate increases reliability while decrasing data-rate. +* * 4/5 - 1.25x overhead +* * 4/6 - 1.5x overhead +* * 4/7 - 1.75x overhead +* * 4/8 - 2x overhead + +Predefined Channels: | Channel setting | Alt Channel Name | Data-rate | SF / Symbols | Coding Rate | Bandwidth | |:---------------------------|:-----------------|:---------------------|:-------------|:------------|:----------| @@ -40,7 +56,26 @@ Various data-rates are selectable when configuring a channel and are inversely p | Long range (but slower) | Long Alt | 0.275 kbps | 9 / 512 | 4/8 | 31 | | Very long range (but slow) | Long Slow | 0.183 kbps (default) | 12 / 4096 | 4/8 | 125 | -Other radio settings can be configured by using the Python API. An easy calculator of other bit rates is: +Other settings can be set by using the Python API. + +> meshtastic --set spread_factor 10 --set coding_rate 8 --bandwidth 125 + +Some example settings: + +| Data-rate | SF / Symbols | Coding Rate | Bandwidth | Note | +|:---------------------|:-------------|:------------|:----------|:-----| +| 3.125 kbps | 8 / 256 | 4/5 | 125 | | +| 1.953 kbps | 8 / 256 | 4/8 | 125 | | +| 1.343 kbps | 11 / 2048 | 4/8 | 512 | | +| 1.099 kbps | 9 / 512 | 4/8 | 125 | | +| 0.814 kbps | 10 / 1024 | 4/6 | 125 | | +| 0.610 kbps | 10 / 1024 | 4/8 | 125 | | +| 0.488 kbps | 11 / 2048 | 4/6 | 125 | | +| 0.336 kbps | 11 / 2048 | 4/8 | 125 | | +| 0.092 kbps | 12 / 4096 | 4/8 | 62 | | +| 0.046 kbps | 12 / 4096 | 4/8 | 31 | Twice the range of "Long Slow" | + +An easy calculator of other bit rates is: [Lora Parameters](https://unsigned.io/understanding-lora-parameters/) From 6d66a53f8d3811b5523dc81d6162cf6e487b27f0 Mon Sep 17 00:00:00 2001 From: Jm Casler Date: Tue, 2 Feb 2021 23:59:34 -0800 Subject: [PATCH 045/258] Another update to radio-settings.md --- docs/radio-settings.md | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/docs/radio-settings.md b/docs/radio-settings.md index 9968ee27e..73aba91ff 100644 --- a/docs/radio-settings.md +++ b/docs/radio-settings.md @@ -31,6 +31,8 @@ Channel zero starts at 903.08 MHz center frequency. ## Data-rates +### About + Various data-rates are selectable when configuring a channel and are inversely proportional to the theoretical range of the devices. Considerations: @@ -47,6 +49,9 @@ Considerations: * * 4/7 - 1.75x overhead * * 4/8 - 2x overhead + +### Pre-Defined + Predefined Channels: | Channel setting | Alt Channel Name | Data-rate | SF / Symbols | Coding Rate | Bandwidth | @@ -56,6 +61,8 @@ Predefined Channels: | Long range (but slower) | Long Alt | 0.275 kbps | 9 / 512 | 4/8 | 31 | | Very long range (but slow) | Long Slow | 0.183 kbps (default) | 12 / 4096 | 4/8 | 125 | +### Custom Settings + Other settings can be set by using the Python API. > meshtastic --set spread_factor 10 --set coding_rate 8 --bandwidth 125 @@ -75,7 +82,4 @@ Some example settings: | 0.092 kbps | 12 / 4096 | 4/8 | 62 | | | 0.046 kbps | 12 / 4096 | 4/8 | 31 | Twice the range of "Long Slow" | -An easy calculator of other bit rates is: - -[Lora Parameters](https://unsigned.io/understanding-lora-parameters/) From 9c60a7966fb9e254978690959555f69bf78ef37e Mon Sep 17 00:00:00 2001 From: Jm Casler Date: Wed, 3 Feb 2021 00:01:52 -0800 Subject: [PATCH 046/258] Update radio-settings.md --- docs/radio-settings.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/radio-settings.md b/docs/radio-settings.md index 73aba91ff..4a3f615e0 100644 --- a/docs/radio-settings.md +++ b/docs/radio-settings.md @@ -52,7 +52,7 @@ Considerations: ### Pre-Defined -Predefined Channels: +We have four predefined channels. These are the most common settings and have been proven to work well: | Channel setting | Alt Channel Name | Data-rate | SF / Symbols | Coding Rate | Bandwidth | |:---------------------------|:-----------------|:---------------------|:-------------|:------------|:----------| @@ -63,7 +63,7 @@ Predefined Channels: ### Custom Settings -Other settings can be set by using the Python API. +You may want to select other channels for your usage. The other settings can be set by using the Python API. > meshtastic --set spread_factor 10 --set coding_rate 8 --bandwidth 125 From b901f8d9ae3dec67ae0623ad106b20df245bdd14 Mon Sep 17 00:00:00 2001 From: Jm Casler Date: Wed, 3 Feb 2021 00:15:41 -0800 Subject: [PATCH 047/258] Update to radio-settings.md --- docs/radio-settings.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/radio-settings.md b/docs/radio-settings.md index 4a3f615e0..e6b148cc1 100644 --- a/docs/radio-settings.md +++ b/docs/radio-settings.md @@ -37,12 +37,12 @@ Various data-rates are selectable when configuring a channel and are inversely p Considerations: -* Spreading Factor +* Spreading Factor - How much we "spread" our data over time. * * Each step up in Spreading Factor dobules the airtime to transmit. * * Each step up in Spreading Factor adds about 2.5db extra link budget. -* Bandwidth +* Bandwidth - How big of a slice of the spectrum we use. * * Each doubling of the bandwidth is almost 3db less link budget. -* Coding Rate +* Coding Rate - How much redundency we encode to resist noise. * * Increasing coding rate increases reliability while decrasing data-rate. * * 4/5 - 1.25x overhead * * 4/6 - 1.5x overhead From 45c17659ccd5add061853ec7c38dbc7d4668c7a2 Mon Sep 17 00:00:00 2001 From: Jm Casler Date: Wed, 3 Feb 2021 01:04:23 -0800 Subject: [PATCH 048/258] radio-settings.md - add note about TCXO stability --- docs/radio-settings.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/radio-settings.md b/docs/radio-settings.md index e6b148cc1..027b9638f 100644 --- a/docs/radio-settings.md +++ b/docs/radio-settings.md @@ -42,6 +42,7 @@ Considerations: * * Each step up in Spreading Factor adds about 2.5db extra link budget. * Bandwidth - How big of a slice of the spectrum we use. * * Each doubling of the bandwidth is almost 3db less link budget. +* * Bandwidths less than 31 may be unstable unless you have a high quality Crystal Ossilator. * Coding Rate - How much redundency we encode to resist noise. * * Increasing coding rate increases reliability while decrasing data-rate. * * 4/5 - 1.25x overhead From 0fa654e53ad97cd68e38a7ce28e20971fa304a9e Mon Sep 17 00:00:00 2001 From: Jm Casler Date: Wed, 3 Feb 2021 07:01:35 -0800 Subject: [PATCH 049/258] update radio-settings.md --- docs/radio-settings.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/radio-settings.md b/docs/radio-settings.md index 027b9638f..e45ea387c 100644 --- a/docs/radio-settings.md +++ b/docs/radio-settings.md @@ -66,7 +66,7 @@ We have four predefined channels. These are the most common settings and have be You may want to select other channels for your usage. The other settings can be set by using the Python API. -> meshtastic --set spread_factor 10 --set coding_rate 8 --bandwidth 125 +> meshtastic --setchan spread_factor 10 --setchan coding_rate 8 --setchan bandwidth 125 Some example settings: From 0c71de4e59e26a2e53fc6a503b6f669e6df07b4c Mon Sep 17 00:00:00 2001 From: Jm Date: Wed, 3 Feb 2021 08:09:59 -0800 Subject: [PATCH 050/258] Update for rangetest plugin --- platformio.ini | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/platformio.ini b/platformio.ini index fc94967b5..bbdd58d48 100644 --- a/platformio.ini +++ b/platformio.ini @@ -9,14 +9,14 @@ ; https://docs.platformio.org/page/projectconf.html [platformio] -;default_envs = tbeam +default_envs = tbeam ;default_envs = tlora-v1.3 ;default_envs = tbeam0.7 ;default_envs = heltec ;default_envs = tlora-v1 ;default_envs = tlora-v2 ;default_envs = lora-relay-v1 # nrf board -default_envs = linux # lora-relay-v1 # nrf52840dk-geeksville # linux # or if you'd like to change the default to something like lora-relay-v1 put that here +;default_envs = linux # lora-relay-v1 # nrf52840dk-geeksville # linux # or if you'd like to change the default to something like lora-relay-v1 put that here [common] ; common is not currently used @@ -44,8 +44,8 @@ build_flags = -Wno-missing-field-initializers -Isrc -Isrc/mesh -Isrc/gps -Ilib/n ;upload_port = /dev/ttyUSB0 ;monitor_port = /dev/ttyUSB0 -;upload_port = /dev/cu.SLAB_USBtoUART -;monitor_port = /dev/cu.SLAB_USBtoUART +upload_port = /dev/cu.SLAB_USBtoUART +monitor_port = /dev/cu.SLAB_USBtoUART ; the default is esptool ; upload_protocol = esp-prog From f46059ec4c407722caf0e73df593ad7f02b0981e Mon Sep 17 00:00:00 2001 From: Jm Date: Wed, 3 Feb 2021 08:10:13 -0800 Subject: [PATCH 051/258] update to range test plugin --- src/plugins/Plugins.cpp | 4 +-- src/plugins/RangeTestPlugin.cpp | 55 ++++++++++++++++++++++++--------- 2 files changed, 42 insertions(+), 17 deletions(-) diff --git a/src/plugins/Plugins.cpp b/src/plugins/Plugins.cpp index 93487ac7a..c845e652b 100644 --- a/src/plugins/Plugins.cpp +++ b/src/plugins/Plugins.cpp @@ -31,7 +31,7 @@ void setupPlugins() */ new SerialPlugin(); new ExternalNotificationPlugin(); - new StoreForwardPlugin(); - new RangeTestPlugin(); + //new StoreForwardPlugin(); + rangeTestPlugin = new RangeTestPlugin(); #endif } \ No newline at end of file diff --git a/src/plugins/RangeTestPlugin.cpp b/src/plugins/RangeTestPlugin.cpp index ffe98458c..a1fee184b 100644 --- a/src/plugins/RangeTestPlugin.cpp +++ b/src/plugins/RangeTestPlugin.cpp @@ -12,15 +12,17 @@ //#undef str - #define RANGETESTPLUGIN_ENABLED 1 -#define RANGETESTPLUGIN_SENDER 20000 +//#define RANGETESTPLUGIN_SENDER 60 * 1000 +#define RANGETESTPLUGIN_SENDER 0 RangeTestPlugin *rangeTestPlugin; RangeTestPluginRadio *rangeTestPluginRadio; RangeTestPlugin::RangeTestPlugin() : concurrency::OSThread("RangeTestPlugin") {} +uint16_t packetSequence = 0; + // char serialStringChar[Constants_DATA_PAYLOAD_LEN]; int32_t RangeTestPlugin::runOnce() @@ -32,34 +34,40 @@ int32_t RangeTestPlugin::runOnce() if (firstTime) { // Interface with the serial peripheral from in here. - DEBUG_MSG("Initializing Range Test Plugin\n"); rangeTestPluginRadio = new RangeTestPluginRadio(); firstTime = 0; + if (RANGETESTPLUGIN_SENDER) { + DEBUG_MSG("Initializing Range Test Plugin -- Sender\n"); + return (RANGETESTPLUGIN_SENDER); + } else { + DEBUG_MSG("Initializing Range Test Plugin -- Receiver\n"); + return (500); + } + } else { - // If sender if (RANGETESTPLUGIN_SENDER) { - - return (RANGETESTPLUGIN_SENDER); - - // Otherwise, we're a receiver. - } else { + // If sender + DEBUG_MSG("Range Test Plugin - Sending heartbeat\n"); rangeTestPluginRadio->sendPayload(); - return (500); + return (RANGETESTPLUGIN_SENDER); + } else { + // Otherwise, we're a receiver. + + return (INT32_MAX); } // TBD } } else { DEBUG_MSG("Range Test Plugin - Disabled\n"); - - return (INT32_MAX); } + return (INT32_MAX); #endif } @@ -79,9 +87,10 @@ void RangeTestPluginRadio::sendPayload(NodeNum dest, bool wantReplies) p->want_ack = true; - uint16_t packetSequence = 123456; + packetSequence++; + static char heartbeatString[20]; - snprintf(heartbeatString, sizeof(heartbeatString), "Seq: %d%%", packetSequence); + snprintf(heartbeatString, sizeof(heartbeatString), "seq %d", packetSequence); p->decoded.data.payload.size = strlen(heartbeatString); // You must specify how many bytes are in the reply memcpy(p->decoded.data.payload.bytes, heartbeatString, p->decoded.data.payload.size); @@ -103,7 +112,10 @@ bool RangeTestPluginRadio::handleReceived(const MeshPacket &mp) // DEBUG_MSG("* * Message came from the mesh\n"); // Serial2.println("* * Message came from the mesh"); - Serial2.printf("%s", p.payload.bytes); + //Serial2.printf("%s", p.payload.bytes); + /* + + p.payload.size; gpsStatus->getLatitude(); gpsStatus->getLongitude(); @@ -113,6 +125,19 @@ bool RangeTestPluginRadio::handleReceived(const MeshPacket &mp) mp.hop_limit; mp.decoded.position.latitude_i; mp.decoded.position.longitude_i; + + */ + DEBUG_MSG("p.payload.bytes \"%s\"\n", p.payload.bytes); + DEBUG_MSG("p.payload.size %d\n", p.payload.size); + DEBUG_MSG("mp.rx_snr %f\n", mp.rx_snr); + DEBUG_MSG("mp.hop_limit %d\n", mp.hop_limit); + DEBUG_MSG("mp.decoded.position.latitude_i %d\n", mp.decoded.position.latitude_i); + DEBUG_MSG("mp.decoded.position.longitude_i %d\n", mp.decoded.position.longitude_i); + DEBUG_MSG("gpsStatus->getLatitude() %d\n", gpsStatus->getLatitude()); + DEBUG_MSG("gpsStatus->getLongitude() %d\n", gpsStatus->getLongitude()); + DEBUG_MSG("gpsStatus->getHasLock() %d\n", gpsStatus->getHasLock()); + DEBUG_MSG("gpsStatus->getDOP() %d\n", gpsStatus->getDOP()); + } } else { From 9069e5b33e5155731e43bfba98494bdd878e2fa0 Mon Sep 17 00:00:00 2001 From: Kevin Hester Date: Thu, 4 Feb 2021 11:51:12 +0800 Subject: [PATCH 052/258] no longer need to set num jobs, because my computer is better --- bin/build-all.sh | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/bin/build-all.sh b/bin/build-all.sh index caa7c59af..ecb96e7a1 100755 --- a/bin/build-all.sh +++ b/bin/build-all.sh @@ -14,8 +14,6 @@ BOARDS_ESP32="tlora-v2 tlora-v1 tlora-v2-1-1.6 tbeam heltec tbeam0.7" # FIXME note nrf52840dk build is for some reason only generating a BIN file but not a HEX file nrf52840dk-geeksville is fine BOARDS_NRF52="lora-relay-v1" -NUM_JOBS=2 || true - OUTDIR=release/latest # We keep all old builds (and their map files in the archive dir) @@ -51,7 +49,7 @@ function do_build() { basename=universal/firmware-$BOARD-$VERSION fi - pio run --jobs $NUM_JOBS --environment $BOARD # -v + pio run --environment $BOARD # -v SRCELF=.pio/build/$BOARD/firmware.elf cp $SRCELF $OUTDIR/elfs/$basename.elf From e7af338c31290af07c83a350e4db1c982b4dc6bd Mon Sep 17 00:00:00 2001 From: Kevin Hester Date: Thu, 4 Feb 2021 15:46:57 +0800 Subject: [PATCH 053/258] add trademark --- README.md | 2 +- docs/README.md | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index bd9143565..5c33d0f45 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ This is the device side code for the [meshtastic.org](https://www.meshtastic.org ![Continuous Integration](https://github.com/meshtastic/Meshtastic-esp32/workflows/Continuous%20Integration/badge.svg) -Meshtastic™ is a project that lets you use +Meshtastic® is a project that lets you use inexpensive GPS mesh radios as an extensible, super long battery life mesh GPS communicator. These radios are great for hiking, skiing, paragliding - essentially any hobby where you don't have reliable internet access. Each member of your private mesh can always see the location and distance of all other members and any text messages sent to your group chat. diff --git a/docs/README.md b/docs/README.md index 2018f387b..982bb4f67 100644 --- a/docs/README.md +++ b/docs/README.md @@ -1,13 +1,13 @@ # What is Meshtastic? -Meshtastic™ is a project that lets you use +Meshtastic® is a project that lets you use inexpensive (\$30 ish) GPS radios as an extensible, long battery life, secure, mesh GPS communicator. These radios are great for hiking, skiing, paragliding - essentially any hobby where you don't have reliable internet access. Each member of your private mesh can always see the location and distance of all other members and any text messages sent to your group chat. The radios automatically create a mesh to forward packets as needed, so everyone in the group can receive messages from even the furthest member. The radios will optionally work with your phone, but no phone is required. Note: Questions after reading this? See our new [forum](https://meshtastic.discourse.group/). -### Uses +## Uses - Outdoor sports where cellular coverage is limited. (Hiking, Skiing, Boating, Paragliding, Gliders etc..) - Applications where closed source GPS communicators just won't cut it (it is easy to add features for glider pilots etc...) @@ -17,7 +17,7 @@ Note: Questions after reading this? See our new [forum](https://meshtastic.disco [![Youtube video demo](desk-video-screenshot.png)](https://www.youtube.com/watch?v=WlNbMbVZlHI "Meshtastic early demo") -### Features +## Features Not all of these features are fully implemented yet - see **important** disclaimers below. But they should be in by the time we decide to call this project beta (three months?) From 056940a4ad39144602fab4f47706f1db2eb0e6bb Mon Sep 17 00:00:00 2001 From: Jm Casler Date: Sat, 6 Feb 2021 09:13:49 -0800 Subject: [PATCH 054/258] Documentation --- docs/radio-settings.md | 11 +++++++++++ .../{StoreRequestPlugin.md => StoreForwardPlugin.md} | 0 2 files changed, 11 insertions(+) rename docs/software/plugins/{StoreRequestPlugin.md => StoreForwardPlugin.md} (100%) diff --git a/docs/radio-settings.md b/docs/radio-settings.md index e45ea387c..d8790d0a2 100644 --- a/docs/radio-settings.md +++ b/docs/radio-settings.md @@ -84,3 +84,14 @@ Some example settings: | 0.046 kbps | 12 / 4096 | 4/8 | 31 | Twice the range of "Long Slow" | +## Cryptography + +The presahred key used by the devices can be updated. + +* 0 = No crypto +* 1 = Default channel key +* 2 - 10 = The default channel key, except with 1 through 9 added to the last byte + +To disable cryptography: + +> meshtastic --setchan psk 0 \ No newline at end of file diff --git a/docs/software/plugins/StoreRequestPlugin.md b/docs/software/plugins/StoreForwardPlugin.md similarity index 100% rename from docs/software/plugins/StoreRequestPlugin.md rename to docs/software/plugins/StoreForwardPlugin.md From 9035a06b4a3a22c24f34d122194a76b6f9525355 Mon Sep 17 00:00:00 2001 From: Jm Date: Sat, 6 Feb 2021 10:02:23 -0800 Subject: [PATCH 055/258] Add link budget to radio-settings.md --- docs/radio-settings.md | 43 ++++++++++++++++++++++++------------------ 1 file changed, 25 insertions(+), 18 deletions(-) diff --git a/docs/radio-settings.md b/docs/radio-settings.md index e45ea387c..122dcc01d 100644 --- a/docs/radio-settings.md +++ b/docs/radio-settings.md @@ -55,12 +55,14 @@ Considerations: We have four predefined channels. These are the most common settings and have been proven to work well: -| Channel setting | Alt Channel Name | Data-rate | SF / Symbols | Coding Rate | Bandwidth | -|:---------------------------|:-----------------|:---------------------|:-------------|:------------|:----------| -| Short range (but fast) | Short Fast | 21.875 kbps | 7 / 128 | 4/5 | 125 | -| Medium range (but fast) | Medium | 5.469 kbps | 7 / 512 | 4/5 | 500 | -| Long range (but slower) | Long Alt | 0.275 kbps | 9 / 512 | 4/8 | 31 | -| Very long range (but slow) | Long Slow | 0.183 kbps (default) | 12 / 4096 | 4/8 | 125 | +| Channel setting | Alt Channel Name | Data-rate | SF / Symbols | Coding Rate | Bandwidth | Link Budget | +|:---------------------------|:-----------------|:---------------------|:-------------|:------------|:----------|:------------| +| Short range (but fast) | Short Fast | 21.875 kbps | 7 / 128 | 4/5 | 125 | 134dB | +| Medium range (but fast) | Medium | 5.469 kbps | 7 / 128 | 4/5 | 500 | 140dB | +| Long range (but slower) | Long Alt | 0.275 kbps | 9 / 512 | 4/8 | 31 | 153dB | +| Very long range (but slow) | Long Slow | 0.183 kbps (default) | 12 / 4096 | 4/8 | 125 | 154dB | + +The link budget used by these calculations assumes a transmit power of 17dBm. Adjust your link budget assumptions based on your actual devices. ### Custom Settings @@ -68,19 +70,24 @@ You may want to select other channels for your usage. The other settings can be > meshtastic --setchan spread_factor 10 --setchan coding_rate 8 --setchan bandwidth 125 +After applying the settings, you will need to restart the device. After your device is restarted, it will generate a new crypto key and you will need to share the newly generated QR Code or URL to all your other devices. + Some example settings: -| Data-rate | SF / Symbols | Coding Rate | Bandwidth | Note | -|:---------------------|:-------------|:------------|:----------|:-----| -| 3.125 kbps | 8 / 256 | 4/5 | 125 | | -| 1.953 kbps | 8 / 256 | 4/8 | 125 | | -| 1.343 kbps | 11 / 2048 | 4/8 | 512 | | -| 1.099 kbps | 9 / 512 | 4/8 | 125 | | -| 0.814 kbps | 10 / 1024 | 4/6 | 125 | | -| 0.610 kbps | 10 / 1024 | 4/8 | 125 | | -| 0.488 kbps | 11 / 2048 | 4/6 | 125 | | -| 0.336 kbps | 11 / 2048 | 4/8 | 125 | | -| 0.092 kbps | 12 / 4096 | 4/8 | 62 | | -| 0.046 kbps | 12 / 4096 | 4/8 | 31 | Twice the range of "Long Slow" | +| Data-rate | SF / Symbols | Coding Rate | Bandwidth | Link Budget | Note | +|:---------------------|:-------------|:------------|:----------|:------------|:-----| +| 37.50 kbps | 6 / 64 | 4/5 | 500 | 129dB | Fastest possible speed | +| 3.125 kbps | 8 / 256 | 4/5 | 125 | 143dB | | +| 1.953 kbps | 8 / 256 | 4/8 | 125 | 143dB | | +| 1.343 kbps | 11 / 2048 | 4/8 | 500 | 145dB | | +| 1.099 kbps | 9 / 512 | 4/8 | 125 | 146dB | | +| 0.814 kbps | 10 / 1024 | 4/6 | 125 | 149dB | | +| 0.610 kbps | 10 / 1024 | 4/8 | 125 | 149dB | | +| 0.488 kbps | 11 / 2048 | 4/6 | 125 | 152dB | | +| 0.336 kbps | 11 / 2048 | 4/8 | 125 | 152dB | | +| 0.073 kbps | 12 / 4096 | 4/5 | 31 | 160dB | Twice the range of "Long Slow", low resliance to noise | +| 0.046 kbps | 12 / 4096 | 4/8 | 31 | 160dB | Twice the range of "Long Slow", high resliance to noise | +The link budget used by these calculations assumes a transmit power of 17dBm. Adjust your link budget assumptions based on your actual devices. +These channel settings may have not been tested. Use at your own discression. Share on https://meshtastic.discourse.group with your successes or failure. From 22af1b551a6840fec24c4195e072d3d4f363c6a3 Mon Sep 17 00:00:00 2001 From: Jm Date: Sat, 6 Feb 2021 10:06:20 -0800 Subject: [PATCH 056/258] Add note about antenna gain. --- docs/radio-settings.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/radio-settings.md b/docs/radio-settings.md index baa076542..c7ac2c9a3 100644 --- a/docs/radio-settings.md +++ b/docs/radio-settings.md @@ -62,7 +62,7 @@ We have four predefined channels. These are the most common settings and have be | Long range (but slower) | Long Alt | 0.275 kbps | 9 / 512 | 4/8 | 31 | 153dB | | Very long range (but slow) | Long Slow | 0.183 kbps (default) | 12 / 4096 | 4/8 | 125 | 154dB | -The link budget used by these calculations assumes a transmit power of 17dBm. Adjust your link budget assumptions based on your actual devices. +The link budget used by these calculations assumes a transmit power of 17dBm and an antenna with 0dB gain. Adjust your link budget assumptions based on your actual devices. ### Custom Settings @@ -88,7 +88,7 @@ Some example settings: | 0.073 kbps | 12 / 4096 | 4/5 | 31 | 160dB | Twice the range of "Long Slow", low resliance to noise | | 0.046 kbps | 12 / 4096 | 4/8 | 31 | 160dB | Twice the range of "Long Slow", high resliance to noise | -The link budget used by these calculations assumes a transmit power of 17dBm. Adjust your link budget assumptions based on your actual devices. +The link budget used by these calculations assumes a transmit power of 17dBm and an antenna with 0dB gain. Adjust your link budget assumptions based on your actual devices. These channel settings may have not been tested. Use at your own discression. Share on https://meshtastic.discourse.group with your successes or failure. From ccb232b6accfdc2c36bdf4b10b25864d959b9be1 Mon Sep 17 00:00:00 2001 From: Kevin Hester Date: Sun, 7 Feb 2021 09:46:35 +0800 Subject: [PATCH 057/258] make route errors a more general 'message delivery failure' reason in support of https://github.com/meshtastic/Meshtastic-device/issues/677 --- proto | 2 +- src/mesh/DSRRouter.cpp | 8 ++++---- src/mesh/DSRRouter.h | 2 +- src/mesh/generated/mesh.pb.h | 25 +++++++++++++------------ src/mesh/generated/portnums.pb.h | 2 +- 5 files changed, 20 insertions(+), 19 deletions(-) diff --git a/proto b/proto index c9ad10d7e..1813b370a 160000 --- a/proto +++ b/proto @@ -1 +1 @@ -Subproject commit c9ad10d7e2f7f465dc477e98d6ec9d3b7059336c +Subproject commit 1813b370ab5336fc3ba453fa92206f4941eda96b diff --git a/src/mesh/DSRRouter.cpp b/src/mesh/DSRRouter.cpp index d8ca542d7..ad41afdde 100644 --- a/src/mesh/DSRRouter.cpp +++ b/src/mesh/DSRRouter.cpp @@ -105,7 +105,7 @@ void DSRRouter::sniffReceived(const MeshPacket *p) // packets until ack arrives) // FIXME, if we don't get a route reply at all (or a route error), timeout and generate a routeerror TIMEOUT on our own... break; - case SubPacket_route_error_tag: + case SubPacket_error_reason_tag: removeRoute(p->decoded.dest); // FIXME: if any pending packets were waiting on this route, delete them @@ -131,7 +131,7 @@ void DSRRouter::sniffReceived(const MeshPacket *p) assert(p->decoded.source); // I think this is guaranteed by now // FIXME - what if the current packet _is_ a route error packet? - sendRouteError(p, RouteError_NO_ROUTE); + sendRouteError(p, ErrorReason_NO_ROUTE); } // FIXME, stop local processing of this packet @@ -145,7 +145,7 @@ void DSRRouter::sniffReceived(const MeshPacket *p) if (pending && pending->packet->decoded.source) { // if source not set, this was not a multihop packet, just ignore removeRoute(pending->packet->decoded.dest); // We no longer have a route to the specified node - sendRouteError(p, RouteError_GOT_NAK); + sendRouteError(p, ErrorReason_GOT_NAK); } } } @@ -230,7 +230,7 @@ void DSRRouter::sendNextHop(NodeNum n, const MeshPacket *p) /** * Send a route error packet towards whoever originally sent this message */ -void DSRRouter::sendRouteError(const MeshPacket *p, RouteError err) +void DSRRouter::sendRouteError(const MeshPacket *p, ErrorReason err) { DEBUG_MSG("FIXME not implemented sendRouteError\n"); } diff --git a/src/mesh/DSRRouter.h b/src/mesh/DSRRouter.h index 3bc461571..02c0f2775 100644 --- a/src/mesh/DSRRouter.h +++ b/src/mesh/DSRRouter.h @@ -70,7 +70,7 @@ class DSRRouter : public ReliableRouter /** * Send a route error packet towards whoever originally sent this message */ - void sendRouteError(const MeshPacket *p, RouteError err); + void sendRouteError(const MeshPacket *p, ErrorReason err); /** make a copy of p, start discovery, but only if we don't * already a discovery in progress for that node number. Caller has already scheduled this message for retransmission diff --git a/src/mesh/generated/mesh.pb.h b/src/mesh/generated/mesh.pb.h index a13d7de56..3f1b24c27 100644 --- a/src/mesh/generated/mesh.pb.h +++ b/src/mesh/generated/mesh.pb.h @@ -11,12 +11,13 @@ #endif /* Enum definitions */ -typedef enum _RouteError { - RouteError_NONE = 0, - RouteError_NO_ROUTE = 1, - RouteError_GOT_NAK = 2, - RouteError_TIMEOUT = 3 -} RouteError; +typedef enum _ErrorReason { + ErrorReason_NONE = 0, + ErrorReason_NO_ROUTE = 1, + ErrorReason_GOT_NAK = 2, + ErrorReason_TIMEOUT = 3, + ErrorReason_NO_INTERFACE = 4 +} ErrorReason; typedef enum _Constants { Constants_Unused = 0, @@ -230,7 +231,7 @@ typedef struct _SubPacket { User user; RouteDiscovery route_request; RouteDiscovery route_reply; - RouteError route_error; + ErrorReason error_reason; }; uint32_t original_id; bool want_response; @@ -288,9 +289,9 @@ typedef struct _ToRadio { /* Helper constants for enums */ -#define _RouteError_MIN RouteError_NONE -#define _RouteError_MAX RouteError_TIMEOUT -#define _RouteError_ARRAYSIZE ((RouteError)(RouteError_TIMEOUT+1)) +#define _ErrorReason_MIN ErrorReason_NONE +#define _ErrorReason_MAX ErrorReason_NO_INTERFACE +#define _ErrorReason_ARRAYSIZE ((ErrorReason)(ErrorReason_NO_INTERFACE+1)) #define _Constants_MIN Constants_Unused #define _Constants_MAX Constants_DATA_PAYLOAD_LEN @@ -450,7 +451,7 @@ extern "C" { #define SubPacket_user_tag 4 #define SubPacket_route_request_tag 6 #define SubPacket_route_reply_tag 7 -#define SubPacket_route_error_tag 13 +#define SubPacket_error_reason_tag 13 #define SubPacket_original_id_tag 2 #define SubPacket_want_response_tag 5 #define SubPacket_dest_tag 9 @@ -517,7 +518,7 @@ X(a, STATIC, ONEOF, MESSAGE, (payload,data,data), 3) \ X(a, STATIC, ONEOF, MESSAGE, (payload,user,user), 4) \ X(a, STATIC, ONEOF, MESSAGE, (payload,route_request,route_request), 6) \ X(a, STATIC, ONEOF, MESSAGE, (payload,route_reply,route_reply), 7) \ -X(a, STATIC, ONEOF, UENUM, (payload,route_error,route_error), 13) \ +X(a, STATIC, ONEOF, UENUM, (payload,error_reason,error_reason), 13) \ X(a, STATIC, SINGULAR, UINT32, original_id, 2) \ X(a, STATIC, SINGULAR, BOOL, want_response, 5) \ X(a, STATIC, SINGULAR, UINT32, dest, 9) \ diff --git a/src/mesh/generated/portnums.pb.h b/src/mesh/generated/portnums.pb.h index 99df1222d..15572ca17 100644 --- a/src/mesh/generated/portnums.pb.h +++ b/src/mesh/generated/portnums.pb.h @@ -19,7 +19,7 @@ typedef enum _PortNum { PortNum_REPLY_APP = 32, PortNum_IP_TUNNEL_APP = 33, PortNum_SERIAL_APP = 64, - PortNum_STORE_REQUEST_APP = 65, + PortNum_STORE_FORWARD_APP = 65, PortNum_PRIVATE_APP = 256, PortNum_ATAK_FORWARDER = 257 } PortNum; From 486b03e985f56eb68a60f9b9b53add7c510a4100 Mon Sep 17 00:00:00 2001 From: Kevin Hester Date: Sun, 7 Feb 2021 10:26:11 +0800 Subject: [PATCH 058/258] bug 677. Don't assert fail for missing interfaces, instead return nak packet to clients. --- proto | 2 +- src/main.cpp | 6 ++++ src/mesh/ReliableRouter.cpp | 27 ++--------------- src/mesh/ReliableRouter.h | 4 --- src/mesh/Router.cpp | 59 ++++++++++++++++++++++++++++-------- src/mesh/Router.h | 8 ++++- src/mesh/generated/mesh.pb.h | 7 +++-- 7 files changed, 68 insertions(+), 45 deletions(-) diff --git a/proto b/proto index 1813b370a..106f4bfde 160000 --- a/proto +++ b/proto @@ -1 +1 @@ -Subproject commit 1813b370ab5336fc3ba453fa92206f4941eda96b +Subproject commit 106f4bfdebe277ab0b86d2b8c950ab78a35b0654 diff --git a/src/main.cpp b/src/main.cpp index aa7b191d9..bb3ec4820 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -490,6 +490,8 @@ void setup() DEBUG_MSG("Warning: Failed to find RF95 radio\n"); delete rIf; rIf = NULL; + } else { + DEBUG_MSG("Radio init succeeded, using RF95 radio\n"); } } #endif @@ -501,6 +503,8 @@ void setup() DEBUG_MSG("Warning: Failed to find SX1262 radio\n"); delete rIf; rIf = NULL; + } else { + DEBUG_MSG("Radio init succeeded, using SX1262 radio\n"); } } #endif @@ -512,6 +516,8 @@ void setup() DEBUG_MSG("Warning: Failed to find simulated radio\n"); delete rIf; rIf = NULL; + } else { + DEBUG_MSG("Using SIMULATED radio!\n"); } } #endif diff --git a/src/mesh/ReliableRouter.cpp b/src/mesh/ReliableRouter.cpp index 93402c127..6060b1f03 100644 --- a/src/mesh/ReliableRouter.cpp +++ b/src/mesh/ReliableRouter.cpp @@ -34,7 +34,7 @@ bool ReliableRouter::shouldFilterReceived(const MeshPacket *p) // the original sending process. if (stopRetransmission(p->from, p->id)) { DEBUG_MSG("Someone is retransmitting for us, generate implicit ack\n"); - sendAckNak(true, p->from, p->id); + sendAckNak(ErrorReason_NONE, p->from, p->id); } } @@ -60,7 +60,7 @@ void ReliableRouter::sniffReceived(const MeshPacket *p) if (p->to == ourNode) { // ignore ack/nak/want_ack packets that are not address to us (we only handle 0 hop reliability // - not DSR routing) if (p->want_ack) { - sendAckNak(true, p->from, p->id); + sendAckNak(ErrorReason_NONE, p->from, p->id); } // If the payload is valid, look for ack/nak @@ -84,27 +84,6 @@ void ReliableRouter::sniffReceived(const MeshPacket *p) FloodingRouter::sniffReceived(p); } -/** - * Send an ack or a nak packet back towards whoever sent idFrom - */ -void ReliableRouter::sendAckNak(bool isAck, NodeNum to, PacketId idFrom) -{ - auto p = allocForSending(); - p->hop_limit = 0; // Assume just immediate neighbors for now - p->to = to; - DEBUG_MSG("Sending an ack=0x%x,to=0x%x,idFrom=0x%x,id=0x%x\n", isAck, to, idFrom, p->id); - - if (isAck) { - p->decoded.ack.success_id = idFrom; - p->decoded.which_ack = SubPacket_success_id_tag; - } else { - p->decoded.ack.fail_id = idFrom; - p->decoded.which_ack = SubPacket_fail_id_tag; - } - - sendLocal(p); // we sometimes send directly to the local node -} - #define NUM_RETRANSMISSIONS 3 PendingPacket::PendingPacket(MeshPacket *p) @@ -176,7 +155,7 @@ int32_t ReliableRouter::doRetransmissions() if (p.numRetransmissions == 0) { DEBUG_MSG("Reliable send failed, returning a nak fr=0x%x,to=0x%x,id=%d\n", p.packet->from, p.packet->to, p.packet->id); - sendAckNak(false, p.packet->from, p.packet->id); + sendAckNak(ErrorReason_MAX_RETRANSMIT, p.packet->from, p.packet->id); // Note: we don't stop retransmission here, instead the Nak packet gets processed in sniffReceived - which // allows the DSR version to still be able to look at the PendingPacket stopRetransmission(it->first); diff --git a/src/mesh/ReliableRouter.h b/src/mesh/ReliableRouter.h index 91dd248a8..62d555389 100644 --- a/src/mesh/ReliableRouter.h +++ b/src/mesh/ReliableRouter.h @@ -109,10 +109,6 @@ class ReliableRouter : public FloodingRouter PendingPacket *startRetransmission(MeshPacket *p); private: - /** - * Send an ack or a nak packet back towards whoever sent idFrom - */ - void sendAckNak(bool isAck, NodeNum to, PacketId idFrom); /** * Stop any retransmissions we are doing of the specified node/packet ID pair diff --git a/src/mesh/Router.cpp b/src/mesh/Router.cpp index 458a338fe..c3a345522 100644 --- a/src/mesh/Router.cpp +++ b/src/mesh/Router.cpp @@ -99,6 +99,31 @@ MeshPacket *Router::allocForSending() return p; } +/** + * Send an ack or a nak packet back towards whoever sent idFrom + */ +void Router::sendAckNak(ErrorReason err, NodeNum to, PacketId idFrom) +{ + auto p = allocForSending(); + p->hop_limit = 0; // Assume just immediate neighbors for now + p->to = to; + DEBUG_MSG("Sending an err=%d,to=0x%x,idFrom=0x%x,id=0x%x\n", err, to, idFrom, p->id); + + if (!err) { + p->decoded.ack.success_id = idFrom; + p->decoded.which_ack = SubPacket_success_id_tag; + } else { + p->decoded.ack.fail_id = idFrom; + p->decoded.which_ack = SubPacket_fail_id_tag; + + // Also send back the error reason + p->decoded.which_payload = SubPacket_error_reason_tag; + p->decoded.error_reason = err; + } + + sendLocal(p); // we sometimes send directly to the local node +} + ErrorCode Router::sendLocal(MeshPacket *p) { // No need to deliver externally if the destination is the local node @@ -106,15 +131,24 @@ ErrorCode Router::sendLocal(MeshPacket *p) printPacket("Enqueuing local", p); fromRadioQueue.enqueue(p); return ERRNO_OK; - } + } else if (!iface) { + // We must be sending to remote nodes also, fail if no interface found - // If we are sending a broadcast, we also treat it as if we just received it ourself - // this allows local apps (and PCs) to see broadcasts sourced locally - if (p->to == NODENUM_BROADCAST) { - handleReceived(p); - } + // ERROR! no radio found, report failure back to the client and drop the packet + DEBUG_MSG("Error: No interface, returning NAK and dropping packet.\n"); + sendAckNak(ErrorReason_NO_INTERFACE, p->from, p->id); + packetPool.release(p); - return send(p); + return ERRNO_NO_INTERFACES; + } else { + // If we are sending a broadcast, we also treat it as if we just received it ourself + // this allows local apps (and PCs) to see broadcasts sourced locally + if (p->to == NODENUM_BROADCAST) { + handleReceived(p); + } + + return send(p); + } } /** @@ -154,14 +188,15 @@ ErrorCode Router::send(MeshPacket *p) p->which_payload = MeshPacket_encrypted_tag; } - if (iface) { - // DEBUG_MSG("Sending packet via interface fr=0x%x,to=0x%x,id=%d\n", p->from, p->to, p->id); - return iface->send(p); - } else { + assert(iface); // This should have been detected already in sendLocal (or we just received a packet from outside) + // if (iface) { + // DEBUG_MSG("Sending packet via interface fr=0x%x,to=0x%x,id=%d\n", p->from, p->to, p->id); + return iface->send(p); + /* } else { DEBUG_MSG("Dropping packet - no interfaces - fr=0x%x,to=0x%x,id=%d\n", p->from, p->to, p->id); packetPool.release(p); return ERRNO_NO_INTERFACES; - } + } */ } /** diff --git a/src/mesh/Router.h b/src/mesh/Router.h index 0035f2ac5..dfc44dfa4 100644 --- a/src/mesh/Router.h +++ b/src/mesh/Router.h @@ -48,7 +48,8 @@ class Router : protected concurrency::OSThread virtual int32_t runOnce(); /** - * Works like send, but if we are sending to the local node, we directly put the message in the receive queue + * Works like send, but if we are sending to the local node, we directly put the message in the receive queue. + * This is the primary method used for sending packets, because it handles both the remote and local cases. * * NOTE: This method will free the provided packet (even if we return an error code) */ @@ -92,6 +93,11 @@ class Router : protected concurrency::OSThread */ bool perhapsDecode(MeshPacket *p); + /** + * Send an ack or a nak packet back towards whoever sent idFrom + */ + void sendAckNak(ErrorReason err, NodeNum to, PacketId idFrom); + private: /** * Called from loop() diff --git a/src/mesh/generated/mesh.pb.h b/src/mesh/generated/mesh.pb.h index 3f1b24c27..6bf3a1c01 100644 --- a/src/mesh/generated/mesh.pb.h +++ b/src/mesh/generated/mesh.pb.h @@ -16,7 +16,8 @@ typedef enum _ErrorReason { ErrorReason_NO_ROUTE = 1, ErrorReason_GOT_NAK = 2, ErrorReason_TIMEOUT = 3, - ErrorReason_NO_INTERFACE = 4 + ErrorReason_NO_INTERFACE = 4, + ErrorReason_MAX_RETRANSMIT = 5 } ErrorReason; typedef enum _Constants { @@ -290,8 +291,8 @@ typedef struct _ToRadio { /* Helper constants for enums */ #define _ErrorReason_MIN ErrorReason_NONE -#define _ErrorReason_MAX ErrorReason_NO_INTERFACE -#define _ErrorReason_ARRAYSIZE ((ErrorReason)(ErrorReason_NO_INTERFACE+1)) +#define _ErrorReason_MAX ErrorReason_MAX_RETRANSMIT +#define _ErrorReason_ARRAYSIZE ((ErrorReason)(ErrorReason_MAX_RETRANSMIT+1)) #define _Constants_MIN Constants_Unused #define _Constants_MAX Constants_DATA_PAYLOAD_LEN From 55349ea570c9c2c587e238014c3d0e36592a2dc6 Mon Sep 17 00:00:00 2001 From: Kevin Hester Date: Sun, 7 Feb 2021 10:27:04 +0800 Subject: [PATCH 059/258] 1.1.42 --- version.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version.properties b/version.properties index dd592ccf0..5ff3c45fa 100644 --- a/version.properties +++ b/version.properties @@ -1,4 +1,4 @@ [VERSION] major = 1 minor = 1 -build = 34 +build = 42 From 86553a4fc9a9a2f6973b6669c3a54cbb03a8376d Mon Sep 17 00:00:00 2001 From: Kevin Hester Date: Sun, 7 Feb 2021 10:44:31 +0800 Subject: [PATCH 060/258] add libs needed for linux build on CI server --- .github/workflows/main.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 3f0d994df..1f51272ab 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -22,5 +22,8 @@ jobs: - name: Install extra python tools run: | pip install -U adafruit-nrfutil + - name: Install libs needed for linux build + run: | + sudo apt install -y libpsocksxx-dev - name: Build run: platformio run -e tbeam -e heltec -e lora-relay-v1 -e linux From ccf3450864596c647d294845339ac97cea9b6677 Mon Sep 17 00:00:00 2001 From: Kevin Hester Date: Sun, 7 Feb 2021 10:49:14 +0800 Subject: [PATCH 061/258] make CI build steps more atomic for easier reporting --- .github/workflows/main.yml | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 1f51272ab..5f17d9176 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -25,5 +25,12 @@ jobs: - name: Install libs needed for linux build run: | sudo apt install -y libpsocksxx-dev - - name: Build - run: platformio run -e tbeam -e heltec -e lora-relay-v1 -e linux + - name: Build for tbeam + run: platformio run -e tbeam + - name: Build for heltec + run: platformio run -e heltec + - name: Build for lora-relay-v1 + run: platformio run -e lora-relay-v1 + - name: Build for linux + run: platformio run -e linux + From 9f9f02fc6f6b1054c72279855afe55c813255122 Mon Sep 17 00:00:00 2001 From: Jm Date: Sat, 6 Feb 2021 21:38:54 -0800 Subject: [PATCH 062/258] Reverting platform.ini back to the way it was. --- platformio.ini | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/platformio.ini b/platformio.ini index bbdd58d48..fc94967b5 100644 --- a/platformio.ini +++ b/platformio.ini @@ -9,14 +9,14 @@ ; https://docs.platformio.org/page/projectconf.html [platformio] -default_envs = tbeam +;default_envs = tbeam ;default_envs = tlora-v1.3 ;default_envs = tbeam0.7 ;default_envs = heltec ;default_envs = tlora-v1 ;default_envs = tlora-v2 ;default_envs = lora-relay-v1 # nrf board -;default_envs = linux # lora-relay-v1 # nrf52840dk-geeksville # linux # or if you'd like to change the default to something like lora-relay-v1 put that here +default_envs = linux # lora-relay-v1 # nrf52840dk-geeksville # linux # or if you'd like to change the default to something like lora-relay-v1 put that here [common] ; common is not currently used @@ -44,8 +44,8 @@ build_flags = -Wno-missing-field-initializers -Isrc -Isrc/mesh -Isrc/gps -Ilib/n ;upload_port = /dev/ttyUSB0 ;monitor_port = /dev/ttyUSB0 -upload_port = /dev/cu.SLAB_USBtoUART -monitor_port = /dev/cu.SLAB_USBtoUART +;upload_port = /dev/cu.SLAB_USBtoUART +;monitor_port = /dev/cu.SLAB_USBtoUART ; the default is esptool ; upload_protocol = esp-prog From d678c4888471805b87016d5d4a7d5b79b8cabde3 Mon Sep 17 00:00:00 2001 From: Jm Date: Sat, 6 Feb 2021 23:29:18 -0800 Subject: [PATCH 063/258] work on rangetestplugin and storeforwardplugin done for the night. --- src/mesh/generated/deviceonly.pb.h | 2 +- src/mesh/generated/mesh.pb.h | 29 ++++++++++++++----- src/plugins/Plugins.cpp | 2 +- src/plugins/RangeTestPlugin.cpp | 46 ++++++++++++++++++------------ src/plugins/StoreForwardPlugin.cpp | 14 +++++++-- 5 files changed, 62 insertions(+), 31 deletions(-) diff --git a/src/mesh/generated/deviceonly.pb.h b/src/mesh/generated/deviceonly.pb.h index a6388af96..fb503be49 100644 --- a/src/mesh/generated/deviceonly.pb.h +++ b/src/mesh/generated/deviceonly.pb.h @@ -80,7 +80,7 @@ extern const pb_msgdesc_t DeviceState_msg; #define DeviceState_fields &DeviceState_msg /* Maximum encoded size of messages (where known) */ -#define DeviceState_size 6239 +#define DeviceState_size 6262 #ifdef __cplusplus } /* extern "C" */ diff --git a/src/mesh/generated/mesh.pb.h b/src/mesh/generated/mesh.pb.h index 6bf3a1c01..d37806307 100644 --- a/src/mesh/generated/mesh.pb.h +++ b/src/mesh/generated/mesh.pb.h @@ -193,6 +193,11 @@ typedef struct _RadioConfig_UserPreferences { bool ext_notification_plugin_active; bool ext_notification_plugin_alert_message; bool ext_notification_plugin_alert_bell; + bool range_test_plugin_enabled; + uint32_t range_test_plugin_sender; + bool range_test_plugin_save; + bool store_forward_plugin_enabled; + uint32_t store_forward_plugin_records; } RadioConfig_UserPreferences; typedef struct _RouteDiscovery { @@ -340,7 +345,7 @@ extern "C" { #define MeshPacket_init_default {0, 0, 0, {SubPacket_init_default}, 0, 0, 0, 0, 0, 0} #define ChannelSettings_init_default {0, _ChannelSettings_ModemConfig_MIN, {0, {0}}, "", 0, 0, 0, 0, 0, 0, 0} #define RadioConfig_init_default {false, RadioConfig_UserPreferences_init_default, false, ChannelSettings_init_default} -#define RadioConfig_UserPreferences_init_default {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, "", "", 0, _RegionCode_MIN, _ChargeCurrent_MIN, _LocationSharing_MIN, _GpsOperation_MIN, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0}, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} +#define RadioConfig_UserPreferences_init_default {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, "", "", 0, _RegionCode_MIN, _ChargeCurrent_MIN, _LocationSharing_MIN, _GpsOperation_MIN, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0}, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} #define NodeInfo_init_default {0, false, User_init_default, false, Position_init_default, 0, 0} #define MyNodeInfo_init_default {0, 0, 0, "", "", "", _CriticalErrorCode_MIN, 0, 0, 0, 0, 0, 0, 0} #define LogRecord_init_default {"", 0, "", _LogRecord_Level_MIN} @@ -354,7 +359,7 @@ extern "C" { #define MeshPacket_init_zero {0, 0, 0, {SubPacket_init_zero}, 0, 0, 0, 0, 0, 0} #define ChannelSettings_init_zero {0, _ChannelSettings_ModemConfig_MIN, {0, {0}}, "", 0, 0, 0, 0, 0, 0, 0} #define RadioConfig_init_zero {false, RadioConfig_UserPreferences_init_zero, false, ChannelSettings_init_zero} -#define RadioConfig_UserPreferences_init_zero {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, "", "", 0, _RegionCode_MIN, _ChargeCurrent_MIN, _LocationSharing_MIN, _GpsOperation_MIN, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0}, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} +#define RadioConfig_UserPreferences_init_zero {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, "", "", 0, _RegionCode_MIN, _ChargeCurrent_MIN, _LocationSharing_MIN, _GpsOperation_MIN, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0}, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} #define NodeInfo_init_zero {0, false, User_init_zero, false, Position_init_zero, 0, 0} #define MyNodeInfo_init_zero {0, 0, 0, "", "", "", _CriticalErrorCode_MIN, 0, 0, 0, 0, 0, 0, 0} #define LogRecord_init_zero {"", 0, "", _LogRecord_Level_MIN} @@ -435,6 +440,11 @@ extern "C" { #define RadioConfig_UserPreferences_ext_notification_plugin_active_tag 129 #define RadioConfig_UserPreferences_ext_notification_plugin_alert_message_tag 130 #define RadioConfig_UserPreferences_ext_notification_plugin_alert_bell_tag 131 +#define RadioConfig_UserPreferences_range_test_plugin_enabled_tag 132 +#define RadioConfig_UserPreferences_range_test_plugin_sender_tag 133 +#define RadioConfig_UserPreferences_range_test_plugin_save_tag 134 +#define RadioConfig_UserPreferences_store_forward_plugin_enabled_tag 136 +#define RadioConfig_UserPreferences_store_forward_plugin_records_tag 137 #define RouteDiscovery_route_tag 2 #define User_id_tag 1 #define User_long_name_tag 2 @@ -609,7 +619,12 @@ X(a, STATIC, SINGULAR, UINT32, ext_notification_plugin_output_ms, 127) \ X(a, STATIC, SINGULAR, UINT32, ext_notification_plugin_output, 128) \ X(a, STATIC, SINGULAR, BOOL, ext_notification_plugin_active, 129) \ X(a, STATIC, SINGULAR, BOOL, ext_notification_plugin_alert_message, 130) \ -X(a, STATIC, SINGULAR, BOOL, ext_notification_plugin_alert_bell, 131) +X(a, STATIC, SINGULAR, BOOL, ext_notification_plugin_alert_bell, 131) \ +X(a, STATIC, SINGULAR, BOOL, range_test_plugin_enabled, 132) \ +X(a, STATIC, SINGULAR, UINT32, range_test_plugin_sender, 133) \ +X(a, STATIC, SINGULAR, BOOL, range_test_plugin_save, 134) \ +X(a, STATIC, SINGULAR, BOOL, store_forward_plugin_enabled, 136) \ +X(a, STATIC, SINGULAR, UINT32, store_forward_plugin_records, 137) #define RadioConfig_UserPreferences_CALLBACK NULL #define RadioConfig_UserPreferences_DEFAULT NULL @@ -721,13 +736,13 @@ extern const pb_msgdesc_t ToRadio_msg; #define SubPacket_size 275 #define MeshPacket_size 320 #define ChannelSettings_size 95 -#define RadioConfig_size 382 -#define RadioConfig_UserPreferences_size 282 +#define RadioConfig_size 405 +#define RadioConfig_UserPreferences_size 305 #define NodeInfo_size 132 #define MyNodeInfo_size 106 #define LogRecord_size 81 -#define FromRadio_size 391 -#define ToRadio_size 386 +#define FromRadio_size 414 +#define ToRadio_size 409 #ifdef __cplusplus } /* extern "C" */ diff --git a/src/plugins/Plugins.cpp b/src/plugins/Plugins.cpp index c845e652b..ac8dd7336 100644 --- a/src/plugins/Plugins.cpp +++ b/src/plugins/Plugins.cpp @@ -31,7 +31,7 @@ void setupPlugins() */ new SerialPlugin(); new ExternalNotificationPlugin(); - //new StoreForwardPlugin(); + //storeForwardPlugin = new StoreForwardPlugin(); rangeTestPlugin = new RangeTestPlugin(); #endif } \ No newline at end of file diff --git a/src/plugins/RangeTestPlugin.cpp b/src/plugins/RangeTestPlugin.cpp index a1fee184b..bae5e45fd 100644 --- a/src/plugins/RangeTestPlugin.cpp +++ b/src/plugins/RangeTestPlugin.cpp @@ -6,15 +6,6 @@ #include "configuration.h" #include #include -//#include -//#include -//#include - -//#undef str - -#define RANGETESTPLUGIN_ENABLED 1 -//#define RANGETESTPLUGIN_SENDER 60 * 1000 -#define RANGETESTPLUGIN_SENDER 0 RangeTestPlugin *rangeTestPlugin; RangeTestPluginRadio *rangeTestPluginRadio; @@ -29,7 +20,18 @@ int32_t RangeTestPlugin::runOnce() { #ifndef NO_ESP32 - if (RANGETESTPLUGIN_ENABLED) { + /* + Uncomment the preferences below if you want to use the plugin + without having to configure it from the PythonAPI or WebUI. + */ + + radioConfig.preferences.range_test_plugin_enabled = 1; + radioConfig.preferences.range_test_plugin_sender = 60; + radioConfig.preferences.fixed_position = 1; + + uint32_t senderHeartbeat = radioConfig.preferences.range_test_plugin_sender * 1000; + + if (radioConfig.preferences.range_test_plugin_enabled) { if (firstTime) { @@ -39,9 +41,9 @@ int32_t RangeTestPlugin::runOnce() firstTime = 0; - if (RANGETESTPLUGIN_SENDER) { + if (radioConfig.preferences.range_test_plugin_sender) { DEBUG_MSG("Initializing Range Test Plugin -- Sender\n"); - return (RANGETESTPLUGIN_SENDER); + return (senderHeartbeat); } else { DEBUG_MSG("Initializing Range Test Plugin -- Receiver\n"); return (500); @@ -49,16 +51,23 @@ int32_t RangeTestPlugin::runOnce() } else { - if (RANGETESTPLUGIN_SENDER) { + if (radioConfig.preferences.range_test_plugin_sender) { // If sender - DEBUG_MSG("Range Test Plugin - Sending heartbeat\n"); + DEBUG_MSG("Range Test Plugin - Sending heartbeat every %d ms\n", + (senderHeartbeat)); + + DEBUG_MSG("gpsStatus->getLatitude() %d\n", gpsStatus->getLatitude()); + DEBUG_MSG("gpsStatus->getLongitude() %d\n", gpsStatus->getLongitude()); + DEBUG_MSG("gpsStatus->getHasLock() %d\n", gpsStatus->getHasLock()); + DEBUG_MSG("gpsStatus->getDOP() %d\n", gpsStatus->getDOP()); + DEBUG_MSG("pref.fixed_position() %d\n", radioConfig.preferences.fixed_position); rangeTestPluginRadio->sendPayload(); - return (RANGETESTPLUGIN_SENDER); + return ((senderHeartbeat)); } else { // Otherwise, we're a receiver. - return (INT32_MAX); + return (500); } // TBD } @@ -102,7 +111,7 @@ bool RangeTestPluginRadio::handleReceived(const MeshPacket &mp) { #ifndef NO_ESP32 - if (RANGETESTPLUGIN_ENABLED) { + if (radioConfig.preferences.range_test_plugin_enabled) { auto &p = mp.decoded.data; // DEBUG_MSG("Received text msg self=0x%0x, from=0x%0x, to=0x%0x, id=%d, msg=%.*s\n", @@ -112,7 +121,7 @@ bool RangeTestPluginRadio::handleReceived(const MeshPacket &mp) // DEBUG_MSG("* * Message came from the mesh\n"); // Serial2.println("* * Message came from the mesh"); - //Serial2.printf("%s", p.payload.bytes); + // Serial2.printf("%s", p.payload.bytes); /* @@ -137,7 +146,6 @@ bool RangeTestPluginRadio::handleReceived(const MeshPacket &mp) DEBUG_MSG("gpsStatus->getLongitude() %d\n", gpsStatus->getLongitude()); DEBUG_MSG("gpsStatus->getHasLock() %d\n", gpsStatus->getHasLock()); DEBUG_MSG("gpsStatus->getDOP() %d\n", gpsStatus->getDOP()); - } } else { diff --git a/src/plugins/StoreForwardPlugin.cpp b/src/plugins/StoreForwardPlugin.cpp index c40c35109..4ee4eac7c 100644 --- a/src/plugins/StoreForwardPlugin.cpp +++ b/src/plugins/StoreForwardPlugin.cpp @@ -8,7 +8,7 @@ #include -#define STORE_RECORDS 10 +#define STORE_RECORDS 5000 #define BYTES_PER_RECORDS 512 struct sfRecord @@ -23,7 +23,7 @@ struct sfRecord records[STORE_RECORDS]; StoreForwardPlugin *storeForwardPlugin; StoreForwardPluginRadio *storeForwardPluginRadio; - + StoreForwardPlugin::StoreForwardPlugin() : concurrency::OSThread("SerialPlugin") {} // char serialStringChar[Constants_DATA_PAYLOAD_LEN]; @@ -32,7 +32,15 @@ int32_t StoreForwardPlugin::runOnce() { #ifndef NO_ESP32 - if (STOREFORWARDPLUGIN_ENABLED) { + /* + Uncomment the preferences below if you want to use the plugin + without having to configure it from the PythonAPI or WebUI. + */ + + //radioConfig.preferences.store_forward_plugin_enabled = 1; + //radioConfig.preferences.store_forward_plugin_records = 80; + + if (radioConfig.preferences.store_forward_plugin_enabled) { if (firstTime) { From 4ee01acb40487a97131842d890d324446497214e Mon Sep 17 00:00:00 2001 From: Jm Casler Date: Sun, 7 Feb 2021 09:31:29 -0800 Subject: [PATCH 064/258] Change where the location information is taken from. --- src/plugins/RangeTestPlugin.cpp | 30 +++++++++++++++++------------- 1 file changed, 17 insertions(+), 13 deletions(-) diff --git a/src/plugins/RangeTestPlugin.cpp b/src/plugins/RangeTestPlugin.cpp index bae5e45fd..f1131dfd0 100644 --- a/src/plugins/RangeTestPlugin.cpp +++ b/src/plugins/RangeTestPlugin.cpp @@ -53,13 +53,13 @@ int32_t RangeTestPlugin::runOnce() if (radioConfig.preferences.range_test_plugin_sender) { // If sender - DEBUG_MSG("Range Test Plugin - Sending heartbeat every %d ms\n", - (senderHeartbeat)); + DEBUG_MSG("Range Test Plugin - Sending heartbeat every %d ms\n", (senderHeartbeat)); DEBUG_MSG("gpsStatus->getLatitude() %d\n", gpsStatus->getLatitude()); DEBUG_MSG("gpsStatus->getLongitude() %d\n", gpsStatus->getLongitude()); DEBUG_MSG("gpsStatus->getHasLock() %d\n", gpsStatus->getHasLock()); DEBUG_MSG("gpsStatus->getDOP() %d\n", gpsStatus->getDOP()); + DEBUG_MSG("gpsStatus->getHasLock() %d\n", gpsStatus->getHasLock()); DEBUG_MSG("pref.fixed_position() %d\n", radioConfig.preferences.fixed_position); rangeTestPluginRadio->sendPayload(); @@ -125,23 +125,27 @@ bool RangeTestPluginRadio::handleReceived(const MeshPacket &mp) /* - p.payload.size; - gpsStatus->getLatitude(); - gpsStatus->getLongitude(); - gpsStatus->getHasLock(); - gpsStatus->getDOP(); - mp.rx_snr; - mp.hop_limit; - mp.decoded.position.latitude_i; - mp.decoded.position.longitude_i; */ + + NodeInfo *n = nodeDB.getNode(mp.from); + DEBUG_MSG("p.payload.bytes \"%s\"\n", p.payload.bytes); DEBUG_MSG("p.payload.size %d\n", p.payload.size); + DEBUG_MSG("mp.from %d\n", mp.from); DEBUG_MSG("mp.rx_snr %f\n", mp.rx_snr); DEBUG_MSG("mp.hop_limit %d\n", mp.hop_limit); - DEBUG_MSG("mp.decoded.position.latitude_i %d\n", mp.decoded.position.latitude_i); - DEBUG_MSG("mp.decoded.position.longitude_i %d\n", mp.decoded.position.longitude_i); + // DEBUG_MSG("mp.decoded.position.latitude_i %d\n", mp.decoded.position.latitude_i); + // DEBUG_MSG("mp.decoded.position.longitude_i %d\n", mp.decoded.position.longitude_i); + DEBUG_MSG("n->has_position %d\n", n->has_position); + DEBUG_MSG("n->position.latitude_i %d\n", n->position.latitude_i); + DEBUG_MSG("n->position.longitude_i %d\n", n->position.longitude_i); + + n->user.long_name; + n->user.short_name; + n->user.macaddr; + n->position.battery_level; + DEBUG_MSG("gpsStatus->getLatitude() %d\n", gpsStatus->getLatitude()); DEBUG_MSG("gpsStatus->getLongitude() %d\n", gpsStatus->getLongitude()); DEBUG_MSG("gpsStatus->getHasLock() %d\n", gpsStatus->getHasLock()); From cb541d75a93a54fd73fd24f1aa8494384300dd43 Mon Sep 17 00:00:00 2001 From: Jm Date: Sun, 7 Feb 2021 13:19:52 -0800 Subject: [PATCH 065/258] Update radio-settings.md with note of coverage. --- docs/radio-settings.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/radio-settings.md b/docs/radio-settings.md index c7ac2c9a3..3240d3ddd 100644 --- a/docs/radio-settings.md +++ b/docs/radio-settings.md @@ -85,8 +85,8 @@ Some example settings: | 0.610 kbps | 10 / 1024 | 4/8 | 125 | 149dB | | | 0.488 kbps | 11 / 2048 | 4/6 | 125 | 152dB | | | 0.336 kbps | 11 / 2048 | 4/8 | 125 | 152dB | | -| 0.073 kbps | 12 / 4096 | 4/5 | 31 | 160dB | Twice the range of "Long Slow", low resliance to noise | -| 0.046 kbps | 12 / 4096 | 4/8 | 31 | 160dB | Twice the range of "Long Slow", high resliance to noise | +| 0.073 kbps | 12 / 4096 | 4/5 | 31 | 160dB | Twice the range and/or coverage of "Long Slow", low resliance to noise | +| 0.046 kbps | 12 / 4096 | 4/8 | 31 | 160dB | Twice the range and/or coverage of "Long Slow", high resliance to noise | The link budget used by these calculations assumes a transmit power of 17dBm and an antenna with 0dB gain. Adjust your link budget assumptions based on your actual devices. From 58bb7169a0f87d3c9e4bc9c0068f3b82b62d438c Mon Sep 17 00:00:00 2001 From: Kevin Hester Date: Mon, 8 Feb 2021 10:15:02 +0800 Subject: [PATCH 066/258] use nodenum as the default nodeid --- src/mesh/NodeDB.cpp | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/mesh/NodeDB.cpp b/src/mesh/NodeDB.cpp index ea79e6ccb..dc27276ab 100644 --- a/src/mesh/NodeDB.cpp +++ b/src/mesh/NodeDB.cpp @@ -265,16 +265,15 @@ void NodeDB::installDefaultDeviceState() // Init our blank owner info to reasonable defaults getMacAddr(ourMacAddr); - sprintf(owner.id, "!%02x%02x%02x%02x%02x%02x", ourMacAddr[0], ourMacAddr[1], ourMacAddr[2], ourMacAddr[3], ourMacAddr[4], - ourMacAddr[5]); - memcpy(owner.macaddr, ourMacAddr, sizeof(owner.macaddr)); // Set default owner name - pickNewNodeNum(); // Note: we will repick later, just in case the settings are corrupted, but we need a valid - // owner.short_name now + pickNewNodeNum(); // based on macaddr now sprintf(owner.long_name, "Unknown %02x%02x", ourMacAddr[4], ourMacAddr[5]); sprintf(owner.short_name, "?%02X", (unsigned)(myNodeInfo.my_node_num & 0xff)); + sprintf(owner.id, "!%08x", getNodeNum()); // Default node ID now based on nodenum + memcpy(owner.macaddr, ourMacAddr, sizeof(owner.macaddr)); + // Restore region if possible if (oldRegionCode != RegionCode_Unset) radioConfig.preferences.region = oldRegionCode; From ca8a0ca8d222aef2dfe09d1e099500153c0e1df3 Mon Sep 17 00:00:00 2001 From: Jm Date: Sun, 7 Feb 2021 19:20:29 -0800 Subject: [PATCH 067/258] update rangetest --- src/plugins/RangeTestPlugin.cpp | 35 ++++++++++++++++++++++----------- 1 file changed, 23 insertions(+), 12 deletions(-) diff --git a/src/plugins/RangeTestPlugin.cpp b/src/plugins/RangeTestPlugin.cpp index f1131dfd0..4ed11f447 100644 --- a/src/plugins/RangeTestPlugin.cpp +++ b/src/plugins/RangeTestPlugin.cpp @@ -7,6 +7,13 @@ #include #include +/* + As a sender, I can send packets every n-seonds. These packets include an incramented PacketID. + + As a receiver, I can receive packets from multiple senders. These packets can be saved to the spiffs. + +*/ + RangeTestPlugin *rangeTestPlugin; RangeTestPluginRadio *rangeTestPluginRadio; @@ -26,7 +33,7 @@ int32_t RangeTestPlugin::runOnce() */ radioConfig.preferences.range_test_plugin_enabled = 1; - radioConfig.preferences.range_test_plugin_sender = 60; + radioConfig.preferences.range_test_plugin_sender = 0; radioConfig.preferences.fixed_position = 1; uint32_t senderHeartbeat = radioConfig.preferences.range_test_plugin_sender * 1000; @@ -130,26 +137,30 @@ bool RangeTestPluginRadio::handleReceived(const MeshPacket &mp) NodeInfo *n = nodeDB.getNode(mp.from); + + DEBUG_MSG("-----------------------------------------\n"); DEBUG_MSG("p.payload.bytes \"%s\"\n", p.payload.bytes); DEBUG_MSG("p.payload.size %d\n", p.payload.size); + DEBUG_MSG("---- Received Packet:\n"); DEBUG_MSG("mp.from %d\n", mp.from); DEBUG_MSG("mp.rx_snr %f\n", mp.rx_snr); DEBUG_MSG("mp.hop_limit %d\n", mp.hop_limit); - // DEBUG_MSG("mp.decoded.position.latitude_i %d\n", mp.decoded.position.latitude_i); - // DEBUG_MSG("mp.decoded.position.longitude_i %d\n", mp.decoded.position.longitude_i); - DEBUG_MSG("n->has_position %d\n", n->has_position); - DEBUG_MSG("n->position.latitude_i %d\n", n->position.latitude_i); - DEBUG_MSG("n->position.longitude_i %d\n", n->position.longitude_i); - - n->user.long_name; - n->user.short_name; - n->user.macaddr; - n->position.battery_level; - + DEBUG_MSG("mp.decoded.position.latitude_i %d\n", mp.decoded.position.latitude_i); + DEBUG_MSG("mp.decoded.position.longitude_i %d\n", mp.decoded.position.longitude_i); + DEBUG_MSG("---- Node Information of Received Packet (mp.from):\n"); + DEBUG_MSG("n->user.long_name %s\n", n->user.long_name); + DEBUG_MSG("n->user.short_name %s\n", n->user.short_name); + DEBUG_MSG("n->user.macaddr %X\n", n->user.macaddr); + DEBUG_MSG("n->has_position %d\n", n->has_position); + DEBUG_MSG("n->position.latitude_i %d\n", n->position.latitude_i); + DEBUG_MSG("n->position.longitude_i %d\n", n->position.longitude_i); + DEBUG_MSG("n->position.battery_level %d\n", n->position.battery_level); + DEBUG_MSG("---- Current device location information:\n"); DEBUG_MSG("gpsStatus->getLatitude() %d\n", gpsStatus->getLatitude()); DEBUG_MSG("gpsStatus->getLongitude() %d\n", gpsStatus->getLongitude()); DEBUG_MSG("gpsStatus->getHasLock() %d\n", gpsStatus->getHasLock()); DEBUG_MSG("gpsStatus->getDOP() %d\n", gpsStatus->getDOP()); + DEBUG_MSG("-----------------------------------------\n"); } } else { From 2fa38c7dc4c45cec68eac167cdf278c3de093453 Mon Sep 17 00:00:00 2001 From: Kevin Hester Date: Mon, 8 Feb 2021 17:57:45 +0800 Subject: [PATCH 068/258] update protos --- platformio.ini | 4 +- proto | 2 +- src/mesh/generated/deviceonly.pb.h | 2 +- src/mesh/generated/mesh.pb.h | 127 ++++++++++++++++------------- src/mesh/generated/portnums.pb.h | 1 + 5 files changed, 76 insertions(+), 60 deletions(-) diff --git a/platformio.ini b/platformio.ini index 9e3b123db..9a0e9f6c4 100644 --- a/platformio.ini +++ b/platformio.ini @@ -9,13 +9,13 @@ ; https://docs.platformio.org/page/projectconf.html [platformio] -;default_envs = tbeam +default_envs = tbeam ;default_envs = tbeam0.7 ;default_envs = heltec ;default_envs = tlora-v1 ;default_envs = tlora-v2 ;default_envs = lora-relay-v1 # nrf board -default_envs = linux # lora-relay-v1 # nrf52840dk-geeksville # linux # or if you'd like to change the default to something like lora-relay-v1 put that here +;default_envs = linux # lora-relay-v1 # nrf52840dk-geeksville # linux # or if you'd like to change the default to something like lora-relay-v1 put that here [common] ; common is not currently used diff --git a/proto b/proto index 106f4bfde..259984106 160000 --- a/proto +++ b/proto @@ -1 +1 @@ -Subproject commit 106f4bfdebe277ab0b86d2b8c950ab78a35b0654 +Subproject commit 25998410668a1ff1b092512439ec0e7089f91ce9 diff --git a/src/mesh/generated/deviceonly.pb.h b/src/mesh/generated/deviceonly.pb.h index a6388af96..fb503be49 100644 --- a/src/mesh/generated/deviceonly.pb.h +++ b/src/mesh/generated/deviceonly.pb.h @@ -80,7 +80,7 @@ extern const pb_msgdesc_t DeviceState_msg; #define DeviceState_fields &DeviceState_msg /* Maximum encoded size of messages (where known) */ -#define DeviceState_size 6239 +#define DeviceState_size 6262 #ifdef __cplusplus } /* extern "C" */ diff --git a/src/mesh/generated/mesh.pb.h b/src/mesh/generated/mesh.pb.h index 6bf3a1c01..5968850ab 100644 --- a/src/mesh/generated/mesh.pb.h +++ b/src/mesh/generated/mesh.pb.h @@ -193,6 +193,11 @@ typedef struct _RadioConfig_UserPreferences { bool ext_notification_plugin_active; bool ext_notification_plugin_alert_message; bool ext_notification_plugin_alert_bell; + bool range_test_plugin_enabled; + uint32_t range_test_plugin_sender; + bool range_test_plugin_save; + bool store_forward_plugin_enabled; + uint32_t store_forward_plugin_records; } RadioConfig_UserPreferences; typedef struct _RouteDiscovery { @@ -225,7 +230,7 @@ typedef struct _RadioConfig { } RadioConfig; typedef struct _SubPacket { - pb_size_t which_payload; + pb_size_t which_payloadVariant; union { Position position; Data data; @@ -233,15 +238,15 @@ typedef struct _SubPacket { RouteDiscovery route_request; RouteDiscovery route_reply; ErrorReason error_reason; - }; + } payloadVariant; uint32_t original_id; bool want_response; uint32_t dest; - pb_size_t which_ack; + pb_size_t which_ackVariant; union { uint32_t success_id; uint32_t fail_id; - } ack; + } ackVariant; uint32_t source; } SubPacket; @@ -249,11 +254,11 @@ typedef PB_BYTES_ARRAY_T(256) MeshPacket_encrypted_t; typedef struct _MeshPacket { uint32_t from; uint32_t to; - pb_size_t which_payload; + pb_size_t which_payloadVariant; union { SubPacket decoded; MeshPacket_encrypted_t encrypted; - }; + } payloadVariant; uint32_t channel_index; uint32_t id; float rx_snr; @@ -264,7 +269,7 @@ typedef struct _MeshPacket { typedef struct _FromRadio { uint32_t num; - pb_size_t which_variant; + pb_size_t which_payloadVariant; union { MeshPacket packet; MyNodeInfo my_info; @@ -274,18 +279,18 @@ typedef struct _FromRadio { uint32_t config_complete_id; bool rebooted; ChannelSettings channel; - } variant; + } payloadVariant; } FromRadio; typedef struct _ToRadio { - pb_size_t which_variant; + pb_size_t which_payloadVariant; union { MeshPacket packet; uint32_t want_config_id; RadioConfig set_radio; User set_owner; ChannelSettings set_channel; - } variant; + } payloadVariant; } ToRadio; @@ -340,7 +345,7 @@ extern "C" { #define MeshPacket_init_default {0, 0, 0, {SubPacket_init_default}, 0, 0, 0, 0, 0, 0} #define ChannelSettings_init_default {0, _ChannelSettings_ModemConfig_MIN, {0, {0}}, "", 0, 0, 0, 0, 0, 0, 0} #define RadioConfig_init_default {false, RadioConfig_UserPreferences_init_default, false, ChannelSettings_init_default} -#define RadioConfig_UserPreferences_init_default {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, "", "", 0, _RegionCode_MIN, _ChargeCurrent_MIN, _LocationSharing_MIN, _GpsOperation_MIN, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0}, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} +#define RadioConfig_UserPreferences_init_default {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, "", "", 0, _RegionCode_MIN, _ChargeCurrent_MIN, _LocationSharing_MIN, _GpsOperation_MIN, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0}, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} #define NodeInfo_init_default {0, false, User_init_default, false, Position_init_default, 0, 0} #define MyNodeInfo_init_default {0, 0, 0, "", "", "", _CriticalErrorCode_MIN, 0, 0, 0, 0, 0, 0, 0} #define LogRecord_init_default {"", 0, "", _LogRecord_Level_MIN} @@ -354,7 +359,7 @@ extern "C" { #define MeshPacket_init_zero {0, 0, 0, {SubPacket_init_zero}, 0, 0, 0, 0, 0, 0} #define ChannelSettings_init_zero {0, _ChannelSettings_ModemConfig_MIN, {0, {0}}, "", 0, 0, 0, 0, 0, 0, 0} #define RadioConfig_init_zero {false, RadioConfig_UserPreferences_init_zero, false, ChannelSettings_init_zero} -#define RadioConfig_UserPreferences_init_zero {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, "", "", 0, _RegionCode_MIN, _ChargeCurrent_MIN, _LocationSharing_MIN, _GpsOperation_MIN, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0}, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} +#define RadioConfig_UserPreferences_init_zero {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, "", "", 0, _RegionCode_MIN, _ChargeCurrent_MIN, _LocationSharing_MIN, _GpsOperation_MIN, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0}, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} #define NodeInfo_init_zero {0, false, User_init_zero, false, Position_init_zero, 0, 0} #define MyNodeInfo_init_zero {0, 0, 0, "", "", "", _CriticalErrorCode_MIN, 0, 0, 0, 0, 0, 0, 0} #define LogRecord_init_zero {"", 0, "", _LogRecord_Level_MIN} @@ -435,6 +440,11 @@ extern "C" { #define RadioConfig_UserPreferences_ext_notification_plugin_active_tag 129 #define RadioConfig_UserPreferences_ext_notification_plugin_alert_message_tag 130 #define RadioConfig_UserPreferences_ext_notification_plugin_alert_bell_tag 131 +#define RadioConfig_UserPreferences_range_test_plugin_enabled_tag 132 +#define RadioConfig_UserPreferences_range_test_plugin_sender_tag 133 +#define RadioConfig_UserPreferences_range_test_plugin_save_tag 134 +#define RadioConfig_UserPreferences_store_forward_plugin_enabled_tag 136 +#define RadioConfig_UserPreferences_store_forward_plugin_records_tag 137 #define RouteDiscovery_route_tag 2 #define User_id_tag 1 #define User_long_name_tag 2 @@ -514,31 +524,31 @@ X(a, STATIC, REPEATED, INT32, route, 2) #define RouteDiscovery_DEFAULT NULL #define SubPacket_FIELDLIST(X, a) \ -X(a, STATIC, ONEOF, MESSAGE, (payload,position,position), 1) \ -X(a, STATIC, ONEOF, MESSAGE, (payload,data,data), 3) \ -X(a, STATIC, ONEOF, MESSAGE, (payload,user,user), 4) \ -X(a, STATIC, ONEOF, MESSAGE, (payload,route_request,route_request), 6) \ -X(a, STATIC, ONEOF, MESSAGE, (payload,route_reply,route_reply), 7) \ -X(a, STATIC, ONEOF, UENUM, (payload,error_reason,error_reason), 13) \ +X(a, STATIC, ONEOF, MESSAGE, (payloadVariant,position,payloadVariant.position), 1) \ +X(a, STATIC, ONEOF, MESSAGE, (payloadVariant,data,payloadVariant.data), 3) \ +X(a, STATIC, ONEOF, MESSAGE, (payloadVariant,user,payloadVariant.user), 4) \ +X(a, STATIC, ONEOF, MESSAGE, (payloadVariant,route_request,payloadVariant.route_request), 6) \ +X(a, STATIC, ONEOF, MESSAGE, (payloadVariant,route_reply,payloadVariant.route_reply), 7) \ +X(a, STATIC, ONEOF, UENUM, (payloadVariant,error_reason,payloadVariant.error_reason), 13) \ X(a, STATIC, SINGULAR, UINT32, original_id, 2) \ X(a, STATIC, SINGULAR, BOOL, want_response, 5) \ X(a, STATIC, SINGULAR, UINT32, dest, 9) \ -X(a, STATIC, ONEOF, UINT32, (ack,success_id,ack.success_id), 10) \ -X(a, STATIC, ONEOF, UINT32, (ack,fail_id,ack.fail_id), 11) \ +X(a, STATIC, ONEOF, UINT32, (ackVariant,success_id,ackVariant.success_id), 10) \ +X(a, STATIC, ONEOF, UINT32, (ackVariant,fail_id,ackVariant.fail_id), 11) \ X(a, STATIC, SINGULAR, UINT32, source, 12) #define SubPacket_CALLBACK NULL #define SubPacket_DEFAULT NULL -#define SubPacket_payload_position_MSGTYPE Position -#define SubPacket_payload_data_MSGTYPE Data -#define SubPacket_payload_user_MSGTYPE User -#define SubPacket_payload_route_request_MSGTYPE RouteDiscovery -#define SubPacket_payload_route_reply_MSGTYPE RouteDiscovery +#define SubPacket_payloadVariant_position_MSGTYPE Position +#define SubPacket_payloadVariant_data_MSGTYPE Data +#define SubPacket_payloadVariant_user_MSGTYPE User +#define SubPacket_payloadVariant_route_request_MSGTYPE RouteDiscovery +#define SubPacket_payloadVariant_route_reply_MSGTYPE RouteDiscovery #define MeshPacket_FIELDLIST(X, a) \ X(a, STATIC, SINGULAR, UINT32, from, 1) \ X(a, STATIC, SINGULAR, UINT32, to, 2) \ -X(a, STATIC, ONEOF, MESSAGE, (payload,decoded,decoded), 3) \ -X(a, STATIC, ONEOF, BYTES, (payload,encrypted,encrypted), 8) \ +X(a, STATIC, ONEOF, MESSAGE, (payloadVariant,decoded,payloadVariant.decoded), 3) \ +X(a, STATIC, ONEOF, BYTES, (payloadVariant,encrypted,payloadVariant.encrypted), 8) \ X(a, STATIC, SINGULAR, UINT32, channel_index, 4) \ X(a, STATIC, SINGULAR, UINT32, id, 6) \ X(a, STATIC, SINGULAR, FLOAT, rx_snr, 7) \ @@ -547,7 +557,7 @@ X(a, STATIC, SINGULAR, UINT32, hop_limit, 10) \ X(a, STATIC, SINGULAR, BOOL, want_ack, 11) #define MeshPacket_CALLBACK NULL #define MeshPacket_DEFAULT NULL -#define MeshPacket_payload_decoded_MSGTYPE SubPacket +#define MeshPacket_payloadVariant_decoded_MSGTYPE SubPacket #define ChannelSettings_FIELDLIST(X, a) \ X(a, STATIC, SINGULAR, INT32, tx_power, 1) \ @@ -609,7 +619,12 @@ X(a, STATIC, SINGULAR, UINT32, ext_notification_plugin_output_ms, 127) \ X(a, STATIC, SINGULAR, UINT32, ext_notification_plugin_output, 128) \ X(a, STATIC, SINGULAR, BOOL, ext_notification_plugin_active, 129) \ X(a, STATIC, SINGULAR, BOOL, ext_notification_plugin_alert_message, 130) \ -X(a, STATIC, SINGULAR, BOOL, ext_notification_plugin_alert_bell, 131) +X(a, STATIC, SINGULAR, BOOL, ext_notification_plugin_alert_bell, 131) \ +X(a, STATIC, SINGULAR, BOOL, range_test_plugin_enabled, 132) \ +X(a, STATIC, SINGULAR, UINT32, range_test_plugin_sender, 133) \ +X(a, STATIC, SINGULAR, BOOL, range_test_plugin_save, 134) \ +X(a, STATIC, SINGULAR, BOOL, store_forward_plugin_enabled, 136) \ +X(a, STATIC, SINGULAR, UINT32, store_forward_plugin_records, 137) #define RadioConfig_UserPreferences_CALLBACK NULL #define RadioConfig_UserPreferences_DEFAULT NULL @@ -652,35 +667,35 @@ X(a, STATIC, SINGULAR, UENUM, level, 4) #define FromRadio_FIELDLIST(X, a) \ X(a, STATIC, SINGULAR, UINT32, num, 1) \ -X(a, STATIC, ONEOF, MESSAGE, (variant,packet,variant.packet), 2) \ -X(a, STATIC, ONEOF, MESSAGE, (variant,my_info,variant.my_info), 3) \ -X(a, STATIC, ONEOF, MESSAGE, (variant,node_info,variant.node_info), 4) \ -X(a, STATIC, ONEOF, MESSAGE, (variant,radio,variant.radio), 6) \ -X(a, STATIC, ONEOF, MESSAGE, (variant,log_record,variant.log_record), 7) \ -X(a, STATIC, ONEOF, UINT32, (variant,config_complete_id,variant.config_complete_id), 8) \ -X(a, STATIC, ONEOF, BOOL, (variant,rebooted,variant.rebooted), 9) \ -X(a, STATIC, ONEOF, MESSAGE, (variant,channel,variant.channel), 10) +X(a, STATIC, ONEOF, MESSAGE, (payloadVariant,packet,payloadVariant.packet), 2) \ +X(a, STATIC, ONEOF, MESSAGE, (payloadVariant,my_info,payloadVariant.my_info), 3) \ +X(a, STATIC, ONEOF, MESSAGE, (payloadVariant,node_info,payloadVariant.node_info), 4) \ +X(a, STATIC, ONEOF, MESSAGE, (payloadVariant,radio,payloadVariant.radio), 6) \ +X(a, STATIC, ONEOF, MESSAGE, (payloadVariant,log_record,payloadVariant.log_record), 7) \ +X(a, STATIC, ONEOF, UINT32, (payloadVariant,config_complete_id,payloadVariant.config_complete_id), 8) \ +X(a, STATIC, ONEOF, BOOL, (payloadVariant,rebooted,payloadVariant.rebooted), 9) \ +X(a, STATIC, ONEOF, MESSAGE, (payloadVariant,channel,payloadVariant.channel), 10) #define FromRadio_CALLBACK NULL #define FromRadio_DEFAULT NULL -#define FromRadio_variant_packet_MSGTYPE MeshPacket -#define FromRadio_variant_my_info_MSGTYPE MyNodeInfo -#define FromRadio_variant_node_info_MSGTYPE NodeInfo -#define FromRadio_variant_radio_MSGTYPE RadioConfig -#define FromRadio_variant_log_record_MSGTYPE LogRecord -#define FromRadio_variant_channel_MSGTYPE ChannelSettings +#define FromRadio_payloadVariant_packet_MSGTYPE MeshPacket +#define FromRadio_payloadVariant_my_info_MSGTYPE MyNodeInfo +#define FromRadio_payloadVariant_node_info_MSGTYPE NodeInfo +#define FromRadio_payloadVariant_radio_MSGTYPE RadioConfig +#define FromRadio_payloadVariant_log_record_MSGTYPE LogRecord +#define FromRadio_payloadVariant_channel_MSGTYPE ChannelSettings #define ToRadio_FIELDLIST(X, a) \ -X(a, STATIC, ONEOF, MESSAGE, (variant,packet,variant.packet), 1) \ -X(a, STATIC, ONEOF, UINT32, (variant,want_config_id,variant.want_config_id), 100) \ -X(a, STATIC, ONEOF, MESSAGE, (variant,set_radio,variant.set_radio), 101) \ -X(a, STATIC, ONEOF, MESSAGE, (variant,set_owner,variant.set_owner), 102) \ -X(a, STATIC, ONEOF, MESSAGE, (variant,set_channel,variant.set_channel), 103) +X(a, STATIC, ONEOF, MESSAGE, (payloadVariant,packet,payloadVariant.packet), 1) \ +X(a, STATIC, ONEOF, UINT32, (payloadVariant,want_config_id,payloadVariant.want_config_id), 100) \ +X(a, STATIC, ONEOF, MESSAGE, (payloadVariant,set_radio,payloadVariant.set_radio), 101) \ +X(a, STATIC, ONEOF, MESSAGE, (payloadVariant,set_owner,payloadVariant.set_owner), 102) \ +X(a, STATIC, ONEOF, MESSAGE, (payloadVariant,set_channel,payloadVariant.set_channel), 103) #define ToRadio_CALLBACK NULL #define ToRadio_DEFAULT NULL -#define ToRadio_variant_packet_MSGTYPE MeshPacket -#define ToRadio_variant_set_radio_MSGTYPE RadioConfig -#define ToRadio_variant_set_owner_MSGTYPE User -#define ToRadio_variant_set_channel_MSGTYPE ChannelSettings +#define ToRadio_payloadVariant_packet_MSGTYPE MeshPacket +#define ToRadio_payloadVariant_set_radio_MSGTYPE RadioConfig +#define ToRadio_payloadVariant_set_owner_MSGTYPE User +#define ToRadio_payloadVariant_set_channel_MSGTYPE ChannelSettings extern const pb_msgdesc_t Position_msg; extern const pb_msgdesc_t Data_msg; @@ -721,13 +736,13 @@ extern const pb_msgdesc_t ToRadio_msg; #define SubPacket_size 275 #define MeshPacket_size 320 #define ChannelSettings_size 95 -#define RadioConfig_size 382 -#define RadioConfig_UserPreferences_size 282 +#define RadioConfig_size 405 +#define RadioConfig_UserPreferences_size 305 #define NodeInfo_size 132 #define MyNodeInfo_size 106 #define LogRecord_size 81 -#define FromRadio_size 391 -#define ToRadio_size 386 +#define FromRadio_size 414 +#define ToRadio_size 409 #ifdef __cplusplus } /* extern "C" */ diff --git a/src/mesh/generated/portnums.pb.h b/src/mesh/generated/portnums.pb.h index 15572ca17..2133ecaa7 100644 --- a/src/mesh/generated/portnums.pb.h +++ b/src/mesh/generated/portnums.pb.h @@ -20,6 +20,7 @@ typedef enum _PortNum { PortNum_IP_TUNNEL_APP = 33, PortNum_SERIAL_APP = 64, PortNum_STORE_FORWARD_APP = 65, + PortNum_RANGE_TEST_APP = 66, PortNum_PRIVATE_APP = 256, PortNum_ATAK_FORWARDER = 257 } PortNum; From b29bcbbd4170416d937f0e299235b5c250063e4f Mon Sep 17 00:00:00 2001 From: Jm Date: Tue, 9 Feb 2021 21:59:00 -0800 Subject: [PATCH 069/258] #682 Exposing the actual radio center frequency to /static/report --- src/mesh/RadioInterface.cpp | 41 ++++++++++++++++++++++++++++---- src/mesh/RadioInterface.h | 23 ++++++++++++++++++ src/mesh/http/ContentHandler.cpp | 11 ++++++++- 3 files changed, 70 insertions(+), 5 deletions(-) diff --git a/src/mesh/RadioInterface.cpp b/src/mesh/RadioInterface.cpp index b1aa807bc..01f3f7911 100644 --- a/src/mesh/RadioInterface.cpp +++ b/src/mesh/RadioInterface.cpp @@ -209,6 +209,38 @@ unsigned long hash(const char *str) return hash; } +/** + * Save our frequency for later reuse. + */ +void RadioInterface::saveFreq(float freq) +{ + savedFreq = freq; +} + +/** + * Save our channel for later reuse. + */ +void RadioInterface::saveChannelNum(uint32_t channel_num) +{ + savedChannelNum = channel_num; +} + +/** + * Save our frequency for later reuse. + */ +float RadioInterface::getFreq() +{ + return savedFreq; +} + +/** + * Save our channel for later reuse. + */ +uint32_t RadioInterface::getChannelNum() +{ + return savedChannelNum; +} + /** * Pull our channel settings etc... from protobufs to the dumb interface settings */ @@ -261,18 +293,19 @@ void RadioInterface::applyModemConfig() assert(myRegion); // Should have been found in init // If user has manually specified a channel num, then use that, otherwise generate one by hashing the name - int channel_num = - (channelSettings.channel_num ? channelSettings.channel_num - 1 : hash(channelName)) % myRegion->numChannels; + int channel_num = (channelSettings.channel_num ? channelSettings.channel_num - 1 : hash(channelName)) % myRegion->numChannels; freq = myRegion->freq + myRegion->spacing * channel_num; - DEBUG_MSG("Set radio: name=%s, config=%u, ch=%d, power=%d\n", channelName, channelSettings.modem_config, channel_num, - power); + DEBUG_MSG("Set radio: name=%s, config=%u, ch=%d, power=%d\n", channelName, channelSettings.modem_config, channel_num, power); DEBUG_MSG("Radio myRegion->freq: %f\n", myRegion->freq); DEBUG_MSG("Radio myRegion->spacing: %f\n", myRegion->spacing); DEBUG_MSG("Radio myRegion->numChannels: %d\n", myRegion->numChannels); DEBUG_MSG("Radio channel_num: %d\n", channel_num); DEBUG_MSG("Radio frequency: %f\n", freq); DEBUG_MSG("Short packet time: %u msec\n", shortPacketMsec); + + saveChannelNum(channel_num); + saveFreq(freq); } /** diff --git a/src/mesh/RadioInterface.h b/src/mesh/RadioInterface.h index 0d8c7b9b7..1f4fb8457 100644 --- a/src/mesh/RadioInterface.h +++ b/src/mesh/RadioInterface.h @@ -133,9 +133,22 @@ class RadioInterface uint32_t getPacketTime(MeshPacket *p); uint32_t getPacketTime(uint32_t totalPacketLen); + /** + * Get the channel we saved. + */ + uint32_t getChannelNum(); + + /** + * Get the frequency we saved. + */ + float getFreq(); + protected: int8_t power = 17; // Set by applyModemConfig() + float savedFreq; + uint32_t savedChannelNum; + /*** * given a packet set sendingPacket and decode the protobufs into radiobuf. Returns # of bytes to send (including the * PacketHeader & payload). @@ -157,6 +170,16 @@ class RadioInterface */ virtual void applyModemConfig(); + /** + * Save the frequency we selected for later reuse. + */ + virtual void saveFreq(float savedFreq); + + /** + * Save the chanel we selected for later reuse. + */ + virtual void saveChannelNum(uint32_t savedChannelNum); + private: /// Return 0 if sleep is okay int preflightSleepCb(void *unused = NULL) { return canSleep() ? 0 : 1; } diff --git a/src/mesh/http/ContentHandler.cpp b/src/mesh/http/ContentHandler.cpp index 5f79702fc..8535dd349 100644 --- a/src/mesh/http/ContentHandler.cpp +++ b/src/mesh/http/ContentHandler.cpp @@ -11,6 +11,7 @@ #include #include #include +#include "RadioLibInterface.h" #ifndef NO_ESP32 #include "esp_task_wdt.h" @@ -928,10 +929,18 @@ void handleReport(HTTPRequest *req, HTTPResponse *res) res->printf("\"has_battery\": %s,\n", BoolToString(powerStatus->getHasBattery())); res->printf("\"has_usb\": %s,\n", BoolToString(powerStatus->getHasUSB())); res->printf("\"is_charging\": %s\n", BoolToString(powerStatus->getIsCharging())); - res->println("}"); + res->println("},"); + + res->println("\"radio\": {"); + res->printf("\"frequecy\": %f,\n", RadioLibInterface::instance->getFreq()); + res->printf("\"lora_channel\": %d\n", RadioLibInterface::instance->getChannelNum()); + res->println("},"); + res->println("},"); + + res->println("\"status\": \"ok\""); res->println("}"); } From fdfe62edf0fd3b6a580c818eda698dad902c7038 Mon Sep 17 00:00:00 2001 From: Kevin Hester Date: Wed, 10 Feb 2021 16:18:41 +0800 Subject: [PATCH 070/258] updates to work with new protobuf names --- proto | 2 +- src/graphics/Screen.cpp | 2 +- src/mesh/DSRRouter.cpp | 4 +-- src/mesh/MeshService.cpp | 2 +- src/mesh/NodeDB.cpp | 4 +-- src/mesh/PhoneAPI.cpp | 36 ++++++++++++------------ src/mesh/RadioInterface.cpp | 18 ++++++------ src/mesh/RadioLibInterface.cpp | 2 +- src/mesh/ReliableRouter.cpp | 4 +-- src/mesh/Router.cpp | 28 +++++++++---------- src/mesh/SinglePortPlugin.h | 2 +- src/mesh/StreamAPI.cpp | 4 +-- src/mesh/generated/mesh.pb.h | 50 +++++++++++++++++----------------- 13 files changed, 79 insertions(+), 79 deletions(-) diff --git a/proto b/proto index 259984106..a76ceb150 160000 --- a/proto +++ b/proto @@ -1 +1 @@ -Subproject commit 25998410668a1ff1b092512439ec0e7089f91ce9 +Subproject commit a76ceb1509b2ec3d844af0378e998e7d4737492c diff --git a/src/graphics/Screen.cpp b/src/graphics/Screen.cpp index 6f022943f..853cdc29c 100644 --- a/src/graphics/Screen.cpp +++ b/src/graphics/Screen.cpp @@ -201,7 +201,7 @@ static void drawTextMessageFrame(OLEDDisplay *display, OLEDDisplayUiState *state // the max length of this buffer is much longer than we can possibly print static char tempBuf[96]; - assert(mp.decoded.which_payload == SubPacket_data_tag); + assert(mp.decoded.which_payloadVariant == SubPacket_data_tag); snprintf(tempBuf, sizeof(tempBuf), " %s", mp.decoded.data.payload.bytes); display->drawStringMaxWidth(4 + x, 10 + y, SCREEN_WIDTH - (6 + x), tempBuf); diff --git a/src/mesh/DSRRouter.cpp b/src/mesh/DSRRouter.cpp index ad41afdde..8b1e6f67e 100644 --- a/src/mesh/DSRRouter.cpp +++ b/src/mesh/DSRRouter.cpp @@ -72,7 +72,7 @@ void DSRRouter::sniffReceived(const MeshPacket *p) addRoute(p->from, p->from, 0); // We are adjacent with zero hops } - switch (p->decoded.which_payload) { + switch (p->decoded.which_payloadVariant) { case SubPacket_route_request_tag: // Handle route discovery packets (will be a broadcast message) // FIXME - always start request with the senders nodenum @@ -139,7 +139,7 @@ void DSRRouter::sniffReceived(const MeshPacket *p) // handle naks - convert them to route error packets // All naks are generated locally, because we failed resending the packet too many times - PacketId nakId = p->decoded.which_ack == SubPacket_fail_id_tag ? p->decoded.ack.fail_id : 0; + PacketId nakId = p->decoded.which_ackVariant == SubPacket_fail_id_tag ? p->decoded.ackVariant.fail_id : 0; if (nakId) { auto pending = findPendingPacket(p->to, nakId); if (pending && pending->packet->decoded.source) { // if source not set, this was not a multihop packet, just ignore diff --git a/src/mesh/MeshService.cpp b/src/mesh/MeshService.cpp index 073c48144..1629b16e8 100644 --- a/src/mesh/MeshService.cpp +++ b/src/mesh/MeshService.cpp @@ -176,7 +176,7 @@ void MeshService::sendToMesh(MeshPacket *p) // Strip out any time information before sending packets to other nodes - to keep the wire size small (and because other // nodes shouldn't trust it anyways) Note: we allow a device with a local GPS to include the time, so that gpsless // devices can get time. - if (p->which_payload == MeshPacket_decoded_tag && p->decoded.which_payload == SubPacket_position_tag && + if (p->which_payloadVariant == MeshPacket_decoded_tag && p->decoded.which_payloadVariant == SubPacket_position_tag && p->decoded.position.time) { if (getRTCQuality() < RTCQualityGPS) { DEBUG_MSG("Stripping time %u from position send\n", p->decoded.position.time); diff --git a/src/mesh/NodeDB.cpp b/src/mesh/NodeDB.cpp index dc27276ab..18e07f561 100644 --- a/src/mesh/NodeDB.cpp +++ b/src/mesh/NodeDB.cpp @@ -525,7 +525,7 @@ void NodeDB::updateUser(uint32_t nodeId, const User &p) /// we updateGUI and updateGUIforNode if we think our this change is big enough for a redraw void NodeDB::updateFrom(const MeshPacket &mp) { - if (mp.which_payload == MeshPacket_decoded_tag) { + if (mp.which_payloadVariant == MeshPacket_decoded_tag) { const SubPacket &p = mp.decoded; DEBUG_MSG("Update DB node 0x%x, rx_time=%u\n", mp.from, mp.rx_time); @@ -538,7 +538,7 @@ void NodeDB::updateFrom(const MeshPacket &mp) info->snr = mp.rx_snr; // keep the most recent SNR we received for this node. - switch (p.which_payload) { + switch (p.which_payloadVariant) { case SubPacket_position_tag: { // handle a legacy position packet DEBUG_MSG("WARNING: Processing a (deprecated) position packet from %d\n", mp.from); diff --git a/src/mesh/PhoneAPI.cpp b/src/mesh/PhoneAPI.cpp index 48898f16b..fa10e20fa 100644 --- a/src/mesh/PhoneAPI.cpp +++ b/src/mesh/PhoneAPI.cpp @@ -59,15 +59,15 @@ void PhoneAPI::handleToRadio(const uint8_t *buf, size_t bufLength) // return (lastContactMsec != 0) && if (pb_decode_from_bytes(buf, bufLength, ToRadio_fields, &toRadioScratch)) { - switch (toRadioScratch.which_variant) { + switch (toRadioScratch.which_payloadVariant) { case ToRadio_packet_tag: { - MeshPacket &p = toRadioScratch.variant.packet; + MeshPacket &p = toRadioScratch.packet; printPacket("PACKET FROM PHONE", &p); service.handleToRadio(p); break; } case ToRadio_want_config_id_tag: - config_nonce = toRadioScratch.variant.want_config_id; + config_nonce = toRadioScratch.want_config_id; DEBUG_MSG("Client wants config, nonce=%u\n", config_nonce); state = STATE_SEND_MY_INFO; @@ -79,12 +79,12 @@ void PhoneAPI::handleToRadio(const uint8_t *buf, size_t bufLength) case ToRadio_set_owner_tag: DEBUG_MSG("Client is setting owner\n"); - handleSetOwner(toRadioScratch.variant.set_owner); + handleSetOwner(toRadioScratch.set_owner); break; case ToRadio_set_radio_tag: DEBUG_MSG("Client is setting radio\n"); - handleSetRadio(toRadioScratch.variant.set_radio); + handleSetRadio(toRadioScratch.set_radio); break; default: @@ -131,22 +131,22 @@ size_t PhoneAPI::getFromRadio(uint8_t *buf) myNodeInfo.has_gps = (radioConfig.preferences.location_share == LocationSharing_LocDisabled) ? true : (gps && gps->isConnected()); // Update with latest GPS connect info - fromRadioScratch.which_variant = FromRadio_my_info_tag; - fromRadioScratch.variant.my_info = myNodeInfo; + fromRadioScratch.which_payloadVariant = FromRadio_my_info_tag; + fromRadioScratch.my_info = myNodeInfo; state = STATE_SEND_RADIO; service.refreshMyNodeInfo(); // Update my NodeInfo because the client will be asking for it soon. break; case STATE_SEND_RADIO: - fromRadioScratch.which_variant = FromRadio_radio_tag; + fromRadioScratch.which_payloadVariant = FromRadio_radio_tag; - fromRadioScratch.variant.radio = radioConfig; + fromRadioScratch.radio = radioConfig; // 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). - fromRadioScratch.variant.radio.preferences.ls_secs = getPref_ls_secs(); + fromRadioScratch.radio.preferences.ls_secs = getPref_ls_secs(); state = STATE_SEND_NODEINFO; break; @@ -158,8 +158,8 @@ size_t PhoneAPI::getFromRadio(uint8_t *buf) if (info) { DEBUG_MSG("Sending nodeinfo: num=0x%x, lastseen=%u, id=%s, name=%s\n", info->num, info->position.time, info->user.id, info->user.long_name); - fromRadioScratch.which_variant = FromRadio_node_info_tag; - fromRadioScratch.variant.node_info = *info; + fromRadioScratch.which_payloadVariant = FromRadio_node_info_tag; + fromRadioScratch.node_info = *info; // Stay in current state until done sending nodeinfos } else { DEBUG_MSG("Done sending nodeinfos\n"); @@ -171,8 +171,8 @@ size_t PhoneAPI::getFromRadio(uint8_t *buf) } case STATE_SEND_COMPLETE_ID: - fromRadioScratch.which_variant = FromRadio_config_complete_id_tag; - fromRadioScratch.variant.config_complete_id = config_nonce; + fromRadioScratch.which_payloadVariant = FromRadio_config_complete_id_tag; + fromRadioScratch.config_complete_id = config_nonce; config_nonce = 0; state = STATE_SEND_PACKETS; break; @@ -185,8 +185,8 @@ size_t PhoneAPI::getFromRadio(uint8_t *buf) printPacket("phone downloaded packet", packetForPhone); // Encapsulate as a FromRadio packet - fromRadioScratch.which_variant = FromRadio_packet_tag; - fromRadioScratch.variant.packet = *packetForPhone; + fromRadioScratch.which_payloadVariant = FromRadio_packet_tag; + fromRadioScratch.packet = *packetForPhone; service.releaseToPool(packetForPhone); // we just copied the bytes, so don't need this buffer anymore packetForPhone = NULL; @@ -198,9 +198,9 @@ size_t PhoneAPI::getFromRadio(uint8_t *buf) } // Do we have a message from the mesh? - if (fromRadioScratch.which_variant != 0) { + if (fromRadioScratch.which_payloadVariant != 0) { // Encapsulate as a FromRadio packet - DEBUG_MSG("encoding toPhone packet to phone variant=%d", fromRadioScratch.which_variant); + DEBUG_MSG("encoding toPhone packet to phone variant=%d", fromRadioScratch.which_payloadVariant); size_t numbytes = pb_encode_to_bytes(buf, FromRadio_size, FromRadio_fields, &fromRadioScratch); DEBUG_MSG(", %d bytes\n", numbytes); return numbytes; diff --git a/src/mesh/RadioInterface.cpp b/src/mesh/RadioInterface.cpp index b1aa807bc..34e04298f 100644 --- a/src/mesh/RadioInterface.cpp +++ b/src/mesh/RadioInterface.cpp @@ -83,7 +83,7 @@ uint32_t RadioInterface::getPacketTime(uint32_t pl) uint32_t RadioInterface::getPacketTime(MeshPacket *p) { - assert(p->which_payload == MeshPacket_encrypted_tag); // It should have already been encoded by now + assert(p->which_payloadVariant == MeshPacket_encrypted_tag); // It should have already been encoded by now uint32_t pl = p->encrypted.size + sizeof(PacketHeader); return getPacketTime(pl); @@ -119,9 +119,9 @@ void printPacket(const char *prefix, const MeshPacket *p) { DEBUG_MSG("%s (id=0x%08x Fr0x%02x To0x%02x, WantAck%d, HopLim%d", prefix, p->id, p->from & 0xff, p->to & 0xff, p->want_ack, p->hop_limit); - if (p->which_payload == MeshPacket_decoded_tag) { + if (p->which_payloadVariant == MeshPacket_decoded_tag) { auto &s = p->decoded; - switch (s.which_payload) { + switch (s.which_payloadVariant) { case SubPacket_data_tag: DEBUG_MSG(" Portnum=%d", s.data.portnum); break; @@ -135,7 +135,7 @@ void printPacket(const char *prefix, const MeshPacket *p) DEBUG_MSG(" Payload:None"); break; default: - DEBUG_MSG(" Payload:%d", s.which_payload); + DEBUG_MSG(" Payload:%d", s.which_payloadVariant); break; } if (s.want_response) @@ -147,10 +147,10 @@ void printPacket(const char *prefix, const MeshPacket *p) if (s.dest != 0) DEBUG_MSG(" dest=%08x", s.dest); - if (s.which_ack == SubPacket_success_id_tag) - DEBUG_MSG(" successId=%08x", s.ack.success_id); - else if (s.which_ack == SubPacket_fail_id_tag) - DEBUG_MSG(" failId=%08x", s.ack.fail_id); + if (s.which_ackVariant == SubPacket_success_id_tag) + DEBUG_MSG(" successId=%08x", s.ackVariant.success_id); + else if (s.which_ackVariant == SubPacket_fail_id_tag) + DEBUG_MSG(" failId=%08x", s.ackVariant.fail_id); } else { DEBUG_MSG(" encrypted"); } @@ -315,7 +315,7 @@ size_t RadioInterface::beginSending(MeshPacket *p) assert(!sendingPacket); // DEBUG_MSG("sending queued packet on mesh (txGood=%d,rxGood=%d,rxBad=%d)\n", rf95.txGood(), rf95.rxGood(), rf95.rxBad()); - assert(p->which_payload == MeshPacket_encrypted_tag); // It should have already been encoded by now + assert(p->which_payloadVariant == MeshPacket_encrypted_tag); // It should have already been encoded by now lastTxStart = millis(); diff --git a/src/mesh/RadioLibInterface.cpp b/src/mesh/RadioLibInterface.cpp index f2fafef76..27e767bf7 100644 --- a/src/mesh/RadioLibInterface.cpp +++ b/src/mesh/RadioLibInterface.cpp @@ -264,7 +264,7 @@ void RadioLibInterface::handleReceiveInterrupt() addReceiveMetadata(mp); - mp->which_payload = MeshPacket_encrypted_tag; // Mark that the payload is still encrypted at this point + mp->which_payloadVariant = MeshPacket_encrypted_tag; // Mark that the payload is still encrypted at this point assert(((uint32_t) payloadLen) <= sizeof(mp->encrypted.bytes)); memcpy(mp->encrypted.bytes, payload, payloadLen); mp->encrypted.size = payloadLen; diff --git a/src/mesh/ReliableRouter.cpp b/src/mesh/ReliableRouter.cpp index 6060b1f03..3bc8bfde5 100644 --- a/src/mesh/ReliableRouter.cpp +++ b/src/mesh/ReliableRouter.cpp @@ -65,8 +65,8 @@ void ReliableRouter::sniffReceived(const MeshPacket *p) // If the payload is valid, look for ack/nak - PacketId ackId = p->decoded.which_ack == SubPacket_success_id_tag ? p->decoded.ack.success_id : 0; - PacketId nakId = p->decoded.which_ack == SubPacket_fail_id_tag ? p->decoded.ack.fail_id : 0; + PacketId ackId = p->decoded.which_ackVariant == SubPacket_success_id_tag ? p->decoded.ackVariant.success_id : 0; + PacketId nakId = p->decoded.which_ackVariant == SubPacket_fail_id_tag ? p->decoded.ackVariant.fail_id : 0; // We intentionally don't check wasSeenRecently, because it is harmless to delete non existent retransmission records if (ackId || nakId) { diff --git a/src/mesh/Router.cpp b/src/mesh/Router.cpp index c3a345522..3ea6e9138 100644 --- a/src/mesh/Router.cpp +++ b/src/mesh/Router.cpp @@ -88,7 +88,7 @@ MeshPacket *Router::allocForSending() { MeshPacket *p = packetPool.allocZeroed(); - p->which_payload = MeshPacket_decoded_tag; // Assume payload is decoded at start. + p->which_payloadVariant = MeshPacket_decoded_tag; // Assume payload is decoded at start. p->from = nodeDB.getNodeNum(); p->to = NODENUM_BROADCAST; p->hop_limit = HOP_RELIABLE; @@ -110,14 +110,14 @@ void Router::sendAckNak(ErrorReason err, NodeNum to, PacketId idFrom) DEBUG_MSG("Sending an err=%d,to=0x%x,idFrom=0x%x,id=0x%x\n", err, to, idFrom, p->id); if (!err) { - p->decoded.ack.success_id = idFrom; - p->decoded.which_ack = SubPacket_success_id_tag; + p->decoded.ackVariant.success_id = idFrom; + p->decoded.which_ackVariant = SubPacket_success_id_tag; } else { - p->decoded.ack.fail_id = idFrom; - p->decoded.which_ack = SubPacket_fail_id_tag; + p->decoded.ackVariant.fail_id = idFrom; + p->decoded.which_ackVariant = SubPacket_fail_id_tag; // Also send back the error reason - p->decoded.which_payload = SubPacket_error_reason_tag; + p->decoded.which_payloadVariant = SubPacket_error_reason_tag; p->decoded.error_reason = err; } @@ -160,7 +160,7 @@ ErrorCode Router::send(MeshPacket *p) { assert(p->to != nodeDB.getNodeNum()); // should have already been handled by sendLocal - PacketId nakId = p->decoded.which_ack == SubPacket_fail_id_tag ? p->decoded.ack.fail_id : 0; + PacketId nakId = p->decoded.which_ackVariant == SubPacket_fail_id_tag ? p->decoded.ackVariant.fail_id : 0; assert( !nakId); // I don't think we ever send 0hop naks over the wire (other than to the phone), test that assumption with assert @@ -170,11 +170,11 @@ ErrorCode Router::send(MeshPacket *p) // If the packet hasn't yet been encrypted, do so now (it might already be encrypted if we are just forwarding it) - assert(p->which_payload == MeshPacket_encrypted_tag || - p->which_payload == MeshPacket_decoded_tag); // I _think_ all packets should have a payload by now + assert(p->which_payloadVariant == MeshPacket_encrypted_tag || + p->which_payloadVariant == MeshPacket_decoded_tag); // I _think_ all packets should have a payload by now // First convert from protobufs to raw bytes - if (p->which_payload == MeshPacket_decoded_tag) { + if (p->which_payloadVariant == MeshPacket_decoded_tag) { static uint8_t bytes[MAX_RHPACKETLEN]; // we have to use a scratch buffer because a union size_t numbytes = pb_encode_to_bytes(bytes, sizeof(bytes), SubPacket_fields, &p->decoded); @@ -185,7 +185,7 @@ ErrorCode Router::send(MeshPacket *p) // Copy back into the packet and set the variant type memcpy(p->encrypted.bytes, bytes, numbytes); p->encrypted.size = numbytes; - p->which_payload = MeshPacket_encrypted_tag; + p->which_payloadVariant = MeshPacket_encrypted_tag; } assert(iface); // This should have been detected already in sendLocal (or we just received a packet from outside) @@ -211,10 +211,10 @@ void Router::sniffReceived(const MeshPacket *p) bool Router::perhapsDecode(MeshPacket *p) { - if (p->which_payload == MeshPacket_decoded_tag) + if (p->which_payloadVariant == MeshPacket_decoded_tag) return true; // If packet was already decoded just return - assert(p->which_payload == MeshPacket_encrypted_tag); + assert(p->which_payloadVariant == MeshPacket_encrypted_tag); // FIXME - someday don't send routing packets encrypted. That would allow us to route for other channels without // being able to decrypt their data. @@ -230,7 +230,7 @@ bool Router::perhapsDecode(MeshPacket *p) return false; } else { // parsing was successful - p->which_payload = MeshPacket_decoded_tag; + p->which_payloadVariant = MeshPacket_decoded_tag; return true; } } diff --git a/src/mesh/SinglePortPlugin.h b/src/mesh/SinglePortPlugin.h index 01ee1963a..d182579b7 100644 --- a/src/mesh/SinglePortPlugin.h +++ b/src/mesh/SinglePortPlugin.h @@ -32,7 +32,7 @@ class SinglePortPlugin : public MeshPlugin { // Update our local node info with our position (even if we don't decide to update anyone else) MeshPacket *p = router->allocForSending(); - p->decoded.which_payload = SubPacket_data_tag; + p->decoded.which_payloadVariant = SubPacket_data_tag; p->decoded.data.portnum = ourPortNum; return p; diff --git a/src/mesh/StreamAPI.cpp b/src/mesh/StreamAPI.cpp index 06b80b2fa..8015b951b 100644 --- a/src/mesh/StreamAPI.cpp +++ b/src/mesh/StreamAPI.cpp @@ -84,8 +84,8 @@ void StreamAPI::emitRebooted() { // In case we send a FromRadio packet memset(&fromRadioScratch, 0, sizeof(fromRadioScratch)); - fromRadioScratch.which_variant = FromRadio_rebooted_tag; - fromRadioScratch.variant.rebooted = true; + fromRadioScratch.which_payloadVariant = FromRadio_rebooted_tag; + fromRadioScratch.rebooted = true; DEBUG_MSG("Emitting reboot packet for serial shell\n"); emitTxBuffer(pb_encode_to_bytes(txBuf + HEADER_LEN, FromRadio_size, FromRadio_fields, &fromRadioScratch)); diff --git a/src/mesh/generated/mesh.pb.h b/src/mesh/generated/mesh.pb.h index 5968850ab..b9de66a98 100644 --- a/src/mesh/generated/mesh.pb.h +++ b/src/mesh/generated/mesh.pb.h @@ -238,7 +238,7 @@ typedef struct _SubPacket { RouteDiscovery route_request; RouteDiscovery route_reply; ErrorReason error_reason; - } payloadVariant; + }; uint32_t original_id; bool want_response; uint32_t dest; @@ -258,7 +258,7 @@ typedef struct _MeshPacket { union { SubPacket decoded; MeshPacket_encrypted_t encrypted; - } payloadVariant; + }; uint32_t channel_index; uint32_t id; float rx_snr; @@ -279,7 +279,7 @@ typedef struct _FromRadio { uint32_t config_complete_id; bool rebooted; ChannelSettings channel; - } payloadVariant; + }; } FromRadio; typedef struct _ToRadio { @@ -290,7 +290,7 @@ typedef struct _ToRadio { RadioConfig set_radio; User set_owner; ChannelSettings set_channel; - } payloadVariant; + }; } ToRadio; @@ -524,12 +524,12 @@ X(a, STATIC, REPEATED, INT32, route, 2) #define RouteDiscovery_DEFAULT NULL #define SubPacket_FIELDLIST(X, a) \ -X(a, STATIC, ONEOF, MESSAGE, (payloadVariant,position,payloadVariant.position), 1) \ -X(a, STATIC, ONEOF, MESSAGE, (payloadVariant,data,payloadVariant.data), 3) \ -X(a, STATIC, ONEOF, MESSAGE, (payloadVariant,user,payloadVariant.user), 4) \ -X(a, STATIC, ONEOF, MESSAGE, (payloadVariant,route_request,payloadVariant.route_request), 6) \ -X(a, STATIC, ONEOF, MESSAGE, (payloadVariant,route_reply,payloadVariant.route_reply), 7) \ -X(a, STATIC, ONEOF, UENUM, (payloadVariant,error_reason,payloadVariant.error_reason), 13) \ +X(a, STATIC, ONEOF, MESSAGE, (payloadVariant,position,position), 1) \ +X(a, STATIC, ONEOF, MESSAGE, (payloadVariant,data,data), 3) \ +X(a, STATIC, ONEOF, MESSAGE, (payloadVariant,user,user), 4) \ +X(a, STATIC, ONEOF, MESSAGE, (payloadVariant,route_request,route_request), 6) \ +X(a, STATIC, ONEOF, MESSAGE, (payloadVariant,route_reply,route_reply), 7) \ +X(a, STATIC, ONEOF, UENUM, (payloadVariant,error_reason,error_reason), 13) \ X(a, STATIC, SINGULAR, UINT32, original_id, 2) \ X(a, STATIC, SINGULAR, BOOL, want_response, 5) \ X(a, STATIC, SINGULAR, UINT32, dest, 9) \ @@ -547,8 +547,8 @@ X(a, STATIC, SINGULAR, UINT32, source, 12) #define MeshPacket_FIELDLIST(X, a) \ X(a, STATIC, SINGULAR, UINT32, from, 1) \ X(a, STATIC, SINGULAR, UINT32, to, 2) \ -X(a, STATIC, ONEOF, MESSAGE, (payloadVariant,decoded,payloadVariant.decoded), 3) \ -X(a, STATIC, ONEOF, BYTES, (payloadVariant,encrypted,payloadVariant.encrypted), 8) \ +X(a, STATIC, ONEOF, MESSAGE, (payloadVariant,decoded,decoded), 3) \ +X(a, STATIC, ONEOF, BYTES, (payloadVariant,encrypted,encrypted), 8) \ X(a, STATIC, SINGULAR, UINT32, channel_index, 4) \ X(a, STATIC, SINGULAR, UINT32, id, 6) \ X(a, STATIC, SINGULAR, FLOAT, rx_snr, 7) \ @@ -667,14 +667,14 @@ X(a, STATIC, SINGULAR, UENUM, level, 4) #define FromRadio_FIELDLIST(X, a) \ X(a, STATIC, SINGULAR, UINT32, num, 1) \ -X(a, STATIC, ONEOF, MESSAGE, (payloadVariant,packet,payloadVariant.packet), 2) \ -X(a, STATIC, ONEOF, MESSAGE, (payloadVariant,my_info,payloadVariant.my_info), 3) \ -X(a, STATIC, ONEOF, MESSAGE, (payloadVariant,node_info,payloadVariant.node_info), 4) \ -X(a, STATIC, ONEOF, MESSAGE, (payloadVariant,radio,payloadVariant.radio), 6) \ -X(a, STATIC, ONEOF, MESSAGE, (payloadVariant,log_record,payloadVariant.log_record), 7) \ -X(a, STATIC, ONEOF, UINT32, (payloadVariant,config_complete_id,payloadVariant.config_complete_id), 8) \ -X(a, STATIC, ONEOF, BOOL, (payloadVariant,rebooted,payloadVariant.rebooted), 9) \ -X(a, STATIC, ONEOF, MESSAGE, (payloadVariant,channel,payloadVariant.channel), 10) +X(a, STATIC, ONEOF, MESSAGE, (payloadVariant,packet,packet), 2) \ +X(a, STATIC, ONEOF, MESSAGE, (payloadVariant,my_info,my_info), 3) \ +X(a, STATIC, ONEOF, MESSAGE, (payloadVariant,node_info,node_info), 4) \ +X(a, STATIC, ONEOF, MESSAGE, (payloadVariant,radio,radio), 6) \ +X(a, STATIC, ONEOF, MESSAGE, (payloadVariant,log_record,log_record), 7) \ +X(a, STATIC, ONEOF, UINT32, (payloadVariant,config_complete_id,config_complete_id), 8) \ +X(a, STATIC, ONEOF, BOOL, (payloadVariant,rebooted,rebooted), 9) \ +X(a, STATIC, ONEOF, MESSAGE, (payloadVariant,channel,channel), 10) #define FromRadio_CALLBACK NULL #define FromRadio_DEFAULT NULL #define FromRadio_payloadVariant_packet_MSGTYPE MeshPacket @@ -685,11 +685,11 @@ X(a, STATIC, ONEOF, MESSAGE, (payloadVariant,channel,payloadVariant.channe #define FromRadio_payloadVariant_channel_MSGTYPE ChannelSettings #define ToRadio_FIELDLIST(X, a) \ -X(a, STATIC, ONEOF, MESSAGE, (payloadVariant,packet,payloadVariant.packet), 1) \ -X(a, STATIC, ONEOF, UINT32, (payloadVariant,want_config_id,payloadVariant.want_config_id), 100) \ -X(a, STATIC, ONEOF, MESSAGE, (payloadVariant,set_radio,payloadVariant.set_radio), 101) \ -X(a, STATIC, ONEOF, MESSAGE, (payloadVariant,set_owner,payloadVariant.set_owner), 102) \ -X(a, STATIC, ONEOF, MESSAGE, (payloadVariant,set_channel,payloadVariant.set_channel), 103) +X(a, STATIC, ONEOF, MESSAGE, (payloadVariant,packet,packet), 1) \ +X(a, STATIC, ONEOF, UINT32, (payloadVariant,want_config_id,want_config_id), 100) \ +X(a, STATIC, ONEOF, MESSAGE, (payloadVariant,set_radio,set_radio), 101) \ +X(a, STATIC, ONEOF, MESSAGE, (payloadVariant,set_owner,set_owner), 102) \ +X(a, STATIC, ONEOF, MESSAGE, (payloadVariant,set_channel,set_channel), 103) #define ToRadio_CALLBACK NULL #define ToRadio_DEFAULT NULL #define ToRadio_payloadVariant_packet_MSGTYPE MeshPacket From 917090856f9b04330f7d07b8f2f827d43c5c3385 Mon Sep 17 00:00:00 2001 From: Kevin Hester Date: Thu, 11 Feb 2021 17:39:53 +0800 Subject: [PATCH 071/258] partial for #681: Never let stale nodeinfos/positions stay in xmit queue --- src/mesh/MeshService.cpp | 5 +++++ src/mesh/MeshService.h | 3 +++ src/mesh/RadioInterface.h | 3 +++ src/mesh/RadioLibInterface.cpp | 7 +++++++ src/mesh/RadioLibInterface.h | 3 +++ src/mesh/Router.cpp | 9 +++++++++ src/mesh/Router.h | 7 ++++++- src/plugins/NodeInfoPlugin.cpp | 7 ++++++- src/plugins/NodeInfoPlugin.h | 3 +++ src/plugins/PositionPlugin.cpp | 5 +++++ src/plugins/PositionPlugin.h | 3 +++ 11 files changed, 53 insertions(+), 2 deletions(-) diff --git a/src/mesh/MeshService.cpp b/src/mesh/MeshService.cpp index 1629b16e8..f3a3bd1aa 100644 --- a/src/mesh/MeshService.cpp +++ b/src/mesh/MeshService.cpp @@ -169,6 +169,11 @@ void MeshService::handleToRadio(MeshPacket &p) } } +/** Attempt to cancel a previously sent packet from this _local_ node. Returns true if a packet was found we could cancel */ +bool MeshService::cancelSending(PacketId id) { + return router->cancelSending(nodeDB.getNodeNum(), id); +} + void MeshService::sendToMesh(MeshPacket *p) { nodeDB.updateFrom(*p); // update our local DB for this packet (because phone might have sent position packets etc...) diff --git a/src/mesh/MeshService.h b/src/mesh/MeshService.h index 5c30339a0..8cba07710 100644 --- a/src/mesh/MeshService.h +++ b/src/mesh/MeshService.h @@ -79,6 +79,9 @@ class MeshService /// cache void sendToMesh(MeshPacket *p); + /** Attempt to cancel a previously sent packet from this _local_ node. Returns true if a packet was found we could cancel */ + bool cancelSending(PacketId id); + /// Pull the latest power and time info into my nodeinfo NodeInfo *refreshMyNodeInfo(); diff --git a/src/mesh/RadioInterface.h b/src/mesh/RadioInterface.h index 0d8c7b9b7..c49421d11 100644 --- a/src/mesh/RadioInterface.h +++ b/src/mesh/RadioInterface.h @@ -105,6 +105,9 @@ class RadioInterface */ virtual ErrorCode send(MeshPacket *p) = 0; + /** Attempt to cancel a previously sent packet. Returns true if a packet was found we could cancel */ + virtual bool cancelSending(NodeNum from, PacketId id) { return false; } + // methods from radiohead /// Initialise the Driver transport hardware and software. diff --git a/src/mesh/RadioLibInterface.cpp b/src/mesh/RadioLibInterface.cpp index 27e767bf7..744762c08 100644 --- a/src/mesh/RadioLibInterface.cpp +++ b/src/mesh/RadioLibInterface.cpp @@ -132,6 +132,13 @@ bool RadioLibInterface::canSleep() return res; } +/** Attempt to cancel a previously sent packet. Returns true if a packet was found we could cancel */ +bool RadioLibInterface::cancelSending(NodeNum from, PacketId id) { + assert(0); + return false; +} + + /** radio helper thread callback. We never immediately transmit after any operation (either rx or tx). Instead we should start receiving and diff --git a/src/mesh/RadioLibInterface.h b/src/mesh/RadioLibInterface.h index e762fdcdc..b002f49bc 100644 --- a/src/mesh/RadioLibInterface.h +++ b/src/mesh/RadioLibInterface.h @@ -136,6 +136,9 @@ class RadioLibInterface : public RadioInterface, protected concurrency::Notified */ virtual bool isActivelyReceiving() = 0; + /** Attempt to cancel a previously sent packet. Returns true if a packet was found we could cancel */ + virtual bool cancelSending(NodeNum from, PacketId id); + private: /** if we have something waiting to send, start a short random timer so we can come check for collision before actually doing * the transmit diff --git a/src/mesh/Router.cpp b/src/mesh/Router.cpp index 3ea6e9138..121d42a21 100644 --- a/src/mesh/Router.cpp +++ b/src/mesh/Router.cpp @@ -124,6 +124,8 @@ void Router::sendAckNak(ErrorReason err, NodeNum to, PacketId idFrom) sendLocal(p); // we sometimes send directly to the local node } + + ErrorCode Router::sendLocal(MeshPacket *p) { // No need to deliver externally if the destination is the local node @@ -199,6 +201,13 @@ ErrorCode Router::send(MeshPacket *p) } */ } +/** Attempt to cancel a previously sent packet. Returns true if a packet was found we could cancel */ +bool Router::cancelSending(NodeNum from, PacketId id) { + return iface ? iface->cancelSending(from, id) : false; +} + + + /** * Every (non duplicate) packet this node receives will be passed through this method. This allows subclasses to * update routing tables etc... based on what we overhear (even for messages not destined to our node) diff --git a/src/mesh/Router.h b/src/mesh/Router.h index dfc44dfa4..3951f3062 100644 --- a/src/mesh/Router.h +++ b/src/mesh/Router.h @@ -55,7 +55,12 @@ class Router : protected concurrency::OSThread */ ErrorCode sendLocal(MeshPacket *p); - /// Allocate and return a meshpacket which defaults as send to broadcast from the current node. + /** Attempt to cancel a previously sent packet. Returns true if a packet was found we could cancel */ + bool cancelSending(NodeNum from, PacketId id); + + /** Allocate and return a meshpacket which defaults as send to broadcast from the current node. + * The returned packet is guaranteed to have a unique packet ID already assigned + */ MeshPacket *allocForSending(); /** diff --git a/src/plugins/NodeInfoPlugin.cpp b/src/plugins/NodeInfoPlugin.cpp index 54aea4cc7..494387dd5 100644 --- a/src/plugins/NodeInfoPlugin.cpp +++ b/src/plugins/NodeInfoPlugin.cpp @@ -28,10 +28,15 @@ bool NodeInfoPlugin::handleReceivedProtobuf(const MeshPacket &mp, const User &p) void NodeInfoPlugin::sendOurNodeInfo(NodeNum dest, bool wantReplies) { + // cancel any not yet sent (now stale) position packets + if(prevPacketId) // if we wrap around to zero, we'll simply fail to cancel in that rare case (no big deal) + service.cancelSending(prevPacketId); + MeshPacket *p = allocReply(); p->to = dest; p->decoded.want_response = wantReplies; - + prevPacketId = p->id; + service.sendToMesh(p); } diff --git a/src/plugins/NodeInfoPlugin.h b/src/plugins/NodeInfoPlugin.h index aabeb0059..8b01ea25e 100644 --- a/src/plugins/NodeInfoPlugin.h +++ b/src/plugins/NodeInfoPlugin.h @@ -6,6 +6,9 @@ */ class NodeInfoPlugin : public ProtobufPlugin { + /// The id of the last packet we sent, to allow us to cancel it if we make something fresher + PacketId prevPacketId = 0; + public: /** Constructor * name is for debugging output diff --git a/src/plugins/PositionPlugin.cpp b/src/plugins/PositionPlugin.cpp index f9f86bf68..ab89eddc1 100644 --- a/src/plugins/PositionPlugin.cpp +++ b/src/plugins/PositionPlugin.cpp @@ -37,9 +37,14 @@ MeshPacket *PositionPlugin::allocReply() void PositionPlugin::sendOurPosition(NodeNum dest, bool wantReplies) { + // cancel any not yet sent (now stale) position packets + if(prevPacketId) // if we wrap around to zero, we'll simply fail to cancel in that rare case (no big deal) + service.cancelSending(prevPacketId); + MeshPacket *p = allocReply(); p->to = dest; p->decoded.want_response = wantReplies; + prevPacketId = p->id; service.sendToMesh(p); } diff --git a/src/plugins/PositionPlugin.h b/src/plugins/PositionPlugin.h index 6a1eb05f0..9ca2d2082 100644 --- a/src/plugins/PositionPlugin.h +++ b/src/plugins/PositionPlugin.h @@ -6,6 +6,9 @@ */ class PositionPlugin : public ProtobufPlugin { + /// The id of the last packet we sent, to allow us to cancel it if we make something fresher + PacketId prevPacketId = 0; + public: /** Constructor * name is for debugging output From 2ff5046dcd09f360ad61c95d8c1d4cde309c1651 Mon Sep 17 00:00:00 2001 From: Kevin Hester Date: Thu, 11 Feb 2021 19:00:17 +0800 Subject: [PATCH 072/258] for #681, add MeshPacketQueue (a priority queue) to ensure acks get sent quickly --- proto | 2 +- src/mesh/MeshPacketQueue.cpp | 79 ++++++++++++++++++++++++++++++ src/mesh/MeshPacketQueue.h | 33 +++++++++++++ src/mesh/RadioInterface.cpp | 3 ++ src/mesh/RadioLibInterface.cpp | 19 ++++--- src/mesh/RadioLibInterface.h | 5 +- src/mesh/Router.cpp | 1 + src/mesh/generated/deviceonly.pb.h | 2 +- src/mesh/generated/mesh.pb.c | 1 + src/mesh/generated/mesh.pb.h | 24 +++++++-- src/plugins/NodeInfoPlugin.cpp | 3 +- src/plugins/PositionPlugin.cpp | 3 +- 12 files changed, 158 insertions(+), 17 deletions(-) create mode 100644 src/mesh/MeshPacketQueue.cpp create mode 100644 src/mesh/MeshPacketQueue.h diff --git a/proto b/proto index a76ceb150..0221e83d6 160000 --- a/proto +++ b/proto @@ -1 +1 @@ -Subproject commit a76ceb1509b2ec3d844af0378e998e7d4737492c +Subproject commit 0221e83d689f7930ed3e5c474eff4fbb8697efbb diff --git a/src/mesh/MeshPacketQueue.cpp b/src/mesh/MeshPacketQueue.cpp new file mode 100644 index 000000000..7d3d2aa2b --- /dev/null +++ b/src/mesh/MeshPacketQueue.cpp @@ -0,0 +1,79 @@ +#include "MeshPacketQueue.h" + +/// @return the priority of the specified packet +inline uint32_t getPriority(MeshPacket *p) +{ + auto pri = p->priority; + return pri; +} + +/// @return "true" if "p1" is ordered before "p2" +bool CompareMeshPacket::operator()(MeshPacket *p1, MeshPacket *p2) +{ + assert(p1 && p2); + auto p1p = getPriority(p1), p2p = getPriority(p2); + + // If priorities differ, use that + // for equal priorities, order by id (older packets have higher priority - this will briefly be wrong when IDs roll over but + // no big deal) + return (p1p != p2p) ? (p1p < p2p) // prefer bigger priorities + : (p1->id >= p2->id); // prefer smaller packet ids +} + +MeshPacketQueue::MeshPacketQueue(size_t _maxLen) : maxLen(_maxLen) +{ +} + +/** enqueue a packet, return false if full */ +bool MeshPacketQueue::enqueue(MeshPacket *p) +{ + + // We might receive acks from other nodes (and since generated remotely, they won't have priority assigned. Check for that + // and fix it + if (p->priority == MeshPacket_Priority_UNSET) + p->priority = p->decoded.which_ackVariant ? MeshPacket_Priority_ACK : MeshPacket_Priority_DEFAULT; + + if (size() >= maxLen) + return false; + else { + push(p); + return true; + } +} + +MeshPacket *MeshPacketQueue::dequeue() +{ + if (empty()) + return NULL; + else { + auto p = top(); + pop(); // remove the first item + return p; + } +} + +// this is kinda yucky, but I'm not sure if all arduino c++ compilers support closuers. And we only have one +// thread that can run at a time - so safe +static NodeNum findFrom; +static PacketId findId; + +static bool isMyPacket(MeshPacket *p) +{ + return p->id == findId && p->from == findFrom; +} + +/** Attempt to find and remove a packet from this queue. Returns true the packet which was removed from the queue */ +MeshPacket *MeshPacketQueue::remove(NodeNum from, PacketId id) +{ + findFrom = from; + findId = id; + auto it = std::find_if(this->c.begin(), this->c.end(), isMyPacket); + if (it != this->c.end()) { + auto p = *it; + this->c.erase(it); + std::make_heap(this->c.begin(), this->c.end(), this->comp); + return p; + } else { + return NULL; + } +} diff --git a/src/mesh/MeshPacketQueue.h b/src/mesh/MeshPacketQueue.h new file mode 100644 index 000000000..f04649cb5 --- /dev/null +++ b/src/mesh/MeshPacketQueue.h @@ -0,0 +1,33 @@ +#pragma once + +#include "MeshTypes.h" + +#include +#include + +// this is an strucure which implements the +// operator overloading +struct CompareMeshPacket { + bool operator()(MeshPacket *p1, MeshPacket *p2); +}; + +/** + * A priority queue of packets. + * + */ +class MeshPacketQueue : public std::priority_queue, CompareMeshPacket> +{ + size_t maxLen; + public: + MeshPacketQueue(size_t _maxLen); + + /** enqueue a packet, return false if full */ + bool enqueue(MeshPacket *p); + + // bool isEmpty(); + + MeshPacket *dequeue(); + + /** Attempt to find and remove a packet from this queue. Returns true the packet which was removed from the queue */ + MeshPacket *remove(NodeNum from, PacketId id); +}; \ No newline at end of file diff --git a/src/mesh/RadioInterface.cpp b/src/mesh/RadioInterface.cpp index 34e04298f..972e67678 100644 --- a/src/mesh/RadioInterface.cpp +++ b/src/mesh/RadioInterface.cpp @@ -161,6 +161,9 @@ void printPacket(const char *prefix, const MeshPacket *p) if (p->rx_snr != 0.0) { DEBUG_MSG(" rxSNR=%g", p->rx_snr); } + if(p->priority != 0) + DEBUG_MSG(" priority=%d", p->priority); + DEBUG_MSG(")\n"); } diff --git a/src/mesh/RadioLibInterface.cpp b/src/mesh/RadioLibInterface.cpp index 744762c08..84fd37ee6 100644 --- a/src/mesh/RadioLibInterface.cpp +++ b/src/mesh/RadioLibInterface.cpp @@ -100,7 +100,7 @@ ErrorCode RadioLibInterface::send(MeshPacket *p) uint32_t xmitMsec = getPacketTime(p); DEBUG_MSG("txGood=%d,rxGood=%d,rxBad=%d\n", txGood, rxGood, rxBad); - ErrorCode res = txQueue.enqueue(p, 0) ? ERRNO_OK : ERRNO_UNKNOWN; + ErrorCode res = txQueue.enqueue(p) ? ERRNO_OK : ERRNO_UNKNOWN; if (res != ERRNO_OK) { // we weren't able to queue it, so we must drop it to prevent leaks packetPool.release(p); @@ -125,7 +125,7 @@ ErrorCode RadioLibInterface::send(MeshPacket *p) bool RadioLibInterface::canSleep() { - bool res = txQueue.isEmpty(); + bool res = txQueue.empty(); if (!res) // only print debug messages if we are vetoing sleep DEBUG_MSG("radio wait to sleep, txEmpty=%d\n", res); @@ -134,8 +134,13 @@ bool RadioLibInterface::canSleep() /** Attempt to cancel a previously sent packet. Returns true if a packet was found we could cancel */ bool RadioLibInterface::cancelSending(NodeNum from, PacketId id) { - assert(0); - return false; + auto p = txQueue.remove(from, id); + if(p) + packetPool.release(p); // free the packet we just removed + + bool result = (p != NULL); + DEBUG_MSG("cancelSending id=0x%x, removed=%d", id, result); + return result; } @@ -172,12 +177,12 @@ void RadioLibInterface::onNotify(uint32_t notification) // If we are not currently in receive mode, then restart the timer and try again later (this can happen if the main thread // has placed the unit into standby) FIXME, how will this work if the chipset is in sleep mode? - if (!txQueue.isEmpty()) { + if (!txQueue.empty()) { if (!canSendImmediately()) { startTransmitTimer(); // try again in a little while } else { // Send any outgoing packets we have ready - MeshPacket *txp = txQueue.dequeuePtr(0); + MeshPacket *txp = txQueue.dequeue(); assert(txp); startSend(txp); } @@ -193,7 +198,7 @@ void RadioLibInterface::onNotify(uint32_t notification) void RadioLibInterface::startTransmitTimer(bool withDelay) { // If we have work to do and the timer wasn't already scheduled, schedule it now - if (!txQueue.isEmpty()) { + if (!txQueue.empty()) { uint32_t delay = !withDelay ? 1 : getTxDelayMsec(); // DEBUG_MSG("xmit timer %d\n", delay); notifyLater(delay, TRANSMIT_DELAY_COMPLETED, false); // This will implicitly enable diff --git a/src/mesh/RadioLibInterface.h b/src/mesh/RadioLibInterface.h index b002f49bc..726e81b37 100644 --- a/src/mesh/RadioLibInterface.h +++ b/src/mesh/RadioLibInterface.h @@ -2,6 +2,7 @@ #include "../concurrency/OSThread.h" #include "RadioInterface.h" +#include "MeshPacketQueue.h" #ifdef CubeCell_BoardPlus #define RADIOLIB_SOFTWARE_SERIAL_UNSUPPORTED @@ -74,7 +75,7 @@ class RadioLibInterface : public RadioInterface, protected concurrency::Notified */ uint32_t rxBad = 0, rxGood = 0, txGood = 0; - PointerQueue txQueue = PointerQueue(MAX_TX_QUEUE); + MeshPacketQueue txQueue = MeshPacketQueue(MAX_TX_QUEUE); protected: @@ -138,7 +139,7 @@ class RadioLibInterface : public RadioInterface, protected concurrency::Notified /** Attempt to cancel a previously sent packet. Returns true if a packet was found we could cancel */ virtual bool cancelSending(NodeNum from, PacketId id); - + private: /** if we have something waiting to send, start a short random timer so we can come check for collision before actually doing * the transmit diff --git a/src/mesh/Router.cpp b/src/mesh/Router.cpp index 121d42a21..43d939c31 100644 --- a/src/mesh/Router.cpp +++ b/src/mesh/Router.cpp @@ -120,6 +120,7 @@ void Router::sendAckNak(ErrorReason err, NodeNum to, PacketId idFrom) p->decoded.which_payloadVariant = SubPacket_error_reason_tag; p->decoded.error_reason = err; } + p->priority = MeshPacket_Priority_ACK; sendLocal(p); // we sometimes send directly to the local node } diff --git a/src/mesh/generated/deviceonly.pb.h b/src/mesh/generated/deviceonly.pb.h index fb503be49..ad6b31738 100644 --- a/src/mesh/generated/deviceonly.pb.h +++ b/src/mesh/generated/deviceonly.pb.h @@ -80,7 +80,7 @@ extern const pb_msgdesc_t DeviceState_msg; #define DeviceState_fields &DeviceState_msg /* Maximum encoded size of messages (where known) */ -#define DeviceState_size 6262 +#define DeviceState_size 6266 #ifdef __cplusplus } /* extern "C" */ diff --git a/src/mesh/generated/mesh.pb.c b/src/mesh/generated/mesh.pb.c index 3bc2b0800..0bf5fbe38 100644 --- a/src/mesh/generated/mesh.pb.c +++ b/src/mesh/generated/mesh.pb.c @@ -58,3 +58,4 @@ PB_BIND(ToRadio, ToRadio, 2) + diff --git a/src/mesh/generated/mesh.pb.h b/src/mesh/generated/mesh.pb.h index b9de66a98..7dd097cef 100644 --- a/src/mesh/generated/mesh.pb.h +++ b/src/mesh/generated/mesh.pb.h @@ -83,6 +83,15 @@ typedef enum _CriticalErrorCode { CriticalErrorCode_TransmitFailed = 8 } CriticalErrorCode; +typedef enum _MeshPacket_Priority { + MeshPacket_Priority_UNSET = 0, + MeshPacket_Priority_MIN = 1, + MeshPacket_Priority_BACKGROUND = 10, + MeshPacket_Priority_DEFAULT = 64, + MeshPacket_Priority_ACK = 120, + MeshPacket_Priority_MAX = 127 +} MeshPacket_Priority; + typedef enum _ChannelSettings_ModemConfig { ChannelSettings_ModemConfig_Bw125Cr45Sf128 = 0, ChannelSettings_ModemConfig_Bw500Cr45Sf128 = 1, @@ -265,6 +274,7 @@ typedef struct _MeshPacket { uint32_t rx_time; uint32_t hop_limit; bool want_ack; + MeshPacket_Priority priority; } MeshPacket; typedef struct _FromRadio { @@ -323,6 +333,10 @@ typedef struct _ToRadio { #define _CriticalErrorCode_MAX CriticalErrorCode_TransmitFailed #define _CriticalErrorCode_ARRAYSIZE ((CriticalErrorCode)(CriticalErrorCode_TransmitFailed+1)) +#define _MeshPacket_Priority_MIN MeshPacket_Priority_UNSET +#define _MeshPacket_Priority_MAX MeshPacket_Priority_MAX +#define _MeshPacket_Priority_ARRAYSIZE ((MeshPacket_Priority)(MeshPacket_Priority_MAX+1)) + #define _ChannelSettings_ModemConfig_MIN ChannelSettings_ModemConfig_Bw125Cr45Sf128 #define _ChannelSettings_ModemConfig_MAX ChannelSettings_ModemConfig_Bw125Cr48Sf4096 #define _ChannelSettings_ModemConfig_ARRAYSIZE ((ChannelSettings_ModemConfig)(ChannelSettings_ModemConfig_Bw125Cr48Sf4096+1)) @@ -342,7 +356,7 @@ extern "C" { #define User_init_default {"", "", "", {0}} #define RouteDiscovery_init_default {0, {0, 0, 0, 0, 0, 0, 0, 0}} #define SubPacket_init_default {0, {Position_init_default}, 0, 0, 0, 0, {0}, 0} -#define MeshPacket_init_default {0, 0, 0, {SubPacket_init_default}, 0, 0, 0, 0, 0, 0} +#define MeshPacket_init_default {0, 0, 0, {SubPacket_init_default}, 0, 0, 0, 0, 0, 0, _MeshPacket_Priority_MIN} #define ChannelSettings_init_default {0, _ChannelSettings_ModemConfig_MIN, {0, {0}}, "", 0, 0, 0, 0, 0, 0, 0} #define RadioConfig_init_default {false, RadioConfig_UserPreferences_init_default, false, ChannelSettings_init_default} #define RadioConfig_UserPreferences_init_default {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, "", "", 0, _RegionCode_MIN, _ChargeCurrent_MIN, _LocationSharing_MIN, _GpsOperation_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} @@ -356,7 +370,7 @@ extern "C" { #define User_init_zero {"", "", "", {0}} #define RouteDiscovery_init_zero {0, {0, 0, 0, 0, 0, 0, 0, 0}} #define SubPacket_init_zero {0, {Position_init_zero}, 0, 0, 0, 0, {0}, 0} -#define MeshPacket_init_zero {0, 0, 0, {SubPacket_init_zero}, 0, 0, 0, 0, 0, 0} +#define MeshPacket_init_zero {0, 0, 0, {SubPacket_init_zero}, 0, 0, 0, 0, 0, 0, _MeshPacket_Priority_MIN} #define ChannelSettings_init_zero {0, _ChannelSettings_ModemConfig_MIN, {0, {0}}, "", 0, 0, 0, 0, 0, 0, 0} #define RadioConfig_init_zero {false, RadioConfig_UserPreferences_init_zero, false, ChannelSettings_init_zero} #define RadioConfig_UserPreferences_init_zero {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, "", "", 0, _RegionCode_MIN, _ChargeCurrent_MIN, _LocationSharing_MIN, _GpsOperation_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} @@ -479,6 +493,7 @@ extern "C" { #define MeshPacket_rx_time_tag 9 #define MeshPacket_hop_limit_tag 10 #define MeshPacket_want_ack_tag 11 +#define MeshPacket_priority_tag 12 #define FromRadio_num_tag 1 #define FromRadio_packet_tag 2 #define FromRadio_my_info_tag 3 @@ -554,7 +569,8 @@ X(a, STATIC, SINGULAR, UINT32, id, 6) \ X(a, STATIC, SINGULAR, FLOAT, rx_snr, 7) \ X(a, STATIC, SINGULAR, FIXED32, rx_time, 9) \ X(a, STATIC, SINGULAR, UINT32, hop_limit, 10) \ -X(a, STATIC, SINGULAR, BOOL, want_ack, 11) +X(a, STATIC, SINGULAR, BOOL, want_ack, 11) \ +X(a, STATIC, SINGULAR, UENUM, priority, 12) #define MeshPacket_CALLBACK NULL #define MeshPacket_DEFAULT NULL #define MeshPacket_payloadVariant_decoded_MSGTYPE SubPacket @@ -734,7 +750,7 @@ extern const pb_msgdesc_t ToRadio_msg; #define User_size 72 #define RouteDiscovery_size 88 #define SubPacket_size 275 -#define MeshPacket_size 320 +#define MeshPacket_size 322 #define ChannelSettings_size 95 #define RadioConfig_size 405 #define RadioConfig_UserPreferences_size 305 diff --git a/src/plugins/NodeInfoPlugin.cpp b/src/plugins/NodeInfoPlugin.cpp index 494387dd5..6c236ed34 100644 --- a/src/plugins/NodeInfoPlugin.cpp +++ b/src/plugins/NodeInfoPlugin.cpp @@ -35,8 +35,9 @@ void NodeInfoPlugin::sendOurNodeInfo(NodeNum dest, bool wantReplies) MeshPacket *p = allocReply(); p->to = dest; p->decoded.want_response = wantReplies; + p->priority = MeshPacket_Priority_BACKGROUND; prevPacketId = p->id; - + service.sendToMesh(p); } diff --git a/src/plugins/PositionPlugin.cpp b/src/plugins/PositionPlugin.cpp index ab89eddc1..4ea7298e6 100644 --- a/src/plugins/PositionPlugin.cpp +++ b/src/plugins/PositionPlugin.cpp @@ -40,10 +40,11 @@ void PositionPlugin::sendOurPosition(NodeNum dest, bool wantReplies) // cancel any not yet sent (now stale) position packets if(prevPacketId) // if we wrap around to zero, we'll simply fail to cancel in that rare case (no big deal) service.cancelSending(prevPacketId); - + MeshPacket *p = allocReply(); p->to = dest; p->decoded.want_response = wantReplies; + p->priority = MeshPacket_Priority_BACKGROUND; prevPacketId = p->id; service.sendToMesh(p); From f2b7ff2b7902e1dcd58c3186b028f60b5c380015 Mon Sep 17 00:00:00 2001 From: Kevin Hester Date: Fri, 12 Feb 2021 09:40:20 +0800 Subject: [PATCH 073/258] an optimization for #681 - make want_ack packets higher priority --- proto | 2 +- src/mesh/MeshPacketQueue.cpp | 20 +++++++++++++++----- src/mesh/generated/mesh.pb.h | 1 + 3 files changed, 17 insertions(+), 6 deletions(-) diff --git a/proto b/proto index 0221e83d6..b1aed0644 160000 --- a/proto +++ b/proto @@ -1 +1 @@ -Subproject commit 0221e83d689f7930ed3e5c474eff4fbb8697efbb +Subproject commit b1aed06442025624841b2288fac273d9bc41c438 diff --git a/src/mesh/MeshPacketQueue.cpp b/src/mesh/MeshPacketQueue.cpp index 7d3d2aa2b..2c542c7c4 100644 --- a/src/mesh/MeshPacketQueue.cpp +++ b/src/mesh/MeshPacketQueue.cpp @@ -20,19 +20,29 @@ bool CompareMeshPacket::operator()(MeshPacket *p1, MeshPacket *p2) : (p1->id >= p2->id); // prefer smaller packet ids } -MeshPacketQueue::MeshPacketQueue(size_t _maxLen) : maxLen(_maxLen) +MeshPacketQueue::MeshPacketQueue(size_t _maxLen) : maxLen(_maxLen) {} + +/** Some clients might not properly set priority, therefore we fix it here. + */ +void fixPriority(MeshPacket *p) { + // We might receive acks from other nodes (and since generated remotely, they won't have priority assigned. Check for that + // and fix it + if (p->priority == MeshPacket_Priority_UNSET) { + // if acks give high priority + // if a reliable message give a bit higher default priority + p->priority = p->decoded.which_ackVariant ? MeshPacket_Priority_ACK : + (p->want_ack ? MeshPacket_Priority_RELIABLE : MeshPacket_Priority_DEFAULT); + } } /** enqueue a packet, return false if full */ bool MeshPacketQueue::enqueue(MeshPacket *p) { - // We might receive acks from other nodes (and since generated remotely, they won't have priority assigned. Check for that - // and fix it - if (p->priority == MeshPacket_Priority_UNSET) - p->priority = p->decoded.which_ackVariant ? MeshPacket_Priority_ACK : MeshPacket_Priority_DEFAULT; + fixPriority(p); + // fixme if there is something lower priority in the queue that can be deleted to make space, delete that instead if (size() >= maxLen) return false; else { diff --git a/src/mesh/generated/mesh.pb.h b/src/mesh/generated/mesh.pb.h index 7dd097cef..397a313ea 100644 --- a/src/mesh/generated/mesh.pb.h +++ b/src/mesh/generated/mesh.pb.h @@ -88,6 +88,7 @@ typedef enum _MeshPacket_Priority { MeshPacket_Priority_MIN = 1, MeshPacket_Priority_BACKGROUND = 10, MeshPacket_Priority_DEFAULT = 64, + MeshPacket_Priority_RELIABLE = 70, MeshPacket_Priority_ACK = 120, MeshPacket_Priority_MAX = 127 } MeshPacket_Priority; From 16d63bd0ce82d96fee1e334629673f0935e0f4fe Mon Sep 17 00:00:00 2001 From: Kevin Hester Date: Fri, 12 Feb 2021 09:42:04 +0800 Subject: [PATCH 074/258] 1.1.46 --- version.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version.properties b/version.properties index 5ff3c45fa..98083da23 100644 --- a/version.properties +++ b/version.properties @@ -1,4 +1,4 @@ [VERSION] major = 1 minor = 1 -build = 42 +build = 46 From 9d81511153fefe79be2ae65f8efae11a98e6b488 Mon Sep 17 00:00:00 2001 From: Kevin Hester Date: Fri, 12 Feb 2021 09:56:35 +0800 Subject: [PATCH 075/258] fix warning --- src/mesh/NodeDB.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mesh/NodeDB.cpp b/src/mesh/NodeDB.cpp index 18e07f561..b8f0b5697 100644 --- a/src/mesh/NodeDB.cpp +++ b/src/mesh/NodeDB.cpp @@ -600,7 +600,7 @@ void recordCriticalError(CriticalErrorCode code, uint32_t address) // Print error to screen and serial port String lcd = String("Critical error ") + code + "!\n"; screen->print(lcd.c_str()); - DEBUG_MSG("NOTE! Recording critical error %d, address=%x\n", code, address); + DEBUG_MSG("NOTE! Recording critical error %d, address=%lx\n", code, address); // Record error to DB myNodeInfo.error_code = code; From bbc8fc0269405896c7d11fbfb77f83b71d43d39f Mon Sep 17 00:00:00 2001 From: Kevin Hester Date: Fri, 12 Feb 2021 09:56:42 +0800 Subject: [PATCH 076/258] fix build for nrf52 --- src/mesh/MeshPacketQueue.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/mesh/MeshPacketQueue.cpp b/src/mesh/MeshPacketQueue.cpp index 2c542c7c4..363e83ba7 100644 --- a/src/mesh/MeshPacketQueue.cpp +++ b/src/mesh/MeshPacketQueue.cpp @@ -1,5 +1,7 @@ #include "MeshPacketQueue.h" +#include + /// @return the priority of the specified packet inline uint32_t getPriority(MeshPacket *p) { From 8c225a3c653f94de9e22986d8c1e9d52c4284add Mon Sep 17 00:00:00 2001 From: Kevin Hester Date: Fri, 12 Feb 2021 13:48:12 +0800 Subject: [PATCH 077/258] disable lora while updating, show "Updating" on oled screen --- proto | 2 +- src/commands.h | 1 + src/esp32/BluetoothSoftwareUpdate.cpp | 5 ++- src/graphics/Screen.cpp | 29 ++++++++++++++++ src/graphics/Screen.h | 9 +++++ src/mesh/MeshTypes.h | 1 + src/mesh/RadioInterface.h | 5 +++ src/mesh/RadioLibInterface.cpp | 49 ++++++++++++++++----------- 8 files changed, 79 insertions(+), 22 deletions(-) diff --git a/proto b/proto index b1aed0644..0cadaed39 160000 --- a/proto +++ b/proto @@ -1 +1 @@ -Subproject commit b1aed06442025624841b2288fac273d9bc41c438 +Subproject commit 0cadaed3953f66cf1edc99d0fa53e4fd5ebf56d6 diff --git a/src/commands.h b/src/commands.h index c9d519dee..803ea2b55 100644 --- a/src/commands.h +++ b/src/commands.h @@ -9,6 +9,7 @@ enum class Cmd { SET_OFF, ON_PRESS, START_BLUETOOTH_PIN_SCREEN, + START_FIRMWARE_UPDATE_SCREEN, STOP_BLUETOOTH_PIN_SCREEN, STOP_BOOT_SCREEN, PRINT, diff --git a/src/esp32/BluetoothSoftwareUpdate.cpp b/src/esp32/BluetoothSoftwareUpdate.cpp index 03e156b0b..33707c57a 100644 --- a/src/esp32/BluetoothSoftwareUpdate.cpp +++ b/src/esp32/BluetoothSoftwareUpdate.cpp @@ -7,6 +7,8 @@ #include "configuration.h" #include "nimble/BluetoothUtil.h" #include "NodeDB.h" +#include "../graphics/Screen.h" +#include "../main.h" #include #include @@ -47,8 +49,9 @@ int update_size_callback(uint16_t conn_handle, uint16_t attr_handle, struct ble_ // void stopMeshBluetoothService(); // stopMeshBluetoothService(); + screen->startFirmwareUpdateScreen(); if (RadioLibInterface::instance) - RadioLibInterface::instance->sleep(); // FIXME, nasty hack - the RF95 ISR/SPI code on ESP32 can fail while we are + 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 } } diff --git a/src/graphics/Screen.cpp b/src/graphics/Screen.cpp index 853cdc29c..40ea25237 100644 --- a/src/graphics/Screen.cpp +++ b/src/graphics/Screen.cpp @@ -164,6 +164,20 @@ static void drawFrameBluetooth(OLEDDisplay *display, OLEDDisplayUiState *state, display->drawString(64 + x, 48 + y, buf); } +static void drawFrameFirmware(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y) +{ + display->setTextAlignment(TEXT_ALIGN_CENTER); + display->setFont(FONT_MEDIUM); + display->drawString(64 + x, y, "Updating"); + + display->setFont(FONT_SMALL); + 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 static void drawCriticalFaultFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y) { @@ -798,6 +812,9 @@ int32_t Screen::runOnce() case Cmd::START_BLUETOOTH_PIN_SCREEN: handleStartBluetoothPinScreen(cmd.bluetooth_pin); break; + case Cmd::START_FIRMWARE_UPDATE_SCREEN: + handleStartFirmwareUpdateScreen(); + break; case Cmd::STOP_BLUETOOTH_PIN_SCREEN: case Cmd::STOP_BOOT_SCREEN: setFrames(); @@ -928,6 +945,18 @@ void Screen::handleStartBluetoothPinScreen(uint32_t pin) setFastFramerate(); } +void Screen::handleStartFirmwareUpdateScreen() +{ + DEBUG_MSG("showing firmware screen\n"); + showingNormalScreen = false; + + static FrameCallback btFrames[] = {drawFrameFirmware}; + + ui.disableAllIndicators(); + ui.setFrames(btFrames, 1); + setFastFramerate(); +} + void Screen::blink() { setFastFramerate(); diff --git a/src/graphics/Screen.h b/src/graphics/Screen.h index 888f31011..041da4865 100644 --- a/src/graphics/Screen.h +++ b/src/graphics/Screen.h @@ -128,6 +128,14 @@ class Screen : public concurrency::OSThread enqueueCmd(cmd); } + void startFirmwareUpdateScreen() + { + ScreenCmd cmd; + cmd.cmd = Cmd::START_FIRMWARE_UPDATE_SCREEN; + enqueueCmd(cmd); + } + + /// Stops showing the bluetooth PIN screen. void stopBluetoothPinScreen() { enqueueCmd(ScreenCmd{.cmd = Cmd::STOP_BLUETOOTH_PIN_SCREEN}); } @@ -233,6 +241,7 @@ class Screen : public concurrency::OSThread void handleOnPress(); void handleStartBluetoothPinScreen(uint32_t pin); void handlePrint(const char *text); + void handleStartFirmwareUpdateScreen(); /// Rebuilds our list of frames (screens) to default ones. void setFrames(); diff --git a/src/mesh/MeshTypes.h b/src/mesh/MeshTypes.h index 8fd098f43..69e782b12 100644 --- a/src/mesh/MeshTypes.h +++ b/src/mesh/MeshTypes.h @@ -13,6 +13,7 @@ typedef uint32_t PacketId; // A packet sequence number #define ERRNO_OK 0 #define ERRNO_NO_INTERFACES 33 #define ERRNO_UNKNOWN 32 // pick something that doesn't conflict with RH_ROUTER_ERROR_UNABLE_TO_DELIVER +#define ERRNO_DISABLED 34 // the itnerface is disabled /** * the max number of hops a message can pass through, used as the default max for hop_limit in MeshPacket. diff --git a/src/mesh/RadioInterface.h b/src/mesh/RadioInterface.h index c49421d11..e1e23ba29 100644 --- a/src/mesh/RadioInterface.h +++ b/src/mesh/RadioInterface.h @@ -54,6 +54,8 @@ class RadioInterface uint32_t shortPacketMsec; protected: + bool disabled = false; + float bw = 125; uint8_t sf = 9; uint8_t cr = 7; @@ -98,6 +100,9 @@ class RadioInterface /// Prepare hardware for sleep. Call this _only_ for deep sleep, not needed for light sleep. virtual bool sleep() { return true; } + /// Disable this interface (while disabled, no packets can be sent or received) + void disable() { disabled = true; sleep(); } + /** * Send a packet (possibly by enquing in a private fifo). This routine will * later free() the packet to pool. This routine is not allowed to stall. diff --git a/src/mesh/RadioLibInterface.cpp b/src/mesh/RadioLibInterface.cpp index 84fd37ee6..63d7095c5 100644 --- a/src/mesh/RadioLibInterface.cpp +++ b/src/mesh/RadioLibInterface.cpp @@ -2,8 +2,8 @@ #include "MeshTypes.h" #include "NodeDB.h" #include "SPILock.h" -#include "mesh-pb-constants.h" #include "error.h" +#include "mesh-pb-constants.h" #include #include #include @@ -68,13 +68,12 @@ bool RadioLibInterface::canSendImmediately() bool busyTx = sendingPacket != NULL; bool busyRx = isReceiving && isActivelyReceiving(); - if (busyTx || busyRx) { if (busyTx) DEBUG_MSG("Can not send yet, busyTx\n"); // If we've been trying to send the same packet more than one minute and we haven't gotten a // TX IRQ from the radio, the radio is probably broken. - if (busyTx && (millis() - lastTxStart > 60000)){ + if (busyTx && (millis() - lastTxStart > 60000)) { DEBUG_MSG("Hardware Failure! busyTx for more than 60s\n"); recordCriticalError(CriticalErrorCode_TransmitFailed); #ifndef NO_ESP32 @@ -94,6 +93,11 @@ bool RadioLibInterface::canSendImmediately() /// bluetooth comms code. If the txmit queue is empty it might return an error ErrorCode RadioLibInterface::send(MeshPacket *p) { + if (disabled) { + packetPool.release(p); + return ERRNO_DISABLED; + } + // Sometimes when testing it is useful to be able to never turn on the xmitter #ifndef LORA_DISABLE_SENDING printPacket("enqueuing for send", p); @@ -110,7 +114,7 @@ ErrorCode RadioLibInterface::send(MeshPacket *p) // Count the packet toward our TX airtime utilization. // We only count it if it can be added to the TX queue. airTime->logAirtime(TX_LOG, xmitMsec); - //airTime.logAirtime(TX_LOG, xmitMsec); + // airTime.logAirtime(TX_LOG, xmitMsec); // We want all sending/receiving to be done by our daemon thread, We use a delay here because this packet might have been sent // in response to a packet we just received. So we want to make sure the other side has had a chance to reconfigure its radio @@ -119,7 +123,7 @@ ErrorCode RadioLibInterface::send(MeshPacket *p) return res; #else packetPool.release(p); - return ERRNO_UNKNOWN; + return ERRNO_DISABLED; #endif } @@ -133,17 +137,17 @@ bool RadioLibInterface::canSleep() } /** Attempt to cancel a previously sent packet. Returns true if a packet was found we could cancel */ -bool RadioLibInterface::cancelSending(NodeNum from, PacketId id) { +bool RadioLibInterface::cancelSending(NodeNum from, PacketId id) +{ auto p = txQueue.remove(from, id); - if(p) + if (p) packetPool.release(p); // free the packet we just removed bool result = (p != NULL); - DEBUG_MSG("cancelSending id=0x%x, removed=%d", id, result); + DEBUG_MSG("cancelSending id=0x%x, removed=%d\n", id, result); return result; } - /** radio helper thread callback. We never immediately transmit after any operation (either rx or tx). Instead we should start receiving and @@ -242,7 +246,7 @@ void RadioLibInterface::handleReceiveInterrupt() xmitMsec = getPacketTime(length); airTime->logAirtime(RX_ALL_LOG, xmitMsec); - //airTime.logAirtime(RX_ALL_LOG, xmitMsec); + // airTime.logAirtime(RX_ALL_LOG, xmitMsec); int state = iface->readData(radiobuf, length); if (state != ERR_NONE) { @@ -277,7 +281,7 @@ void RadioLibInterface::handleReceiveInterrupt() addReceiveMetadata(mp); mp->which_payloadVariant = MeshPacket_encrypted_tag; // Mark that the payload is still encrypted at this point - assert(((uint32_t) payloadLen) <= sizeof(mp->encrypted.bytes)); + assert(((uint32_t)payloadLen) <= sizeof(mp->encrypted.bytes)); memcpy(mp->encrypted.bytes, payload, payloadLen); mp->encrypted.size = payloadLen; @@ -285,7 +289,7 @@ void RadioLibInterface::handleReceiveInterrupt() xmitMsec = getPacketTime(mp); airTime->logAirtime(RX_LOG, xmitMsec); - //airTime.logAirtime(RX_LOG, xmitMsec); + // airTime.logAirtime(RX_LOG, xmitMsec); deliverToReceiver(mp); } @@ -295,16 +299,21 @@ void RadioLibInterface::handleReceiveInterrupt() /** start an immediate transmit */ void RadioLibInterface::startSend(MeshPacket *txp) { - printPacket("Starting low level send", txp); - setStandby(); // Cancel any already in process receives + printPacket("Starting low level send", txp); + if (disabled) { + DEBUG_MSG("startSend is dropping tx packet because we are disabled\n"); + packetPool.release(txp); + } else { + setStandby(); // Cancel any already in process receives - configHardwareForSend(); // must be after setStandby + configHardwareForSend(); // must be after setStandby - size_t numbytes = beginSending(txp); + size_t numbytes = beginSending(txp); - int res = iface->startTransmit(radiobuf, numbytes); - assert(res == ERR_NONE); + int res = iface->startTransmit(radiobuf, numbytes); + assert(res == ERR_NONE); - // Must be done AFTER, starting transmit, because startTransmit clears (possibly stale) interrupt pending register bits - enableInterrupt(isrTxLevel0); + // Must be done AFTER, starting transmit, because startTransmit clears (possibly stale) interrupt pending register bits + enableInterrupt(isrTxLevel0); + } } From 8c27baae844ba7b5f6d41bf24a34cce666f6f31b Mon Sep 17 00:00:00 2001 From: Jm Date: Fri, 12 Feb 2021 18:48:18 -0800 Subject: [PATCH 078/258] Update platformio.ini --- platformio.ini | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/platformio.ini b/platformio.ini index fc94967b5..c90e9c7c5 100644 --- a/platformio.ini +++ b/platformio.ini @@ -9,14 +9,13 @@ ; https://docs.platformio.org/page/projectconf.html [platformio] -;default_envs = tbeam -;default_envs = tlora-v1.3 +default_envs = tbeam ;default_envs = tbeam0.7 ;default_envs = heltec ;default_envs = tlora-v1 ;default_envs = tlora-v2 ;default_envs = lora-relay-v1 # nrf board -default_envs = linux # lora-relay-v1 # nrf52840dk-geeksville # linux # or if you'd like to change the default to something like lora-relay-v1 put that here +;default_envs = linux # lora-relay-v1 # nrf52840dk-geeksville # linux # or if you'd like to change the default to something like lora-relay-v1 put that here [common] ; common is not currently used @@ -150,12 +149,6 @@ board = ttgo-lora32-v1 build_flags = ${esp32_base.build_flags} -D TLORA_V1 -[env:tlora-v1.3] -extends = esp32_base -board = ttgo-lora32-v1 -build_flags = - ${esp32_base.build_flags} -D TLORA_V1_3 - ; note: the platformio definition for lora32-v2 seems stale, it is missing a pins_arduino.h file, therefore I don't think it works [env:tlora-v2] extends = esp32_base @@ -349,4 +342,4 @@ lib_deps = extends = esp32_base board = genieblocks_lora build_flags = - ${esp32_base.build_flags} -D GENIEBLOCKS + ${esp32_base.build_flags} -D GENIEBLOCKS \ No newline at end of file From c9b1ee532dc030ddd045a7c0e7ed6533a6f7c4c5 Mon Sep 17 00:00:00 2001 From: Jm Date: Fri, 12 Feb 2021 18:49:24 -0800 Subject: [PATCH 079/258] Update deviceonly.pb.h --- src/mesh/generated/deviceonly.pb.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/mesh/generated/deviceonly.pb.h b/src/mesh/generated/deviceonly.pb.h index fb503be49..99d838d39 100644 --- a/src/mesh/generated/deviceonly.pb.h +++ b/src/mesh/generated/deviceonly.pb.h @@ -80,10 +80,10 @@ extern const pb_msgdesc_t DeviceState_msg; #define DeviceState_fields &DeviceState_msg /* Maximum encoded size of messages (where known) */ -#define DeviceState_size 6262 +#define DeviceState_size 6266 #ifdef __cplusplus } /* extern "C" */ #endif -#endif +#endif \ No newline at end of file From e225af28dc9f63ff555e85f51af87e8b52138b4a Mon Sep 17 00:00:00 2001 From: Jm Date: Fri, 12 Feb 2021 18:52:31 -0800 Subject: [PATCH 080/258] Disable plugins --- src/plugins/RangeTestPlugin.cpp | 6 +++--- src/plugins/StoreForwardPlugin.cpp | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/plugins/RangeTestPlugin.cpp b/src/plugins/RangeTestPlugin.cpp index 4ed11f447..8f03589c2 100644 --- a/src/plugins/RangeTestPlugin.cpp +++ b/src/plugins/RangeTestPlugin.cpp @@ -32,9 +32,9 @@ int32_t RangeTestPlugin::runOnce() without having to configure it from the PythonAPI or WebUI. */ - radioConfig.preferences.range_test_plugin_enabled = 1; - radioConfig.preferences.range_test_plugin_sender = 0; - radioConfig.preferences.fixed_position = 1; + // radioConfig.preferences.range_test_plugin_enabled = 1; + // radioConfig.preferences.range_test_plugin_sender = 0; + // radioConfig.preferences.fixed_position = 1; uint32_t senderHeartbeat = radioConfig.preferences.range_test_plugin_sender * 1000; diff --git a/src/plugins/StoreForwardPlugin.cpp b/src/plugins/StoreForwardPlugin.cpp index 4ee4eac7c..f71fb965b 100644 --- a/src/plugins/StoreForwardPlugin.cpp +++ b/src/plugins/StoreForwardPlugin.cpp @@ -19,7 +19,7 @@ struct sfRecord struct sfRecord records[STORE_RECORDS]; -#define STOREFORWARDPLUGIN_ENABLED 1 +#define STOREFORWARDPLUGIN_ENABLED 0 StoreForwardPlugin *storeForwardPlugin; StoreForwardPluginRadio *storeForwardPluginRadio; From 875eeb699cbae6f34339b0bec656a670a0b99a6c Mon Sep 17 00:00:00 2001 From: Sacha Weatherstone Date: Sat, 13 Feb 2021 19:51:31 +1100 Subject: [PATCH 081/258] Fix report formatting --- src/mesh/http/ContentHandler.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/mesh/http/ContentHandler.cpp b/src/mesh/http/ContentHandler.cpp index 8535dd349..e46fdb1f7 100644 --- a/src/mesh/http/ContentHandler.cpp +++ b/src/mesh/http/ContentHandler.cpp @@ -934,8 +934,7 @@ void handleReport(HTTPRequest *req, HTTPResponse *res) res->println("\"radio\": {"); res->printf("\"frequecy\": %f,\n", RadioLibInterface::instance->getFreq()); res->printf("\"lora_channel\": %d\n", RadioLibInterface::instance->getChannelNum()); - res->println("},"); - + res->println("}"); res->println("},"); From 52ec4d511cc37d5ce9456ba324ece4c2c672e159 Mon Sep 17 00:00:00 2001 From: Kevin Hester Date: Sun, 14 Feb 2021 11:37:32 +0800 Subject: [PATCH 082/258] oops - we weren't properly stripping timestamps from new style positions --- src/mesh/MeshService.cpp | 14 +------------- src/plugins/PositionPlugin.cpp | 18 ++++++++++++++---- 2 files changed, 15 insertions(+), 17 deletions(-) diff --git a/src/mesh/MeshService.cpp b/src/mesh/MeshService.cpp index f3a3bd1aa..59e9fb25f 100644 --- a/src/mesh/MeshService.cpp +++ b/src/mesh/MeshService.cpp @@ -178,18 +178,6 @@ void MeshService::sendToMesh(MeshPacket *p) { nodeDB.updateFrom(*p); // update our local DB for this packet (because phone might have sent position packets etc...) - // Strip out any time information before sending packets to other nodes - to keep the wire size small (and because other - // nodes shouldn't trust it anyways) Note: we allow a device with a local GPS to include the time, so that gpsless - // devices can get time. - if (p->which_payloadVariant == MeshPacket_decoded_tag && p->decoded.which_payloadVariant == SubPacket_position_tag && - p->decoded.position.time) { - if (getRTCQuality() < RTCQualityGPS) { - DEBUG_MSG("Stripping time %u from position send\n", p->decoded.position.time); - p->decoded.position.time = 0; - } else - DEBUG_MSG("Providing time to mesh %u\n", p->decoded.position.time); - } - // Note: We might return !OK if our fifo was full, at that point the only option we have is to drop it router->sendLocal(p); } @@ -221,7 +209,7 @@ NodeInfo *MeshService::refreshMyNodeInfo() { Position &position = node->position; // Update our local node info with our position (even if we don't decide to update anyone else) - position.time = getValidTime(RTCQualityGPS); // This nodedb timestamp might be stale, so update it if our clock is valid. + position.time = getValidTime(RTCQualityFromNet); // This nodedb timestamp might be stale, so update it if our clock is kinda valid position.battery_level = powerStatus->getBatteryChargePercent(); updateBatteryLevel(position.battery_level); diff --git a/src/plugins/PositionPlugin.cpp b/src/plugins/PositionPlugin.cpp index 4ea7298e6..4a0fdb4d8 100644 --- a/src/plugins/PositionPlugin.cpp +++ b/src/plugins/PositionPlugin.cpp @@ -31,14 +31,25 @@ MeshPacket *PositionPlugin::allocReply() { NodeInfo *node = service.refreshMyNodeInfo(); // should guarantee there is now a position assert(node->has_position); - - return allocDataProtobuf(node->position); + + Position p = node->position; + + // Strip out any time information before sending packets to other nodes - to keep the wire size small (and because other + // nodes shouldn't trust it anyways) Note: we allow a device with a local GPS to include the time, so that gpsless + // devices can get time. + if (getRTCQuality() < RTCQualityGPS) { + DEBUG_MSG("Stripping time %u from position send\n", p.time); + p.time = 0; + } else + DEBUG_MSG("Providing time to mesh %u\n", p.time); + + return allocDataProtobuf(p); } void PositionPlugin::sendOurPosition(NodeNum dest, bool wantReplies) { // cancel any not yet sent (now stale) position packets - if(prevPacketId) // if we wrap around to zero, we'll simply fail to cancel in that rare case (no big deal) + if (prevPacketId) // if we wrap around to zero, we'll simply fail to cancel in that rare case (no big deal) service.cancelSending(prevPacketId); MeshPacket *p = allocReply(); @@ -49,4 +60,3 @@ void PositionPlugin::sendOurPosition(NodeNum dest, bool wantReplies) service.sendToMesh(p); } - From a872231f8a25ddb7b834dab399fbfb6dab3f6a5b Mon Sep 17 00:00:00 2001 From: Kevin Hester Date: Sun, 14 Feb 2021 11:57:48 +0800 Subject: [PATCH 083/258] clean up position broadcasts, send them even if we don't have gps lock --- src/mesh/MeshService.cpp | 17 ----------------- src/plugins/PositionPlugin.cpp | 19 +++++++++++++++++++ src/plugins/PositionPlugin.h | 14 ++++++++++++-- 3 files changed, 31 insertions(+), 19 deletions(-) diff --git a/src/mesh/MeshService.cpp b/src/mesh/MeshService.cpp index 59e9fb25f..a6eaff5cf 100644 --- a/src/mesh/MeshService.cpp +++ b/src/mesh/MeshService.cpp @@ -247,22 +247,5 @@ int MeshService::onGPSChanged(const meshtastic::GPSStatus *unused) // Update our current position in the local DB nodeDB.updatePosition(nodeDB.getNodeNum(), pos); - // We limit our GPS broadcasts to a max rate - static uint32_t lastGpsSend; - uint32_t now = millis(); - if (lastGpsSend == 0 || now - lastGpsSend > getPref_position_broadcast_secs() * 1000) { - lastGpsSend = now; - - static uint32_t currentGeneration; - - // If we changed channels, ask everyone else for their latest info - bool requestReplies = currentGeneration != radioGeneration; - currentGeneration = radioGeneration; - - DEBUG_MSG("Sending position to mesh (wantReplies=%d)\n", requestReplies); - assert(positionPlugin); - positionPlugin->sendOurPosition(NODENUM_BROADCAST, requestReplies); - } - return 0; } diff --git a/src/plugins/PositionPlugin.cpp b/src/plugins/PositionPlugin.cpp index 4a0fdb4d8..09dbdd502 100644 --- a/src/plugins/PositionPlugin.cpp +++ b/src/plugins/PositionPlugin.cpp @@ -60,3 +60,22 @@ void PositionPlugin::sendOurPosition(NodeNum dest, bool wantReplies) service.sendToMesh(p); } + + +int32_t PositionPlugin::runOnce(){ + + // We limit our GPS broadcasts to a max rate + uint32_t now = millis(); + if (lastGpsSend == 0 || now - lastGpsSend >= getPref_position_broadcast_secs() * 1000) { + lastGpsSend = now; + + // If we changed channels, ask everyone else for their latest info + bool requestReplies = currentGeneration != radioGeneration; + currentGeneration = radioGeneration; + + DEBUG_MSG("Sending position to mesh (wantReplies=%d)\n", requestReplies); + sendOurPosition(NODENUM_BROADCAST, requestReplies); + } + + return 5000; // to save power only wake for our callback occasionally +} \ No newline at end of file diff --git a/src/plugins/PositionPlugin.h b/src/plugins/PositionPlugin.h index 9ca2d2082..580a22999 100644 --- a/src/plugins/PositionPlugin.h +++ b/src/plugins/PositionPlugin.h @@ -1,19 +1,26 @@ #pragma once #include "ProtobufPlugin.h" +#include "concurrency/OSThread.h" /** * Position plugin for sending/receiving positions into the mesh */ -class PositionPlugin : public ProtobufPlugin +class PositionPlugin : public ProtobufPlugin, private concurrency::OSThread { /// The id of the last packet we sent, to allow us to cancel it if we make something fresher PacketId prevPacketId = 0; + /// We limit our GPS broadcasts to a max rate + uint32_t lastGpsSend = 0; + + /// We force a rebroadcast if the radio settings change + uint32_t currentGeneration = 0; + public: /** Constructor * name is for debugging output */ - PositionPlugin() : ProtobufPlugin("position", PortNum_POSITION_APP, Position_fields) {} + PositionPlugin() : ProtobufPlugin("position", PortNum_POSITION_APP, Position_fields), concurrency::OSThread("PositionPlugin") {} /** * Send our position into the mesh @@ -31,6 +38,9 @@ class PositionPlugin : public ProtobufPlugin /** Messages can be received that have the want_response bit set. If set, this callback will be invoked * so that subclasses can (optionally) send a response back to the original sender. */ virtual MeshPacket *allocReply(); + + /** Does our periodic broadcast */ + virtual int32_t runOnce(); }; extern PositionPlugin *positionPlugin; \ No newline at end of file From 66a7e8eab98c4b3dfe6ed84d25c0e2224d34cde9 Mon Sep 17 00:00:00 2001 From: Kevin Hester Date: Sun, 14 Feb 2021 12:02:24 +0800 Subject: [PATCH 084/258] oops - we were never sending 'fixed' gps positions to other nodes --- src/mesh/MeshService.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/mesh/MeshService.cpp b/src/mesh/MeshService.cpp index a6eaff5cf..a1a6f885f 100644 --- a/src/mesh/MeshService.cpp +++ b/src/mesh/MeshService.cpp @@ -232,7 +232,7 @@ int MeshService::onGPSChanged(const meshtastic::GPSStatus *unused) else { // The GPS has lost lock, if we are fixed position we should just keep using // the old position - if(!radioConfig.preferences.fixed_position) { + if(radioConfig.preferences.fixed_position) { DEBUG_MSG("WARNING: Using fixed position\n"); } else { // throw away old position @@ -242,7 +242,7 @@ int MeshService::onGPSChanged(const meshtastic::GPSStatus *unused) } } - DEBUG_MSG("got gps notify time=%u, lat=%d, bat=%d\n", pos.latitude_i, pos.time, pos.battery_level); + DEBUG_MSG("got gps notify time=%u, lat=%d, bat=%d\n", pos.time, pos.latitude_i, pos.battery_level); // Update our current position in the local DB nodeDB.updatePosition(nodeDB.getNodeNum(), pos); From 71c35304d64c731ee6ca63b6256128bf4600b3be Mon Sep 17 00:00:00 2001 From: Kevin Hester Date: Sun, 14 Feb 2021 12:26:51 +0800 Subject: [PATCH 085/258] delay position plugin start until 60 secs after first boot --- src/plugins/PositionPlugin.cpp | 12 ++++++++++-- src/plugins/PositionPlugin.h | 4 ++-- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/src/plugins/PositionPlugin.cpp b/src/plugins/PositionPlugin.cpp index 09dbdd502..153d20cfc 100644 --- a/src/plugins/PositionPlugin.cpp +++ b/src/plugins/PositionPlugin.cpp @@ -7,6 +7,14 @@ PositionPlugin *positionPlugin; +PositionPlugin::PositionPlugin() + : ProtobufPlugin("position", PortNum_POSITION_APP, Position_fields), concurrency::OSThread("PositionPlugin") +{ + setIntervalFromNow(60 * + 1000); // Send our initial position 60 seconds after we start (to give GPS time to setup) + +} + bool PositionPlugin::handleReceivedProtobuf(const MeshPacket &mp, const Position &p) { // FIXME - we currently update position data in the DB only if the message was a broadcast or destined to us @@ -61,8 +69,8 @@ void PositionPlugin::sendOurPosition(NodeNum dest, bool wantReplies) service.sendToMesh(p); } - -int32_t PositionPlugin::runOnce(){ +int32_t PositionPlugin::runOnce() +{ // We limit our GPS broadcasts to a max rate uint32_t now = millis(); diff --git a/src/plugins/PositionPlugin.h b/src/plugins/PositionPlugin.h index 580a22999..7a45c23a0 100644 --- a/src/plugins/PositionPlugin.h +++ b/src/plugins/PositionPlugin.h @@ -20,8 +20,8 @@ class PositionPlugin : public ProtobufPlugin, private concurrency::OST /** Constructor * name is for debugging output */ - PositionPlugin() : ProtobufPlugin("position", PortNum_POSITION_APP, Position_fields), concurrency::OSThread("PositionPlugin") {} - + PositionPlugin(); + /** * Send our position into the mesh */ From e35f13798624e7def920ee12d8b7350c0c3ee6bd Mon Sep 17 00:00:00 2001 From: Kevin Hester Date: Sun, 14 Feb 2021 12:27:10 +0800 Subject: [PATCH 086/258] clean up nodeinfo broadcasts and move into plugin --- src/mesh/MeshService.cpp | 18 ------------------ src/plugins/NodeInfoPlugin.cpp | 25 ++++++++++++++++++++++++- src/plugins/NodeInfoPlugin.h | 12 ++++++++---- 3 files changed, 32 insertions(+), 23 deletions(-) diff --git a/src/mesh/MeshService.cpp b/src/mesh/MeshService.cpp index a1a6f885f..ae53e802f 100644 --- a/src/mesh/MeshService.cpp +++ b/src/mesh/MeshService.cpp @@ -51,22 +51,7 @@ MeshService service; #include "Router.h" -static int32_t sendOwnerCb() -{ - static uint32_t currentGeneration; - // If we changed channels, ask everyone else for their latest info - bool requestReplies = currentGeneration != radioGeneration; - currentGeneration = radioGeneration; - - DEBUG_MSG("Sending our nodeinfo to mesh (wantReplies=%d)\n", requestReplies); - assert(nodeInfoPlugin); - nodeInfoPlugin->sendOurNodeInfo(NODENUM_BROADCAST, requestReplies); // Send our info (don't request replies) - - return getPref_send_owner_interval() * getPref_position_broadcast_secs() * 1000; -} - -static concurrency::Periodic *sendOwnerPeriod; MeshService::MeshService() : toPhoneQueue(MAX_RX_TOPHONE) { @@ -75,9 +60,6 @@ MeshService::MeshService() : toPhoneQueue(MAX_RX_TOPHONE) void MeshService::init() { - sendOwnerPeriod = new concurrency::Periodic("SendOwner", sendOwnerCb); - sendOwnerPeriod->setIntervalFromNow(30 * 1000); // Send our initial owner announcement 30 seconds after we start (to give network time to setup) - // moved much earlier in boot (called from setup()) // nodeDB.init(); diff --git a/src/plugins/NodeInfoPlugin.cpp b/src/plugins/NodeInfoPlugin.cpp index 6c236ed34..a04ec4159 100644 --- a/src/plugins/NodeInfoPlugin.cpp +++ b/src/plugins/NodeInfoPlugin.cpp @@ -29,7 +29,7 @@ bool NodeInfoPlugin::handleReceivedProtobuf(const MeshPacket &mp, const User &p) void NodeInfoPlugin::sendOurNodeInfo(NodeNum dest, bool wantReplies) { // cancel any not yet sent (now stale) position packets - if(prevPacketId) // if we wrap around to zero, we'll simply fail to cancel in that rare case (no big deal) + if (prevPacketId) // if we wrap around to zero, we'll simply fail to cancel in that rare case (no big deal) service.cancelSending(prevPacketId); MeshPacket *p = allocReply(); @@ -48,3 +48,26 @@ MeshPacket *NodeInfoPlugin::allocReply() DEBUG_MSG("sending owner %s/%s/%s\n", u.id, u.long_name, u.short_name); return allocDataProtobuf(u); } + +NodeInfoPlugin::NodeInfoPlugin() + : ProtobufPlugin("nodeinfo", PortNum_NODEINFO_APP, User_fields), concurrency::OSThread("NodeInfoPlugin") +{ + setIntervalFromNow(30 * + 1000); // Send our initial owner announcement 30 seconds after we start (to give network time to setup) +} + +int32_t NodeInfoPlugin::runOnce() +{ + static uint32_t currentGeneration; + + // If we changed channels, ask everyone else for their latest info + bool requestReplies = currentGeneration != radioGeneration; + currentGeneration = radioGeneration; + + DEBUG_MSG("Sending our nodeinfo to mesh (wantReplies=%d)\n", requestReplies); + assert(nodeInfoPlugin); + nodeInfoPlugin->sendOurNodeInfo(NODENUM_BROADCAST, requestReplies); // Send our info (don't request replies) + + return getPref_position_broadcast_secs() * 1000; +} + diff --git a/src/plugins/NodeInfoPlugin.h b/src/plugins/NodeInfoPlugin.h index 8b01ea25e..f0a7efebd 100644 --- a/src/plugins/NodeInfoPlugin.h +++ b/src/plugins/NodeInfoPlugin.h @@ -4,17 +4,18 @@ /** * NodeInfo plugin for sending/receiving NodeInfos into the mesh */ -class NodeInfoPlugin : public ProtobufPlugin +class NodeInfoPlugin : public ProtobufPlugin, private concurrency::OSThread { /// The id of the last packet we sent, to allow us to cancel it if we make something fresher PacketId prevPacketId = 0; - + + uint32_t currentGeneration = 0; public: /** Constructor * name is for debugging output */ - NodeInfoPlugin() : ProtobufPlugin("nodeinfo", PortNum_NODEINFO_APP, User_fields) {} - + NodeInfoPlugin(); + /** * Send our NodeInfo into the mesh */ @@ -30,6 +31,9 @@ class NodeInfoPlugin : public ProtobufPlugin /** Messages can be received that have the want_response bit set. If set, this callback will be invoked * so that subclasses can (optionally) send a response back to the original sender. */ virtual MeshPacket *allocReply(); + + /** Does our periodic broadcast */ + virtual int32_t runOnce(); }; extern NodeInfoPlugin *nodeInfoPlugin; \ No newline at end of file From 51ccc3aa9e85f5c76d957519ef6f9f1aead45443 Mon Sep 17 00:00:00 2001 From: Kevin Hester Date: Sun, 14 Feb 2021 12:28:27 +0800 Subject: [PATCH 087/258] 1.1.47 --- version.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version.properties b/version.properties index 98083da23..30f4b34dd 100644 --- a/version.properties +++ b/version.properties @@ -1,4 +1,4 @@ [VERSION] major = 1 minor = 1 -build = 46 +build = 47 From 450e877cfb4d559c850a9b3cc211edae1f8721c3 Mon Sep 17 00:00:00 2001 From: Kevin Hester Date: Sun, 14 Feb 2021 14:14:50 +0800 Subject: [PATCH 088/258] fix #661 - create $archivedir --- bin/build-all.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/build-all.sh b/bin/build-all.sh index ecb96e7a1..c4d48b122 100755 --- a/bin/build-all.sh +++ b/bin/build-all.sh @@ -21,7 +21,7 @@ ARCHIVEDIR=release/archive rm -f $OUTDIR/firmware* -mkdir -p $OUTDIR/bins +mkdir -p $OUTDIR/bins $ARCHIVEDIR rm -r $OUTDIR/bins/* mkdir -p $OUTDIR/bins/universal $OUTDIR/elfs/universal From 92a62d93ef0e93072493ea4009c844e01a377eec Mon Sep 17 00:00:00 2001 From: Jm Casler Date: Sat, 13 Feb 2021 22:21:01 -0800 Subject: [PATCH 089/258] #671 Rangetest - This just needs to be tested. --- src/plugins/RangeTestPlugin.cpp | 137 +++++++++++++++++++++++++++++++- src/plugins/RangeTestPlugin.h | 11 ++- 2 files changed, 144 insertions(+), 4 deletions(-) diff --git a/src/plugins/RangeTestPlugin.cpp b/src/plugins/RangeTestPlugin.cpp index 8f03589c2..c719ad04c 100644 --- a/src/plugins/RangeTestPlugin.cpp +++ b/src/plugins/RangeTestPlugin.cpp @@ -5,13 +5,13 @@ #include "Router.h" #include "configuration.h" #include +#include #include /* As a sender, I can send packets every n-seonds. These packets include an incramented PacketID. As a receiver, I can receive packets from multiple senders. These packets can be saved to the spiffs. - */ RangeTestPlugin *rangeTestPlugin; @@ -19,9 +19,11 @@ RangeTestPluginRadio *rangeTestPluginRadio; RangeTestPlugin::RangeTestPlugin() : concurrency::OSThread("RangeTestPlugin") {} -uint16_t packetSequence = 0; +uint32_t packetSequence = 0; -// char serialStringChar[Constants_DATA_PAYLOAD_LEN]; +#define SEC_PER_DAY 86400 +#define SEC_PER_HOUR 3600 +#define SEC_PER_MIN 60 int32_t RangeTestPlugin::runOnce() { @@ -34,8 +36,12 @@ int32_t RangeTestPlugin::runOnce() // radioConfig.preferences.range_test_plugin_enabled = 1; // radioConfig.preferences.range_test_plugin_sender = 0; + // radioConfig.preferences.range_test_plugin_save = 1; + + // Fixed position is useful when testing indoors. // radioConfig.preferences.fixed_position = 1; + uint32_t senderHeartbeat = radioConfig.preferences.range_test_plugin_sender * 1000; if (radioConfig.preferences.range_test_plugin_enabled) { @@ -137,6 +143,9 @@ bool RangeTestPluginRadio::handleReceived(const MeshPacket &mp) NodeInfo *n = nodeDB.getNode(mp.from); + if (radioConfig.preferences.range_test_plugin_save) { + appendFile(mp); + } DEBUG_MSG("-----------------------------------------\n"); DEBUG_MSG("p.payload.bytes \"%s\"\n", p.payload.bytes); @@ -171,3 +180,125 @@ bool RangeTestPluginRadio::handleReceived(const MeshPacket &mp) return true; // Let others look at this message also if they want } + +/// Ported from my old java code, returns distance in meters along the globe +/// surface (by magic?) +float RangeTestPluginRadio::latLongToMeter(double lat_a, double lng_a, double lat_b, double lng_b) +{ + double pk = (180 / 3.14169); + double a1 = lat_a / pk; + double a2 = lng_a / pk; + double b1 = lat_b / pk; + double b2 = lng_b / pk; + double cos_b1 = cos(b1); + double cos_a1 = cos(a1); + double t1 = cos_a1 * cos(a2) * cos_b1 * cos(b2); + double t2 = cos_a1 * sin(a2) * cos_b1 * sin(b2); + double t3 = sin(a1) * sin(b1); + double tt = acos(t1 + t2 + t3); + if (isnan(tt)) + tt = 0.0; // Must have been the same point? + + return (float)(6366000 * tt); +} + +bool RangeTestPluginRadio::appendFile(const MeshPacket &mp) +{ + auto &p = mp.decoded.data; + + NodeInfo *n = nodeDB.getNode(mp.from); + /* + DEBUG_MSG("-----------------------------------------\n"); + DEBUG_MSG("p.payload.bytes \"%s\"\n", p.payload.bytes); + DEBUG_MSG("p.payload.size %d\n", p.payload.size); + DEBUG_MSG("---- Received Packet:\n"); + DEBUG_MSG("mp.from %d\n", mp.from); + DEBUG_MSG("mp.rx_snr %f\n", mp.rx_snr); + DEBUG_MSG("mp.hop_limit %d\n", mp.hop_limit); + // DEBUG_MSG("mp.decoded.position.latitude_i %d\n", mp.decoded.position.latitude_i); // Depricated + // DEBUG_MSG("mp.decoded.position.longitude_i %d\n", mp.decoded.position.longitude_i); // Depricated + DEBUG_MSG("---- Node Information of Received Packet (mp.from):\n"); + DEBUG_MSG("n->user.long_name %s\n", n->user.long_name); + DEBUG_MSG("n->user.short_name %s\n", n->user.short_name); + DEBUG_MSG("n->user.macaddr %X\n", n->user.macaddr); + DEBUG_MSG("n->has_position %d\n", n->has_position); + DEBUG_MSG("n->position.latitude_i %d\n", n->position.latitude_i); + DEBUG_MSG("n->position.longitude_i %d\n", n->position.longitude_i); + DEBUG_MSG("n->position.battery_level %d\n", n->position.battery_level); + DEBUG_MSG("---- Current device location information:\n"); + DEBUG_MSG("gpsStatus->getLatitude() %d\n", gpsStatus->getLatitude()); + DEBUG_MSG("gpsStatus->getLongitude() %d\n", gpsStatus->getLongitude()); + DEBUG_MSG("gpsStatus->getHasLock() %d\n", gpsStatus->getHasLock()); + DEBUG_MSG("gpsStatus->getDOP() %d\n", gpsStatus->getDOP()); + DEBUG_MSG("-----------------------------------------\n"); + */ + if (!SPIFFS.begin(true)) { + DEBUG_MSG("An Error has occurred while mounting SPIFFS\n"); + return 0; + } + + if (SPIFFS.totalBytes() - SPIFFS.usedBytes() < 51200) { + DEBUG_MSG("SPIFFS doesn't have enough free space. Abourting write.\n"); + return 0; + } + + //--------- Write to file + File fileToWrite = SPIFFS.open("/static/rangetest.csv", FILE_WRITE); + + if (!fileToWrite) { + DEBUG_MSG("There was an error opening the file for writing\n"); + return 0; + } + + if (fileToWrite.println("time,sender mac,rx snr,sender lat,sender long,rx lat,rx long,distance,payload")) { + DEBUG_MSG("File was written\n"); + } else { + DEBUG_MSG("File write failed\n"); + } + + fileToWrite.close(); + + //--------- Apend content to file + File fileToAppend = SPIFFS.open("/static/rangetest.csv", FILE_APPEND); + + if (!fileToAppend) { + DEBUG_MSG("There was an error opening the file for appending\n"); + return 0; + } + + struct timeval tv; + if (!gettimeofday(&tv, NULL)) { + long hms = tv.tv_sec % SEC_PER_DAY; + // hms += tz.tz_dsttime * SEC_PER_HOUR; + // hms -= tz.tz_minuteswest * SEC_PER_MIN; + // mod `hms` to ensure in positive range of [0...SEC_PER_DAY) + hms = (hms + SEC_PER_DAY) % SEC_PER_DAY; + + // Tear apart hms into h:m:s + int hour = hms / SEC_PER_HOUR; + int min = (hms % SEC_PER_HOUR) / SEC_PER_MIN; + int sec = (hms % SEC_PER_HOUR) % SEC_PER_MIN; // or hms % SEC_PER_MIN + + fileToAppend.printf("%02d:%02d:%02d ", hour, min, sec); // Time + } else { + fileToAppend.printf("??:??:?? "); // Time + } + + fileToAppend.printf("$X,", n->user.macaddr); // Mac Address + fileToAppend.printf("%f,", mp.rx_snr); // RX SNR + fileToAppend.printf("%d,", n->position.latitude_i); // Sender Lat + fileToAppend.printf("%d,", n->position.longitude_i); // Sender Long + fileToAppend.printf("%d,", gpsStatus->getLatitude()); // RX Lat + fileToAppend.printf("%d,", gpsStatus->getLongitude()); // RX Long + + float distance = latLongToMeter(n->position.latitude_i * 1e-7, n->position.longitude_i * 1e-7, + gpsStatus->getLatitude() * 1e-7, gpsStatus->getLongitude() * 1e-7); + fileToAppend.printf("%f,", distance); // Distance in meters + + // TODO: If quotes are found in the payload, it has to be escaped. + fileToAppend.printf("\"%s\"\n", p.payload.bytes); + + fileToAppend.close(); + + return 1; +} diff --git a/src/plugins/RangeTestPlugin.h b/src/plugins/RangeTestPlugin.h index f66744dbd..8a10ca395 100644 --- a/src/plugins/RangeTestPlugin.h +++ b/src/plugins/RangeTestPlugin.h @@ -28,7 +28,6 @@ class RangeTestPluginRadio : public SinglePortPlugin uint32_t lastRxID; public: - RangeTestPluginRadio() : SinglePortPlugin("RangeTestPluginRadio", PortNum_TEXT_MESSAGE_APP) {} /** @@ -36,6 +35,16 @@ class RangeTestPluginRadio : public SinglePortPlugin */ void sendPayload(NodeNum dest = NODENUM_BROADCAST, bool wantReplies = false); + /** + * Append range test data to the file on the spiffs + */ + bool appendFile(const MeshPacket &mp); + + /** + * Kevin's magical calculation of two points to meters. + */ + float latLongToMeter(double lat_a, double lng_a, double lat_b, double lng_b); + protected: virtual MeshPacket *allocReply(); From 36643cf5f543e5e114daf2c400bfc16816c9ed3e Mon Sep 17 00:00:00 2001 From: Jm Casler Date: Sat, 13 Feb 2021 22:40:04 -0800 Subject: [PATCH 090/258] #671 range test plugin documentation #671 range test plugin documentation --- docs/software/plugins/RangeTestPlugin.md | 54 ++++++++++++++++++++++++ 1 file changed, 54 insertions(+) create mode 100644 docs/software/plugins/RangeTestPlugin.md diff --git a/docs/software/plugins/RangeTestPlugin.md b/docs/software/plugins/RangeTestPlugin.md new file mode 100644 index 000000000..9fd9b2724 --- /dev/null +++ b/docs/software/plugins/RangeTestPlugin.md @@ -0,0 +1,54 @@ +# About + +The RangeTest Plugin will help you perform range and coverage tests. + +# Configuration + +These are the settings that can be configured. + + range_test_plugin_enabled + Is the plugin enabled? + + 0 = Disabled (Default) + 1 = Enabled + + range_test_plugin_save + If enabled, we will save a log of all received messages to /static/rangetest.csv which you can access from the webserver. We will abort + writing if there is less than 50k of space on the filesystem to prevent filling up the storage. + + 0 = Disabled (Default) + 1 = Enabled + + range_test_plugin_sender + Number of seconds to wait between sending packets. Using the long_slow channel configuration, it's best not to go more frequent than once every 60 seconds. You can be more agressive with faster settings. 0 is default which disables sending messages. + +# Usage Notes + +For basic usage, you will need two devices both with a GPS. A device with a paired phone with GPS may work, I have not tried it. + +The first thing to do is to turn on the plugin. With the plugin turned on, the other settings will be available: + + range_test_plugin_enabled = 1 + +If you want to send a message every 60 seconds: + + range_test_plugin_sender = 60 + +To save a log of the messages: + + range_test_plugin_save = 1 + + +# Known Problems + +* If turned on, using mesh network will become unwieldly because messages are sent over the same channel as the other messages. See TODO below. + +# TODO + +* Right now range test messages go over the TEXT_MESSAGE_APP port. We need a toggle to switch to RANGE_TEST_APP. + +# Need more help? + +Go to the Meshtastic Discourse Group if you have any questions or to share how you have used this. + +https://meshtastic.discourse.group From c55074f7fead8a3adf27faea7500c304a14a6099 Mon Sep 17 00:00:00 2001 From: Kevin Hester Date: Sun, 14 Feb 2021 15:06:49 +0800 Subject: [PATCH 091/258] oops: we should crash if we >MAX_THREADS, also raise max threads --- platformio.ini | 2 +- src/concurrency/OSThread.cpp | 6 ++++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/platformio.ini b/platformio.ini index c90e9c7c5..4b91317d9 100644 --- a/platformio.ini +++ b/platformio.ini @@ -75,7 +75,7 @@ lib_deps = https://github.com/meshtastic/AXP202X_Library.git#8404abb6d4b486748636bc6ad72d2a47baaf5460 Wire ; explicitly needed here because the AXP202 library forgets to add it SPI - https://github.com/geeksville/ArduinoThread.git#333ffd09b596977c217ba25da4258f588b462ac6 + https://github.com/geeksville/ArduinoThread.git#72921ac222eed6f526ba1682023cee290d9aa1b3 ; Common settings for conventional (non Portduino) Ardino targets [arduino_base] diff --git a/src/concurrency/OSThread.cpp b/src/concurrency/OSThread.cpp index 5e20debf9..4bde72b07 100644 --- a/src/concurrency/OSThread.cpp +++ b/src/concurrency/OSThread.cpp @@ -32,8 +32,10 @@ OSThread::OSThread(const char *_name, uint32_t period, ThreadController *_contro ThreadName = _name; - if (controller) - controller->add(this); + if (controller) { + bool added = controller->add(this); + assert(added); + } } OSThread::~OSThread() From 7c1ddd9447d9b777f74ce5ef6b0078eae9fa803b Mon Sep 17 00:00:00 2001 From: Kevin Hester Date: Sun, 14 Feb 2021 15:13:58 +0800 Subject: [PATCH 092/258] 1.1.48 --- version.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version.properties b/version.properties index 30f4b34dd..6c1503acd 100644 --- a/version.properties +++ b/version.properties @@ -1,4 +1,4 @@ [VERSION] major = 1 minor = 1 -build = 47 +build = 48 From 3201d1c3bcc636feade1f82f74a5afdb20d9248c Mon Sep 17 00:00:00 2001 From: Jm Casler Date: Sun, 14 Feb 2021 08:44:49 -0800 Subject: [PATCH 093/258] #668 Partial work for store & forward --- src/plugins/StoreForwardPlugin.cpp | 54 +++++++----------------------- src/plugins/StoreForwardPlugin.h | 3 ++ 2 files changed, 15 insertions(+), 42 deletions(-) diff --git a/src/plugins/StoreForwardPlugin.cpp b/src/plugins/StoreForwardPlugin.cpp index f71fb965b..c82724560 100644 --- a/src/plugins/StoreForwardPlugin.cpp +++ b/src/plugins/StoreForwardPlugin.cpp @@ -8,22 +8,14 @@ #include -#define STORE_RECORDS 5000 -#define BYTES_PER_RECORDS 512 - -struct sfRecord -{ - uint8_t bytes[BYTES_PER_RECORDS]; - uint32_t timestamp; // Time the packet was received -}; - -struct sfRecord records[STORE_RECORDS]; +#define STORE_RECORDS 5000 +#define BYTES_PER_RECORDS 512 #define STOREFORWARDPLUGIN_ENABLED 0 StoreForwardPlugin *storeForwardPlugin; StoreForwardPluginRadio *storeForwardPluginRadio; - + StoreForwardPlugin::StoreForwardPlugin() : concurrency::OSThread("SerialPlugin") {} // char serialStringChar[Constants_DATA_PAYLOAD_LEN]; @@ -37,8 +29,8 @@ int32_t StoreForwardPlugin::runOnce() without having to configure it from the PythonAPI or WebUI. */ - //radioConfig.preferences.store_forward_plugin_enabled = 1; - //radioConfig.preferences.store_forward_plugin_records = 80; + // radioConfig.preferences.store_forward_plugin_enabled = 1; + // radioConfig.preferences.store_forward_plugin_records = 80; if (radioConfig.preferences.store_forward_plugin_enabled) { @@ -67,9 +59,8 @@ int32_t StoreForwardPlugin::runOnce() return (INT32_MAX); } - // Non-Router + // Non-Router } else { - } storeForwardPluginRadio = new StoreForwardPluginRadio(); @@ -104,7 +95,7 @@ void StoreForwardPluginRadio::sendPayload(NodeNum dest, bool wantReplies) p->to = dest; p->decoded.want_response = wantReplies; - //p->want_ack = SERIALPLUGIN_ACK; + // p->want_ack = SERIALPLUGIN_ACK; // p->decoded.data.payload.size = strlen(serialStringChar); // You must specify how many bytes are in the reply // memcpy(p->decoded.data.payload.bytes, serialStringChar, p->decoded.data.payload.size); @@ -118,36 +109,15 @@ bool StoreForwardPluginRadio::handleReceived(const MeshPacket &mp) if (STOREFORWARDPLUGIN_ENABLED) { - auto &p = mp.decoded.data; - // DEBUG_MSG("Received text msg self=0x%0x, from=0x%0x, to=0x%0x, id=%d, msg=%.*s\n", - // nodeDB.getNodeNum(), mp.from, mp.to, mp.id, p.payload.size, p.payload.bytes); + // auto &p = mp.decoded.data; - if (mp.from == nodeDB.getNodeNum()) { - - /* - * If radioConfig.preferences.serialplugin_echo is true, then echo the packets that are sent out back to the TX - * of the serial interface. - */ - if (radioConfig.preferences.serialplugin_echo) { - - // For some reason, we get the packet back twice when we send out of the radio. - // TODO: need to find out why. - if (lastRxID != mp.id) { - lastRxID = mp.id; - // DEBUG_MSG("* * Message came this device\n"); - // Serial2.println("* * Message came this device"); - Serial2.printf("%s", p.payload.bytes); - } - } - - } else { - // DEBUG_MSG("* * Message came from the mesh\n"); - // Serial2.println("* * Message came from the mesh"); - Serial2.printf("%s", p.payload.bytes); + if (mp.from != nodeDB.getNodeNum()) { + DEBUG_MSG("Store & Forward Plugin ---------- ---------- ---------- ---------- ----------\n"); + printPacket("PACKET FROM PHONE", &mp); } } else { - DEBUG_MSG("Serial Plugin Disabled\n"); + DEBUG_MSG("Store & Forward Plugin - Disabled\n"); } #endif diff --git a/src/plugins/StoreForwardPlugin.h b/src/plugins/StoreForwardPlugin.h index e9dac9b45..952206c58 100644 --- a/src/plugins/StoreForwardPlugin.h +++ b/src/plugins/StoreForwardPlugin.h @@ -34,6 +34,7 @@ class StoreForwardPluginRadio : public SinglePortPlugin */ // SerialPluginRadio() : SinglePortPlugin("SerialPluginRadio", PortNum_TEXT_MESSAGE_APP) {} + // SerialPluginRadio() : SinglePortPlugin("SerialPluginRadio", PortNum_STORE_FORWARD_APP) {} StoreForwardPluginRadio() : SinglePortPlugin("SerialPluginRadio", PortNum_SERIAL_APP) {} /** @@ -44,6 +45,8 @@ class StoreForwardPluginRadio : public SinglePortPlugin protected: virtual MeshPacket *allocReply(); + virtual bool wantPortnum(PortNum p){return true;}; + /** Called to handle a particular incoming message @return true if you've guaranteed you've handled this message and no other handlers should be considered for it From a95f612452aa4ad2e0e3152858d9a5ffb6213451 Mon Sep 17 00:00:00 2001 From: Jm Date: Sun, 14 Feb 2021 10:56:08 -0800 Subject: [PATCH 094/258] Update StoreForwardPlugin.md --- docs/software/plugins/StoreForwardPlugin.md | 82 +++++++++++++++++++-- 1 file changed, 75 insertions(+), 7 deletions(-) diff --git a/docs/software/plugins/StoreForwardPlugin.md b/docs/software/plugins/StoreForwardPlugin.md index 571ac4ed6..3877a0c0f 100644 --- a/docs/software/plugins/StoreForwardPlugin.md +++ b/docs/software/plugins/StoreForwardPlugin.md @@ -1,14 +1,12 @@ # About - This is a work in progress and is not yet available. +This is a work in progress and is not yet available. The Store Request Plugin is an implementation of a Store and Forward system to enable resilient messaging in the event that a client device is disconnected from the main network. -Because of the increased network traffic for this overhead, it's not adviced to use this if you are duty cycle limited for your airtime usage nor is it adviced to use this for SF12. +Because of the increased network traffic for this overhead, it's not adviced to use this if you are duty cycle limited for your airtime usage nor is it adviced to use this for SF12 (Long range but Slow). -# Running notes - -This will only work on nodes that are designated as a Router. +# Requirements Initial Requirements: @@ -17,5 +15,75 @@ Initial Requirements: * * Router nodes are intended to be always online. If this plugin misses any messages, the reliability of the stored messages will be reduced * Esp32 Processor based device with external PSRAM. (tbeam v1.0 and tbeamv1.1, maybe others) -Initial Features -* \ No newline at end of file +# Implementation timeline + +Not necessarily in this order: + +UC 1) MVP - automagically forward packets to a client that may have missed packets. + +UC 2) Client Interface (Web, Android, Python or iOS when that happens) to request packets be resent + +UC 3) router sends a periodic “heartbeat” to let the clients know they’re part of the main mesh + +UC 4) support for a mesh to have multiple routers that have the store & forward functionality (for redundancy) + +# Things to consider + +Not all these cases will be initially implemented. It's just a running stream of thoughts to be considered. + +## Main Mesh Network with Router + +The store and forward plugin is intended to be enabled on a router that designates your "main" mesh network. + +## Store and Forward on Multiple Routers + +If multiple routers with the plugin are enabled, they should be able to share their stored database amongst each other. This enable resilliancy from one router going offline. + +## Fragmented networks - No router + +In this case, the mesh network has been fragmented by two client devices leaving the main network. + +If two Meshtastic devices walk away from the main mesh, they will be able to message each other but not message the main network. When they return to the main network, they will receive the messages they have missed from the main mesh network. + +## Fragmented network - With routers + +In this case, we have two routers separate by a great distance, each serving multiple devices. One of the routers have gone offline. This has now created two physically seaprated mesh networks using the same channel configuration. + +Q: How do we rejoin both fragmented networks? Do we care about messages that were unrouted between fagments? + +# Router Data Structures + +Structure of received messages: + + receivedMessages + Port_No + packetID + to + from + rxTimeMsec + data + +Structure of nodes and last time we heard from them. This is a record of any packet type. + + senderRecord + From + rxTimeMsec + +# General Operation for UC1 - automagically forward packets to a client that may have missed packets + +On every handled packet +* Record the sender from and the time we heard from that sender. + +On every handled packet + +* If the packet is a message, save the messsage into receivedMessages + +On every handled packet, if we have not heard from that sender in a period of time greater than timeAway, let's assume that they have been away from the network. + +* In this case, we will resend them all the messages they have missed since they were gone + +## Expected problems this implementation + +* If the client has been away for less than 5 minutes and has received the previously sent message, the client will gracefully ignore it. This is thanks to PacketHistory::wasSeenRecently in PacketHistory.cpp. +* * If the client has been away for more than 5 minutes and we resend packets that they have already received, it's possible they will see duplicate messages. This should be unlikely but is still possible. + From d5c1e3c6e00bf9a06140761e22bfccf45759c809 Mon Sep 17 00:00:00 2001 From: Jm Date: Sun, 14 Feb 2021 11:00:11 -0800 Subject: [PATCH 095/258] Update StoreForwardPlugin.md --- docs/software/plugins/StoreForwardPlugin.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/docs/software/plugins/StoreForwardPlugin.md b/docs/software/plugins/StoreForwardPlugin.md index 3877a0c0f..97b8f49ee 100644 --- a/docs/software/plugins/StoreForwardPlugin.md +++ b/docs/software/plugins/StoreForwardPlugin.md @@ -72,7 +72,7 @@ Structure of nodes and last time we heard from them. This is a record of any pac # General Operation for UC1 - automagically forward packets to a client that may have missed packets On every handled packet -* Record the sender from and the time we heard from that sender. +* Record the sender from and the time we heard from that sender into senderRecord. On every handled packet @@ -87,3 +87,7 @@ On every handled packet, if we have not heard from that sender in a period of ti * If the client has been away for less than 5 minutes and has received the previously sent message, the client will gracefully ignore it. This is thanks to PacketHistory::wasSeenRecently in PacketHistory.cpp. * * If the client has been away for more than 5 minutes and we resend packets that they have already received, it's possible they will see duplicate messages. This should be unlikely but is still possible. + +# Designed limitations + +The Store and Forward plugin will subscribe to specific packet types and channels and only save those. This will both reduce the amount of data we will need to store and reduce the overhead on the network. Eg: There's no need to replay ACK packets nor is there's no need to replay old location packets. \ No newline at end of file From ae46b3df329e6b3434931f98e41883d1f9f790d1 Mon Sep 17 00:00:00 2001 From: Jm Date: Sun, 14 Feb 2021 11:10:56 -0800 Subject: [PATCH 096/258] Update StoreForwardPlugin.md --- docs/software/plugins/StoreForwardPlugin.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/software/plugins/StoreForwardPlugin.md b/docs/software/plugins/StoreForwardPlugin.md index 97b8f49ee..2b3aa71ad 100644 --- a/docs/software/plugins/StoreForwardPlugin.md +++ b/docs/software/plugins/StoreForwardPlugin.md @@ -2,7 +2,7 @@ This is a work in progress and is not yet available. -The Store Request Plugin is an implementation of a Store and Forward system to enable resilient messaging in the event that a client device is disconnected from the main network. +The Store Forward Plugin is an implementation of a Store and Forward system to enable resilient messaging in the event that a client device is disconnected from the main network. Because of the increased network traffic for this overhead, it's not adviced to use this if you are duty cycle limited for your airtime usage nor is it adviced to use this for SF12 (Long range but Slow). @@ -21,7 +21,7 @@ Not necessarily in this order: UC 1) MVP - automagically forward packets to a client that may have missed packets. -UC 2) Client Interface (Web, Android, Python or iOS when that happens) to request packets be resent +UC 2) Client Interface (Web, Android, Python or iOS when that happens) to optionally request packets be resent. This is to support the case where the client may not have received the message the Router has not detected that the client was away. This is because the router will only know you're away if you've been gone for a long time but will have no way of knowing if you were offline for a few minutes. This will cover the case where you have ducked into a cave or you're swapping out your battery. UC 3) router sends a periodic “heartbeat” to let the clients know they’re part of the main mesh From f1a65f9d0e67952f0f53109f6aa823a0ff9a59d4 Mon Sep 17 00:00:00 2001 From: Jm Date: Sun, 14 Feb 2021 13:31:11 -0800 Subject: [PATCH 097/258] Update to store and forward. Don't merge this to main! --- docs/software/plugins/StoreForwardPlugin.md | 2 +- src/plugins/ExternalNotificationPlugin.cpp | 2 +- src/plugins/Plugins.cpp | 6 ++- src/plugins/RangeTestPlugin.cpp | 2 +- src/plugins/StoreForwardPlugin.cpp | 43 +++++++++------------ src/plugins/StoreForwardPlugin.h | 16 +++----- 6 files changed, 32 insertions(+), 39 deletions(-) diff --git a/docs/software/plugins/StoreForwardPlugin.md b/docs/software/plugins/StoreForwardPlugin.md index 2b3aa71ad..6761f50e6 100644 --- a/docs/software/plugins/StoreForwardPlugin.md +++ b/docs/software/plugins/StoreForwardPlugin.md @@ -21,7 +21,7 @@ Not necessarily in this order: UC 1) MVP - automagically forward packets to a client that may have missed packets. -UC 2) Client Interface (Web, Android, Python or iOS when that happens) to optionally request packets be resent. This is to support the case where the client may not have received the message the Router has not detected that the client was away. This is because the router will only know you're away if you've been gone for a long time but will have no way of knowing if you were offline for a few minutes. This will cover the case where you have ducked into a cave or you're swapping out your battery. +UC 2) Client Interface (Web, Android, Python or iOS when that happens) to optionally request packets be resent. This is to support the case where Router has not detected that the client was away. This is because the router will only know you're away if you've been gone for a period of time but will have no way of knowing if you were offline for a short number of minutes. This will cover the case where you have ducked into a cave or you're swapping out your battery. UC 3) router sends a periodic “heartbeat” to let the clients know they’re part of the main mesh diff --git a/src/plugins/ExternalNotificationPlugin.cpp b/src/plugins/ExternalNotificationPlugin.cpp index 505eff7d1..b36919fd7 100644 --- a/src/plugins/ExternalNotificationPlugin.cpp +++ b/src/plugins/ExternalNotificationPlugin.cpp @@ -6,7 +6,7 @@ #include "configuration.h" #include -#include +//#include /* diff --git a/src/plugins/Plugins.cpp b/src/plugins/Plugins.cpp index ac8dd7336..46f854106 100644 --- a/src/plugins/Plugins.cpp +++ b/src/plugins/Plugins.cpp @@ -31,7 +31,11 @@ void setupPlugins() */ new SerialPlugin(); new ExternalNotificationPlugin(); + + //rangeTestPlugin = new RangeTestPlugin(); //storeForwardPlugin = new StoreForwardPlugin(); - rangeTestPlugin = new RangeTestPlugin(); + + new RangeTestPlugin(); + new StoreForwardPlugin(); #endif } \ No newline at end of file diff --git a/src/plugins/RangeTestPlugin.cpp b/src/plugins/RangeTestPlugin.cpp index c719ad04c..f8e4f53de 100644 --- a/src/plugins/RangeTestPlugin.cpp +++ b/src/plugins/RangeTestPlugin.cpp @@ -6,7 +6,7 @@ #include "configuration.h" #include #include -#include +//#include /* As a sender, I can send packets every n-seonds. These packets include an incramented PacketID. diff --git a/src/plugins/StoreForwardPlugin.cpp b/src/plugins/StoreForwardPlugin.cpp index c82724560..633aaa5ec 100644 --- a/src/plugins/StoreForwardPlugin.cpp +++ b/src/plugins/StoreForwardPlugin.cpp @@ -6,22 +6,15 @@ #include "configuration.h" #include -#include - -#define STORE_RECORDS 5000 -#define BYTES_PER_RECORDS 512 - -#define STOREFORWARDPLUGIN_ENABLED 0 - StoreForwardPlugin *storeForwardPlugin; StoreForwardPluginRadio *storeForwardPluginRadio; -StoreForwardPlugin::StoreForwardPlugin() : concurrency::OSThread("SerialPlugin") {} - -// char serialStringChar[Constants_DATA_PAYLOAD_LEN]; +StoreForwardPlugin::StoreForwardPlugin() : concurrency::OSThread("StoreForwardPlugin") {} int32_t StoreForwardPlugin::runOnce() { +#if 0 + #ifndef NO_ESP32 /* @@ -29,15 +22,15 @@ int32_t StoreForwardPlugin::runOnce() without having to configure it from the PythonAPI or WebUI. */ - // radioConfig.preferences.store_forward_plugin_enabled = 1; - // radioConfig.preferences.store_forward_plugin_records = 80; + radioConfig.preferences.store_forward_plugin_enabled = 0; if (radioConfig.preferences.store_forward_plugin_enabled) { if (firstTime) { - // Interface with the serial peripheral from in here. DEBUG_MSG("Initializing Store & Forward Plugin\n"); + /* + */ // Router if (radioConfig.preferences.is_router) { @@ -62,8 +55,7 @@ int32_t StoreForwardPlugin::runOnce() // Non-Router } else { } - - storeForwardPluginRadio = new StoreForwardPluginRadio(); + // storeForwardPluginRadio = new StoreForwardPluginRadio(); firstTime = 0; @@ -71,7 +63,7 @@ int32_t StoreForwardPlugin::runOnce() // TBD } - return (10); + return (1000); } else { DEBUG_MSG("Store & Forward Plugin - Disabled\n"); @@ -79,6 +71,8 @@ int32_t StoreForwardPlugin::runOnce() } #endif +#endif + return (INT32_MAX); } MeshPacket *StoreForwardPluginRadio::allocReply() @@ -91,35 +85,36 @@ MeshPacket *StoreForwardPluginRadio::allocReply() void StoreForwardPluginRadio::sendPayload(NodeNum dest, bool wantReplies) { +#if 0 MeshPacket *p = allocReply(); p->to = dest; p->decoded.want_response = wantReplies; - // p->want_ack = SERIALPLUGIN_ACK; - - // p->decoded.data.payload.size = strlen(serialStringChar); // You must specify how many bytes are in the reply - // memcpy(p->decoded.data.payload.bytes, serialStringChar, p->decoded.data.payload.size); - service.sendToMesh(p); +#endif } bool StoreForwardPluginRadio::handleReceived(const MeshPacket &mp) { + +#if 0 #ifndef NO_ESP32 - if (STOREFORWARDPLUGIN_ENABLED) { + if (radioConfig.preferences.store_forward_plugin_enabled) { // auto &p = mp.decoded.data; if (mp.from != nodeDB.getNodeNum()) { - DEBUG_MSG("Store & Forward Plugin ---------- ---------- ---------- ---------- ----------\n"); - printPacket("PACKET FROM PHONE", &mp); + DEBUG_MSG("Store & Forward Plugin -- Print Start ---------- ---------- ---------- ---------- ----------\n"); + printPacket("PACKET FROM RADIO", &mp); + DEBUG_MSG("Store & Forward Plugin -- Print End ---------- ---------- ---------- ---------- ----------\n"); } } else { DEBUG_MSG("Store & Forward Plugin - Disabled\n"); } +#endif #endif return true; // Let others look at this message also if they want diff --git a/src/plugins/StoreForwardPlugin.h b/src/plugins/StoreForwardPlugin.h index 952206c58..f40c7aa41 100644 --- a/src/plugins/StoreForwardPlugin.h +++ b/src/plugins/StoreForwardPlugin.h @@ -20,22 +20,16 @@ class StoreForwardPlugin : private concurrency::OSThread extern StoreForwardPlugin *storeForwardPlugin; /* - * Radio interface for SerialPlugin + * Radio interface for StoreForwardPlugin * */ class StoreForwardPluginRadio : public SinglePortPlugin { - uint32_t lastRxID; + //uint32_t lastRxID; public: - /* - TODO: Switch this to PortNum_SERIAL_APP once the change is able to be merged back here - from the main code. - */ - - // SerialPluginRadio() : SinglePortPlugin("SerialPluginRadio", PortNum_TEXT_MESSAGE_APP) {} - // SerialPluginRadio() : SinglePortPlugin("SerialPluginRadio", PortNum_STORE_FORWARD_APP) {} - StoreForwardPluginRadio() : SinglePortPlugin("SerialPluginRadio", PortNum_SERIAL_APP) {} + StoreForwardPluginRadio() : SinglePortPlugin("StoreForwardPluginRadio", PortNum_STORE_FORWARD_APP) {} + //StoreForwardPluginRadio() : SinglePortPlugin("StoreForwardPluginRadio", PortNum_TEXT_MESSAGE_APP) {} /** * Send our payload into the mesh @@ -45,7 +39,7 @@ class StoreForwardPluginRadio : public SinglePortPlugin protected: virtual MeshPacket *allocReply(); - virtual bool wantPortnum(PortNum p){return true;}; + //virtual bool wantPortnum(PortNum p){return true;}; /** Called to handle a particular incoming message From 24329a26dee2f09c11c491a597f247678ba46ac4 Mon Sep 17 00:00:00 2001 From: Jm Date: Sun, 14 Feb 2021 14:01:08 -0800 Subject: [PATCH 098/258] Framework for storeforward --- src/plugins/RangeTestPlugin.cpp | 1 - src/plugins/StoreForwardPlugin.cpp | 65 +++++------------------------- src/plugins/StoreForwardPlugin.h | 12 ++---- 3 files changed, 12 insertions(+), 66 deletions(-) diff --git a/src/plugins/RangeTestPlugin.cpp b/src/plugins/RangeTestPlugin.cpp index f8e4f53de..a1c69b101 100644 --- a/src/plugins/RangeTestPlugin.cpp +++ b/src/plugins/RangeTestPlugin.cpp @@ -41,7 +41,6 @@ int32_t RangeTestPlugin::runOnce() // Fixed position is useful when testing indoors. // radioConfig.preferences.fixed_position = 1; - uint32_t senderHeartbeat = radioConfig.preferences.range_test_plugin_sender * 1000; if (radioConfig.preferences.range_test_plugin_enabled) { diff --git a/src/plugins/StoreForwardPlugin.cpp b/src/plugins/StoreForwardPlugin.cpp index 633aaa5ec..2db4d7358 100644 --- a/src/plugins/StoreForwardPlugin.cpp +++ b/src/plugins/StoreForwardPlugin.cpp @@ -6,6 +6,10 @@ #include "configuration.h" #include +#include + + + StoreForwardPlugin *storeForwardPlugin; StoreForwardPluginRadio *storeForwardPluginRadio; @@ -13,8 +17,6 @@ StoreForwardPlugin::StoreForwardPlugin() : concurrency::OSThread("StoreForwardPl int32_t StoreForwardPlugin::runOnce() { -#if 0 - #ifndef NO_ESP32 /* @@ -22,57 +24,27 @@ int32_t StoreForwardPlugin::runOnce() without having to configure it from the PythonAPI or WebUI. */ - radioConfig.preferences.store_forward_plugin_enabled = 0; - - if (radioConfig.preferences.store_forward_plugin_enabled) { + if (0) { if (firstTime) { - DEBUG_MSG("Initializing Store & Forward Plugin\n"); - /* - */ - // Router - if (radioConfig.preferences.is_router) { - if (ESP.getPsramSize()) { - if (ESP.getFreePsram() <= 1024 * 1024) { - // Do the startup here - - } else { - DEBUG_MSG("Device has less than 1M of PSRAM free. Aborting startup.\n"); - DEBUG_MSG("Store & Forward Plugin - Aborting Startup.\n"); - - return (INT32_MAX); - } - - } else { - DEBUG_MSG("Device doesn't have PSRAM.\n"); - DEBUG_MSG("Store & Forward Plugin - Aborting Startup.\n"); - - return (INT32_MAX); - } - - // Non-Router - } else { - } - // storeForwardPluginRadio = new StoreForwardPluginRadio(); + storeForwardPluginRadio = new StoreForwardPluginRadio(); firstTime = 0; } else { - // TBD + } - return (1000); + return (10); } else { - DEBUG_MSG("Store & Forward Plugin - Disabled\n"); + DEBUG_MSG("StoreForwardPlugin Disabled\n"); return (INT32_MAX); } #endif -#endif - return (INT32_MAX); } MeshPacket *StoreForwardPluginRadio::allocReply() @@ -82,39 +54,20 @@ MeshPacket *StoreForwardPluginRadio::allocReply() return reply; } - void StoreForwardPluginRadio::sendPayload(NodeNum dest, bool wantReplies) { -#if 0 MeshPacket *p = allocReply(); p->to = dest; p->decoded.want_response = wantReplies; service.sendToMesh(p); -#endif } bool StoreForwardPluginRadio::handleReceived(const MeshPacket &mp) { - -#if 0 #ifndef NO_ESP32 - if (radioConfig.preferences.store_forward_plugin_enabled) { - // auto &p = mp.decoded.data; - - if (mp.from != nodeDB.getNodeNum()) { - DEBUG_MSG("Store & Forward Plugin -- Print Start ---------- ---------- ---------- ---------- ----------\n"); - printPacket("PACKET FROM RADIO", &mp); - DEBUG_MSG("Store & Forward Plugin -- Print End ---------- ---------- ---------- ---------- ----------\n"); - } - - } else { - DEBUG_MSG("Store & Forward Plugin - Disabled\n"); - } - -#endif #endif return true; // Let others look at this message also if they want diff --git a/src/plugins/StoreForwardPlugin.h b/src/plugins/StoreForwardPlugin.h index f40c7aa41..1a27222f4 100644 --- a/src/plugins/StoreForwardPlugin.h +++ b/src/plugins/StoreForwardPlugin.h @@ -19,17 +19,13 @@ class StoreForwardPlugin : private concurrency::OSThread extern StoreForwardPlugin *storeForwardPlugin; -/* - * Radio interface for StoreForwardPlugin - * - */ class StoreForwardPluginRadio : public SinglePortPlugin { - //uint32_t lastRxID; + uint32_t lastRxID; public: - StoreForwardPluginRadio() : SinglePortPlugin("StoreForwardPluginRadio", PortNum_STORE_FORWARD_APP) {} - //StoreForwardPluginRadio() : SinglePortPlugin("StoreForwardPluginRadio", PortNum_TEXT_MESSAGE_APP) {} + + StoreForwardPluginRadio() : SinglePortPlugin("StoreForwardPluginRadio", PortNum_TEXT_MESSAGE_APP) {} /** * Send our payload into the mesh @@ -39,8 +35,6 @@ class StoreForwardPluginRadio : public SinglePortPlugin protected: virtual MeshPacket *allocReply(); - //virtual bool wantPortnum(PortNum p){return true;}; - /** Called to handle a particular incoming message @return true if you've guaranteed you've handled this message and no other handlers should be considered for it From b8adaf6fbe9bf0b943a59623f1b9da8655a14860 Mon Sep 17 00:00:00 2001 From: Jm Date: Sun, 14 Feb 2021 16:17:40 -0800 Subject: [PATCH 099/258] #671 Range test plugin --- src/plugins/Plugins.cpp | 2 +- src/plugins/RangeTestPlugin.cpp | 62 ++++++------ src/plugins/StoreForwardPlugin-old.cpp | 125 +++++++++++++++++++++++++ src/plugins/StoreForwardPlugin-old.h | 55 +++++++++++ 4 files changed, 216 insertions(+), 28 deletions(-) create mode 100644 src/plugins/StoreForwardPlugin-old.cpp create mode 100644 src/plugins/StoreForwardPlugin-old.h diff --git a/src/plugins/Plugins.cpp b/src/plugins/Plugins.cpp index 46f854106..6fe1459f2 100644 --- a/src/plugins/Plugins.cpp +++ b/src/plugins/Plugins.cpp @@ -36,6 +36,6 @@ void setupPlugins() //storeForwardPlugin = new StoreForwardPlugin(); new RangeTestPlugin(); - new StoreForwardPlugin(); + //new StoreForwardPlugin(); #endif } \ No newline at end of file diff --git a/src/plugins/RangeTestPlugin.cpp b/src/plugins/RangeTestPlugin.cpp index a1c69b101..7f99070ec 100644 --- a/src/plugins/RangeTestPlugin.cpp +++ b/src/plugins/RangeTestPlugin.cpp @@ -153,12 +153,12 @@ bool RangeTestPluginRadio::handleReceived(const MeshPacket &mp) DEBUG_MSG("mp.from %d\n", mp.from); DEBUG_MSG("mp.rx_snr %f\n", mp.rx_snr); DEBUG_MSG("mp.hop_limit %d\n", mp.hop_limit); - DEBUG_MSG("mp.decoded.position.latitude_i %d\n", mp.decoded.position.latitude_i); - DEBUG_MSG("mp.decoded.position.longitude_i %d\n", mp.decoded.position.longitude_i); + // DEBUG_MSG("mp.decoded.position.latitude_i %d\n", mp.decoded.position.latitude_i); // Depricated + // DEBUG_MSG("mp.decoded.position.longitude_i %d\n", mp.decoded.position.longitude_i); // Depricated DEBUG_MSG("---- Node Information of Received Packet (mp.from):\n"); DEBUG_MSG("n->user.long_name %s\n", n->user.long_name); DEBUG_MSG("n->user.short_name %s\n", n->user.short_name); - DEBUG_MSG("n->user.macaddr %X\n", n->user.macaddr); + // DEBUG_MSG("n->user.macaddr %X\n", n->user.macaddr); DEBUG_MSG("n->has_position %d\n", n->has_position); DEBUG_MSG("n->position.latitude_i %d\n", n->position.latitude_i); DEBUG_MSG("n->position.longitude_i %d\n", n->position.longitude_i); @@ -241,22 +241,25 @@ bool RangeTestPluginRadio::appendFile(const MeshPacket &mp) return 0; } - //--------- Write to file - File fileToWrite = SPIFFS.open("/static/rangetest.csv", FILE_WRITE); + // If the file doesn't exist, write the header. + if (!SPIFFS.exists("/static/rangetest.csv")) { + //--------- Write to file + File fileToWrite = SPIFFS.open("/static/rangetest.csv", FILE_WRITE); - if (!fileToWrite) { - DEBUG_MSG("There was an error opening the file for writing\n"); - return 0; + if (!fileToWrite) { + DEBUG_MSG("There was an error opening the file for writing\n"); + return 0; + } + + if (fileToWrite.println("time,from,sender name,sender lat,sender long,rx lat,rx long,rx snr,distance,payload")) { + DEBUG_MSG("File was written\n"); + } else { + DEBUG_MSG("File write failed\n"); + } + + fileToWrite.close(); } - if (fileToWrite.println("time,sender mac,rx snr,sender lat,sender long,rx lat,rx long,distance,payload")) { - DEBUG_MSG("File was written\n"); - } else { - DEBUG_MSG("File write failed\n"); - } - - fileToWrite.close(); - //--------- Apend content to file File fileToAppend = SPIFFS.open("/static/rangetest.csv", FILE_APPEND); @@ -278,21 +281,26 @@ bool RangeTestPluginRadio::appendFile(const MeshPacket &mp) int min = (hms % SEC_PER_HOUR) / SEC_PER_MIN; int sec = (hms % SEC_PER_HOUR) % SEC_PER_MIN; // or hms % SEC_PER_MIN - fileToAppend.printf("%02d:%02d:%02d ", hour, min, sec); // Time + fileToAppend.printf("%02d:%02d:%02d,", hour, min, sec); // Time } else { - fileToAppend.printf("??:??:?? "); // Time + fileToAppend.printf("??:??:??,"); // Time } - fileToAppend.printf("$X,", n->user.macaddr); // Mac Address - fileToAppend.printf("%f,", mp.rx_snr); // RX SNR - fileToAppend.printf("%d,", n->position.latitude_i); // Sender Lat - fileToAppend.printf("%d,", n->position.longitude_i); // Sender Long - fileToAppend.printf("%d,", gpsStatus->getLatitude()); // RX Lat - fileToAppend.printf("%d,", gpsStatus->getLongitude()); // RX Long + fileToAppend.printf("%d,", mp.from); // From + fileToAppend.printf("%s,", n->user.long_name); // Long Name + fileToAppend.printf("%f,", n->position.latitude_i * 1e-7); // Sender Lat + fileToAppend.printf("%f,", n->position.longitude_i * 1e-7); // Sender Long + fileToAppend.printf("%f,", gpsStatus->getLatitude() * 1e-7); // RX Lat + fileToAppend.printf("%f,", gpsStatus->getLongitude() * 1e-7); // RX Long + fileToAppend.printf("%f,", mp.rx_snr); // RX SNR - float distance = latLongToMeter(n->position.latitude_i * 1e-7, n->position.longitude_i * 1e-7, - gpsStatus->getLatitude() * 1e-7, gpsStatus->getLongitude() * 1e-7); - fileToAppend.printf("%f,", distance); // Distance in meters + if (n->position.latitude_i && n->position.longitude_i && gpsStatus->getLatitude() && gpsStatus->getLongitude()) { + float distance = latLongToMeter(n->position.latitude_i * 1e-7, n->position.longitude_i * 1e-7, + gpsStatus->getLatitude() * 1e-7, gpsStatus->getLongitude() * 1e-7); + fileToAppend.printf("%f,", distance); // Distance in meters + } else { + fileToAppend.printf("0,"); + } // TODO: If quotes are found in the payload, it has to be escaped. fileToAppend.printf("\"%s\"\n", p.payload.bytes); diff --git a/src/plugins/StoreForwardPlugin-old.cpp b/src/plugins/StoreForwardPlugin-old.cpp new file mode 100644 index 000000000..3df421af6 --- /dev/null +++ b/src/plugins/StoreForwardPlugin-old.cpp @@ -0,0 +1,125 @@ +#if 0 + +#include "StoreForwardPlugin.h" +#include "MeshService.h" +#include "NodeDB.h" +#include "RTC.h" +#include "Router.h" +#include "configuration.h" +#include + +StoreForwardPlugin *storeForwardPlugin; +StoreForwardPluginRadio *storeForwardPluginRadio; + +StoreForwardPlugin::StoreForwardPlugin() : concurrency::OSThread("StoreForwardPlugin") {} + +int32_t StoreForwardPlugin::runOnce() +{ +#if 0 + +#ifndef NO_ESP32 + + /* + Uncomment the preferences below if you want to use the plugin + without having to configure it from the PythonAPI or WebUI. + */ + + radioConfig.preferences.store_forward_plugin_enabled = 0; + + if (radioConfig.preferences.store_forward_plugin_enabled) { + + if (firstTime) { + + DEBUG_MSG("Initializing Store & Forward Plugin\n"); + /* + */ + + // Router + if (radioConfig.preferences.is_router) { + if (ESP.getPsramSize()) { + if (ESP.getFreePsram() <= 1024 * 1024) { + // Do the startup here + + } else { + DEBUG_MSG("Device has less than 1M of PSRAM free. Aborting startup.\n"); + DEBUG_MSG("Store & Forward Plugin - Aborting Startup.\n"); + + return (INT32_MAX); + } + + } else { + DEBUG_MSG("Device doesn't have PSRAM.\n"); + DEBUG_MSG("Store & Forward Plugin - Aborting Startup.\n"); + + return (INT32_MAX); + } + + // Non-Router + } else { + } + // storeForwardPluginRadio = new StoreForwardPluginRadio(); + + firstTime = 0; + + } else { + // TBD + } + + return (1000); + } else { + DEBUG_MSG("Store & Forward Plugin - Disabled\n"); + + return (INT32_MAX); + } + +#endif +#endif + return (INT32_MAX); +} + +MeshPacket *StoreForwardPluginRadio::allocReply() +{ + + auto reply = allocDataPacket(); // Allocate a packet for sending + + return reply; +} + +void StoreForwardPluginRadio::sendPayload(NodeNum dest, bool wantReplies) +{ +#if 0 + MeshPacket *p = allocReply(); + p->to = dest; + p->decoded.want_response = wantReplies; + + service.sendToMesh(p); +#endif +} + +bool StoreForwardPluginRadio::handleReceived(const MeshPacket &mp) +{ + +#if 0 +#ifndef NO_ESP32 + + if (radioConfig.preferences.store_forward_plugin_enabled) { + + // auto &p = mp.decoded.data; + + if (mp.from != nodeDB.getNodeNum()) { + DEBUG_MSG("Store & Forward Plugin -- Print Start ---------- ---------- ---------- ---------- ----------\n"); + printPacket("PACKET FROM RADIO", &mp); + DEBUG_MSG("Store & Forward Plugin -- Print End ---------- ---------- ---------- ---------- ----------\n"); + } + + } else { + DEBUG_MSG("Store & Forward Plugin - Disabled\n"); + } + +#endif +#endif + + return true; // Let others look at this message also if they want +} + +#endif \ No newline at end of file diff --git a/src/plugins/StoreForwardPlugin-old.h b/src/plugins/StoreForwardPlugin-old.h new file mode 100644 index 000000000..29d11ea7d --- /dev/null +++ b/src/plugins/StoreForwardPlugin-old.h @@ -0,0 +1,55 @@ +#if 0 + +#pragma once + +#include "SinglePortPlugin.h" +#include "concurrency/OSThread.h" +#include "configuration.h" +#include +#include + +class StoreForwardPlugin : private concurrency::OSThread +{ + bool firstTime = 1; + + public: + StoreForwardPlugin(); + + protected: + virtual int32_t runOnce(); +}; + +extern StoreForwardPlugin *storeForwardPlugin; + +/* + * Radio interface for StoreForwardPlugin + * + */ +class StoreForwardPluginRadio : public SinglePortPlugin +{ + //uint32_t lastRxID; + + public: + StoreForwardPluginRadio() : SinglePortPlugin("StoreForwardPluginRadio", PortNum_STORE_FORWARD_APP) {} + //StoreForwardPluginRadio() : SinglePortPlugin("StoreForwardPluginRadio", PortNum_TEXT_MESSAGE_APP) {} + + /** + * Send our payload into the mesh + */ + void sendPayload(NodeNum dest = NODENUM_BROADCAST, bool wantReplies = false); + + protected: + virtual MeshPacket *allocReply(); + + //virtual bool wantPortnum(PortNum p){return true;}; + + /** Called to handle a particular incoming message + + @return true if you've guaranteed you've handled this message and no other handlers should be considered for it + */ + virtual bool handleReceived(const MeshPacket &mp); +}; + +extern StoreForwardPluginRadio *storeForwardPluginRadio; + +#endif \ No newline at end of file From 3311146abaf1524209a3d4c888d64c20961c8987 Mon Sep 17 00:00:00 2001 From: Jm Date: Sun, 14 Feb 2021 16:19:06 -0800 Subject: [PATCH 100/258] Turning storeforward back on for @geeksville --- src/plugins/Plugins.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/Plugins.cpp b/src/plugins/Plugins.cpp index 6fe1459f2..46f854106 100644 --- a/src/plugins/Plugins.cpp +++ b/src/plugins/Plugins.cpp @@ -36,6 +36,6 @@ void setupPlugins() //storeForwardPlugin = new StoreForwardPlugin(); new RangeTestPlugin(); - //new StoreForwardPlugin(); + new StoreForwardPlugin(); #endif } \ No newline at end of file From e6605e5ac8654055476a04553430061ad5ff8e96 Mon Sep 17 00:00:00 2001 From: Jm Date: Sun, 14 Feb 2021 20:13:52 -0800 Subject: [PATCH 101/258] Store Forward can see All(?) rx packets! --- src/plugins/Plugins.cpp | 4 +- src/plugins/StoreForwardPlugin-old.cpp | 125 ------------------------- src/plugins/StoreForwardPlugin-old.h | 55 ----------- src/plugins/StoreForwardPlugin.cpp | 62 ++++++++++-- src/plugins/StoreForwardPlugin.h | 15 ++- 5 files changed, 65 insertions(+), 196 deletions(-) delete mode 100644 src/plugins/StoreForwardPlugin-old.cpp delete mode 100644 src/plugins/StoreForwardPlugin-old.h diff --git a/src/plugins/Plugins.cpp b/src/plugins/Plugins.cpp index 46f854106..69e68ea4f 100644 --- a/src/plugins/Plugins.cpp +++ b/src/plugins/Plugins.cpp @@ -33,9 +33,9 @@ void setupPlugins() new ExternalNotificationPlugin(); //rangeTestPlugin = new RangeTestPlugin(); - //storeForwardPlugin = new StoreForwardPlugin(); + storeForwardPlugin = new StoreForwardPlugin(); new RangeTestPlugin(); - new StoreForwardPlugin(); + //new StoreForwardPlugin(); #endif } \ No newline at end of file diff --git a/src/plugins/StoreForwardPlugin-old.cpp b/src/plugins/StoreForwardPlugin-old.cpp deleted file mode 100644 index 3df421af6..000000000 --- a/src/plugins/StoreForwardPlugin-old.cpp +++ /dev/null @@ -1,125 +0,0 @@ -#if 0 - -#include "StoreForwardPlugin.h" -#include "MeshService.h" -#include "NodeDB.h" -#include "RTC.h" -#include "Router.h" -#include "configuration.h" -#include - -StoreForwardPlugin *storeForwardPlugin; -StoreForwardPluginRadio *storeForwardPluginRadio; - -StoreForwardPlugin::StoreForwardPlugin() : concurrency::OSThread("StoreForwardPlugin") {} - -int32_t StoreForwardPlugin::runOnce() -{ -#if 0 - -#ifndef NO_ESP32 - - /* - Uncomment the preferences below if you want to use the plugin - without having to configure it from the PythonAPI or WebUI. - */ - - radioConfig.preferences.store_forward_plugin_enabled = 0; - - if (radioConfig.preferences.store_forward_plugin_enabled) { - - if (firstTime) { - - DEBUG_MSG("Initializing Store & Forward Plugin\n"); - /* - */ - - // Router - if (radioConfig.preferences.is_router) { - if (ESP.getPsramSize()) { - if (ESP.getFreePsram() <= 1024 * 1024) { - // Do the startup here - - } else { - DEBUG_MSG("Device has less than 1M of PSRAM free. Aborting startup.\n"); - DEBUG_MSG("Store & Forward Plugin - Aborting Startup.\n"); - - return (INT32_MAX); - } - - } else { - DEBUG_MSG("Device doesn't have PSRAM.\n"); - DEBUG_MSG("Store & Forward Plugin - Aborting Startup.\n"); - - return (INT32_MAX); - } - - // Non-Router - } else { - } - // storeForwardPluginRadio = new StoreForwardPluginRadio(); - - firstTime = 0; - - } else { - // TBD - } - - return (1000); - } else { - DEBUG_MSG("Store & Forward Plugin - Disabled\n"); - - return (INT32_MAX); - } - -#endif -#endif - return (INT32_MAX); -} - -MeshPacket *StoreForwardPluginRadio::allocReply() -{ - - auto reply = allocDataPacket(); // Allocate a packet for sending - - return reply; -} - -void StoreForwardPluginRadio::sendPayload(NodeNum dest, bool wantReplies) -{ -#if 0 - MeshPacket *p = allocReply(); - p->to = dest; - p->decoded.want_response = wantReplies; - - service.sendToMesh(p); -#endif -} - -bool StoreForwardPluginRadio::handleReceived(const MeshPacket &mp) -{ - -#if 0 -#ifndef NO_ESP32 - - if (radioConfig.preferences.store_forward_plugin_enabled) { - - // auto &p = mp.decoded.data; - - if (mp.from != nodeDB.getNodeNum()) { - DEBUG_MSG("Store & Forward Plugin -- Print Start ---------- ---------- ---------- ---------- ----------\n"); - printPacket("PACKET FROM RADIO", &mp); - DEBUG_MSG("Store & Forward Plugin -- Print End ---------- ---------- ---------- ---------- ----------\n"); - } - - } else { - DEBUG_MSG("Store & Forward Plugin - Disabled\n"); - } - -#endif -#endif - - return true; // Let others look at this message also if they want -} - -#endif \ No newline at end of file diff --git a/src/plugins/StoreForwardPlugin-old.h b/src/plugins/StoreForwardPlugin-old.h deleted file mode 100644 index 29d11ea7d..000000000 --- a/src/plugins/StoreForwardPlugin-old.h +++ /dev/null @@ -1,55 +0,0 @@ -#if 0 - -#pragma once - -#include "SinglePortPlugin.h" -#include "concurrency/OSThread.h" -#include "configuration.h" -#include -#include - -class StoreForwardPlugin : private concurrency::OSThread -{ - bool firstTime = 1; - - public: - StoreForwardPlugin(); - - protected: - virtual int32_t runOnce(); -}; - -extern StoreForwardPlugin *storeForwardPlugin; - -/* - * Radio interface for StoreForwardPlugin - * - */ -class StoreForwardPluginRadio : public SinglePortPlugin -{ - //uint32_t lastRxID; - - public: - StoreForwardPluginRadio() : SinglePortPlugin("StoreForwardPluginRadio", PortNum_STORE_FORWARD_APP) {} - //StoreForwardPluginRadio() : SinglePortPlugin("StoreForwardPluginRadio", PortNum_TEXT_MESSAGE_APP) {} - - /** - * Send our payload into the mesh - */ - void sendPayload(NodeNum dest = NODENUM_BROADCAST, bool wantReplies = false); - - protected: - virtual MeshPacket *allocReply(); - - //virtual bool wantPortnum(PortNum p){return true;}; - - /** Called to handle a particular incoming message - - @return true if you've guaranteed you've handled this message and no other handlers should be considered for it - */ - virtual bool handleReceived(const MeshPacket &mp); -}; - -extern StoreForwardPluginRadio *storeForwardPluginRadio; - -#endif \ No newline at end of file diff --git a/src/plugins/StoreForwardPlugin.cpp b/src/plugins/StoreForwardPlugin.cpp index 2db4d7358..087b34c1c 100644 --- a/src/plugins/StoreForwardPlugin.cpp +++ b/src/plugins/StoreForwardPlugin.cpp @@ -6,10 +6,6 @@ #include "configuration.h" #include -#include - - - StoreForwardPlugin *storeForwardPlugin; StoreForwardPluginRadio *storeForwardPluginRadio; @@ -17,6 +13,7 @@ StoreForwardPlugin::StoreForwardPlugin() : concurrency::OSThread("StoreForwardPl int32_t StoreForwardPlugin::runOnce() { + #ifndef NO_ESP32 /* @@ -24,27 +21,60 @@ int32_t StoreForwardPlugin::runOnce() without having to configure it from the PythonAPI or WebUI. */ - if (0) { + radioConfig.preferences.store_forward_plugin_enabled = 1; + radioConfig.preferences.is_router = 0; + + if (radioConfig.preferences.store_forward_plugin_enabled) { if (firstTime) { + /* + */ - storeForwardPluginRadio = new StoreForwardPluginRadio(); + if (radioConfig.preferences.is_router) { + DEBUG_MSG("Initializing Store & Forward Plugin - Enabled\n"); + // Router + if (ESP.getPsramSize()) { + if (ESP.getFreePsram() >= 1024 * 1024) { + // Do the startup here + storeForwardPluginRadio = new StoreForwardPluginRadio(); - firstTime = 0; + firstTime = 0; + + } else { + DEBUG_MSG("Device has less than 1M of PSRAM free. Aborting startup.\n"); + DEBUG_MSG("Store & Forward Plugin - Aborting Startup.\n"); + + return (INT32_MAX); + } + + } else { + DEBUG_MSG("Device doesn't have PSRAM.\n"); + DEBUG_MSG("Store & Forward Plugin - Aborting Startup.\n"); + + return (INT32_MAX); + } + + } else { + DEBUG_MSG("Initializing Store & Forward Plugin - Enabled but is_router is not turned on.\n"); + DEBUG_MSG( + "Initializing Store & Forward Plugin - If you want to use this plugin, you must also turn on is_router.\n"); + // Non-Router + } } else { - + // TBD } - return (10); + return (1000); } else { - DEBUG_MSG("StoreForwardPlugin Disabled\n"); + DEBUG_MSG("Store & Forward Plugin - Disabled\n"); return (INT32_MAX); } #endif + return (INT32_MAX); } MeshPacket *StoreForwardPluginRadio::allocReply() @@ -54,6 +84,7 @@ MeshPacket *StoreForwardPluginRadio::allocReply() return reply; } + void StoreForwardPluginRadio::sendPayload(NodeNum dest, bool wantReplies) { MeshPacket *p = allocReply(); @@ -66,7 +97,18 @@ void StoreForwardPluginRadio::sendPayload(NodeNum dest, bool wantReplies) bool StoreForwardPluginRadio::handleReceived(const MeshPacket &mp) { #ifndef NO_ESP32 + if (radioConfig.preferences.store_forward_plugin_enabled) { + // auto &p = mp.decoded.data; + if (mp.from != nodeDB.getNodeNum()) { + DEBUG_MSG("Store & Forward Plugin -- Print Start ---------- ---------- ---------- ---------- ----------\n"); + printPacket("----- PACKET FROM RADIO", &mp); + DEBUG_MSG("Store & Forward Plugin -- Print End ---------- ---------- ---------- ---------- ----------\n"); + } + + } else { + DEBUG_MSG("Store & Forward Plugin - Disabled\n"); + } #endif diff --git a/src/plugins/StoreForwardPlugin.h b/src/plugins/StoreForwardPlugin.h index 1a27222f4..be9634913 100644 --- a/src/plugins/StoreForwardPlugin.h +++ b/src/plugins/StoreForwardPlugin.h @@ -19,13 +19,17 @@ class StoreForwardPlugin : private concurrency::OSThread extern StoreForwardPlugin *storeForwardPlugin; +/* + * Radio interface for StoreForwardPlugin + * + */ class StoreForwardPluginRadio : public SinglePortPlugin { - uint32_t lastRxID; + //uint32_t lastRxID; public: - - StoreForwardPluginRadio() : SinglePortPlugin("StoreForwardPluginRadio", PortNum_TEXT_MESSAGE_APP) {} + StoreForwardPluginRadio() : SinglePortPlugin("StoreForwardPluginRadio", PortNum_STORE_FORWARD_APP) {} + //StoreForwardPluginRadio() : SinglePortPlugin("StoreForwardPluginRadio", PortNum_TEXT_MESSAGE_APP) {} /** * Send our payload into the mesh @@ -35,6 +39,8 @@ class StoreForwardPluginRadio : public SinglePortPlugin protected: virtual MeshPacket *allocReply(); + virtual bool wantPortnum(PortNum p){return true;}; + /** Called to handle a particular incoming message @return true if you've guaranteed you've handled this message and no other handlers should be considered for it @@ -42,4 +48,5 @@ class StoreForwardPluginRadio : public SinglePortPlugin virtual bool handleReceived(const MeshPacket &mp); }; -extern StoreForwardPluginRadio *storeForwardPluginRadio; \ No newline at end of file +extern StoreForwardPluginRadio *storeForwardPluginRadio; + From 7d4ce483c5e3928f4281b916fbaaf9a0ac071aa6 Mon Sep 17 00:00:00 2001 From: Jm Date: Sun, 14 Feb 2021 20:16:29 -0800 Subject: [PATCH 102/258] Update RangeTestPlugin.md --- docs/software/plugins/RangeTestPlugin.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docs/software/plugins/RangeTestPlugin.md b/docs/software/plugins/RangeTestPlugin.md index 9fd9b2724..998ce4f06 100644 --- a/docs/software/plugins/RangeTestPlugin.md +++ b/docs/software/plugins/RangeTestPlugin.md @@ -38,6 +38,10 @@ To save a log of the messages: range_test_plugin_save = 1 +Be sure to turn off either the plugin configured as a sender or the device where the plugin setup as sender when not in use. This will use a lot of time on air and will spam your channel. + +Also be mindful of your space usage on the file system. It has protections from filling up the space but it's best to delete old range test results. + # Known Problems From fea2228b16f822a3e23f2e90ef326162c0cf495d Mon Sep 17 00:00:00 2001 From: Jm Date: Sun, 14 Feb 2021 20:17:16 -0800 Subject: [PATCH 103/258] Update RangeTestPlugin.md --- docs/software/plugins/RangeTestPlugin.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/software/plugins/RangeTestPlugin.md b/docs/software/plugins/RangeTestPlugin.md index 998ce4f06..58baff1e5 100644 --- a/docs/software/plugins/RangeTestPlugin.md +++ b/docs/software/plugins/RangeTestPlugin.md @@ -38,6 +38,8 @@ To save a log of the messages: range_test_plugin_save = 1 +## Other things to keep in mind + Be sure to turn off either the plugin configured as a sender or the device where the plugin setup as sender when not in use. This will use a lot of time on air and will spam your channel. Also be mindful of your space usage on the file system. It has protections from filling up the space but it's best to delete old range test results. @@ -49,7 +51,7 @@ Also be mindful of your space usage on the file system. It has protections from # TODO -* Right now range test messages go over the TEXT_MESSAGE_APP port. We need a toggle to switch to RANGE_TEST_APP. +* Right now range test messages go over the TEXT_MESSAGE_APP port. We need a toggle to switch to optionally send over RANGE_TEST_APP. # Need more help? From c9353ebee34dcc186746879dfba2937502039356 Mon Sep 17 00:00:00 2001 From: Jm Date: Sun, 14 Feb 2021 21:24:41 -0800 Subject: [PATCH 104/258] Update RangeTestPlugin.md --- docs/software/plugins/RangeTestPlugin.md | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/docs/software/plugins/RangeTestPlugin.md b/docs/software/plugins/RangeTestPlugin.md index 58baff1e5..ba9f006f2 100644 --- a/docs/software/plugins/RangeTestPlugin.md +++ b/docs/software/plugins/RangeTestPlugin.md @@ -53,6 +53,26 @@ Also be mindful of your space usage on the file system. It has protections from * Right now range test messages go over the TEXT_MESSAGE_APP port. We need a toggle to switch to optionally send over RANGE_TEST_APP. +# FAQ + +Q: Where is rangetest.csv saved? +A: Turn on the WiFi on your device as either a WiFi client or a WiFi AP. Once you can connect to your device, go to /static and you will see rangetest.csv. + +Q: Do I need to have WiFi turned on for the file to be saved? +A: Nope, it'll just work. + +Q: Do I need a phone for this plugin? +A: There's no need for a phone. + +Q: Can I use this as a message logger? +A: While it's not the intended purpose, sure, why not. Do it! + +Q: What will happen if I run out of space on my device? +A: We have a protection in place to keep you from completly filling up your device. This will make sure that other device critical functions will continue to work. We will reserve at least 50k of free space. + +Q: What do I do with the rangetest.csv file when I'm done? +A: Go to /static and delete the file. + # Need more help? Go to the Meshtastic Discourse Group if you have any questions or to share how you have used this. From 703ce2e292eca62ccfaa7a1afa282b0d9974989c Mon Sep 17 00:00:00 2001 From: Jm Date: Sun, 14 Feb 2021 21:34:47 -0800 Subject: [PATCH 105/258] Keep device from sleeping while transmitting in range test plugin. --- docs/software/plugins/RangeTestPlugin.md | 3 +++ src/plugins/RangeTestPlugin.cpp | 4 ++++ 2 files changed, 7 insertions(+) diff --git a/docs/software/plugins/RangeTestPlugin.md b/docs/software/plugins/RangeTestPlugin.md index ba9f006f2..14a43d292 100644 --- a/docs/software/plugins/RangeTestPlugin.md +++ b/docs/software/plugins/RangeTestPlugin.md @@ -73,6 +73,9 @@ A: We have a protection in place to keep you from completly filling up your devi Q: What do I do with the rangetest.csv file when I'm done? A: Go to /static and delete the file. +Q: Can I use this as a sender while on battery power? +A: Yes, but your battery will run down quicker than normal. While sending, we tell the device not to go into low-power mode since it needs to keep to a fairly strict timer. + # Need more help? Go to the Meshtastic Discourse Group if you have any questions or to share how you have used this. diff --git a/src/plugins/RangeTestPlugin.cpp b/src/plugins/RangeTestPlugin.cpp index 7f99070ec..a789357d1 100644 --- a/src/plugins/RangeTestPlugin.cpp +++ b/src/plugins/RangeTestPlugin.cpp @@ -1,6 +1,7 @@ #include "RangeTestPlugin.h" #include "MeshService.h" #include "NodeDB.h" +#include "PowerFSM.h" #include "RTC.h" #include "Router.h" #include "configuration.h" @@ -117,6 +118,9 @@ void RangeTestPluginRadio::sendPayload(NodeNum dest, bool wantReplies) memcpy(p->decoded.data.payload.bytes, heartbeatString, p->decoded.data.payload.size); service.sendToMesh(p); + + // TODO: Handle this better. We want to keep the phone awake otherwise it stops sending. + powerFSM.trigger(EVENT_CONTACT_FROM_PHONE); } bool RangeTestPluginRadio::handleReceived(const MeshPacket &mp) From 8320754b985e8c8cebb42d72c3287fb1dab45d74 Mon Sep 17 00:00:00 2001 From: Jm Date: Sun, 14 Feb 2021 21:45:26 -0800 Subject: [PATCH 106/258] Added recommended settings as a sender --- docs/software/plugins/RangeTestPlugin.md | 7 +++++++ src/plugins/StoreForwardPlugin.cpp | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/docs/software/plugins/RangeTestPlugin.md b/docs/software/plugins/RangeTestPlugin.md index 14a43d292..0c5915f6b 100644 --- a/docs/software/plugins/RangeTestPlugin.md +++ b/docs/software/plugins/RangeTestPlugin.md @@ -38,6 +38,13 @@ To save a log of the messages: range_test_plugin_save = 1 +Recommended settings for a sender at different radio settings: + + Long Slow ... range_test_plugin_sender = 60 + Long Alt ... range_test_plugin_sender = 30 + Medium ... range_test_plugin_sender = 15 + Short Fast ... range_test_plugin_sender = 15 + ## Other things to keep in mind Be sure to turn off either the plugin configured as a sender or the device where the plugin setup as sender when not in use. This will use a lot of time on air and will spam your channel. diff --git a/src/plugins/StoreForwardPlugin.cpp b/src/plugins/StoreForwardPlugin.cpp index 087b34c1c..ef0b23090 100644 --- a/src/plugins/StoreForwardPlugin.cpp +++ b/src/plugins/StoreForwardPlugin.cpp @@ -21,7 +21,7 @@ int32_t StoreForwardPlugin::runOnce() without having to configure it from the PythonAPI or WebUI. */ - radioConfig.preferences.store_forward_plugin_enabled = 1; + radioConfig.preferences.store_forward_plugin_enabled = 0; radioConfig.preferences.is_router = 0; if (radioConfig.preferences.store_forward_plugin_enabled) { From 9a044f31a345cc61653408853d943a5147ebd747 Mon Sep 17 00:00:00 2001 From: Jm Date: Mon, 15 Feb 2021 09:11:28 -0800 Subject: [PATCH 107/258] Tweak to the startup condition of the range test plugin. --- src/plugins/RangeTestPlugin.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/plugins/RangeTestPlugin.cpp b/src/plugins/RangeTestPlugin.cpp index a789357d1..fad1991df 100644 --- a/src/plugins/RangeTestPlugin.cpp +++ b/src/plugins/RangeTestPlugin.cpp @@ -35,8 +35,8 @@ int32_t RangeTestPlugin::runOnce() without having to configure it from the PythonAPI or WebUI. */ - // radioConfig.preferences.range_test_plugin_enabled = 1; - // radioConfig.preferences.range_test_plugin_sender = 0; + //radioConfig.preferences.range_test_plugin_enabled = 1; + //radioConfig.preferences.range_test_plugin_sender = 45; // radioConfig.preferences.range_test_plugin_save = 1; // Fixed position is useful when testing indoors. @@ -56,7 +56,7 @@ int32_t RangeTestPlugin::runOnce() if (radioConfig.preferences.range_test_plugin_sender) { DEBUG_MSG("Initializing Range Test Plugin -- Sender\n"); - return (senderHeartbeat); + return (5000); // Sending first message 5 seconds after initilization. } else { DEBUG_MSG("Initializing Range Test Plugin -- Receiver\n"); return (500); @@ -76,7 +76,7 @@ int32_t RangeTestPlugin::runOnce() DEBUG_MSG("pref.fixed_position() %d\n", radioConfig.preferences.fixed_position); rangeTestPluginRadio->sendPayload(); - return ((senderHeartbeat)); + return (senderHeartbeat); } else { // Otherwise, we're a receiver. From 05d237ee8400076c966121d5b5fca314deaf780b Mon Sep 17 00:00:00 2001 From: Charles Crossan Date: Mon, 15 Feb 2021 21:01:18 -0500 Subject: [PATCH 108/258] add handleSetChannel --- src/mesh/PhoneAPI.cpp | 15 +++++++++++++++ src/mesh/PhoneAPI.h | 1 + 2 files changed, 16 insertions(+) diff --git a/src/mesh/PhoneAPI.cpp b/src/mesh/PhoneAPI.cpp index fa10e20fa..f9c9b6175 100644 --- a/src/mesh/PhoneAPI.cpp +++ b/src/mesh/PhoneAPI.cpp @@ -87,6 +87,10 @@ void PhoneAPI::handleToRadio(const uint8_t *buf, size_t bufLength) handleSetRadio(toRadioScratch.set_radio); break; + case ToRadio_set_channel_tag: + DEBUG_MSG("Client is setting channel\n"); + handleSetChannel(toRadioScratch.set_channel); + break; default: DEBUG_MSG("Error: unexpected ToRadio variant\n"); break; @@ -275,6 +279,17 @@ void PhoneAPI::handleSetOwner(const User &o) service.reloadOwner(); } +void PhoneAPI::handleSetChannel(const ChannelSettings &cc) +{ + radioConfig.channel_settings = cc; + + bool didReset = service.reloadConfig(); + if (didReset) { + state = STATE_SEND_MY_INFO; // Squirt a completely new set of configs to the client + } + +} + void PhoneAPI::handleSetRadio(const RadioConfig &r) { radioConfig = r; diff --git a/src/mesh/PhoneAPI.h b/src/mesh/PhoneAPI.h index 3cfd97441..663d6824c 100644 --- a/src/mesh/PhoneAPI.h +++ b/src/mesh/PhoneAPI.h @@ -88,6 +88,7 @@ class PhoneAPI // void handleSetOwner(const User &o); + void handleSetChannel(const ChannelSettings &cc); void handleSetRadio(const RadioConfig &r); protected: From c8584d576aca41b5f92695b1600841fcb3e63a18 Mon Sep 17 00:00:00 2001 From: geoffreyheller Date: Mon, 15 Feb 2021 19:33:35 -0800 Subject: [PATCH 109/258] Fix for non-working tx pin --- src/configuration.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/configuration.h b/src/configuration.h index 267420878..4fd395fd7 100644 --- a/src/configuration.h +++ b/src/configuration.h @@ -343,7 +343,7 @@ along with this program. If not, see . #undef GPS_RX_PIN #undef GPS_TX_PIN #define GPS_RX_PIN 36 -#define GPS_TX_PIN 39 +#define GPS_TX_PIN 13 #define BATTERY_PIN 35 // A battery voltage measurement pin, voltage divider connected here to measure battery voltage From d67e2187d0156791cd9ca083cef28d839bda10b9 Mon Sep 17 00:00:00 2001 From: Jm Casler Date: Mon, 15 Feb 2021 21:17:06 -0800 Subject: [PATCH 110/258] Update RangeTestPlugin.md --- docs/software/plugins/RangeTestPlugin.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/docs/software/plugins/RangeTestPlugin.md b/docs/software/plugins/RangeTestPlugin.md index 0c5915f6b..ee7732175 100644 --- a/docs/software/plugins/RangeTestPlugin.md +++ b/docs/software/plugins/RangeTestPlugin.md @@ -83,6 +83,9 @@ A: Go to /static and delete the file. Q: Can I use this as a sender while on battery power? A: Yes, but your battery will run down quicker than normal. While sending, we tell the device not to go into low-power mode since it needs to keep to a fairly strict timer. +Q: Why is this operating on incoming messages instead of the existing location discovery protocol? +A: This plugin is still young and currently supports monitoring just one port at a time. I decided to use the existing message port because that is easy to test with. A future version will listen to multiple ports to be more promiscuous. + # Need more help? Go to the Meshtastic Discourse Group if you have any questions or to share how you have used this. From 45caf394f0fa84c37b731d04b98cfb8c2d4120e3 Mon Sep 17 00:00:00 2001 From: Kevin Hester Date: Tue, 16 Feb 2021 15:41:52 +0800 Subject: [PATCH 111/258] WIP multichannel support --- .vscode/settings.json | 10 +- docs/software/TODO.md | 18 +++ proto | 2 +- src/graphics/Screen.cpp | 11 +- src/graphics/Screen.h | 9 -- src/mesh/Channels.cpp | 228 +++++++++++++++++++++++++++++ src/mesh/Channels.h | 51 +++++++ src/mesh/NodeDB.cpp | 165 ++------------------- src/mesh/NodeDB.h | 19 --- src/mesh/PhoneAPI.cpp | 5 +- src/mesh/PhoneAPI.h | 12 +- src/mesh/RadioInterface.cpp | 13 +- src/mesh/Router.cpp | 1 - src/mesh/generated/deviceonly.pb.h | 18 +-- src/mesh/generated/mesh.pb.c | 4 + src/mesh/generated/mesh.pb.h | 122 ++++++++------- src/mesh/mesh-pb-constants.h | 3 + src/plugins/RangeTestPlugin.cpp | 5 +- 18 files changed, 421 insertions(+), 275 deletions(-) create mode 100644 src/mesh/Channels.cpp create mode 100644 src/mesh/Channels.h diff --git a/.vscode/settings.json b/.vscode/settings.json index f78fe51b8..965532c24 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -68,5 +68,13 @@ "protobufs", "wifi" ], - "C_Cpp.dimInactiveRegions": true + "C_Cpp.dimInactiveRegions": true, + "protoc": { + "compile_on_save": false, + "compile_all_path": "/home/kevinh/development/meshtastic/meshtastic-esp32/proto", + "options": [ + "--java_out=/tmp", + "-I=/home/kevinh/development/meshtastic/meshtastic-esp32/proto" + ] + } } \ No newline at end of file diff --git a/docs/software/TODO.md b/docs/software/TODO.md index f6df164b0..ded8796de 100644 --- a/docs/software/TODO.md +++ b/docs/software/TODO.md @@ -2,6 +2,24 @@ You probably don't care about this section - skip to the next one. +1.2 cleanup & multichannel: + +* remove deprecated +* allow chaning packets in single transmission +* fix setchannel in phoneapi.cpp +* set mynodeinfo.max_channels +* set mynodeinfo.num_bands (formerly num_channels) +* send a hint that can be used to select which channel to try and hash against with each message +* change syncword +* move acks into routing +* make all subpackets different versions of data +* move routing control into a data packet +* make a primaryChannel global and properly maintain it when the phone sends setChannel +* move setCrypto call into packet send and packet decode code +* implement'small locations' change? +* move battery level out of position? +* DOUBLE CHECK android app can still upgrade 1.1 and 1.0 loads + eink: * new battery level sensing diff --git a/proto b/proto index 0cadaed39..481beb41b 160000 --- a/proto +++ b/proto @@ -1 +1 @@ -Subproject commit 0cadaed3953f66cf1edc99d0fa53e4fd5ebf56d6 +Subproject commit 481beb41ba8c8f39bfc6b3f397d6107af04dfb93 diff --git a/src/graphics/Screen.cpp b/src/graphics/Screen.cpp index 40ea25237..f7193260f 100644 --- a/src/graphics/Screen.cpp +++ b/src/graphics/Screen.cpp @@ -32,6 +32,7 @@ along with this program. If not, see . #include "main.h" #include "mesh-pb-constants.h" #include "plugins/TextMessagePlugin.h" +#include "mesh/Channels.h" #include "target_specific.h" #include "utils.h" @@ -790,9 +791,6 @@ int32_t Screen::runOnce() showingBootScreen = false; } - // Update the screen last, after we've figured out what to show. - debug_info()->setChannelNameStatus(getChannelName()); - // Process incoming commands. for (;;) { ScreenCmd cmd; @@ -1022,7 +1020,8 @@ void DebugInfo::drawFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16 char channelStr[20]; { concurrency::LockGuard guard(&lock); - snprintf(channelStr, sizeof(channelStr), "%s", channelName.c_str()); + auto chName = channels.getPrimaryName(); + snprintf(channelStr, sizeof(channelStr), "%s", chName); } // Display power status @@ -1229,8 +1228,8 @@ void DebugInfo::drawFrameSettings(OLEDDisplay *display, OLEDDisplayUiState *stat display->drawString(x, y, String("USB")); } - display->drawString(x + SCREEN_WIDTH - display->getStringWidth("Mode " + String(channelSettings.modem_config)), y, - "Mode " + String(channelSettings.modem_config)); + auto mode = "Mode " + String(channels.getPrimary().modem_config); + display->drawString(x + SCREEN_WIDTH - display->getStringWidth(mode), y, mode); // Line 2 uint32_t currentMillis = millis(); diff --git a/src/graphics/Screen.h b/src/graphics/Screen.h index 041da4865..9be119a48 100644 --- a/src/graphics/Screen.h +++ b/src/graphics/Screen.h @@ -39,13 +39,6 @@ class DebugInfo DebugInfo(const DebugInfo &) = delete; DebugInfo &operator=(const DebugInfo &) = delete; - /// Sets the name of the channel. - void setChannelNameStatus(const char *name) - { - concurrency::LockGuard guard(&lock); - channelName = name; - } - private: friend Screen; @@ -56,8 +49,6 @@ class DebugInfo void drawFrameSettings(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y); void drawFrameWiFi(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y); - std::string channelName; - /// Protects all of internal state. concurrency::Lock lock; }; diff --git a/src/mesh/Channels.cpp b/src/mesh/Channels.cpp new file mode 100644 index 000000000..584a83bc8 --- /dev/null +++ b/src/mesh/Channels.cpp @@ -0,0 +1,228 @@ +#include "Channels.h" +#include "NodeDB.h" +#include "CryptoEngine.h" + +#include + +/// A usable psk - which has been constructed based on the (possibly short psk) in channelSettings +static uint8_t activePSK[32]; +static uint8_t activePSKSize; + +/// 16 bytes of random PSK for our _public_ default channel that all devices power up on (AES128) +static const uint8_t defaultpsk[] = {0xd4, 0xf1, 0xbb, 0x3a, 0x20, 0x29, 0x07, 0x59, + 0xf0, 0xbc, 0xff, 0xab, 0xcf, 0x4e, 0x69, 0xbf}; + +Channels channels; + +/** + * Validate a channel, fixing any errors as needed + */ +Channel &fixupChannel(size_t chIndex) +{ + assert(chIndex < devicestate.channels_count); + + Channel *ch = devicestate.channels + chIndex; + + ch->index = chIndex; // Preinit the index so it be ready to share with the phone (we'll never change it later) + + if (!ch->has_settings) { + // No settings! Must disable and skip + ch->role = Channel_Role_DISABLED; + } else { + ChannelSettings &channelSettings = ch->settings; + + // Convert the old string "Default" to our new short representation + if (strcmp(channelSettings.name, "Default") == 0) + *channelSettings.name = '\0'; + + // Convert any old usage of the defaultpsk into our new short representation. + if (channelSettings.psk.size == sizeof(defaultpsk) && + memcmp(channelSettings.psk.bytes, defaultpsk, sizeof(defaultpsk)) == 0) { + *channelSettings.psk.bytes = 1; + channelSettings.psk.size = 1; + } + } + + return *ch; +} + + + +/** + * Write a default channel to the specified channel index + */ +void initDefaultChannel(size_t chIndex) +{ + assert(chIndex < devicestate.channels_count); + Channel *ch = devicestate.channels + chIndex; + ChannelSettings &channelSettings = ch->settings; + + // radioConfig.modem_config = RadioConfig_ModemConfig_Bw125Cr45Sf128; // medium range and fast + // channelSettings.modem_config = ChannelSettings_ModemConfig_Bw500Cr45Sf128; // short range and fast, but wide + // bandwidth so incompatible radios can talk together + channelSettings.modem_config = ChannelSettings_ModemConfig_Bw125Cr48Sf4096; // slow and long range + + channelSettings.tx_power = 0; // default + uint8_t defaultpskIndex = 1; + channelSettings.psk.bytes[0] = defaultpskIndex; + channelSettings.psk.size = 1; + strcpy(channelSettings.name, ""); + + ch->has_settings = true; + ch->role = Channel_Role_PRIMARY; +} + +/** Given a channel index, change to use the crypto key specified by that index + */ +void setCrypto(size_t chIndex) +{ + + assert(chIndex < devicestate.channels_count); + Channel *ch = devicestate.channels + chIndex; + ChannelSettings &channelSettings = ch->settings; + + memset(activePSK, 0, sizeof(activePSK)); // In case the user provided a short key, we want to pad the rest with zeros + memcpy(activePSK, channelSettings.psk.bytes, channelSettings.psk.size); + activePSKSize = channelSettings.psk.size; + if (activePSKSize == 0) + DEBUG_MSG("Warning: User disabled encryption\n"); + else if (activePSKSize == 1) { + // Convert the short single byte variants of psk into variant that can be used more generally + + uint8_t pskIndex = activePSK[0]; + DEBUG_MSG("Expanding short PSK #%d\n", pskIndex); + if (pskIndex == 0) + activePSKSize = 0; // Turn off encryption + else { + memcpy(activePSK, defaultpsk, sizeof(defaultpsk)); + activePSKSize = sizeof(defaultpsk); + // Bump up the last byte of PSK as needed + uint8_t *last = activePSK + sizeof(defaultpsk) - 1; + *last = *last + pskIndex - 1; // index of 1 means no change vs defaultPSK + } + } else if (activePSKSize < 16) { + // Error! The user specified only the first few bits of an AES128 key. So by convention we just pad the rest of the key + // with zeros + DEBUG_MSG("Warning: User provided a too short AES128 key - padding\n"); + activePSKSize = 16; + } else if (activePSKSize < 32 && activePSKSize != 16) { + // Error! The user specified only the first few bits of an AES256 key. So by convention we just pad the rest of the key + // with zeros + DEBUG_MSG("Warning: User provided a too short AES256 key - padding\n"); + activePSKSize = 32; + } + + // Tell our crypto engine about the psk + crypto->setKey(activePSKSize, activePSK); +} + +void Channels::initDefaults() +{ + devicestate.channels_count = MAX_CHANNELS; + for (int i = 0; i < devicestate.channels_count; i++) + fixupChannel(i); + initDefaultChannel(0); +} + +void Channels::onConfigChanged() +{ + // Make sure the phone hasn't mucked anything up + for (int i = 0; i < devicestate.channels_count; i++) { + auto ch = fixupChannel(i); + + if(ch.role == Channel_Role_PRIMARY) + primaryIndex = i; + } + + setCrypto(0); // FIXME: for the time being (still single channel - just use our only channel as the crypto key) +} + +Channel &Channels::getChannel(size_t chIndex) +{ + assert(chIndex < devicestate.channels_count); + Channel *ch = devicestate.channels + chIndex; + return *ch; +} + +void Channels::setChannel(const Channel &c) { + Channel &old = getChannel(c.index); + + // if this is the new primary, demote any existing roles + if(c.role == Channel_Role_PRIMARY) + for (int i = 0; i < devicestate.channels_count; i++) + if(devicestate.channels[i].role == Channel_Role_PRIMARY) + devicestate.channels[i].role = Channel_Role_SECONDARY; + + old = c; // slam in the new settings/role +} + +const char *Channels::getName(size_t chIndex) +{ + // Convert the short "" representation for Default into a usable string + ChannelSettings &channelSettings = getChannel(chIndex).settings; + const char *channelName = channelSettings.name; + if (!*channelName) { // emptystring + // Per mesh.proto spec, if bandwidth is specified we must ignore modemConfig enum, we assume that in that case + // the app fucked up and forgot to set channelSettings.name + + if (channelSettings.bandwidth != 0) + channelName = "Unset"; + else + switch (channelSettings.modem_config) { + case ChannelSettings_ModemConfig_Bw125Cr45Sf128: + channelName = "Medium"; + break; + case ChannelSettings_ModemConfig_Bw500Cr45Sf128: + channelName = "ShortFast"; + break; + case ChannelSettings_ModemConfig_Bw31_25Cr48Sf512: + channelName = "LongAlt"; + break; + case ChannelSettings_ModemConfig_Bw125Cr48Sf4096: + channelName = "LongSlow"; + break; + default: + channelName = "Invalid"; + break; + } + } + + return channelName; +} + +/** +* Generate a short suffix used to disambiguate channels that might have the same "name" entered by the human but different PSKs. +* The ideas is that the PSK changing should be visible to the user so that they see they probably messed up and that's why they +their nodes +* aren't talking to each other. +* +* This string is of the form "#name-X". +* +* Where X is either: +* (for custom PSKS) a letter from A to Z (base26), and formed by xoring all the bytes of the PSK together, +* OR (for the standard minimially secure PSKs) a number from 0 to 9. +* +* This function will also need to be implemented in GUI apps that talk to the radio. +* +* https://github.com/meshtastic/Meshtastic-device/issues/269 +*/ +const char *Channels::getPrimaryName() +{ + static char buf[32]; + + char suffix; + auto channelSettings = getPrimary(); + if (channelSettings.psk.size != 1) { + // We have a standard PSK, so generate a letter based hash. + uint8_t code = 0; + for (int i = 0; i < activePSKSize; i++) + code ^= activePSK[i]; + + suffix = 'A' + (code % 26); + } else { + suffix = '0' + channelSettings.psk.bytes[0]; + } + + snprintf(buf, sizeof(buf), "#%s-%c", channelSettings.name, suffix); + return buf; +} \ No newline at end of file diff --git a/src/mesh/Channels.h b/src/mesh/Channels.h new file mode 100644 index 000000000..5654fb1f2 --- /dev/null +++ b/src/mesh/Channels.h @@ -0,0 +1,51 @@ +#pragma once + +#include "mesh-pb-constants.h" +#include + +class Channels +{ + size_t primaryIndex = 0; + + public: + const ChannelSettings &getPrimary() { return getChannel(getPrimaryIndex()).settings; } + + Channel &getChannel(size_t chIndex); + + /** Using the index inside the channel, update the specified channel's settings and role. If this channel is being promoted to be + * primary, force all other channels to be secondary. + */ + void setChannel(const Channel &c); + + const char *getName(size_t chIndex); + + /** The index of the primary channel */ + size_t getPrimaryIndex() const { return primaryIndex; } + + /** + * Generate a short suffix used to disambiguate channels that might have the same "name" entered by the human but different PSKs. + * The ideas is that the PSK changing should be visible to the user so that they see they probably messed up and that's why they +their nodes + * aren't talking to each other. + * + * This string is of the form "#name-X". + * + * Where X is either: + * (for custom PSKS) a letter from A to Z (base26), and formed by xoring all the bytes of the PSK together, + * OR (for the standard minimially secure PSKs) a number from 0 to 9. + * + * This function will also need to be implemented in GUI apps that talk to the radio. + * + * https://github.com/meshtastic/Meshtastic-device/issues/269 + */ + const char *getPrimaryName(); + + /// Called by NodeDB on initial boot when the radio config settings are unset. Set a default single channel config. + void initDefaults(); + + /// called when the user has just changed our radio config and we might need to change channel keys + void onConfigChanged(); +}; + +/// Singleton channel table +extern Channels channels; \ No newline at end of file diff --git a/src/mesh/NodeDB.cpp b/src/mesh/NodeDB.cpp index b8f0b5697..9347ef0fd 100644 --- a/src/mesh/NodeDB.cpp +++ b/src/mesh/NodeDB.cpp @@ -7,7 +7,6 @@ #include "CryptoEngine.h" #include "FSCommon.h" #include "GPS.h" -#include "main.h" #include "MeshRadio.h" #include "NodeDB.h" #include "PacketHistory.h" @@ -16,6 +15,8 @@ #include "Router.h" #include "configuration.h" #include "error.h" +#include "main.h" +#include "Channels.h" #include "mesh-pb-constants.h" #include #include @@ -30,7 +31,6 @@ NodeDB nodeDB; EXT_RAM_ATTR DeviceState devicestate; MyNodeInfo &myNodeInfo = devicestate.my_node; RadioConfig &radioConfig = devicestate.radio; -ChannelSettings &channelSettings = radioConfig.channel_settings; /** The current change # for radio settings. Starts at 0 on boot and any time the radio settings * might have changed is incremented. Allows others to detect they might now be on a new channel. @@ -64,49 +64,6 @@ static uint8_t ourMacAddr[6]; */ NodeNum displayedNodeNum; -/// A usable (but bigger) version of the channel name in the channelSettings object -const char *channelName; - -/// A usable psk - which has been constructed based on the (possibly short psk) in channelSettings -static uint8_t activePSK[32]; -static uint8_t activePSKSize; - -/** - * Generate a short suffix used to disambiguate channels that might have the same "name" entered by the human but different PSKs. - * The ideas is that the PSK changing should be visible to the user so that they see they probably messed up and that's why they -their nodes - * aren't talking to each other. - * - * This string is of the form "#name-X". - * - * Where X is either: - * (for custom PSKS) a letter from A to Z (base26), and formed by xoring all the bytes of the PSK together, - * OR (for the standard minimially secure PSKs) a number from 0 to 9. - * - * This function will also need to be implemented in GUI apps that talk to the radio. - * - * https://github.com/meshtastic/Meshtastic-device/issues/269 - */ -const char *getChannelName() -{ - static char buf[32]; - - char suffix; - if (channelSettings.psk.size != 1) { - // We have a standard PSK, so generate a letter based hash. - uint8_t code = 0; - for (int i = 0; i < activePSKSize; i++) - code ^= activePSK[i]; - - suffix = 'A' + (code % 26); - } else { - suffix = '0' + channelSettings.psk.bytes[0]; - } - - snprintf(buf, sizeof(buf), "#%s-%c", channelName, suffix); - return buf; -} - NodeDB::NodeDB() : nodes(devicestate.node_db), numNodes(&devicestate.node_db_count) {} bool NodeDB::resetRadioConfig() @@ -115,104 +72,19 @@ bool NodeDB::resetRadioConfig() radioGeneration++; - /// 16 bytes of random PSK for our _public_ default channel that all devices power up on (AES128) - static const uint8_t defaultpsk[] = {0xd4, 0xf1, 0xbb, 0x3a, 0x20, 0x29, 0x07, 0x59, - 0xf0, 0xbc, 0xff, 0xab, 0xcf, 0x4e, 0x69, 0xbf}; - if (radioConfig.preferences.factory_reset) { DEBUG_MSG("Performing factory reset!\n"); installDefaultDeviceState(); didFactoryReset = true; - } else if (!channelSettings.psk.size) { - DEBUG_MSG("Setting default preferences!\n"); + } else if (devicestate.channels_count == 0) { + DEBUG_MSG("Setting default channel and radio preferences!\n"); + + channels.initDefaults(); - radioConfig.has_channel_settings = true; radioConfig.has_preferences = true; - - // radioConfig.modem_config = RadioConfig_ModemConfig_Bw125Cr45Sf128; // medium range and fast - // channelSettings.modem_config = ChannelSettings_ModemConfig_Bw500Cr45Sf128; // short range and fast, but wide - // bandwidth so incompatible radios can talk together - channelSettings.modem_config = ChannelSettings_ModemConfig_Bw125Cr48Sf4096; // slow and long range - - channelSettings.tx_power = 0; // default - uint8_t defaultpskIndex = 1; - channelSettings.psk.bytes[0] = defaultpskIndex; - channelSettings.psk.size = 1; - strcpy(channelSettings.name, ""); } - // Convert the old string "Default" to our new short representation - if (strcmp(channelSettings.name, "Default") == 0) - *channelSettings.name = '\0'; - - // Convert the short "" representation for Default into a usable string - channelName = channelSettings.name; - if (!*channelName) { // emptystring - // Per mesh.proto spec, if bandwidth is specified we must ignore modemConfig enum, we assume that in that case - // the app fucked up and forgot to set channelSettings.name - - if (channelSettings.bandwidth != 0) - channelName = "Unset"; - else - switch (channelSettings.modem_config) { - case ChannelSettings_ModemConfig_Bw125Cr45Sf128: - channelName = "Medium"; - break; - case ChannelSettings_ModemConfig_Bw500Cr45Sf128: - channelName = "ShortFast"; - break; - case ChannelSettings_ModemConfig_Bw31_25Cr48Sf512: - channelName = "LongAlt"; - break; - case ChannelSettings_ModemConfig_Bw125Cr48Sf4096: - channelName = "LongSlow"; - break; - default: - channelName = "Invalid"; - break; - } - } - - // Convert any old usage of the defaultpsk into our new short representation. - if (channelSettings.psk.size == sizeof(defaultpsk) && - memcmp(channelSettings.psk.bytes, defaultpsk, sizeof(defaultpsk)) == 0) { - *channelSettings.psk.bytes = 1; - channelSettings.psk.size = 1; - } - - memset(activePSK, 0, sizeof(activePSK)); // In case the user provided a short key, we want to pad the rest with zeros - memcpy(activePSK, channelSettings.psk.bytes, channelSettings.psk.size); - activePSKSize = channelSettings.psk.size; - if(activePSKSize == 0) - DEBUG_MSG("Warning: User disabled encryption\n"); - else if (activePSKSize == 1) { - // Convert the short single byte variants of psk into variant that can be used more generally - - uint8_t pskIndex = activePSK[0]; - DEBUG_MSG("Expanding short PSK #%d\n", pskIndex); - if (pskIndex == 0) - activePSKSize = 0; // Turn off encryption - else { - memcpy(activePSK, defaultpsk, sizeof(defaultpsk)); - activePSKSize = sizeof(defaultpsk); - // Bump up the last byte of PSK as needed - uint8_t *last = activePSK + sizeof(defaultpsk) - 1; - *last = *last + pskIndex - 1; // index of 1 means no change vs defaultPSK - } - } else if(activePSKSize < 16) { - // Error! The user specified only the first few bits of an AES128 key. So by convention we just pad the rest of the key - // with zeros - DEBUG_MSG("Warning: User provided a too short AES128 key - padding\n"); - activePSKSize = 16; - } else if(activePSKSize < 32 && activePSKSize != 16) { - // Error! The user specified only the first few bits of an AES256 key. So by convention we just pad the rest of the key - // with zeros - DEBUG_MSG("Warning: User provided a too short AES256 key - padding\n"); - activePSKSize = 32; - } - - // Tell our crypto engine about the psk - crypto->setKey(activePSKSize, activePSK); + channels.onConfigChanged(); // temp hack for quicker testing // devicestate.no_save = true; @@ -251,7 +123,6 @@ void NodeDB::installDefaultDeviceState() devicestate.has_my_node = true; devicestate.has_radio = true; devicestate.has_owner = true; - devicestate.radio.has_channel_settings = true; devicestate.radio.has_preferences = true; devicestate.node_db_count = 0; devicestate.receive_queue_count = 0; // Not yet implemented FIXME @@ -289,17 +160,14 @@ void NodeDB::init() loadFromDisk(); // saveToDisk(); - // We set node_num and packet_id _after_ loading from disk, because we always want to use the values this - // rom was compiled for, not what happens to be in the save file. - myNodeInfo.node_num_bits = sizeof(NodeNum) * 8; - myNodeInfo.packet_id_bits = sizeof(PacketId) * 8; + myNodeInfo.max_channels = MAX_CHANNELS; // tell others the max # of channels we can understand myNodeInfo.error_code = CriticalErrorCode_None; // For the error code, only show values from this boot (discard value from flash) myNodeInfo.error_address = 0; // likewise - we always want the app requirements to come from the running appload - myNodeInfo.min_app_version = 20120; // format is Mmmss (where M is 1+the numeric major number. i.e. 20120 means 1.1.20 + myNodeInfo.min_app_version = 20200; // format is Mmmss (where M is 1+the numeric major number. i.e. 20120 means 1.1.20 // Note! We do this after loading saved settings, so that if somehow an invalid nodenum was stored in preferences we won't // keep using that nodenum forever. Crummy guess at our nodenum (but we will check against the nodedb to avoid conflicts) @@ -539,12 +407,6 @@ void NodeDB::updateFrom(const MeshPacket &mp) info->snr = mp.rx_snr; // keep the most recent SNR we received for this node. switch (p.which_payloadVariant) { - case SubPacket_position_tag: { - // handle a legacy position packet - DEBUG_MSG("WARNING: Processing a (deprecated) position packet from %d\n", mp.from); - updatePosition(mp.from, p.position); - break; - } case SubPacket_data_tag: { if (mp.to == NODENUM_BROADCAST || mp.to == nodeDB.getNodeNum()) @@ -552,12 +414,6 @@ void NodeDB::updateFrom(const MeshPacket &mp) break; } - case SubPacket_user_tag: { - DEBUG_MSG("WARNING: Processing a (deprecated) user packet from %d\n", mp.from); - updateUser(mp.from, p.user); - break; - } - default: { notifyObservers(); // If the node counts have changed, notify observers } @@ -601,10 +457,9 @@ void recordCriticalError(CriticalErrorCode code, uint32_t address) String lcd = String("Critical error ") + code + "!\n"; screen->print(lcd.c_str()); DEBUG_MSG("NOTE! Recording critical error %d, address=%lx\n", code, address); - + // Record error to DB myNodeInfo.error_code = code; myNodeInfo.error_address = address; myNodeInfo.error_count++; - } diff --git a/src/mesh/NodeDB.h b/src/mesh/NodeDB.h index 5174f5642..29c35369f 100644 --- a/src/mesh/NodeDB.h +++ b/src/mesh/NodeDB.h @@ -11,9 +11,7 @@ extern DeviceState devicestate; extern MyNodeInfo &myNodeInfo; extern RadioConfig &radioConfig; -extern ChannelSettings &channelSettings; extern User &owner; -extern const char *channelName; /// Given a node, return how many seconds in the past (vs now) that we last heard from it uint32_t sinceLastSeen(const NodeInfo *n); @@ -130,23 +128,6 @@ extern NodeNum displayedNodeNum; extern NodeDB nodeDB; -/** - * Generate a short suffix used to disambiguate channels that might have the same "name" entered by the human but different PSKs. - * The ideas is that the PSK changing should be visible to the user so that they see they probably messed up and that's why they -their nodes - * aren't talking to each other. - * - * This string is of the form "#name-XY". - * - * Where X is a letter from A to Z (base26), and formed by xoring all the bytes of the PSK together. - * Y is not yet used but should eventually indicate 'speed/range' of the link - * - * This function will also need to be implemented in GUI apps that talk to the radio. - * - * https://github.com/meshtastic/Meshtastic-device/issues/269 - */ -const char *getChannelName(); - /* If is_router is set, we use a number of different default values diff --git a/src/mesh/PhoneAPI.cpp b/src/mesh/PhoneAPI.cpp index f9c9b6175..6ec09b2ca 100644 --- a/src/mesh/PhoneAPI.cpp +++ b/src/mesh/PhoneAPI.cpp @@ -4,6 +4,7 @@ #include "NodeDB.h" #include "PowerFSM.h" #include "RadioInterface.h" +#include "Channels.h" #include #if FromRadio_size > MAX_TO_FROM_RADIO_SIZE @@ -279,9 +280,9 @@ void PhoneAPI::handleSetOwner(const User &o) service.reloadOwner(); } -void PhoneAPI::handleSetChannel(const ChannelSettings &cc) +void PhoneAPI::handleSetChannel(const Channel &cc) { - radioConfig.channel_settings = cc; + channels.setChannel(cc); bool didReset = service.reloadConfig(); if (didReset) { diff --git a/src/mesh/PhoneAPI.h b/src/mesh/PhoneAPI.h index 663d6824c..6d4e8d626 100644 --- a/src/mesh/PhoneAPI.h +++ b/src/mesh/PhoneAPI.h @@ -83,14 +83,6 @@ class PhoneAPI */ bool available(); - // - // The following routines are only public for now - until the rev1 bluetooth API is removed - // - - void handleSetOwner(const User &o); - void handleSetChannel(const ChannelSettings &cc); - void handleSetRadio(const RadioConfig &r); - protected: /// Are we currently connected to a client? bool isConnected = false; @@ -109,6 +101,10 @@ class PhoneAPI */ virtual void onNowHasData(uint32_t fromRadioNum) {} + void handleSetOwner(const User &o); + void handleSetChannel(const Channel &cc); + void handleSetRadio(const RadioConfig &r); + private: /** * Handle a packet that the phone wants us to send. It is our responsibility to free the packet to the pool diff --git a/src/mesh/RadioInterface.cpp b/src/mesh/RadioInterface.cpp index 0884c260d..0d99ca2ff 100644 --- a/src/mesh/RadioInterface.cpp +++ b/src/mesh/RadioInterface.cpp @@ -6,6 +6,7 @@ #include "assert.h" #include "configuration.h" #include "sleep.h" +#include "Channels.h" #include #include #include @@ -36,7 +37,7 @@ void initRegion() myRegion = r; DEBUG_MSG("Wanted region %d, using %s\n", radioConfig.preferences.region, r->name); - myNodeInfo.num_channels = myRegion->numChannels; // Tell our android app how many channels we have + myNodeInfo.num_bands = myRegion->numChannels; // Tell our android app how many channels we have } /** @@ -125,12 +126,6 @@ void printPacket(const char *prefix, const MeshPacket *p) case SubPacket_data_tag: DEBUG_MSG(" Portnum=%d", s.data.portnum); break; - case SubPacket_position_tag: - DEBUG_MSG(" Payload:Position"); - break; - case SubPacket_user_tag: - DEBUG_MSG(" Payload:User"); - break; case 0: DEBUG_MSG(" Payload:None"); break; @@ -252,6 +247,7 @@ void RadioInterface::applyModemConfig() // Set up default configuration // No Sync Words in LORA mode + auto channelSettings = channels.getPrimary(); if (channelSettings.spread_factor == 0) { switch (channelSettings.modem_config) { case ChannelSettings_ModemConfig_Bw125Cr45Sf128: ///< Bw = 125 kHz, Cr = 4/5, Sf = 128chips/symbol, CRC on. Default medium @@ -296,7 +292,8 @@ void RadioInterface::applyModemConfig() assert(myRegion); // Should have been found in init // If user has manually specified a channel num, then use that, otherwise generate one by hashing the name - int channel_num = (channelSettings.channel_num ? channelSettings.channel_num - 1 : hash(channelName)) % myRegion->numChannels; + const char *channelName = channels.getName(channels.getPrimaryIndex()); + int channel_num = channelSettings.channel_num ? channelSettings.channel_num - 1 : hash(channelName) % myRegion->numChannels; freq = myRegion->freq + myRegion->spacing * channel_num; DEBUG_MSG("Set radio: name=%s, config=%u, ch=%d, power=%d\n", channelName, channelSettings.modem_config, channel_num, power); diff --git a/src/mesh/Router.cpp b/src/mesh/Router.cpp index 43d939c31..5178e229b 100644 --- a/src/mesh/Router.cpp +++ b/src/mesh/Router.cpp @@ -80,7 +80,6 @@ PacketId generatePacketId() i++; PacketId id = (i % numPacketId) + 1; // return number between 1 and numPacketId (ie - never zero) - myNodeInfo.current_packet_id = id; // Kinda crufty - we keep updating this so the phone can see a current value return id; } diff --git a/src/mesh/generated/deviceonly.pb.h b/src/mesh/generated/deviceonly.pb.h index 99d838d39..e1f4c4010 100644 --- a/src/mesh/generated/deviceonly.pb.h +++ b/src/mesh/generated/deviceonly.pb.h @@ -27,8 +27,8 @@ typedef struct _DeviceState { uint32_t version; bool no_save; bool did_gps_reset; - pb_size_t secondary_channels_count; - ChannelSettings secondary_channels[7]; + pb_size_t channels_count; + Channel channels[8]; } DeviceState; @@ -37,8 +37,8 @@ extern "C" { #endif /* Initializer values for message structs */ -#define DeviceState_init_default {false, RadioConfig_init_default, false, MyNodeInfo_init_default, false, User_init_default, 0, {NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default}, 0, {MeshPacket_init_default}, false, MeshPacket_init_default, 0, 0, 0, 0, {ChannelSettings_init_default, ChannelSettings_init_default, ChannelSettings_init_default, ChannelSettings_init_default, ChannelSettings_init_default, ChannelSettings_init_default, ChannelSettings_init_default}} -#define DeviceState_init_zero {false, RadioConfig_init_zero, false, MyNodeInfo_init_zero, false, User_init_zero, 0, {NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero}, 0, {MeshPacket_init_zero}, false, MeshPacket_init_zero, 0, 0, 0, 0, {ChannelSettings_init_zero, ChannelSettings_init_zero, ChannelSettings_init_zero, ChannelSettings_init_zero, ChannelSettings_init_zero, ChannelSettings_init_zero, ChannelSettings_init_zero}} +#define DeviceState_init_default {false, RadioConfig_init_default, false, MyNodeInfo_init_default, false, User_init_default, 0, {NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default}, 0, {MeshPacket_init_default}, false, MeshPacket_init_default, 0, 0, 0, 0, {Channel_init_default, Channel_init_default, Channel_init_default, Channel_init_default, Channel_init_default, Channel_init_default, Channel_init_default, Channel_init_default}} +#define DeviceState_init_zero {false, RadioConfig_init_zero, false, MyNodeInfo_init_zero, false, User_init_zero, 0, {NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero}, 0, {MeshPacket_init_zero}, false, MeshPacket_init_zero, 0, 0, 0, 0, {Channel_init_zero, Channel_init_zero, Channel_init_zero, Channel_init_zero, Channel_init_zero, Channel_init_zero, Channel_init_zero, Channel_init_zero}} /* Field tags (for use in manual encoding/decoding) */ #define DeviceState_radio_tag 1 @@ -50,7 +50,7 @@ extern "C" { #define DeviceState_version_tag 8 #define DeviceState_no_save_tag 9 #define DeviceState_did_gps_reset_tag 11 -#define DeviceState_secondary_channels_tag 12 +#define DeviceState_channels_tag 12 /* Struct field encoding specification for nanopb */ #define DeviceState_FIELDLIST(X, a) \ @@ -63,7 +63,7 @@ X(a, STATIC, OPTIONAL, MESSAGE, rx_text_message, 7) \ X(a, STATIC, SINGULAR, UINT32, version, 8) \ X(a, STATIC, SINGULAR, BOOL, no_save, 9) \ X(a, STATIC, SINGULAR, BOOL, did_gps_reset, 11) \ -X(a, STATIC, REPEATED, MESSAGE, secondary_channels, 12) +X(a, STATIC, REPEATED, MESSAGE, channels, 12) #define DeviceState_CALLBACK NULL #define DeviceState_DEFAULT NULL #define DeviceState_radio_MSGTYPE RadioConfig @@ -72,7 +72,7 @@ X(a, STATIC, REPEATED, MESSAGE, secondary_channels, 12) #define DeviceState_node_db_MSGTYPE NodeInfo #define DeviceState_receive_queue_MSGTYPE MeshPacket #define DeviceState_rx_text_message_MSGTYPE MeshPacket -#define DeviceState_secondary_channels_MSGTYPE ChannelSettings +#define DeviceState_channels_MSGTYPE Channel extern const pb_msgdesc_t DeviceState_msg; @@ -80,10 +80,10 @@ extern const pb_msgdesc_t DeviceState_msg; #define DeviceState_fields &DeviceState_msg /* Maximum encoded size of messages (where known) */ -#define DeviceState_size 6266 +#define DeviceState_size 6265 #ifdef __cplusplus } /* extern "C" */ #endif -#endif \ No newline at end of file +#endif diff --git a/src/mesh/generated/mesh.pb.c b/src/mesh/generated/mesh.pb.c index 0bf5fbe38..872447623 100644 --- a/src/mesh/generated/mesh.pb.c +++ b/src/mesh/generated/mesh.pb.c @@ -27,6 +27,9 @@ PB_BIND(MeshPacket, MeshPacket, 2) PB_BIND(ChannelSettings, ChannelSettings, AUTO) +PB_BIND(Channel, Channel, AUTO) + + PB_BIND(RadioConfig, RadioConfig, 2) @@ -59,3 +62,4 @@ PB_BIND(ToRadio, ToRadio, 2) + diff --git a/src/mesh/generated/mesh.pb.h b/src/mesh/generated/mesh.pb.h index 397a313ea..691b4cd78 100644 --- a/src/mesh/generated/mesh.pb.h +++ b/src/mesh/generated/mesh.pb.h @@ -100,6 +100,12 @@ typedef enum _ChannelSettings_ModemConfig { ChannelSettings_ModemConfig_Bw125Cr48Sf4096 = 3 } ChannelSettings_ModemConfig; +typedef enum _Channel_Role { + Channel_Role_DISABLED = 0, + Channel_Role_PRIMARY = 1, + Channel_Role_SECONDARY = 2 +} Channel_Role; + typedef enum _LogRecord_Level { LogRecord_Level_UNSET = 0, LogRecord_Level_CRITICAL = 50, @@ -142,25 +148,23 @@ typedef struct _LogRecord { typedef struct _MyNodeInfo { uint32_t my_node_num; bool has_gps; - int32_t num_channels; + uint32_t num_bands; char region[12]; char hw_model[16]; char firmware_version[12]; CriticalErrorCode error_code; uint32_t error_address; uint32_t error_count; - uint32_t packet_id_bits; - uint32_t current_packet_id; - uint32_t node_num_bits; uint32_t message_timeout_msec; uint32_t min_app_version; + uint32_t max_channels; } MyNodeInfo; typedef struct _Position { - int32_t altitude; - int32_t battery_level; int32_t latitude_i; int32_t longitude_i; + int32_t altitude; + int32_t battery_level; uint32_t time; } Position; @@ -222,6 +226,13 @@ typedef struct _User { pb_byte_t macaddr[6]; } User; +typedef struct _Channel { + uint32_t index; + bool has_settings; + ChannelSettings settings; + Channel_Role role; +} Channel; + typedef struct _NodeInfo { uint32_t num; bool has_user; @@ -235,21 +246,17 @@ typedef struct _NodeInfo { typedef struct _RadioConfig { bool has_preferences; RadioConfig_UserPreferences preferences; - bool has_channel_settings; - ChannelSettings channel_settings; } RadioConfig; typedef struct _SubPacket { + uint32_t original_id; pb_size_t which_payloadVariant; union { - Position position; Data data; - User user; RouteDiscovery route_request; RouteDiscovery route_reply; ErrorReason error_reason; }; - uint32_t original_id; bool want_response; uint32_t dest; pb_size_t which_ackVariant; @@ -289,7 +296,7 @@ typedef struct _FromRadio { LogRecord log_record; uint32_t config_complete_id; bool rebooted; - ChannelSettings channel; + Channel channel; }; } FromRadio; @@ -300,7 +307,7 @@ typedef struct _ToRadio { uint32_t want_config_id; RadioConfig set_radio; User set_owner; - ChannelSettings set_channel; + Channel set_channel; }; } ToRadio; @@ -342,6 +349,10 @@ typedef struct _ToRadio { #define _ChannelSettings_ModemConfig_MAX ChannelSettings_ModemConfig_Bw125Cr48Sf4096 #define _ChannelSettings_ModemConfig_ARRAYSIZE ((ChannelSettings_ModemConfig)(ChannelSettings_ModemConfig_Bw125Cr48Sf4096+1)) +#define _Channel_Role_MIN Channel_Role_DISABLED +#define _Channel_Role_MAX Channel_Role_SECONDARY +#define _Channel_Role_ARRAYSIZE ((Channel_Role)(Channel_Role_SECONDARY+1)) + #define _LogRecord_Level_MIN LogRecord_Level_UNSET #define _LogRecord_Level_MAX LogRecord_Level_CRITICAL #define _LogRecord_Level_ARRAYSIZE ((LogRecord_Level)(LogRecord_Level_CRITICAL+1)) @@ -356,13 +367,14 @@ extern "C" { #define Data_init_default {_PortNum_MIN, {0, {0}}} #define User_init_default {"", "", "", {0}} #define RouteDiscovery_init_default {0, {0, 0, 0, 0, 0, 0, 0, 0}} -#define SubPacket_init_default {0, {Position_init_default}, 0, 0, 0, 0, {0}, 0} +#define SubPacket_init_default {0, 0, {Data_init_default}, 0, 0, 0, {0}, 0} #define MeshPacket_init_default {0, 0, 0, {SubPacket_init_default}, 0, 0, 0, 0, 0, 0, _MeshPacket_Priority_MIN} #define ChannelSettings_init_default {0, _ChannelSettings_ModemConfig_MIN, {0, {0}}, "", 0, 0, 0, 0, 0, 0, 0} -#define RadioConfig_init_default {false, RadioConfig_UserPreferences_init_default, false, ChannelSettings_init_default} +#define Channel_init_default {0, false, ChannelSettings_init_default, _Channel_Role_MIN} +#define RadioConfig_init_default {false, RadioConfig_UserPreferences_init_default} #define RadioConfig_UserPreferences_init_default {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, "", "", 0, _RegionCode_MIN, _ChargeCurrent_MIN, _LocationSharing_MIN, _GpsOperation_MIN, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0}, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} #define NodeInfo_init_default {0, false, User_init_default, false, Position_init_default, 0, 0} -#define MyNodeInfo_init_default {0, 0, 0, "", "", "", _CriticalErrorCode_MIN, 0, 0, 0, 0, 0, 0, 0} +#define MyNodeInfo_init_default {0, 0, 0, "", "", "", _CriticalErrorCode_MIN, 0, 0, 0, 0, 0} #define LogRecord_init_default {"", 0, "", _LogRecord_Level_MIN} #define FromRadio_init_default {0, 0, {MeshPacket_init_default}} #define ToRadio_init_default {0, {MeshPacket_init_default}} @@ -370,13 +382,14 @@ extern "C" { #define Data_init_zero {_PortNum_MIN, {0, {0}}} #define User_init_zero {"", "", "", {0}} #define RouteDiscovery_init_zero {0, {0, 0, 0, 0, 0, 0, 0, 0}} -#define SubPacket_init_zero {0, {Position_init_zero}, 0, 0, 0, 0, {0}, 0} +#define SubPacket_init_zero {0, 0, {Data_init_zero}, 0, 0, 0, {0}, 0} #define MeshPacket_init_zero {0, 0, 0, {SubPacket_init_zero}, 0, 0, 0, 0, 0, 0, _MeshPacket_Priority_MIN} #define ChannelSettings_init_zero {0, _ChannelSettings_ModemConfig_MIN, {0, {0}}, "", 0, 0, 0, 0, 0, 0, 0} -#define RadioConfig_init_zero {false, RadioConfig_UserPreferences_init_zero, false, ChannelSettings_init_zero} +#define Channel_init_zero {0, false, ChannelSettings_init_zero, _Channel_Role_MIN} +#define RadioConfig_init_zero {false, RadioConfig_UserPreferences_init_zero} #define RadioConfig_UserPreferences_init_zero {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, "", "", 0, _RegionCode_MIN, _ChargeCurrent_MIN, _LocationSharing_MIN, _GpsOperation_MIN, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0}, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} #define NodeInfo_init_zero {0, false, User_init_zero, false, Position_init_zero, 0, 0} -#define MyNodeInfo_init_zero {0, 0, 0, "", "", "", _CriticalErrorCode_MIN, 0, 0, 0, 0, 0, 0, 0} +#define MyNodeInfo_init_zero {0, 0, 0, "", "", "", _CriticalErrorCode_MIN, 0, 0, 0, 0, 0} #define LogRecord_init_zero {"", 0, "", _LogRecord_Level_MIN} #define FromRadio_init_zero {0, 0, {MeshPacket_init_zero}} #define ToRadio_init_zero {0, {MeshPacket_init_zero}} @@ -401,22 +414,20 @@ extern "C" { #define LogRecord_level_tag 4 #define MyNodeInfo_my_node_num_tag 1 #define MyNodeInfo_has_gps_tag 2 -#define MyNodeInfo_num_channels_tag 3 +#define MyNodeInfo_num_bands_tag 3 #define MyNodeInfo_region_tag 4 #define MyNodeInfo_hw_model_tag 5 #define MyNodeInfo_firmware_version_tag 6 #define MyNodeInfo_error_code_tag 7 #define MyNodeInfo_error_address_tag 8 #define MyNodeInfo_error_count_tag 9 -#define MyNodeInfo_packet_id_bits_tag 10 -#define MyNodeInfo_current_packet_id_tag 11 -#define MyNodeInfo_node_num_bits_tag 12 #define MyNodeInfo_message_timeout_msec_tag 13 #define MyNodeInfo_min_app_version_tag 14 +#define MyNodeInfo_max_channels_tag 15 +#define Position_latitude_i_tag 1 +#define Position_longitude_i_tag 2 #define Position_altitude_tag 3 #define Position_battery_level_tag 4 -#define Position_latitude_i_tag 7 -#define Position_longitude_i_tag 8 #define Position_time_tag 9 #define RadioConfig_UserPreferences_position_broadcast_secs_tag 1 #define RadioConfig_UserPreferences_send_owner_interval_tag 2 @@ -465,20 +476,20 @@ extern "C" { #define User_long_name_tag 2 #define User_short_name_tag 3 #define User_macaddr_tag 4 +#define Channel_index_tag 1 +#define Channel_settings_tag 2 +#define Channel_role_tag 3 #define NodeInfo_num_tag 1 #define NodeInfo_user_tag 2 #define NodeInfo_position_tag 3 #define NodeInfo_next_hop_tag 5 #define NodeInfo_snr_tag 7 #define RadioConfig_preferences_tag 1 -#define RadioConfig_channel_settings_tag 2 -#define SubPacket_position_tag 1 +#define SubPacket_original_id_tag 2 #define SubPacket_data_tag 3 -#define SubPacket_user_tag 4 #define SubPacket_route_request_tag 6 #define SubPacket_route_reply_tag 7 #define SubPacket_error_reason_tag 13 -#define SubPacket_original_id_tag 2 #define SubPacket_want_response_tag 5 #define SubPacket_dest_tag 9 #define SubPacket_success_id_tag 10 @@ -508,14 +519,14 @@ extern "C" { #define ToRadio_want_config_id_tag 100 #define ToRadio_set_radio_tag 101 #define ToRadio_set_owner_tag 102 -#define ToRadio_set_channel_tag 103 +#define ToRadio_set_channel_tag 104 /* Struct field encoding specification for nanopb */ #define Position_FIELDLIST(X, a) \ +X(a, STATIC, SINGULAR, SFIXED32, latitude_i, 1) \ +X(a, STATIC, SINGULAR, SFIXED32, longitude_i, 2) \ X(a, STATIC, SINGULAR, INT32, altitude, 3) \ X(a, STATIC, SINGULAR, INT32, battery_level, 4) \ -X(a, STATIC, SINGULAR, SINT32, latitude_i, 7) \ -X(a, STATIC, SINGULAR, SINT32, longitude_i, 8) \ X(a, STATIC, SINGULAR, FIXED32, time, 9) #define Position_CALLBACK NULL #define Position_DEFAULT NULL @@ -540,13 +551,11 @@ X(a, STATIC, REPEATED, INT32, route, 2) #define RouteDiscovery_DEFAULT NULL #define SubPacket_FIELDLIST(X, a) \ -X(a, STATIC, ONEOF, MESSAGE, (payloadVariant,position,position), 1) \ +X(a, STATIC, SINGULAR, UINT32, original_id, 2) \ X(a, STATIC, ONEOF, MESSAGE, (payloadVariant,data,data), 3) \ -X(a, STATIC, ONEOF, MESSAGE, (payloadVariant,user,user), 4) \ X(a, STATIC, ONEOF, MESSAGE, (payloadVariant,route_request,route_request), 6) \ X(a, STATIC, ONEOF, MESSAGE, (payloadVariant,route_reply,route_reply), 7) \ X(a, STATIC, ONEOF, UENUM, (payloadVariant,error_reason,error_reason), 13) \ -X(a, STATIC, SINGULAR, UINT32, original_id, 2) \ X(a, STATIC, SINGULAR, BOOL, want_response, 5) \ X(a, STATIC, SINGULAR, UINT32, dest, 9) \ X(a, STATIC, ONEOF, UINT32, (ackVariant,success_id,ackVariant.success_id), 10) \ @@ -554,9 +563,7 @@ X(a, STATIC, ONEOF, UINT32, (ackVariant,fail_id,ackVariant.fail_id), 11) X(a, STATIC, SINGULAR, UINT32, source, 12) #define SubPacket_CALLBACK NULL #define SubPacket_DEFAULT NULL -#define SubPacket_payloadVariant_position_MSGTYPE Position #define SubPacket_payloadVariant_data_MSGTYPE Data -#define SubPacket_payloadVariant_user_MSGTYPE User #define SubPacket_payloadVariant_route_request_MSGTYPE RouteDiscovery #define SubPacket_payloadVariant_route_reply_MSGTYPE RouteDiscovery @@ -591,13 +598,19 @@ X(a, STATIC, SINGULAR, BOOL, downlink_enabled, 17) #define ChannelSettings_CALLBACK NULL #define ChannelSettings_DEFAULT NULL +#define Channel_FIELDLIST(X, a) \ +X(a, STATIC, SINGULAR, UINT32, index, 1) \ +X(a, STATIC, OPTIONAL, MESSAGE, settings, 2) \ +X(a, STATIC, SINGULAR, UENUM, role, 3) +#define Channel_CALLBACK NULL +#define Channel_DEFAULT NULL +#define Channel_settings_MSGTYPE ChannelSettings + #define RadioConfig_FIELDLIST(X, a) \ -X(a, STATIC, OPTIONAL, MESSAGE, preferences, 1) \ -X(a, STATIC, OPTIONAL, MESSAGE, channel_settings, 2) +X(a, STATIC, OPTIONAL, MESSAGE, preferences, 1) #define RadioConfig_CALLBACK NULL #define RadioConfig_DEFAULT NULL #define RadioConfig_preferences_MSGTYPE RadioConfig_UserPreferences -#define RadioConfig_channel_settings_MSGTYPE ChannelSettings #define RadioConfig_UserPreferences_FIELDLIST(X, a) \ X(a, STATIC, SINGULAR, UINT32, position_broadcast_secs, 1) \ @@ -659,18 +672,16 @@ X(a, STATIC, SINGULAR, FLOAT, snr, 7) #define MyNodeInfo_FIELDLIST(X, a) \ X(a, STATIC, SINGULAR, UINT32, my_node_num, 1) \ X(a, STATIC, SINGULAR, BOOL, has_gps, 2) \ -X(a, STATIC, SINGULAR, INT32, num_channels, 3) \ +X(a, STATIC, SINGULAR, UINT32, num_bands, 3) \ X(a, STATIC, SINGULAR, STRING, region, 4) \ X(a, STATIC, SINGULAR, STRING, hw_model, 5) \ X(a, STATIC, SINGULAR, STRING, firmware_version, 6) \ X(a, STATIC, SINGULAR, UENUM, error_code, 7) \ X(a, STATIC, SINGULAR, UINT32, error_address, 8) \ X(a, STATIC, SINGULAR, UINT32, error_count, 9) \ -X(a, STATIC, SINGULAR, UINT32, packet_id_bits, 10) \ -X(a, STATIC, SINGULAR, UINT32, current_packet_id, 11) \ -X(a, STATIC, SINGULAR, UINT32, node_num_bits, 12) \ X(a, STATIC, SINGULAR, UINT32, message_timeout_msec, 13) \ -X(a, STATIC, SINGULAR, UINT32, min_app_version, 14) +X(a, STATIC, SINGULAR, UINT32, min_app_version, 14) \ +X(a, STATIC, SINGULAR, UINT32, max_channels, 15) #define MyNodeInfo_CALLBACK NULL #define MyNodeInfo_DEFAULT NULL @@ -699,20 +710,20 @@ X(a, STATIC, ONEOF, MESSAGE, (payloadVariant,channel,channel), 10) #define FromRadio_payloadVariant_node_info_MSGTYPE NodeInfo #define FromRadio_payloadVariant_radio_MSGTYPE RadioConfig #define FromRadio_payloadVariant_log_record_MSGTYPE LogRecord -#define FromRadio_payloadVariant_channel_MSGTYPE ChannelSettings +#define FromRadio_payloadVariant_channel_MSGTYPE Channel #define ToRadio_FIELDLIST(X, a) \ X(a, STATIC, ONEOF, MESSAGE, (payloadVariant,packet,packet), 1) \ X(a, STATIC, ONEOF, UINT32, (payloadVariant,want_config_id,want_config_id), 100) \ X(a, STATIC, ONEOF, MESSAGE, (payloadVariant,set_radio,set_radio), 101) \ X(a, STATIC, ONEOF, MESSAGE, (payloadVariant,set_owner,set_owner), 102) \ -X(a, STATIC, ONEOF, MESSAGE, (payloadVariant,set_channel,set_channel), 103) +X(a, STATIC, ONEOF, MESSAGE, (payloadVariant,set_channel,set_channel), 104) #define ToRadio_CALLBACK NULL #define ToRadio_DEFAULT NULL #define ToRadio_payloadVariant_packet_MSGTYPE MeshPacket #define ToRadio_payloadVariant_set_radio_MSGTYPE RadioConfig #define ToRadio_payloadVariant_set_owner_MSGTYPE User -#define ToRadio_payloadVariant_set_channel_MSGTYPE ChannelSettings +#define ToRadio_payloadVariant_set_channel_MSGTYPE Channel extern const pb_msgdesc_t Position_msg; extern const pb_msgdesc_t Data_msg; @@ -721,6 +732,7 @@ extern const pb_msgdesc_t RouteDiscovery_msg; extern const pb_msgdesc_t SubPacket_msg; extern const pb_msgdesc_t MeshPacket_msg; extern const pb_msgdesc_t ChannelSettings_msg; +extern const pb_msgdesc_t Channel_msg; extern const pb_msgdesc_t RadioConfig_msg; extern const pb_msgdesc_t RadioConfig_UserPreferences_msg; extern const pb_msgdesc_t NodeInfo_msg; @@ -737,6 +749,7 @@ extern const pb_msgdesc_t ToRadio_msg; #define SubPacket_fields &SubPacket_msg #define MeshPacket_fields &MeshPacket_msg #define ChannelSettings_fields &ChannelSettings_msg +#define Channel_fields &Channel_msg #define RadioConfig_fields &RadioConfig_msg #define RadioConfig_UserPreferences_fields &RadioConfig_UserPreferences_msg #define NodeInfo_fields &NodeInfo_msg @@ -746,20 +759,21 @@ extern const pb_msgdesc_t ToRadio_msg; #define ToRadio_fields &ToRadio_msg /* Maximum encoded size of messages (where known) */ -#define Position_size 39 +#define Position_size 37 #define Data_size 246 #define User_size 72 #define RouteDiscovery_size 88 #define SubPacket_size 275 #define MeshPacket_size 322 #define ChannelSettings_size 95 -#define RadioConfig_size 405 +#define Channel_size 105 +#define RadioConfig_size 308 #define RadioConfig_UserPreferences_size 305 -#define NodeInfo_size 132 -#define MyNodeInfo_size 106 +#define NodeInfo_size 130 +#define MyNodeInfo_size 89 #define LogRecord_size 81 -#define FromRadio_size 414 -#define ToRadio_size 409 +#define FromRadio_size 331 +#define ToRadio_size 325 #ifdef __cplusplus } /* extern "C" */ diff --git a/src/mesh/mesh-pb-constants.h b/src/mesh/mesh-pb-constants.h index fd3b2cedf..ed1c4f7e8 100644 --- a/src/mesh/mesh-pb-constants.h +++ b/src/mesh/mesh-pb-constants.h @@ -16,6 +16,9 @@ /// max number of nodes allowed in the mesh #define MAX_NUM_NODES (member_size(DeviceState, node_db) / member_size(DeviceState, node_db[0])) +/// Max number of channels allowed +#define MAX_CHANNELS (member_size(DeviceState, channels) / member_size(DeviceState, channels[0])) + /// helper function for encoding a record as a protobuf, any failures to encode are fatal and we will panic /// returns the encoded packet size size_t pb_encode_to_bytes(uint8_t *destbuf, size_t destbufsize, const pb_msgdesc_t *fields, const void *src_struct); diff --git a/src/plugins/RangeTestPlugin.cpp b/src/plugins/RangeTestPlugin.cpp index 8f03589c2..58150f5bb 100644 --- a/src/plugins/RangeTestPlugin.cpp +++ b/src/plugins/RangeTestPlugin.cpp @@ -145,8 +145,9 @@ bool RangeTestPluginRadio::handleReceived(const MeshPacket &mp) DEBUG_MSG("mp.from %d\n", mp.from); DEBUG_MSG("mp.rx_snr %f\n", mp.rx_snr); DEBUG_MSG("mp.hop_limit %d\n", mp.hop_limit); - DEBUG_MSG("mp.decoded.position.latitude_i %d\n", mp.decoded.position.latitude_i); - DEBUG_MSG("mp.decoded.position.longitude_i %d\n", mp.decoded.position.longitude_i); + //deprecated and unpopulated for sometime + //DEBUG_MSG("mp.decoded.position.latitude_i %d\n", mp.decoded.position.latitude_i); + //DEBUG_MSG("mp.decoded.position.longitude_i %d\n", mp.decoded.position.longitude_i); DEBUG_MSG("---- Node Information of Received Packet (mp.from):\n"); DEBUG_MSG("n->user.long_name %s\n", n->user.long_name); DEBUG_MSG("n->user.short_name %s\n", n->user.short_name); From 937955b36d1d9241eadbed3a494fe6af188853ea Mon Sep 17 00:00:00 2001 From: Jm Date: Tue, 16 Feb 2021 17:42:46 -0800 Subject: [PATCH 112/258] Updating range test and storeforward. --- docs/software/plugins/StoreForwardPlugin.md | 4 +- src/plugins/StoreForwardPlugin.cpp | 55 ++++++++++++++++++--- src/plugins/StoreForwardPlugin.h | 20 ++++++-- 3 files changed, 67 insertions(+), 12 deletions(-) diff --git a/docs/software/plugins/StoreForwardPlugin.md b/docs/software/plugins/StoreForwardPlugin.md index 6761f50e6..e05171ed8 100644 --- a/docs/software/plugins/StoreForwardPlugin.md +++ b/docs/software/plugins/StoreForwardPlugin.md @@ -65,9 +65,9 @@ Structure of received messages: Structure of nodes and last time we heard from them. This is a record of any packet type. - senderRecord + receivedRecord From - rxTimeMsec + rxTimeMillis # General Operation for UC1 - automagically forward packets to a client that may have missed packets diff --git a/src/plugins/StoreForwardPlugin.cpp b/src/plugins/StoreForwardPlugin.cpp index ef0b23090..af9bf5ecd 100644 --- a/src/plugins/StoreForwardPlugin.cpp +++ b/src/plugins/StoreForwardPlugin.cpp @@ -5,6 +5,7 @@ #include "Router.h" #include "configuration.h" #include +#include StoreForwardPlugin *storeForwardPlugin; StoreForwardPluginRadio *storeForwardPluginRadio; @@ -21,8 +22,8 @@ int32_t StoreForwardPlugin::runOnce() without having to configure it from the PythonAPI or WebUI. */ - radioConfig.preferences.store_forward_plugin_enabled = 0; - radioConfig.preferences.is_router = 0; + // radioConfig.preferences.store_forward_plugin_enabled = 1; + // radioConfig.preferences.is_router = 1; if (radioConfig.preferences.store_forward_plugin_enabled) { @@ -60,13 +61,16 @@ int32_t StoreForwardPlugin::runOnce() DEBUG_MSG( "Initializing Store & Forward Plugin - If you want to use this plugin, you must also turn on is_router.\n"); // Non-Router + + return (30 * 1000); } } else { - // TBD + // What do we do if it's not our first time? + + // Maybe some cleanup functions? } - return (1000); } else { DEBUG_MSG("Store & Forward Plugin - Disabled\n"); @@ -77,6 +81,43 @@ int32_t StoreForwardPlugin::runOnce() return (INT32_MAX); } +// We saw a node. +uint32_t StoreForwardPlugin::sawNode(uint32_t node) +{ + + /* + TODO: Move receivedRecord into the PSRAM + + TODO: Gracefully handle the case where we run out of records. + Maybe replace the oldest record that hasn't been seen in a while and assume they won't be back. + + TODO: Implment this as a std::map for quicker lookups (maybe it doesn't matter?). + */ + + DEBUG_MSG("looking for node - %i\n", node); + for (int i = 0; i < 50; i++) { + DEBUG_MSG("Iterating through the seen nodes - %d %d %d\n", i, receivedRecord[i][0], receivedRecord[i][1]); + // First time seeing that node. + if (receivedRecord[i][0] == 0) { + DEBUG_MSG("New node! Woohoo! Win!\n"); + receivedRecord[i][0] = node; + receivedRecord[i][1] = millis(); + + return receivedRecord[i][1]; + } + + // We've seen this node before. + if (receivedRecord[i][0] == node) { + DEBUG_MSG("We've seen this node before\n"); + uint32_t lastSaw = receivedRecord[i][1]; + receivedRecord[i][1] = millis(); + return lastSaw; + } + } + + return 0; +} + MeshPacket *StoreForwardPluginRadio::allocReply() { @@ -101,9 +142,11 @@ bool StoreForwardPluginRadio::handleReceived(const MeshPacket &mp) // auto &p = mp.decoded.data; if (mp.from != nodeDB.getNodeNum()) { - DEBUG_MSG("Store & Forward Plugin -- Print Start ---------- ---------- ---------- ---------- ----------\n"); + DEBUG_MSG("Store & Forward Plugin -- Print Start ---------- ---------- ---------- ---------- ----------\n\n\n"); printPacket("----- PACKET FROM RADIO", &mp); - DEBUG_MSG("Store & Forward Plugin -- Print End ---------- ---------- ---------- ---------- ----------\n"); + // DEBUG_MSG("\n\nStore & Forward Plugin -- Print End ---------- ---------- ---------- ---------- ----------\n"); + uint32_t sawTime = storeForwardPlugin->sawNode(mp.from); + DEBUG_MSG("Last Saw this node %d, %d millis ago\n", mp.from, (millis() - sawTime)); } } else { diff --git a/src/plugins/StoreForwardPlugin.h b/src/plugins/StoreForwardPlugin.h index be9634913..e44d53704 100644 --- a/src/plugins/StoreForwardPlugin.h +++ b/src/plugins/StoreForwardPlugin.h @@ -10,9 +10,22 @@ class StoreForwardPlugin : private concurrency::OSThread { bool firstTime = 1; + // TODO: Move this into the PSRAM + // TODO: Allow configuration of the maximum number of records. + uint32_t receivedRecord[50][2] = {{0}}; + public: StoreForwardPlugin(); + /** + Update our local reference of when we last saw that node. + @return 0 if we have never seen that node before otherwise return the last time we saw the node. + */ + uint32_t sawNode(uint32_t); + + private: + // Nothing here + protected: virtual int32_t runOnce(); }; @@ -25,11 +38,11 @@ extern StoreForwardPlugin *storeForwardPlugin; */ class StoreForwardPluginRadio : public SinglePortPlugin { - //uint32_t lastRxID; + // uint32_t lastRxID; public: StoreForwardPluginRadio() : SinglePortPlugin("StoreForwardPluginRadio", PortNum_STORE_FORWARD_APP) {} - //StoreForwardPluginRadio() : SinglePortPlugin("StoreForwardPluginRadio", PortNum_TEXT_MESSAGE_APP) {} + // StoreForwardPluginRadio() : SinglePortPlugin("StoreForwardPluginRadio", PortNum_TEXT_MESSAGE_APP) {} /** * Send our payload into the mesh @@ -39,7 +52,7 @@ class StoreForwardPluginRadio : public SinglePortPlugin protected: virtual MeshPacket *allocReply(); - virtual bool wantPortnum(PortNum p){return true;}; + virtual bool wantPortnum(PortNum p) { return true; }; /** Called to handle a particular incoming message @@ -49,4 +62,3 @@ class StoreForwardPluginRadio : public SinglePortPlugin }; extern StoreForwardPluginRadio *storeForwardPluginRadio; - From a4fd74b58ec78309f848b0e2ce8a32267bcf9cb8 Mon Sep 17 00:00:00 2001 From: Jm Date: Tue, 16 Feb 2021 18:07:02 -0800 Subject: [PATCH 113/258] Update Plugins.cpp --- src/plugins/Plugins.cpp | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/plugins/Plugins.cpp b/src/plugins/Plugins.cpp index 69e68ea4f..0c18389b4 100644 --- a/src/plugins/Plugins.cpp +++ b/src/plugins/Plugins.cpp @@ -1,12 +1,15 @@ #include "plugins/ExternalNotificationPlugin.h" #include "plugins/NodeInfoPlugin.h" #include "plugins/PositionPlugin.h" -#include "plugins/RangeTestPlugin.h" #include "plugins/RemoteHardwarePlugin.h" #include "plugins/ReplyPlugin.h" +#include "plugins/TextMessagePlugin.h" + +#ifndef NO_ESP32 +#include "plugins/RangeTestPlugin.h" #include "plugins/SerialPlugin.h" #include "plugins/StoreForwardPlugin.h" -#include "plugins/TextMessagePlugin.h" +#endif /** * Create plugin instances here. If you are adding a new plugin, you must 'new' it here (or somewhere else) @@ -32,10 +35,10 @@ void setupPlugins() new SerialPlugin(); new ExternalNotificationPlugin(); - //rangeTestPlugin = new RangeTestPlugin(); + // rangeTestPlugin = new RangeTestPlugin(); storeForwardPlugin = new StoreForwardPlugin(); new RangeTestPlugin(); - //new StoreForwardPlugin(); + // new StoreForwardPlugin(); #endif } \ No newline at end of file From 205282c4bcd13160cada7f3cd0e40774a21bff44 Mon Sep 17 00:00:00 2001 From: Kevin Hester Date: Wed, 17 Feb 2021 10:08:33 +0800 Subject: [PATCH 114/258] show hwvendor at boot --- src/main.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main.cpp b/src/main.cpp index bb3ec4820..985bec808 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -356,7 +356,7 @@ void setup() #endif // Hello - DEBUG_MSG("Meshtastic swver=%s, hwver=%s\n", optstr(APP_VERSION), optstr(HW_VERSION)); + DEBUG_MSG("Meshtastic hwvendor=%s, swver=%s, hwver=%s\n", HW_VENDOR, optstr(APP_VERSION), optstr(HW_VERSION)); #ifndef NO_ESP32 // Don't init display if we don't have one or we are waking headless due to a timer event From b35cd7685456b5f74b5580115cd92e3a9b71f23a Mon Sep 17 00:00:00 2001 From: Jm Casler Date: Tue, 16 Feb 2021 18:19:24 -0800 Subject: [PATCH 115/258] Update StoreForwardPlugin.md --- docs/software/plugins/StoreForwardPlugin.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/docs/software/plugins/StoreForwardPlugin.md b/docs/software/plugins/StoreForwardPlugin.md index e05171ed8..cb104314a 100644 --- a/docs/software/plugins/StoreForwardPlugin.md +++ b/docs/software/plugins/StoreForwardPlugin.md @@ -51,6 +51,10 @@ In this case, we have two routers separate by a great distance, each serving mul Q: How do we rejoin both fragmented networks? Do we care about messages that were unrouted between fagments? +## Identifing Delayed Messages + +When a message is replayed for a node, identify the packet as "Delayed". This will indicate that the message was not received in real time. + # Router Data Structures Structure of received messages: @@ -90,4 +94,4 @@ On every handled packet, if we have not heard from that sender in a period of ti # Designed limitations -The Store and Forward plugin will subscribe to specific packet types and channels and only save those. This will both reduce the amount of data we will need to store and reduce the overhead on the network. Eg: There's no need to replay ACK packets nor is there's no need to replay old location packets. \ No newline at end of file +The Store and Forward plugin will subscribe to specific packet types and channels and only save those. This will both reduce the amount of data we will need to store and reduce the overhead on the network. Eg: There's no need to replay ACK packets nor is there's no need to replay old location packets. From bd29d78a29dcb6b3b8de33b33dc4ec3e089ff1ba Mon Sep 17 00:00:00 2001 From: Jm Casler Date: Tue, 16 Feb 2021 18:24:37 -0800 Subject: [PATCH 116/258] Update StoreForwardPlugin.md --- docs/software/plugins/StoreForwardPlugin.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/software/plugins/StoreForwardPlugin.md b/docs/software/plugins/StoreForwardPlugin.md index cb104314a..129005baf 100644 --- a/docs/software/plugins/StoreForwardPlugin.md +++ b/docs/software/plugins/StoreForwardPlugin.md @@ -27,6 +27,8 @@ UC 3) router sends a periodic “heartbeat” to let the clients know they’re UC 4) support for a mesh to have multiple routers that have the store & forward functionality (for redundancy) +UC 5) Support for "long term" delayed messages and "short term" delayed messages. Handle the cases slightly different to improve user expierence. A short term delayed message would be a message that was resent becaue a node was not heard from for <5 minutes. A long term delayed message is a message that has not been delivered in >5 minutes. + # Things to consider Not all these cases will be initially implemented. It's just a running stream of thoughts to be considered. From 6376ab51f1e5f7888e31794b56a4554540c6e8b5 Mon Sep 17 00:00:00 2001 From: Jm Casler Date: Tue, 16 Feb 2021 18:36:30 -0800 Subject: [PATCH 117/258] Moving to plugins/esp32 --- src/plugins/{ => esp32}/RangeTestPlugin.cpp | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename src/plugins/{ => esp32}/RangeTestPlugin.cpp (100%) diff --git a/src/plugins/RangeTestPlugin.cpp b/src/plugins/esp32/RangeTestPlugin.cpp similarity index 100% rename from src/plugins/RangeTestPlugin.cpp rename to src/plugins/esp32/RangeTestPlugin.cpp From f24e8e5f5c4b26bc866395a17aa8f2183075f4fa Mon Sep 17 00:00:00 2001 From: Jm Casler Date: Tue, 16 Feb 2021 18:36:58 -0800 Subject: [PATCH 118/258] Rename src/plugins/RangeTestPlugin.h to src/plugins/esp32/RangeTestPlugin.h --- src/plugins/{ => esp32}/RangeTestPlugin.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename src/plugins/{ => esp32}/RangeTestPlugin.h (96%) diff --git a/src/plugins/RangeTestPlugin.h b/src/plugins/esp32/RangeTestPlugin.h similarity index 96% rename from src/plugins/RangeTestPlugin.h rename to src/plugins/esp32/RangeTestPlugin.h index 8a10ca395..be998e510 100644 --- a/src/plugins/RangeTestPlugin.h +++ b/src/plugins/esp32/RangeTestPlugin.h @@ -55,4 +55,4 @@ class RangeTestPluginRadio : public SinglePortPlugin virtual bool handleReceived(const MeshPacket &mp); }; -extern RangeTestPluginRadio *rangeTestPluginRadio; \ No newline at end of file +extern RangeTestPluginRadio *rangeTestPluginRadio; From e840465ef3429046258af5dbafb1c2d0cc6bab75 Mon Sep 17 00:00:00 2001 From: Jm Date: Tue, 16 Feb 2021 18:46:16 -0800 Subject: [PATCH 119/258] fix for failed builds on nrf and linux --- platformio.ini | 4 ++-- src/plugins/Plugins.cpp | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/platformio.ini b/platformio.ini index 4b91317d9..89cf5a1ac 100644 --- a/platformio.ini +++ b/platformio.ini @@ -188,7 +188,7 @@ build_flags = -Isdk-nrfxlib/crypto/nrf_oberon/include -Lsdk-nrfxlib/crypto/nrf_oberon/lib/cortex-m4/hard-float/ -lliboberon_3.0.7 ;-DCFG_DEBUG=3 src_filter = - ${arduino_base.src_filter} - - - - + ${arduino_base.src_filter} - - - - - lib_ignore = BluetoothOTA monitor_port = /dev/ttyACM1 @@ -329,7 +329,7 @@ lib_deps = ; The Portduino based sim environment on top of linux [env:linux] platform = https://github.com/geeksville/platform-portduino.git -src_filter = ${env.src_filter} - - - - +src_filter = ${env.src_filter} - - - - - build_flags = ${arduino_base.build_flags} -O0 framework = arduino board = linux_x86_64 diff --git a/src/plugins/Plugins.cpp b/src/plugins/Plugins.cpp index 0c18389b4..c2dfd73ca 100644 --- a/src/plugins/Plugins.cpp +++ b/src/plugins/Plugins.cpp @@ -6,7 +6,7 @@ #include "plugins/TextMessagePlugin.h" #ifndef NO_ESP32 -#include "plugins/RangeTestPlugin.h" +#include "plugins/esp32/RangeTestPlugin.h" #include "plugins/SerialPlugin.h" #include "plugins/StoreForwardPlugin.h" #endif From 42ae27973e977bdc5e5739f48a011a13f47b8355 Mon Sep 17 00:00:00 2001 From: Kevin Hester Date: Wed, 17 Feb 2021 13:06:23 +0800 Subject: [PATCH 120/258] WIP 1.2 move routing into plugin --- docs/software/TODO.md | 24 +++- proto | 2 +- src/graphics/Screen.cpp | 3 +- src/mesh/Channels.cpp | 2 +- src/mesh/DSRRouter.cpp | 30 ++-- src/mesh/DSRRouter.h | 4 +- src/mesh/FloodingRouter.cpp | 4 +- src/mesh/FloodingRouter.h | 2 +- src/mesh/MeshPacketQueue.cpp | 2 +- src/mesh/MeshPlugin.cpp | 4 +- src/mesh/MeshPlugin.h | 6 + src/mesh/NodeDB.cpp | 20 +-- src/mesh/ProtobufPlugin.h | 8 +- src/mesh/RadioInterface.cpp | 23 ++- src/mesh/ReliableRouter.cpp | 14 +- src/mesh/ReliableRouter.h | 2 +- src/mesh/Router.cpp | 39 ++---- src/mesh/Router.h | 8 +- src/mesh/SinglePortPlugin.h | 3 +- src/mesh/generated/apponly.pb.c | 3 + src/mesh/generated/apponly.pb.h | 16 +++ src/mesh/generated/deviceonly.pb.h | 2 +- src/mesh/generated/mesh.pb.c | 8 +- src/mesh/generated/mesh.pb.h | 215 ++++++++++++++--------------- src/mesh/generated/portnums.pb.h | 1 + src/mesh/mesh-pb-constants.h | 2 +- src/plugins/Plugins.cpp | 2 + src/plugins/RangeTestPlugin.cpp | 4 +- src/plugins/ReplyPlugin.cpp | 6 +- src/plugins/RoutingPlugin.cpp | 54 ++++++++ src/plugins/RoutingPlugin.h | 31 +++++ src/plugins/SerialPlugin.cpp | 4 +- src/plugins/TextMessagePlugin.cpp | 2 +- 33 files changed, 317 insertions(+), 233 deletions(-) create mode 100644 src/plugins/RoutingPlugin.cpp create mode 100644 src/plugins/RoutingPlugin.h diff --git a/docs/software/TODO.md b/docs/software/TODO.md index ded8796de..c4569cbda 100644 --- a/docs/software/TODO.md +++ b/docs/software/TODO.md @@ -4,16 +4,26 @@ You probably don't care about this section - skip to the next one. 1.2 cleanup & multichannel: -* remove deprecated +* DONE remove deprecated * allow chaning packets in single transmission -* fix setchannel in phoneapi.cpp -* set mynodeinfo.max_channels -* set mynodeinfo.num_bands (formerly num_channels) +* DONE fix setchannel in phoneapi.cpp +* DONE set mynodeinfo.max_channels +* DONE set mynodeinfo.num_bands (formerly num_channels) +* fix sniffing of non Routing packets +* move portnum up? +* scrub protobufs to make sure they are absoloute minimum wiresize (in particular packets, ChannelSets and positions) * send a hint that can be used to select which channel to try and hash against with each message * change syncword -* move acks into routing -* make all subpackets different versions of data -* move routing control into a data packet +* DONE move acks into routing +* DONE make all subpackets different versions of data +* DONE move routing control into a data packet +* have phoneapi done via plugin +* figure out how to add micro_delta to position, make it so that phone apps don't need to understand it? +* only send battery updates a max of once a minute +* add multichannel support in python +* add channel selection for sending +* record recevied channel in meshpacket +* add channel restrictions for plugins (and restrict routing plugin to the "control" channel) * make a primaryChannel global and properly maintain it when the phone sends setChannel * move setCrypto call into packet send and packet decode code * implement'small locations' change? diff --git a/proto b/proto index 481beb41b..65914b84f 160000 --- a/proto +++ b/proto @@ -1 +1 @@ -Subproject commit 481beb41ba8c8f39bfc6b3f397d6107af04dfb93 +Subproject commit 65914b84f1ee8f25807187d60b43ad29dfbaedc3 diff --git a/src/graphics/Screen.cpp b/src/graphics/Screen.cpp index f7193260f..a2c74ba7e 100644 --- a/src/graphics/Screen.cpp +++ b/src/graphics/Screen.cpp @@ -216,8 +216,7 @@ static void drawTextMessageFrame(OLEDDisplay *display, OLEDDisplayUiState *state // the max length of this buffer is much longer than we can possibly print static char tempBuf[96]; - assert(mp.decoded.which_payloadVariant == SubPacket_data_tag); - snprintf(tempBuf, sizeof(tempBuf), " %s", mp.decoded.data.payload.bytes); + snprintf(tempBuf, sizeof(tempBuf), " %s", mp.decoded.payload.bytes); display->drawStringMaxWidth(4 + x, 10 + y, SCREEN_WIDTH - (6 + x), tempBuf); } diff --git a/src/mesh/Channels.cpp b/src/mesh/Channels.cpp index 584a83bc8..510510ca3 100644 --- a/src/mesh/Channels.cpp +++ b/src/mesh/Channels.cpp @@ -118,7 +118,7 @@ void setCrypto(size_t chIndex) void Channels::initDefaults() { - devicestate.channels_count = MAX_CHANNELS; + devicestate.channels_count = MAX_NUM_CHANNELS; for (int i = 0; i < devicestate.channels_count; i++) fixupChannel(i); initDefaultChannel(0); diff --git a/src/mesh/DSRRouter.cpp b/src/mesh/DSRRouter.cpp index 8b1e6f67e..04d4a2bef 100644 --- a/src/mesh/DSRRouter.cpp +++ b/src/mesh/DSRRouter.cpp @@ -62,7 +62,7 @@ ErrorCode DSRRouter::send(MeshPacket *p) return ReliableRouter::send(p); } -void DSRRouter::sniffReceived(const MeshPacket *p) +void DSRRouter::sniffReceived(const MeshPacket *p, const Routing &c) { // Learn 0 hop routes by just hearing any adjacent nodes // But treat broadcasts carefully, because when flood broadcasts go out they keep the same original "from". So we want to @@ -72,25 +72,25 @@ void DSRRouter::sniffReceived(const MeshPacket *p) addRoute(p->from, p->from, 0); // We are adjacent with zero hops } - switch (p->decoded.which_payloadVariant) { - case SubPacket_route_request_tag: + switch (c.which_variant) { + case Routing_route_request_tag: // Handle route discovery packets (will be a broadcast message) // FIXME - always start request with the senders nodenum - if (weAreInRoute(p->decoded.route_request)) { + if (weAreInRoute(c.route_request)) { DEBUG_MSG("Ignoring a route request that contains us\n"); } else { - updateRoutes(p->decoded.route_request, + updateRoutes(c.route_request, true); // Update our routing tables based on the route that came in so far on this request if (p->decoded.dest == getNodeNum()) { // They were looking for us, send back a route reply (the sender address will be first in the list) - sendRouteReply(p->decoded.route_request); + sendRouteReply(c.route_request); } else { // They were looking for someone else, forward it along (as a zero hop broadcast) NodeNum nextHop = getNextHop(p->decoded.dest); if (nextHop) { // in our route cache, reply to the requester (the sender address will be first in the list) - sendRouteReply(p->decoded.route_request, nextHop); + sendRouteReply(c.route_request, nextHop); } else { // Not in our route cache, rebroadcast on their behalf (after adding ourselves to the request route) resendRouteRequest(p); @@ -98,14 +98,14 @@ void DSRRouter::sniffReceived(const MeshPacket *p) } } break; - case SubPacket_route_reply_tag: - updateRoutes(p->decoded.route_reply, false); + case Routing_route_reply_tag: + updateRoutes(c.route_reply, false); // FIXME, if any of our current pending packets were waiting for this route, send them (and leave them as regular pending // packets until ack arrives) // FIXME, if we don't get a route reply at all (or a route error), timeout and generate a routeerror TIMEOUT on our own... break; - case SubPacket_error_reason_tag: + case Routing_error_reason_tag: removeRoute(p->decoded.dest); // FIXME: if any pending packets were waiting on this route, delete them @@ -131,7 +131,7 @@ void DSRRouter::sniffReceived(const MeshPacket *p) assert(p->decoded.source); // I think this is guaranteed by now // FIXME - what if the current packet _is_ a route error packet? - sendRouteError(p, ErrorReason_NO_ROUTE); + sendRouteError(p, Routing_Error_NO_ROUTE); } // FIXME, stop local processing of this packet @@ -139,18 +139,18 @@ void DSRRouter::sniffReceived(const MeshPacket *p) // handle naks - convert them to route error packets // All naks are generated locally, because we failed resending the packet too many times - PacketId nakId = p->decoded.which_ackVariant == SubPacket_fail_id_tag ? p->decoded.ackVariant.fail_id : 0; + PacketId nakId = c.fail_id; if (nakId) { auto pending = findPendingPacket(p->to, nakId); if (pending && pending->packet->decoded.source) { // if source not set, this was not a multihop packet, just ignore removeRoute(pending->packet->decoded.dest); // We no longer have a route to the specified node - sendRouteError(p, ErrorReason_GOT_NAK); + sendRouteError(p, Routing_Error_GOT_NAK); } } } - return ReliableRouter::sniffReceived(p); + ReliableRouter::sniffReceived(p, c); } /** @@ -230,7 +230,7 @@ void DSRRouter::sendNextHop(NodeNum n, const MeshPacket *p) /** * Send a route error packet towards whoever originally sent this message */ -void DSRRouter::sendRouteError(const MeshPacket *p, ErrorReason err) +void DSRRouter::sendRouteError(const MeshPacket *p, Routing_Error err) { DEBUG_MSG("FIXME not implemented sendRouteError\n"); } diff --git a/src/mesh/DSRRouter.h b/src/mesh/DSRRouter.h index 02c0f2775..eef1a991c 100644 --- a/src/mesh/DSRRouter.h +++ b/src/mesh/DSRRouter.h @@ -8,7 +8,7 @@ class DSRRouter : public ReliableRouter * Every (non duplicate) packet this node receives will be passed through this method. This allows subclasses to * update routing tables etc... based on what we overhear (even for messages not destined to our node) */ - virtual void sniffReceived(const MeshPacket *p); + virtual void sniffReceived(const MeshPacket *p, const Routing &c); /** * Send a packet on a suitable interface. This routine will @@ -70,7 +70,7 @@ class DSRRouter : public ReliableRouter /** * Send a route error packet towards whoever originally sent this message */ - void sendRouteError(const MeshPacket *p, ErrorReason err); + void sendRouteError(const MeshPacket *p, Routing_Error err); /** make a copy of p, start discovery, but only if we don't * already a discovery in progress for that node number. Caller has already scheduled this message for retransmission diff --git a/src/mesh/FloodingRouter.cpp b/src/mesh/FloodingRouter.cpp index f2b718835..777178c41 100644 --- a/src/mesh/FloodingRouter.cpp +++ b/src/mesh/FloodingRouter.cpp @@ -27,7 +27,7 @@ bool FloodingRouter::shouldFilterReceived(const MeshPacket *p) return Router::shouldFilterReceived(p); } -void FloodingRouter::sniffReceived(const MeshPacket *p) +void FloodingRouter::sniffReceived(const MeshPacket *p, const Routing &c) { // If a broadcast, possibly _also_ send copies out into the mesh. // (FIXME, do something smarter than naive flooding here) @@ -48,5 +48,5 @@ void FloodingRouter::sniffReceived(const MeshPacket *p) } // handle the packet as normal - Router::sniffReceived(p); + Router::sniffReceived(p, c); } diff --git a/src/mesh/FloodingRouter.h b/src/mesh/FloodingRouter.h index ca7ee489f..3e4f5de6e 100644 --- a/src/mesh/FloodingRouter.h +++ b/src/mesh/FloodingRouter.h @@ -55,5 +55,5 @@ class FloodingRouter : public Router, protected PacketHistory /** * Look for broadcasts we need to rebroadcast */ - virtual void sniffReceived(const MeshPacket *p); + virtual void sniffReceived(const MeshPacket *p, const Routing &c); }; diff --git a/src/mesh/MeshPacketQueue.cpp b/src/mesh/MeshPacketQueue.cpp index 363e83ba7..56db3feb3 100644 --- a/src/mesh/MeshPacketQueue.cpp +++ b/src/mesh/MeshPacketQueue.cpp @@ -33,7 +33,7 @@ void fixPriority(MeshPacket *p) if (p->priority == MeshPacket_Priority_UNSET) { // if acks give high priority // if a reliable message give a bit higher default priority - p->priority = p->decoded.which_ackVariant ? MeshPacket_Priority_ACK : + p->priority = (p->decoded.portnum == PortNum_ROUTING_APP) ? MeshPacket_Priority_ACK : (p->want_ack ? MeshPacket_Priority_RELIABLE : MeshPacket_Priority_DEFAULT); } } diff --git a/src/mesh/MeshPlugin.cpp b/src/mesh/MeshPlugin.cpp index ebaee49a6..7befb6623 100644 --- a/src/mesh/MeshPlugin.cpp +++ b/src/mesh/MeshPlugin.cpp @@ -32,7 +32,7 @@ void MeshPlugin::callPlugins(const MeshPacket &mp) auto &pi = **i; pi.currentRequest = ∓ - if (pi.wantPortnum(mp.decoded.data.portnum)) { + if (pi.wantPortnum(mp.decoded.portnum)) { pluginFound = true; bool handled = pi.handleReceived(mp); @@ -50,7 +50,7 @@ void MeshPlugin::callPlugins(const MeshPacket &mp) } if(!pluginFound) - DEBUG_MSG("No plugins interested in portnum=%d\n", mp.decoded.data.portnum); + DEBUG_MSG("No plugins interested in portnum=%d\n", mp.decoded.portnum); } /** Messages can be received that have the want_response bit set. If set, this callback will be invoked diff --git a/src/mesh/MeshPlugin.h b/src/mesh/MeshPlugin.h index 01af58114..1c90f8829 100644 --- a/src/mesh/MeshPlugin.h +++ b/src/mesh/MeshPlugin.h @@ -31,6 +31,12 @@ class MeshPlugin protected: const char *name; + /* Most plugins only care about packets that are destined for their node (i.e. broadcasts or has their node as the specific recipient) + But some plugs might want to 'sniff' packets that are merely being routed (passing through the current node). Those plugins can set this to + true and their handleReceived() will be called for every packet. + */ + bool isPromiscuous = false; + /** * If this plugin is currently handling a request currentRequest will be preset * to the packet with the request. This is mostly useful for reply handlers. diff --git a/src/mesh/NodeDB.cpp b/src/mesh/NodeDB.cpp index 9347ef0fd..3cc6b000b 100644 --- a/src/mesh/NodeDB.cpp +++ b/src/mesh/NodeDB.cpp @@ -4,6 +4,7 @@ #include "FS.h" +#include "Channels.h" #include "CryptoEngine.h" #include "FSCommon.h" #include "GPS.h" @@ -16,7 +17,6 @@ #include "configuration.h" #include "error.h" #include "main.h" -#include "Channels.h" #include "mesh-pb-constants.h" #include #include @@ -160,7 +160,7 @@ void NodeDB::init() loadFromDisk(); // saveToDisk(); - myNodeInfo.max_channels = MAX_CHANNELS; // tell others the max # of channels we can understand + myNodeInfo.max_channels = MAX_NUM_CHANNELS; // tell others the max # of channels we can understand myNodeInfo.error_code = CriticalErrorCode_None; // For the error code, only show values from this boot (discard value from flash) @@ -394,7 +394,7 @@ void NodeDB::updateUser(uint32_t nodeId, const User &p) void NodeDB::updateFrom(const MeshPacket &mp) { if (mp.which_payloadVariant == MeshPacket_decoded_tag) { - const SubPacket &p = mp.decoded; + const Data &p = mp.decoded; DEBUG_MSG("Update DB node 0x%x, rx_time=%u\n", mp.from, mp.rx_time); NodeInfo *info = getOrCreateNode(mp.from); @@ -406,18 +406,8 @@ void NodeDB::updateFrom(const MeshPacket &mp) info->snr = mp.rx_snr; // keep the most recent SNR we received for this node. - switch (p.which_payloadVariant) { - - case SubPacket_data_tag: { - if (mp.to == NODENUM_BROADCAST || mp.to == nodeDB.getNodeNum()) - MeshPlugin::callPlugins(mp); - break; - } - - default: { - notifyObservers(); // If the node counts have changed, notify observers - } - } + if (mp.to == NODENUM_BROADCAST || mp.to == nodeDB.getNodeNum()) + MeshPlugin::callPlugins(mp); } } diff --git a/src/mesh/ProtobufPlugin.h b/src/mesh/ProtobufPlugin.h index a5c0aea15..d931185e0 100644 --- a/src/mesh/ProtobufPlugin.h +++ b/src/mesh/ProtobufPlugin.h @@ -8,7 +8,7 @@ * If you are using protobufs to encode your packets (recommended) you can use this as a baseclass for your plugin * and avoid a bunch of boilerplate code. */ -template class ProtobufPlugin : private SinglePortPlugin +template class ProtobufPlugin : protected SinglePortPlugin { const pb_msgdesc_t *fields; @@ -38,8 +38,8 @@ template class ProtobufPlugin : private SinglePortPlugin // Update our local node info with our position (even if we don't decide to update anyone else) MeshPacket *p = allocDataPacket(); - p->decoded.data.payload.size = - pb_encode_to_bytes(p->decoded.data.payload.bytes, sizeof(p->decoded.data.payload.bytes), fields, &payload); + p->decoded.payload.size = + pb_encode_to_bytes(p->decoded.payload.bytes, sizeof(p->decoded.payload.bytes), fields, &payload); // DEBUG_MSG("did encode\n"); return p; } @@ -54,7 +54,7 @@ template class ProtobufPlugin : private SinglePortPlugin // FIXME - we currently update position data in the DB only if the message was a broadcast or destined to us // it would be better to update even if the message was destined to others. - auto &p = mp.decoded.data; + auto &p = mp.decoded; DEBUG_MSG("Received %s from=0x%0x, id=0x%x, payloadlen=%d\n", name, mp.from, mp.id, p.payload.size); T scratch; diff --git a/src/mesh/RadioInterface.cpp b/src/mesh/RadioInterface.cpp index 0d99ca2ff..08ac40d5d 100644 --- a/src/mesh/RadioInterface.cpp +++ b/src/mesh/RadioInterface.cpp @@ -1,12 +1,12 @@ #include "RadioInterface.h" +#include "Channels.h" #include "MeshRadio.h" #include "MeshService.h" #include "NodeDB.h" #include "assert.h" #include "configuration.h" #include "sleep.h" -#include "Channels.h" #include #include #include @@ -122,17 +122,9 @@ void printPacket(const char *prefix, const MeshPacket *p) p->hop_limit); if (p->which_payloadVariant == MeshPacket_decoded_tag) { auto &s = p->decoded; - switch (s.which_payloadVariant) { - case SubPacket_data_tag: - DEBUG_MSG(" Portnum=%d", s.data.portnum); - break; - case 0: - DEBUG_MSG(" Payload:None"); - break; - default: - DEBUG_MSG(" Payload:%d", s.which_payloadVariant); - break; - } + + DEBUG_MSG(" Portnum=%d", s.portnum); + if (s.want_response) DEBUG_MSG(" WANTRESP"); @@ -142,10 +134,11 @@ void printPacket(const char *prefix, const MeshPacket *p) if (s.dest != 0) DEBUG_MSG(" dest=%08x", s.dest); + /* now inside Data and therefore kinda opaque if (s.which_ackVariant == SubPacket_success_id_tag) DEBUG_MSG(" successId=%08x", s.ackVariant.success_id); else if (s.which_ackVariant == SubPacket_fail_id_tag) - DEBUG_MSG(" failId=%08x", s.ackVariant.fail_id); + DEBUG_MSG(" failId=%08x", s.ackVariant.fail_id); */ } else { DEBUG_MSG(" encrypted"); } @@ -156,9 +149,9 @@ void printPacket(const char *prefix, const MeshPacket *p) if (p->rx_snr != 0.0) { DEBUG_MSG(" rxSNR=%g", p->rx_snr); } - if(p->priority != 0) + if (p->priority != 0) DEBUG_MSG(" priority=%d", p->priority); - + DEBUG_MSG(")\n"); } diff --git a/src/mesh/ReliableRouter.cpp b/src/mesh/ReliableRouter.cpp index 3bc8bfde5..3dc07c9c9 100644 --- a/src/mesh/ReliableRouter.cpp +++ b/src/mesh/ReliableRouter.cpp @@ -34,7 +34,7 @@ bool ReliableRouter::shouldFilterReceived(const MeshPacket *p) // the original sending process. if (stopRetransmission(p->from, p->id)) { DEBUG_MSG("Someone is retransmitting for us, generate implicit ack\n"); - sendAckNak(ErrorReason_NONE, p->from, p->id); + sendAckNak(Routing_Error_NONE, p->from, p->id); } } @@ -53,20 +53,20 @@ bool ReliableRouter::shouldFilterReceived(const MeshPacket *p) * * Otherwise, let superclass handle it. */ -void ReliableRouter::sniffReceived(const MeshPacket *p) +void ReliableRouter::sniffReceived(const MeshPacket *p, const Routing &c) { NodeNum ourNode = getNodeNum(); if (p->to == ourNode) { // ignore ack/nak/want_ack packets that are not address to us (we only handle 0 hop reliability // - not DSR routing) if (p->want_ack) { - sendAckNak(ErrorReason_NONE, p->from, p->id); + sendAckNak(Routing_Error_NONE, p->from, p->id); } // If the payload is valid, look for ack/nak - PacketId ackId = p->decoded.which_ackVariant == SubPacket_success_id_tag ? p->decoded.ackVariant.success_id : 0; - PacketId nakId = p->decoded.which_ackVariant == SubPacket_fail_id_tag ? p->decoded.ackVariant.fail_id : 0; + PacketId ackId = c.success_id; + PacketId nakId = c.fail_id; // We intentionally don't check wasSeenRecently, because it is harmless to delete non existent retransmission records if (ackId || nakId) { @@ -81,7 +81,7 @@ void ReliableRouter::sniffReceived(const MeshPacket *p) } // handle the packet as normal - FloodingRouter::sniffReceived(p); + FloodingRouter::sniffReceived(p, c); } #define NUM_RETRANSMISSIONS 3 @@ -155,7 +155,7 @@ int32_t ReliableRouter::doRetransmissions() if (p.numRetransmissions == 0) { DEBUG_MSG("Reliable send failed, returning a nak fr=0x%x,to=0x%x,id=%d\n", p.packet->from, p.packet->to, p.packet->id); - sendAckNak(ErrorReason_MAX_RETRANSMIT, p.packet->from, p.packet->id); + sendAckNak(Routing_Error_MAX_RETRANSMIT, p.packet->from, p.packet->id); // Note: we don't stop retransmission here, instead the Nak packet gets processed in sniffReceived - which // allows the DSR version to still be able to look at the PendingPacket stopRetransmission(it->first); diff --git a/src/mesh/ReliableRouter.h b/src/mesh/ReliableRouter.h index 62d555389..bf0338f9b 100644 --- a/src/mesh/ReliableRouter.h +++ b/src/mesh/ReliableRouter.h @@ -90,7 +90,7 @@ class ReliableRouter : public FloodingRouter /** * Look for acks/naks or someone retransmitting us */ - virtual void sniffReceived(const MeshPacket *p); + virtual void sniffReceived(const MeshPacket *p, const Routing &c); /** * Try to find the pending packet record for this ID (or NULL if not found) diff --git a/src/mesh/Router.cpp b/src/mesh/Router.cpp index 5178e229b..f20cf02bf 100644 --- a/src/mesh/Router.cpp +++ b/src/mesh/Router.cpp @@ -4,6 +4,7 @@ #include "configuration.h" #include "mesh-pb-constants.h" #include +#include "plugins/RoutingPlugin.h" /** * Router todo @@ -101,27 +102,9 @@ MeshPacket *Router::allocForSending() /** * Send an ack or a nak packet back towards whoever sent idFrom */ -void Router::sendAckNak(ErrorReason err, NodeNum to, PacketId idFrom) +void Router::sendAckNak(Routing_Error err, NodeNum to, PacketId idFrom) { - auto p = allocForSending(); - p->hop_limit = 0; // Assume just immediate neighbors for now - p->to = to; - DEBUG_MSG("Sending an err=%d,to=0x%x,idFrom=0x%x,id=0x%x\n", err, to, idFrom, p->id); - - if (!err) { - p->decoded.ackVariant.success_id = idFrom; - p->decoded.which_ackVariant = SubPacket_success_id_tag; - } else { - p->decoded.ackVariant.fail_id = idFrom; - p->decoded.which_ackVariant = SubPacket_fail_id_tag; - - // Also send back the error reason - p->decoded.which_payloadVariant = SubPacket_error_reason_tag; - p->decoded.error_reason = err; - } - p->priority = MeshPacket_Priority_ACK; - - sendLocal(p); // we sometimes send directly to the local node + routingPlugin->sendAckNak(err, to, idFrom); } @@ -138,7 +121,7 @@ ErrorCode Router::sendLocal(MeshPacket *p) // ERROR! no radio found, report failure back to the client and drop the packet DEBUG_MSG("Error: No interface, returning NAK and dropping packet.\n"); - sendAckNak(ErrorReason_NO_INTERFACE, p->from, p->id); + sendAckNak(Routing_Error_NO_INTERFACE, p->from, p->id); packetPool.release(p); return ERRNO_NO_INTERFACES; @@ -162,9 +145,8 @@ ErrorCode Router::send(MeshPacket *p) { assert(p->to != nodeDB.getNodeNum()); // should have already been handled by sendLocal - PacketId nakId = p->decoded.which_ackVariant == SubPacket_fail_id_tag ? p->decoded.ackVariant.fail_id : 0; - assert( - !nakId); // I don't think we ever send 0hop naks over the wire (other than to the phone), test that assumption with assert + // PacketId nakId = p->decoded.which_ackVariant == SubPacket_fail_id_tag ? p->decoded.ackVariant.fail_id : 0; + // assert(!nakId); // I don't think we ever send 0hop naks over the wire (other than to the phone), test that assumption with assert // Never set the want_ack flag on broadcast packets sent over the air. if (p->to == NODENUM_BROADCAST) @@ -179,7 +161,7 @@ ErrorCode Router::send(MeshPacket *p) if (p->which_payloadVariant == MeshPacket_decoded_tag) { static uint8_t bytes[MAX_RHPACKETLEN]; // we have to use a scratch buffer because a union - size_t numbytes = pb_encode_to_bytes(bytes, sizeof(bytes), SubPacket_fields, &p->decoded); + size_t numbytes = pb_encode_to_bytes(bytes, sizeof(bytes), Data_fields, &p->decoded); assert(numbytes <= MAX_RHPACKETLEN); crypto->encrypt(p->from, p->id, numbytes, bytes); @@ -212,7 +194,7 @@ bool Router::cancelSending(NodeNum from, PacketId id) { * Every (non duplicate) packet this node receives will be passed through this method. This allows subclasses to * update routing tables etc... based on what we overhear (even for messages not destined to our node) */ -void Router::sniffReceived(const MeshPacket *p) +void Router::sniffReceived(const MeshPacket *p, const Routing &c) { DEBUG_MSG("FIXME-update-db Sniffing packet\n"); // FIXME, update nodedb here for any packet that passes through us @@ -234,7 +216,7 @@ bool Router::perhapsDecode(MeshPacket *p) crypto->decrypt(p->from, p->id, p->encrypted.size, bytes); // Take those raw bytes and convert them back into a well structured protobuf we can understand - if (!pb_decode_from_bytes(bytes, p->encrypted.size, SubPacket_fields, &p->decoded)) { + if (!pb_decode_from_bytes(bytes, p->encrypted.size, Data_fields, &p->decoded)) { DEBUG_MSG("Invalid protobufs in received mesh packet!\n"); return false; } else { @@ -262,7 +244,8 @@ void Router::handleReceived(MeshPacket *p) if (perhapsDecode(p)) { // parsing was successful, queue for our recipient - sniffReceived(p); + assert(0); // FIXME, call any promiscious plugins here, make a (non promisiocous) plugin for forwarding messages to phone api + // sniffReceived(p); if (p->to == NODENUM_BROADCAST || p->to == getNodeNum()) { printPacket("Delivering rx packet", p); diff --git a/src/mesh/Router.h b/src/mesh/Router.h index 3951f3062..e9a10dae1 100644 --- a/src/mesh/Router.h +++ b/src/mesh/Router.h @@ -68,6 +68,8 @@ class Router : protected concurrency::OSThread NodeNum getNodeNum(); protected: + friend class RoutingPlugin; + /** * Send a packet on a suitable interface. This routine will * later free() the packet to pool. This routine is not allowed to stall. @@ -79,6 +81,8 @@ class Router : protected concurrency::OSThread /** * Should this incoming filter be dropped? + * + * FIXME, move this into the new RoutingPlugin and do the filtering there using the regular plugin logic * * Called immedately on receiption, before any further processing. * @return true to abandon the packet @@ -89,7 +93,7 @@ class Router : protected concurrency::OSThread * Every (non duplicate) packet this node receives will be passed through this method. This allows subclasses to * update routing tables etc... based on what we overhear (even for messages not destined to our node) */ - virtual void sniffReceived(const MeshPacket *p); + virtual void sniffReceived(const MeshPacket *p, const Routing &c); /** * Remove any encryption and decode the protobufs inside this packet (if necessary). @@ -101,7 +105,7 @@ class Router : protected concurrency::OSThread /** * Send an ack or a nak packet back towards whoever sent idFrom */ - void sendAckNak(ErrorReason err, NodeNum to, PacketId idFrom); + void sendAckNak(Routing_Error err, NodeNum to, PacketId idFrom); private: /** diff --git a/src/mesh/SinglePortPlugin.h b/src/mesh/SinglePortPlugin.h index d182579b7..5fa609dd4 100644 --- a/src/mesh/SinglePortPlugin.h +++ b/src/mesh/SinglePortPlugin.h @@ -32,8 +32,7 @@ class SinglePortPlugin : public MeshPlugin { // Update our local node info with our position (even if we don't decide to update anyone else) MeshPacket *p = router->allocForSending(); - p->decoded.which_payloadVariant = SubPacket_data_tag; - p->decoded.data.portnum = ourPortNum; + p->decoded.portnum = ourPortNum; return p; } diff --git a/src/mesh/generated/apponly.pb.c b/src/mesh/generated/apponly.pb.c index c93d63292..d6f17d7f7 100644 --- a/src/mesh/generated/apponly.pb.c +++ b/src/mesh/generated/apponly.pb.c @@ -9,4 +9,7 @@ PB_BIND(ServiceEnvelope, ServiceEnvelope, 2) +PB_BIND(ChannelSet, ChannelSet, AUTO) + + diff --git a/src/mesh/generated/apponly.pb.h b/src/mesh/generated/apponly.pb.h index fbf80324b..af527f0c8 100644 --- a/src/mesh/generated/apponly.pb.h +++ b/src/mesh/generated/apponly.pb.h @@ -11,6 +11,10 @@ #endif /* Struct definitions */ +typedef struct _ChannelSet { + pb_callback_t settings; +} ChannelSet; + typedef struct _ServiceEnvelope { bool has_packet; MeshPacket packet; @@ -25,9 +29,12 @@ extern "C" { /* Initializer values for message structs */ #define ServiceEnvelope_init_default {false, MeshPacket_init_default, {{NULL}, NULL}, {{NULL}, NULL}} +#define ChannelSet_init_default {{{NULL}, NULL}} #define ServiceEnvelope_init_zero {false, MeshPacket_init_zero, {{NULL}, NULL}, {{NULL}, NULL}} +#define ChannelSet_init_zero {{{NULL}, NULL}} /* Field tags (for use in manual encoding/decoding) */ +#define ChannelSet_settings_tag 1 #define ServiceEnvelope_packet_tag 1 #define ServiceEnvelope_channel_id_tag 2 #define ServiceEnvelope_gateway_id_tag 3 @@ -41,13 +48,22 @@ X(a, CALLBACK, SINGULAR, STRING, gateway_id, 3) #define ServiceEnvelope_DEFAULT NULL #define ServiceEnvelope_packet_MSGTYPE MeshPacket +#define ChannelSet_FIELDLIST(X, a) \ +X(a, CALLBACK, REPEATED, MESSAGE, settings, 1) +#define ChannelSet_CALLBACK pb_default_field_callback +#define ChannelSet_DEFAULT NULL +#define ChannelSet_settings_MSGTYPE ChannelSettings + extern const pb_msgdesc_t ServiceEnvelope_msg; +extern const pb_msgdesc_t ChannelSet_msg; /* Defines for backwards compatibility with code written before nanopb-0.4.0 */ #define ServiceEnvelope_fields &ServiceEnvelope_msg +#define ChannelSet_fields &ChannelSet_msg /* Maximum encoded size of messages (where known) */ /* ServiceEnvelope_size depends on runtime parameters */ +/* ChannelSet_size depends on runtime parameters */ #ifdef __cplusplus } /* extern "C" */ diff --git a/src/mesh/generated/deviceonly.pb.h b/src/mesh/generated/deviceonly.pb.h index e1f4c4010..47ffe2ae3 100644 --- a/src/mesh/generated/deviceonly.pb.h +++ b/src/mesh/generated/deviceonly.pb.h @@ -80,7 +80,7 @@ extern const pb_msgdesc_t DeviceState_msg; #define DeviceState_fields &DeviceState_msg /* Maximum encoded size of messages (where known) */ -#define DeviceState_size 6265 +#define DeviceState_size 6225 #ifdef __cplusplus } /* extern "C" */ diff --git a/src/mesh/generated/mesh.pb.c b/src/mesh/generated/mesh.pb.c index 872447623..c4fd0d8e5 100644 --- a/src/mesh/generated/mesh.pb.c +++ b/src/mesh/generated/mesh.pb.c @@ -9,16 +9,16 @@ PB_BIND(Position, Position, AUTO) -PB_BIND(Data, Data, AUTO) - - PB_BIND(User, User, AUTO) PB_BIND(RouteDiscovery, RouteDiscovery, AUTO) -PB_BIND(SubPacket, SubPacket, 2) +PB_BIND(Routing, Routing, AUTO) + + +PB_BIND(Data, Data, 2) PB_BIND(MeshPacket, MeshPacket, 2) diff --git a/src/mesh/generated/mesh.pb.h b/src/mesh/generated/mesh.pb.h index 691b4cd78..ca47ffa89 100644 --- a/src/mesh/generated/mesh.pb.h +++ b/src/mesh/generated/mesh.pb.h @@ -11,15 +11,6 @@ #endif /* Enum definitions */ -typedef enum _ErrorReason { - ErrorReason_NONE = 0, - ErrorReason_NO_ROUTE = 1, - ErrorReason_GOT_NAK = 2, - ErrorReason_TIMEOUT = 3, - ErrorReason_NO_INTERFACE = 4, - ErrorReason_MAX_RETRANSMIT = 5 -} ErrorReason; - typedef enum _Constants { Constants_Unused = 0, Constants_DATA_PAYLOAD_LEN = 240 @@ -83,6 +74,15 @@ typedef enum _CriticalErrorCode { CriticalErrorCode_TransmitFailed = 8 } CriticalErrorCode; +typedef enum _Routing_Error { + Routing_Error_NONE = 0, + Routing_Error_NO_ROUTE = 1, + Routing_Error_GOT_NAK = 2, + Routing_Error_TIMEOUT = 3, + Routing_Error_NO_INTERFACE = 4, + Routing_Error_MAX_RETRANSMIT = 5 +} Routing_Error; + typedef enum _MeshPacket_Priority { MeshPacket_Priority_UNSET = 0, MeshPacket_Priority_MIN = 1, @@ -136,6 +136,9 @@ typedef PB_BYTES_ARRAY_T(240) Data_payload_t; typedef struct _Data { PortNum portnum; Data_payload_t payload; + bool want_response; + uint32_t dest; + uint32_t source; } Data; typedef struct _LogRecord { @@ -216,7 +219,7 @@ typedef struct _RadioConfig_UserPreferences { typedef struct _RouteDiscovery { pb_size_t route_count; - int32_t route[8]; + uint32_t route[8]; } RouteDiscovery; typedef struct _User { @@ -233,6 +236,24 @@ typedef struct _Channel { Channel_Role role; } Channel; +typedef PB_BYTES_ARRAY_T(256) MeshPacket_encrypted_t; +typedef struct _MeshPacket { + uint32_t from; + uint32_t to; + pb_size_t which_payloadVariant; + union { + Data decoded; + MeshPacket_encrypted_t encrypted; + }; + uint32_t channel_index; + uint32_t id; + float rx_snr; + uint32_t rx_time; + uint32_t hop_limit; + bool want_ack; + MeshPacket_Priority priority; +} MeshPacket; + typedef struct _NodeInfo { uint32_t num; bool has_user; @@ -248,48 +269,22 @@ typedef struct _RadioConfig { RadioConfig_UserPreferences preferences; } RadioConfig; -typedef struct _SubPacket { - uint32_t original_id; - pb_size_t which_payloadVariant; +typedef struct _Routing { + pb_size_t which_variant; union { - Data data; RouteDiscovery route_request; RouteDiscovery route_reply; - ErrorReason error_reason; - }; - bool want_response; - uint32_t dest; - pb_size_t which_ackVariant; - union { + Routing_Error error_reason; uint32_t success_id; uint32_t fail_id; - } ackVariant; - uint32_t source; -} SubPacket; - -typedef PB_BYTES_ARRAY_T(256) MeshPacket_encrypted_t; -typedef struct _MeshPacket { - uint32_t from; - uint32_t to; - pb_size_t which_payloadVariant; - union { - SubPacket decoded; - MeshPacket_encrypted_t encrypted; }; - uint32_t channel_index; - uint32_t id; - float rx_snr; - uint32_t rx_time; - uint32_t hop_limit; - bool want_ack; - MeshPacket_Priority priority; -} MeshPacket; + uint32_t original_id; +} Routing; typedef struct _FromRadio { uint32_t num; pb_size_t which_payloadVariant; union { - MeshPacket packet; MyNodeInfo my_info; NodeInfo node_info; RadioConfig radio; @@ -297,6 +292,7 @@ typedef struct _FromRadio { uint32_t config_complete_id; bool rebooted; Channel channel; + MeshPacket packet; }; } FromRadio; @@ -313,10 +309,6 @@ typedef struct _ToRadio { /* Helper constants for enums */ -#define _ErrorReason_MIN ErrorReason_NONE -#define _ErrorReason_MAX ErrorReason_MAX_RETRANSMIT -#define _ErrorReason_ARRAYSIZE ((ErrorReason)(ErrorReason_MAX_RETRANSMIT+1)) - #define _Constants_MIN Constants_Unused #define _Constants_MAX Constants_DATA_PAYLOAD_LEN #define _Constants_ARRAYSIZE ((Constants)(Constants_DATA_PAYLOAD_LEN+1)) @@ -341,6 +333,10 @@ typedef struct _ToRadio { #define _CriticalErrorCode_MAX CriticalErrorCode_TransmitFailed #define _CriticalErrorCode_ARRAYSIZE ((CriticalErrorCode)(CriticalErrorCode_TransmitFailed+1)) +#define _Routing_Error_MIN Routing_Error_NONE +#define _Routing_Error_MAX Routing_Error_MAX_RETRANSMIT +#define _Routing_Error_ARRAYSIZE ((Routing_Error)(Routing_Error_MAX_RETRANSMIT+1)) + #define _MeshPacket_Priority_MIN MeshPacket_Priority_UNSET #define _MeshPacket_Priority_MAX MeshPacket_Priority_MAX #define _MeshPacket_Priority_ARRAYSIZE ((MeshPacket_Priority)(MeshPacket_Priority_MAX+1)) @@ -364,11 +360,11 @@ extern "C" { /* Initializer values for message structs */ #define Position_init_default {0, 0, 0, 0, 0} -#define Data_init_default {_PortNum_MIN, {0, {0}}} #define User_init_default {"", "", "", {0}} #define RouteDiscovery_init_default {0, {0, 0, 0, 0, 0, 0, 0, 0}} -#define SubPacket_init_default {0, 0, {Data_init_default}, 0, 0, 0, {0}, 0} -#define MeshPacket_init_default {0, 0, 0, {SubPacket_init_default}, 0, 0, 0, 0, 0, 0, _MeshPacket_Priority_MIN} +#define Routing_init_default {0, {RouteDiscovery_init_default}, 0} +#define Data_init_default {_PortNum_MIN, {0, {0}}, 0, 0, 0} +#define MeshPacket_init_default {0, 0, 0, {Data_init_default}, 0, 0, 0, 0, 0, 0, _MeshPacket_Priority_MIN} #define ChannelSettings_init_default {0, _ChannelSettings_ModemConfig_MIN, {0, {0}}, "", 0, 0, 0, 0, 0, 0, 0} #define Channel_init_default {0, false, ChannelSettings_init_default, _Channel_Role_MIN} #define RadioConfig_init_default {false, RadioConfig_UserPreferences_init_default} @@ -376,14 +372,14 @@ extern "C" { #define NodeInfo_init_default {0, false, User_init_default, false, Position_init_default, 0, 0} #define MyNodeInfo_init_default {0, 0, 0, "", "", "", _CriticalErrorCode_MIN, 0, 0, 0, 0, 0} #define LogRecord_init_default {"", 0, "", _LogRecord_Level_MIN} -#define FromRadio_init_default {0, 0, {MeshPacket_init_default}} +#define FromRadio_init_default {0, 0, {MyNodeInfo_init_default}} #define ToRadio_init_default {0, {MeshPacket_init_default}} #define Position_init_zero {0, 0, 0, 0, 0} -#define Data_init_zero {_PortNum_MIN, {0, {0}}} #define User_init_zero {"", "", "", {0}} #define RouteDiscovery_init_zero {0, {0, 0, 0, 0, 0, 0, 0, 0}} -#define SubPacket_init_zero {0, 0, {Data_init_zero}, 0, 0, 0, {0}, 0} -#define MeshPacket_init_zero {0, 0, 0, {SubPacket_init_zero}, 0, 0, 0, 0, 0, 0, _MeshPacket_Priority_MIN} +#define Routing_init_zero {0, {RouteDiscovery_init_zero}, 0} +#define Data_init_zero {_PortNum_MIN, {0, {0}}, 0, 0, 0} +#define MeshPacket_init_zero {0, 0, 0, {Data_init_zero}, 0, 0, 0, 0, 0, 0, _MeshPacket_Priority_MIN} #define ChannelSettings_init_zero {0, _ChannelSettings_ModemConfig_MIN, {0, {0}}, "", 0, 0, 0, 0, 0, 0, 0} #define Channel_init_zero {0, false, ChannelSettings_init_zero, _Channel_Role_MIN} #define RadioConfig_init_zero {false, RadioConfig_UserPreferences_init_zero} @@ -391,7 +387,7 @@ extern "C" { #define NodeInfo_init_zero {0, false, User_init_zero, false, Position_init_zero, 0, 0} #define MyNodeInfo_init_zero {0, 0, 0, "", "", "", _CriticalErrorCode_MIN, 0, 0, 0, 0, 0} #define LogRecord_init_zero {"", 0, "", _LogRecord_Level_MIN} -#define FromRadio_init_zero {0, 0, {MeshPacket_init_zero}} +#define FromRadio_init_zero {0, 0, {MyNodeInfo_init_zero}} #define ToRadio_init_zero {0, {MeshPacket_init_zero}} /* Field tags (for use in manual encoding/decoding) */ @@ -408,6 +404,9 @@ extern "C" { #define ChannelSettings_downlink_enabled_tag 17 #define Data_portnum_tag 1 #define Data_payload_tag 2 +#define Data_want_response_tag 5 +#define Data_dest_tag 9 +#define Data_source_tag 12 #define LogRecord_message_tag 1 #define LogRecord_time_tag 2 #define LogRecord_source_tag 3 @@ -479,22 +478,6 @@ extern "C" { #define Channel_index_tag 1 #define Channel_settings_tag 2 #define Channel_role_tag 3 -#define NodeInfo_num_tag 1 -#define NodeInfo_user_tag 2 -#define NodeInfo_position_tag 3 -#define NodeInfo_next_hop_tag 5 -#define NodeInfo_snr_tag 7 -#define RadioConfig_preferences_tag 1 -#define SubPacket_original_id_tag 2 -#define SubPacket_data_tag 3 -#define SubPacket_route_request_tag 6 -#define SubPacket_route_reply_tag 7 -#define SubPacket_error_reason_tag 13 -#define SubPacket_want_response_tag 5 -#define SubPacket_dest_tag 9 -#define SubPacket_success_id_tag 10 -#define SubPacket_fail_id_tag 11 -#define SubPacket_source_tag 12 #define MeshPacket_from_tag 1 #define MeshPacket_to_tag 2 #define MeshPacket_decoded_tag 3 @@ -506,8 +489,19 @@ extern "C" { #define MeshPacket_hop_limit_tag 10 #define MeshPacket_want_ack_tag 11 #define MeshPacket_priority_tag 12 +#define NodeInfo_num_tag 1 +#define NodeInfo_user_tag 2 +#define NodeInfo_position_tag 3 +#define NodeInfo_next_hop_tag 5 +#define NodeInfo_snr_tag 7 +#define RadioConfig_preferences_tag 1 +#define Routing_route_request_tag 1 +#define Routing_route_reply_tag 2 +#define Routing_error_reason_tag 3 +#define Routing_success_id_tag 4 +#define Routing_fail_id_tag 5 +#define Routing_original_id_tag 6 #define FromRadio_num_tag 1 -#define FromRadio_packet_tag 2 #define FromRadio_my_info_tag 3 #define FromRadio_node_info_tag 4 #define FromRadio_radio_tag 6 @@ -515,7 +509,8 @@ extern "C" { #define FromRadio_config_complete_id_tag 8 #define FromRadio_rebooted_tag 9 #define FromRadio_channel_tag 10 -#define ToRadio_packet_tag 1 +#define FromRadio_packet_tag 11 +#define ToRadio_packet_tag 2 #define ToRadio_want_config_id_tag 100 #define ToRadio_set_radio_tag 101 #define ToRadio_set_owner_tag 102 @@ -531,12 +526,6 @@ X(a, STATIC, SINGULAR, FIXED32, time, 9) #define Position_CALLBACK NULL #define Position_DEFAULT NULL -#define Data_FIELDLIST(X, a) \ -X(a, STATIC, SINGULAR, UENUM, portnum, 1) \ -X(a, STATIC, SINGULAR, BYTES, payload, 2) -#define Data_CALLBACK NULL -#define Data_DEFAULT NULL - #define User_FIELDLIST(X, a) \ X(a, STATIC, SINGULAR, STRING, id, 1) \ X(a, STATIC, SINGULAR, STRING, long_name, 2) \ @@ -546,34 +535,38 @@ X(a, STATIC, SINGULAR, FIXED_LENGTH_BYTES, macaddr, 4) #define User_DEFAULT NULL #define RouteDiscovery_FIELDLIST(X, a) \ -X(a, STATIC, REPEATED, INT32, route, 2) +X(a, STATIC, REPEATED, FIXED32, route, 2) #define RouteDiscovery_CALLBACK NULL #define RouteDiscovery_DEFAULT NULL -#define SubPacket_FIELDLIST(X, a) \ -X(a, STATIC, SINGULAR, UINT32, original_id, 2) \ -X(a, STATIC, ONEOF, MESSAGE, (payloadVariant,data,data), 3) \ -X(a, STATIC, ONEOF, MESSAGE, (payloadVariant,route_request,route_request), 6) \ -X(a, STATIC, ONEOF, MESSAGE, (payloadVariant,route_reply,route_reply), 7) \ -X(a, STATIC, ONEOF, UENUM, (payloadVariant,error_reason,error_reason), 13) \ +#define Routing_FIELDLIST(X, a) \ +X(a, STATIC, ONEOF, MESSAGE, (variant,route_request,route_request), 1) \ +X(a, STATIC, ONEOF, MESSAGE, (variant,route_reply,route_reply), 2) \ +X(a, STATIC, ONEOF, UENUM, (variant,error_reason,error_reason), 3) \ +X(a, STATIC, ONEOF, FIXED32, (variant,success_id,success_id), 4) \ +X(a, STATIC, ONEOF, FIXED32, (variant,fail_id,fail_id), 5) \ +X(a, STATIC, SINGULAR, FIXED32, original_id, 6) +#define Routing_CALLBACK NULL +#define Routing_DEFAULT NULL +#define Routing_variant_route_request_MSGTYPE RouteDiscovery +#define Routing_variant_route_reply_MSGTYPE RouteDiscovery + +#define Data_FIELDLIST(X, a) \ +X(a, STATIC, SINGULAR, UENUM, portnum, 1) \ +X(a, STATIC, SINGULAR, BYTES, payload, 2) \ X(a, STATIC, SINGULAR, BOOL, want_response, 5) \ -X(a, STATIC, SINGULAR, UINT32, dest, 9) \ -X(a, STATIC, ONEOF, UINT32, (ackVariant,success_id,ackVariant.success_id), 10) \ -X(a, STATIC, ONEOF, UINT32, (ackVariant,fail_id,ackVariant.fail_id), 11) \ -X(a, STATIC, SINGULAR, UINT32, source, 12) -#define SubPacket_CALLBACK NULL -#define SubPacket_DEFAULT NULL -#define SubPacket_payloadVariant_data_MSGTYPE Data -#define SubPacket_payloadVariant_route_request_MSGTYPE RouteDiscovery -#define SubPacket_payloadVariant_route_reply_MSGTYPE RouteDiscovery +X(a, STATIC, SINGULAR, FIXED32, dest, 9) \ +X(a, STATIC, SINGULAR, FIXED32, source, 12) +#define Data_CALLBACK NULL +#define Data_DEFAULT NULL #define MeshPacket_FIELDLIST(X, a) \ -X(a, STATIC, SINGULAR, UINT32, from, 1) \ -X(a, STATIC, SINGULAR, UINT32, to, 2) \ +X(a, STATIC, SINGULAR, FIXED32, from, 1) \ +X(a, STATIC, SINGULAR, FIXED32, to, 2) \ X(a, STATIC, ONEOF, MESSAGE, (payloadVariant,decoded,decoded), 3) \ X(a, STATIC, ONEOF, BYTES, (payloadVariant,encrypted,encrypted), 8) \ X(a, STATIC, SINGULAR, UINT32, channel_index, 4) \ -X(a, STATIC, SINGULAR, UINT32, id, 6) \ +X(a, STATIC, SINGULAR, FIXED32, id, 6) \ X(a, STATIC, SINGULAR, FLOAT, rx_snr, 7) \ X(a, STATIC, SINGULAR, FIXED32, rx_time, 9) \ X(a, STATIC, SINGULAR, UINT32, hop_limit, 10) \ @@ -581,7 +574,7 @@ X(a, STATIC, SINGULAR, BOOL, want_ack, 11) \ X(a, STATIC, SINGULAR, UENUM, priority, 12) #define MeshPacket_CALLBACK NULL #define MeshPacket_DEFAULT NULL -#define MeshPacket_payloadVariant_decoded_MSGTYPE SubPacket +#define MeshPacket_payloadVariant_decoded_MSGTYPE Data #define ChannelSettings_FIELDLIST(X, a) \ X(a, STATIC, SINGULAR, INT32, tx_power, 1) \ @@ -695,25 +688,25 @@ X(a, STATIC, SINGULAR, UENUM, level, 4) #define FromRadio_FIELDLIST(X, a) \ X(a, STATIC, SINGULAR, UINT32, num, 1) \ -X(a, STATIC, ONEOF, MESSAGE, (payloadVariant,packet,packet), 2) \ X(a, STATIC, ONEOF, MESSAGE, (payloadVariant,my_info,my_info), 3) \ X(a, STATIC, ONEOF, MESSAGE, (payloadVariant,node_info,node_info), 4) \ X(a, STATIC, ONEOF, MESSAGE, (payloadVariant,radio,radio), 6) \ X(a, STATIC, ONEOF, MESSAGE, (payloadVariant,log_record,log_record), 7) \ X(a, STATIC, ONEOF, UINT32, (payloadVariant,config_complete_id,config_complete_id), 8) \ X(a, STATIC, ONEOF, BOOL, (payloadVariant,rebooted,rebooted), 9) \ -X(a, STATIC, ONEOF, MESSAGE, (payloadVariant,channel,channel), 10) +X(a, STATIC, ONEOF, MESSAGE, (payloadVariant,channel,channel), 10) \ +X(a, STATIC, ONEOF, MESSAGE, (payloadVariant,packet,packet), 11) #define FromRadio_CALLBACK NULL #define FromRadio_DEFAULT NULL -#define FromRadio_payloadVariant_packet_MSGTYPE MeshPacket #define FromRadio_payloadVariant_my_info_MSGTYPE MyNodeInfo #define FromRadio_payloadVariant_node_info_MSGTYPE NodeInfo #define FromRadio_payloadVariant_radio_MSGTYPE RadioConfig #define FromRadio_payloadVariant_log_record_MSGTYPE LogRecord #define FromRadio_payloadVariant_channel_MSGTYPE Channel +#define FromRadio_payloadVariant_packet_MSGTYPE MeshPacket #define ToRadio_FIELDLIST(X, a) \ -X(a, STATIC, ONEOF, MESSAGE, (payloadVariant,packet,packet), 1) \ +X(a, STATIC, ONEOF, MESSAGE, (payloadVariant,packet,packet), 2) \ X(a, STATIC, ONEOF, UINT32, (payloadVariant,want_config_id,want_config_id), 100) \ X(a, STATIC, ONEOF, MESSAGE, (payloadVariant,set_radio,set_radio), 101) \ X(a, STATIC, ONEOF, MESSAGE, (payloadVariant,set_owner,set_owner), 102) \ @@ -726,10 +719,10 @@ X(a, STATIC, ONEOF, MESSAGE, (payloadVariant,set_channel,set_channel), 104 #define ToRadio_payloadVariant_set_channel_MSGTYPE Channel extern const pb_msgdesc_t Position_msg; -extern const pb_msgdesc_t Data_msg; extern const pb_msgdesc_t User_msg; extern const pb_msgdesc_t RouteDiscovery_msg; -extern const pb_msgdesc_t SubPacket_msg; +extern const pb_msgdesc_t Routing_msg; +extern const pb_msgdesc_t Data_msg; extern const pb_msgdesc_t MeshPacket_msg; extern const pb_msgdesc_t ChannelSettings_msg; extern const pb_msgdesc_t Channel_msg; @@ -743,10 +736,10 @@ extern const pb_msgdesc_t ToRadio_msg; /* Defines for backwards compatibility with code written before nanopb-0.4.0 */ #define Position_fields &Position_msg -#define Data_fields &Data_msg #define User_fields &User_msg #define RouteDiscovery_fields &RouteDiscovery_msg -#define SubPacket_fields &SubPacket_msg +#define Routing_fields &Routing_msg +#define Data_fields &Data_msg #define MeshPacket_fields &MeshPacket_msg #define ChannelSettings_fields &ChannelSettings_msg #define Channel_fields &Channel_msg @@ -760,11 +753,11 @@ extern const pb_msgdesc_t ToRadio_msg; /* Maximum encoded size of messages (where known) */ #define Position_size 37 -#define Data_size 246 #define User_size 72 -#define RouteDiscovery_size 88 -#define SubPacket_size 275 -#define MeshPacket_size 322 +#define RouteDiscovery_size 40 +#define Routing_size 47 +#define Data_size 258 +#define MeshPacket_size 302 #define ChannelSettings_size 95 #define Channel_size 105 #define RadioConfig_size 308 @@ -772,8 +765,8 @@ extern const pb_msgdesc_t ToRadio_msg; #define NodeInfo_size 130 #define MyNodeInfo_size 89 #define LogRecord_size 81 -#define FromRadio_size 331 -#define ToRadio_size 325 +#define FromRadio_size 317 +#define ToRadio_size 312 #ifdef __cplusplus } /* extern "C" */ diff --git a/src/mesh/generated/portnums.pb.h b/src/mesh/generated/portnums.pb.h index 2133ecaa7..72360f295 100644 --- a/src/mesh/generated/portnums.pb.h +++ b/src/mesh/generated/portnums.pb.h @@ -16,6 +16,7 @@ typedef enum _PortNum { PortNum_REMOTE_HARDWARE_APP = 2, PortNum_POSITION_APP = 3, PortNum_NODEINFO_APP = 4, + PortNum_ROUTING_APP = 5, PortNum_REPLY_APP = 32, PortNum_IP_TUNNEL_APP = 33, PortNum_SERIAL_APP = 64, diff --git a/src/mesh/mesh-pb-constants.h b/src/mesh/mesh-pb-constants.h index ed1c4f7e8..21163c496 100644 --- a/src/mesh/mesh-pb-constants.h +++ b/src/mesh/mesh-pb-constants.h @@ -17,7 +17,7 @@ #define MAX_NUM_NODES (member_size(DeviceState, node_db) / member_size(DeviceState, node_db[0])) /// Max number of channels allowed -#define MAX_CHANNELS (member_size(DeviceState, channels) / member_size(DeviceState, channels[0])) +#define MAX_NUM_CHANNELS (member_size(DeviceState, channels) / member_size(DeviceState, channels[0])) /// helper function for encoding a record as a protobuf, any failures to encode are fatal and we will panic /// returns the encoded packet size diff --git a/src/plugins/Plugins.cpp b/src/plugins/Plugins.cpp index ac8dd7336..65cfdcee4 100644 --- a/src/plugins/Plugins.cpp +++ b/src/plugins/Plugins.cpp @@ -7,12 +7,14 @@ #include "plugins/SerialPlugin.h" #include "plugins/StoreForwardPlugin.h" #include "plugins/TextMessagePlugin.h" +#include "plugins/RoutingPlugin.h" /** * Create plugin instances here. If you are adding a new plugin, you must 'new' it here (or somewhere else) */ void setupPlugins() { + routingPlugin = new RoutingPlugin(); nodeInfoPlugin = new NodeInfoPlugin(); positionPlugin = new PositionPlugin(); textMessagePlugin = new TextMessagePlugin(); diff --git a/src/plugins/RangeTestPlugin.cpp b/src/plugins/RangeTestPlugin.cpp index 58150f5bb..dc5f30048 100644 --- a/src/plugins/RangeTestPlugin.cpp +++ b/src/plugins/RangeTestPlugin.cpp @@ -108,8 +108,8 @@ void RangeTestPluginRadio::sendPayload(NodeNum dest, bool wantReplies) static char heartbeatString[20]; snprintf(heartbeatString, sizeof(heartbeatString), "seq %d", packetSequence); - p->decoded.data.payload.size = strlen(heartbeatString); // You must specify how many bytes are in the reply - memcpy(p->decoded.data.payload.bytes, heartbeatString, p->decoded.data.payload.size); + p->decoded.payload.size = strlen(heartbeatString); // You must specify how many bytes are in the reply + memcpy(p->decoded.payload.bytes, heartbeatString, p->decoded.payload.size); service.sendToMesh(p); } diff --git a/src/plugins/ReplyPlugin.cpp b/src/plugins/ReplyPlugin.cpp index a8c607436..69903aa36 100644 --- a/src/plugins/ReplyPlugin.cpp +++ b/src/plugins/ReplyPlugin.cpp @@ -9,7 +9,7 @@ MeshPacket *ReplyPlugin::allocReply() { assert(currentRequest); // should always be !NULL auto req = *currentRequest; - auto &p = req.decoded.data; + auto &p = req.decoded; // The incoming message is in p.payload DEBUG_MSG("Received message from=0x%0x, id=%d, msg=%.*s\n", req.from, req.id, p.payload.size, p.payload.bytes); @@ -17,8 +17,8 @@ MeshPacket *ReplyPlugin::allocReply() const char *replyStr = "Message Received"; auto reply = allocDataPacket(); // Allocate a packet for sending - reply->decoded.data.payload.size = strlen(replyStr); // You must specify how many bytes are in the reply - memcpy(reply->decoded.data.payload.bytes, replyStr, reply->decoded.data.payload.size); + reply->decoded.payload.size = strlen(replyStr); // You must specify how many bytes are in the reply + memcpy(reply->decoded.payload.bytes, replyStr, reply->decoded.payload.size); return reply; } diff --git a/src/plugins/RoutingPlugin.cpp b/src/plugins/RoutingPlugin.cpp new file mode 100644 index 000000000..6f4c2123b --- /dev/null +++ b/src/plugins/RoutingPlugin.cpp @@ -0,0 +1,54 @@ +#include "RoutingPlugin.h" +#include "MeshService.h" +#include "NodeDB.h" +#include "RTC.h" +#include "Router.h" +#include "configuration.h" +#include "main.h" + +RoutingPlugin *routingPlugin; + +bool RoutingPlugin::handleReceivedProtobuf(const MeshPacket &mp, const Routing &p) +{ + + return false; // Let others look at this message also if they want +} + + +MeshPacket *RoutingPlugin::allocReply() +{ + assert(0); // 1.2 refactoring fixme, Not sure if anything needs this yet? + // return allocDataProtobuf(u); + return NULL; +} + +void RoutingPlugin::sendAckNak(Routing_Error err, NodeNum to, PacketId idFrom) +{ + Routing c = Routing_init_default; + + if (!err) { + c.success_id = idFrom; + } else { + c.fail_id = idFrom; + + // Also send back the error reason + c.error_reason = err; + } + + auto p = allocDataProtobuf(c); + p->priority = MeshPacket_Priority_ACK; + + p->hop_limit = 0; // Assume just immediate neighbors for now + p->to = to; + DEBUG_MSG("Sending an err=%d,to=0x%x,idFrom=0x%x,id=0x%x\n", err, to, idFrom, p->id); + + router->sendLocal(p); // we sometimes send directly to the local node +} + +RoutingPlugin::RoutingPlugin() + : ProtobufPlugin("routing", PortNum_ROUTING_APP, User_fields) +{ + isPromiscuous = true; +} + + diff --git a/src/plugins/RoutingPlugin.h b/src/plugins/RoutingPlugin.h new file mode 100644 index 000000000..080b8fe12 --- /dev/null +++ b/src/plugins/RoutingPlugin.h @@ -0,0 +1,31 @@ +#pragma once +#include "ProtobufPlugin.h" + +/** + * Routing plugin for router control messages + */ +class RoutingPlugin : public ProtobufPlugin +{ + public: + /** Constructor + * name is for debugging output + */ + RoutingPlugin(); + + protected: + friend class Router; + + /** Called to handle a particular incoming message + + @return true if you've guaranteed you've handled this message and no other handlers should be considered for it + */ + virtual bool handleReceivedProtobuf(const MeshPacket &mp, const Routing &p); + + /** Messages can be received that have the want_response bit set. If set, this callback will be invoked + * so that subclasses can (optionally) send a response back to the original sender. */ + virtual MeshPacket *allocReply(); + + void sendAckNak(Routing_Error err, NodeNum to, PacketId idFrom); +}; + +extern RoutingPlugin *routingPlugin; \ No newline at end of file diff --git a/src/plugins/SerialPlugin.cpp b/src/plugins/SerialPlugin.cpp index 47f279089..a3493c880 100644 --- a/src/plugins/SerialPlugin.cpp +++ b/src/plugins/SerialPlugin.cpp @@ -144,8 +144,8 @@ void SerialPluginRadio::sendPayload(NodeNum dest, bool wantReplies) p->want_ack = SERIALPLUGIN_ACK; - p->decoded.data.payload.size = strlen(serialStringChar); // You must specify how many bytes are in the reply - memcpy(p->decoded.data.payload.bytes, serialStringChar, p->decoded.data.payload.size); + p->decoded.payload.size = strlen(serialStringChar); // You must specify how many bytes are in the reply + memcpy(p->decoded.payload.bytes, serialStringChar, p->decoded.payload.size); service.sendToMesh(p); } diff --git a/src/plugins/TextMessagePlugin.cpp b/src/plugins/TextMessagePlugin.cpp index 4ad080702..8da2a10f9 100644 --- a/src/plugins/TextMessagePlugin.cpp +++ b/src/plugins/TextMessagePlugin.cpp @@ -7,7 +7,7 @@ TextMessagePlugin *textMessagePlugin; bool TextMessagePlugin::handleReceived(const MeshPacket &mp) { - auto &p = mp.decoded.data; + auto &p = mp.decoded; DEBUG_MSG("Received text msg from=0x%0x, id=%d, msg=%.*s\n", mp.from, mp.id, p.payload.size, p.payload.bytes); // We only store/display messages destined for us. From f064e56dc944114ed1a489c6ca73409a1505338a Mon Sep 17 00:00:00 2001 From: Kevin Hester Date: Wed, 17 Feb 2021 16:17:46 +0800 Subject: [PATCH 121/258] fix esp32 build for dev1.2 --- docs/software/TODO.md | 9 +++++++-- platformio.ini | 1 + proto | 2 +- src/plugins/ExternalNotificationPlugin.cpp | 2 +- src/plugins/RangeTestPlugin.cpp | 2 +- src/plugins/SerialPlugin.cpp | 2 +- src/plugins/StoreForwardPlugin.cpp | 2 +- 7 files changed, 13 insertions(+), 7 deletions(-) diff --git a/docs/software/TODO.md b/docs/software/TODO.md index c4569cbda..c15c837f3 100644 --- a/docs/software/TODO.md +++ b/docs/software/TODO.md @@ -4,16 +4,21 @@ You probably don't care about this section - skip to the next one. 1.2 cleanup & multichannel: +* clear priority before sending (to keep wire size small) +* generate channel hash from the name of the channel+the psk (not just one or the other) * DONE remove deprecated -* allow chaning packets in single transmission * DONE fix setchannel in phoneapi.cpp * DONE set mynodeinfo.max_channels * DONE set mynodeinfo.num_bands (formerly num_channels) * fix sniffing of non Routing packets -* move portnum up? +* DONE move portnum up? * scrub protobufs to make sure they are absoloute minimum wiresize (in particular packets, ChannelSets and positions) * send a hint that can be used to select which channel to try and hash against with each message * change syncword +* allow chaning packets in single transmission - to increase airtime efficiency and amortize packet overhead +* move #define PACKET_FLAGS_HOP_MASK PACKET_FLAGS_WANT_ACK_MASK out of wire header, instead include keyHint. shrink header len to 14 bytes. +* move most parts of meshpacket into the Data packet, so that we can chain multiple Data for sending when they all have a common destination and key. +when selecting a MeshPacket for transmit, scan the TX queue for any Data packets we can merge together. * DONE move acks into routing * DONE make all subpackets different versions of data * DONE move routing control into a data packet diff --git a/platformio.ini b/platformio.ini index 4b91317d9..c29fe0e0f 100644 --- a/platformio.ini +++ b/platformio.ini @@ -15,6 +15,7 @@ default_envs = tbeam ;default_envs = tlora-v1 ;default_envs = tlora-v2 ;default_envs = lora-relay-v1 # nrf board +;default_envs = eink ;default_envs = linux # lora-relay-v1 # nrf52840dk-geeksville # linux # or if you'd like to change the default to something like lora-relay-v1 put that here [common] diff --git a/proto b/proto index 65914b84f..527b0fdc3 160000 --- a/proto +++ b/proto @@ -1 +1 @@ -Subproject commit 65914b84f1ee8f25807187d60b43ad29dfbaedc3 +Subproject commit 527b0fdc343f89843158977a1c1a7c14db854565 diff --git a/src/plugins/ExternalNotificationPlugin.cpp b/src/plugins/ExternalNotificationPlugin.cpp index 505eff7d1..84822f1d9 100644 --- a/src/plugins/ExternalNotificationPlugin.cpp +++ b/src/plugins/ExternalNotificationPlugin.cpp @@ -145,7 +145,7 @@ bool ExternalNotificationPluginRadio::handleReceived(const MeshPacket &mp) if (radioConfig.preferences.ext_notification_plugin_enabled) { - auto &p = mp.decoded.data; + auto &p = mp.decoded; if (mp.from != nodeDB.getNodeNum()) { diff --git a/src/plugins/RangeTestPlugin.cpp b/src/plugins/RangeTestPlugin.cpp index dc5f30048..e277f70e9 100644 --- a/src/plugins/RangeTestPlugin.cpp +++ b/src/plugins/RangeTestPlugin.cpp @@ -120,7 +120,7 @@ bool RangeTestPluginRadio::handleReceived(const MeshPacket &mp) if (radioConfig.preferences.range_test_plugin_enabled) { - auto &p = mp.decoded.data; + auto &p = mp.decoded; // DEBUG_MSG("Received text msg self=0x%0x, from=0x%0x, to=0x%0x, id=%d, msg=%.*s\n", // nodeDB.getNodeNum(), mp.from, mp.to, mp.id, p.payload.size, p.payload.bytes); diff --git a/src/plugins/SerialPlugin.cpp b/src/plugins/SerialPlugin.cpp index a3493c880..060f05ba1 100644 --- a/src/plugins/SerialPlugin.cpp +++ b/src/plugins/SerialPlugin.cpp @@ -156,7 +156,7 @@ bool SerialPluginRadio::handleReceived(const MeshPacket &mp) if (radioConfig.preferences.serialplugin_enabled) { - auto &p = mp.decoded.data; + auto &p = mp.decoded; // DEBUG_MSG("Received text msg self=0x%0x, from=0x%0x, to=0x%0x, id=%d, msg=%.*s\n", // nodeDB.getNodeNum(), mp.from, mp.to, mp.id, p.payload.size, p.payload.bytes); diff --git a/src/plugins/StoreForwardPlugin.cpp b/src/plugins/StoreForwardPlugin.cpp index f71fb965b..73df054e8 100644 --- a/src/plugins/StoreForwardPlugin.cpp +++ b/src/plugins/StoreForwardPlugin.cpp @@ -118,7 +118,7 @@ bool StoreForwardPluginRadio::handleReceived(const MeshPacket &mp) if (STOREFORWARDPLUGIN_ENABLED) { - auto &p = mp.decoded.data; + auto &p = mp.decoded; // DEBUG_MSG("Received text msg self=0x%0x, from=0x%0x, to=0x%0x, id=%d, msg=%.*s\n", // nodeDB.getNodeNum(), mp.from, mp.to, mp.id, p.payload.size, p.payload.bytes); From 60a01567d9e7d5275bdcce2c88694efa95060e34 Mon Sep 17 00:00:00 2001 From: Kevin Hester Date: Wed, 17 Feb 2021 19:01:20 +0800 Subject: [PATCH 122/258] remove region specific builds --- bin/build-all.sh | 4 +++- docs/software/TODO.md | 13 ++++++++----- 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/bin/build-all.sh b/bin/build-all.sh index c4d48b122..fb14156df 100755 --- a/bin/build-all.sh +++ b/bin/build-all.sh @@ -4,7 +4,9 @@ set -e VERSION=`bin/buildinfo.py` -COUNTRIES="US EU433 EU865 CN JP ANZ KR" +# We now only do regionless builds +COUNTRIES="" +#COUNTRIES="US EU433 EU865 CN JP ANZ KR" #COUNTRIES=US #COUNTRIES=CN diff --git a/docs/software/TODO.md b/docs/software/TODO.md index c15c837f3..8f1b07625 100644 --- a/docs/software/TODO.md +++ b/docs/software/TODO.md @@ -2,8 +2,9 @@ You probably don't care about this section - skip to the next one. -1.2 cleanup & multichannel: +1.2 cleanup & multichannel support: +* call RouterPlugin for *all* packets - not just Router packets * clear priority before sending (to keep wire size small) * generate channel hash from the name of the channel+the psk (not just one or the other) * DONE remove deprecated @@ -12,13 +13,15 @@ You probably don't care about this section - skip to the next one. * DONE set mynodeinfo.num_bands (formerly num_channels) * fix sniffing of non Routing packets * DONE move portnum up? +* DONE remove region specific builds from the firmware +* add gui in android app for setting region * scrub protobufs to make sure they are absoloute minimum wiresize (in particular packets, ChannelSets and positions) * send a hint that can be used to select which channel to try and hash against with each message * change syncword * allow chaning packets in single transmission - to increase airtime efficiency and amortize packet overhead -* move #define PACKET_FLAGS_HOP_MASK PACKET_FLAGS_WANT_ACK_MASK out of wire header, instead include keyHint. shrink header len to 14 bytes. -* move most parts of meshpacket into the Data packet, so that we can chain multiple Data for sending when they all have a common destination and key. -when selecting a MeshPacket for transmit, scan the TX queue for any Data packets we can merge together. +* DONE move most parts of meshpacket into the Data packet, so that we can chain multiple Data for sending when they all have a common destination and key. +* when selecting a MeshPacket for transmit, scan the TX queue for any Data packets we can merge together as a WirePayload. In the low level send/rx code expand that into multiple MeshPackets as needed (thus 'hiding' from MeshPacket that over the wire we send multiple datapackets +* confirm we are still calling the plugins for messages inbound from the phone (or generated locally) * DONE move acks into routing * DONE make all subpackets different versions of data * DONE move routing control into a data packet @@ -31,7 +34,7 @@ when selecting a MeshPacket for transmit, scan the TX queue for any Data packets * add channel restrictions for plugins (and restrict routing plugin to the "control" channel) * make a primaryChannel global and properly maintain it when the phone sends setChannel * move setCrypto call into packet send and packet decode code -* implement'small locations' change? +* implement 'small location diffs' change * move battery level out of position? * DOUBLE CHECK android app can still upgrade 1.1 and 1.0 loads From 69a11e7375efa1624f1a884b0a35ca80e47b9fdf Mon Sep 17 00:00:00 2001 From: Kevin Hester Date: Wed, 17 Feb 2021 19:04:41 +0800 Subject: [PATCH 123/258] WIP phone api changes for dev1.2 --- src/mesh/MeshPlugin.cpp | 25 +++++++++---- src/mesh/MeshPlugin.h | 2 +- src/mesh/MeshService.cpp | 1 - src/mesh/MeshService.h | 2 -- src/mesh/NodeDB.cpp | 9 +++-- src/mesh/ProtobufPlugin.h | 16 ++++++--- src/mesh/Router.cpp | 5 +-- src/mesh/Router.h | 4 --- src/mesh/SinglePortPlugin.h | 2 +- src/mesh/generated/mesh.pb.h | 52 ++++++++++++++-------------- src/plugins/NodeInfoPlugin.cpp | 6 ++-- src/plugins/NodeInfoPlugin.h | 2 +- src/plugins/PositionPlugin.cpp | 6 ++-- src/plugins/PositionPlugin.h | 2 +- src/plugins/RemoteHardwarePlugin.cpp | 3 +- src/plugins/RemoteHardwarePlugin.h | 2 +- src/plugins/RoutingPlugin.cpp | 4 +-- src/plugins/RoutingPlugin.h | 2 +- 18 files changed, 82 insertions(+), 63 deletions(-) diff --git a/src/mesh/MeshPlugin.cpp b/src/mesh/MeshPlugin.cpp index 7befb6623..763d4d46e 100644 --- a/src/mesh/MeshPlugin.cpp +++ b/src/mesh/MeshPlugin.cpp @@ -28,22 +28,35 @@ void MeshPlugin::callPlugins(const MeshPacket &mp) { // DEBUG_MSG("In call plugins\n"); bool pluginFound = false; + + assert(mp.which_payloadVariant == MeshPacket_decoded_tag); // I think we are guarnteed the packet is decoded by this point? + + // Was this message directed to us specifically? Will be false if we are sniffing someone elses packets + bool toUs = mp.to == NODENUM_BROADCAST || mp.to == nodeDB.getNodeNum(); for (auto i = plugins->begin(); i != plugins->end(); ++i) { auto &pi = **i; pi.currentRequest = ∓ - if (pi.wantPortnum(mp.decoded.portnum)) { + + // We only call plugins that are interested in the packet (and the message is destined to us or we are promiscious) + bool wantsPacket = (pi.isPromiscuous || toUs) && pi.wantPacket(&mp); + if (wantsPacket) { pluginFound = true; bool handled = pi.handleReceived(mp); - // Possibly send replies - if (mp.decoded.want_response) + // Possibly send replies (but only if the message was directed to us specifically, i.e. not for promiscious sniffing) + if (mp.decoded.want_response && toUs) { pi.sendResponse(mp); - - DEBUG_MSG("Plugin %s handled=%d\n", pi.name, handled); - if (handled) + DEBUG_MSG("Plugin %s sent a response\n", pi.name); + } + else { + DEBUG_MSG("Plugin %s considered\n", pi.name); + } + if (handled) { + DEBUG_MSG("Plugin %s handled and skipped other processing\n", pi.name); break; + } } pi.currentRequest = NULL; diff --git a/src/mesh/MeshPlugin.h b/src/mesh/MeshPlugin.h index 1c90f8829..11f579fa9 100644 --- a/src/mesh/MeshPlugin.h +++ b/src/mesh/MeshPlugin.h @@ -55,7 +55,7 @@ class MeshPlugin /** * @return true if you want to receive the specified portnum */ - virtual bool wantPortnum(PortNum p) = 0; + virtual bool wantPacket(const MeshPacket *p) = 0; /** Called to handle a particular incoming message diff --git a/src/mesh/MeshService.cpp b/src/mesh/MeshService.cpp index ae53e802f..753d942df 100644 --- a/src/mesh/MeshService.cpp +++ b/src/mesh/MeshService.cpp @@ -65,7 +65,6 @@ void MeshService::init() if (gps) gpsObserver.observe(&gps->newStatus); - packetReceivedObserver.observe(&router->notifyPacketReceived); } diff --git a/src/mesh/MeshService.h b/src/mesh/MeshService.h index 8cba07710..6cf52a00e 100644 --- a/src/mesh/MeshService.h +++ b/src/mesh/MeshService.h @@ -19,8 +19,6 @@ class MeshService { CallbackObserver gpsObserver = CallbackObserver(this, &MeshService::onGPSChanged); - CallbackObserver packetReceivedObserver = - CallbackObserver(this, &MeshService::handleFromRadio); /// received packets waiting for the phone to process them /// FIXME, change to a DropOldestQueue and keep a count of the number of dropped packets to ensure diff --git a/src/mesh/NodeDB.cpp b/src/mesh/NodeDB.cpp index 3cc6b000b..6e81acd76 100644 --- a/src/mesh/NodeDB.cpp +++ b/src/mesh/NodeDB.cpp @@ -357,7 +357,13 @@ void NodeDB::updatePosition(uint32_t nodeId, const Position &p) DEBUG_MSG("DB update position node=0x%x time=%u, latI=%d, lonI=%d\n", nodeId, p.time, p.latitude_i, p.longitude_i); + auto oldtime = info->position.time; info->position = p; + if(p.time == 0 && oldtime != 0) { + // A lot of position reports don't have time populated. In that case, be careful to not blow away the time we + // recorded based on the packet rxTime + info->position.time = oldtime; + } info->has_position = true; updateGUIforNode = info; notifyObservers(true); // Force an update whether or not our node counts have changed @@ -405,9 +411,6 @@ void NodeDB::updateFrom(const MeshPacket &mp) } info->snr = mp.rx_snr; // keep the most recent SNR we received for this node. - - if (mp.to == NODENUM_BROADCAST || mp.to == nodeDB.getNodeNum()) - MeshPlugin::callPlugins(mp); } } diff --git a/src/mesh/ProtobufPlugin.h b/src/mesh/ProtobufPlugin.h index d931185e0..c68885df2 100644 --- a/src/mesh/ProtobufPlugin.h +++ b/src/mesh/ProtobufPlugin.h @@ -25,8 +25,11 @@ template class ProtobufPlugin : protected SinglePortPlugin /** * Handle a received message, the data field in the message is already decoded and is provided + * + * In general decoded will always be !NULL. But in some special applications (where you have handling packets + * for multiple port numbers, decoding will ONLY be attempted for packets where the portnum matches our expected ourPortNum. */ - virtual bool handleReceivedProtobuf(const MeshPacket &mp, const T &decoded) = 0; + virtual bool handleReceivedProtobuf(const MeshPacket &mp, const T *decoded) = 0; /** * Return a mesh packet which has been preinited with a particular protobuf data payload and port number. @@ -58,9 +61,14 @@ template class ProtobufPlugin : protected SinglePortPlugin DEBUG_MSG("Received %s from=0x%0x, id=0x%x, payloadlen=%d\n", name, mp.from, mp.id, p.payload.size); T scratch; - if (pb_decode_from_bytes(p.payload.bytes, p.payload.size, fields, &scratch)) - return handleReceivedProtobuf(mp, scratch); + T *decoded = NULL; + if(mp.decoded.portnum == ourPortNum) { + if (pb_decode_from_bytes(p.payload.bytes, p.payload.size, fields, &scratch)) + decoded = &scratch; + else + DEBUG_MSG("Error decoding protobuf plugin!\n"); + } - return false; // Let others look at this message also if they want + return handleReceivedProtobuf(mp, decoded); } }; diff --git a/src/mesh/Router.cpp b/src/mesh/Router.cpp index f20cf02bf..7876ddde4 100644 --- a/src/mesh/Router.cpp +++ b/src/mesh/Router.cpp @@ -244,12 +244,13 @@ void Router::handleReceived(MeshPacket *p) if (perhapsDecode(p)) { // parsing was successful, queue for our recipient - assert(0); // FIXME, call any promiscious plugins here, make a (non promisiocous) plugin for forwarding messages to phone api + // call any promiscious plugins here, make a (non promisiocous) plugin for forwarding messages to phone api // sniffReceived(p); + MeshPlugin::callPlugins(*p); if (p->to == NODENUM_BROADCAST || p->to == getNodeNum()) { printPacket("Delivering rx packet", p); - notifyPacketReceived.notifyObservers(p); + meshservice.handleFromRadio(p); } } } diff --git a/src/mesh/Router.h b/src/mesh/Router.h index e9a10dae1..17297ba14 100644 --- a/src/mesh/Router.h +++ b/src/mesh/Router.h @@ -21,10 +21,6 @@ class Router : protected concurrency::OSThread RadioInterface *iface = NULL; public: - /// Local services that want to see _every_ packet this node receives can observe this. - /// Observers should always return 0 and _copy_ any packets they want to keep for use later (this packet will be getting - /// freed) - Observable notifyPacketReceived; /** * Constructor diff --git a/src/mesh/SinglePortPlugin.h b/src/mesh/SinglePortPlugin.h index 5fa609dd4..305532dc5 100644 --- a/src/mesh/SinglePortPlugin.h +++ b/src/mesh/SinglePortPlugin.h @@ -21,7 +21,7 @@ class SinglePortPlugin : public MeshPlugin /** * @return true if you want to receive the specified portnum */ - virtual bool wantPortnum(PortNum p) { return p == ourPortNum; } + virtual bool wantPacket(const MeshPacket *p) { return p->decoded.portnum == ourPortNum; } /** * Return a mesh packet which has been preinited as a data packet with a particular port number. diff --git a/src/mesh/generated/mesh.pb.h b/src/mesh/generated/mesh.pb.h index ca47ffa89..106444eb3 100644 --- a/src/mesh/generated/mesh.pb.h +++ b/src/mesh/generated/mesh.pb.h @@ -240,15 +240,15 @@ typedef PB_BYTES_ARRAY_T(256) MeshPacket_encrypted_t; typedef struct _MeshPacket { uint32_t from; uint32_t to; + uint32_t channel_index; pb_size_t which_payloadVariant; union { Data decoded; MeshPacket_encrypted_t encrypted; }; - uint32_t channel_index; uint32_t id; - float rx_snr; uint32_t rx_time; + float rx_snr; uint32_t hop_limit; bool want_ack; MeshPacket_Priority priority; @@ -364,7 +364,7 @@ extern "C" { #define RouteDiscovery_init_default {0, {0, 0, 0, 0, 0, 0, 0, 0}} #define Routing_init_default {0, {RouteDiscovery_init_default}, 0} #define Data_init_default {_PortNum_MIN, {0, {0}}, 0, 0, 0} -#define MeshPacket_init_default {0, 0, 0, {Data_init_default}, 0, 0, 0, 0, 0, 0, _MeshPacket_Priority_MIN} +#define MeshPacket_init_default {0, 0, 0, 0, {Data_init_default}, 0, 0, 0, 0, 0, _MeshPacket_Priority_MIN} #define ChannelSettings_init_default {0, _ChannelSettings_ModemConfig_MIN, {0, {0}}, "", 0, 0, 0, 0, 0, 0, 0} #define Channel_init_default {0, false, ChannelSettings_init_default, _Channel_Role_MIN} #define RadioConfig_init_default {false, RadioConfig_UserPreferences_init_default} @@ -379,7 +379,7 @@ extern "C" { #define RouteDiscovery_init_zero {0, {0, 0, 0, 0, 0, 0, 0, 0}} #define Routing_init_zero {0, {RouteDiscovery_init_zero}, 0} #define Data_init_zero {_PortNum_MIN, {0, {0}}, 0, 0, 0} -#define MeshPacket_init_zero {0, 0, 0, {Data_init_zero}, 0, 0, 0, 0, 0, 0, _MeshPacket_Priority_MIN} +#define MeshPacket_init_zero {0, 0, 0, 0, {Data_init_zero}, 0, 0, 0, 0, 0, _MeshPacket_Priority_MIN} #define ChannelSettings_init_zero {0, _ChannelSettings_ModemConfig_MIN, {0, {0}}, "", 0, 0, 0, 0, 0, 0, 0} #define Channel_init_zero {0, false, ChannelSettings_init_zero, _Channel_Role_MIN} #define RadioConfig_init_zero {false, RadioConfig_UserPreferences_init_zero} @@ -404,9 +404,9 @@ extern "C" { #define ChannelSettings_downlink_enabled_tag 17 #define Data_portnum_tag 1 #define Data_payload_tag 2 -#define Data_want_response_tag 5 -#define Data_dest_tag 9 -#define Data_source_tag 12 +#define Data_want_response_tag 3 +#define Data_dest_tag 4 +#define Data_source_tag 5 #define LogRecord_message_tag 1 #define LogRecord_time_tag 2 #define LogRecord_source_tag 3 @@ -480,15 +480,15 @@ extern "C" { #define Channel_role_tag 3 #define MeshPacket_from_tag 1 #define MeshPacket_to_tag 2 -#define MeshPacket_decoded_tag 3 -#define MeshPacket_encrypted_tag 8 -#define MeshPacket_channel_index_tag 4 +#define MeshPacket_channel_index_tag 3 +#define MeshPacket_decoded_tag 4 +#define MeshPacket_encrypted_tag 5 #define MeshPacket_id_tag 6 -#define MeshPacket_rx_snr_tag 7 -#define MeshPacket_rx_time_tag 9 -#define MeshPacket_hop_limit_tag 10 -#define MeshPacket_want_ack_tag 11 -#define MeshPacket_priority_tag 12 +#define MeshPacket_rx_time_tag 7 +#define MeshPacket_rx_snr_tag 8 +#define MeshPacket_hop_limit_tag 9 +#define MeshPacket_want_ack_tag 10 +#define MeshPacket_priority_tag 11 #define NodeInfo_num_tag 1 #define NodeInfo_user_tag 2 #define NodeInfo_position_tag 3 @@ -554,24 +554,24 @@ X(a, STATIC, SINGULAR, FIXED32, original_id, 6) #define Data_FIELDLIST(X, a) \ X(a, STATIC, SINGULAR, UENUM, portnum, 1) \ X(a, STATIC, SINGULAR, BYTES, payload, 2) \ -X(a, STATIC, SINGULAR, BOOL, want_response, 5) \ -X(a, STATIC, SINGULAR, FIXED32, dest, 9) \ -X(a, STATIC, SINGULAR, FIXED32, source, 12) +X(a, STATIC, SINGULAR, BOOL, want_response, 3) \ +X(a, STATIC, SINGULAR, FIXED32, dest, 4) \ +X(a, STATIC, SINGULAR, FIXED32, source, 5) #define Data_CALLBACK NULL #define Data_DEFAULT NULL #define MeshPacket_FIELDLIST(X, a) \ X(a, STATIC, SINGULAR, FIXED32, from, 1) \ X(a, STATIC, SINGULAR, FIXED32, to, 2) \ -X(a, STATIC, ONEOF, MESSAGE, (payloadVariant,decoded,decoded), 3) \ -X(a, STATIC, ONEOF, BYTES, (payloadVariant,encrypted,encrypted), 8) \ -X(a, STATIC, SINGULAR, UINT32, channel_index, 4) \ +X(a, STATIC, SINGULAR, UINT32, channel_index, 3) \ +X(a, STATIC, ONEOF, MESSAGE, (payloadVariant,decoded,decoded), 4) \ +X(a, STATIC, ONEOF, BYTES, (payloadVariant,encrypted,encrypted), 5) \ X(a, STATIC, SINGULAR, FIXED32, id, 6) \ -X(a, STATIC, SINGULAR, FLOAT, rx_snr, 7) \ -X(a, STATIC, SINGULAR, FIXED32, rx_time, 9) \ -X(a, STATIC, SINGULAR, UINT32, hop_limit, 10) \ -X(a, STATIC, SINGULAR, BOOL, want_ack, 11) \ -X(a, STATIC, SINGULAR, UENUM, priority, 12) +X(a, STATIC, SINGULAR, FIXED32, rx_time, 7) \ +X(a, STATIC, SINGULAR, FLOAT, rx_snr, 8) \ +X(a, STATIC, SINGULAR, UINT32, hop_limit, 9) \ +X(a, STATIC, SINGULAR, BOOL, want_ack, 10) \ +X(a, STATIC, SINGULAR, UENUM, priority, 11) #define MeshPacket_CALLBACK NULL #define MeshPacket_DEFAULT NULL #define MeshPacket_payloadVariant_decoded_MSGTYPE Data diff --git a/src/plugins/NodeInfoPlugin.cpp b/src/plugins/NodeInfoPlugin.cpp index a04ec4159..2524ffa58 100644 --- a/src/plugins/NodeInfoPlugin.cpp +++ b/src/plugins/NodeInfoPlugin.cpp @@ -8,10 +8,9 @@ NodeInfoPlugin *nodeInfoPlugin; -bool NodeInfoPlugin::handleReceivedProtobuf(const MeshPacket &mp, const User &p) +bool NodeInfoPlugin::handleReceivedProtobuf(const MeshPacket &mp, const User *pptr) { - // FIXME - we currently update NodeInfo data in the DB only if the message was a broadcast or destined to us - // it would be better to update even if the message was destined to others. + auto p = *pptr; nodeDB.updateUser(mp.from, p); @@ -52,6 +51,7 @@ MeshPacket *NodeInfoPlugin::allocReply() NodeInfoPlugin::NodeInfoPlugin() : ProtobufPlugin("nodeinfo", PortNum_NODEINFO_APP, User_fields), concurrency::OSThread("NodeInfoPlugin") { + 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) } diff --git a/src/plugins/NodeInfoPlugin.h b/src/plugins/NodeInfoPlugin.h index f0a7efebd..eb2a16da1 100644 --- a/src/plugins/NodeInfoPlugin.h +++ b/src/plugins/NodeInfoPlugin.h @@ -26,7 +26,7 @@ class NodeInfoPlugin : public ProtobufPlugin, private concurrency::OSThrea @return true if you've guaranteed you've handled this message and no other handlers should be considered for it */ - virtual bool handleReceivedProtobuf(const MeshPacket &mp, const User &p); + virtual bool handleReceivedProtobuf(const MeshPacket &mp, const User *p); /** Messages can be received that have the want_response bit set. If set, this callback will be invoked * so that subclasses can (optionally) send a response back to the original sender. */ diff --git a/src/plugins/PositionPlugin.cpp b/src/plugins/PositionPlugin.cpp index 153d20cfc..251605865 100644 --- a/src/plugins/PositionPlugin.cpp +++ b/src/plugins/PositionPlugin.cpp @@ -10,15 +10,15 @@ PositionPlugin *positionPlugin; PositionPlugin::PositionPlugin() : ProtobufPlugin("position", PortNum_POSITION_APP, Position_fields), concurrency::OSThread("PositionPlugin") { + isPromiscuous = true; // We always want to update our nodedb, even if we are sniffing on others setIntervalFromNow(60 * 1000); // Send our initial position 60 seconds after we start (to give GPS time to setup) } -bool PositionPlugin::handleReceivedProtobuf(const MeshPacket &mp, const Position &p) +bool PositionPlugin::handleReceivedProtobuf(const MeshPacket &mp, const Position *pptr) { - // FIXME - we currently update position data in the DB only if the message was a broadcast or destined to us - // it would be better to update even if the message was destined to others. + auto p = *pptr; if (p.time) { struct timeval tv; diff --git a/src/plugins/PositionPlugin.h b/src/plugins/PositionPlugin.h index 7a45c23a0..45c4884a5 100644 --- a/src/plugins/PositionPlugin.h +++ b/src/plugins/PositionPlugin.h @@ -33,7 +33,7 @@ class PositionPlugin : public ProtobufPlugin, private concurrency::OST @return true if you've guaranteed you've handled this message and no other handlers should be considered for it */ - virtual bool handleReceivedProtobuf(const MeshPacket &mp, const Position &p); + virtual bool handleReceivedProtobuf(const MeshPacket &mp, const Position *p); /** Messages can be received that have the want_response bit set. If set, this callback will be invoked * so that subclasses can (optionally) send a response back to the original sender. */ diff --git a/src/plugins/RemoteHardwarePlugin.cpp b/src/plugins/RemoteHardwarePlugin.cpp index 26b78c800..33130663f 100644 --- a/src/plugins/RemoteHardwarePlugin.cpp +++ b/src/plugins/RemoteHardwarePlugin.cpp @@ -47,8 +47,9 @@ RemoteHardwarePlugin::RemoteHardwarePlugin() { } -bool RemoteHardwarePlugin::handleReceivedProtobuf(const MeshPacket &req, const HardwareMessage &p) +bool RemoteHardwarePlugin::handleReceivedProtobuf(const MeshPacket &req, const HardwareMessage *pptr) { + auto p = *pptr; DEBUG_MSG("Received RemoteHardware typ=%d\n", p.typ); switch (p.typ) { diff --git a/src/plugins/RemoteHardwarePlugin.h b/src/plugins/RemoteHardwarePlugin.h index 5147a18e8..fad6e8386 100644 --- a/src/plugins/RemoteHardwarePlugin.h +++ b/src/plugins/RemoteHardwarePlugin.h @@ -27,7 +27,7 @@ class RemoteHardwarePlugin : public ProtobufPlugin, private con @return true if you've guaranteed you've handled this message and no other handlers should be considered for it */ - virtual bool handleReceivedProtobuf(const MeshPacket &mp, const HardwareMessage &p); + virtual bool handleReceivedProtobuf(const MeshPacket &mp, const HardwareMessage *p); /** * Periodically read the gpios we have been asked to WATCH, if they have changed, diff --git a/src/plugins/RoutingPlugin.cpp b/src/plugins/RoutingPlugin.cpp index 6f4c2123b..d0bcaf6a9 100644 --- a/src/plugins/RoutingPlugin.cpp +++ b/src/plugins/RoutingPlugin.cpp @@ -8,9 +8,9 @@ RoutingPlugin *routingPlugin; -bool RoutingPlugin::handleReceivedProtobuf(const MeshPacket &mp, const Routing &p) +bool RoutingPlugin::handleReceivedProtobuf(const MeshPacket &mp, const Routing *p) { - + assert(0); return false; // Let others look at this message also if they want } diff --git a/src/plugins/RoutingPlugin.h b/src/plugins/RoutingPlugin.h index 080b8fe12..0d987f39e 100644 --- a/src/plugins/RoutingPlugin.h +++ b/src/plugins/RoutingPlugin.h @@ -19,7 +19,7 @@ class RoutingPlugin : public ProtobufPlugin @return true if you've guaranteed you've handled this message and no other handlers should be considered for it */ - virtual bool handleReceivedProtobuf(const MeshPacket &mp, const Routing &p); + virtual bool handleReceivedProtobuf(const MeshPacket &mp, const Routing *p); /** Messages can be received that have the want_response bit set. If set, this callback will be invoked * so that subclasses can (optionally) send a response back to the original sender. */ From 13b8c140b46f70b0c784819e4e893b38896832bd Mon Sep 17 00:00:00 2001 From: Jm Date: Thu, 18 Feb 2021 21:47:16 -0800 Subject: [PATCH 124/258] Update StoreForwardPlugin.md --- docs/software/plugins/StoreForwardPlugin.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/docs/software/plugins/StoreForwardPlugin.md b/docs/software/plugins/StoreForwardPlugin.md index 129005baf..02389e426 100644 --- a/docs/software/plugins/StoreForwardPlugin.md +++ b/docs/software/plugins/StoreForwardPlugin.md @@ -29,6 +29,12 @@ UC 4) support for a mesh to have multiple routers that have the store & forward UC 5) Support for "long term" delayed messages and "short term" delayed messages. Handle the cases slightly different to improve user expierence. A short term delayed message would be a message that was resent becaue a node was not heard from for <5 minutes. A long term delayed message is a message that has not been delivered in >5 minutes. +UC 6) Eventually we could add a "want_store_and_forward" bit to MeshPacket and that could be nicer than whitelists in this plugin. Initially we'd only set that bit in text messages (and any other plugin messages that can cope with this). This change would be backward wire compatible so can add easily later. + +UC 7) Currently the way we allocate messages in the device code is super inefficient. It always allocates the worst case message size. Really we should dynamically allocate just the # of bytes we need. This would allow many more MeshPackets to be kept in RAM. + +UC 8) We'll want a "delayed" bit in MeshPacket. This will indicate that the message was not received in real time. + # Things to consider Not all these cases will be initially implemented. It's just a running stream of thoughts to be considered. From a2bea87332be9b9a37f1983d2f3486c3cc719bdc Mon Sep 17 00:00:00 2001 From: Charles Crossan Date: Fri, 19 Feb 2021 19:24:18 -0500 Subject: [PATCH 125/258] Fix exception decoder output --- bin/exception_decoder.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/exception_decoder.py b/bin/exception_decoder.py index 0286e1c16..8ef66b9bb 100755 --- a/bin/exception_decoder.py +++ b/bin/exception_decoder.py @@ -241,7 +241,7 @@ def print_addr(name, value, resolver): def print_stack_full(lines, resolver): print("stack:") for line in lines: - print(line.offset + ":") + print(str(line.offset) + ":") for content in line.content: print(" " + resolver.resolve_stack_addr(content)) From 621313d63cd5630827e906247c595ed4e487e9e4 Mon Sep 17 00:00:00 2001 From: Jm Date: Fri, 19 Feb 2021 16:58:52 -0800 Subject: [PATCH 126/258] #701 - Add system up time to debug output --- src/RedirectablePrint.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/RedirectablePrint.cpp b/src/RedirectablePrint.cpp index 541b55c78..c60b8a502 100644 --- a/src/RedirectablePrint.cpp +++ b/src/RedirectablePrint.cpp @@ -78,9 +78,9 @@ size_t RedirectablePrint::logDebug(const char *format, ...) int min = (hms % SEC_PER_HOUR) / SEC_PER_MIN; int sec = (hms % SEC_PER_HOUR) % SEC_PER_MIN; // or hms % SEC_PER_MIN - r += printf("%02d:%02d:%02d ", hour, min, sec); + r += printf("%02d:%02d:%02d %u ", hour, min, sec, millis() / 1000); } else - r += printf("??:??:?? "); + r += printf("??:??:?? %u ", millis() / 1000); auto thread = concurrency::OSThread::currentThread; if(thread) { From 47b942ca00ac3786d38ab018b5c4e6ba224653fa Mon Sep 17 00:00:00 2001 From: Jm Date: Fri, 19 Feb 2021 17:46:15 -0800 Subject: [PATCH 127/258] #697 - Fixed button selection for tlora v2 1.6 --- src/configuration.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/configuration.h b/src/configuration.h index 4fd395fd7..e5b80efe6 100644 --- a/src/configuration.h +++ b/src/configuration.h @@ -355,7 +355,7 @@ along with this program. If not, see . #define VEXT_ENABLE 21 // active low, powers the oled display and the lora antenna boost #define LED_PIN 25 // If defined we will blink this LED #define BUTTON_PIN \ - 12 // If defined, this will be used for user button presses, if your board doesn't have a physical switch, you can wire one + 34 // If defined, this will be used for user button presses, if your board doesn't have a physical switch, you can wire one // between this pin and ground #define BUTTON_NEED_PULLUP From c690f8157437865a8293a891db6384511b97e5ca Mon Sep 17 00:00:00 2001 From: Jm Date: Fri, 19 Feb 2021 18:19:14 -0800 Subject: [PATCH 128/258] #697 Disable internal pullup on this board. --- src/configuration.h | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/configuration.h b/src/configuration.h index e5b80efe6..55612a121 100644 --- a/src/configuration.h +++ b/src/configuration.h @@ -355,9 +355,14 @@ along with this program. If not, see . #define VEXT_ENABLE 21 // active low, powers the oled display and the lora antenna boost #define LED_PIN 25 // If defined we will blink this LED #define BUTTON_PIN \ - 34 // If defined, this will be used for user button presses, if your board doesn't have a physical switch, you can wire one + 12 // If defined, this will be used for user button presses, if your board doesn't have a physical switch, you can wire one // between this pin and ground -#define BUTTON_NEED_PULLUP + +/* Don't enable the internal pull up on the TLORA_V2_1_16. GPIO 12 is connected to a bidirectional + diode. If someone needs to use a button, they should connect an external pull up that's stronger + than what's built into the esp32 +*/ +// #define BUTTON_NEED_PULLUP #define USE_RF95 #define LORA_DIO0 26 // a No connect on the SX1262 module From e4141df0e9ddb2f95dd01daa548b6c3453a82533 Mon Sep 17 00:00:00 2001 From: Jm Date: Sat, 20 Feb 2021 00:34:25 -0800 Subject: [PATCH 129/258] #697 GPIO 12 is an odd pin. --- src/configuration.h | 19 +++++++------------ src/main.cpp | 7 +++++-- 2 files changed, 12 insertions(+), 14 deletions(-) diff --git a/src/configuration.h b/src/configuration.h index 55612a121..cb68a2e39 100644 --- a/src/configuration.h +++ b/src/configuration.h @@ -354,15 +354,9 @@ along with this program. If not, see . #define VEXT_ENABLE 21 // active low, powers the oled display and the lora antenna boost #define LED_PIN 25 // If defined we will blink this LED -#define BUTTON_PIN \ - 12 // If defined, this will be used for user button presses, if your board doesn't have a physical switch, you can wire one - // between this pin and ground +#define BUTTON_PIN 12 // If defined, this will be used for user button presses, -/* Don't enable the internal pull up on the TLORA_V2_1_16. GPIO 12 is connected to a bidirectional - diode. If someone needs to use a button, they should connect an external pull up that's stronger - than what's built into the esp32 -*/ -// #define BUTTON_NEED_PULLUP +#define BUTTON_NEED_PULLUP #define USE_RF95 #define LORA_DIO0 26 // a No connect on the SX1262 module @@ -380,15 +374,16 @@ along with this program. If not, see . #define GPS_RESET_N 10 #define GPS_EXTINT 23 // On MAX-M8 module pin name is EXTINT. On L70 module pin name is STANDBY. -#define BATTERY_PIN 39 // A battery voltage measurement pin, voltage divider connected here to measure battery voltage +#define BATTERY_PIN 39 // A battery voltage measurement pin, voltage divider connected here to measure battery voltage #define BATTERY_EN_PIN 14 // Voltage voltage divider enable pin connected to mosfet #define I2C_SDA 4 // I2C pins for this board #define I2C_SCL 2 -#define LED_PIN 12 // If defined we will blink this LED -//#define BUTTON_PIN 36 // If defined, this will be used for user button presses (ToDo problem on that line on debug screen --> Long press start!) -//#define BUTTON_NEED_PULLUP //GPIOs 34 to 39 are GPIs – input only pins. These pins don’t have internal pull-ups or pull-down resistors. +#define LED_PIN 12 // If defined we will blink this LED +//#define BUTTON_PIN 36 // If defined, this will be used for user button presses (ToDo problem on that line on debug screen --> +//Long press start!) #define BUTTON_NEED_PULLUP //GPIOs 34 to 39 are GPIs – input only pins. These pins don’t have internal +//pull-ups or pull-down resistors. #define USE_RF95 #define LORA_DIO0 38 // a No connect on the SX1262 module diff --git a/src/main.cpp b/src/main.cpp index bb3ec4820..9bd34c23e 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -305,12 +305,15 @@ void setup() #ifdef BUTTON_PIN #ifndef NO_ESP32 - // If BUTTON_PIN is held down during the startup process, - // force the device to go into a SoftAP mode. bool forceSoftAP = 0; + + // If the button is connected to GPIO 12, don't enable the ability to use + // meshtasticAdmin on the device. pinMode(BUTTON_PIN, INPUT); + #ifdef BUTTON_NEED_PULLUP gpio_pullup_en((gpio_num_t)BUTTON_PIN); + delay(10); #endif // BUTTON_PIN is pulled high by a 12k resistor. From ca40cb4be33ef05f4c29b9bb147ddfc8c1b4c634 Mon Sep 17 00:00:00 2001 From: Jm Date: Sat, 20 Feb 2021 00:43:56 -0800 Subject: [PATCH 130/258] Update RangeTestPlugin.cpp --- src/plugins/esp32/RangeTestPlugin.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/esp32/RangeTestPlugin.cpp b/src/plugins/esp32/RangeTestPlugin.cpp index fad1991df..d453574f3 100644 --- a/src/plugins/esp32/RangeTestPlugin.cpp +++ b/src/plugins/esp32/RangeTestPlugin.cpp @@ -37,7 +37,7 @@ int32_t RangeTestPlugin::runOnce() //radioConfig.preferences.range_test_plugin_enabled = 1; //radioConfig.preferences.range_test_plugin_sender = 45; - // radioConfig.preferences.range_test_plugin_save = 1; + //radioConfig.preferences.range_test_plugin_save = 1; // Fixed position is useful when testing indoors. // radioConfig.preferences.fixed_position = 1; From 587102f6bc06796892599f75f779c30b074a70c8 Mon Sep 17 00:00:00 2001 From: Kevin Hester Date: Sun, 21 Feb 2021 11:36:34 +0800 Subject: [PATCH 131/258] fix android lint warning --- bin/build-all.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/build-all.sh b/bin/build-all.sh index fb14156df..d9a6393e4 100755 --- a/bin/build-all.sh +++ b/bin/build-all.sh @@ -109,7 +109,7 @@ release. It is used by the android app for forcing software updates. Do not ed Generated by bin/buildall.sh --> - $VERSION + $VERSION XML From 99467cd874253166048e95bac65ff4c80ca10ed5 Mon Sep 17 00:00:00 2001 From: Kevin Hester Date: Sun, 21 Feb 2021 12:59:47 +0800 Subject: [PATCH 132/258] 1.2 WIP at least doesn't crash --- docs/software/TODO.md | 10 ++-- proto | 2 +- src/mesh/DSRRouter.cpp | 95 ++++++++++++++++++----------------- src/mesh/DSRRouter.h | 2 +- src/mesh/FloodingRouter.cpp | 4 +- src/mesh/FloodingRouter.h | 2 +- src/mesh/MeshService.h | 3 +- src/mesh/ReliableRouter.cpp | 25 ++++----- src/mesh/ReliableRouter.h | 2 +- src/mesh/Router.cpp | 7 +-- src/mesh/Router.h | 2 +- src/plugins/RoutingPlugin.cpp | 11 +++- 12 files changed, 89 insertions(+), 76 deletions(-) diff --git a/docs/software/TODO.md b/docs/software/TODO.md index 8f1b07625..d2c4a7c97 100644 --- a/docs/software/TODO.md +++ b/docs/software/TODO.md @@ -4,14 +4,14 @@ You probably don't care about this section - skip to the next one. 1.2 cleanup & multichannel support: -* call RouterPlugin for *all* packets - not just Router packets -* clear priority before sending (to keep wire size small) +* DONE call RouterPlugin for *all* packets - not just Router packets * generate channel hash from the name of the channel+the psk (not just one or the other) * DONE remove deprecated * DONE fix setchannel in phoneapi.cpp * DONE set mynodeinfo.max_channels * DONE set mynodeinfo.num_bands (formerly num_channels) -* fix sniffing of non Routing packets +* DONE fix sniffing of non Routing packets +* enable remote setttings access by moving settings operations into a regular plugin (move settings ops out of PhoneAPI) * DONE move portnum up? * DONE remove region specific builds from the firmware * add gui in android app for setting region @@ -22,6 +22,9 @@ You probably don't care about this section - skip to the next one. * DONE move most parts of meshpacket into the Data packet, so that we can chain multiple Data for sending when they all have a common destination and key. * when selecting a MeshPacket for transmit, scan the TX queue for any Data packets we can merge together as a WirePayload. In the low level send/rx code expand that into multiple MeshPackets as needed (thus 'hiding' from MeshPacket that over the wire we send multiple datapackets * confirm we are still calling the plugins for messages inbound from the phone (or generated locally) +* confirm we are still multi hop routing flood broadcasts +* confirm we are still doing resends on unicast reliable packets +* add support for full DSR unicast delivery * DONE move acks into routing * DONE make all subpackets different versions of data * DONE move routing control into a data packet @@ -31,6 +34,7 @@ You probably don't care about this section - skip to the next one. * add multichannel support in python * add channel selection for sending * record recevied channel in meshpacket +* test remote settings operations (confirm it works 3 hops away) * add channel restrictions for plugins (and restrict routing plugin to the "control" channel) * make a primaryChannel global and properly maintain it when the phone sends setChannel * move setCrypto call into packet send and packet decode code diff --git a/proto b/proto index 527b0fdc3..f23417aa7 160000 --- a/proto +++ b/proto @@ -1 +1 @@ -Subproject commit 527b0fdc343f89843158977a1c1a7c14db854565 +Subproject commit f23417aa7dcb8f61bbb2c1ea07c7b988ae66ec38 diff --git a/src/mesh/DSRRouter.cpp b/src/mesh/DSRRouter.cpp index 04d4a2bef..0b28257f6 100644 --- a/src/mesh/DSRRouter.cpp +++ b/src/mesh/DSRRouter.cpp @@ -62,7 +62,7 @@ ErrorCode DSRRouter::send(MeshPacket *p) return ReliableRouter::send(p); } -void DSRRouter::sniffReceived(const MeshPacket *p, const Routing &c) +void DSRRouter::sniffReceived(const MeshPacket *p, const Routing *c) { // Learn 0 hop routes by just hearing any adjacent nodes // But treat broadcasts carefully, because when flood broadcasts go out they keep the same original "from". So we want to @@ -72,47 +72,49 @@ void DSRRouter::sniffReceived(const MeshPacket *p, const Routing &c) addRoute(p->from, p->from, 0); // We are adjacent with zero hops } - switch (c.which_variant) { - case Routing_route_request_tag: - // Handle route discovery packets (will be a broadcast message) - // FIXME - always start request with the senders nodenum - if (weAreInRoute(c.route_request)) { - DEBUG_MSG("Ignoring a route request that contains us\n"); - } else { - updateRoutes(c.route_request, - true); // Update our routing tables based on the route that came in so far on this request - - if (p->decoded.dest == getNodeNum()) { - // They were looking for us, send back a route reply (the sender address will be first in the list) - sendRouteReply(c.route_request); + if (c) + switch (c->which_variant) { + case Routing_route_request_tag: + // Handle route discovery packets (will be a broadcast message) + // FIXME - always start request with the senders nodenum + if (weAreInRoute(c->route_request)) { + DEBUG_MSG("Ignoring a route request that contains us\n"); } else { - // They were looking for someone else, forward it along (as a zero hop broadcast) - NodeNum nextHop = getNextHop(p->decoded.dest); - if (nextHop) { - // in our route cache, reply to the requester (the sender address will be first in the list) - sendRouteReply(c.route_request, nextHop); + updateRoutes(c->route_request, + true); // Update our routing tables based on the route that came in so far on this request + + if (p->decoded.dest == getNodeNum()) { + // They were looking for us, send back a route reply (the sender address will be first in the list) + sendRouteReply(c->route_request); } else { - // Not in our route cache, rebroadcast on their behalf (after adding ourselves to the request route) - resendRouteRequest(p); + // They were looking for someone else, forward it along (as a zero hop broadcast) + NodeNum nextHop = getNextHop(p->decoded.dest); + if (nextHop) { + // in our route cache, reply to the requester (the sender address will be first in the list) + sendRouteReply(c->route_request, nextHop); + } else { + // Not in our route cache, rebroadcast on their behalf (after adding ourselves to the request route) + resendRouteRequest(p); + } } } + break; + case Routing_route_reply_tag: + updateRoutes(c->route_reply, false); + + // FIXME, if any of our current pending packets were waiting for this route, send them (and leave them as regular + // pending packets until ack arrives) + // FIXME, if we don't get a route reply at all (or a route error), timeout and generate a routeerror TIMEOUT on our + // own... + break; + case Routing_error_reason_tag: + removeRoute(p->decoded.dest); + + // FIXME: if any pending packets were waiting on this route, delete them + break; + default: + break; } - break; - case Routing_route_reply_tag: - updateRoutes(c.route_reply, false); - - // FIXME, if any of our current pending packets were waiting for this route, send them (and leave them as regular pending - // packets until ack arrives) - // FIXME, if we don't get a route reply at all (or a route error), timeout and generate a routeerror TIMEOUT on our own... - break; - case Routing_error_reason_tag: - removeRoute(p->decoded.dest); - - // FIXME: if any pending packets were waiting on this route, delete them - break; - default: - break; - } // We simply ignore ACKs - because ReliableRouter will delete the pending packet for us @@ -137,15 +139,18 @@ void DSRRouter::sniffReceived(const MeshPacket *p, const Routing &c) // FIXME, stop local processing of this packet } - // handle naks - convert them to route error packets - // All naks are generated locally, because we failed resending the packet too many times - PacketId nakId = c.fail_id; - if (nakId) { - auto pending = findPendingPacket(p->to, nakId); - if (pending && pending->packet->decoded.source) { // if source not set, this was not a multihop packet, just ignore - removeRoute(pending->packet->decoded.dest); // We no longer have a route to the specified node + if (c) { + // handle naks - convert them to route error packets + // All naks are generated locally, because we failed resending the packet too many times + PacketId nakId = c->fail_id; + if (nakId) { + auto pending = findPendingPacket(p->to, nakId); + if (pending && + pending->packet->decoded.source) { // if source not set, this was not a multihop packet, just ignore + removeRoute(pending->packet->decoded.dest); // We no longer have a route to the specified node - sendRouteError(p, Routing_Error_GOT_NAK); + sendRouteError(p, Routing_Error_GOT_NAK); + } } } } diff --git a/src/mesh/DSRRouter.h b/src/mesh/DSRRouter.h index eef1a991c..796dc236c 100644 --- a/src/mesh/DSRRouter.h +++ b/src/mesh/DSRRouter.h @@ -8,7 +8,7 @@ class DSRRouter : public ReliableRouter * Every (non duplicate) packet this node receives will be passed through this method. This allows subclasses to * update routing tables etc... based on what we overhear (even for messages not destined to our node) */ - virtual void sniffReceived(const MeshPacket *p, const Routing &c); + virtual void sniffReceived(const MeshPacket *p, const Routing *c); /** * Send a packet on a suitable interface. This routine will diff --git a/src/mesh/FloodingRouter.cpp b/src/mesh/FloodingRouter.cpp index 777178c41..049d038c7 100644 --- a/src/mesh/FloodingRouter.cpp +++ b/src/mesh/FloodingRouter.cpp @@ -27,11 +27,11 @@ bool FloodingRouter::shouldFilterReceived(const MeshPacket *p) return Router::shouldFilterReceived(p); } -void FloodingRouter::sniffReceived(const MeshPacket *p, const Routing &c) +void FloodingRouter::sniffReceived(const MeshPacket *p, const Routing *c) { // If a broadcast, possibly _also_ send copies out into the mesh. // (FIXME, do something smarter than naive flooding here) - if (p->to == NODENUM_BROADCAST && p->hop_limit > 0) { + if (p->to == NODENUM_BROADCAST && p->hop_limit > 0 && p->from != getNodeNum()) { if (p->id != 0) { MeshPacket *tosend = packetPool.allocCopy(*p); // keep a copy because we will be sending it diff --git a/src/mesh/FloodingRouter.h b/src/mesh/FloodingRouter.h index 3e4f5de6e..41bc898df 100644 --- a/src/mesh/FloodingRouter.h +++ b/src/mesh/FloodingRouter.h @@ -55,5 +55,5 @@ class FloodingRouter : public Router, protected PacketHistory /** * Look for broadcasts we need to rebroadcast */ - virtual void sniffReceived(const MeshPacket *p, const Routing &c); + virtual void sniffReceived(const MeshPacket *p, const Routing *c); }; diff --git a/src/mesh/MeshService.h b/src/mesh/MeshService.h index 6cf52a00e..0f2e772b3 100644 --- a/src/mesh/MeshService.h +++ b/src/mesh/MeshService.h @@ -89,9 +89,10 @@ class MeshService /// returns 0 to allow futher processing int onGPSChanged(const meshtastic::GPSStatus *arg); - /// Handle a packet that just arrived from the radio. This method does _not_ free the provided packet. If it needs + /// Handle a packet that just arrived from the radio. This method does _ReliableRouternot_ free the provided packet. If it needs /// to keep the packet around it makes a copy int handleFromRadio(const MeshPacket *p); + friend class RoutingPlugin; }; extern MeshService service; diff --git a/src/mesh/ReliableRouter.cpp b/src/mesh/ReliableRouter.cpp index 3dc07c9c9..65e1ff9f8 100644 --- a/src/mesh/ReliableRouter.cpp +++ b/src/mesh/ReliableRouter.cpp @@ -53,7 +53,7 @@ bool ReliableRouter::shouldFilterReceived(const MeshPacket *p) * * Otherwise, let superclass handle it. */ -void ReliableRouter::sniffReceived(const MeshPacket *p, const Routing &c) +void ReliableRouter::sniffReceived(const MeshPacket *p, const Routing *c) { NodeNum ourNode = getNodeNum(); @@ -64,18 +64,19 @@ void ReliableRouter::sniffReceived(const MeshPacket *p, const Routing &c) } // If the payload is valid, look for ack/nak + if (c) { + PacketId ackId = c->success_id; + PacketId nakId = c->fail_id; - PacketId ackId = c.success_id; - PacketId nakId = c.fail_id; - - // 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=%d, stopping retransmissions\n", ackId); - stopRetransmission(p->to, ackId); - } else { - DEBUG_MSG("Received a nak=%d, stopping retransmissions\n", nakId); - stopRetransmission(p->to, nakId); + // 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=%d, stopping retransmissions\n", ackId); + stopRetransmission(p->to, ackId); + } else { + DEBUG_MSG("Received a nak=%d, stopping retransmissions\n", nakId); + stopRetransmission(p->to, nakId); + } } } } diff --git a/src/mesh/ReliableRouter.h b/src/mesh/ReliableRouter.h index bf0338f9b..e6a71f423 100644 --- a/src/mesh/ReliableRouter.h +++ b/src/mesh/ReliableRouter.h @@ -90,7 +90,7 @@ class ReliableRouter : public FloodingRouter /** * Look for acks/naks or someone retransmitting us */ - virtual void sniffReceived(const MeshPacket *p, const Routing &c); + virtual void sniffReceived(const MeshPacket *p, const Routing *c); /** * Try to find the pending packet record for this ID (or NULL if not found) diff --git a/src/mesh/Router.cpp b/src/mesh/Router.cpp index 7876ddde4..673fafefd 100644 --- a/src/mesh/Router.cpp +++ b/src/mesh/Router.cpp @@ -194,7 +194,7 @@ bool Router::cancelSending(NodeNum from, PacketId id) { * Every (non duplicate) packet this node receives will be passed through this method. This allows subclasses to * update routing tables etc... based on what we overhear (even for messages not destined to our node) */ -void Router::sniffReceived(const MeshPacket *p, const Routing &c) +void Router::sniffReceived(const MeshPacket *p, const Routing *c) { DEBUG_MSG("FIXME-update-db Sniffing packet\n"); // FIXME, update nodedb here for any packet that passes through us @@ -247,11 +247,6 @@ void Router::handleReceived(MeshPacket *p) // call any promiscious plugins here, make a (non promisiocous) plugin for forwarding messages to phone api // sniffReceived(p); MeshPlugin::callPlugins(*p); - - if (p->to == NODENUM_BROADCAST || p->to == getNodeNum()) { - printPacket("Delivering rx packet", p); - meshservice.handleFromRadio(p); - } } } diff --git a/src/mesh/Router.h b/src/mesh/Router.h index 17297ba14..4b1656936 100644 --- a/src/mesh/Router.h +++ b/src/mesh/Router.h @@ -89,7 +89,7 @@ class Router : protected concurrency::OSThread * Every (non duplicate) packet this node receives will be passed through this method. This allows subclasses to * update routing tables etc... based on what we overhear (even for messages not destined to our node) */ - virtual void sniffReceived(const MeshPacket *p, const Routing &c); + virtual void sniffReceived(const MeshPacket *p, const Routing *c); /** * Remove any encryption and decode the protobufs inside this packet (if necessary). diff --git a/src/plugins/RoutingPlugin.cpp b/src/plugins/RoutingPlugin.cpp index d0bcaf6a9..c3709ea5a 100644 --- a/src/plugins/RoutingPlugin.cpp +++ b/src/plugins/RoutingPlugin.cpp @@ -8,9 +8,16 @@ RoutingPlugin *routingPlugin; -bool RoutingPlugin::handleReceivedProtobuf(const MeshPacket &mp, const Routing *p) +bool RoutingPlugin::handleReceivedProtobuf(const MeshPacket &mp, const Routing *r) { - assert(0); + router->sniffReceived(&mp, r); + + // FIXME - move this to a non promsicious PhoneAPI plugin? + if (mp.to == NODENUM_BROADCAST || mp.to == nodeDB.getNodeNum()) { + printPacket("Delivering rx packet", &mp); + service.handleFromRadio(&mp); + } + return false; // Let others look at this message also if they want } From c6091338ab5433befbbae4a0a817c96cf2906f99 Mon Sep 17 00:00:00 2001 From: Kevin Hester Date: Sun, 21 Feb 2021 14:03:44 +0800 Subject: [PATCH 133/258] admin ops --- docs/software/TODO.md | 2 + proto | 2 +- src/mesh/PhoneAPI.cpp | 60 --------------------- src/mesh/generated/mesh.pb.c | 3 ++ src/mesh/generated/mesh.pb.h | 43 ++++++++++----- src/mesh/generated/portnums.pb.h | 1 + src/plugins/AdminPlugin.cpp | 93 ++++++++++++++++++++++++++++++++ src/plugins/AdminPlugin.h | 32 +++++++++++ src/plugins/Plugins.cpp | 2 + src/plugins/RoutingPlugin.cpp | 3 +- 10 files changed, 164 insertions(+), 77 deletions(-) create mode 100644 src/plugins/AdminPlugin.cpp create mode 100644 src/plugins/AdminPlugin.h diff --git a/docs/software/TODO.md b/docs/software/TODO.md index d2c4a7c97..1c6714e84 100644 --- a/docs/software/TODO.md +++ b/docs/software/TODO.md @@ -14,7 +14,9 @@ You probably don't care about this section - skip to the next one. * enable remote setttings access by moving settings operations into a regular plugin (move settings ops out of PhoneAPI) * DONE move portnum up? * DONE remove region specific builds from the firmware +* restrict settings operations to the admin channel * add gui in android app for setting region +* "FIXME - move the radioconfig/user/channel READ operations into SettingsMessage as well" * scrub protobufs to make sure they are absoloute minimum wiresize (in particular packets, ChannelSets and positions) * send a hint that can be used to select which channel to try and hash against with each message * change syncword diff --git a/proto b/proto index f23417aa7..649c3deb7 160000 --- a/proto +++ b/proto @@ -1 +1 @@ -Subproject commit f23417aa7dcb8f61bbb2c1ea07c7b988ae66ec38 +Subproject commit 649c3deb71d1780416fac5db33ad3c957c0278b6 diff --git a/src/mesh/PhoneAPI.cpp b/src/mesh/PhoneAPI.cpp index 6ec09b2ca..7f63fc18e 100644 --- a/src/mesh/PhoneAPI.cpp +++ b/src/mesh/PhoneAPI.cpp @@ -78,20 +78,6 @@ void PhoneAPI::handleToRadio(const uint8_t *buf, size_t bufLength) // this will break once we have multiple instances of PhoneAPI running independently break; - case ToRadio_set_owner_tag: - DEBUG_MSG("Client is setting owner\n"); - handleSetOwner(toRadioScratch.set_owner); - break; - - case ToRadio_set_radio_tag: - DEBUG_MSG("Client is setting radio\n"); - handleSetRadio(toRadioScratch.set_radio); - break; - - case ToRadio_set_channel_tag: - DEBUG_MSG("Client is setting channel\n"); - handleSetChannel(toRadioScratch.set_channel); - break; default: DEBUG_MSG("Error: unexpected ToRadio variant\n"); break; @@ -255,52 +241,6 @@ bool PhoneAPI::available() return false; } -// -// The following routines are only public for now - until the rev1 bluetooth API is removed -// - -void PhoneAPI::handleSetOwner(const User &o) -{ - int changed = 0; - - if (*o.long_name) { - changed |= strcmp(owner.long_name, o.long_name); - strcpy(owner.long_name, o.long_name); - } - if (*o.short_name) { - changed |= strcmp(owner.short_name, o.short_name); - strcpy(owner.short_name, o.short_name); - } - if (*o.id) { - changed |= strcmp(owner.id, o.id); - strcpy(owner.id, o.id); - } - - if (changed) // If nothing really changed, don't broadcast on the network or write to flash - service.reloadOwner(); -} - -void PhoneAPI::handleSetChannel(const Channel &cc) -{ - channels.setChannel(cc); - - bool didReset = service.reloadConfig(); - if (didReset) { - state = STATE_SEND_MY_INFO; // Squirt a completely new set of configs to the client - } - -} - -void PhoneAPI::handleSetRadio(const RadioConfig &r) -{ - radioConfig = r; - - bool didReset = service.reloadConfig(); - if (didReset) { - state = STATE_SEND_MY_INFO; // Squirt a completely new set of configs to the client - } -} - /** * Handle a packet that the phone wants us to send. It is our responsibility to free the packet to the pool */ diff --git a/src/mesh/generated/mesh.pb.c b/src/mesh/generated/mesh.pb.c index c4fd0d8e5..f0b3f8c66 100644 --- a/src/mesh/generated/mesh.pb.c +++ b/src/mesh/generated/mesh.pb.c @@ -51,6 +51,9 @@ PB_BIND(FromRadio, FromRadio, 2) PB_BIND(ToRadio, ToRadio, 2) +PB_BIND(AdminMessage, AdminMessage, 2) + + diff --git a/src/mesh/generated/mesh.pb.h b/src/mesh/generated/mesh.pb.h index 106444eb3..d29f6c86b 100644 --- a/src/mesh/generated/mesh.pb.h +++ b/src/mesh/generated/mesh.pb.h @@ -281,6 +281,15 @@ typedef struct _Routing { uint32_t original_id; } Routing; +typedef struct _AdminMessage { + pb_size_t which_variant; + union { + RadioConfig set_radio; + User set_owner; + Channel set_channel; + }; +} AdminMessage; + typedef struct _FromRadio { uint32_t num; pb_size_t which_payloadVariant; @@ -301,9 +310,6 @@ typedef struct _ToRadio { union { MeshPacket packet; uint32_t want_config_id; - RadioConfig set_radio; - User set_owner; - Channel set_channel; }; } ToRadio; @@ -374,6 +380,7 @@ extern "C" { #define LogRecord_init_default {"", 0, "", _LogRecord_Level_MIN} #define FromRadio_init_default {0, 0, {MyNodeInfo_init_default}} #define ToRadio_init_default {0, {MeshPacket_init_default}} +#define AdminMessage_init_default {0, {RadioConfig_init_default}} #define Position_init_zero {0, 0, 0, 0, 0} #define User_init_zero {"", "", "", {0}} #define RouteDiscovery_init_zero {0, {0, 0, 0, 0, 0, 0, 0, 0}} @@ -389,6 +396,7 @@ extern "C" { #define LogRecord_init_zero {"", 0, "", _LogRecord_Level_MIN} #define FromRadio_init_zero {0, 0, {MyNodeInfo_init_zero}} #define ToRadio_init_zero {0, {MeshPacket_init_zero}} +#define AdminMessage_init_zero {0, {RadioConfig_init_zero}} /* Field tags (for use in manual encoding/decoding) */ #define ChannelSettings_tx_power_tag 1 @@ -501,6 +509,9 @@ extern "C" { #define Routing_success_id_tag 4 #define Routing_fail_id_tag 5 #define Routing_original_id_tag 6 +#define AdminMessage_set_radio_tag 1 +#define AdminMessage_set_owner_tag 2 +#define AdminMessage_set_channel_tag 3 #define FromRadio_num_tag 1 #define FromRadio_my_info_tag 3 #define FromRadio_node_info_tag 4 @@ -512,9 +523,6 @@ extern "C" { #define FromRadio_packet_tag 11 #define ToRadio_packet_tag 2 #define ToRadio_want_config_id_tag 100 -#define ToRadio_set_radio_tag 101 -#define ToRadio_set_owner_tag 102 -#define ToRadio_set_channel_tag 104 /* Struct field encoding specification for nanopb */ #define Position_FIELDLIST(X, a) \ @@ -707,16 +715,20 @@ X(a, STATIC, ONEOF, MESSAGE, (payloadVariant,packet,packet), 11) #define ToRadio_FIELDLIST(X, a) \ X(a, STATIC, ONEOF, MESSAGE, (payloadVariant,packet,packet), 2) \ -X(a, STATIC, ONEOF, UINT32, (payloadVariant,want_config_id,want_config_id), 100) \ -X(a, STATIC, ONEOF, MESSAGE, (payloadVariant,set_radio,set_radio), 101) \ -X(a, STATIC, ONEOF, MESSAGE, (payloadVariant,set_owner,set_owner), 102) \ -X(a, STATIC, ONEOF, MESSAGE, (payloadVariant,set_channel,set_channel), 104) +X(a, STATIC, ONEOF, UINT32, (payloadVariant,want_config_id,want_config_id), 100) #define ToRadio_CALLBACK NULL #define ToRadio_DEFAULT NULL #define ToRadio_payloadVariant_packet_MSGTYPE MeshPacket -#define ToRadio_payloadVariant_set_radio_MSGTYPE RadioConfig -#define ToRadio_payloadVariant_set_owner_MSGTYPE User -#define ToRadio_payloadVariant_set_channel_MSGTYPE Channel + +#define AdminMessage_FIELDLIST(X, a) \ +X(a, STATIC, ONEOF, MESSAGE, (variant,set_radio,set_radio), 1) \ +X(a, STATIC, ONEOF, MESSAGE, (variant,set_owner,set_owner), 2) \ +X(a, STATIC, ONEOF, MESSAGE, (variant,set_channel,set_channel), 3) +#define AdminMessage_CALLBACK NULL +#define AdminMessage_DEFAULT NULL +#define AdminMessage_variant_set_radio_MSGTYPE RadioConfig +#define AdminMessage_variant_set_owner_MSGTYPE User +#define AdminMessage_variant_set_channel_MSGTYPE Channel extern const pb_msgdesc_t Position_msg; extern const pb_msgdesc_t User_msg; @@ -733,6 +745,7 @@ extern const pb_msgdesc_t MyNodeInfo_msg; extern const pb_msgdesc_t LogRecord_msg; extern const pb_msgdesc_t FromRadio_msg; extern const pb_msgdesc_t ToRadio_msg; +extern const pb_msgdesc_t AdminMessage_msg; /* Defines for backwards compatibility with code written before nanopb-0.4.0 */ #define Position_fields &Position_msg @@ -750,6 +763,7 @@ extern const pb_msgdesc_t ToRadio_msg; #define LogRecord_fields &LogRecord_msg #define FromRadio_fields &FromRadio_msg #define ToRadio_fields &ToRadio_msg +#define AdminMessage_fields &AdminMessage_msg /* Maximum encoded size of messages (where known) */ #define Position_size 37 @@ -766,7 +780,8 @@ extern const pb_msgdesc_t ToRadio_msg; #define MyNodeInfo_size 89 #define LogRecord_size 81 #define FromRadio_size 317 -#define ToRadio_size 312 +#define ToRadio_size 305 +#define AdminMessage_size 311 #ifdef __cplusplus } /* extern "C" */ diff --git a/src/mesh/generated/portnums.pb.h b/src/mesh/generated/portnums.pb.h index 72360f295..3ddd806ea 100644 --- a/src/mesh/generated/portnums.pb.h +++ b/src/mesh/generated/portnums.pb.h @@ -17,6 +17,7 @@ typedef enum _PortNum { PortNum_POSITION_APP = 3, PortNum_NODEINFO_APP = 4, PortNum_ROUTING_APP = 5, + PortNum_ADMIN_APP = 6, PortNum_REPLY_APP = 32, PortNum_IP_TUNNEL_APP = 33, PortNum_SERIAL_APP = 64, diff --git a/src/plugins/AdminPlugin.cpp b/src/plugins/AdminPlugin.cpp new file mode 100644 index 000000000..248a4ebd3 --- /dev/null +++ b/src/plugins/AdminPlugin.cpp @@ -0,0 +1,93 @@ +#include "AdminPlugin.h" +#include "MeshService.h" +#include "NodeDB.h" +#include "Router.h" +#include "configuration.h" +#include "main.h" +#include "Channels.h" + +AdminPlugin *adminPlugin; + +bool AdminPlugin::handleReceivedProtobuf(const MeshPacket &mp, const AdminMessage *r) +{ + assert(r); + switch(r->which_variant) { + case AdminMessage_set_owner_tag: + DEBUG_MSG("Client is setting owner\n"); + handleSetOwner(r->set_owner); + break; + + case AdminMessage_set_radio_tag: + DEBUG_MSG("Client is setting radio\n"); + handleSetRadio(r->set_radio); + break; + + case AdminMessage_set_channel_tag: + DEBUG_MSG("Client is setting channel\n"); + handleSetChannel(r->set_channel); + break; + } + return false; // Let others look at this message also if they want +} + + + +void AdminPlugin::handleSetOwner(const User &o) +{ + int changed = 0; + + if (*o.long_name) { + changed |= strcmp(owner.long_name, o.long_name); + strcpy(owner.long_name, o.long_name); + } + if (*o.short_name) { + changed |= strcmp(owner.short_name, o.short_name); + strcpy(owner.short_name, o.short_name); + } + if (*o.id) { + changed |= strcmp(owner.id, o.id); + strcpy(owner.id, o.id); + } + + if (changed) // If nothing really changed, don't broadcast on the network or write to flash + service.reloadOwner(); +} + +void AdminPlugin::handleSetChannel(const Channel &cc) +{ + channels.setChannel(cc); + + bool didReset = service.reloadConfig(); + /* FIXME - do we need this still? + if (didReset) { + state = STATE_SEND_MY_INFO; // Squirt a completely new set of configs to the client + } */ + +} + +void AdminPlugin::handleSetRadio(const RadioConfig &r) +{ + radioConfig = r; + + bool didReset = service.reloadConfig(); + /* FIXME - do we need this still? if (didReset) { + state = STATE_SEND_MY_INFO; // Squirt a completely new set of configs to the client + } */ +} + + +MeshPacket *AdminPlugin::allocReply() +{ + assert(0); // 1.2 refactoring fixme, Not sure if anything needs this yet? + // return allocDataProtobuf(u); + return NULL; +} + +AdminPlugin::AdminPlugin() + : ProtobufPlugin("Admin", PortNum_ADMIN_APP, AdminMessage_fields) +{ + // FIXME, restrict to the admin channel for rx +} + + + diff --git a/src/plugins/AdminPlugin.h b/src/plugins/AdminPlugin.h new file mode 100644 index 000000000..de8ffac11 --- /dev/null +++ b/src/plugins/AdminPlugin.h @@ -0,0 +1,32 @@ +#pragma once +#include "ProtobufPlugin.h" + +/** + * Routing plugin for router control messages + */ +class AdminPlugin : public ProtobufPlugin +{ + public: + /** Constructor + * name is for debugging output + */ + AdminPlugin(); + + protected: + /** Called to handle a particular incoming message + + @return true if you've guaranteed you've handled this message and no other handlers should be considered for it + */ + virtual bool handleReceivedProtobuf(const MeshPacket &mp, const AdminMessage *p); + + /** Messages can be received that have the want_response bit set. If set, this callback will be invoked + * so that subclasses can (optionally) send a response back to the original sender. */ + virtual MeshPacket *allocReply(); + + private: + void handleSetOwner(const User &o); + void handleSetChannel(const Channel &cc); + void handleSetRadio(const RadioConfig &r); +}; + +extern AdminPlugin *adminPlugin; \ No newline at end of file diff --git a/src/plugins/Plugins.cpp b/src/plugins/Plugins.cpp index 65cfdcee4..12246f8c8 100644 --- a/src/plugins/Plugins.cpp +++ b/src/plugins/Plugins.cpp @@ -8,6 +8,7 @@ #include "plugins/StoreForwardPlugin.h" #include "plugins/TextMessagePlugin.h" #include "plugins/RoutingPlugin.h" +#include "plugins/AdminPlugin.h" /** * Create plugin instances here. If you are adding a new plugin, you must 'new' it here (or somewhere else) @@ -15,6 +16,7 @@ void setupPlugins() { routingPlugin = new RoutingPlugin(); + adminPlugin = new AdminPlugin(); nodeInfoPlugin = new NodeInfoPlugin(); positionPlugin = new PositionPlugin(); textMessagePlugin = new TextMessagePlugin(); diff --git a/src/plugins/RoutingPlugin.cpp b/src/plugins/RoutingPlugin.cpp index c3709ea5a..58b3f08ae 100644 --- a/src/plugins/RoutingPlugin.cpp +++ b/src/plugins/RoutingPlugin.cpp @@ -1,7 +1,6 @@ #include "RoutingPlugin.h" #include "MeshService.h" #include "NodeDB.h" -#include "RTC.h" #include "Router.h" #include "configuration.h" #include "main.h" @@ -53,7 +52,7 @@ void RoutingPlugin::sendAckNak(Routing_Error err, NodeNum to, PacketId idFrom) } RoutingPlugin::RoutingPlugin() - : ProtobufPlugin("routing", PortNum_ROUTING_APP, User_fields) + : ProtobufPlugin("routing", PortNum_ROUTING_APP, Routing_fields) { isPromiscuous = true; } From 7ffe601743db09bb964da8de4a2a8bdb967fb37f Mon Sep 17 00:00:00 2001 From: Jm Date: Sat, 20 Feb 2021 23:53:17 -0800 Subject: [PATCH 134/258] Changes to how airtime noise is gathered. --- src/mesh/RadioLibInterface.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/mesh/RadioLibInterface.cpp b/src/mesh/RadioLibInterface.cpp index 63d7095c5..d7eaa8faa 100644 --- a/src/mesh/RadioLibInterface.cpp +++ b/src/mesh/RadioLibInterface.cpp @@ -114,7 +114,6 @@ ErrorCode RadioLibInterface::send(MeshPacket *p) // Count the packet toward our TX airtime utilization. // We only count it if it can be added to the TX queue. airTime->logAirtime(TX_LOG, xmitMsec); - // airTime.logAirtime(TX_LOG, xmitMsec); // We want all sending/receiving to be done by our daemon thread, We use a delay here because this packet might have been sent // in response to a packet we just received. So we want to make sure the other side has had a chance to reconfigure its radio @@ -245,13 +244,14 @@ void RadioLibInterface::handleReceiveInterrupt() size_t length = iface->getPacketLength(); xmitMsec = getPacketTime(length); - airTime->logAirtime(RX_ALL_LOG, xmitMsec); - // airTime.logAirtime(RX_ALL_LOG, xmitMsec); int state = iface->readData(radiobuf, length); if (state != ERR_NONE) { DEBUG_MSG("ignoring received packet due to error=%d\n", state); rxBad++; + + airTime->logAirtime(RX_ALL_LOG, xmitMsec); + } else { // Skip the 4 headers that are at the beginning of the rxBuf int32_t payloadLen = length - sizeof(PacketHeader); @@ -261,6 +261,7 @@ void RadioLibInterface::handleReceiveInterrupt() if (payloadLen < 0) { DEBUG_MSG("ignoring received packet too short\n"); rxBad++; + airTime->logAirtime(RX_ALL_LOG, xmitMsec); } else { const PacketHeader *h = (PacketHeader *)radiobuf; @@ -287,9 +288,8 @@ void RadioLibInterface::handleReceiveInterrupt() printPacket("Lora RX", mp); - xmitMsec = getPacketTime(mp); + //xmitMsec = getPacketTime(mp); airTime->logAirtime(RX_LOG, xmitMsec); - // airTime.logAirtime(RX_LOG, xmitMsec); deliverToReceiver(mp); } @@ -299,7 +299,7 @@ void RadioLibInterface::handleReceiveInterrupt() /** start an immediate transmit */ void RadioLibInterface::startSend(MeshPacket *txp) { - printPacket("Starting low level send", txp); + printPacket("Starting low level send", txp); if (disabled) { DEBUG_MSG("startSend is dropping tx packet because we are disabled\n"); packetPool.release(txp); From a4e5c7224fe0684371972ec0be44e9ddaac13109 Mon Sep 17 00:00:00 2001 From: Jm Date: Sat, 20 Feb 2021 23:53:53 -0800 Subject: [PATCH 135/258] Add sawNodeReport to storeforwardplugin --- src/plugins/StoreForwardPlugin.cpp | 85 ++++++++++++++++++++++++++---- src/plugins/StoreForwardPlugin.h | 1 + 2 files changed, 75 insertions(+), 11 deletions(-) diff --git a/src/plugins/StoreForwardPlugin.cpp b/src/plugins/StoreForwardPlugin.cpp index af9bf5ecd..1396afd0f 100644 --- a/src/plugins/StoreForwardPlugin.cpp +++ b/src/plugins/StoreForwardPlugin.cpp @@ -4,6 +4,7 @@ #include "RTC.h" #include "Router.h" #include "configuration.h" +#include "mesh-pb-constants.h" #include #include @@ -22,8 +23,8 @@ int32_t StoreForwardPlugin::runOnce() without having to configure it from the PythonAPI or WebUI. */ - // radioConfig.preferences.store_forward_plugin_enabled = 1; - // radioConfig.preferences.is_router = 1; + radioConfig.preferences.store_forward_plugin_enabled = 1; + radioConfig.preferences.is_router = 1; if (radioConfig.preferences.store_forward_plugin_enabled) { @@ -42,6 +43,8 @@ int32_t StoreForwardPlugin::runOnce() firstTime = 0; + return (10 * 1000); + } else { DEBUG_MSG("Device has less than 1M of PSRAM free. Aborting startup.\n"); DEBUG_MSG("Store & Forward Plugin - Aborting Startup.\n"); @@ -69,6 +72,8 @@ int32_t StoreForwardPlugin::runOnce() // What do we do if it's not our first time? // Maybe some cleanup functions? + this->sawNodeReport(); + return (10 * 1000); } } else { @@ -94,12 +99,12 @@ uint32_t StoreForwardPlugin::sawNode(uint32_t node) TODO: Implment this as a std::map for quicker lookups (maybe it doesn't matter?). */ - DEBUG_MSG("looking for node - %i\n", node); + DEBUG_MSG("looking for node - %u\n", node); for (int i = 0; i < 50; i++) { - DEBUG_MSG("Iterating through the seen nodes - %d %d %d\n", i, receivedRecord[i][0], receivedRecord[i][1]); + //DEBUG_MSG("Iterating through the seen nodes - %u %u %u\n", i, receivedRecord[i][0], receivedRecord[i][1]); // First time seeing that node. if (receivedRecord[i][0] == 0) { - DEBUG_MSG("New node! Woohoo! Win!\n"); + //DEBUG_MSG("New node! Woohoo! Win!\n"); receivedRecord[i][0] = node; receivedRecord[i][1] = millis(); @@ -108,7 +113,7 @@ uint32_t StoreForwardPlugin::sawNode(uint32_t node) // We've seen this node before. if (receivedRecord[i][0] == node) { - DEBUG_MSG("We've seen this node before\n"); + //DEBUG_MSG("We've seen this node before\n"); uint32_t lastSaw = receivedRecord[i][1]; receivedRecord[i][1] = millis(); return lastSaw; @@ -118,6 +123,27 @@ uint32_t StoreForwardPlugin::sawNode(uint32_t node) return 0; } +// We saw a node. +void StoreForwardPlugin::sawNodeReport() +{ + + /* + TODO: Move receivedRecord into the PSRAM + + TODO: Gracefully handle the case where we run out of records. + Maybe replace the oldest record that hasn't been seen in a while and assume they won't be back. + + TODO: Implment this as a std::map for quicker lookups (maybe it doesn't matter?). + */ + + DEBUG_MSG("Iterating through the seen nodes ...\n"); + for (int i = 0; i < 50; i++) { + if (receivedRecord[i][1]) { + DEBUG_MSG("... record-%u node-%u secAgo-%u\n", i, receivedRecord[i][0], (millis() - receivedRecord[i][1]) / 1000); + } + } +} + MeshPacket *StoreForwardPluginRadio::allocReply() { @@ -139,14 +165,51 @@ bool StoreForwardPluginRadio::handleReceived(const MeshPacket &mp) { #ifndef NO_ESP32 if (radioConfig.preferences.store_forward_plugin_enabled) { - // auto &p = mp.decoded.data; + auto &p = mp; if (mp.from != nodeDB.getNodeNum()) { - DEBUG_MSG("Store & Forward Plugin -- Print Start ---------- ---------- ---------- ---------- ----------\n\n\n"); - printPacket("----- PACKET FROM RADIO", &mp); - // DEBUG_MSG("\n\nStore & Forward Plugin -- Print End ---------- ---------- ---------- ---------- ----------\n"); + // DEBUG_MSG("Store & Forward Plugin -- Print Start ---------- ---------- ---------- ---------- ----------\n\n\n"); + printPacket("----- PACKET FROM RADIO -----", &mp); uint32_t sawTime = storeForwardPlugin->sawNode(mp.from); - DEBUG_MSG("Last Saw this node %d, %d millis ago\n", mp.from, (millis() - sawTime)); + DEBUG_MSG("We last saw this node (%u), %u sec ago\n", mp.from, (millis() - sawTime) / 1000); + + if (mp.decoded.data.portnum == PortNum_UNKNOWN_APP) { + DEBUG_MSG("Packet came from - PortNum_UNKNOWN_APP\n"); + } else if (mp.decoded.data.portnum == PortNum_TEXT_MESSAGE_APP) { + DEBUG_MSG("Packet came from - PortNum_TEXT_MESSAGE_APP\n"); + } else if (mp.decoded.data.portnum == PortNum_REMOTE_HARDWARE_APP) { + DEBUG_MSG("Packet came from - PortNum_REMOTE_HARDWARE_APP\n"); + } else if (mp.decoded.data.portnum == PortNum_POSITION_APP) { + DEBUG_MSG("Packet came from - PortNum_POSITION_APP\n"); + } else if (mp.decoded.data.portnum == PortNum_NODEINFO_APP) { + DEBUG_MSG("Packet came from - PortNum_NODEINFO_APP\n"); + } else if (mp.decoded.data.portnum == PortNum_REPLY_APP) { + DEBUG_MSG("Packet came from - PortNum_REPLY_APP\n"); + } else if (mp.decoded.data.portnum == PortNum_IP_TUNNEL_APP) { + DEBUG_MSG("Packet came from - PortNum_IP_TUNNEL_APP\n"); + } else if (mp.decoded.data.portnum == PortNum_SERIAL_APP) { + DEBUG_MSG("Packet came from - PortNum_SERIAL_APP\n"); + } else if (mp.decoded.data.portnum == PortNum_STORE_FORWARD_APP) { + DEBUG_MSG("Packet came from - PortNum_STORE_FORWARD_APP\n"); + } else if (mp.decoded.data.portnum == PortNum_RANGE_TEST_APP) { + DEBUG_MSG("Packet came from - PortNum_RANGE_TEST_APP\n"); + } else if (mp.decoded.data.portnum == PortNum_PRIVATE_APP) { + DEBUG_MSG("Packet came from - PortNum_PRIVATE_APP\n"); + } else if (mp.decoded.data.portnum == PortNum_RANGE_TEST_APP) { + DEBUG_MSG("Packet came from - PortNum_RANGE_TEST_APP\n"); + } else if (mp.decoded.data.portnum == PortNum_ATAK_FORWARDER) { + DEBUG_MSG("Packet came from - PortNum_ATAK_FORWARDER\n"); + } else { + DEBUG_MSG("Packet came from an unknown port %u\n", mp.decoded.data.portnum); + } + + static uint8_t bytes[MAX_RHPACKETLEN]; + size_t numbytes = pb_encode_to_bytes(bytes, sizeof(bytes), SubPacket_fields, &p.decoded); + assert(numbytes <= MAX_RHPACKETLEN); + + DEBUG_MSG("MP numbytes %u\n", numbytes); + + // Serialization is in Router.cpp line 180 } } else { diff --git a/src/plugins/StoreForwardPlugin.h b/src/plugins/StoreForwardPlugin.h index e44d53704..9380d2161 100644 --- a/src/plugins/StoreForwardPlugin.h +++ b/src/plugins/StoreForwardPlugin.h @@ -22,6 +22,7 @@ class StoreForwardPlugin : private concurrency::OSThread @return 0 if we have never seen that node before otherwise return the last time we saw the node. */ uint32_t sawNode(uint32_t); + void sawNodeReport(); private: // Nothing here From 3c564796e0f540a5d25243ab23f9929c8312ff9b Mon Sep 17 00:00:00 2001 From: Charles Crossan Date: Sun, 17 Jan 2021 15:59:48 -0500 Subject: [PATCH 136/258] --- platformio.ini | 2 + proto | 2 +- .../generated/environmental_measurement.pb.c | 12 ++ .../generated/environmental_measurement.pb.h | 53 +++++++++ src/mesh/generated/portnums.pb.h | 1 + src/plugins/Plugins.cpp | 2 + .../esp32/EnvironmentalMeasurementPlugin.cpp | 104 ++++++++++++++++++ .../esp32/EnvironmentalMeasurementPlugin.h | 45 ++++++++ 8 files changed, 220 insertions(+), 1 deletion(-) create mode 100644 src/mesh/generated/environmental_measurement.pb.c create mode 100644 src/mesh/generated/environmental_measurement.pb.h create mode 100644 src/plugins/esp32/EnvironmentalMeasurementPlugin.cpp create mode 100644 src/plugins/esp32/EnvironmentalMeasurementPlugin.h diff --git a/platformio.ini b/platformio.ini index 89cf5a1ac..39b57dd9c 100644 --- a/platformio.ini +++ b/platformio.ini @@ -104,6 +104,8 @@ build_flags = lib_deps = ${arduino_base.lib_deps} https://github.com/meshtastic/esp32_https_server.git + adafruit/DHT sensor library@^1.4.1 + adafruit/Adafruit Unified Sensor@^1.1.4 # Hmm - this doesn't work yet # board_build.ldscript = linker/esp32.extram.bss.ld lib_ignore = segger_rtt diff --git a/proto b/proto index 0cadaed39..564292ee8 160000 --- a/proto +++ b/proto @@ -1 +1 @@ -Subproject commit 0cadaed3953f66cf1edc99d0fa53e4fd5ebf56d6 +Subproject commit 564292ee83bbd085d0c51a7f882d3a2aa305d6d6 diff --git a/src/mesh/generated/environmental_measurement.pb.c b/src/mesh/generated/environmental_measurement.pb.c new file mode 100644 index 000000000..b55d14a0a --- /dev/null +++ b/src/mesh/generated/environmental_measurement.pb.c @@ -0,0 +1,12 @@ +/* Automatically generated nanopb constant definitions */ +/* Generated by nanopb-0.4.4 */ + +#include "environmental_measurement.pb.h" +#if PB_PROTO_HEADER_VERSION != 40 +#error Regenerate this file with the current version of nanopb generator. +#endif + +PB_BIND(EnvironmentalMeasurement, EnvironmentalMeasurement, AUTO) + + + diff --git a/src/mesh/generated/environmental_measurement.pb.h b/src/mesh/generated/environmental_measurement.pb.h new file mode 100644 index 000000000..8adf5774a --- /dev/null +++ b/src/mesh/generated/environmental_measurement.pb.h @@ -0,0 +1,53 @@ +/* Automatically generated nanopb header */ +/* Generated by nanopb-0.4.4 */ + +#ifndef PB_ENVIRONMENTAL_MEASUREMENT_PB_H_INCLUDED +#define PB_ENVIRONMENTAL_MEASUREMENT_PB_H_INCLUDED +#include + +#if PB_PROTO_HEADER_VERSION != 40 +#error Regenerate this file with the current version of nanopb generator. +#endif + +/* Struct definitions */ +typedef struct _EnvironmentalMeasurement { + float temperature; + float relative_humidity; + float barometric_pressure; +} EnvironmentalMeasurement; + + +#ifdef __cplusplus +extern "C" { +#endif + +/* Initializer values for message structs */ +#define EnvironmentalMeasurement_init_default {0, 0, 0} +#define EnvironmentalMeasurement_init_zero {0, 0, 0} + +/* Field tags (for use in manual encoding/decoding) */ +#define EnvironmentalMeasurement_temperature_tag 1 +#define EnvironmentalMeasurement_relative_humidity_tag 2 +#define EnvironmentalMeasurement_barometric_pressure_tag 3 + +/* Struct field encoding specification for nanopb */ +#define EnvironmentalMeasurement_FIELDLIST(X, a) \ +X(a, STATIC, SINGULAR, FLOAT, temperature, 1) \ +X(a, STATIC, SINGULAR, FLOAT, relative_humidity, 2) \ +X(a, STATIC, SINGULAR, FLOAT, barometric_pressure, 3) +#define EnvironmentalMeasurement_CALLBACK NULL +#define EnvironmentalMeasurement_DEFAULT NULL + +extern const pb_msgdesc_t EnvironmentalMeasurement_msg; + +/* Defines for backwards compatibility with code written before nanopb-0.4.0 */ +#define EnvironmentalMeasurement_fields &EnvironmentalMeasurement_msg + +/* Maximum encoded size of messages (where known) */ +#define EnvironmentalMeasurement_size 15 + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif diff --git a/src/mesh/generated/portnums.pb.h b/src/mesh/generated/portnums.pb.h index 2133ecaa7..8d262c471 100644 --- a/src/mesh/generated/portnums.pb.h +++ b/src/mesh/generated/portnums.pb.h @@ -18,6 +18,7 @@ typedef enum _PortNum { PortNum_NODEINFO_APP = 4, PortNum_REPLY_APP = 32, PortNum_IP_TUNNEL_APP = 33, + PortNum_ENVIRONMENTAL_MEASUREMENT_APP = 34, PortNum_SERIAL_APP = 64, PortNum_STORE_FORWARD_APP = 65, PortNum_RANGE_TEST_APP = 66, diff --git a/src/plugins/Plugins.cpp b/src/plugins/Plugins.cpp index c2dfd73ca..233c5f376 100644 --- a/src/plugins/Plugins.cpp +++ b/src/plugins/Plugins.cpp @@ -6,6 +6,7 @@ #include "plugins/TextMessagePlugin.h" #ifndef NO_ESP32 +#include "plugins/esp32/EnvironmentalMeasurementPlugin.h" #include "plugins/esp32/RangeTestPlugin.h" #include "plugins/SerialPlugin.h" #include "plugins/StoreForwardPlugin.h" @@ -19,6 +20,7 @@ void setupPlugins() nodeInfoPlugin = new NodeInfoPlugin(); positionPlugin = new PositionPlugin(); textMessagePlugin = new TextMessagePlugin(); + environmentalMeasurementPlugin = new EnvironmentalMeasurementPlugin(); // Note: if the rest of meshtastic doesn't need to explicitly use your plugin, you do not need to assign the instance // to a global variable. diff --git a/src/plugins/esp32/EnvironmentalMeasurementPlugin.cpp b/src/plugins/esp32/EnvironmentalMeasurementPlugin.cpp new file mode 100644 index 000000000..75bb09114 --- /dev/null +++ b/src/plugins/esp32/EnvironmentalMeasurementPlugin.cpp @@ -0,0 +1,104 @@ +#include "EnvironmentalMeasurementPlugin.h" +#include "MeshService.h" +#include "NodeDB.h" +#include "RTC.h" +#include "Router.h" +#include "configuration.h" +#include "main.h" +#include "../mesh/generated/environmental_measurement.pb.h" +#include + +EnvironmentalMeasurementPlugin *environmentalMeasurementPlugin; +EnvironmentalMeasurementPluginRadio *environmentalMeasurementPluginRadio; + +EnvironmentalMeasurementPlugin::EnvironmentalMeasurementPlugin() : concurrency::OSThread("EnvironmentalMeasurementPlugin") {} + +uint32_t sensor_read_error_count = 0; + +#define DHT_11_GPIO_PIN 13 +//TODO: Make a related radioconfig preference to allow less-frequent reads +#define DHT_SENSOR_MINIMUM_WAIT_TIME_BETWEEN_READS 1000 +#define SENSOR_READ_ERROR_COUNT_THRESHOLD 5 +#define SENSOR_READ_MULTIPLIER 3 + + +DHT dht(DHT_11_GPIO_PIN,DHT11); + +int32_t EnvironmentalMeasurementPlugin::runOnce() { +#ifndef NO_ESP32 + if (firstTime) { + // This is the first time the OSThread library has called this function, so do some setup + DEBUG_MSG("Initializing Environmental Measurement Plugin -- Sender\n"); + environmentalMeasurementPluginRadio = new EnvironmentalMeasurementPluginRadio(); + firstTime = 0; + // begin reading measurements from the sensor + // DHT have a max read-rate of 1HZ, so we should wait at least 1 second + // after initializing the sensor before we try to read from it. + // returning the interval here means that the next time OSThread + // calls our plugin, we'll run the other branch of this if statement + // and actually do a "sendOurEnvironmentalMeasurement()" + dht.begin(); + return(DHT_SENSOR_MINIMUM_WAIT_TIME_BETWEEN_READS); + } + else { + // this is not the first time OSThread library has called this function + // so just do what we intend to do on the interval + if(sensor_read_error_count > SENSOR_READ_ERROR_COUNT_THRESHOLD) + { + DEBUG_MSG("Environmental Measurement Plugin: DISABLED; The SENSOR_READ_ERROR_COUNT_THRESHOLD has been exceed: %d\n",SENSOR_READ_ERROR_COUNT_THRESHOLD); + return(DHT_SENSOR_MINIMUM_WAIT_TIME_BETWEEN_READS); + } + else if (sensor_read_error_count > 0){ + DEBUG_MSG("Environmental Measurement Plugin: There have been %d sensor read failures.\n",sensor_read_error_count); + } + if (! environmentalMeasurementPluginRadio->sendOurEnvironmentalMeasurement() ){ + // if we failed to read the sensor, then try again + // as soon as we can according to the maximum polling frequency + return(DHT_SENSOR_MINIMUM_WAIT_TIME_BETWEEN_READS); + } + } + // The return of runOnce is an int32 representing the desired number of + // miliseconds until the function should be called again by the + // OSThread library. + return(SENSOR_READ_MULTIPLIER * DHT_SENSOR_MINIMUM_WAIT_TIME_BETWEEN_READS); +#endif +} + +bool EnvironmentalMeasurementPluginRadio::handleReceivedProtobuf(const MeshPacket &mp, const EnvironmentalMeasurement &p) +{ + // This plugin doesn't really do anything with the messages it receives. + return false; // Let others look at this message also if they want +} + +bool EnvironmentalMeasurementPluginRadio::sendOurEnvironmentalMeasurement(NodeNum dest, bool wantReplies) +{ + EnvironmentalMeasurement m; + + m.barometric_pressure=0; + float t = dht.readTemperature(); + float h = dht.readHumidity(); + m.relative_humidity= 0; + m.temperature=0; + + DEBUG_MSG("-----------------------------------------\n"); + + DEBUG_MSG("Environmental Measurement Plugin: Read data\n"); + DEBUG_MSG("EnvironmentalMeasurement->relative_humidity: %f\n",h); + DEBUG_MSG("EnvironmentalMeasurement->temperature: %f\n",t); + + if (isnan(h) || isnan(t) ){ + sensor_read_error_count++; + DEBUG_MSG("Environmental Measurement Plugin: FAILED TO READ DATA\n"); + return false; + } + + sensor_read_error_count = 0; + + MeshPacket *p = allocDataProtobuf(m); + p->to = dest; + p->decoded.want_response = wantReplies; + + service.sendToMesh(p); + return true; +} + diff --git a/src/plugins/esp32/EnvironmentalMeasurementPlugin.h b/src/plugins/esp32/EnvironmentalMeasurementPlugin.h new file mode 100644 index 000000000..31581b31b --- /dev/null +++ b/src/plugins/esp32/EnvironmentalMeasurementPlugin.h @@ -0,0 +1,45 @@ +#pragma once +#include "ProtobufPlugin.h" +#include "../mesh/generated/environmental_measurement.pb.h" + + +class EnvironmentalMeasurementPlugin : private concurrency::OSThread +{ + bool firstTime = 1; + + public: + EnvironmentalMeasurementPlugin(); + + protected: + virtual int32_t runOnce(); +}; + +extern EnvironmentalMeasurementPlugin *environmentalMeasurementPlugin; + +/** + * EnvironmentalMeasurementPluginRadio plugin for sending/receiving environmental measurements to/from the mesh + */ +class EnvironmentalMeasurementPluginRadio : public ProtobufPlugin +{ + public: + /** Constructor + * name is for debugging output + */ + EnvironmentalMeasurementPluginRadio() : ProtobufPlugin("EnvironmentalMeasurement", PortNum_ENVIRONMENTAL_MEASUREMENT_APP, &EnvironmentalMeasurement_msg) {} + + /** + * Send our EnvironmentalMeasurement into the mesh + */ + bool sendOurEnvironmentalMeasurement(NodeNum dest = NODENUM_BROADCAST, bool wantReplies = false); + + protected: + + /** Called to handle a particular incoming message + + @return true if you've guaranteed you've handled this message and no other handlers should be considered for it + */ + virtual bool handleReceivedProtobuf(const MeshPacket &mp, const EnvironmentalMeasurement &p); + +}; + +extern EnvironmentalMeasurementPluginRadio *environmentalMeasurementPluginRadio; \ No newline at end of file From 77961e8e9366d68c4a10b23d870bc17d5918928f Mon Sep 17 00:00:00 2001 From: Charles Crossan Date: Sun, 21 Feb 2021 11:00:58 -0500 Subject: [PATCH 137/258] Un-derp testing details --- .../esp32/EnvironmentalMeasurementPlugin.cpp | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/src/plugins/esp32/EnvironmentalMeasurementPlugin.cpp b/src/plugins/esp32/EnvironmentalMeasurementPlugin.cpp index 75bb09114..76eda3d2d 100644 --- a/src/plugins/esp32/EnvironmentalMeasurementPlugin.cpp +++ b/src/plugins/esp32/EnvironmentalMeasurementPlugin.cpp @@ -74,19 +74,17 @@ bool EnvironmentalMeasurementPluginRadio::sendOurEnvironmentalMeasurement(NodeNu { EnvironmentalMeasurement m; - m.barometric_pressure=0; - float t = dht.readTemperature(); - float h = dht.readHumidity(); - m.relative_humidity= 0; - m.temperature=0; + m.barometric_pressure = 0; // TODO: Add support for barometric sensors + m.relative_humidity = dht.readHumidity(); + m.temperature = dht.readTemperature();; DEBUG_MSG("-----------------------------------------\n"); DEBUG_MSG("Environmental Measurement Plugin: Read data\n"); - DEBUG_MSG("EnvironmentalMeasurement->relative_humidity: %f\n",h); - DEBUG_MSG("EnvironmentalMeasurement->temperature: %f\n",t); + DEBUG_MSG("EnvironmentalMeasurement->relative_humidity: %f\n", m.relative_humidity); + DEBUG_MSG("EnvironmentalMeasurement->temperature: %f\n", m.temperature); - if (isnan(h) || isnan(t) ){ + if (isnan(m.relative_humidity) || isnan(m.temperature) ){ sensor_read_error_count++; DEBUG_MSG("Environmental Measurement Plugin: FAILED TO READ DATA\n"); return false; From 27f74382aab3a77dd5150a6f60510b5e92c77ccc Mon Sep 17 00:00:00 2001 From: Charles Crossan Date: Sun, 21 Feb 2021 11:09:58 -0500 Subject: [PATCH 138/258] Fix CI build for non-esp32 devices --- src/plugins/Plugins.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/Plugins.cpp b/src/plugins/Plugins.cpp index 233c5f376..cfcc21d54 100644 --- a/src/plugins/Plugins.cpp +++ b/src/plugins/Plugins.cpp @@ -20,7 +20,6 @@ void setupPlugins() nodeInfoPlugin = new NodeInfoPlugin(); positionPlugin = new PositionPlugin(); textMessagePlugin = new TextMessagePlugin(); - environmentalMeasurementPlugin = new EnvironmentalMeasurementPlugin(); // Note: if the rest of meshtastic doesn't need to explicitly use your plugin, you do not need to assign the instance // to a global variable. @@ -42,5 +41,6 @@ void setupPlugins() new RangeTestPlugin(); // new StoreForwardPlugin(); + new EnvironmentalMeasurementPlugin(); #endif } \ No newline at end of file From 0b20c46b790872e3fbaaa372397d10b9cb08d888 Mon Sep 17 00:00:00 2001 From: Charles Crossan Date: Sun, 21 Feb 2021 11:39:20 -0500 Subject: [PATCH 139/258] standardize log line beginnings --- src/plugins/esp32/EnvironmentalMeasurementPlugin.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/plugins/esp32/EnvironmentalMeasurementPlugin.cpp b/src/plugins/esp32/EnvironmentalMeasurementPlugin.cpp index 76eda3d2d..0497a2b67 100644 --- a/src/plugins/esp32/EnvironmentalMeasurementPlugin.cpp +++ b/src/plugins/esp32/EnvironmentalMeasurementPlugin.cpp @@ -28,7 +28,7 @@ int32_t EnvironmentalMeasurementPlugin::runOnce() { #ifndef NO_ESP32 if (firstTime) { // This is the first time the OSThread library has called this function, so do some setup - DEBUG_MSG("Initializing Environmental Measurement Plugin -- Sender\n"); + DEBUG_MSG("EnvironmentalMeasurement: Initializing as sender\n"); environmentalMeasurementPluginRadio = new EnvironmentalMeasurementPluginRadio(); firstTime = 0; // begin reading measurements from the sensor @@ -45,11 +45,11 @@ int32_t EnvironmentalMeasurementPlugin::runOnce() { // so just do what we intend to do on the interval if(sensor_read_error_count > SENSOR_READ_ERROR_COUNT_THRESHOLD) { - DEBUG_MSG("Environmental Measurement Plugin: DISABLED; The SENSOR_READ_ERROR_COUNT_THRESHOLD has been exceed: %d\n",SENSOR_READ_ERROR_COUNT_THRESHOLD); - return(DHT_SENSOR_MINIMUM_WAIT_TIME_BETWEEN_READS); + DEBUG_MSG("EEnvironmentalMeasurement: DISABLED; The SENSOR_READ_ERROR_COUNT_THRESHOLD has been exceed: %d\n",SENSOR_READ_ERROR_COUNT_THRESHOLD); + return(FAILED_STATE_SENSOR_READ_MULTIPLIER * DHT_SENSOR_MINIMUM_WAIT_TIME_BETWEEN_READS); } else if (sensor_read_error_count > 0){ - DEBUG_MSG("Environmental Measurement Plugin: There have been %d sensor read failures.\n",sensor_read_error_count); + DEBUG_MSG("EnvironmentalMeasurement: There have been %d sensor read failures.\n",sensor_read_error_count); } if (! environmentalMeasurementPluginRadio->sendOurEnvironmentalMeasurement() ){ // if we failed to read the sensor, then try again @@ -80,13 +80,13 @@ bool EnvironmentalMeasurementPluginRadio::sendOurEnvironmentalMeasurement(NodeNu DEBUG_MSG("-----------------------------------------\n"); - DEBUG_MSG("Environmental Measurement Plugin: Read data\n"); + DEBUG_MSG("EnvironmentalMeasurement: Read data\n"); DEBUG_MSG("EnvironmentalMeasurement->relative_humidity: %f\n", m.relative_humidity); DEBUG_MSG("EnvironmentalMeasurement->temperature: %f\n", m.temperature); if (isnan(m.relative_humidity) || isnan(m.temperature) ){ sensor_read_error_count++; - DEBUG_MSG("Environmental Measurement Plugin: FAILED TO READ DATA\n"); + DEBUG_MSG("EnvironmentalMeasurement: FAILED TO READ DATA\n"); return false; } From 765a6fcc627c6a53d3b770201ade1a6abc06f5ee Mon Sep 17 00:00:00 2001 From: Charles Crossan Date: Sun, 21 Feb 2021 11:39:45 -0500 Subject: [PATCH 140/258] Display received measurements in logs and on screen --- .../esp32/EnvironmentalMeasurementPlugin.cpp | 25 +++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/src/plugins/esp32/EnvironmentalMeasurementPlugin.cpp b/src/plugins/esp32/EnvironmentalMeasurementPlugin.cpp index 0497a2b67..d141bf8d8 100644 --- a/src/plugins/esp32/EnvironmentalMeasurementPlugin.cpp +++ b/src/plugins/esp32/EnvironmentalMeasurementPlugin.cpp @@ -20,7 +20,8 @@ uint32_t sensor_read_error_count = 0; #define DHT_SENSOR_MINIMUM_WAIT_TIME_BETWEEN_READS 1000 #define SENSOR_READ_ERROR_COUNT_THRESHOLD 5 #define SENSOR_READ_MULTIPLIER 3 - +#define FAILED_STATE_SENSOR_READ_MULTIPLIER 10 +#define DISPLAY_RECEIVEID_MEASUREMENTS_ON_SCREEN true DHT dht(DHT_11_GPIO_PIN,DHT11); @@ -66,7 +67,27 @@ int32_t EnvironmentalMeasurementPlugin::runOnce() { bool EnvironmentalMeasurementPluginRadio::handleReceivedProtobuf(const MeshPacket &mp, const EnvironmentalMeasurement &p) { - // This plugin doesn't really do anything with the messages it receives. + bool wasBroadcast = mp.to == NODENUM_BROADCAST; + String sender; + + if (nodeDB.getNode(mp.from)){ + sender = nodeDB.getNode(mp.from)->user.short_name; + } + else { + sender = "UNK"; + } + // Show new nodes on LCD screen + if (DISPLAY_RECEIVEID_MEASUREMENTS_ON_SCREEN && wasBroadcast) { + String lcd = String("Env Measured: ") + sender + "\n" + + "T: " + p.temperature + "\n" + + "H: " + p.relative_humidity + "\n"; + screen->print(lcd.c_str()); + } + DEBUG_MSG("-----------------------------------------\n"); + + DEBUG_MSG("EnvironmentalMeasurement: Received data from %s\n",sender); + DEBUG_MSG("EnvironmentalMeasurement->relative_humidity: %f\n", p.relative_humidity); + DEBUG_MSG("EnvironmentalMeasurement->temperature: %f\n", p.temperature); return false; // Let others look at this message also if they want } From 5817afd4ac2a632f62eb1ab4abbdcdcc7a021869 Mon Sep 17 00:00:00 2001 From: Charles Crossan Date: Sun, 21 Feb 2021 11:42:03 -0500 Subject: [PATCH 141/258] fix port number for ENVIRONMENTAL_MEASUREMENT_APP --- proto | 2 +- src/mesh/generated/portnums.pb.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/proto b/proto index 564292ee8..c92fafdf6 160000 --- a/proto +++ b/proto @@ -1 +1 @@ -Subproject commit 564292ee83bbd085d0c51a7f882d3a2aa305d6d6 +Subproject commit c92fafdf61b923618a5f671ff2fa5a4a9f8bd65c diff --git a/src/mesh/generated/portnums.pb.h b/src/mesh/generated/portnums.pb.h index 8d262c471..8f261c947 100644 --- a/src/mesh/generated/portnums.pb.h +++ b/src/mesh/generated/portnums.pb.h @@ -18,7 +18,7 @@ typedef enum _PortNum { PortNum_NODEINFO_APP = 4, PortNum_REPLY_APP = 32, PortNum_IP_TUNNEL_APP = 33, - PortNum_ENVIRONMENTAL_MEASUREMENT_APP = 34, + PortNum_ENVIRONMENTAL_MEASUREMENT_APP = 67, PortNum_SERIAL_APP = 64, PortNum_STORE_FORWARD_APP = 65, PortNum_RANGE_TEST_APP = 66, From fc72d16bcb121a6acb81abe6e6a3c65ca50b6cb0 Mon Sep 17 00:00:00 2001 From: Charles Crossan Date: Sun, 21 Feb 2021 11:48:32 -0500 Subject: [PATCH 142/258] Disable the plugin by default --- src/plugins/esp32/EnvironmentalMeasurementPlugin.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/plugins/esp32/EnvironmentalMeasurementPlugin.cpp b/src/plugins/esp32/EnvironmentalMeasurementPlugin.cpp index d141bf8d8..1e6aed778 100644 --- a/src/plugins/esp32/EnvironmentalMeasurementPlugin.cpp +++ b/src/plugins/esp32/EnvironmentalMeasurementPlugin.cpp @@ -17,6 +17,7 @@ uint32_t sensor_read_error_count = 0; #define DHT_11_GPIO_PIN 13 //TODO: Make a related radioconfig preference to allow less-frequent reads +#define ENVIRONMENTAL_MEASUREMENT_APP_ENABLED false // DISABLED by default; set this to true if you want to use the plugin #define DHT_SENSOR_MINIMUM_WAIT_TIME_BETWEEN_READS 1000 #define SENSOR_READ_ERROR_COUNT_THRESHOLD 5 #define SENSOR_READ_MULTIPLIER 3 @@ -27,6 +28,10 @@ DHT dht(DHT_11_GPIO_PIN,DHT11); int32_t EnvironmentalMeasurementPlugin::runOnce() { #ifndef NO_ESP32 + if (!ENVIRONMENTAL_MEASUREMENT_APP_ENABLED){ + // If this plugin is not enabled, don't waste any OSThread time on it + return (INT32_MAX); + } if (firstTime) { // This is the first time the OSThread library has called this function, so do some setup DEBUG_MSG("EnvironmentalMeasurement: Initializing as sender\n"); @@ -67,6 +72,10 @@ int32_t EnvironmentalMeasurementPlugin::runOnce() { bool EnvironmentalMeasurementPluginRadio::handleReceivedProtobuf(const MeshPacket &mp, const EnvironmentalMeasurement &p) { + if (!ENVIRONMENTAL_MEASUREMENT_APP_ENABLED){ + // If this plugin is not enabled, don't handle the packet, and allow other plugins to consume + return false; + } bool wasBroadcast = mp.to == NODENUM_BROADCAST; String sender; From 087945d7cb61b1726e87c188b9eb77bda5700468 Mon Sep 17 00:00:00 2001 From: Charles Crossan Date: Sun, 21 Feb 2021 12:05:23 -0500 Subject: [PATCH 143/258] udpate protobufs --- proto | 2 +- src/mesh/generated/portnums.pb.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/proto b/proto index c92fafdf6..930646441 160000 --- a/proto +++ b/proto @@ -1 +1 @@ -Subproject commit c92fafdf61b923618a5f671ff2fa5a4a9f8bd65c +Subproject commit 9306464417522aa8b25672b324a3bd5e9dec3395 diff --git a/src/mesh/generated/portnums.pb.h b/src/mesh/generated/portnums.pb.h index 8f261c947..496324a86 100644 --- a/src/mesh/generated/portnums.pb.h +++ b/src/mesh/generated/portnums.pb.h @@ -18,10 +18,10 @@ typedef enum _PortNum { PortNum_NODEINFO_APP = 4, PortNum_REPLY_APP = 32, PortNum_IP_TUNNEL_APP = 33, - PortNum_ENVIRONMENTAL_MEASUREMENT_APP = 67, PortNum_SERIAL_APP = 64, PortNum_STORE_FORWARD_APP = 65, PortNum_RANGE_TEST_APP = 66, + PortNum_ENVIRONMENTAL_MEASUREMENT_APP = 67, PortNum_PRIVATE_APP = 256, PortNum_ATAK_FORWARDER = 257 } PortNum; From ae76ce4024b2976ccd88e2b874e8a96f3984f52a Mon Sep 17 00:00:00 2001 From: Charles Crossan Date: Sun, 21 Feb 2021 16:46:46 -0500 Subject: [PATCH 144/258] Implement interface for plugins to have custom UI Frames --- src/graphics/Screen.cpp | 31 ++++++++++ src/mesh/MeshPlugin.cpp | 16 ++++- src/mesh/MeshPlugin.h | 15 ++++- .../esp32/EnvironmentalMeasurementPlugin.cpp | 60 +++++++++++++++---- .../esp32/EnvironmentalMeasurementPlugin.h | 15 +++++ 5 files changed, 125 insertions(+), 12 deletions(-) diff --git a/src/graphics/Screen.cpp b/src/graphics/Screen.cpp index 40ea25237..d0a235e8c 100644 --- a/src/graphics/Screen.cpp +++ b/src/graphics/Screen.cpp @@ -64,6 +64,10 @@ uint8_t imgBattery[16] = {0xFF, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, // Threshold values for the GPS lock accuracy bar display uint32_t dopThresholds[5] = {2000, 1000, 500, 200, 100}; +// At some point, we're going to ask all of the plugins if they would like to display a screen frame +// we'll need to hold onto pointers for the plugins that can draw a frame. +std::vector pluginFrames; + // Stores the last 4 of our hardware ID, to make finding the device for pairing easier static char ourId[5]; @@ -144,6 +148,14 @@ static void drawSleepScreen(OLEDDisplay *display, OLEDDisplayUiState *state, int drawIconScreen("Sleeping...", display, state, x, y); } +static void drawPluginFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y) +{ + DEBUG_MSG("Drawing Plugin Frame %d\n\n", state->currentFrame); + MeshPlugin &pi = *pluginFrames.at(state->currentFrame); + pi.drawFrame(display,state,x,y); + +} + static void drawFrameBluetooth(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y) { display->setTextAlignment(TEXT_ALIGN_CENTER); @@ -887,6 +899,11 @@ void Screen::setFrames() DEBUG_MSG("showing standard frames\n"); showingNormalScreen = true; + pluginFrames = MeshPlugin::GetMeshPluginsWithUIFrames(); + DEBUG_MSG("Showing %d plugin frames\n", pluginFrames.size()); + int totalFrameCount = MAX_NUM_NODES + NUM_EXTRA_FRAMES + pluginFrames.size(); + DEBUG_MSG("Total frame count: %d\n", totalFrameCount); + // We don't show the node info our our node (if we have it yet - we should) size_t numnodes = nodeStatus->getNumTotal(); if (numnodes > 0) @@ -894,6 +911,18 @@ void Screen::setFrames() size_t numframes = 0; + // put all of the plugin frames first. + // this is a little bit of a dirty hack; since we're going to call + // the same drawPluginFrame handler here for all of these plugin frames + // and then we'll just assume that the state->currentFrame value + // is the same offset into the pluginFrames vector + // so that we can invoke the plugin's callback + for (auto i = pluginFrames.begin(); i != pluginFrames.end(); ++i) { + normalFrames[numframes++] = drawPluginFrame; + } + + DEBUG_MSG("Added plugins. numframes: %d", numframes); + // If we have a critical fault, show it first if (myNodeInfo.error_code) normalFrames[numframes++] = drawCriticalFaultFrame; @@ -922,6 +951,8 @@ void Screen::setFrames() } #endif + DEBUG_MSG("Finished building frames. numframes: %d\n", numframes); + ui.setFrames(normalFrames, numframes); ui.enableAllIndicators(); diff --git a/src/mesh/MeshPlugin.cpp b/src/mesh/MeshPlugin.cpp index ebaee49a6..006ce571b 100644 --- a/src/mesh/MeshPlugin.cpp +++ b/src/mesh/MeshPlugin.cpp @@ -75,4 +75,18 @@ void MeshPlugin::sendResponse(const MeshPacket &req) { void setReplyTo(MeshPacket *p, const MeshPacket &to) { p->to = to.from; p->want_ack = to.want_ack; -} \ No newline at end of file +} + +std::vector MeshPlugin::GetMeshPluginsWithUIFrames() { + + std::vector pluginsWithUIFrames; + for (auto i = plugins->begin(); i != plugins->end(); ++i) { + auto &pi = **i; + if ( pi.wantUIFrame()) { + DEBUG_MSG("Plugin wants a UI Frame\n"); + pluginsWithUIFrames.push_back(&pi); + } + } + return pluginsWithUIFrames; + +} diff --git a/src/mesh/MeshPlugin.h b/src/mesh/MeshPlugin.h index 01af58114..a5fa48445 100644 --- a/src/mesh/MeshPlugin.h +++ b/src/mesh/MeshPlugin.h @@ -2,6 +2,8 @@ #include "mesh/MeshTypes.h" #include +#include +#include /** A baseclass for any mesh "plugin". * * A plugin allows you to add new features to meshtastic device code, without needing to know messaging details. @@ -14,7 +16,7 @@ */ class MeshPlugin { - static std::vector *plugins; + static std::vector *plugins; public: /** Constructor @@ -28,6 +30,10 @@ class MeshPlugin */ static void callPlugins(const MeshPacket &mp); + static std::vector GetMeshPluginsWithUIFrames(); + + virtual void drawFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y) { return; } + protected: const char *name; @@ -61,6 +67,13 @@ class MeshPlugin * so that subclasses can (optionally) send a response back to the original sender. */ virtual MeshPacket *allocReply() { return NULL; } + /*** + * @return true if you want to be alloced a UI screen frame + */ + virtual bool wantUIFrame() { return false; } + + + private: /** Messages can be received that have the want_response bit set. If set, this callback will be invoked diff --git a/src/plugins/esp32/EnvironmentalMeasurementPlugin.cpp b/src/plugins/esp32/EnvironmentalMeasurementPlugin.cpp index 1e6aed778..1d8ecfab7 100644 --- a/src/plugins/esp32/EnvironmentalMeasurementPlugin.cpp +++ b/src/plugins/esp32/EnvironmentalMeasurementPlugin.cpp @@ -7,6 +7,8 @@ #include "main.h" #include "../mesh/generated/environmental_measurement.pb.h" #include +#include +#include EnvironmentalMeasurementPlugin *environmentalMeasurementPlugin; EnvironmentalMeasurementPluginRadio *environmentalMeasurementPluginRadio; @@ -17,7 +19,7 @@ uint32_t sensor_read_error_count = 0; #define DHT_11_GPIO_PIN 13 //TODO: Make a related radioconfig preference to allow less-frequent reads -#define ENVIRONMENTAL_MEASUREMENT_APP_ENABLED false // DISABLED by default; set this to true if you want to use the plugin +#define ENVIRONMENTAL_MEASUREMENT_APP_ENABLED true // DISABLED by default; set this to true if you want to use the plugin #define DHT_SENSOR_MINIMUM_WAIT_TIME_BETWEEN_READS 1000 #define SENSOR_READ_ERROR_COUNT_THRESHOLD 5 #define SENSOR_READ_MULTIPLIER 3 @@ -26,6 +28,24 @@ uint32_t sensor_read_error_count = 0; DHT dht(DHT_11_GPIO_PIN,DHT11); + +#ifdef HAS_EINK +// The screen is bigger so use bigger fonts +#define FONT_SMALL ArialMT_Plain_16 +#define FONT_MEDIUM ArialMT_Plain_24 +#define FONT_LARGE ArialMT_Plain_24 +#else +#define FONT_SMALL ArialMT_Plain_10 +#define FONT_MEDIUM ArialMT_Plain_16 +#define FONT_LARGE ArialMT_Plain_24 +#endif + +#define fontHeight(font) ((font)[1] + 1) // height is position 1 + +#define FONT_HEIGHT_SMALL fontHeight(FONT_SMALL) +#define FONT_HEIGHT_MEDIUM fontHeight(FONT_MEDIUM) + + int32_t EnvironmentalMeasurementPlugin::runOnce() { #ifndef NO_ESP32 if (!ENVIRONMENTAL_MEASUREMENT_APP_ENABLED){ @@ -70,6 +90,28 @@ int32_t EnvironmentalMeasurementPlugin::runOnce() { #endif } +void EnvironmentalMeasurementPluginRadio::drawFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y) +{ + display->setTextAlignment(TEXT_ALIGN_LEFT); + display->setFont(FONT_MEDIUM); + display->drawString(x, y, "Environment"); + display->setFont(FONT_SMALL); + display->drawString(x, y += fontHeight(FONT_MEDIUM), lastSender+": T:"+ String(lastMeasurement.temperature,2) + " H:" + String(lastMeasurement.relative_humidity,2)); + +} + +String GetSenderName(const MeshPacket &mp) { + String sender; + + if (nodeDB.getNode(mp.from)){ + sender = nodeDB.getNode(mp.from)->user.short_name; + } + else { + sender = "UNK"; + } + return sender; +} + bool EnvironmentalMeasurementPluginRadio::handleReceivedProtobuf(const MeshPacket &mp, const EnvironmentalMeasurement &p) { if (!ENVIRONMENTAL_MEASUREMENT_APP_ENABLED){ @@ -77,26 +119,24 @@ bool EnvironmentalMeasurementPluginRadio::handleReceivedProtobuf(const MeshPacke return false; } bool wasBroadcast = mp.to == NODENUM_BROADCAST; - String sender; + + String sender = GetSenderName(mp); - if (nodeDB.getNode(mp.from)){ - sender = nodeDB.getNode(mp.from)->user.short_name; - } - else { - sender = "UNK"; - } // Show new nodes on LCD screen if (DISPLAY_RECEIVEID_MEASUREMENTS_ON_SCREEN && wasBroadcast) { - String lcd = String("Env Measured: ") + sender + "\n" + + String lcd = String("Env Measured: ") +sender + "\n" + "T: " + p.temperature + "\n" + "H: " + p.relative_humidity + "\n"; screen->print(lcd.c_str()); } DEBUG_MSG("-----------------------------------------\n"); - DEBUG_MSG("EnvironmentalMeasurement: Received data from %s\n",sender); + DEBUG_MSG("EnvironmentalMeasurement: Received data from %s\n", sender); DEBUG_MSG("EnvironmentalMeasurement->relative_humidity: %f\n", p.relative_humidity); DEBUG_MSG("EnvironmentalMeasurement->temperature: %f\n", p.temperature); + + lastMeasurement = p; + lastSender = sender; return false; // Let others look at this message also if they want } diff --git a/src/plugins/esp32/EnvironmentalMeasurementPlugin.h b/src/plugins/esp32/EnvironmentalMeasurementPlugin.h index 31581b31b..8e9d968ba 100644 --- a/src/plugins/esp32/EnvironmentalMeasurementPlugin.h +++ b/src/plugins/esp32/EnvironmentalMeasurementPlugin.h @@ -1,6 +1,8 @@ #pragma once #include "ProtobufPlugin.h" #include "../mesh/generated/environmental_measurement.pb.h" +#include +#include class EnvironmentalMeasurementPlugin : private concurrency::OSThread @@ -31,6 +33,8 @@ class EnvironmentalMeasurementPluginRadio : public ProtobufPlugin Date: Sun, 21 Feb 2021 16:49:35 -0500 Subject: [PATCH 145/258] fix typo --- src/plugins/esp32/EnvironmentalMeasurementPlugin.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/esp32/EnvironmentalMeasurementPlugin.cpp b/src/plugins/esp32/EnvironmentalMeasurementPlugin.cpp index 1d8ecfab7..6d8938fe8 100644 --- a/src/plugins/esp32/EnvironmentalMeasurementPlugin.cpp +++ b/src/plugins/esp32/EnvironmentalMeasurementPlugin.cpp @@ -71,7 +71,7 @@ int32_t EnvironmentalMeasurementPlugin::runOnce() { // so just do what we intend to do on the interval if(sensor_read_error_count > SENSOR_READ_ERROR_COUNT_THRESHOLD) { - DEBUG_MSG("EEnvironmentalMeasurement: DISABLED; The SENSOR_READ_ERROR_COUNT_THRESHOLD has been exceed: %d\n",SENSOR_READ_ERROR_COUNT_THRESHOLD); + DEBUG_MSG("EnvironmentalMeasurement: DISABLED; The SENSOR_READ_ERROR_COUNT_THRESHOLD has been exceed: %d\n",SENSOR_READ_ERROR_COUNT_THRESHOLD); return(FAILED_STATE_SENSOR_READ_MULTIPLIER * DHT_SENSOR_MINIMUM_WAIT_TIME_BETWEEN_READS); } else if (sensor_read_error_count > 0){ From 008187caa4776b84be403b09029951405c22d02b Mon Sep 17 00:00:00 2001 From: Kevin Hester Date: Mon, 22 Feb 2021 10:26:11 +0800 Subject: [PATCH 146/258] 1.2 wip - psk work --- docs/software/TODO.md | 6 +++--- proto | 2 +- src/mesh/Channels.cpp | 15 ++++++++++----- src/mesh/Channels.h | 29 +++++++++++++++++++++++++++++ src/mesh/generated/deviceonly.pb.h | 2 +- src/mesh/generated/mesh.pb.h | 26 +++++++++++++------------- src/mesh/generated/portnums.pb.h | 7 ++++--- 7 files changed, 61 insertions(+), 26 deletions(-) diff --git a/docs/software/TODO.md b/docs/software/TODO.md index 1c6714e84..c4769c2ef 100644 --- a/docs/software/TODO.md +++ b/docs/software/TODO.md @@ -6,19 +6,19 @@ You probably don't care about this section - skip to the next one. * DONE call RouterPlugin for *all* packets - not just Router packets * generate channel hash from the name of the channel+the psk (not just one or the other) +* send a hint that can be used to select which channel to try and hash against with each message * DONE remove deprecated * DONE fix setchannel in phoneapi.cpp * DONE set mynodeinfo.max_channels * DONE set mynodeinfo.num_bands (formerly num_channels) * DONE fix sniffing of non Routing packets -* enable remote setttings access by moving settings operations into a regular plugin (move settings ops out of PhoneAPI) +* DONE enable remote setttings access by moving settings operations into a regular plugin (move settings ops out of PhoneAPI) * DONE move portnum up? * DONE remove region specific builds from the firmware * restrict settings operations to the admin channel * add gui in android app for setting region * "FIXME - move the radioconfig/user/channel READ operations into SettingsMessage as well" -* scrub protobufs to make sure they are absoloute minimum wiresize (in particular packets, ChannelSets and positions) -* send a hint that can be used to select which channel to try and hash against with each message +* DONE scrub protobufs to make sure they are absoloute minimum wiresize (in particular Data, ChannelSets and positions) * change syncword * allow chaning packets in single transmission - to increase airtime efficiency and amortize packet overhead * DONE move most parts of meshpacket into the Data packet, so that we can chain multiple Data for sending when they all have a common destination and key. diff --git a/proto b/proto index 649c3deb7..7db1c2edb 160000 --- a/proto +++ b/proto @@ -1 +1 @@ -Subproject commit 649c3deb71d1780416fac5db33ad3c957c0278b6 +Subproject commit 7db1c2edb2e62e90b1f297be2f11aff0df35330a diff --git a/src/mesh/Channels.cpp b/src/mesh/Channels.cpp index 510510ca3..dc1383bdf 100644 --- a/src/mesh/Channels.cpp +++ b/src/mesh/Channels.cpp @@ -74,18 +74,23 @@ void initDefaultChannel(size_t chIndex) /** Given a channel index, change to use the crypto key specified by that index */ -void setCrypto(size_t chIndex) +void Channels::setCrypto(size_t chIndex) { - assert(chIndex < devicestate.channels_count); Channel *ch = devicestate.channels + chIndex; ChannelSettings &channelSettings = ch->settings; + assert(ch->has_settings); memset(activePSK, 0, sizeof(activePSK)); // In case the user provided a short key, we want to pad the rest with zeros memcpy(activePSK, channelSettings.psk.bytes, channelSettings.psk.size); activePSKSize = channelSettings.psk.size; - if (activePSKSize == 0) - DEBUG_MSG("Warning: User disabled encryption\n"); + if (activePSKSize == 0) { + if(ch->role == Channel_Role_SECONDARY) { + DEBUG_MSG("Unset PSK for secondary channel %s. using primary key\n", ch->settings.name); + setCrypto(primaryIndex); + } else + DEBUG_MSG("Warning: User disabled encryption\n"); + } else if (activePSKSize == 1) { // Convert the short single byte variants of psk into variant that can be used more generally @@ -134,7 +139,7 @@ void Channels::onConfigChanged() primaryIndex = i; } - setCrypto(0); // FIXME: for the time being (still single channel - just use our only channel as the crypto key) + setCrypto(primaryIndex); // FIXME: for the time being (still single channel - just use our only channel as the crypto key) } Channel &Channels::getChannel(size_t chIndex) diff --git a/src/mesh/Channels.h b/src/mesh/Channels.h index 5654fb1f2..ec64cd49b 100644 --- a/src/mesh/Channels.h +++ b/src/mesh/Channels.h @@ -45,6 +45,35 @@ their nodes /// called when the user has just changed our radio config and we might need to change channel keys void onConfigChanged(); + + /** Given a channel hash setup crypto for decoding that channel (or the primary channel if that channel is unsecured) + * + * This method is called before decoding inbound packets + * + * @return false if no suitable channel could be found. + */ + bool setCryptoByHash(uint8_t channelHash); + + /** Given a channel index setup crypto for encoding that channel (or the primary channel if that channel is unsecured) + * + * This method is called before encoding inbound packets + * + * @eturn the (0 to 255) hash for that channel - if no suitable channel could be found, return -1 + */ + int16_t setCryptoByIndex(uint8_t channelIndex); + +private: + /** Given a channel index, change to use the crypto key specified by that index + */ + void setCrypto(size_t chIndex); + + /** Return the channel index for the specified channel hash, or -1 for not found */ + int8_t getChannelIndexByHash(uint8_t channelHash); + + /** Given a channel number, return the (0 to 255) hash for that channel + * If no suitable channel could be found, return -1 + */ + int16_t getChannelHash(size_t channelNum); }; /// Singleton channel table diff --git a/src/mesh/generated/deviceonly.pb.h b/src/mesh/generated/deviceonly.pb.h index 47ffe2ae3..b8c372664 100644 --- a/src/mesh/generated/deviceonly.pb.h +++ b/src/mesh/generated/deviceonly.pb.h @@ -80,7 +80,7 @@ extern const pb_msgdesc_t DeviceState_msg; #define DeviceState_fields &DeviceState_msg /* Maximum encoded size of messages (where known) */ -#define DeviceState_size 6225 +#define DeviceState_size 6119 #ifdef __cplusplus } /* extern "C" */ diff --git a/src/mesh/generated/mesh.pb.h b/src/mesh/generated/mesh.pb.h index d29f6c86b..873e0aa2f 100644 --- a/src/mesh/generated/mesh.pb.h +++ b/src/mesh/generated/mesh.pb.h @@ -119,20 +119,20 @@ typedef enum _LogRecord_Level { /* Struct definitions */ typedef PB_BYTES_ARRAY_T(32) ChannelSettings_psk_t; typedef struct _ChannelSettings { - int32_t tx_power; + int8_t tx_power; ChannelSettings_ModemConfig modem_config; ChannelSettings_psk_t psk; char name[12]; - uint32_t bandwidth; + uint16_t bandwidth; uint32_t spread_factor; - uint32_t coding_rate; - uint32_t channel_num; + uint8_t coding_rate; + uint8_t channel_num; uint32_t id; bool uplink_enabled; bool downlink_enabled; } ChannelSettings; -typedef PB_BYTES_ARRAY_T(240) Data_payload_t; +typedef PB_BYTES_ARRAY_T(237) Data_payload_t; typedef struct _Data { PortNum portnum; Data_payload_t payload; @@ -230,7 +230,7 @@ typedef struct _User { } User; typedef struct _Channel { - uint32_t index; + uint8_t index; bool has_settings; ChannelSettings settings; Channel_Role role; @@ -240,7 +240,7 @@ typedef PB_BYTES_ARRAY_T(256) MeshPacket_encrypted_t; typedef struct _MeshPacket { uint32_t from; uint32_t to; - uint32_t channel_index; + uint8_t channel_index; pb_size_t which_payloadVariant; union { Data decoded; @@ -249,7 +249,7 @@ typedef struct _MeshPacket { uint32_t id; uint32_t rx_time; float rx_snr; - uint32_t hop_limit; + uint8_t hop_limit; bool want_ack; MeshPacket_Priority priority; } MeshPacket; @@ -770,17 +770,17 @@ extern const pb_msgdesc_t AdminMessage_msg; #define User_size 72 #define RouteDiscovery_size 40 #define Routing_size 47 -#define Data_size 258 -#define MeshPacket_size 302 -#define ChannelSettings_size 95 -#define Channel_size 105 +#define Data_size 255 +#define MeshPacket_size 294 +#define ChannelSettings_size 87 +#define Channel_size 94 #define RadioConfig_size 308 #define RadioConfig_UserPreferences_size 305 #define NodeInfo_size 130 #define MyNodeInfo_size 89 #define LogRecord_size 81 #define FromRadio_size 317 -#define ToRadio_size 305 +#define ToRadio_size 297 #define AdminMessage_size 311 #ifdef __cplusplus diff --git a/src/mesh/generated/portnums.pb.h b/src/mesh/generated/portnums.pb.h index 3ddd806ea..4e9203db1 100644 --- a/src/mesh/generated/portnums.pb.h +++ b/src/mesh/generated/portnums.pb.h @@ -24,13 +24,14 @@ typedef enum _PortNum { PortNum_STORE_FORWARD_APP = 65, PortNum_RANGE_TEST_APP = 66, PortNum_PRIVATE_APP = 256, - PortNum_ATAK_FORWARDER = 257 + PortNum_ATAK_FORWARDER = 257, + PortNum_MAX = 511 } PortNum; /* Helper constants for enums */ #define _PortNum_MIN PortNum_UNKNOWN_APP -#define _PortNum_MAX PortNum_ATAK_FORWARDER -#define _PortNum_ARRAYSIZE ((PortNum)(PortNum_ATAK_FORWARDER+1)) +#define _PortNum_MAX PortNum_MAX +#define _PortNum_ARRAYSIZE ((PortNum)(PortNum_MAX+1)) #ifdef __cplusplus From d4781280b752dfc24b017c0515559ffe422a3876 Mon Sep 17 00:00:00 2001 From: Kevin Hester Date: Mon, 22 Feb 2021 10:29:27 +0800 Subject: [PATCH 147/258] update protos --- proto | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/proto b/proto index 7db1c2edb..4396b3689 160000 --- a/proto +++ b/proto @@ -1 +1 @@ -Subproject commit 7db1c2edb2e62e90b1f297be2f11aff0df35330a +Subproject commit 4396b3689719ac292f9628752b5b1c78288ab2e7 From d6c2e9063ada43c34c9634406c1d3e3380b063a3 Mon Sep 17 00:00:00 2001 From: Kevin Hester Date: Mon, 22 Feb 2021 11:16:38 +0800 Subject: [PATCH 148/258] 1.2 channel cleanup --- docs/software/TODO.md | 1 + proto | 2 +- src/mesh/Channels.cpp | 70 +++++++++++------------- src/mesh/Channels.h | 94 ++++++++++++++++++++------------ src/mesh/generated/portnums.pb.h | 2 +- 5 files changed, 94 insertions(+), 75 deletions(-) diff --git a/docs/software/TODO.md b/docs/software/TODO.md index c4769c2ef..b30b58795 100644 --- a/docs/software/TODO.md +++ b/docs/software/TODO.md @@ -17,6 +17,7 @@ You probably don't care about this section - skip to the next one. * DONE remove region specific builds from the firmware * restrict settings operations to the admin channel * add gui in android app for setting region +* make an alpha channel for the python API * "FIXME - move the radioconfig/user/channel READ operations into SettingsMessage as well" * DONE scrub protobufs to make sure they are absoloute minimum wiresize (in particular Data, ChannelSets and positions) * change syncword diff --git a/proto b/proto index 4396b3689..6421b29ef 160000 --- a/proto +++ b/proto @@ -1 +1 @@ -Subproject commit 4396b3689719ac292f9628752b5b1c78288ab2e7 +Subproject commit 6421b29ef45dbd34d7c6c43f4be48a7906e66ad9 diff --git a/src/mesh/Channels.cpp b/src/mesh/Channels.cpp index dc1383bdf..8b5d5cb6b 100644 --- a/src/mesh/Channels.cpp +++ b/src/mesh/Channels.cpp @@ -1,13 +1,9 @@ #include "Channels.h" -#include "NodeDB.h" #include "CryptoEngine.h" +#include "NodeDB.h" #include -/// A usable psk - which has been constructed based on the (possibly short psk) in channelSettings -static uint8_t activePSK[32]; -static uint8_t activePSKSize; - /// 16 bytes of random PSK for our _public_ default channel that all devices power up on (AES128) static const uint8_t defaultpsk[] = {0xd4, 0xf1, 0xbb, 0x3a, 0x20, 0x29, 0x07, 0x59, 0xf0, 0xbc, 0xff, 0xab, 0xcf, 0x4e, 0x69, 0xbf}; @@ -17,19 +13,19 @@ Channels channels; /** * Validate a channel, fixing any errors as needed */ -Channel &fixupChannel(size_t chIndex) +Channel &Channels::fixupChannel(ChannelIndex chIndex) { - assert(chIndex < devicestate.channels_count); + auto ch = getByIndex(chIndex); - Channel *ch = devicestate.channels + chIndex; + ch.index = chIndex; // Preinit the index so it be ready to share with the phone (we'll never change it later) - ch->index = chIndex; // Preinit the index so it be ready to share with the phone (we'll never change it later) - - if (!ch->has_settings) { + if (!ch.has_settings) { // No settings! Must disable and skip - ch->role = Channel_Role_DISABLED; + ch.role = Channel_Role_DISABLED; + memset(&ch.settings, 0, sizeof(ch.settings)); + ch.has_settings = true; } else { - ChannelSettings &channelSettings = ch->settings; + ChannelSettings &channelSettings = ch.settings; // Convert the old string "Default" to our new short representation if (strcmp(channelSettings.name, "Default") == 0) @@ -43,19 +39,16 @@ Channel &fixupChannel(size_t chIndex) } } - return *ch; + return ch; } - - /** * Write a default channel to the specified channel index */ -void initDefaultChannel(size_t chIndex) +void Channels::initDefaultChannel(ChannelIndex chIndex) { - assert(chIndex < devicestate.channels_count); - Channel *ch = devicestate.channels + chIndex; - ChannelSettings &channelSettings = ch->settings; + auto ch = getByIndex(chIndex); + ChannelSettings &channelSettings = ch.settings; // radioConfig.modem_config = RadioConfig_ModemConfig_Bw125Cr45Sf128; // medium range and fast // channelSettings.modem_config = ChannelSettings_ModemConfig_Bw500Cr45Sf128; // short range and fast, but wide @@ -68,30 +61,28 @@ void initDefaultChannel(size_t chIndex) channelSettings.psk.size = 1; strcpy(channelSettings.name, ""); - ch->has_settings = true; - ch->role = Channel_Role_PRIMARY; + ch.has_settings = true; + ch.role = Channel_Role_PRIMARY; } /** Given a channel index, change to use the crypto key specified by that index */ -void Channels::setCrypto(size_t chIndex) +void Channels::setCrypto(ChannelIndex chIndex) { - assert(chIndex < devicestate.channels_count); - Channel *ch = devicestate.channels + chIndex; - ChannelSettings &channelSettings = ch->settings; - assert(ch->has_settings); + auto ch = getByIndex(chIndex); + ChannelSettings &channelSettings = ch.settings; + assert(ch.has_settings); memset(activePSK, 0, sizeof(activePSK)); // In case the user provided a short key, we want to pad the rest with zeros memcpy(activePSK, channelSettings.psk.bytes, channelSettings.psk.size); activePSKSize = channelSettings.psk.size; if (activePSKSize == 0) { - if(ch->role == Channel_Role_SECONDARY) { - DEBUG_MSG("Unset PSK for secondary channel %s. using primary key\n", ch->settings.name); + if (ch.role == Channel_Role_SECONDARY) { + DEBUG_MSG("Unset PSK for secondary channel %s. using primary key\n", ch.settings.name); setCrypto(primaryIndex); } else DEBUG_MSG("Warning: User disabled encryption\n"); - } - else if (activePSKSize == 1) { + } else if (activePSKSize == 1) { // Convert the short single byte variants of psk into variant that can be used more generally uint8_t pskIndex = activePSK[0]; @@ -135,27 +126,28 @@ void Channels::onConfigChanged() for (int i = 0; i < devicestate.channels_count; i++) { auto ch = fixupChannel(i); - if(ch.role == Channel_Role_PRIMARY) + if (ch.role == Channel_Role_PRIMARY) primaryIndex = i; } setCrypto(primaryIndex); // FIXME: for the time being (still single channel - just use our only channel as the crypto key) } -Channel &Channels::getChannel(size_t chIndex) +Channel &Channels::getByIndex(ChannelIndex chIndex) { assert(chIndex < devicestate.channels_count); Channel *ch = devicestate.channels + chIndex; return *ch; } -void Channels::setChannel(const Channel &c) { - Channel &old = getChannel(c.index); +void Channels::setChannel(const Channel &c) +{ + Channel &old = getByIndex(c.index); // if this is the new primary, demote any existing roles - if(c.role == Channel_Role_PRIMARY) - for (int i = 0; i < devicestate.channels_count; i++) - if(devicestate.channels[i].role == Channel_Role_PRIMARY) + if (c.role == Channel_Role_PRIMARY) + for (int i = 0; i < devicestate.channels_count; i++) + if (devicestate.channels[i].role == Channel_Role_PRIMARY) devicestate.channels[i].role = Channel_Role_SECONDARY; old = c; // slam in the new settings/role @@ -164,7 +156,7 @@ void Channels::setChannel(const Channel &c) { const char *Channels::getName(size_t chIndex) { // Convert the short "" representation for Default into a usable string - ChannelSettings &channelSettings = getChannel(chIndex).settings; + ChannelSettings &channelSettings = getByIndex(chIndex).settings; const char *channelName = channelSettings.name; if (!*channelName) { // emptystring // Per mesh.proto spec, if bandwidth is specified we must ignore modemConfig enum, we assume that in that case diff --git a/src/mesh/Channels.h b/src/mesh/Channels.h index ec64cd49b..913c316dc 100644 --- a/src/mesh/Channels.h +++ b/src/mesh/Channels.h @@ -3,41 +3,57 @@ #include "mesh-pb-constants.h" #include +typedef uint8_t ChannelIndex; +typedef uint8_t ChannelHash; + +/** The container/on device API for working with channels */ class Channels { - size_t primaryIndex = 0; - + /// The index of the primary channel + ChannelIndex primaryIndex = 0; + + /** The channel index that was requested for sending/receving. Note: if this channel is a secondary + channel and does not have a PSK, we will use the PSK from the primary channel. If this channel is disabled + no sending or receiving will be allowed */ + ChannelIndex activeChannelIndex = 0; + + /// The in-use psk - which has been constructed based on the (possibly short psk) in channelSettings + uint8_t activePSK[32]; + uint8_t activePSKSize = 0; + public: - const ChannelSettings &getPrimary() { return getChannel(getPrimaryIndex()).settings; } + const ChannelSettings &getPrimary() { return getByIndex(getPrimaryIndex()).settings; } - Channel &getChannel(size_t chIndex); + /** Return the Channel for a specified index */ + Channel &getByIndex(ChannelIndex chIndex); - /** Using the index inside the channel, update the specified channel's settings and role. If this channel is being promoted to be - * primary, force all other channels to be secondary. + /** Using the index inside the channel, update the specified channel's settings and role. If this channel is being promoted + * to be primary, force all other channels to be secondary. */ void setChannel(const Channel &c); const char *getName(size_t chIndex); /** The index of the primary channel */ - size_t getPrimaryIndex() const { return primaryIndex; } + ChannelIndex getPrimaryIndex() const { return primaryIndex; } /** - * Generate a short suffix used to disambiguate channels that might have the same "name" entered by the human but different PSKs. - * The ideas is that the PSK changing should be visible to the user so that they see they probably messed up and that's why they -their nodes - * aren't talking to each other. - * - * This string is of the form "#name-X". - * - * Where X is either: - * (for custom PSKS) a letter from A to Z (base26), and formed by xoring all the bytes of the PSK together, - * OR (for the standard minimially secure PSKs) a number from 0 to 9. - * - * This function will also need to be implemented in GUI apps that talk to the radio. - * - * https://github.com/meshtastic/Meshtastic-device/issues/269 - */ + * Generate a short suffix used to disambiguate channels that might have the same "name" entered by the human but different + PSKs. + * The ideas is that the PSK changing should be visible to the user so that they see they probably messed up and that's why + they their nodes + * aren't talking to each other. + * + * This string is of the form "#name-X". + * + * Where X is either: + * (for custom PSKS) a letter from A to Z (base26), and formed by xoring all the bytes of the PSK together, + * OR (for the standard minimially secure PSKs) a number from 0 to 9. + * + * This function will also need to be implemented in GUI apps that talk to the radio. + * + * https://github.com/meshtastic/Meshtastic-device/issues/269 + */ const char *getPrimaryName(); /// Called by NodeDB on initial boot when the radio config settings are unset. Set a default single channel config. @@ -47,33 +63,43 @@ their nodes void onConfigChanged(); /** Given a channel hash setup crypto for decoding that channel (or the primary channel if that channel is unsecured) - * + * * This method is called before decoding inbound packets - * + * * @return false if no suitable channel could be found. */ - bool setCryptoByHash(uint8_t channelHash); + bool setActiveByHash(ChannelHash channelHash); /** Given a channel index setup crypto for encoding that channel (or the primary channel if that channel is unsecured) - * + * * This method is called before encoding inbound packets - * + * * @eturn the (0 to 255) hash for that channel - if no suitable channel could be found, return -1 */ - int16_t setCryptoByIndex(uint8_t channelIndex); + int16_t setActiveByIndex(ChannelIndex channelIndex); -private: + private: /** Given a channel index, change to use the crypto key specified by that index */ - void setCrypto(size_t chIndex); + void setCrypto(ChannelIndex chIndex); /** Return the channel index for the specified channel hash, or -1 for not found */ - int8_t getChannelIndexByHash(uint8_t channelHash); + int8_t getIndexByHash(ChannelHash channelHash); - /** Given a channel number, return the (0 to 255) hash for that channel + /** Given a channel number, return the (0 to 255) hash for that channel * If no suitable channel could be found, return -1 - */ - int16_t getChannelHash(size_t channelNum); + */ + int16_t getHash(ChannelIndex channelNum); + + /** + * Validate a channel, fixing any errors as needed + */ + Channel &fixupChannel(ChannelIndex chIndex); + + /** + * Write a default channel to the specified channel index + */ + void initDefaultChannel(ChannelIndex chIndex); }; /// Singleton channel table diff --git a/src/mesh/generated/portnums.pb.h b/src/mesh/generated/portnums.pb.h index 758db47a6..5904a548c 100644 --- a/src/mesh/generated/portnums.pb.h +++ b/src/mesh/generated/portnums.pb.h @@ -20,10 +20,10 @@ typedef enum _PortNum { PortNum_ADMIN_APP = 6, PortNum_REPLY_APP = 32, PortNum_IP_TUNNEL_APP = 33, - PortNum_ENVIRONMENTAL_MEASUREMENT_APP = 34, PortNum_SERIAL_APP = 64, PortNum_STORE_FORWARD_APP = 65, PortNum_RANGE_TEST_APP = 66, + PortNum_ENVIRONMENTAL_MEASUREMENT_APP = 67, PortNum_PRIVATE_APP = 256, PortNum_ATAK_FORWARDER = 257, PortNum_MAX = 511 From d5cb7ebf3bf0aec104cc78107dfbc8e89ded9d57 Mon Sep 17 00:00:00 2001 From: Jm Casler Date: Sun, 21 Feb 2021 20:15:31 -0800 Subject: [PATCH 149/258] check in partial work. --- src/plugins/StoreForwardPlugin.cpp | 63 +++++++++++++++++++++++------- src/plugins/StoreForwardPlugin.h | 9 ++++- 2 files changed, 57 insertions(+), 15 deletions(-) diff --git a/src/plugins/StoreForwardPlugin.cpp b/src/plugins/StoreForwardPlugin.cpp index 1396afd0f..213189cd0 100644 --- a/src/plugins/StoreForwardPlugin.cpp +++ b/src/plugins/StoreForwardPlugin.cpp @@ -8,6 +8,8 @@ #include #include +#define STOREFORWARD_MAX_PACKETS 6000 + StoreForwardPlugin *storeForwardPlugin; StoreForwardPluginRadio *storeForwardPluginRadio; @@ -37,16 +39,37 @@ int32_t StoreForwardPlugin::runOnce() DEBUG_MSG("Initializing Store & Forward Plugin - Enabled\n"); // Router if (ESP.getPsramSize()) { - if (ESP.getFreePsram() >= 1024 * 1024) { + if (ESP.getFreePsram() >= 2048 * 1024) { // Do the startup here storeForwardPluginRadio = new StoreForwardPluginRadio(); firstTime = 0; + /* + For PSRAM usage, see: + https://learn.upesy.com/en/programmation/psram.html#psram-tab + */ + + DEBUG_MSG("Total heap: %d\n", ESP.getHeapSize()); + DEBUG_MSG("Free heap: %d\n", ESP.getFreeHeap()); + DEBUG_MSG("Total PSRAM: %d\n", ESP.getPsramSize()); + DEBUG_MSG("Free PSRAM: %d\n", ESP.getFreePsram()); + + PacketHistoryStruct *packetHistory = + (PacketHistoryStruct *)ps_calloc(STOREFORWARD_MAX_PACKETS, sizeof(PacketHistoryStruct)); + + DEBUG_MSG("Total heap: %d\n", ESP.getHeapSize()); + DEBUG_MSG("Free heap: %d\n", ESP.getFreeHeap()); + DEBUG_MSG("Total PSRAM: %d\n", ESP.getPsramSize()); + DEBUG_MSG("Free PSRAM: %d\n", ESP.getFreePsram()); + + DEBUG_MSG("packetHistory Size - %u", sizeof(packetHistory)); + + // packetHistory[0].bytes; return (10 * 1000); } else { - DEBUG_MSG("Device has less than 1M of PSRAM free. Aborting startup.\n"); + DEBUG_MSG("Device has less than 2M of PSRAM free. Aborting startup.\n"); DEBUG_MSG("Store & Forward Plugin - Aborting Startup.\n"); return (INT32_MAX); @@ -101,10 +124,10 @@ uint32_t StoreForwardPlugin::sawNode(uint32_t node) DEBUG_MSG("looking for node - %u\n", node); for (int i = 0; i < 50; i++) { - //DEBUG_MSG("Iterating through the seen nodes - %u %u %u\n", i, receivedRecord[i][0], receivedRecord[i][1]); + // DEBUG_MSG("Iterating through the seen nodes - %u %u %u\n", i, receivedRecord[i][0], receivedRecord[i][1]); // First time seeing that node. if (receivedRecord[i][0] == 0) { - //DEBUG_MSG("New node! Woohoo! Win!\n"); + // DEBUG_MSG("New node! Woohoo! Win!\n"); receivedRecord[i][0] = node; receivedRecord[i][1] = millis(); @@ -113,7 +136,7 @@ uint32_t StoreForwardPlugin::sawNode(uint32_t node) // We've seen this node before. if (receivedRecord[i][0] == node) { - //DEBUG_MSG("We've seen this node before\n"); + // DEBUG_MSG("We've seen this node before\n"); uint32_t lastSaw = receivedRecord[i][1]; receivedRecord[i][1] = millis(); return lastSaw; @@ -123,6 +146,24 @@ uint32_t StoreForwardPlugin::sawNode(uint32_t node) return 0; } +void StoreForwardPlugin::addHistory(const MeshPacket &mp) +{ + auto &p = mp; + + static uint8_t bytes[MAX_RHPACKETLEN]; + size_t numbytes = pb_encode_to_bytes(bytes, sizeof(bytes), SubPacket_fields, &p.decoded); + assert(numbytes <= MAX_RHPACKETLEN); + + DEBUG_MSG("MP numbytes %u\n", numbytes); + + // destination, source, bytes + // memcpy(p->encrypted.bytes, bytes, numbytes); + + // pb_decode_from_bytes + + // Serialization is in Router.cpp line 180 +} + // We saw a node. void StoreForwardPlugin::sawNodeReport() { @@ -165,7 +206,6 @@ bool StoreForwardPluginRadio::handleReceived(const MeshPacket &mp) { #ifndef NO_ESP32 if (radioConfig.preferences.store_forward_plugin_enabled) { - auto &p = mp; if (mp.from != nodeDB.getNodeNum()) { // DEBUG_MSG("Store & Forward Plugin -- Print Start ---------- ---------- ---------- ---------- ----------\n\n\n"); @@ -177,6 +217,9 @@ bool StoreForwardPluginRadio::handleReceived(const MeshPacket &mp) DEBUG_MSG("Packet came from - PortNum_UNKNOWN_APP\n"); } else if (mp.decoded.data.portnum == PortNum_TEXT_MESSAGE_APP) { DEBUG_MSG("Packet came from - PortNum_TEXT_MESSAGE_APP\n"); + + storeForwardPlugin->addHistory(&mp); + } else if (mp.decoded.data.portnum == PortNum_REMOTE_HARDWARE_APP) { DEBUG_MSG("Packet came from - PortNum_REMOTE_HARDWARE_APP\n"); } else if (mp.decoded.data.portnum == PortNum_POSITION_APP) { @@ -202,14 +245,6 @@ bool StoreForwardPluginRadio::handleReceived(const MeshPacket &mp) } else { DEBUG_MSG("Packet came from an unknown port %u\n", mp.decoded.data.portnum); } - - static uint8_t bytes[MAX_RHPACKETLEN]; - size_t numbytes = pb_encode_to_bytes(bytes, sizeof(bytes), SubPacket_fields, &p.decoded); - assert(numbytes <= MAX_RHPACKETLEN); - - DEBUG_MSG("MP numbytes %u\n", numbytes); - - // Serialization is in Router.cpp line 180 } } else { diff --git a/src/plugins/StoreForwardPlugin.h b/src/plugins/StoreForwardPlugin.h index 9380d2161..d7888333e 100644 --- a/src/plugins/StoreForwardPlugin.h +++ b/src/plugins/StoreForwardPlugin.h @@ -6,6 +6,12 @@ #include #include +struct PacketHistoryStruct { + uint32_t time; + uint32_t to; + uint8_t bytes[MAX_RHPACKETLEN]; +}; + class StoreForwardPlugin : private concurrency::OSThread { bool firstTime = 1; @@ -23,9 +29,10 @@ class StoreForwardPlugin : private concurrency::OSThread */ uint32_t sawNode(uint32_t); void sawNodeReport(); + void addHistory(const MeshPacket &mp) private: - // Nothing here + // Nothing here protected: virtual int32_t runOnce(); From 923ecc9d8a0e4d1ba0e65f909d39f421ddd2d4dc Mon Sep 17 00:00:00 2001 From: Kevin Hester Date: Mon, 22 Feb 2021 12:57:03 +0800 Subject: [PATCH 150/258] fix printf warnings --- platformio.ini | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/platformio.ini b/platformio.ini index 2ae37ea31..09ac280f6 100644 --- a/platformio.ini +++ b/platformio.ini @@ -34,7 +34,9 @@ extra_scripts = bin/platformio-custom.py ; note: we add src to our include search path so that lmic_project_config can override ; FIXME: fix lib/BluetoothOTA dependency back on src/ so we can remove -Isrc -build_flags = -Wno-missing-field-initializers -Isrc -Isrc/mesh -Isrc/gps -Ilib/nanopb/include -Wl,-Map,.pio/build/output.map +build_flags = -Wno-missing-field-initializers + -Wno-format + -Isrc -Isrc/mesh -Isrc/gps -Ilib/nanopb/include -Wl,-Map,.pio/build/output.map -DHW_VERSION_${sysenv.COUNTRY} -DHW_VERSION=${sysenv.HW_VERSION} -DUSE_THREAD_NAMES From 94cd96cfdea1cb2387c807e0fb8a4089b0ccabb0 Mon Sep 17 00:00:00 2001 From: Kevin Hester Date: Mon, 22 Feb 2021 12:57:26 +0800 Subject: [PATCH 151/258] begin multichannel hash impl --- proto | 2 +- src/mesh/Channels.cpp | 49 +++++++++++++---- src/mesh/Channels.h | 20 +++++-- src/mesh/MeshTypes.h | 2 + src/mesh/RadioInterface.cpp | 4 +- src/mesh/RadioInterface.h | 3 ++ src/mesh/RadioLibInterface.cpp | 1 + src/mesh/Router.cpp | 84 ++++++++++++++++++------------ src/mesh/Router.h | 3 ++ src/mesh/generated/deviceonly.pb.h | 2 +- src/mesh/generated/mesh.pb.h | 18 ++++--- 11 files changed, 129 insertions(+), 59 deletions(-) diff --git a/proto b/proto index 6421b29ef..f6ff4cc0c 160000 --- a/proto +++ b/proto @@ -1 +1 @@ -Subproject commit 6421b29ef45dbd34d7c6c43f4be48a7906e66ad9 +Subproject commit f6ff4cc0c98b201342c32776eeeb9ace83b450dd diff --git a/src/mesh/Channels.cpp b/src/mesh/Channels.cpp index 8b5d5cb6b..696f78f4f 100644 --- a/src/mesh/Channels.cpp +++ b/src/mesh/Channels.cpp @@ -10,12 +10,20 @@ static const uint8_t defaultpsk[] = {0xd4, 0xf1, 0xbb, 0x3a, 0x20, 0x29, 0x07, 0 Channels channels; +uint8_t xorHash(uint8_t *p, size_t len) +{ + uint8_t code = 0; + for (int i = 0; i < len; i++) + code ^= p[i]; + return code; +} + /** * Validate a channel, fixing any errors as needed */ Channel &Channels::fixupChannel(ChannelIndex chIndex) { - auto ch = getByIndex(chIndex); + Channel &ch = getByIndex(chIndex); ch.index = chIndex; // Preinit the index so it be ready to share with the phone (we'll never change it later) @@ -31,14 +39,16 @@ Channel &Channels::fixupChannel(ChannelIndex chIndex) if (strcmp(channelSettings.name, "Default") == 0) *channelSettings.name = '\0'; - // Convert any old usage of the defaultpsk into our new short representation. + /* Convert any old usage of the defaultpsk into our new short representation. if (channelSettings.psk.size == sizeof(defaultpsk) && memcmp(channelSettings.psk.bytes, defaultpsk, sizeof(defaultpsk)) == 0) { *channelSettings.psk.bytes = 1; channelSettings.psk.size = 1; - } + } */ } + hashes[chIndex] = generateHash(chIndex); + return ch; } @@ -47,7 +57,7 @@ Channel &Channels::fixupChannel(ChannelIndex chIndex) */ void Channels::initDefaultChannel(ChannelIndex chIndex) { - auto ch = getByIndex(chIndex); + Channel &ch = getByIndex(chIndex); ChannelSettings &channelSettings = ch.settings; // radioConfig.modem_config = RadioConfig_ModemConfig_Bw125Cr45Sf128; // medium range and fast @@ -69,7 +79,7 @@ void Channels::initDefaultChannel(ChannelIndex chIndex) */ void Channels::setCrypto(ChannelIndex chIndex) { - auto ch = getByIndex(chIndex); + Channel &ch = getByIndex(chIndex); ChannelSettings &channelSettings = ch.settings; assert(ch.has_settings); @@ -124,7 +134,7 @@ void Channels::onConfigChanged() { // Make sure the phone hasn't mucked anything up for (int i = 0; i < devicestate.channels_count; i++) { - auto ch = fixupChannel(i); + Channel &ch = fixupChannel(i); if (ch.role == Channel_Role_PRIMARY) primaryIndex = i; @@ -211,9 +221,7 @@ const char *Channels::getPrimaryName() auto channelSettings = getPrimary(); if (channelSettings.psk.size != 1) { // We have a standard PSK, so generate a letter based hash. - uint8_t code = 0; - for (int i = 0; i < activePSKSize; i++) - code ^= activePSK[i]; + uint8_t code = xorHash(activePSK, activePSKSize); suffix = 'A' + (code % 26); } else { @@ -222,4 +230,25 @@ const char *Channels::getPrimaryName() snprintf(buf, sizeof(buf), "#%s-%c", channelSettings.name, suffix); return buf; -} \ No newline at end of file +} + +/** Given a channel hash setup crypto for decoding that channel (or the primary channel if that channel is unsecured) + * + * This method is called before decoding inbound packets + * + * @return -1 if no suitable channel could be found, otherwise returns the channel index + */ +int16_t Channels::setActiveByHash(ChannelHash channelHash) {} + +/** Given a channel index setup crypto for encoding that channel (or the primary channel if that channel is unsecured) + * + * This method is called before encoding outbound packets + * + * @eturn the (0 to 255) hash for that channel - if no suitable channel could be found, return -1 + */ +int16_t Channels::setActiveByIndex(ChannelIndex channelIndex) {} + +/** Given a channel number, return the (0 to 255) hash for that channel + * If no suitable channel could be found, return -1 + */ +ChannelHash Channels::generateHash(ChannelIndex channelNum) {} \ No newline at end of file diff --git a/src/mesh/Channels.h b/src/mesh/Channels.h index 913c316dc..a86b7ff68 100644 --- a/src/mesh/Channels.h +++ b/src/mesh/Channels.h @@ -3,7 +3,13 @@ #include "mesh-pb-constants.h" #include +/** A channel number (index into the channel table) + */ typedef uint8_t ChannelIndex; + +/** A low quality hash of the channel PSK and the channel name. created by generateHash(chIndex) + * Used as a hint to limit which PSKs are considered for packet decoding. +*/ typedef uint8_t ChannelHash; /** The container/on device API for working with channels */ @@ -21,6 +27,9 @@ class Channels uint8_t activePSK[32]; uint8_t activePSKSize = 0; + /// the precomputed hashes for each of our channels + ChannelHash hashes[MAX_NUM_CHANNELS]; + public: const ChannelSettings &getPrimary() { return getByIndex(getPrimaryIndex()).settings; } @@ -66,18 +75,21 @@ class Channels * * This method is called before decoding inbound packets * - * @return false if no suitable channel could be found. + * @return -1 if no suitable channel could be found, otherwise returns the channel index */ - bool setActiveByHash(ChannelHash channelHash); + int16_t setActiveByHash(ChannelHash channelHash); /** Given a channel index setup crypto for encoding that channel (or the primary channel if that channel is unsecured) * - * This method is called before encoding inbound packets + * This method is called before encoding outbound packets * * @eturn the (0 to 255) hash for that channel - if no suitable channel could be found, return -1 */ int16_t setActiveByIndex(ChannelIndex channelIndex); + /** return the channel hash we are currently using for sending */ + ChannelHash getActiveHash(); + private: /** Given a channel index, change to use the crypto key specified by that index */ @@ -89,7 +101,7 @@ class Channels /** Given a channel number, return the (0 to 255) hash for that channel * If no suitable channel could be found, return -1 */ - int16_t getHash(ChannelIndex channelNum); + ChannelHash generateHash(ChannelIndex channelNum); /** * Validate a channel, fixing any errors as needed diff --git a/src/mesh/MeshTypes.h b/src/mesh/MeshTypes.h index 69e782b12..06f2bf480 100644 --- a/src/mesh/MeshTypes.h +++ b/src/mesh/MeshTypes.h @@ -14,6 +14,8 @@ typedef uint32_t PacketId; // A packet sequence number #define ERRNO_NO_INTERFACES 33 #define ERRNO_UNKNOWN 32 // pick something that doesn't conflict with RH_ROUTER_ERROR_UNABLE_TO_DELIVER #define ERRNO_DISABLED 34 // the itnerface is disabled +#define ERRNO_TOO_LARGE 35 +#define ERRNO_NO_CHANNEL 36 /** * the max number of hops a message can pass through, used as the default max for hop_limit in MeshPacket. diff --git a/src/mesh/RadioInterface.cpp b/src/mesh/RadioInterface.cpp index 08ac40d5d..93dd55e80 100644 --- a/src/mesh/RadioInterface.cpp +++ b/src/mesh/RadioInterface.cpp @@ -10,6 +10,7 @@ #include #include #include +#include "Channels.h" #define RDEF(name, freq, spacing, num_ch, power_limit) \ { \ @@ -157,7 +158,7 @@ void printPacket(const char *prefix, const MeshPacket *p) RadioInterface::RadioInterface() { - assert(sizeof(PacketHeader) == 4 || sizeof(PacketHeader) == 16); // make sure the compiler did what we expected + assert(sizeof(PacketHeader) == 16); // make sure the compiler did what we expected // Can't print strings this early - serial not setup yet // DEBUG_MSG("Set meshradio defaults name=%s\n", channelSettings.name); @@ -350,6 +351,7 @@ size_t RadioInterface::beginSending(MeshPacket *p) h->from = p->from; h->to = p->to; h->id = p->id; + h->channel = p->channel; assert(p->hop_limit <= HOP_MAX); h->flags = p->hop_limit | (p->want_ack ? PACKET_FLAGS_WANT_ACK_MASK : 0); diff --git a/src/mesh/RadioInterface.h b/src/mesh/RadioInterface.h index 5efad0ae4..9d19fa590 100644 --- a/src/mesh/RadioInterface.h +++ b/src/mesh/RadioInterface.h @@ -29,6 +29,9 @@ typedef struct { * The bottom three bits of flags are use to store hop_limit when sent over the wire. **/ uint8_t flags; + + /** The channel hash - used as a hint for the decoder to limit which channels we consider */ + uint8_t channel; } PacketHeader; /** diff --git a/src/mesh/RadioLibInterface.cpp b/src/mesh/RadioLibInterface.cpp index 63d7095c5..ab1728126 100644 --- a/src/mesh/RadioLibInterface.cpp +++ b/src/mesh/RadioLibInterface.cpp @@ -274,6 +274,7 @@ void RadioLibInterface::handleReceiveInterrupt() mp->from = h->from; mp->to = h->to; mp->id = h->id; + mp->channel = h->id; assert(HOP_MAX <= PACKET_FLAGS_HOP_MASK); // If hopmax changes, carefully check this code mp->hop_limit = h->flags & PACKET_FLAGS_HOP_MASK; mp->want_ack = !!(h->flags & PACKET_FLAGS_WANT_ACK_MASK); diff --git a/src/mesh/Router.cpp b/src/mesh/Router.cpp index 673fafefd..434bdde5d 100644 --- a/src/mesh/Router.cpp +++ b/src/mesh/Router.cpp @@ -1,9 +1,10 @@ #include "Router.h" +#include "Channels.h" #include "CryptoEngine.h" +#include "NodeDB.h" #include "RTC.h" #include "configuration.h" #include "mesh-pb-constants.h" -#include #include "plugins/RoutingPlugin.h" /** @@ -107,7 +108,12 @@ void Router::sendAckNak(Routing_Error err, NodeNum to, PacketId idFrom) routingPlugin->sendAckNak(err, to, idFrom); } - +void Router::abortSendAndNak(Routing_Error err, MeshPacket *p) +{ + DEBUG_MSG("Error=%d, returning NAK and dropping packet.\n", err); + sendAckNak(Routing_Error_NO_INTERFACE, p->from, p->id); + packetPool.release(p); +} ErrorCode Router::sendLocal(MeshPacket *p) { @@ -118,11 +124,7 @@ ErrorCode Router::sendLocal(MeshPacket *p) return ERRNO_OK; } else if (!iface) { // We must be sending to remote nodes also, fail if no interface found - - // ERROR! no radio found, report failure back to the client and drop the packet - DEBUG_MSG("Error: No interface, returning NAK and dropping packet.\n"); - sendAckNak(Routing_Error_NO_INTERFACE, p->from, p->id); - packetPool.release(p); + abortSendAndNak(Routing_Error_NO_INTERFACE, p); return ERRNO_NO_INTERFACES; } else { @@ -146,7 +148,8 @@ ErrorCode Router::send(MeshPacket *p) assert(p->to != nodeDB.getNodeNum()); // should have already been handled by sendLocal // PacketId nakId = p->decoded.which_ackVariant == SubPacket_fail_id_tag ? p->decoded.ackVariant.fail_id : 0; - // assert(!nakId); // I don't think we ever send 0hop naks over the wire (other than to the phone), test that assumption with assert + // assert(!nakId); // I don't think we ever send 0hop naks over the wire (other than to the phone), test that assumption with + // assert // Never set the want_ack flag on broadcast packets sent over the air. if (p->to == NODENUM_BROADCAST) @@ -163,7 +166,20 @@ ErrorCode Router::send(MeshPacket *p) size_t numbytes = pb_encode_to_bytes(bytes, sizeof(bytes), Data_fields, &p->decoded); - assert(numbytes <= MAX_RHPACKETLEN); + if (numbytes > MAX_RHPACKETLEN) { + abortSendAndNak(Routing_Error_TOO_LARGE, p); + return ERRNO_TOO_LARGE; + } + + auto hash = channels.setActiveByIndex(p->channel); + if (hash < 0) { + // No suitable channel could be found for sending + abortSendAndNak(Routing_Error_NO_CHANNEL, p); + return ERRNO_NO_CHANNEL; + } + + // Now that we are encrypting the packet channel should be the hash (no longer the index) + p->channel = hash; crypto->encrypt(p->from, p->id, numbytes, bytes); // Copy back into the packet and set the variant type @@ -173,23 +189,15 @@ ErrorCode Router::send(MeshPacket *p) } assert(iface); // This should have been detected already in sendLocal (or we just received a packet from outside) - // if (iface) { - // DEBUG_MSG("Sending packet via interface fr=0x%x,to=0x%x,id=%d\n", p->from, p->to, p->id); return iface->send(p); - /* } else { - DEBUG_MSG("Dropping packet - no interfaces - fr=0x%x,to=0x%x,id=%d\n", p->from, p->to, p->id); - packetPool.release(p); - return ERRNO_NO_INTERFACES; - } */ } /** Attempt to cancel a previously sent packet. Returns true if a packet was found we could cancel */ -bool Router::cancelSending(NodeNum from, PacketId id) { +bool Router::cancelSending(NodeNum from, PacketId id) +{ return iface ? iface->cancelSending(from, id) : false; } - - /** * Every (non duplicate) packet this node receives will be passed through this method. This allows subclasses to * update routing tables etc... based on what we overhear (even for messages not destined to our node) @@ -207,22 +215,30 @@ bool Router::perhapsDecode(MeshPacket *p) assert(p->which_payloadVariant == MeshPacket_encrypted_tag); - // FIXME - someday don't send routing packets encrypted. That would allow us to route for other channels without - // being able to decrypt their data. - // Try to decrypt the packet if we can - static uint8_t bytes[MAX_RHPACKETLEN]; - memcpy(bytes, p->encrypted.bytes, - p->encrypted.size); // we have to copy into a scratch buffer, because these bytes are a union with the decoded protobuf - crypto->decrypt(p->from, p->id, p->encrypted.size, bytes); - - // Take those raw bytes and convert them back into a well structured protobuf we can understand - if (!pb_decode_from_bytes(bytes, p->encrypted.size, Data_fields, &p->decoded)) { - DEBUG_MSG("Invalid protobufs in received mesh packet!\n"); + ChannelHash chHash = p->channel; + int16_t chIndex = channels.setActiveByHash(chHash); + if (chIndex < 0) { + DEBUG_MSG("No suitable channel found for decoding, hash was 0x%x!\n", chHash); return false; } else { - // parsing was successful - p->which_payloadVariant = MeshPacket_decoded_tag; - return true; + p->channel = chIndex; + + // Try to decrypt the packet if we can + static uint8_t bytes[MAX_RHPACKETLEN]; + memcpy(bytes, p->encrypted.bytes, + p->encrypted + .size); // we have to copy into a scratch buffer, because these bytes are a union with the decoded protobuf + crypto->decrypt(p->from, p->id, p->encrypted.size, bytes); + + // Take those raw bytes and convert them back into a well structured protobuf we can understand + if (!pb_decode_from_bytes(bytes, p->encrypted.size, Data_fields, &p->decoded)) { + DEBUG_MSG("Invalid protobufs in received mesh packet!\n"); + return false; + } else { + // parsing was successful + p->which_payloadVariant = MeshPacket_decoded_tag; + return true; + } } } @@ -244,7 +260,7 @@ void Router::handleReceived(MeshPacket *p) if (perhapsDecode(p)) { // parsing was successful, queue for our recipient - // call any promiscious plugins here, make a (non promisiocous) plugin for forwarding messages to phone api + // call any promiscious plugins here, make a (non promisiocous) plugin for forwarding messages to phone api // sniffReceived(p); MeshPlugin::callPlugins(*p); } diff --git a/src/mesh/Router.h b/src/mesh/Router.h index 4b1656936..6e6bf2c2a 100644 --- a/src/mesh/Router.h +++ b/src/mesh/Router.h @@ -123,6 +123,9 @@ class Router : protected concurrency::OSThread * Note: this method will free the provided packet. */ void handleReceived(MeshPacket *p); + + /** Frees the provided packet, and generates a NAK indicating the speicifed error while sending */ + void abortSendAndNak(Routing_Error err, MeshPacket *p); }; extern Router *router; diff --git a/src/mesh/generated/deviceonly.pb.h b/src/mesh/generated/deviceonly.pb.h index b8c372664..9ec3fa5a0 100644 --- a/src/mesh/generated/deviceonly.pb.h +++ b/src/mesh/generated/deviceonly.pb.h @@ -80,7 +80,7 @@ extern const pb_msgdesc_t DeviceState_msg; #define DeviceState_fields &DeviceState_msg /* Maximum encoded size of messages (where known) */ -#define DeviceState_size 6119 +#define DeviceState_size 6125 #ifdef __cplusplus } /* extern "C" */ diff --git a/src/mesh/generated/mesh.pb.h b/src/mesh/generated/mesh.pb.h index 873e0aa2f..6858cdcd9 100644 --- a/src/mesh/generated/mesh.pb.h +++ b/src/mesh/generated/mesh.pb.h @@ -80,7 +80,9 @@ typedef enum _Routing_Error { Routing_Error_GOT_NAK = 2, Routing_Error_TIMEOUT = 3, Routing_Error_NO_INTERFACE = 4, - Routing_Error_MAX_RETRANSMIT = 5 + Routing_Error_MAX_RETRANSMIT = 5, + Routing_Error_NO_CHANNEL = 6, + Routing_Error_TOO_LARGE = 7 } Routing_Error; typedef enum _MeshPacket_Priority { @@ -240,7 +242,7 @@ typedef PB_BYTES_ARRAY_T(256) MeshPacket_encrypted_t; typedef struct _MeshPacket { uint32_t from; uint32_t to; - uint8_t channel_index; + uint32_t channel; pb_size_t which_payloadVariant; union { Data decoded; @@ -340,8 +342,8 @@ typedef struct _ToRadio { #define _CriticalErrorCode_ARRAYSIZE ((CriticalErrorCode)(CriticalErrorCode_TransmitFailed+1)) #define _Routing_Error_MIN Routing_Error_NONE -#define _Routing_Error_MAX Routing_Error_MAX_RETRANSMIT -#define _Routing_Error_ARRAYSIZE ((Routing_Error)(Routing_Error_MAX_RETRANSMIT+1)) +#define _Routing_Error_MAX Routing_Error_TOO_LARGE +#define _Routing_Error_ARRAYSIZE ((Routing_Error)(Routing_Error_TOO_LARGE+1)) #define _MeshPacket_Priority_MIN MeshPacket_Priority_UNSET #define _MeshPacket_Priority_MAX MeshPacket_Priority_MAX @@ -488,7 +490,7 @@ extern "C" { #define Channel_role_tag 3 #define MeshPacket_from_tag 1 #define MeshPacket_to_tag 2 -#define MeshPacket_channel_index_tag 3 +#define MeshPacket_channel_tag 3 #define MeshPacket_decoded_tag 4 #define MeshPacket_encrypted_tag 5 #define MeshPacket_id_tag 6 @@ -571,7 +573,7 @@ X(a, STATIC, SINGULAR, FIXED32, source, 5) #define MeshPacket_FIELDLIST(X, a) \ X(a, STATIC, SINGULAR, FIXED32, from, 1) \ X(a, STATIC, SINGULAR, FIXED32, to, 2) \ -X(a, STATIC, SINGULAR, UINT32, channel_index, 3) \ +X(a, STATIC, SINGULAR, UINT32, channel, 3) \ X(a, STATIC, ONEOF, MESSAGE, (payloadVariant,decoded,decoded), 4) \ X(a, STATIC, ONEOF, BYTES, (payloadVariant,encrypted,encrypted), 5) \ X(a, STATIC, SINGULAR, FIXED32, id, 6) \ @@ -771,7 +773,7 @@ extern const pb_msgdesc_t AdminMessage_msg; #define RouteDiscovery_size 40 #define Routing_size 47 #define Data_size 255 -#define MeshPacket_size 294 +#define MeshPacket_size 297 #define ChannelSettings_size 87 #define Channel_size 94 #define RadioConfig_size 308 @@ -780,7 +782,7 @@ extern const pb_msgdesc_t AdminMessage_msg; #define MyNodeInfo_size 89 #define LogRecord_size 81 #define FromRadio_size 317 -#define ToRadio_size 297 +#define ToRadio_size 300 #define AdminMessage_size 311 #ifdef __cplusplus From efaf66947902e70787f7a67ccca9b018c21433e5 Mon Sep 17 00:00:00 2001 From: Charles Crossan Date: Mon, 22 Feb 2021 19:50:51 -0500 Subject: [PATCH 152/258] update Environmental Measurement plugin to use radio config prefs --- proto | 2 +- src/mesh/generated/deviceonly.pb.h | 4 +- src/mesh/generated/mesh.pb.h | 26 +++++++--- .../esp32/EnvironmentalMeasurementPlugin.cpp | 48 +++++++++++++------ 4 files changed, 56 insertions(+), 24 deletions(-) diff --git a/proto b/proto index 930646441..040f62989 160000 --- a/proto +++ b/proto @@ -1 +1 @@ -Subproject commit 9306464417522aa8b25672b324a3bd5e9dec3395 +Subproject commit 040f6298976839120b07ee8a34e11494a370d401 diff --git a/src/mesh/generated/deviceonly.pb.h b/src/mesh/generated/deviceonly.pb.h index 99d838d39..45d2bf563 100644 --- a/src/mesh/generated/deviceonly.pb.h +++ b/src/mesh/generated/deviceonly.pb.h @@ -80,10 +80,10 @@ extern const pb_msgdesc_t DeviceState_msg; #define DeviceState_fields &DeviceState_msg /* Maximum encoded size of messages (where known) */ -#define DeviceState_size 6266 +#define DeviceState_size 6290 #ifdef __cplusplus } /* extern "C" */ #endif -#endif \ No newline at end of file +#endif diff --git a/src/mesh/generated/mesh.pb.h b/src/mesh/generated/mesh.pb.h index 397a313ea..f0e149e1f 100644 --- a/src/mesh/generated/mesh.pb.h +++ b/src/mesh/generated/mesh.pb.h @@ -208,6 +208,10 @@ typedef struct _RadioConfig_UserPreferences { bool range_test_plugin_save; bool store_forward_plugin_enabled; uint32_t store_forward_plugin_records; + bool environmental_measurement_plugin_enabled; + uint32_t environmental_measurement_plugin_read_error_count_threshold; + uint32_t environmental_measurement_plugin_update_interval; + uint32_t environmental_measurement_plugin_recovery_interval; } RadioConfig_UserPreferences; typedef struct _RouteDiscovery { @@ -360,7 +364,7 @@ extern "C" { #define MeshPacket_init_default {0, 0, 0, {SubPacket_init_default}, 0, 0, 0, 0, 0, 0, _MeshPacket_Priority_MIN} #define ChannelSettings_init_default {0, _ChannelSettings_ModemConfig_MIN, {0, {0}}, "", 0, 0, 0, 0, 0, 0, 0} #define RadioConfig_init_default {false, RadioConfig_UserPreferences_init_default, false, ChannelSettings_init_default} -#define RadioConfig_UserPreferences_init_default {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, "", "", 0, _RegionCode_MIN, _ChargeCurrent_MIN, _LocationSharing_MIN, _GpsOperation_MIN, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0}, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} +#define RadioConfig_UserPreferences_init_default {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, "", "", 0, _RegionCode_MIN, _ChargeCurrent_MIN, _LocationSharing_MIN, _GpsOperation_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, 0, 0, 0, 0} #define NodeInfo_init_default {0, false, User_init_default, false, Position_init_default, 0, 0} #define MyNodeInfo_init_default {0, 0, 0, "", "", "", _CriticalErrorCode_MIN, 0, 0, 0, 0, 0, 0, 0} #define LogRecord_init_default {"", 0, "", _LogRecord_Level_MIN} @@ -374,7 +378,7 @@ extern "C" { #define MeshPacket_init_zero {0, 0, 0, {SubPacket_init_zero}, 0, 0, 0, 0, 0, 0, _MeshPacket_Priority_MIN} #define ChannelSettings_init_zero {0, _ChannelSettings_ModemConfig_MIN, {0, {0}}, "", 0, 0, 0, 0, 0, 0, 0} #define RadioConfig_init_zero {false, RadioConfig_UserPreferences_init_zero, false, ChannelSettings_init_zero} -#define RadioConfig_UserPreferences_init_zero {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, "", "", 0, _RegionCode_MIN, _ChargeCurrent_MIN, _LocationSharing_MIN, _GpsOperation_MIN, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0}, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} +#define RadioConfig_UserPreferences_init_zero {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, "", "", 0, _RegionCode_MIN, _ChargeCurrent_MIN, _LocationSharing_MIN, _GpsOperation_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, 0, 0, 0, 0} #define NodeInfo_init_zero {0, false, User_init_zero, false, Position_init_zero, 0, 0} #define MyNodeInfo_init_zero {0, 0, 0, "", "", "", _CriticalErrorCode_MIN, 0, 0, 0, 0, 0, 0, 0} #define LogRecord_init_zero {"", 0, "", _LogRecord_Level_MIN} @@ -460,6 +464,10 @@ extern "C" { #define RadioConfig_UserPreferences_range_test_plugin_save_tag 134 #define RadioConfig_UserPreferences_store_forward_plugin_enabled_tag 136 #define RadioConfig_UserPreferences_store_forward_plugin_records_tag 137 +#define RadioConfig_UserPreferences_environmental_measurement_plugin_enabled_tag 140 +#define RadioConfig_UserPreferences_environmental_measurement_plugin_read_error_count_threshold_tag 141 +#define RadioConfig_UserPreferences_environmental_measurement_plugin_update_interval_tag 142 +#define RadioConfig_UserPreferences_environmental_measurement_plugin_recovery_interval_tag 143 #define RouteDiscovery_route_tag 2 #define User_id_tag 1 #define User_long_name_tag 2 @@ -641,7 +649,11 @@ X(a, STATIC, SINGULAR, BOOL, range_test_plugin_enabled, 132) \ X(a, STATIC, SINGULAR, UINT32, range_test_plugin_sender, 133) \ X(a, STATIC, SINGULAR, BOOL, range_test_plugin_save, 134) \ X(a, STATIC, SINGULAR, BOOL, store_forward_plugin_enabled, 136) \ -X(a, STATIC, SINGULAR, UINT32, store_forward_plugin_records, 137) +X(a, STATIC, SINGULAR, UINT32, store_forward_plugin_records, 137) \ +X(a, STATIC, SINGULAR, BOOL, environmental_measurement_plugin_enabled, 140) \ +X(a, STATIC, SINGULAR, UINT32, environmental_measurement_plugin_read_error_count_threshold, 141) \ +X(a, STATIC, SINGULAR, UINT32, environmental_measurement_plugin_update_interval, 142) \ +X(a, STATIC, SINGULAR, UINT32, environmental_measurement_plugin_recovery_interval, 143) #define RadioConfig_UserPreferences_CALLBACK NULL #define RadioConfig_UserPreferences_DEFAULT NULL @@ -753,13 +765,13 @@ extern const pb_msgdesc_t ToRadio_msg; #define SubPacket_size 275 #define MeshPacket_size 322 #define ChannelSettings_size 95 -#define RadioConfig_size 405 -#define RadioConfig_UserPreferences_size 305 +#define RadioConfig_size 429 +#define RadioConfig_UserPreferences_size 329 #define NodeInfo_size 132 #define MyNodeInfo_size 106 #define LogRecord_size 81 -#define FromRadio_size 414 -#define ToRadio_size 409 +#define FromRadio_size 438 +#define ToRadio_size 433 #ifdef __cplusplus } /* extern "C" */ diff --git a/src/plugins/esp32/EnvironmentalMeasurementPlugin.cpp b/src/plugins/esp32/EnvironmentalMeasurementPlugin.cpp index 6d8938fe8..785fa75a0 100644 --- a/src/plugins/esp32/EnvironmentalMeasurementPlugin.cpp +++ b/src/plugins/esp32/EnvironmentalMeasurementPlugin.cpp @@ -18,11 +18,7 @@ EnvironmentalMeasurementPlugin::EnvironmentalMeasurementPlugin() : concurrency:: uint32_t sensor_read_error_count = 0; #define DHT_11_GPIO_PIN 13 -//TODO: Make a related radioconfig preference to allow less-frequent reads -#define ENVIRONMENTAL_MEASUREMENT_APP_ENABLED true // DISABLED by default; set this to true if you want to use the plugin -#define DHT_SENSOR_MINIMUM_WAIT_TIME_BETWEEN_READS 1000 -#define SENSOR_READ_ERROR_COUNT_THRESHOLD 5 -#define SENSOR_READ_MULTIPLIER 3 +#define DHT_SENSOR_MINIMUM_WAIT_TIME_BETWEEN_READS 1000 // Some sensors (the DHT11) have a minimum required duration between read attempts #define FAILED_STATE_SENSOR_READ_MULTIPLIER 10 #define DISPLAY_RECEIVEID_MEASUREMENTS_ON_SCREEN true @@ -47,11 +43,22 @@ DHT dht(DHT_11_GPIO_PIN,DHT11); int32_t EnvironmentalMeasurementPlugin::runOnce() { -#ifndef NO_ESP32 - if (!ENVIRONMENTAL_MEASUREMENT_APP_ENABLED){ +#ifndef NO_ESP32 // this only works on ESP32 devices + + /* + Uncomment the preferences below if you want to use the plugin + without having to configure it from the PythonAPI or WebUI. + */ + /*radioConfig.preferences.environmental_measurement_plugin_enabled = 1; + radioConfig.preferences.environmental_measurement_plugin_read_error_count_threshold = 5; + radioConfig.preferences.environmental_measurement_plugin_update_interval = 30; + radioConfig.preferences.environmental_measurement_plugin_recovery_interval = 600;*/ + + if (!radioConfig.preferences.environmental_measurement_plugin_enabled){ // If this plugin is not enabled, don't waste any OSThread time on it return (INT32_MAX); } + if (firstTime) { // This is the first time the OSThread library has called this function, so do some setup DEBUG_MSG("EnvironmentalMeasurement: Initializing as sender\n"); @@ -69,13 +76,26 @@ int32_t EnvironmentalMeasurementPlugin::runOnce() { else { // this is not the first time OSThread library has called this function // so just do what we intend to do on the interval - if(sensor_read_error_count > SENSOR_READ_ERROR_COUNT_THRESHOLD) + if(sensor_read_error_count > radioConfig.preferences.environmental_measurement_plugin_read_error_count_threshold) { - DEBUG_MSG("EnvironmentalMeasurement: DISABLED; The SENSOR_READ_ERROR_COUNT_THRESHOLD has been exceed: %d\n",SENSOR_READ_ERROR_COUNT_THRESHOLD); - return(FAILED_STATE_SENSOR_READ_MULTIPLIER * DHT_SENSOR_MINIMUM_WAIT_TIME_BETWEEN_READS); + if (radioConfig.preferences.environmental_measurement_plugin_recovery_interval > 0 ) { + DEBUG_MSG( + "EnvironmentalMeasurement: TEMPORARILY DISABLED; The environmental_measurement_plugin_read_error_count_threshold has been exceed: %d. Will retry reads in %d seconds\n", + radioConfig.preferences.environmental_measurement_plugin_read_error_count_threshold, + radioConfig.preferences.environmental_measurement_plugin_recovery_interval); + return(radioConfig.preferences.environmental_measurement_plugin_recovery_interval*1000); + } + DEBUG_MSG( + "EnvironmentalMeasurement: DISABLED; The environmental_measurement_plugin_read_error_count_threshold has been exceed: %d. Reads will not be retried until after device reset\n", + radioConfig.preferences.environmental_measurement_plugin_read_error_count_threshold); + return(INT32_MAX); + + } else if (sensor_read_error_count > 0){ - DEBUG_MSG("EnvironmentalMeasurement: There have been %d sensor read failures.\n",sensor_read_error_count); + DEBUG_MSG("EnvironmentalMeasurement: There have been %d sensor read failures. Will retry %d more times\n", + sensor_read_error_count, + radioConfig.preferences.environmental_measurement_plugin_read_error_count_threshold-sensor_read_error_count); } if (! environmentalMeasurementPluginRadio->sendOurEnvironmentalMeasurement() ){ // if we failed to read the sensor, then try again @@ -85,8 +105,8 @@ int32_t EnvironmentalMeasurementPlugin::runOnce() { } // The return of runOnce is an int32 representing the desired number of // miliseconds until the function should be called again by the - // OSThread library. - return(SENSOR_READ_MULTIPLIER * DHT_SENSOR_MINIMUM_WAIT_TIME_BETWEEN_READS); + // OSThread library. Multiply the preference value by 1000 to convert seconds to miliseconds + return(radioConfig.preferences.environmental_measurement_plugin_update_interval * 1000); #endif } @@ -114,7 +134,7 @@ String GetSenderName(const MeshPacket &mp) { bool EnvironmentalMeasurementPluginRadio::handleReceivedProtobuf(const MeshPacket &mp, const EnvironmentalMeasurement &p) { - if (!ENVIRONMENTAL_MEASUREMENT_APP_ENABLED){ + if (!radioConfig.preferences.environmental_measurement_plugin_enabled){ // If this plugin is not enabled, don't handle the packet, and allow other plugins to consume return false; } From b62b01fe7c3166dc14c9a83f0a9461c0c98d1f69 Mon Sep 17 00:00:00 2001 From: Charles Crossan Date: Mon, 22 Feb 2021 20:18:36 -0500 Subject: [PATCH 153/258] consume the additional details from OLEDDisplayUiState to handle transitions to/from plugin screens better It's still a bit janky, but should work https://github.com/meshtastic/esp8266-oled-ssd1306/pull/2 --- src/graphics/Screen.cpp | 20 +++++++++++++++++-- .../esp32/EnvironmentalMeasurementPlugin.cpp | 4 ++-- 2 files changed, 20 insertions(+), 4 deletions(-) diff --git a/src/graphics/Screen.cpp b/src/graphics/Screen.cpp index d0a235e8c..c21c4335d 100644 --- a/src/graphics/Screen.cpp +++ b/src/graphics/Screen.cpp @@ -150,8 +150,24 @@ static void drawSleepScreen(OLEDDisplay *display, OLEDDisplayUiState *state, int static void drawPluginFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y) { - DEBUG_MSG("Drawing Plugin Frame %d\n\n", state->currentFrame); - MeshPlugin &pi = *pluginFrames.at(state->currentFrame); + uint8_t plugin_frame; + // there's a little but in the UI transition code + // where it invokes the function at the correct offset + // in the array of "drawScreen" functions; however, + // the passed-state doesn't quite reflect the "current" + // screen, so we have to detect it. + if (state->frameState == IN_TRANSITION && state->transitionFrameRelationship == INCOMING) { + // if we're transitioning from the end of the frame list back around to the first + // frame, then we want this to be `0` + plugin_frame = state->transitionFrameTarget; + } + else { + // otherwise, just display the plugin frame that's aligned with the current frame + plugin_frame = state->currentFrame; + DEBUG_MSG("Screen is not in transition. Frame: %d\n\n", plugin_frame); + } + DEBUG_MSG("Drawing Plugin Frame %d\n\n", plugin_frame); + MeshPlugin &pi = *pluginFrames.at(plugin_frame); pi.drawFrame(display,state,x,y); } diff --git a/src/plugins/esp32/EnvironmentalMeasurementPlugin.cpp b/src/plugins/esp32/EnvironmentalMeasurementPlugin.cpp index 785fa75a0..4add55f8c 100644 --- a/src/plugins/esp32/EnvironmentalMeasurementPlugin.cpp +++ b/src/plugins/esp32/EnvironmentalMeasurementPlugin.cpp @@ -49,10 +49,10 @@ int32_t EnvironmentalMeasurementPlugin::runOnce() { Uncomment the preferences below if you want to use the plugin without having to configure it from the PythonAPI or WebUI. */ - /*radioConfig.preferences.environmental_measurement_plugin_enabled = 1; + radioConfig.preferences.environmental_measurement_plugin_enabled = 1; radioConfig.preferences.environmental_measurement_plugin_read_error_count_threshold = 5; radioConfig.preferences.environmental_measurement_plugin_update_interval = 30; - radioConfig.preferences.environmental_measurement_plugin_recovery_interval = 600;*/ + radioConfig.preferences.environmental_measurement_plugin_recovery_interval = 600; if (!radioConfig.preferences.environmental_measurement_plugin_enabled){ // If this plugin is not enabled, don't waste any OSThread time on it From 0c9df6ccbdea89a2216dc11ccd3df2780f7d8378 Mon Sep 17 00:00:00 2001 From: Charles Crossan Date: Mon, 22 Feb 2021 20:33:42 -0500 Subject: [PATCH 154/258] disable the app by default --- src/plugins/esp32/EnvironmentalMeasurementPlugin.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/plugins/esp32/EnvironmentalMeasurementPlugin.cpp b/src/plugins/esp32/EnvironmentalMeasurementPlugin.cpp index 4add55f8c..785fa75a0 100644 --- a/src/plugins/esp32/EnvironmentalMeasurementPlugin.cpp +++ b/src/plugins/esp32/EnvironmentalMeasurementPlugin.cpp @@ -49,10 +49,10 @@ int32_t EnvironmentalMeasurementPlugin::runOnce() { Uncomment the preferences below if you want to use the plugin without having to configure it from the PythonAPI or WebUI. */ - radioConfig.preferences.environmental_measurement_plugin_enabled = 1; + /*radioConfig.preferences.environmental_measurement_plugin_enabled = 1; radioConfig.preferences.environmental_measurement_plugin_read_error_count_threshold = 5; radioConfig.preferences.environmental_measurement_plugin_update_interval = 30; - radioConfig.preferences.environmental_measurement_plugin_recovery_interval = 600; + radioConfig.preferences.environmental_measurement_plugin_recovery_interval = 600;*/ if (!radioConfig.preferences.environmental_measurement_plugin_enabled){ // If this plugin is not enabled, don't waste any OSThread time on it From 3f1ada29ac8532152d67b59810c90791b966d4e0 Mon Sep 17 00:00:00 2001 From: Charles Crossan Date: Mon, 22 Feb 2021 20:47:35 -0500 Subject: [PATCH 155/258] support independently enabling/disabling the on-device screen and actual measurement --- proto | 2 +- src/mesh/generated/deviceonly.pb.h | 2 +- src/mesh/generated/mesh.pb.h | 33 ++++++++++--------- .../esp32/EnvironmentalMeasurementPlugin.cpp | 33 ++++++++++++++----- .../esp32/EnvironmentalMeasurementPlugin.h | 4 +-- 5 files changed, 46 insertions(+), 28 deletions(-) diff --git a/proto b/proto index 040f62989..d70f6f6f6 160000 --- a/proto +++ b/proto @@ -1 +1 @@ -Subproject commit 040f6298976839120b07ee8a34e11494a370d401 +Subproject commit d70f6f6f669df79c9423795caf34adbd28967e19 diff --git a/src/mesh/generated/deviceonly.pb.h b/src/mesh/generated/deviceonly.pb.h index 45d2bf563..0e933b968 100644 --- a/src/mesh/generated/deviceonly.pb.h +++ b/src/mesh/generated/deviceonly.pb.h @@ -80,7 +80,7 @@ extern const pb_msgdesc_t DeviceState_msg; #define DeviceState_fields &DeviceState_msg /* Maximum encoded size of messages (where known) */ -#define DeviceState_size 6290 +#define DeviceState_size 6293 #ifdef __cplusplus } /* extern "C" */ diff --git a/src/mesh/generated/mesh.pb.h b/src/mesh/generated/mesh.pb.h index f0e149e1f..edc74a908 100644 --- a/src/mesh/generated/mesh.pb.h +++ b/src/mesh/generated/mesh.pb.h @@ -208,7 +208,8 @@ typedef struct _RadioConfig_UserPreferences { bool range_test_plugin_save; bool store_forward_plugin_enabled; uint32_t store_forward_plugin_records; - bool environmental_measurement_plugin_enabled; + bool environmental_measurement_plugin_measurement_enabled; + bool environmental_measurement_plugin_screen_enabled; uint32_t environmental_measurement_plugin_read_error_count_threshold; uint32_t environmental_measurement_plugin_update_interval; uint32_t environmental_measurement_plugin_recovery_interval; @@ -364,7 +365,7 @@ extern "C" { #define MeshPacket_init_default {0, 0, 0, {SubPacket_init_default}, 0, 0, 0, 0, 0, 0, _MeshPacket_Priority_MIN} #define ChannelSettings_init_default {0, _ChannelSettings_ModemConfig_MIN, {0, {0}}, "", 0, 0, 0, 0, 0, 0, 0} #define RadioConfig_init_default {false, RadioConfig_UserPreferences_init_default, false, ChannelSettings_init_default} -#define RadioConfig_UserPreferences_init_default {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, "", "", 0, _RegionCode_MIN, _ChargeCurrent_MIN, _LocationSharing_MIN, _GpsOperation_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, 0, 0, 0, 0} +#define RadioConfig_UserPreferences_init_default {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, "", "", 0, _RegionCode_MIN, _ChargeCurrent_MIN, _LocationSharing_MIN, _GpsOperation_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, 0, 0, 0, 0, 0} #define NodeInfo_init_default {0, false, User_init_default, false, Position_init_default, 0, 0} #define MyNodeInfo_init_default {0, 0, 0, "", "", "", _CriticalErrorCode_MIN, 0, 0, 0, 0, 0, 0, 0} #define LogRecord_init_default {"", 0, "", _LogRecord_Level_MIN} @@ -378,7 +379,7 @@ extern "C" { #define MeshPacket_init_zero {0, 0, 0, {SubPacket_init_zero}, 0, 0, 0, 0, 0, 0, _MeshPacket_Priority_MIN} #define ChannelSettings_init_zero {0, _ChannelSettings_ModemConfig_MIN, {0, {0}}, "", 0, 0, 0, 0, 0, 0, 0} #define RadioConfig_init_zero {false, RadioConfig_UserPreferences_init_zero, false, ChannelSettings_init_zero} -#define RadioConfig_UserPreferences_init_zero {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, "", "", 0, _RegionCode_MIN, _ChargeCurrent_MIN, _LocationSharing_MIN, _GpsOperation_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, 0, 0, 0, 0} +#define RadioConfig_UserPreferences_init_zero {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, "", "", 0, _RegionCode_MIN, _ChargeCurrent_MIN, _LocationSharing_MIN, _GpsOperation_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, 0, 0, 0, 0, 0} #define NodeInfo_init_zero {0, false, User_init_zero, false, Position_init_zero, 0, 0} #define MyNodeInfo_init_zero {0, 0, 0, "", "", "", _CriticalErrorCode_MIN, 0, 0, 0, 0, 0, 0, 0} #define LogRecord_init_zero {"", 0, "", _LogRecord_Level_MIN} @@ -464,10 +465,11 @@ extern "C" { #define RadioConfig_UserPreferences_range_test_plugin_save_tag 134 #define RadioConfig_UserPreferences_store_forward_plugin_enabled_tag 136 #define RadioConfig_UserPreferences_store_forward_plugin_records_tag 137 -#define RadioConfig_UserPreferences_environmental_measurement_plugin_enabled_tag 140 -#define RadioConfig_UserPreferences_environmental_measurement_plugin_read_error_count_threshold_tag 141 -#define RadioConfig_UserPreferences_environmental_measurement_plugin_update_interval_tag 142 -#define RadioConfig_UserPreferences_environmental_measurement_plugin_recovery_interval_tag 143 +#define RadioConfig_UserPreferences_environmental_measurement_plugin_measurement_enabled_tag 140 +#define RadioConfig_UserPreferences_environmental_measurement_plugin_screen_enabled_tag 141 +#define RadioConfig_UserPreferences_environmental_measurement_plugin_read_error_count_threshold_tag 142 +#define RadioConfig_UserPreferences_environmental_measurement_plugin_update_interval_tag 143 +#define RadioConfig_UserPreferences_environmental_measurement_plugin_recovery_interval_tag 144 #define RouteDiscovery_route_tag 2 #define User_id_tag 1 #define User_long_name_tag 2 @@ -650,10 +652,11 @@ X(a, STATIC, SINGULAR, UINT32, range_test_plugin_sender, 133) \ X(a, STATIC, SINGULAR, BOOL, range_test_plugin_save, 134) \ X(a, STATIC, SINGULAR, BOOL, store_forward_plugin_enabled, 136) \ X(a, STATIC, SINGULAR, UINT32, store_forward_plugin_records, 137) \ -X(a, STATIC, SINGULAR, BOOL, environmental_measurement_plugin_enabled, 140) \ -X(a, STATIC, SINGULAR, UINT32, environmental_measurement_plugin_read_error_count_threshold, 141) \ -X(a, STATIC, SINGULAR, UINT32, environmental_measurement_plugin_update_interval, 142) \ -X(a, STATIC, SINGULAR, UINT32, environmental_measurement_plugin_recovery_interval, 143) +X(a, STATIC, SINGULAR, BOOL, environmental_measurement_plugin_measurement_enabled, 140) \ +X(a, STATIC, SINGULAR, BOOL, environmental_measurement_plugin_screen_enabled, 141) \ +X(a, STATIC, SINGULAR, UINT32, environmental_measurement_plugin_read_error_count_threshold, 142) \ +X(a, STATIC, SINGULAR, UINT32, environmental_measurement_plugin_update_interval, 143) \ +X(a, STATIC, SINGULAR, UINT32, environmental_measurement_plugin_recovery_interval, 144) #define RadioConfig_UserPreferences_CALLBACK NULL #define RadioConfig_UserPreferences_DEFAULT NULL @@ -765,13 +768,13 @@ extern const pb_msgdesc_t ToRadio_msg; #define SubPacket_size 275 #define MeshPacket_size 322 #define ChannelSettings_size 95 -#define RadioConfig_size 429 -#define RadioConfig_UserPreferences_size 329 +#define RadioConfig_size 432 +#define RadioConfig_UserPreferences_size 332 #define NodeInfo_size 132 #define MyNodeInfo_size 106 #define LogRecord_size 81 -#define FromRadio_size 438 -#define ToRadio_size 433 +#define FromRadio_size 441 +#define ToRadio_size 436 #ifdef __cplusplus } /* extern "C" */ diff --git a/src/plugins/esp32/EnvironmentalMeasurementPlugin.cpp b/src/plugins/esp32/EnvironmentalMeasurementPlugin.cpp index 785fa75a0..2d706150d 100644 --- a/src/plugins/esp32/EnvironmentalMeasurementPlugin.cpp +++ b/src/plugins/esp32/EnvironmentalMeasurementPlugin.cpp @@ -49,19 +49,20 @@ int32_t EnvironmentalMeasurementPlugin::runOnce() { Uncomment the preferences below if you want to use the plugin without having to configure it from the PythonAPI or WebUI. */ - /*radioConfig.preferences.environmental_measurement_plugin_enabled = 1; + /*radioConfig.preferences.environmental_measurement_plugin_measurement_enabled = 1; + radioConfig.preferences.environmental_measurement_plugin_screen_enabled = 1; radioConfig.preferences.environmental_measurement_plugin_read_error_count_threshold = 5; radioConfig.preferences.environmental_measurement_plugin_update_interval = 30; radioConfig.preferences.environmental_measurement_plugin_recovery_interval = 600;*/ - if (!radioConfig.preferences.environmental_measurement_plugin_enabled){ - // If this plugin is not enabled, don't waste any OSThread time on it + if (! (radioConfig.preferences.environmental_measurement_plugin_measurement_enabled || radioConfig.preferences.environmental_measurement_plugin_screen_enabled)){ + // If this plugin is not enabled, and the user doesn't want the display screen don't waste any OSThread time on it return (INT32_MAX); } if (firstTime) { // This is the first time the OSThread library has called this function, so do some setup - DEBUG_MSG("EnvironmentalMeasurement: Initializing as sender\n"); + DEBUG_MSG("EnvironmentalMeasurement: Initializing\n"); environmentalMeasurementPluginRadio = new EnvironmentalMeasurementPluginRadio(); firstTime = 0; // begin reading measurements from the sensor @@ -70,10 +71,22 @@ int32_t EnvironmentalMeasurementPlugin::runOnce() { // returning the interval here means that the next time OSThread // calls our plugin, we'll run the other branch of this if statement // and actually do a "sendOurEnvironmentalMeasurement()" - dht.begin(); - return(DHT_SENSOR_MINIMUM_WAIT_TIME_BETWEEN_READS); + if (radioConfig.preferences.environmental_measurement_plugin_measurement_enabled) + { + // it's possible to have this plugin enabled, only for displaying values on the screen. + // therefore, we should only enable the sensor loop if measurement is also enabled + dht.begin(); + return(DHT_SENSOR_MINIMUM_WAIT_TIME_BETWEEN_READS); + } + return (INT32_MAX); } else { + if (!radioConfig.preferences.environmental_measurement_plugin_measurement_enabled) + { + // if we somehow got to a second run of this plugin with measurement disabled, then just wait forever + // I can't imagine we'd ever get here though. + return (INT32_MAX); + } // this is not the first time OSThread library has called this function // so just do what we intend to do on the interval if(sensor_read_error_count > radioConfig.preferences.environmental_measurement_plugin_read_error_count_threshold) @@ -110,6 +123,10 @@ int32_t EnvironmentalMeasurementPlugin::runOnce() { #endif } +bool EnvironmentalMeasurementPluginRadio::wantUIFrame() { + return radioConfig.preferences.environmental_measurement_plugin_screen_enabled; +} + void EnvironmentalMeasurementPluginRadio::drawFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y) { display->setTextAlignment(TEXT_ALIGN_LEFT); @@ -134,8 +151,8 @@ String GetSenderName(const MeshPacket &mp) { bool EnvironmentalMeasurementPluginRadio::handleReceivedProtobuf(const MeshPacket &mp, const EnvironmentalMeasurement &p) { - if (!radioConfig.preferences.environmental_measurement_plugin_enabled){ - // If this plugin is not enabled, don't handle the packet, and allow other plugins to consume + if (!(radioConfig.preferences.environmental_measurement_plugin_measurement_enabled || radioConfig.preferences.environmental_measurement_plugin_screen_enabled)){ + // If this plugin is not enabled in any capacity, don't handle the packet, and allow other plugins to consume return false; } bool wasBroadcast = mp.to == NODENUM_BROADCAST; diff --git a/src/plugins/esp32/EnvironmentalMeasurementPlugin.h b/src/plugins/esp32/EnvironmentalMeasurementPlugin.h index 8e9d968ba..8184f6cb3 100644 --- a/src/plugins/esp32/EnvironmentalMeasurementPlugin.h +++ b/src/plugins/esp32/EnvironmentalMeasurementPlugin.h @@ -44,9 +44,7 @@ class EnvironmentalMeasurementPluginRadio : public ProtobufPlugin Date: Mon, 22 Feb 2021 20:52:10 -0500 Subject: [PATCH 156/258] add missing newline --- src/graphics/Screen.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/graphics/Screen.cpp b/src/graphics/Screen.cpp index c21c4335d..80fd807cf 100644 --- a/src/graphics/Screen.cpp +++ b/src/graphics/Screen.cpp @@ -937,7 +937,7 @@ void Screen::setFrames() normalFrames[numframes++] = drawPluginFrame; } - DEBUG_MSG("Added plugins. numframes: %d", numframes); + DEBUG_MSG("Added plugins. numframes: %d\n", numframes); // If we have a critical fault, show it first if (myNodeInfo.error_code) From 3a91da5e52496ca5fd21871489efabef42255b43 Mon Sep 17 00:00:00 2001 From: Charles Crossan Date: Mon, 22 Feb 2021 21:00:05 -0500 Subject: [PATCH 157/258] remove UI render comment log spam --- src/graphics/Screen.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/graphics/Screen.cpp b/src/graphics/Screen.cpp index 80fd807cf..8f974a4c0 100644 --- a/src/graphics/Screen.cpp +++ b/src/graphics/Screen.cpp @@ -164,9 +164,9 @@ static void drawPluginFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int else { // otherwise, just display the plugin frame that's aligned with the current frame plugin_frame = state->currentFrame; - DEBUG_MSG("Screen is not in transition. Frame: %d\n\n", plugin_frame); + //DEBUG_MSG("Screen is not in transition. Frame: %d\n\n", plugin_frame); } - DEBUG_MSG("Drawing Plugin Frame %d\n\n", plugin_frame); + //DEBUG_MSG("Drawing Plugin Frame %d\n\n", plugin_frame); MeshPlugin &pi = *pluginFrames.at(plugin_frame); pi.drawFrame(display,state,x,y); From ec41c11e584f67f7351e6cd83f0c837f12273f2a Mon Sep 17 00:00:00 2001 From: Charles Crossan Date: Mon, 22 Feb 2021 21:00:41 -0500 Subject: [PATCH 158/258] initialize the last measurement values to something obviously "unread" --- src/plugins/esp32/EnvironmentalMeasurementPlugin.h | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/plugins/esp32/EnvironmentalMeasurementPlugin.h b/src/plugins/esp32/EnvironmentalMeasurementPlugin.h index 8184f6cb3..19d73914b 100644 --- a/src/plugins/esp32/EnvironmentalMeasurementPlugin.h +++ b/src/plugins/esp32/EnvironmentalMeasurementPlugin.h @@ -27,7 +27,12 @@ class EnvironmentalMeasurementPluginRadio : public ProtobufPlugin Date: Tue, 23 Feb 2021 10:10:35 +0800 Subject: [PATCH 159/258] clean up the crypto api --- src/esp32/ESP32CryptoEngine.cpp | 15 +-- src/mesh/Channels.cpp | 142 ++++++++++++-------- src/mesh/Channels.h | 29 ++-- src/mesh/CryptoEngine.cpp | 5 +- src/mesh/CryptoEngine.h | 11 +- src/nrf52/NRF52CryptoEngine.cpp | 27 +--- src/portduino/CrossPlatformCryptoEngine.cpp | 11 +- 7 files changed, 135 insertions(+), 105 deletions(-) diff --git a/src/esp32/ESP32CryptoEngine.cpp b/src/esp32/ESP32CryptoEngine.cpp index 613d5cc17..9d86ffeb0 100644 --- a/src/esp32/ESP32CryptoEngine.cpp +++ b/src/esp32/ESP32CryptoEngine.cpp @@ -18,9 +18,6 @@ class ESP32CryptoEngine : public CryptoEngine mbedtls_aes_context aes; - /// How many bytes in our key - uint8_t keySize = 0; - public: ESP32CryptoEngine() { mbedtls_aes_init(&aes); } @@ -35,12 +32,12 @@ class ESP32CryptoEngine : public CryptoEngine * @param bytes a _static_ buffer that will remain valid for the life of this crypto instance (i.e. this class will cache the * provided pointer) */ - virtual void setKey(size_t numBytes, uint8_t *bytes) + virtual void setKey(const CryptoKey &k) { - keySize = numBytes; - DEBUG_MSG("Installing AES%d key!\n", numBytes * 8); - if (numBytes != 0) { - auto res = mbedtls_aes_setkey_enc(&aes, bytes, numBytes * 8); + CryptoEngine::setKey(k); + + if (key.length != 0) { + auto res = mbedtls_aes_setkey_enc(&aes, key.bytes, key.length * 8); assert(!res); } } @@ -52,7 +49,7 @@ class ESP32CryptoEngine : public CryptoEngine */ virtual void encrypt(uint32_t fromNode, uint64_t packetNum, size_t numBytes, uint8_t *bytes) { - if (keySize != 0) { + if (key.length > 0) { uint8_t stream_block[16]; static uint8_t scratch[MAX_BLOCKSIZE]; size_t nc_off = 0; diff --git a/src/mesh/Channels.cpp b/src/mesh/Channels.cpp index 696f78f4f..f3238b9c5 100644 --- a/src/mesh/Channels.cpp +++ b/src/mesh/Channels.cpp @@ -10,7 +10,7 @@ static const uint8_t defaultpsk[] = {0xd4, 0xf1, 0xbb, 0x3a, 0x20, 0x29, 0x07, 0 Channels channels; -uint8_t xorHash(uint8_t *p, size_t len) +uint8_t xorHash(const uint8_t *p, size_t len) { uint8_t code = 0; for (int i = 0; i < len; i++) @@ -18,6 +18,26 @@ uint8_t xorHash(uint8_t *p, size_t len) return code; } +/** Given a channel number, return the (0 to 255) hash for that channel. + * The hash is just an xor of the channel name followed by the channel PSK being used for encryption + * If no suitable channel could be found, return -1 + */ +int16_t Channels::generateHash(ChannelIndex channelNum) +{ + auto k = getKey(channelNum); + if (k.length < 0) + return -1; // invalid + else { + Channel &c = getByIndex(channelNum); + + uint8_t h = xorHash((const uint8_t *)c.settings.name, strlen(c.settings.name)); + + h ^= xorHash(k.bytes, k.length); + + return h; + } +} + /** * Validate a channel, fixing any errors as needed */ @@ -75,51 +95,69 @@ void Channels::initDefaultChannel(ChannelIndex chIndex) ch.role = Channel_Role_PRIMARY; } -/** Given a channel index, change to use the crypto key specified by that index - */ -void Channels::setCrypto(ChannelIndex chIndex) +CryptoKey Channels::getKey(ChannelIndex chIndex) { Channel &ch = getByIndex(chIndex); ChannelSettings &channelSettings = ch.settings; assert(ch.has_settings); - memset(activePSK, 0, sizeof(activePSK)); // In case the user provided a short key, we want to pad the rest with zeros - memcpy(activePSK, channelSettings.psk.bytes, channelSettings.psk.size); - activePSKSize = channelSettings.psk.size; - if (activePSKSize == 0) { - if (ch.role == Channel_Role_SECONDARY) { - DEBUG_MSG("Unset PSK for secondary channel %s. using primary key\n", ch.settings.name); - setCrypto(primaryIndex); - } else - DEBUG_MSG("Warning: User disabled encryption\n"); - } else if (activePSKSize == 1) { - // Convert the short single byte variants of psk into variant that can be used more generally + CryptoKey k; + memset(k.bytes, 0, sizeof(k.bytes)); // In case the user provided a short key, we want to pad the rest with zeros - uint8_t pskIndex = activePSK[0]; - DEBUG_MSG("Expanding short PSK #%d\n", pskIndex); - if (pskIndex == 0) - activePSKSize = 0; // Turn off encryption - else { - memcpy(activePSK, defaultpsk, sizeof(defaultpsk)); - activePSKSize = sizeof(defaultpsk); - // Bump up the last byte of PSK as needed - uint8_t *last = activePSK + sizeof(defaultpsk) - 1; - *last = *last + pskIndex - 1; // index of 1 means no change vs defaultPSK + if (ch.role == Channel_Role_DISABLED) { + k.length = -1; // invalid + } else { + memcpy(k.bytes, channelSettings.psk.bytes, channelSettings.psk.size); + k.length = channelSettings.psk.size; + if (k.length == 0) { + if (ch.role == Channel_Role_SECONDARY) { + DEBUG_MSG("Unset PSK for secondary channel %s. using primary key\n", ch.settings.name); + k = getKey(primaryIndex); + } else + DEBUG_MSG("Warning: User disabled encryption\n"); + } else if (k.length == 1) { + // Convert the short single byte variants of psk into variant that can be used more generally + + uint8_t pskIndex = k.bytes[0]; + DEBUG_MSG("Expanding short PSK #%d\n", pskIndex); + if (pskIndex == 0) + k.length = 0; // Turn off encryption + else { + memcpy(k.bytes, defaultpsk, sizeof(defaultpsk)); + k.length = sizeof(defaultpsk); + // Bump up the last byte of PSK as needed + uint8_t *last = k.bytes + sizeof(defaultpsk) - 1; + *last = *last + pskIndex - 1; // index of 1 means no change vs defaultPSK + } + } else if (k.length < 16) { + // Error! The user specified only the first few bits of an AES128 key. So by convention we just pad the rest of the + // key with zeros + DEBUG_MSG("Warning: User provided a too short AES128 key - padding\n"); + k.length = 16; + } else if (k.length < 32 && k.length != 16) { + // Error! The user specified only the first few bits of an AES256 key. So by convention we just pad the rest of the + // key with zeros + DEBUG_MSG("Warning: User provided a too short AES256 key - padding\n"); + k.length = 32; } - } else if (activePSKSize < 16) { - // Error! The user specified only the first few bits of an AES128 key. So by convention we just pad the rest of the key - // with zeros - DEBUG_MSG("Warning: User provided a too short AES128 key - padding\n"); - activePSKSize = 16; - } else if (activePSKSize < 32 && activePSKSize != 16) { - // Error! The user specified only the first few bits of an AES256 key. So by convention we just pad the rest of the key - // with zeros - DEBUG_MSG("Warning: User provided a too short AES256 key - padding\n"); - activePSKSize = 32; } - // Tell our crypto engine about the psk - crypto->setKey(activePSKSize, activePSK); + return k; +} + +/** Given a channel index, change to use the crypto key specified by that index + */ +int16_t Channels::setCrypto(ChannelIndex chIndex) +{ + CryptoKey k = getKey(chIndex); + + if (k.length < 0) + return -1; + else { + // Tell our crypto engine about the psk + crypto->setKey(k); + return getHash(chIndex); + } } void Channels::initDefaults() @@ -139,8 +177,6 @@ void Channels::onConfigChanged() if (ch.role == Channel_Role_PRIMARY) primaryIndex = i; } - - setCrypto(primaryIndex); // FIXME: for the time being (still single channel - just use our only channel as the crypto key) } Channel &Channels::getByIndex(ChannelIndex chIndex) @@ -207,7 +243,6 @@ their nodes * * Where X is either: * (for custom PSKS) a letter from A to Z (base26), and formed by xoring all the bytes of the PSK together, -* OR (for the standard minimially secure PSKs) a number from 0 to 9. * * This function will also need to be implemented in GUI apps that talk to the radio. * @@ -219,14 +254,14 @@ const char *Channels::getPrimaryName() char suffix; auto channelSettings = getPrimary(); - if (channelSettings.psk.size != 1) { - // We have a standard PSK, so generate a letter based hash. - uint8_t code = xorHash(activePSK, activePSKSize); + // if (channelSettings.psk.size != 1) { + // We have a standard PSK, so generate a letter based hash. + uint8_t code = getHash(primaryIndex); - suffix = 'A' + (code % 26); - } else { + suffix = 'A' + (code % 26); + /* } else { suffix = '0' + channelSettings.psk.bytes[0]; - } + } */ snprintf(buf, sizeof(buf), "#%s-%c", channelSettings.name, suffix); return buf; @@ -238,7 +273,10 @@ const char *Channels::getPrimaryName() * * @return -1 if no suitable channel could be found, otherwise returns the channel index */ -int16_t Channels::setActiveByHash(ChannelHash channelHash) {} +int16_t Channels::setActiveByHash(ChannelHash channelHash) +{ + // fixme cant work; +} /** Given a channel index setup crypto for encoding that channel (or the primary channel if that channel is unsecured) * @@ -246,9 +284,7 @@ int16_t Channels::setActiveByHash(ChannelHash channelHash) {} * * @eturn the (0 to 255) hash for that channel - if no suitable channel could be found, return -1 */ -int16_t Channels::setActiveByIndex(ChannelIndex channelIndex) {} - -/** Given a channel number, return the (0 to 255) hash for that channel - * If no suitable channel could be found, return -1 - */ -ChannelHash Channels::generateHash(ChannelIndex channelNum) {} \ No newline at end of file +int16_t Channels::setActiveByIndex(ChannelIndex channelIndex) +{ + return setCrypto(channelIndex); +} diff --git a/src/mesh/Channels.h b/src/mesh/Channels.h index a86b7ff68..4e70e2304 100644 --- a/src/mesh/Channels.h +++ b/src/mesh/Channels.h @@ -2,6 +2,7 @@ #include "mesh-pb-constants.h" #include +#include "CryptoEngine.h" /** A channel number (index into the channel table) */ @@ -23,12 +24,8 @@ class Channels no sending or receiving will be allowed */ ChannelIndex activeChannelIndex = 0; - /// The in-use psk - which has been constructed based on the (possibly short psk) in channelSettings - uint8_t activePSK[32]; - uint8_t activePSKSize = 0; - - /// the precomputed hashes for each of our channels - ChannelHash hashes[MAX_NUM_CHANNELS]; + /// the precomputed hashes for each of our channels, or -1 for invalid + int16_t hashes[MAX_NUM_CHANNELS]; public: const ChannelSettings &getPrimary() { return getByIndex(getPrimaryIndex()).settings; } @@ -87,21 +84,24 @@ class Channels */ int16_t setActiveByIndex(ChannelIndex channelIndex); - /** return the channel hash we are currently using for sending */ - ChannelHash getActiveHash(); - private: /** Given a channel index, change to use the crypto key specified by that index + * + * @eturn the (0 to 255) hash for that channel - if no suitable channel could be found, return -1 */ - void setCrypto(ChannelIndex chIndex); + int16_t setCrypto(ChannelIndex chIndex); /** Return the channel index for the specified channel hash, or -1 for not found */ int8_t getIndexByHash(ChannelHash channelHash); /** Given a channel number, return the (0 to 255) hash for that channel * If no suitable channel could be found, return -1 + * + * called by fixupChannel when a new channel is set */ - ChannelHash generateHash(ChannelIndex channelNum); + int16_t generateHash(ChannelIndex channelNum); + + int16_t getHash(ChannelIndex i) { return hashes[i]; } /** * Validate a channel, fixing any errors as needed @@ -112,6 +112,13 @@ class Channels * Write a default channel to the specified channel index */ void initDefaultChannel(ChannelIndex chIndex); + + /** + * Return the key used for encrypting this channel (if channel is secondary and no key provided, use the primary channel's PSK) + */ + CryptoKey getKey(ChannelIndex chIndex); + + }; /// Singleton channel table diff --git a/src/mesh/CryptoEngine.cpp b/src/mesh/CryptoEngine.cpp index d72be1118..74f4b7836 100644 --- a/src/mesh/CryptoEngine.cpp +++ b/src/mesh/CryptoEngine.cpp @@ -1,9 +1,10 @@ #include "CryptoEngine.h" #include "configuration.h" -void CryptoEngine::setKey(size_t numBytes, uint8_t *bytes) +void CryptoEngine::setKey(const CryptoKey &k) { - DEBUG_MSG("WARNING: Using stub crypto - all crypto is sent in plaintext!\n"); + DEBUG_MSG("Installing AES%d key!\n", k.length * 8); + key = k; } /** diff --git a/src/mesh/CryptoEngine.h b/src/mesh/CryptoEngine.h index b97abed55..9853f564a 100644 --- a/src/mesh/CryptoEngine.h +++ b/src/mesh/CryptoEngine.h @@ -2,6 +2,13 @@ #include +struct CryptoKey { + uint8_t bytes[32]; + + /// # of bytes, or -1 to mean "invalid key - do not use" + int8_t length; +}; + /** * see docs/software/crypto.md for details. * @@ -15,6 +22,8 @@ class CryptoEngine /** Our per packet nonce */ uint8_t nonce[16]; + CryptoKey key; + public: virtual ~CryptoEngine() {} @@ -27,7 +36,7 @@ class CryptoEngine * @param bytes a _static_ buffer that will remain valid for the life of this crypto instance (i.e. this class will cache the * provided pointer) */ - virtual void setKey(size_t numBytes, uint8_t *bytes); + virtual void setKey(const CryptoKey &k); /** * Encrypt a packet diff --git a/src/nrf52/NRF52CryptoEngine.cpp b/src/nrf52/NRF52CryptoEngine.cpp index 2bf16f23f..431fa2e9c 100644 --- a/src/nrf52/NRF52CryptoEngine.cpp +++ b/src/nrf52/NRF52CryptoEngine.cpp @@ -6,30 +6,13 @@ class NRF52CryptoEngine : public CryptoEngine { - /// How many bytes in our key - uint8_t keySize = 0; - const uint8_t *keyBytes; + public: NRF52CryptoEngine() {} ~NRF52CryptoEngine() {} - /** - * Set the key used for encrypt, decrypt. - * - * As a special case: If all bytes are zero, we assume _no encryption_ and send all data in cleartext. - * - * @param numBytes must be 16 (AES128), 32 (AES256) or 0 (no crypt) - * @param bytes a _static_ buffer that will remain valid for the life of this crypto instance (i.e. this class will cache the - * provided pointer) - */ - virtual void setKey(size_t numBytes, uint8_t *bytes) - { - keySize = numBytes; - keyBytes = bytes; - } - /** * Encrypt a packet * @@ -39,11 +22,11 @@ class NRF52CryptoEngine : public CryptoEngine { // DEBUG_MSG("NRF52 encrypt!\n"); - if (keySize != 0) { + if (key.length > 0) { ocrypto_aes_ctr_ctx ctx; initNonce(fromNode, packetNum); - ocrypto_aes_ctr_init(&ctx, keyBytes, keySize, nonce); + ocrypto_aes_ctr_init(&ctx, key.bytes, key.length, nonce); ocrypto_aes_ctr_encrypt(&ctx, bytes, bytes, numBytes); } @@ -53,11 +36,11 @@ class NRF52CryptoEngine : public CryptoEngine { // DEBUG_MSG("NRF52 decrypt!\n"); - if (keySize != 0) { + if (key.length > 0) { ocrypto_aes_ctr_ctx ctx; initNonce(fromNode, packetNum); - ocrypto_aes_ctr_init(&ctx, keyBytes, keySize, nonce); + ocrypto_aes_ctr_init(&ctx, key.bytes, key.length, nonce); ocrypto_aes_ctr_decrypt(&ctx, bytes, bytes, numBytes); } diff --git a/src/portduino/CrossPlatformCryptoEngine.cpp b/src/portduino/CrossPlatformCryptoEngine.cpp index b9e818c0b..06225aa12 100644 --- a/src/portduino/CrossPlatformCryptoEngine.cpp +++ b/src/portduino/CrossPlatformCryptoEngine.cpp @@ -10,9 +10,6 @@ class CrossPlatformCryptoEngine : public CryptoEngine CTRCommon *ctr = NULL; - /// How many bytes in our key - uint8_t keySize = 0; - public: CrossPlatformCryptoEngine() {} @@ -27,9 +24,9 @@ class CrossPlatformCryptoEngine : public CryptoEngine * @param bytes a _static_ buffer that will remain valid for the life of this crypto instance (i.e. this class will cache the * provided pointer) */ - virtual void setKey(size_t numBytes, uint8_t *bytes) + virtual void setKey(const CryptoKey &k) { - keySize = numBytes; + CryptoEngine::setKey(k); DEBUG_MSG("Installing AES%d key!\n", numBytes * 8); if (ctr) { delete ctr; @@ -41,7 +38,7 @@ class CrossPlatformCryptoEngine : public CryptoEngine else ctr = new CTR(); - ctr->setKey(bytes, numBytes); + ctr->setKey(key.bytes, key.length); } } @@ -52,7 +49,7 @@ class CrossPlatformCryptoEngine : public CryptoEngine */ virtual void encrypt(uint32_t fromNode, uint64_t packetNum, size_t numBytes, uint8_t *bytes) { - if (keySize != 0) { + if (key.length > 0) { uint8_t stream_block[16]; static uint8_t scratch[MAX_BLOCKSIZE]; size_t nc_off = 0; From ae6b7e7259c5caa4da3e90342264b0e67afe5346 Mon Sep 17 00:00:00 2001 From: Kevin Hester Date: Tue, 23 Feb 2021 10:45:03 +0800 Subject: [PATCH 160/258] multichannel code is done! (only basic testing completed though) --- docs/software/TODO.md | 8 +++++--- src/mesh/Channels.cpp | 15 +++++++++++---- src/mesh/Channels.h | 24 ++++++++++++----------- src/mesh/Router.cpp | 44 +++++++++++++++++++++---------------------- 4 files changed, 51 insertions(+), 40 deletions(-) diff --git a/docs/software/TODO.md b/docs/software/TODO.md index b30b58795..232ea2122 100644 --- a/docs/software/TODO.md +++ b/docs/software/TODO.md @@ -5,8 +5,8 @@ You probably don't care about this section - skip to the next one. 1.2 cleanup & multichannel support: * DONE call RouterPlugin for *all* packets - not just Router packets -* generate channel hash from the name of the channel+the psk (not just one or the other) -* send a hint that can be used to select which channel to try and hash against with each message +* DONE generate channel hash from the name of the channel+the psk (not just one or the other) +* DONE send a hint that can be used to select which channel to try and hash against with each message * DONE remove deprecated * DONE fix setchannel in phoneapi.cpp * DONE set mynodeinfo.max_channels @@ -15,7 +15,9 @@ You probably don't care about this section - skip to the next one. * DONE enable remote setttings access by moving settings operations into a regular plugin (move settings ops out of PhoneAPI) * DONE move portnum up? * DONE remove region specific builds from the firmware -* restrict settings operations to the admin channel +* test single channel +* test multi channel +* restrict gpio & serial & settings operations to the admin channel (unless local to the current node) * add gui in android app for setting region * make an alpha channel for the python API * "FIXME - move the radioconfig/user/channel READ operations into SettingsMessage as well" diff --git a/src/mesh/Channels.cpp b/src/mesh/Channels.cpp index f3238b9c5..3e1ea3185 100644 --- a/src/mesh/Channels.cpp +++ b/src/mesh/Channels.cpp @@ -192,7 +192,7 @@ void Channels::setChannel(const Channel &c) // if this is the new primary, demote any existing roles if (c.role == Channel_Role_PRIMARY) - for (int i = 0; i < devicestate.channels_count; i++) + for (int i = 0; i < getNumChannels(); i++) if (devicestate.channels[i].role == Channel_Role_PRIMARY) devicestate.channels[i].role = Channel_Role_SECONDARY; @@ -271,11 +271,18 @@ const char *Channels::getPrimaryName() * * This method is called before decoding inbound packets * - * @return -1 if no suitable channel could be found, otherwise returns the channel index + * @return false if the channel hash or channel is invalid */ -int16_t Channels::setActiveByHash(ChannelHash channelHash) +bool Channels::decryptForHash(ChannelIndex chIndex, ChannelHash channelHash) { - // fixme cant work; + if(chIndex > getNumChannels() || getHash(chIndex) != channelHash) { + DEBUG_MSG("Skipping channel %d due to invalid hash/index\n", chIndex); + return false; + } + else { + setCrypto(chIndex); + return true; + } } /** Given a channel index setup crypto for encoding that channel (or the primary channel if that channel is unsecured) diff --git a/src/mesh/Channels.h b/src/mesh/Channels.h index 4e70e2304..547b0a581 100644 --- a/src/mesh/Channels.h +++ b/src/mesh/Channels.h @@ -1,16 +1,17 @@ #pragma once +#include "CryptoEngine.h" +#include "NodeDB.h" #include "mesh-pb-constants.h" #include -#include "CryptoEngine.h" /** A channel number (index into the channel table) */ typedef uint8_t ChannelIndex; -/** A low quality hash of the channel PSK and the channel name. created by generateHash(chIndex) +/** A low quality hash of the channel PSK and the channel name. created by generateHash(chIndex) * Used as a hint to limit which PSKs are considered for packet decoding. -*/ + */ typedef uint8_t ChannelHash; /** The container/on device API for working with channels */ @@ -22,7 +23,7 @@ class Channels /** The channel index that was requested for sending/receving. Note: if this channel is a secondary channel and does not have a PSK, we will use the PSK from the primary channel. If this channel is disabled no sending or receiving will be allowed */ - ChannelIndex activeChannelIndex = 0; + ChannelIndex activeChannelIndex = 0; /// the precomputed hashes for each of our channels, or -1 for invalid int16_t hashes[MAX_NUM_CHANNELS]; @@ -43,6 +44,8 @@ class Channels /** The index of the primary channel */ ChannelIndex getPrimaryIndex() const { return primaryIndex; } + ChannelIndex getNumChannels() { return devicestate.channels_count; } + /** * Generate a short suffix used to disambiguate channels that might have the same "name" entered by the human but different PSKs. @@ -72,9 +75,9 @@ class Channels * * This method is called before decoding inbound packets * - * @return -1 if no suitable channel could be found, otherwise returns the channel index + * @return false if the channel hash or channel is invalid */ - int16_t setActiveByHash(ChannelHash channelHash); + bool decryptForHash(ChannelIndex chIndex, ChannelHash channelHash); /** Given a channel index setup crypto for encoding that channel (or the primary channel if that channel is unsecured) * @@ -86,7 +89,7 @@ class Channels private: /** Given a channel index, change to use the crypto key specified by that index - * + * * @eturn the (0 to 255) hash for that channel - if no suitable channel could be found, return -1 */ int16_t setCrypto(ChannelIndex chIndex); @@ -96,7 +99,7 @@ class Channels /** Given a channel number, return the (0 to 255) hash for that channel * If no suitable channel could be found, return -1 - * + * * called by fixupChannel when a new channel is set */ int16_t generateHash(ChannelIndex channelNum); @@ -114,11 +117,10 @@ class Channels void initDefaultChannel(ChannelIndex chIndex); /** - * Return the key used for encrypting this channel (if channel is secondary and no key provided, use the primary channel's PSK) + * Return the key used for encrypting this channel (if channel is secondary and no key provided, use the primary channel's + * PSK) */ CryptoKey getKey(ChannelIndex chIndex); - - }; /// Singleton channel table diff --git a/src/mesh/Router.cpp b/src/mesh/Router.cpp index 434bdde5d..50e4215b2 100644 --- a/src/mesh/Router.cpp +++ b/src/mesh/Router.cpp @@ -215,31 +215,31 @@ bool Router::perhapsDecode(MeshPacket *p) assert(p->which_payloadVariant == MeshPacket_encrypted_tag); - ChannelHash chHash = p->channel; - int16_t chIndex = channels.setActiveByHash(chHash); - if (chIndex < 0) { - DEBUG_MSG("No suitable channel found for decoding, hash was 0x%x!\n", chHash); - return false; - } else { - p->channel = chIndex; + // Try to find a channel that works with this hash + for (ChannelIndex chIndex = 0; chIndex < channels.getNumChannels(); chIndex++) { + // Try to use this hash/channel pair + if (channels.decryptForHash(chIndex, p->channel)) { + // Try to decrypt the packet if we can + static uint8_t bytes[MAX_RHPACKETLEN]; + memcpy(bytes, p->encrypted.bytes, + p->encrypted + .size); // we have to copy into a scratch buffer, because these bytes are a union with the decoded protobuf + crypto->decrypt(p->from, p->id, p->encrypted.size, bytes); - // Try to decrypt the packet if we can - static uint8_t bytes[MAX_RHPACKETLEN]; - memcpy(bytes, p->encrypted.bytes, - p->encrypted - .size); // we have to copy into a scratch buffer, because these bytes are a union with the decoded protobuf - crypto->decrypt(p->from, p->id, p->encrypted.size, bytes); - - // Take those raw bytes and convert them back into a well structured protobuf we can understand - if (!pb_decode_from_bytes(bytes, p->encrypted.size, Data_fields, &p->decoded)) { - DEBUG_MSG("Invalid protobufs in received mesh packet!\n"); - return false; - } else { - // parsing was successful - p->which_payloadVariant = MeshPacket_decoded_tag; - return true; + // Take those raw bytes and convert them back into a well structured protobuf we can understand + if (!pb_decode_from_bytes(bytes, p->encrypted.size, Data_fields, &p->decoded)) { + DEBUG_MSG("Invalid protobufs in received mesh packet (bad psk?!\n"); + } else { + // parsing was successful + p->channel = chIndex; // change to store the index instead of the hash + p->which_payloadVariant = MeshPacket_decoded_tag; + return true; + } } } + + DEBUG_MSG("No suitable channel found for decoding, hash was 0x%x!\n", p->channel); + return false; } NodeNum Router::getNodeNum() From aa8b86c6b2739af1bcf2d53c315f0d1551df883a Mon Sep 17 00:00:00 2001 From: Kevin Hester Date: Tue, 23 Feb 2021 11:43:30 +0800 Subject: [PATCH 161/258] multichannel send/rx kinda works --- docs/software/TODO.md | 17 +++++++++++------ proto | 2 +- src/mesh/MeshPlugin.cpp | 7 ++++--- src/mesh/NodeDB.cpp | 3 +-- src/mesh/PhoneAPI.h | 4 ---- src/mesh/RadioLibInterface.cpp | 2 +- version.properties | 4 ++-- 7 files changed, 20 insertions(+), 19 deletions(-) diff --git a/docs/software/TODO.md b/docs/software/TODO.md index 232ea2122..c61ce0953 100644 --- a/docs/software/TODO.md +++ b/docs/software/TODO.md @@ -15,11 +15,17 @@ You probably don't care about this section - skip to the next one. * DONE enable remote setttings access by moving settings operations into a regular plugin (move settings ops out of PhoneAPI) * DONE move portnum up? * DONE remove region specific builds from the firmware -* test single channel +* test single channel without python +* test single channel with python +* implement 'get channels' Admin operation +* use get-channels from python +* use set-channel from python * test multi channel +* pick default random admin key * restrict gpio & serial & settings operations to the admin channel (unless local to the current node) * add gui in android app for setting region -* make an alpha channel for the python API +* warn in python api if we are too new to talk to the device code +* make a post warning about 1.2, telling how to stay on old android & python clients. link to this from the android dialog message and python version warning. * "FIXME - move the radioconfig/user/channel READ operations into SettingsMessage as well" * DONE scrub protobufs to make sure they are absoloute minimum wiresize (in particular Data, ChannelSets and positions) * change syncword @@ -34,11 +40,10 @@ You probably don't care about this section - skip to the next one. * DONE make all subpackets different versions of data * DONE move routing control into a data packet * have phoneapi done via plugin -* figure out how to add micro_delta to position, make it so that phone apps don't need to understand it? +* DONE figure out how to add micro_delta to position, make it so that phone apps don't need to understand it? * only send battery updates a max of once a minute -* add multichannel support in python -* add channel selection for sending -* record recevied channel in meshpacket +* add python channel selection for sending +* DONE record recevied channel in meshpacket * test remote settings operations (confirm it works 3 hops away) * add channel restrictions for plugins (and restrict routing plugin to the "control" channel) * make a primaryChannel global and properly maintain it when the phone sends setChannel diff --git a/proto b/proto index f6ff4cc0c..7a5875d96 160000 --- a/proto +++ b/proto @@ -1 +1 @@ -Subproject commit f6ff4cc0c98b201342c32776eeeb9ace83b450dd +Subproject commit 7a5875d9639a0682bd36d7e118bf26d7b4d733be diff --git a/src/mesh/MeshPlugin.cpp b/src/mesh/MeshPlugin.cpp index 763d4d46e..76ac99b6f 100644 --- a/src/mesh/MeshPlugin.cpp +++ b/src/mesh/MeshPlugin.cpp @@ -32,7 +32,8 @@ void MeshPlugin::callPlugins(const MeshPacket &mp) assert(mp.which_payloadVariant == MeshPacket_decoded_tag); // I think we are guarnteed the packet is decoded by this point? // Was this message directed to us specifically? Will be false if we are sniffing someone elses packets - bool toUs = mp.to == NODENUM_BROADCAST || mp.to == nodeDB.getNodeNum(); + auto ourNodeNum = nodeDB.getNodeNum(); + bool toUs = mp.to == NODENUM_BROADCAST || mp.to == ourNodeNum; for (auto i = plugins->begin(); i != plugins->end(); ++i) { auto &pi = **i; @@ -45,8 +46,8 @@ void MeshPlugin::callPlugins(const MeshPacket &mp) bool handled = pi.handleReceived(mp); - // Possibly send replies (but only if the message was directed to us specifically, i.e. not for promiscious sniffing) - if (mp.decoded.want_response && toUs) { + // Possibly send replies (but only if the message was directed to us specifically, i.e. not for promiscious sniffing), also not if we sent it + if (mp.decoded.want_response && toUs && mp.from != ourNodeNum) { pi.sendResponse(mp); DEBUG_MSG("Plugin %s sent a response\n", pi.name); } diff --git a/src/mesh/NodeDB.cpp b/src/mesh/NodeDB.cpp index 6e81acd76..876a66bc5 100644 --- a/src/mesh/NodeDB.cpp +++ b/src/mesh/NodeDB.cpp @@ -148,7 +148,7 @@ void NodeDB::installDefaultDeviceState() // Restore region if possible if (oldRegionCode != RegionCode_Unset) radioConfig.preferences.region = oldRegionCode; - if (oldRegion.length()) + if (oldRegion.length()) // If the old style region was set, try to keep it up-to-date strcpy(myNodeInfo.region, oldRegion.c_str()); } @@ -400,7 +400,6 @@ void NodeDB::updateUser(uint32_t nodeId, const User &p) void NodeDB::updateFrom(const MeshPacket &mp) { if (mp.which_payloadVariant == MeshPacket_decoded_tag) { - const Data &p = mp.decoded; DEBUG_MSG("Update DB node 0x%x, rx_time=%u\n", mp.from, mp.rx_time); NodeInfo *info = getOrCreateNode(mp.from); diff --git a/src/mesh/PhoneAPI.h b/src/mesh/PhoneAPI.h index 6d4e8d626..19c5d0583 100644 --- a/src/mesh/PhoneAPI.h +++ b/src/mesh/PhoneAPI.h @@ -101,10 +101,6 @@ class PhoneAPI */ virtual void onNowHasData(uint32_t fromRadioNum) {} - void handleSetOwner(const User &o); - void handleSetChannel(const Channel &cc); - void handleSetRadio(const RadioConfig &r); - private: /** * Handle a packet that the phone wants us to send. It is our responsibility to free the packet to the pool diff --git a/src/mesh/RadioLibInterface.cpp b/src/mesh/RadioLibInterface.cpp index ab1728126..b3fac2ab8 100644 --- a/src/mesh/RadioLibInterface.cpp +++ b/src/mesh/RadioLibInterface.cpp @@ -274,7 +274,7 @@ void RadioLibInterface::handleReceiveInterrupt() mp->from = h->from; mp->to = h->to; mp->id = h->id; - mp->channel = h->id; + mp->channel = h->channel; assert(HOP_MAX <= PACKET_FLAGS_HOP_MASK); // If hopmax changes, carefully check this code mp->hop_limit = h->flags & PACKET_FLAGS_HOP_MASK; mp->want_ack = !!(h->flags & PACKET_FLAGS_WANT_ACK_MASK); diff --git a/version.properties b/version.properties index 6c1503acd..c77424e6a 100644 --- a/version.properties +++ b/version.properties @@ -1,4 +1,4 @@ [VERSION] major = 1 -minor = 1 -build = 48 +minor = 2 +build = 0 From 256ba8fa1bb76d8e74d09c011ea76d4fdf5cbd9f Mon Sep 17 00:00:00 2001 From: Jm Date: Mon, 22 Feb 2021 20:07:19 -0800 Subject: [PATCH 162/258] partial work, untested --- src/plugins/StoreForwardPlugin.cpp | 66 +++++++++++++++++------------- src/plugins/StoreForwardPlugin.h | 5 ++- 2 files changed, 42 insertions(+), 29 deletions(-) diff --git a/src/plugins/StoreForwardPlugin.cpp b/src/plugins/StoreForwardPlugin.cpp index 213189cd0..ea24313b8 100644 --- a/src/plugins/StoreForwardPlugin.cpp +++ b/src/plugins/StoreForwardPlugin.cpp @@ -9,6 +9,7 @@ #include #define STOREFORWARD_MAX_PACKETS 6000 +#define STOREFORWARD_SEND_HISTORY_SHORT 600 StoreForwardPlugin *storeForwardPlugin; StoreForwardPluginRadio *storeForwardPluginRadio; @@ -45,25 +46,7 @@ int32_t StoreForwardPlugin::runOnce() firstTime = 0; - /* - For PSRAM usage, see: - https://learn.upesy.com/en/programmation/psram.html#psram-tab - */ - - DEBUG_MSG("Total heap: %d\n", ESP.getHeapSize()); - DEBUG_MSG("Free heap: %d\n", ESP.getFreeHeap()); - DEBUG_MSG("Total PSRAM: %d\n", ESP.getPsramSize()); - DEBUG_MSG("Free PSRAM: %d\n", ESP.getFreePsram()); - - PacketHistoryStruct *packetHistory = - (PacketHistoryStruct *)ps_calloc(STOREFORWARD_MAX_PACKETS, sizeof(PacketHistoryStruct)); - - DEBUG_MSG("Total heap: %d\n", ESP.getHeapSize()); - DEBUG_MSG("Free heap: %d\n", ESP.getFreeHeap()); - DEBUG_MSG("Total PSRAM: %d\n", ESP.getPsramSize()); - DEBUG_MSG("Free PSRAM: %d\n", ESP.getFreePsram()); - - DEBUG_MSG("packetHistory Size - %u", sizeof(packetHistory)); + this->populatePSRAM(); // packetHistory[0].bytes; return (10 * 1000); @@ -109,6 +92,30 @@ int32_t StoreForwardPlugin::runOnce() return (INT32_MAX); } +void StoreForwardPlugin::populatePSRAM() +{ + /* + For PSRAM usage, see: + https://learn.upesy.com/en/programmation/psram.html#psram-tab + */ + + DEBUG_MSG("Total heap: %d\n", ESP.getHeapSize()); + DEBUG_MSG("Free heap: %d\n", ESP.getFreeHeap()); + DEBUG_MSG("Total PSRAM: %d\n", ESP.getPsramSize()); + DEBUG_MSG("Free PSRAM: %d\n", ESP.getFreePsram()); + + // PacketHistoryStruct *packetHistory = (PacketHistoryStruct *)ps_calloc(STOREFORWARD_MAX_PACKETS, + // sizeof(PacketHistoryStruct)); + this->packetHistory = (PacketHistoryStruct *)ps_calloc(STOREFORWARD_MAX_PACKETS, sizeof(PacketHistoryStruct)); + + DEBUG_MSG("Total heap: %d\n", ESP.getHeapSize()); + DEBUG_MSG("Free heap: %d\n", ESP.getFreeHeap()); + DEBUG_MSG("Total PSRAM: %d\n", ESP.getPsramSize()); + DEBUG_MSG("Free PSRAM: %d\n", ESP.getFreePsram()); + + DEBUG_MSG("packetHistory Size - %u", sizeof(packetHistory)); +} + // We saw a node. uint32_t StoreForwardPlugin::sawNode(uint32_t node) { @@ -121,8 +128,9 @@ uint32_t StoreForwardPlugin::sawNode(uint32_t node) TODO: Implment this as a std::map for quicker lookups (maybe it doesn't matter?). */ - - DEBUG_MSG("looking for node - %u\n", node); + // DEBUG_MSG("%s (id=0x%08x Fr0x%02x To0x%02x, WantAck%d, HopLim%d", prefix, p->id, p->from & 0xff, p->to & 0xff, + // p->want_ack, p->hop_limit); + DEBUG_MSG("looking for node - from-0x%08x\n", node); for (int i = 0; i < 50; i++) { // DEBUG_MSG("Iterating through the seen nodes - %u %u %u\n", i, receivedRecord[i][0], receivedRecord[i][1]); // First time seeing that node. @@ -146,19 +154,19 @@ uint32_t StoreForwardPlugin::sawNode(uint32_t node) return 0; } -void StoreForwardPlugin::addHistory(const MeshPacket &mp) +void StoreForwardPlugin::addHistory(const MeshPacket *mp) { auto &p = mp; static uint8_t bytes[MAX_RHPACKETLEN]; - size_t numbytes = pb_encode_to_bytes(bytes, sizeof(bytes), SubPacket_fields, &p.decoded); + size_t numbytes = pb_encode_to_bytes(bytes, sizeof(bytes), SubPacket_fields, &p->decoded); assert(numbytes <= MAX_RHPACKETLEN); DEBUG_MSG("MP numbytes %u\n", numbytes); // destination, source, bytes // memcpy(p->encrypted.bytes, bytes, numbytes); - + memcpy(this->packetHistory[0].bytes, bytes, MAX_RHPACKETLEN); // pb_decode_from_bytes // Serialization is in Router.cpp line 180 @@ -177,10 +185,10 @@ void StoreForwardPlugin::sawNodeReport() TODO: Implment this as a std::map for quicker lookups (maybe it doesn't matter?). */ - DEBUG_MSG("Iterating through the seen nodes ...\n"); + DEBUG_MSG("Iterating through the seen nodes in receivedRecord\n"); for (int i = 0; i < 50; i++) { if (receivedRecord[i][1]) { - DEBUG_MSG("... record-%u node-%u secAgo-%u\n", i, receivedRecord[i][0], (millis() - receivedRecord[i][1]) / 1000); + DEBUG_MSG("... record-%u from-0x%08x secAgo-%u\n", i, receivedRecord[i][0], (millis() - receivedRecord[i][1]) / 1000); } } } @@ -209,9 +217,11 @@ bool StoreForwardPluginRadio::handleReceived(const MeshPacket &mp) if (mp.from != nodeDB.getNodeNum()) { // DEBUG_MSG("Store & Forward Plugin -- Print Start ---------- ---------- ---------- ---------- ----------\n\n\n"); + // DEBUG_MSG("%s (id=0x%08x Fr0x%02x To0x%02x, WantAck%d, HopLim%d", prefix, p->id, p->from & 0xff, p->to & 0xff, + // p->want_ack, p->hop_limit); printPacket("----- PACKET FROM RADIO -----", &mp); - uint32_t sawTime = storeForwardPlugin->sawNode(mp.from); - DEBUG_MSG("We last saw this node (%u), %u sec ago\n", mp.from, (millis() - sawTime) / 1000); + uint32_t sawTime = storeForwardPlugin->sawNode(mp.from & 0xffffffff); + DEBUG_MSG("We last saw this node (%u), %u sec ago\n", mp.from & 0xffffffff, (millis() - sawTime) / 1000); if (mp.decoded.data.portnum == PortNum_UNKNOWN_APP) { DEBUG_MSG("Packet came from - PortNum_UNKNOWN_APP\n"); diff --git a/src/plugins/StoreForwardPlugin.h b/src/plugins/StoreForwardPlugin.h index d7888333e..2b7da6fb9 100644 --- a/src/plugins/StoreForwardPlugin.h +++ b/src/plugins/StoreForwardPlugin.h @@ -20,6 +20,8 @@ class StoreForwardPlugin : private concurrency::OSThread // TODO: Allow configuration of the maximum number of records. uint32_t receivedRecord[50][2] = {{0}}; + PacketHistoryStruct *packetHistory; + public: StoreForwardPlugin(); @@ -29,7 +31,8 @@ class StoreForwardPlugin : private concurrency::OSThread */ uint32_t sawNode(uint32_t); void sawNodeReport(); - void addHistory(const MeshPacket &mp) + void addHistory(const MeshPacket *mp); + void populatePSRAM(); private: // Nothing here From f8d8dc25c0aff49d0b99aa7819e46f1f0f38493a Mon Sep 17 00:00:00 2001 From: Kevin Hester Date: Tue, 23 Feb 2021 14:35:34 +0800 Subject: [PATCH 163/258] properly route messages to phone again --- docs/software/TODO.md | 9 ++++++--- src/mesh/Channels.cpp | 9 ++++----- src/mesh/MeshPlugin.cpp | 4 +++- src/mesh/RadioInterface.cpp | 4 ++-- src/mesh/Router.cpp | 6 +++++- src/plugins/RoutingPlugin.cpp | 10 ++++++++-- src/plugins/RoutingPlugin.h | 3 +++ 7 files changed, 31 insertions(+), 14 deletions(-) diff --git a/docs/software/TODO.md b/docs/software/TODO.md index c61ce0953..9dcfa3781 100644 --- a/docs/software/TODO.md +++ b/docs/software/TODO.md @@ -15,11 +15,14 @@ You probably don't care about this section - skip to the next one. * DONE enable remote setttings access by moving settings operations into a regular plugin (move settings ops out of PhoneAPI) * DONE move portnum up? * DONE remove region specific builds from the firmware -* test single channel without python -* test single channel with python -* implement 'get channels' Admin operation +* DONE test single channel without python +* DONE Use "default" for name if name is empty +* DONE fix python data packet receiving (nothing showing in log?) +* implement 'get channels' Admin plugin operation * use get-channels from python * use set-channel from python +* make python tests more exhaustive +* document the relationship between want_response (indicating remote node received it) and want_ack (indicating that this message should be sent reliably - and also get acks from the first rx node and naks if it is never delivered) * test multi channel * pick default random admin key * restrict gpio & serial & settings operations to the admin channel (unless local to the current node) diff --git a/src/mesh/Channels.cpp b/src/mesh/Channels.cpp index 3e1ea3185..76ea3fb92 100644 --- a/src/mesh/Channels.cpp +++ b/src/mesh/Channels.cpp @@ -28,9 +28,8 @@ int16_t Channels::generateHash(ChannelIndex channelNum) if (k.length < 0) return -1; // invalid else { - Channel &c = getByIndex(channelNum); - - uint8_t h = xorHash((const uint8_t *)c.settings.name, strlen(c.settings.name)); + const char *name = getName(channelNum); + uint8_t h = xorHash((const uint8_t *) name, strlen(name)); h ^= xorHash(k.bytes, k.length); @@ -253,7 +252,7 @@ const char *Channels::getPrimaryName() static char buf[32]; char suffix; - auto channelSettings = getPrimary(); + // auto channelSettings = getPrimary(); // if (channelSettings.psk.size != 1) { // We have a standard PSK, so generate a letter based hash. uint8_t code = getHash(primaryIndex); @@ -263,7 +262,7 @@ const char *Channels::getPrimaryName() suffix = '0' + channelSettings.psk.bytes[0]; } */ - snprintf(buf, sizeof(buf), "#%s-%c", channelSettings.name, suffix); + snprintf(buf, sizeof(buf), "#%s-%c", getName(primaryIndex), suffix); return buf; } diff --git a/src/mesh/MeshPlugin.cpp b/src/mesh/MeshPlugin.cpp index 76ac99b6f..a1fdfd2e2 100644 --- a/src/mesh/MeshPlugin.cpp +++ b/src/mesh/MeshPlugin.cpp @@ -41,6 +41,7 @@ void MeshPlugin::callPlugins(const MeshPacket &mp) // We only call plugins that are interested in the packet (and the message is destined to us or we are promiscious) bool wantsPacket = (pi.isPromiscuous || toUs) && pi.wantPacket(&mp); + // DEBUG_MSG("Plugin %s wantsPacket=%d\n", pi.name, wantsPacket); if (wantsPacket) { pluginFound = true; @@ -79,7 +80,8 @@ void MeshPlugin::sendResponse(const MeshPacket &req) { service.sendToMesh(r); } else { - DEBUG_MSG("WARNING: Client requested response but this plugin did not provide\n"); + // Ignore - this is now expected behavior for routing plugin (because it ignores some replies) + // DEBUG_MSG("WARNING: Client requested response but this plugin did not provide\n"); } } diff --git a/src/mesh/RadioInterface.cpp b/src/mesh/RadioInterface.cpp index 93dd55e80..7b8aec605 100644 --- a/src/mesh/RadioInterface.cpp +++ b/src/mesh/RadioInterface.cpp @@ -119,8 +119,8 @@ uint32_t RadioInterface::getTxDelayMsec() void printPacket(const char *prefix, const MeshPacket *p) { - DEBUG_MSG("%s (id=0x%08x Fr0x%02x To0x%02x, WantAck%d, HopLim%d", prefix, p->id, p->from & 0xff, p->to & 0xff, p->want_ack, - p->hop_limit); + DEBUG_MSG("%s (id=0x%08x Fr0x%02x To0x%02x, WantAck%d, HopLim%d Ch0x%x", prefix, p->id, p->from & 0xff, p->to & 0xff, p->want_ack, + p->hop_limit, p->channel); if (p->which_payloadVariant == MeshPacket_decoded_tag) { auto &s = p->decoded; diff --git a/src/mesh/Router.cpp b/src/mesh/Router.cpp index 50e4215b2..a6afe952e 100644 --- a/src/mesh/Router.cpp +++ b/src/mesh/Router.cpp @@ -232,6 +232,7 @@ bool Router::perhapsDecode(MeshPacket *p) } else { // parsing was successful p->channel = chIndex; // change to store the index instead of the hash + // printPacket("decoded message", p); p->which_payloadVariant = MeshPacket_decoded_tag; return true; } @@ -257,7 +258,10 @@ void Router::handleReceived(MeshPacket *p) p->rx_time = getValidTime(RTCQualityFromNet); // store the arrival timestamp for the phone // Take those raw bytes and convert them back into a well structured protobuf we can understand - if (perhapsDecode(p)) { + bool decoded = perhapsDecode(p); + printPacket("handleReceived", p); + DEBUG_MSG("decoded=%d\n", decoded); + if (decoded) { // parsing was successful, queue for our recipient // call any promiscious plugins here, make a (non promisiocous) plugin for forwarding messages to phone api diff --git a/src/plugins/RoutingPlugin.cpp b/src/plugins/RoutingPlugin.cpp index 58b3f08ae..9af7d31ff 100644 --- a/src/plugins/RoutingPlugin.cpp +++ b/src/plugins/RoutingPlugin.cpp @@ -9,6 +9,7 @@ RoutingPlugin *routingPlugin; bool RoutingPlugin::handleReceivedProtobuf(const MeshPacket &mp, const Routing *r) { + DEBUG_MSG("Routing sniffing", &mp); router->sniffReceived(&mp, r); // FIXME - move this to a non promsicious PhoneAPI plugin? @@ -23,8 +24,13 @@ bool RoutingPlugin::handleReceivedProtobuf(const MeshPacket &mp, const Routing * MeshPacket *RoutingPlugin::allocReply() { - assert(0); // 1.2 refactoring fixme, Not sure if anything needs this yet? - // return allocDataProtobuf(u); + assert(currentRequest); + + // We only consider making replies if the request was a legit routing packet (not just something we were sniffing) + if(currentRequest->decoded.portnum == PortNum_ROUTING_APP) { + assert(0); // 1.2 refactoring fixme, Not sure if anything needs this yet? + // return allocDataProtobuf(u); + } return NULL; } diff --git a/src/plugins/RoutingPlugin.h b/src/plugins/RoutingPlugin.h index 0d987f39e..a848bc9c4 100644 --- a/src/plugins/RoutingPlugin.h +++ b/src/plugins/RoutingPlugin.h @@ -25,6 +25,9 @@ class RoutingPlugin : public ProtobufPlugin * so that subclasses can (optionally) send a response back to the original sender. */ virtual MeshPacket *allocReply(); + /// Override wantPacket to say we want to see all packets, not just those for our port number + virtual bool wantPacket(const MeshPacket *p) { return true; } + void sendAckNak(Routing_Error err, NodeNum to, PacketId idFrom); }; From 4b07f9e160f90d4ad059305dcdcdabafb3e1b80e Mon Sep 17 00:00:00 2001 From: Kevin Hester Date: Tue, 23 Feb 2021 14:45:02 +0800 Subject: [PATCH 164/258] todo update --- docs/software/TODO.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/software/TODO.md b/docs/software/TODO.md index 9dcfa3781..564f11f2d 100644 --- a/docs/software/TODO.md +++ b/docs/software/TODO.md @@ -21,6 +21,7 @@ You probably don't care about this section - skip to the next one. * implement 'get channels' Admin plugin operation * use get-channels from python * use set-channel from python +* use portuino TCP connection to debug with python API * make python tests more exhaustive * document the relationship between want_response (indicating remote node received it) and want_ack (indicating that this message should be sent reliably - and also get acks from the first rx node and naks if it is never delivered) * test multi channel From ada05a1374c89f4db0db388e900de0c4211c3847 Mon Sep 17 00:00:00 2001 From: Kevin Hester Date: Tue, 23 Feb 2021 16:56:28 +0800 Subject: [PATCH 165/258] fix linux --- src/portduino/CrossPlatformCryptoEngine.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/portduino/CrossPlatformCryptoEngine.cpp b/src/portduino/CrossPlatformCryptoEngine.cpp index 06225aa12..1f31d592b 100644 --- a/src/portduino/CrossPlatformCryptoEngine.cpp +++ b/src/portduino/CrossPlatformCryptoEngine.cpp @@ -27,13 +27,13 @@ class CrossPlatformCryptoEngine : public CryptoEngine virtual void setKey(const CryptoKey &k) { CryptoEngine::setKey(k); - DEBUG_MSG("Installing AES%d key!\n", numBytes * 8); + DEBUG_MSG("Installing AES%d key!\n", key.length * 8); if (ctr) { delete ctr; ctr = NULL; } - if (numBytes != 0) { - if (numBytes == 16) + if (key.length != 0) { + if (key.length == 16) ctr = new CTR(); else ctr = new CTR(); From 245638a1d4ad009e14a140ee966d8b5977e7b10d Mon Sep 17 00:00:00 2001 From: Kevin Hester Date: Tue, 23 Feb 2021 17:07:38 +0800 Subject: [PATCH 166/258] get more parallism in CI build --- .github/workflows/main.yml | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 5f17d9176..b7dfa69fb 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -4,8 +4,7 @@ on: - pull_request jobs: - main: - name: Main + setup: runs-on: ubuntu-latest steps: - uses: actions/checkout@master @@ -25,12 +24,26 @@ jobs: - name: Install libs needed for linux build run: | sudo apt install -y libpsocksxx-dev + + build-esp: + needs: setup + runs-on: ubuntu-latest + steps: - name: Build for tbeam run: platformio run -e tbeam - name: Build for heltec run: platformio run -e heltec + + build-nrf: + needs: setup + runs-on: ubuntu-latest + steps: - name: Build for lora-relay-v1 run: platformio run -e lora-relay-v1 + + build-portduino: + needs: setup + runs-on: ubuntu-latest + steps: - name: Build for linux - run: platformio run -e linux - + run: platformio run -e linux \ No newline at end of file From 577336d2df034796d8f9a0c4771e27d0b7e0ef9c Mon Sep 17 00:00:00 2001 From: Kevin Hester Date: Tue, 23 Feb 2021 17:16:12 +0800 Subject: [PATCH 167/258] oh well - github actions defeated me --- .github/workflows/main.yml | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index b7dfa69fb..9c9b2fffd 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -24,26 +24,11 @@ jobs: - name: Install libs needed for linux build run: | sudo apt install -y libpsocksxx-dev - - build-esp: - needs: setup - runs-on: ubuntu-latest - steps: - name: Build for tbeam run: platformio run -e tbeam - name: Build for heltec run: platformio run -e heltec - - build-nrf: - needs: setup - runs-on: ubuntu-latest - steps: - name: Build for lora-relay-v1 run: platformio run -e lora-relay-v1 - - build-portduino: - needs: setup - runs-on: ubuntu-latest - steps: - name: Build for linux run: platformio run -e linux \ No newline at end of file From 5f3f62ed468ffc3a62d1ec03c445ea080abdbd67 Mon Sep 17 00:00:00 2001 From: Niko <38405119+Eninspace@users.noreply.github.com> Date: Wed, 24 Feb 2021 13:45:21 +0300 Subject: [PATCH 168/258] Update README.md Added Russian community group link --- docs/README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/README.md b/docs/README.md index 982bb4f67..e268de0d7 100644 --- a/docs/README.md +++ b/docs/README.md @@ -42,6 +42,7 @@ For an detailed walk-through aimed at beginners, we recommend [meshtastic.letsta ### Related Groups Telegram group for **Italy**-based users [t.me/meshtastic_italia](http://t.me/meshtastic_italia) (Italian language, unofficial). +Telegram group for **Russian**-based users [t.me/meshtastic_russia](https://t.me/meshtastic_russia) (Russian language, unofficial). # Updates From b2c47a7deac2a63df71d0feb906c6a6a387ab26d Mon Sep 17 00:00:00 2001 From: Kevin Hester Date: Thu, 25 Feb 2021 08:50:46 +0800 Subject: [PATCH 169/258] fix #710. nodes disappearing from map. thanks @DylanHoen for noticing! --- src/mesh/NodeDB.cpp | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/src/mesh/NodeDB.cpp b/src/mesh/NodeDB.cpp index b8f0b5697..5680b6870 100644 --- a/src/mesh/NodeDB.cpp +++ b/src/mesh/NodeDB.cpp @@ -7,7 +7,6 @@ #include "CryptoEngine.h" #include "FSCommon.h" #include "GPS.h" -#include "main.h" #include "MeshRadio.h" #include "NodeDB.h" #include "PacketHistory.h" @@ -16,6 +15,7 @@ #include "Router.h" #include "configuration.h" #include "error.h" +#include "main.h" #include "mesh-pb-constants.h" #include #include @@ -183,7 +183,7 @@ bool NodeDB::resetRadioConfig() memset(activePSK, 0, sizeof(activePSK)); // In case the user provided a short key, we want to pad the rest with zeros memcpy(activePSK, channelSettings.psk.bytes, channelSettings.psk.size); activePSKSize = channelSettings.psk.size; - if(activePSKSize == 0) + if (activePSKSize == 0) DEBUG_MSG("Warning: User disabled encryption\n"); else if (activePSKSize == 1) { // Convert the short single byte variants of psk into variant that can be used more generally @@ -199,12 +199,12 @@ bool NodeDB::resetRadioConfig() uint8_t *last = activePSK + sizeof(defaultpsk) - 1; *last = *last + pskIndex - 1; // index of 1 means no change vs defaultPSK } - } else if(activePSKSize < 16) { + } else if (activePSKSize < 16) { // Error! The user specified only the first few bits of an AES128 key. So by convention we just pad the rest of the key // with zeros DEBUG_MSG("Warning: User provided a too short AES128 key - padding\n"); activePSKSize = 16; - } else if(activePSKSize < 32 && activePSKSize != 16) { + } else if (activePSKSize < 32 && activePSKSize != 16) { // Error! The user specified only the first few bits of an AES256 key. So by convention we just pad the rest of the key // with zeros DEBUG_MSG("Warning: User provided a too short AES256 key - padding\n"); @@ -489,7 +489,15 @@ void NodeDB::updatePosition(uint32_t nodeId, const Position &p) DEBUG_MSG("DB update position node=0x%x time=%u, latI=%d, lonI=%d\n", nodeId, p.time, p.latitude_i, p.longitude_i); - info->position = p; + // Be careful to only update fields that have been set by the sender + if (p.time) + info->position.time = p.time; + if(p.battery_level) + info->position.battery_level = p.battery_level; + if (p.latitude_i || p.longitude_i) { + info->position.latitude_i = p.latitude_i; + info->position.longitude_i = p.longitude_i; + } info->has_position = true; updateGUIforNode = info; notifyObservers(true); // Force an update whether or not our node counts have changed @@ -601,10 +609,9 @@ void recordCriticalError(CriticalErrorCode code, uint32_t address) String lcd = String("Critical error ") + code + "!\n"; screen->print(lcd.c_str()); DEBUG_MSG("NOTE! Recording critical error %d, address=%lx\n", code, address); - + // Record error to DB myNodeInfo.error_code = code; myNodeInfo.error_address = address; myNodeInfo.error_count++; - } From fd6842cb5b0dc93771107ac058205b38a2c2e2c7 Mon Sep 17 00:00:00 2001 From: Jm Date: Wed, 24 Feb 2021 20:27:21 -0800 Subject: [PATCH 170/258] Partial Work, stable build. --- src/plugins/StoreForwardPlugin.cpp | 50 ++++++++++++++++++++++++------ src/plugins/StoreForwardPlugin.h | 9 ++++-- 2 files changed, 46 insertions(+), 13 deletions(-) diff --git a/src/plugins/StoreForwardPlugin.cpp b/src/plugins/StoreForwardPlugin.cpp index ea24313b8..0550b7af0 100644 --- a/src/plugins/StoreForwardPlugin.cpp +++ b/src/plugins/StoreForwardPlugin.cpp @@ -8,7 +8,7 @@ #include #include -#define STOREFORWARD_MAX_PACKETS 6000 +#define STOREFORWARD_MAX_PACKETS 7500 #define STOREFORWARD_SEND_HISTORY_SHORT 600 StoreForwardPlugin *storeForwardPlugin; @@ -26,8 +26,8 @@ int32_t StoreForwardPlugin::runOnce() without having to configure it from the PythonAPI or WebUI. */ - radioConfig.preferences.store_forward_plugin_enabled = 1; - radioConfig.preferences.is_router = 1; + // radioConfig.preferences.store_forward_plugin_enabled = 1; + // radioConfig.preferences.is_router = 1; if (radioConfig.preferences.store_forward_plugin_enabled) { @@ -79,6 +79,7 @@ int32_t StoreForwardPlugin::runOnce() // Maybe some cleanup functions? this->sawNodeReport(); + this->historyReport(); return (10 * 1000); } @@ -99,6 +100,8 @@ void StoreForwardPlugin::populatePSRAM() https://learn.upesy.com/en/programmation/psram.html#psram-tab */ + DEBUG_MSG("Before PSRAM initilization\n"); + DEBUG_MSG("Total heap: %d\n", ESP.getHeapSize()); DEBUG_MSG("Free heap: %d\n", ESP.getFreeHeap()); DEBUG_MSG("Total PSRAM: %d\n", ESP.getPsramSize()); @@ -107,6 +110,7 @@ void StoreForwardPlugin::populatePSRAM() // PacketHistoryStruct *packetHistory = (PacketHistoryStruct *)ps_calloc(STOREFORWARD_MAX_PACKETS, // sizeof(PacketHistoryStruct)); this->packetHistory = (PacketHistoryStruct *)ps_calloc(STOREFORWARD_MAX_PACKETS, sizeof(PacketHistoryStruct)); + DEBUG_MSG("After PSRAM initilization\n"); DEBUG_MSG("Total heap: %d\n", ESP.getHeapSize()); DEBUG_MSG("Free heap: %d\n", ESP.getFreeHeap()); @@ -154,7 +158,28 @@ uint32_t StoreForwardPlugin::sawNode(uint32_t node) return 0; } -void StoreForwardPlugin::addHistory(const MeshPacket *mp) +void StoreForwardPlugin::historyReport() +{ + DEBUG_MSG("Iterating through the message history...\n"); + DEBUG_MSG("Message history contains %u records\n", this->packetHistoryCurrent); + uint32_t startTimer = millis(); + for (int i = 0; i < this->packetHistoryCurrent; i++) { + if (this->packetHistory[i].time) { + // DEBUG_MSG("... time-%u to-0x%08x\n", this->packetHistory[i].time, this->packetHistory[i].to & 0xffffffff); + } + } + DEBUG_MSG("StoreForwardPlugin::historyReport runtime - %u ms\n", millis() - startTimer); +} +void StoreForwardPlugin::historySend(uint32_t msAgo, uint32_t to) +{ + for (int i = 0; i < this->packetHistoryCurrent; i++) { + if (this->packetHistory[i].time) { + // DEBUG_MSG("... time-%u to-0x%08x\n", this->packetHistory[i].time, this->packetHistory[i].to & 0xffffffff); + } + } +} + +void StoreForwardPlugin::historyAdd(const MeshPacket *mp) { auto &p = mp; @@ -166,10 +191,10 @@ void StoreForwardPlugin::addHistory(const MeshPacket *mp) // destination, source, bytes // memcpy(p->encrypted.bytes, bytes, numbytes); - memcpy(this->packetHistory[0].bytes, bytes, MAX_RHPACKETLEN); - // pb_decode_from_bytes - - // Serialization is in Router.cpp line 180 + memcpy(this->packetHistory[this->packetHistoryCurrent].bytes, bytes, MAX_RHPACKETLEN); + this->packetHistory[this->packetHistoryCurrent].time = millis(); + this->packetHistory[this->packetHistoryCurrent].to = mp->to; + this->packetHistoryCurrent++; } // We saw a node. @@ -185,7 +210,7 @@ void StoreForwardPlugin::sawNodeReport() TODO: Implment this as a std::map for quicker lookups (maybe it doesn't matter?). */ - DEBUG_MSG("Iterating through the seen nodes in receivedRecord\n"); + DEBUG_MSG("Iterating through the seen nodes in receivedRecord...\n"); for (int i = 0; i < 50; i++) { if (receivedRecord[i][1]) { DEBUG_MSG("... record-%u from-0x%08x secAgo-%u\n", i, receivedRecord[i][0], (millis() - receivedRecord[i][1]) / 1000); @@ -228,7 +253,7 @@ bool StoreForwardPluginRadio::handleReceived(const MeshPacket &mp) } else if (mp.decoded.data.portnum == PortNum_TEXT_MESSAGE_APP) { DEBUG_MSG("Packet came from - PortNum_TEXT_MESSAGE_APP\n"); - storeForwardPlugin->addHistory(&mp); + storeForwardPlugin->historyAdd(&mp); } else if (mp.decoded.data.portnum == PortNum_REMOTE_HARDWARE_APP) { DEBUG_MSG("Packet came from - PortNum_REMOTE_HARDWARE_APP\n"); @@ -255,6 +280,11 @@ bool StoreForwardPluginRadio::handleReceived(const MeshPacket &mp) } else { DEBUG_MSG("Packet came from an unknown port %u\n", mp.decoded.data.portnum); } + + if ((millis() - sawTime) > STOREFORWARD_SEND_HISTORY_SHORT) { + // Node has been away for a while. + storeForwardPlugin->historySend(sawTime, mp.from); + } } } else { diff --git a/src/plugins/StoreForwardPlugin.h b/src/plugins/StoreForwardPlugin.h index 2b7da6fb9..e49b38fe9 100644 --- a/src/plugins/StoreForwardPlugin.h +++ b/src/plugins/StoreForwardPlugin.h @@ -6,9 +6,11 @@ #include #include + struct PacketHistoryStruct { uint32_t time; uint32_t to; + bool ack; uint8_t bytes[MAX_RHPACKETLEN]; }; @@ -16,11 +18,10 @@ class StoreForwardPlugin : private concurrency::OSThread { bool firstTime = 1; - // TODO: Move this into the PSRAM - // TODO: Allow configuration of the maximum number of records. uint32_t receivedRecord[50][2] = {{0}}; PacketHistoryStruct *packetHistory; + uint32_t packetHistoryCurrent = 0; public: StoreForwardPlugin(); @@ -31,7 +32,9 @@ class StoreForwardPlugin : private concurrency::OSThread */ uint32_t sawNode(uint32_t); void sawNodeReport(); - void addHistory(const MeshPacket *mp); + void historyAdd(const MeshPacket *mp); + void historyReport(); + void historySend(uint32_t msAgo, uint32_t to); void populatePSRAM(); private: From 204c42234c35d89d06ff39f3df0a896ebbba0adc Mon Sep 17 00:00:00 2001 From: Niko <38405119+Eninspace@users.noreply.github.com> Date: Thu, 25 Feb 2021 13:12:47 +0300 Subject: [PATCH 171/258] Update README.md Added line break --- docs/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/README.md b/docs/README.md index e268de0d7..4a124156f 100644 --- a/docs/README.md +++ b/docs/README.md @@ -41,7 +41,7 @@ For an detailed walk-through aimed at beginners, we recommend [meshtastic.letsta ### Related Groups -Telegram group for **Italy**-based users [t.me/meshtastic_italia](http://t.me/meshtastic_italia) (Italian language, unofficial). +Telegram group for **Italy**-based users [t.me/meshtastic_italia](http://t.me/meshtastic_italia) (Italian language, unofficial).
Telegram group for **Russian**-based users [t.me/meshtastic_russia](https://t.me/meshtastic_russia) (Russian language, unofficial). # Updates From afc901ddbe208c4d2accaac9c6f697ade5482e4d Mon Sep 17 00:00:00 2001 From: Kevin Hester Date: Thu, 25 Feb 2021 19:49:34 +0800 Subject: [PATCH 172/258] fix build. platformio isn't smart enough to git pull latest without specifying a tag/commit/etc (I haven't tried specifying a branch?) Without specifying the hash, the build breaks for anyone who already had a repo (the CI build doesn't see this because it always pulls from scratch) cc @crossan007 & @mc-hamster --- platformio.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platformio.ini b/platformio.ini index 39b57dd9c..9c179724e 100644 --- a/platformio.ini +++ b/platformio.ini @@ -65,7 +65,7 @@ debug_tool = jlink ; monitor adapter_khz 10000 lib_deps = - https://github.com/meshtastic/esp8266-oled-ssd1306.git ; ESP8266_SSD1306 + https://github.com/meshtastic/esp8266-oled-ssd1306.git#35d796226b853b0c0ff818b2f1aa3d35e7296a96 ; ESP8266_SSD1306 https://github.com/geeksville/OneButton.git ; OneButton library for non-blocking button debounce 1202 ; CRC32, explicitly needed because dependency is missing in the ble ota update lib https://github.com/meshtastic/arduino-fsm.git#2f106146071fc7bc620e1e8d4b88dc4e0266ce39 From 8ba43e174557bc00d998cea3dd549d525dc320e0 Mon Sep 17 00:00:00 2001 From: Kevin Hester Date: Thu, 25 Feb 2021 20:02:32 +0800 Subject: [PATCH 173/258] merge latest from master --- proto | 2 +- src/mesh/generated/deviceonly.pb.h | 2 +- src/mesh/generated/mesh.pb.h | 41 ++++++++++++++++++++---------- src/mesh/generated/portnums.pb.h | 2 +- 4 files changed, 31 insertions(+), 16 deletions(-) diff --git a/proto b/proto index f2d342de0..b53818d67 160000 --- a/proto +++ b/proto @@ -1 +1 @@ -Subproject commit f2d342de0ca74e9202c79876afc5aec675150e49 +Subproject commit b53818d67b34bf7a221ae2292cd2cd4af9412253 diff --git a/src/mesh/generated/deviceonly.pb.h b/src/mesh/generated/deviceonly.pb.h index 9ec3fa5a0..01246c70e 100644 --- a/src/mesh/generated/deviceonly.pb.h +++ b/src/mesh/generated/deviceonly.pb.h @@ -80,7 +80,7 @@ extern const pb_msgdesc_t DeviceState_msg; #define DeviceState_fields &DeviceState_msg /* Maximum encoded size of messages (where known) */ -#define DeviceState_size 6125 +#define DeviceState_size 6152 #ifdef __cplusplus } /* extern "C" */ diff --git a/src/mesh/generated/mesh.pb.h b/src/mesh/generated/mesh.pb.h index 6858cdcd9..6ad5945e1 100644 --- a/src/mesh/generated/mesh.pb.h +++ b/src/mesh/generated/mesh.pb.h @@ -217,6 +217,11 @@ typedef struct _RadioConfig_UserPreferences { bool range_test_plugin_save; bool store_forward_plugin_enabled; uint32_t store_forward_plugin_records; + bool environmental_measurement_plugin_measurement_enabled; + bool environmental_measurement_plugin_screen_enabled; + uint32_t environmental_measurement_plugin_read_error_count_threshold; + uint32_t environmental_measurement_plugin_update_interval; + uint32_t environmental_measurement_plugin_recovery_interval; } RadioConfig_UserPreferences; typedef struct _RouteDiscovery { @@ -376,7 +381,7 @@ extern "C" { #define ChannelSettings_init_default {0, _ChannelSettings_ModemConfig_MIN, {0, {0}}, "", 0, 0, 0, 0, 0, 0, 0} #define Channel_init_default {0, false, ChannelSettings_init_default, _Channel_Role_MIN} #define RadioConfig_init_default {false, RadioConfig_UserPreferences_init_default} -#define RadioConfig_UserPreferences_init_default {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, "", "", 0, _RegionCode_MIN, _ChargeCurrent_MIN, _LocationSharing_MIN, _GpsOperation_MIN, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0}, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} +#define RadioConfig_UserPreferences_init_default {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, "", "", 0, _RegionCode_MIN, _ChargeCurrent_MIN, _LocationSharing_MIN, _GpsOperation_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, 0, 0, 0, 0, 0} #define NodeInfo_init_default {0, false, User_init_default, false, Position_init_default, 0, 0} #define MyNodeInfo_init_default {0, 0, 0, "", "", "", _CriticalErrorCode_MIN, 0, 0, 0, 0, 0} #define LogRecord_init_default {"", 0, "", _LogRecord_Level_MIN} @@ -392,7 +397,7 @@ extern "C" { #define ChannelSettings_init_zero {0, _ChannelSettings_ModemConfig_MIN, {0, {0}}, "", 0, 0, 0, 0, 0, 0, 0} #define Channel_init_zero {0, false, ChannelSettings_init_zero, _Channel_Role_MIN} #define RadioConfig_init_zero {false, RadioConfig_UserPreferences_init_zero} -#define RadioConfig_UserPreferences_init_zero {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, "", "", 0, _RegionCode_MIN, _ChargeCurrent_MIN, _LocationSharing_MIN, _GpsOperation_MIN, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0}, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} +#define RadioConfig_UserPreferences_init_zero {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, "", "", 0, _RegionCode_MIN, _ChargeCurrent_MIN, _LocationSharing_MIN, _GpsOperation_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, 0, 0, 0, 0, 0} #define NodeInfo_init_zero {0, false, User_init_zero, false, Position_init_zero, 0, 0} #define MyNodeInfo_init_zero {0, 0, 0, "", "", "", _CriticalErrorCode_MIN, 0, 0, 0, 0, 0} #define LogRecord_init_zero {"", 0, "", _LogRecord_Level_MIN} @@ -480,6 +485,11 @@ extern "C" { #define RadioConfig_UserPreferences_range_test_plugin_save_tag 134 #define RadioConfig_UserPreferences_store_forward_plugin_enabled_tag 136 #define RadioConfig_UserPreferences_store_forward_plugin_records_tag 137 +#define RadioConfig_UserPreferences_environmental_measurement_plugin_measurement_enabled_tag 140 +#define RadioConfig_UserPreferences_environmental_measurement_plugin_screen_enabled_tag 141 +#define RadioConfig_UserPreferences_environmental_measurement_plugin_read_error_count_threshold_tag 142 +#define RadioConfig_UserPreferences_environmental_measurement_plugin_update_interval_tag 143 +#define RadioConfig_UserPreferences_environmental_measurement_plugin_recovery_interval_tag 144 #define RouteDiscovery_route_tag 2 #define User_id_tag 1 #define User_long_name_tag 2 @@ -496,9 +506,9 @@ extern "C" { #define MeshPacket_id_tag 6 #define MeshPacket_rx_time_tag 7 #define MeshPacket_rx_snr_tag 8 -#define MeshPacket_hop_limit_tag 9 -#define MeshPacket_want_ack_tag 10 -#define MeshPacket_priority_tag 11 +#define MeshPacket_hop_limit_tag 10 +#define MeshPacket_want_ack_tag 11 +#define MeshPacket_priority_tag 12 #define NodeInfo_num_tag 1 #define NodeInfo_user_tag 2 #define NodeInfo_position_tag 3 @@ -579,9 +589,9 @@ X(a, STATIC, ONEOF, BYTES, (payloadVariant,encrypted,encrypted), 5) \ X(a, STATIC, SINGULAR, FIXED32, id, 6) \ X(a, STATIC, SINGULAR, FIXED32, rx_time, 7) \ X(a, STATIC, SINGULAR, FLOAT, rx_snr, 8) \ -X(a, STATIC, SINGULAR, UINT32, hop_limit, 9) \ -X(a, STATIC, SINGULAR, BOOL, want_ack, 10) \ -X(a, STATIC, SINGULAR, UENUM, priority, 11) +X(a, STATIC, SINGULAR, UINT32, hop_limit, 10) \ +X(a, STATIC, SINGULAR, BOOL, want_ack, 11) \ +X(a, STATIC, SINGULAR, UENUM, priority, 12) #define MeshPacket_CALLBACK NULL #define MeshPacket_DEFAULT NULL #define MeshPacket_payloadVariant_decoded_MSGTYPE Data @@ -657,7 +667,12 @@ X(a, STATIC, SINGULAR, BOOL, range_test_plugin_enabled, 132) \ X(a, STATIC, SINGULAR, UINT32, range_test_plugin_sender, 133) \ X(a, STATIC, SINGULAR, BOOL, range_test_plugin_save, 134) \ X(a, STATIC, SINGULAR, BOOL, store_forward_plugin_enabled, 136) \ -X(a, STATIC, SINGULAR, UINT32, store_forward_plugin_records, 137) +X(a, STATIC, SINGULAR, UINT32, store_forward_plugin_records, 137) \ +X(a, STATIC, SINGULAR, BOOL, environmental_measurement_plugin_measurement_enabled, 140) \ +X(a, STATIC, SINGULAR, BOOL, environmental_measurement_plugin_screen_enabled, 141) \ +X(a, STATIC, SINGULAR, UINT32, environmental_measurement_plugin_read_error_count_threshold, 142) \ +X(a, STATIC, SINGULAR, UINT32, environmental_measurement_plugin_update_interval, 143) \ +X(a, STATIC, SINGULAR, UINT32, environmental_measurement_plugin_recovery_interval, 144) #define RadioConfig_UserPreferences_CALLBACK NULL #define RadioConfig_UserPreferences_DEFAULT NULL @@ -776,14 +791,14 @@ extern const pb_msgdesc_t AdminMessage_msg; #define MeshPacket_size 297 #define ChannelSettings_size 87 #define Channel_size 94 -#define RadioConfig_size 308 -#define RadioConfig_UserPreferences_size 305 +#define RadioConfig_size 335 +#define RadioConfig_UserPreferences_size 332 #define NodeInfo_size 130 #define MyNodeInfo_size 89 #define LogRecord_size 81 -#define FromRadio_size 317 +#define FromRadio_size 344 #define ToRadio_size 300 -#define AdminMessage_size 311 +#define AdminMessage_size 338 #ifdef __cplusplus } /* extern "C" */ diff --git a/src/mesh/generated/portnums.pb.h b/src/mesh/generated/portnums.pb.h index 5904a548c..758db47a6 100644 --- a/src/mesh/generated/portnums.pb.h +++ b/src/mesh/generated/portnums.pb.h @@ -20,10 +20,10 @@ typedef enum _PortNum { PortNum_ADMIN_APP = 6, PortNum_REPLY_APP = 32, PortNum_IP_TUNNEL_APP = 33, + PortNum_ENVIRONMENTAL_MEASUREMENT_APP = 34, PortNum_SERIAL_APP = 64, PortNum_STORE_FORWARD_APP = 65, PortNum_RANGE_TEST_APP = 66, - PortNum_ENVIRONMENTAL_MEASUREMENT_APP = 67, PortNum_PRIVATE_APP = 256, PortNum_ATAK_FORWARDER = 257, PortNum_MAX = 511 From 5ae4edf8fd5e36eb342d7300903cfd3d78775bc3 Mon Sep 17 00:00:00 2001 From: Kevin Hester Date: Thu, 25 Feb 2021 20:36:37 +0800 Subject: [PATCH 174/258] move admin out of core proto --- proto | 2 +- src/mesh/generated/admin.pb.c | 12 ++++++ src/mesh/generated/admin.pb.h | 66 ++++++++++++++++++++++++++++++ src/mesh/generated/deviceonly.pb.h | 2 +- src/mesh/generated/mesh.pb.c | 3 -- src/mesh/generated/mesh.pb.h | 33 ++------------- src/mesh/mesh-pb-constants.h | 1 + 7 files changed, 84 insertions(+), 35 deletions(-) create mode 100644 src/mesh/generated/admin.pb.c create mode 100644 src/mesh/generated/admin.pb.h diff --git a/proto b/proto index b53818d67..75ae9929a 160000 --- a/proto +++ b/proto @@ -1 +1 @@ -Subproject commit b53818d67b34bf7a221ae2292cd2cd4af9412253 +Subproject commit 75ae9929a22a0cfa65059f30b27485f2ae8f3a63 diff --git a/src/mesh/generated/admin.pb.c b/src/mesh/generated/admin.pb.c new file mode 100644 index 000000000..4b90c51ae --- /dev/null +++ b/src/mesh/generated/admin.pb.c @@ -0,0 +1,12 @@ +/* Automatically generated nanopb constant definitions */ +/* Generated by nanopb-0.4.4 */ + +#include "admin.pb.h" +#if PB_PROTO_HEADER_VERSION != 40 +#error Regenerate this file with the current version of nanopb generator. +#endif + +PB_BIND(AdminMessage, AdminMessage, 2) + + + diff --git a/src/mesh/generated/admin.pb.h b/src/mesh/generated/admin.pb.h new file mode 100644 index 000000000..b3d29825a --- /dev/null +++ b/src/mesh/generated/admin.pb.h @@ -0,0 +1,66 @@ +/* Automatically generated nanopb header */ +/* Generated by nanopb-0.4.4 */ + +#ifndef PB_ADMIN_PB_H_INCLUDED +#define PB_ADMIN_PB_H_INCLUDED +#include +#include "mesh.pb.h" + +#if PB_PROTO_HEADER_VERSION != 40 +#error Regenerate this file with the current version of nanopb generator. +#endif + +/* Struct definitions */ +typedef struct _AdminMessage { + pb_size_t which_variant; + union { + RadioConfig set_radio; + User set_owner; + Channel set_channel; + bool get_radio; + uint32_t get_channel; + }; +} AdminMessage; + + +#ifdef __cplusplus +extern "C" { +#endif + +/* Initializer values for message structs */ +#define AdminMessage_init_default {0, {RadioConfig_init_default}} +#define AdminMessage_init_zero {0, {RadioConfig_init_zero}} + +/* Field tags (for use in manual encoding/decoding) */ +#define AdminMessage_set_radio_tag 1 +#define AdminMessage_set_owner_tag 2 +#define AdminMessage_set_channel_tag 3 +#define AdminMessage_get_radio_tag 4 +#define AdminMessage_get_channel_tag 5 + +/* Struct field encoding specification for nanopb */ +#define AdminMessage_FIELDLIST(X, a) \ +X(a, STATIC, ONEOF, MESSAGE, (variant,set_radio,set_radio), 1) \ +X(a, STATIC, ONEOF, MESSAGE, (variant,set_owner,set_owner), 2) \ +X(a, STATIC, ONEOF, MESSAGE, (variant,set_channel,set_channel), 3) \ +X(a, STATIC, ONEOF, BOOL, (variant,get_radio,get_radio), 4) \ +X(a, STATIC, ONEOF, UINT32, (variant,get_channel,get_channel), 5) +#define AdminMessage_CALLBACK NULL +#define AdminMessage_DEFAULT NULL +#define AdminMessage_variant_set_radio_MSGTYPE RadioConfig +#define AdminMessage_variant_set_owner_MSGTYPE User +#define AdminMessage_variant_set_channel_MSGTYPE Channel + +extern const pb_msgdesc_t AdminMessage_msg; + +/* Defines for backwards compatibility with code written before nanopb-0.4.0 */ +#define AdminMessage_fields &AdminMessage_msg + +/* Maximum encoded size of messages (where known) */ +#define AdminMessage_size 338 + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif diff --git a/src/mesh/generated/deviceonly.pb.h b/src/mesh/generated/deviceonly.pb.h index 01246c70e..3b81f2240 100644 --- a/src/mesh/generated/deviceonly.pb.h +++ b/src/mesh/generated/deviceonly.pb.h @@ -80,7 +80,7 @@ extern const pb_msgdesc_t DeviceState_msg; #define DeviceState_fields &DeviceState_msg /* Maximum encoded size of messages (where known) */ -#define DeviceState_size 6152 +#define DeviceState_size 6146 #ifdef __cplusplus } /* extern "C" */ diff --git a/src/mesh/generated/mesh.pb.c b/src/mesh/generated/mesh.pb.c index f0b3f8c66..c4fd0d8e5 100644 --- a/src/mesh/generated/mesh.pb.c +++ b/src/mesh/generated/mesh.pb.c @@ -51,9 +51,6 @@ PB_BIND(FromRadio, FromRadio, 2) PB_BIND(ToRadio, ToRadio, 2) -PB_BIND(AdminMessage, AdminMessage, 2) - - diff --git a/src/mesh/generated/mesh.pb.h b/src/mesh/generated/mesh.pb.h index 6ad5945e1..eed90661c 100644 --- a/src/mesh/generated/mesh.pb.h +++ b/src/mesh/generated/mesh.pb.h @@ -247,7 +247,7 @@ typedef PB_BYTES_ARRAY_T(256) MeshPacket_encrypted_t; typedef struct _MeshPacket { uint32_t from; uint32_t to; - uint32_t channel; + uint8_t channel; pb_size_t which_payloadVariant; union { Data decoded; @@ -288,15 +288,6 @@ typedef struct _Routing { uint32_t original_id; } Routing; -typedef struct _AdminMessage { - pb_size_t which_variant; - union { - RadioConfig set_radio; - User set_owner; - Channel set_channel; - }; -} AdminMessage; - typedef struct _FromRadio { uint32_t num; pb_size_t which_payloadVariant; @@ -387,7 +378,6 @@ extern "C" { #define LogRecord_init_default {"", 0, "", _LogRecord_Level_MIN} #define FromRadio_init_default {0, 0, {MyNodeInfo_init_default}} #define ToRadio_init_default {0, {MeshPacket_init_default}} -#define AdminMessage_init_default {0, {RadioConfig_init_default}} #define Position_init_zero {0, 0, 0, 0, 0} #define User_init_zero {"", "", "", {0}} #define RouteDiscovery_init_zero {0, {0, 0, 0, 0, 0, 0, 0, 0}} @@ -403,7 +393,6 @@ extern "C" { #define LogRecord_init_zero {"", 0, "", _LogRecord_Level_MIN} #define FromRadio_init_zero {0, 0, {MyNodeInfo_init_zero}} #define ToRadio_init_zero {0, {MeshPacket_init_zero}} -#define AdminMessage_init_zero {0, {RadioConfig_init_zero}} /* Field tags (for use in manual encoding/decoding) */ #define ChannelSettings_tx_power_tag 1 @@ -521,9 +510,6 @@ extern "C" { #define Routing_success_id_tag 4 #define Routing_fail_id_tag 5 #define Routing_original_id_tag 6 -#define AdminMessage_set_radio_tag 1 -#define AdminMessage_set_owner_tag 2 -#define AdminMessage_set_channel_tag 3 #define FromRadio_num_tag 1 #define FromRadio_my_info_tag 3 #define FromRadio_node_info_tag 4 @@ -737,16 +723,6 @@ X(a, STATIC, ONEOF, UINT32, (payloadVariant,want_config_id,want_config_id #define ToRadio_DEFAULT NULL #define ToRadio_payloadVariant_packet_MSGTYPE MeshPacket -#define AdminMessage_FIELDLIST(X, a) \ -X(a, STATIC, ONEOF, MESSAGE, (variant,set_radio,set_radio), 1) \ -X(a, STATIC, ONEOF, MESSAGE, (variant,set_owner,set_owner), 2) \ -X(a, STATIC, ONEOF, MESSAGE, (variant,set_channel,set_channel), 3) -#define AdminMessage_CALLBACK NULL -#define AdminMessage_DEFAULT NULL -#define AdminMessage_variant_set_radio_MSGTYPE RadioConfig -#define AdminMessage_variant_set_owner_MSGTYPE User -#define AdminMessage_variant_set_channel_MSGTYPE Channel - extern const pb_msgdesc_t Position_msg; extern const pb_msgdesc_t User_msg; extern const pb_msgdesc_t RouteDiscovery_msg; @@ -762,7 +738,6 @@ extern const pb_msgdesc_t MyNodeInfo_msg; extern const pb_msgdesc_t LogRecord_msg; extern const pb_msgdesc_t FromRadio_msg; extern const pb_msgdesc_t ToRadio_msg; -extern const pb_msgdesc_t AdminMessage_msg; /* Defines for backwards compatibility with code written before nanopb-0.4.0 */ #define Position_fields &Position_msg @@ -780,7 +755,6 @@ extern const pb_msgdesc_t AdminMessage_msg; #define LogRecord_fields &LogRecord_msg #define FromRadio_fields &FromRadio_msg #define ToRadio_fields &ToRadio_msg -#define AdminMessage_fields &AdminMessage_msg /* Maximum encoded size of messages (where known) */ #define Position_size 37 @@ -788,7 +762,7 @@ extern const pb_msgdesc_t AdminMessage_msg; #define RouteDiscovery_size 40 #define Routing_size 47 #define Data_size 255 -#define MeshPacket_size 297 +#define MeshPacket_size 294 #define ChannelSettings_size 87 #define Channel_size 94 #define RadioConfig_size 335 @@ -797,8 +771,7 @@ extern const pb_msgdesc_t AdminMessage_msg; #define MyNodeInfo_size 89 #define LogRecord_size 81 #define FromRadio_size 344 -#define ToRadio_size 300 -#define AdminMessage_size 338 +#define ToRadio_size 297 #ifdef __cplusplus } /* extern "C" */ diff --git a/src/mesh/mesh-pb-constants.h b/src/mesh/mesh-pb-constants.h index 21163c496..0b2a0d6cf 100644 --- a/src/mesh/mesh-pb-constants.h +++ b/src/mesh/mesh-pb-constants.h @@ -2,6 +2,7 @@ #include "mesh/generated/mesh.pb.h" #include "mesh/generated/deviceonly.pb.h" +#include "mesh/generated/admin.pb.h" // this file defines constants which come from mesh.options From 30d600040b265f97f907187a1fe12aa56c563e6f Mon Sep 17 00:00:00 2001 From: Jm Casler Date: Thu, 25 Feb 2021 08:12:30 -0800 Subject: [PATCH 175/258] Rename src/plugins/StoreForwardPlugin.cpp to src/plugins/esp32/StoreForwardPlugin.cpp --- src/plugins/{ => esp32}/StoreForwardPlugin.cpp | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename src/plugins/{ => esp32}/StoreForwardPlugin.cpp (100%) diff --git a/src/plugins/StoreForwardPlugin.cpp b/src/plugins/esp32/StoreForwardPlugin.cpp similarity index 100% rename from src/plugins/StoreForwardPlugin.cpp rename to src/plugins/esp32/StoreForwardPlugin.cpp From 14271be81684fc02e6f42871adee612870bd393b Mon Sep 17 00:00:00 2001 From: Jm Casler Date: Thu, 25 Feb 2021 08:12:57 -0800 Subject: [PATCH 176/258] Rename src/plugins/StoreForwardPlugin.h to src/plugins/esp32/StoreForwardPlugin.h --- src/plugins/{ => esp32}/StoreForwardPlugin.h | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename src/plugins/{ => esp32}/StoreForwardPlugin.h (100%) diff --git a/src/plugins/StoreForwardPlugin.h b/src/plugins/esp32/StoreForwardPlugin.h similarity index 100% rename from src/plugins/StoreForwardPlugin.h rename to src/plugins/esp32/StoreForwardPlugin.h From 5f041ea7e93686e39e683c5c135f8adcc0ac3c32 Mon Sep 17 00:00:00 2001 From: Jm Date: Thu, 25 Feb 2021 08:14:07 -0800 Subject: [PATCH 177/258] Update Plugins.cpp --- src/plugins/Plugins.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/plugins/Plugins.cpp b/src/plugins/Plugins.cpp index cfcc21d54..39073ac2d 100644 --- a/src/plugins/Plugins.cpp +++ b/src/plugins/Plugins.cpp @@ -6,10 +6,10 @@ #include "plugins/TextMessagePlugin.h" #ifndef NO_ESP32 +#include "plugins/SerialPlugin.h" #include "plugins/esp32/EnvironmentalMeasurementPlugin.h" #include "plugins/esp32/RangeTestPlugin.h" -#include "plugins/SerialPlugin.h" -#include "plugins/StoreForwardPlugin.h" +#include "plugins/esp32/StoreForwardPlugin.h" #endif /** From c7c8b34adf593bf9e34a64a92e47386a3e6786ec Mon Sep 17 00:00:00 2001 From: Kevin Hester Date: Fri, 26 Feb 2021 15:34:00 +0800 Subject: [PATCH 178/258] impl get channels/get radio remote api --- proto | 2 +- src/mesh/generated/admin.pb.h | 20 ++++++--- src/plugins/AdminPlugin.cpp | 80 +++++++++++++++++++++++------------ src/plugins/AdminPlugin.h | 5 +++ 4 files changed, 72 insertions(+), 35 deletions(-) diff --git a/proto b/proto index 75ae9929a..6bb139c0a 160000 --- a/proto +++ b/proto @@ -1 +1 @@ -Subproject commit 75ae9929a22a0cfa65059f30b27485f2ae8f3a63 +Subproject commit 6bb139c0a43825d868a5e78c07c443f8e9e80b55 diff --git a/src/mesh/generated/admin.pb.h b/src/mesh/generated/admin.pb.h index b3d29825a..36696f717 100644 --- a/src/mesh/generated/admin.pb.h +++ b/src/mesh/generated/admin.pb.h @@ -17,8 +17,10 @@ typedef struct _AdminMessage { RadioConfig set_radio; User set_owner; Channel set_channel; - bool get_radio; - uint32_t get_channel; + bool get_radio_request; + RadioConfig get_radio_response; + uint32_t get_channel_request; + Channel get_channel_response; }; } AdminMessage; @@ -35,21 +37,27 @@ extern "C" { #define AdminMessage_set_radio_tag 1 #define AdminMessage_set_owner_tag 2 #define AdminMessage_set_channel_tag 3 -#define AdminMessage_get_radio_tag 4 -#define AdminMessage_get_channel_tag 5 +#define AdminMessage_get_radio_request_tag 4 +#define AdminMessage_get_radio_response_tag 5 +#define AdminMessage_get_channel_request_tag 6 +#define AdminMessage_get_channel_response_tag 7 /* Struct field encoding specification for nanopb */ #define AdminMessage_FIELDLIST(X, a) \ X(a, STATIC, ONEOF, MESSAGE, (variant,set_radio,set_radio), 1) \ X(a, STATIC, ONEOF, MESSAGE, (variant,set_owner,set_owner), 2) \ X(a, STATIC, ONEOF, MESSAGE, (variant,set_channel,set_channel), 3) \ -X(a, STATIC, ONEOF, BOOL, (variant,get_radio,get_radio), 4) \ -X(a, STATIC, ONEOF, UINT32, (variant,get_channel,get_channel), 5) +X(a, STATIC, ONEOF, BOOL, (variant,get_radio_request,get_radio_request), 4) \ +X(a, STATIC, ONEOF, MESSAGE, (variant,get_radio_response,get_radio_response), 5) \ +X(a, STATIC, ONEOF, UINT32, (variant,get_channel_request,get_channel_request), 6) \ +X(a, STATIC, ONEOF, MESSAGE, (variant,get_channel_response,get_channel_response), 7) #define AdminMessage_CALLBACK NULL #define AdminMessage_DEFAULT NULL #define AdminMessage_variant_set_radio_MSGTYPE RadioConfig #define AdminMessage_variant_set_owner_MSGTYPE User #define AdminMessage_variant_set_channel_MSGTYPE Channel +#define AdminMessage_variant_get_radio_response_MSGTYPE RadioConfig +#define AdminMessage_variant_get_channel_response_MSGTYPE Channel extern const pb_msgdesc_t AdminMessage_msg; diff --git a/src/plugins/AdminPlugin.cpp b/src/plugins/AdminPlugin.cpp index 248a4ebd3..f187fb1cc 100644 --- a/src/plugins/AdminPlugin.cpp +++ b/src/plugins/AdminPlugin.cpp @@ -1,37 +1,67 @@ #include "AdminPlugin.h" +#include "Channels.h" #include "MeshService.h" #include "NodeDB.h" #include "Router.h" #include "configuration.h" #include "main.h" -#include "Channels.h" AdminPlugin *adminPlugin; +void AdminPlugin::handleGetChannel(const MeshPacket &req, uint32_t channelIndex) { + if (req.decoded.want_response) { + // We create the reply here + AdminMessage r = AdminMessage_init_default; + r.get_channel_response = channels.getByIndex(channelIndex); + reply = allocDataProtobuf(r); + } +} + +void AdminPlugin::handleGetRadio(const MeshPacket &req) +{ + if (req.decoded.want_response) { + // We create the reply here + AdminMessage r = AdminMessage_init_default; + r.get_radio_response = devicestate.radio; + reply = allocDataProtobuf(r); + } +} + bool AdminPlugin::handleReceivedProtobuf(const MeshPacket &mp, const AdminMessage *r) { assert(r); - switch(r->which_variant) { - case AdminMessage_set_owner_tag: - DEBUG_MSG("Client is setting owner\n"); - handleSetOwner(r->set_owner); - break; + switch (r->which_variant) { + case AdminMessage_set_owner_tag: + DEBUG_MSG("Client is setting owner\n"); + handleSetOwner(r->set_owner); + break; - case AdminMessage_set_radio_tag: - DEBUG_MSG("Client is setting radio\n"); - handleSetRadio(r->set_radio); - break; + case AdminMessage_set_radio_tag: + DEBUG_MSG("Client is setting radio\n"); + handleSetRadio(r->set_radio); + break; - case AdminMessage_set_channel_tag: - DEBUG_MSG("Client is setting channel\n"); - handleSetChannel(r->set_channel); - break; + case AdminMessage_set_channel_tag: + DEBUG_MSG("Client is setting channel\n"); + handleSetChannel(r->set_channel); + break; + + case AdminMessage_get_channel_request_tag: + DEBUG_MSG("Client is getting channel %d\n", r->get_channel_request); + handleGetChannel(mp, r->get_channel_request); + break; + + case AdminMessage_get_radio_request_tag: + DEBUG_MSG("Client is getting radio\n"); + handleGetRadio(mp); + break; + + default: + break; } return false; // Let others look at this message also if they want } - - void AdminPlugin::handleSetOwner(const User &o) { int changed = 0; @@ -58,11 +88,10 @@ void AdminPlugin::handleSetChannel(const Channel &cc) channels.setChannel(cc); bool didReset = service.reloadConfig(); - /* FIXME - do we need this still? + /* FIXME - do we need this still? if (didReset) { state = STATE_SEND_MY_INFO; // Squirt a completely new set of configs to the client } */ - } void AdminPlugin::handleSetRadio(const RadioConfig &r) @@ -75,19 +104,14 @@ void AdminPlugin::handleSetRadio(const RadioConfig &r) } */ } - MeshPacket *AdminPlugin::allocReply() { - assert(0); // 1.2 refactoring fixme, Not sure if anything needs this yet? - // return allocDataProtobuf(u); - return NULL; + auto r = reply; + reply = NULL; // Only use each reply once + return r; } -AdminPlugin::AdminPlugin() - : ProtobufPlugin("Admin", PortNum_ADMIN_APP, AdminMessage_fields) -{ +AdminPlugin::AdminPlugin() : ProtobufPlugin("Admin", PortNum_ADMIN_APP, AdminMessage_fields) +{ // FIXME, restrict to the admin channel for rx } - - - diff --git a/src/plugins/AdminPlugin.h b/src/plugins/AdminPlugin.h index de8ffac11..71dd5536a 100644 --- a/src/plugins/AdminPlugin.h +++ b/src/plugins/AdminPlugin.h @@ -6,6 +6,8 @@ */ class AdminPlugin : public ProtobufPlugin { + MeshPacket *reply = NULL; + public: /** Constructor * name is for debugging output @@ -27,6 +29,9 @@ class AdminPlugin : public ProtobufPlugin void handleSetOwner(const User &o); void handleSetChannel(const Channel &cc); void handleSetRadio(const RadioConfig &r); + + void handleGetChannel(const MeshPacket &req, uint32_t channelIndex); + void handleGetRadio(const MeshPacket &req); }; extern AdminPlugin *adminPlugin; \ No newline at end of file From 0307e4161ec604b06a45279fc236b01588f66f28 Mon Sep 17 00:00:00 2001 From: Kevin Hester Date: Fri, 26 Feb 2021 20:10:41 +0800 Subject: [PATCH 179/258] get settings message works --- docs/software/TODO.md | 1 + src/mesh/MeshPlugin.cpp | 8 ++++++-- src/plugins/AdminPlugin.cpp | 2 ++ 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/docs/software/TODO.md b/docs/software/TODO.md index 564f11f2d..2320eaafb 100644 --- a/docs/software/TODO.md +++ b/docs/software/TODO.md @@ -21,6 +21,7 @@ You probably don't care about this section - skip to the next one. * implement 'get channels' Admin plugin operation * use get-channels from python * use set-channel from python +* combine acks and responses in a single message if possible * use portuino TCP connection to debug with python API * make python tests more exhaustive * document the relationship between want_response (indicating remote node received it) and want_ack (indicating that this message should be sent reliably - and also get acks from the first rx node and naks if it is never delivered) diff --git a/src/mesh/MeshPlugin.cpp b/src/mesh/MeshPlugin.cpp index 2d6b907c5..c9cc89e12 100644 --- a/src/mesh/MeshPlugin.cpp +++ b/src/mesh/MeshPlugin.cpp @@ -47,8 +47,12 @@ void MeshPlugin::callPlugins(const MeshPacket &mp) bool handled = pi.handleReceived(mp); - // Possibly send replies (but only if the message was directed to us specifically, i.e. not for promiscious sniffing), also not if we sent it - if (mp.decoded.want_response && toUs && mp.from != ourNodeNum) { + // Possibly send replies (but only if the message was directed to us specifically, i.e. not for promiscious sniffing) + + // NOTE: we send a reply *even if the (non broadcast) request was from us* which is unfortunate but necessary because currently when the phone + // sends things, it sends things using the local node ID as the from address. A better solution (FIXME) would be to let phones + // have their own distinct addresses and we 'route' to them like any other node. + if (mp.decoded.want_response && toUs && (mp.from != ourNodeNum || mp.to == ourNodeNum)) { pi.sendResponse(mp); DEBUG_MSG("Plugin %s sent a response\n", pi.name); } diff --git a/src/plugins/AdminPlugin.cpp b/src/plugins/AdminPlugin.cpp index f187fb1cc..63f7a41da 100644 --- a/src/plugins/AdminPlugin.cpp +++ b/src/plugins/AdminPlugin.cpp @@ -13,6 +13,7 @@ void AdminPlugin::handleGetChannel(const MeshPacket &req, uint32_t channelIndex) // We create the reply here AdminMessage r = AdminMessage_init_default; r.get_channel_response = channels.getByIndex(channelIndex); + r.which_variant = AdminMessage_get_channel_response_tag; reply = allocDataProtobuf(r); } } @@ -23,6 +24,7 @@ void AdminPlugin::handleGetRadio(const MeshPacket &req) // We create the reply here AdminMessage r = AdminMessage_init_default; r.get_radio_response = devicestate.radio; + r.which_variant = AdminMessage_get_radio_response_tag; reply = allocDataProtobuf(r); } } From 989f52494db5e3d532d7b52076a881f030630582 Mon Sep 17 00:00:00 2001 From: Kevin Hester Date: Fri, 26 Feb 2021 20:36:22 +0800 Subject: [PATCH 180/258] clean up ack packets --- proto | 2 +- src/mesh/DSRRouter.cpp | 2 +- src/mesh/MeshPlugin.cpp | 2 ++ src/mesh/ReliableRouter.cpp | 4 ++-- src/mesh/SinglePortPlugin.h | 1 + src/mesh/generated/deviceonly.pb.h | 2 +- src/mesh/generated/mesh.pb.h | 32 ++++++++++++------------------ src/plugins/RoutingPlugin.cpp | 10 ++-------- 8 files changed, 23 insertions(+), 32 deletions(-) diff --git a/proto b/proto index 6bb139c0a..fa40a9389 160000 --- a/proto +++ b/proto @@ -1 +1 @@ -Subproject commit 6bb139c0a43825d868a5e78c07c443f8e9e80b55 +Subproject commit fa40a9389bc910b6291fabe148260070e393600f diff --git a/src/mesh/DSRRouter.cpp b/src/mesh/DSRRouter.cpp index 0b28257f6..5fa6b1609 100644 --- a/src/mesh/DSRRouter.cpp +++ b/src/mesh/DSRRouter.cpp @@ -142,7 +142,7 @@ void DSRRouter::sniffReceived(const MeshPacket *p, const Routing *c) if (c) { // handle naks - convert them to route error packets // All naks are generated locally, because we failed resending the packet too many times - PacketId nakId = c->fail_id; + PacketId nakId = c->error_reason ? p->decoded.request_id : 0; if (nakId) { auto pending = findPendingPacket(p->to, nakId); if (pending && diff --git a/src/mesh/MeshPlugin.cpp b/src/mesh/MeshPlugin.cpp index c9cc89e12..6fd3c72b8 100644 --- a/src/mesh/MeshPlugin.cpp +++ b/src/mesh/MeshPlugin.cpp @@ -93,8 +93,10 @@ void MeshPlugin::sendResponse(const MeshPacket &req) { * This ensures that if the request packet was sent reliably, the reply is sent that way as well. */ void setReplyTo(MeshPacket *p, const MeshPacket &to) { + assert(p->which_payloadVariant == MeshPacket_decoded_tag); // Should already be set by now p->to = to.from; p->want_ack = to.want_ack; + p->decoded.request_id = to.id; } std::vector MeshPlugin::GetMeshPluginsWithUIFrames() { diff --git a/src/mesh/ReliableRouter.cpp b/src/mesh/ReliableRouter.cpp index 65e1ff9f8..da743c389 100644 --- a/src/mesh/ReliableRouter.cpp +++ b/src/mesh/ReliableRouter.cpp @@ -65,8 +65,8 @@ void ReliableRouter::sniffReceived(const MeshPacket *p, const Routing *c) // If the payload is valid, look for ack/nak if (c) { - PacketId ackId = c->success_id; - PacketId nakId = c->fail_id; + PacketId ackId = c->error_reason == Routing_Error_NONE ? p->decoded.request_id : 0; + PacketId nakId = c->error_reason != Routing_Error_NONE ? p->decoded.request_id : 0; // We intentionally don't check wasSeenRecently, because it is harmless to delete non existent retransmission records if (ackId || nakId) { diff --git a/src/mesh/SinglePortPlugin.h b/src/mesh/SinglePortPlugin.h index 305532dc5..20836246d 100644 --- a/src/mesh/SinglePortPlugin.h +++ b/src/mesh/SinglePortPlugin.h @@ -33,6 +33,7 @@ class SinglePortPlugin : public MeshPlugin // Update our local node info with our position (even if we don't decide to update anyone else) MeshPacket *p = router->allocForSending(); p->decoded.portnum = ourPortNum; + p->which_payloadVariant = MeshPacket_decoded_tag; return p; } diff --git a/src/mesh/generated/deviceonly.pb.h b/src/mesh/generated/deviceonly.pb.h index 3b81f2240..1e4443af5 100644 --- a/src/mesh/generated/deviceonly.pb.h +++ b/src/mesh/generated/deviceonly.pb.h @@ -80,7 +80,7 @@ extern const pb_msgdesc_t DeviceState_msg; #define DeviceState_fields &DeviceState_msg /* Maximum encoded size of messages (where known) */ -#define DeviceState_size 6146 +#define DeviceState_size 6156 #ifdef __cplusplus } /* extern "C" */ diff --git a/src/mesh/generated/mesh.pb.h b/src/mesh/generated/mesh.pb.h index eed90661c..79e14f26a 100644 --- a/src/mesh/generated/mesh.pb.h +++ b/src/mesh/generated/mesh.pb.h @@ -141,6 +141,7 @@ typedef struct _Data { bool want_response; uint32_t dest; uint32_t source; + uint32_t request_id; } Data; typedef struct _LogRecord { @@ -282,10 +283,7 @@ typedef struct _Routing { RouteDiscovery route_request; RouteDiscovery route_reply; Routing_Error error_reason; - uint32_t success_id; - uint32_t fail_id; }; - uint32_t original_id; } Routing; typedef struct _FromRadio { @@ -366,8 +364,8 @@ extern "C" { #define Position_init_default {0, 0, 0, 0, 0} #define User_init_default {"", "", "", {0}} #define RouteDiscovery_init_default {0, {0, 0, 0, 0, 0, 0, 0, 0}} -#define Routing_init_default {0, {RouteDiscovery_init_default}, 0} -#define Data_init_default {_PortNum_MIN, {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} #define MeshPacket_init_default {0, 0, 0, 0, {Data_init_default}, 0, 0, 0, 0, 0, _MeshPacket_Priority_MIN} #define ChannelSettings_init_default {0, _ChannelSettings_ModemConfig_MIN, {0, {0}}, "", 0, 0, 0, 0, 0, 0, 0} #define Channel_init_default {0, false, ChannelSettings_init_default, _Channel_Role_MIN} @@ -381,8 +379,8 @@ extern "C" { #define Position_init_zero {0, 0, 0, 0, 0} #define User_init_zero {"", "", "", {0}} #define RouteDiscovery_init_zero {0, {0, 0, 0, 0, 0, 0, 0, 0}} -#define Routing_init_zero {0, {RouteDiscovery_init_zero}, 0} -#define Data_init_zero {_PortNum_MIN, {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} #define MeshPacket_init_zero {0, 0, 0, 0, {Data_init_zero}, 0, 0, 0, 0, 0, _MeshPacket_Priority_MIN} #define ChannelSettings_init_zero {0, _ChannelSettings_ModemConfig_MIN, {0, {0}}, "", 0, 0, 0, 0, 0, 0, 0} #define Channel_init_zero {0, false, ChannelSettings_init_zero, _Channel_Role_MIN} @@ -411,6 +409,7 @@ extern "C" { #define Data_want_response_tag 3 #define Data_dest_tag 4 #define Data_source_tag 5 +#define Data_request_id_tag 6 #define LogRecord_message_tag 1 #define LogRecord_time_tag 2 #define LogRecord_source_tag 3 @@ -507,9 +506,6 @@ extern "C" { #define Routing_route_request_tag 1 #define Routing_route_reply_tag 2 #define Routing_error_reason_tag 3 -#define Routing_success_id_tag 4 -#define Routing_fail_id_tag 5 -#define Routing_original_id_tag 6 #define FromRadio_num_tag 1 #define FromRadio_my_info_tag 3 #define FromRadio_node_info_tag 4 @@ -548,10 +544,7 @@ X(a, STATIC, REPEATED, FIXED32, route, 2) #define Routing_FIELDLIST(X, a) \ X(a, STATIC, ONEOF, MESSAGE, (variant,route_request,route_request), 1) \ X(a, STATIC, ONEOF, MESSAGE, (variant,route_reply,route_reply), 2) \ -X(a, STATIC, ONEOF, UENUM, (variant,error_reason,error_reason), 3) \ -X(a, STATIC, ONEOF, FIXED32, (variant,success_id,success_id), 4) \ -X(a, STATIC, ONEOF, FIXED32, (variant,fail_id,fail_id), 5) \ -X(a, STATIC, SINGULAR, FIXED32, original_id, 6) +X(a, STATIC, ONEOF, UENUM, (variant,error_reason,error_reason), 3) #define Routing_CALLBACK NULL #define Routing_DEFAULT NULL #define Routing_variant_route_request_MSGTYPE RouteDiscovery @@ -562,7 +555,8 @@ X(a, STATIC, SINGULAR, UENUM, portnum, 1) \ X(a, STATIC, SINGULAR, BYTES, payload, 2) \ X(a, STATIC, SINGULAR, BOOL, want_response, 3) \ X(a, STATIC, SINGULAR, FIXED32, dest, 4) \ -X(a, STATIC, SINGULAR, FIXED32, source, 5) +X(a, STATIC, SINGULAR, FIXED32, source, 5) \ +X(a, STATIC, SINGULAR, FIXED32, request_id, 6) #define Data_CALLBACK NULL #define Data_DEFAULT NULL @@ -760,9 +754,9 @@ extern const pb_msgdesc_t ToRadio_msg; #define Position_size 37 #define User_size 72 #define RouteDiscovery_size 40 -#define Routing_size 47 -#define Data_size 255 -#define MeshPacket_size 294 +#define Routing_size 42 +#define Data_size 260 +#define MeshPacket_size 298 #define ChannelSettings_size 87 #define Channel_size 94 #define RadioConfig_size 335 @@ -771,7 +765,7 @@ extern const pb_msgdesc_t ToRadio_msg; #define MyNodeInfo_size 89 #define LogRecord_size 81 #define FromRadio_size 344 -#define ToRadio_size 297 +#define ToRadio_size 301 #ifdef __cplusplus } /* extern "C" */ diff --git a/src/plugins/RoutingPlugin.cpp b/src/plugins/RoutingPlugin.cpp index 9af7d31ff..18427bdca 100644 --- a/src/plugins/RoutingPlugin.cpp +++ b/src/plugins/RoutingPlugin.cpp @@ -38,20 +38,14 @@ void RoutingPlugin::sendAckNak(Routing_Error err, NodeNum to, PacketId idFrom) { Routing c = Routing_init_default; - if (!err) { - c.success_id = idFrom; - } else { - c.fail_id = idFrom; - - // Also send back the error reason - c.error_reason = err; - } + c.error_reason = err; auto p = allocDataProtobuf(c); p->priority = MeshPacket_Priority_ACK; p->hop_limit = 0; // Assume just immediate neighbors for now p->to = to; + p->decoded.request_id = idFrom; DEBUG_MSG("Sending an err=%d,to=0x%x,idFrom=0x%x,id=0x%x\n", err, to, idFrom, p->id); router->sendLocal(p); // we sometimes send directly to the local node From 63e0b530546a914b27bc3a8453fb1a094a5f9a33 Mon Sep 17 00:00:00 2001 From: Kevin Hester Date: Sat, 27 Feb 2021 09:17:58 +0800 Subject: [PATCH 181/258] 1 index channel index --- docs/software/TODO.md | 2 +- proto | 2 +- src/mesh/SinglePortPlugin.h | 1 - src/plugins/AdminPlugin.cpp | 4 ++-- 4 files changed, 4 insertions(+), 5 deletions(-) diff --git a/docs/software/TODO.md b/docs/software/TODO.md index 2320eaafb..481799cc1 100644 --- a/docs/software/TODO.md +++ b/docs/software/TODO.md @@ -21,7 +21,7 @@ You probably don't care about this section - skip to the next one. * implement 'get channels' Admin plugin operation * use get-channels from python * use set-channel from python -* combine acks and responses in a single message if possible +* combine acks and responses in a single message if possible (do routing plugin LAST and drop ACK if someone else has already replied) * use portuino TCP connection to debug with python API * make python tests more exhaustive * document the relationship between want_response (indicating remote node received it) and want_ack (indicating that this message should be sent reliably - and also get acks from the first rx node and naks if it is never delivered) diff --git a/proto b/proto index fa40a9389..83e00e564 160000 --- a/proto +++ b/proto @@ -1 +1 @@ -Subproject commit fa40a9389bc910b6291fabe148260070e393600f +Subproject commit 83e00e564d3973b594a46e786b62eed2823e02ed diff --git a/src/mesh/SinglePortPlugin.h b/src/mesh/SinglePortPlugin.h index 20836246d..305532dc5 100644 --- a/src/mesh/SinglePortPlugin.h +++ b/src/mesh/SinglePortPlugin.h @@ -33,7 +33,6 @@ class SinglePortPlugin : public MeshPlugin // Update our local node info with our position (even if we don't decide to update anyone else) MeshPacket *p = router->allocForSending(); p->decoded.portnum = ourPortNum; - p->which_payloadVariant = MeshPacket_decoded_tag; return p; } diff --git a/src/plugins/AdminPlugin.cpp b/src/plugins/AdminPlugin.cpp index 63f7a41da..bba1b39a9 100644 --- a/src/plugins/AdminPlugin.cpp +++ b/src/plugins/AdminPlugin.cpp @@ -49,8 +49,8 @@ bool AdminPlugin::handleReceivedProtobuf(const MeshPacket &mp, const AdminMessag break; case AdminMessage_get_channel_request_tag: - DEBUG_MSG("Client is getting channel %d\n", r->get_channel_request); - handleGetChannel(mp, r->get_channel_request); + DEBUG_MSG("Client is getting channel %d\n", r->get_channel_request - 1); + handleGetChannel(mp, r->get_channel_request - 1); break; case AdminMessage_get_radio_request_tag: From 3b8f5ea0991ebe94353c22b1b1a0bfb03b9f6ea5 Mon Sep 17 00:00:00 2001 From: Adrian <73254487+apt105@users.noreply.github.com> Date: Sat, 27 Feb 2021 02:01:51 +0000 Subject: [PATCH 182/258] Add files via upload --- images/Insufficient space.png | Bin 0 -> 10450 bytes images/platformio-erase.png | Bin 0 -> 53687 bytes 2 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 images/Insufficient space.png create mode 100644 images/platformio-erase.png diff --git a/images/Insufficient space.png b/images/Insufficient space.png new file mode 100644 index 0000000000000000000000000000000000000000..e67722979347ecca25e60126f46ed59974f8aa90 GIT binary patch literal 10450 zcmb_?cT`i~wr&&!8z6`xNU>q)D7^>~q)1EXNbkK$uR%pX`cHa~(n3diFG`c%dkMWm z=;`pn@11wknrwHG5G1O3h&Mh^CJAzq}K1V`KyCFSH}lYSqp^)`z1_geSQ*NkAufGOAQH|s4b)~qQr6c3INc@ zL=Gl?EyCOSR=T1+p%)=?Mt+CWS%U$n1F9gYA1W`{(D|h22W#BmOchodJpWt2x(3`` zzVY`GzJKJutFRL9ihLj$X9t3>21)&b+^cB7B{hT)4G%``54%9;-}L_HkG{hL*Y&g) z?Anv1AE;Sr6vUxe{PCa>t_0X~B1+gNYuRkR2)hx|C-)Q)C zo98@rO39Y$c88)Acp0g>gWnythNEXUjLy$60lme+FybWop=xV!L5%A1A-JPnpZhF# zXlCDeZNkpCU@Jk((eD*?l5GbTB4LhDv#r$3uOQi(gZUO}y<&U3mcdk$DfchP+FEQ2 zuA)@`My?u$FfeTvaMno}5eSS|DAZ)DE?BrYyluxk<|6%TCfr?9=7-We1or|ybDu@` zksSE98b+JP|AMFMc$8MGr4;HycCm4h;d^M*0i_Q3dJ(k>*ETf3bQ-zKovPO^>A@D^ zE}$TfIxk<4y^tp8G{EJsgSi=b(r+}kNvnnaMcH!N1oM;9ekWoLov{)bFU;FOt#7J8?p@}KyOv)|9@54Leh7 z9IZU|n5`L8{yh_SC~o0jbCoR)xCpNe;Ndc}I_V%~=aN!g83zUX7N`*V&T)!}LEP3z z06IDg!%SzK1mmb@F$2bgI;gbaQ z>hNWi(lA(a%r&7hrx>sZzjS7%bGpX!vcZ`9TUw;eS=p-&CzyCDij zJYxRpQX_OS(2>N#&M*$jx2&`4L5J$bHg7o_Ki@6T#m6PTMUJjy%sfoL*PG>D8P6rF zYU>e&%%S+10}{q(3)KFUa*v+Y>PRhov<+3`d)AKlprK*n2RZz!4HCA;8mGg62*1zr zG#mJ`8FkKMDl#t73};%ToH$>{&VtfA(F-+$Eky&b^K(o~>b67qhq_;z}$3oS}HkV_hA8xVEO~x-~g~5JbtjjKp z1lgL|L)kM-6pZ@mc>=42XI$+|7_&McQXpMR>AXC9{=sFS2moD78&1fkJW*xkOJ**+ z2rG~QcVMWtrN{CRgZ?Mp-q7}dfMeviG!;k0Dx4qdJxd3=35sur_^kU_Q>el% zZa8M5yScKlgy(%fP^Ssf!PY?v&=LLk8X4hE){QT=;V>zX$O=%?asthkCeBNe>*k%w zFb>&9v_s(Y#Fn5sW^o!Tc){-vvN?wI1aGA&S6i}x@_GNP z=PfiORZBXqr38do)}7pZE|Q}maS?~mpZ|7LFqf4=M@2w&@w-9)y-yq~JaAt=HuR2WwmT0a3yjOObi#A)oz@Xg=`ZpCD z$ot8C59jpM_~@6Nu51La#HHLr{E290ZrlljowT<&DWx&1t^>I=c^-XMSKH-Y;ATSf zYE2xGbOi9QFGVE}C+_jXTHx8UIa%Hbk|F{Dkno(o{&DH{+qABSvCa`0v>A8ygJdYM zEOb7@DK0@sg0nIOA_!c*feZ>8AtPanOZID4&CSaPAvOa=VNNG4KAy|0J*=in4_y?P zDRvl^aUo(C?`6OrM0zOKRxq-$4>}R7=x&v%H1(A*0846}?=Wi|)@xa7V{$V)0sS4>3g z8zQ@@`;+)nG9T(81=zQr06$6nScK1@+Y%dKCTzDZiLj#kKlt=hA+gWvpeumZrEA11 z07}dSS|I>{^GCu-Dgvr-*?UjX{be8kVC+Xp%oG0iKYfG|8xHOfFPCQcYXHFCEth{; zBpO`y1Aq)b0>OnQ7Q@Wa9LXHny@lVMW{+y%-uwm-J1a3^=SeeXyS=&Pxw1S=7nrMf z9%H?d3QUPy4|Q@pL0$M=1@yha^Y0qy{HbqR$Mi3iG%xSJyvy;rsZr#iH?tTrZMN&& ztrjzK<#ZH0lyN(iP&qlfhZ~d)IRIWPLq_bD{n63`KtSugv)BiIm7;>T=TUkqr|9x^ z!X_l}?AOU?`gknwYevVa4VfwafGy-jDidh$0&@+JtB5NH}`QLP_I2%w$>{AKGi9fMVtTi#CJQr)mK#a*lDvo}G-+MAcbMzX*>(rT%%xc~sUQAkfMqSLjz+*K%e;Jh+bSLv+dSJ-eb-1J=* zT{z6cv3PYm|Mf+-8zIzpH3oC)tK*>T58rCd-NpJALhM3bH#S!u*caOHpKFA&zc^C& zkQjXnwiB!K2}xxD9K_n0lz{dOqO0Ra%BW5K2iu_qj>SCEf%Z+k zz|kko4SJ;m@tvTAbu&KO#3p)nhuZUOM9u%$LXw-B|nB- zhsK1Adik()Plrc6_A*cwxU-Q)FN=%!&c{sRa%8>yQ;Wfe`--k-DWyGB)o!}) zEcKMSAwAwV+WJq$mOdcoX5TlrJ2L|qNI^l=N9X)o8|#KgzLd)Y4pv@WM&~m}>;A50 zTX6N`-qH{wUB-nl^~x$Fhz+){w`0R1<~i};2oXSiOUaBzg!CbKDwn(9B)FGsD#M>I zG!dJQexx0#71urAQdZqKm3Q*R2}6L#%ImWx@@qNDf3SZY(DzO>$&RcJYBVL@BcT!d zXT>|eao1svu!Hei52})%I2NgGHm~Nz#XJDCenP2_;pUt6xy1PrJv_SBGjxtbe;H4f zmx;y*;++ZlXnfFt{N2JD((0d&ff2v7&hTH?)o*W{`zX%#wk^y|X3AydMoZmQ2+z#| za~d=hZvVK5@;uA`nP3J_6xv5#PXzbzWa!mZm$}11Ztg?t>P+;8T|)E)**15O9tnEz zD3-lO%ZmgDVQU-k#TO&Rp607-xg*EVmS5aY8$1x958ryrZTKGft(FWB(hGU!tOBE< z007W8{}-jG!6?5D zJt_UyMt}2`Wgo<#bg6YGERp2UrI7EZJ)`61^>I}7Ud>2YAVGXU5yS!<@NTU^q8M3vwyf6 zw@&LmII)V!;Wa!mU&N?;^-d9<8%FL#YsCt=%}=t3KByAhTaXxe6?lPPZ39~%YRdS}TZ$7HlGhOfd;idj$v(Pd$4NA|i6B!tiTRxb-ceryfH zD#eqe&rL-(S$~UzUIvB<~Tk&rf&qZ$TmoVgTuU{E}UM-D_nCKK3pQ>9irps`)7(} zKFbAn^M@@`VUnP48@?+FUWaE=eyxf|CKD9bhGn(8;6`^=Y;DHZ8CC}F_IA9d03~-7 z&Sh;Ys`8burMK>;%)=x`=&wS`as_%VG(dHOCh>M~nAO_*INNmPet*LX^0(TL5FEAK zqN)xZwDT?{x`qvF?;3vYXO2J(JTxejABqOhZV4q-k+3(F^@lHG`&=k7#g6xj}6LkZhAyX?PC~V|dF#oOhx=)A%a1=V|CCzIkbHMJM|jBqz|+{h>I7uX2*kYe)9U_% z9c~7kfTQ5#Yn^IcuePZMZSU*weRw%quSphjTX!B(o!YWm{B4JW9m`fA$f(Oa45@b5 zn-6E9b5aAuq)Z)>@Frk3j>1;2 z(8+$Fe*Rf2+~$Px)#0X8 zw_e+bwg!`8rGHVM`!wcJTUl|TuPTCZAUmnML`Ek>XY1^xgi`H9&B9=i5o}UIlASMK zYh@<79;U0ec;XrUNv;23Z$9gf#y6ZLM%iE$+=r)Fe9@tyd%io#EM=+8Z z!`_(kcxJCxsRa=WUKx8nA~Q}B6F<=Pd9IIikkh)A7CqAvs&tbYy-?1nAhVVp4XrZT z3U4Rhl0*^16phVUU~9NbXPmu|U4kUHnX;aw{M0?3HJ;7i;kTpWBZcz0P^GKICTI8e zgST)oJZz(3GjzRG4m_|ADGsgJ8a4P>Mr*O`K7AA3!R_s@jWVwCHWcmhnN z((*}yI7o_lZd8`HpDO6vGB7Wllh3qMcifsGq4b(Ej7kDP5m%-UNVj^C{=u@TU7}b2S&aTmvhdFe_MiF0zgDo9M*qww zrhp)F(m-ayrW_BmW_wvUU#l`H;H4{+n(<^}V&Wk0X_P_Q6-Qpc$K>PKuTO&I9(^FK z?Y^`pR>;B;&|5Q+Nm?6;=b31sWHCB7-AI{$h)|lpE6W$Bv45#>W)I1d^Qa_*^rQsC zp#G;y&(;dHL10=09-MWUo{B@pL{D0{j%iu!(Pf#4fUalcRWq_Gk}hX`oGkWHi0vKr zT5ISg`}zqhZ)#pm(8^kKI+g`|oIX`o$|(SUayVWpI8ao`UF-d1e7p!_BP?lbb*gTsDh?w?>CjE+ z)sJs?;U(}W8yWwcT#h!#*4Z{`!D4w43uNlY$PlOI zpLvm7$Ukb%A(#7VnUAd?`$}Cc+z0>s{4bx|S)vw1# z0Q)Kp9*JC=&8>MJRzW`cPL-uf#!j^0Iv}Y4CYw}}WbB8`l@U>6N`{%MSlp1k8NAFG zWT)GfHB3|D-K&SOHi^zZm_W)2E$|LV)`r|BaN;4^=Zrgx-`4hxHH#e>e(Jkjo-y z6J#|`YVQ2_3|2KXI>o!VD|GL}Ro7vC^qDQ1guJcYl~p;`a*aoP1+a2-);R9(46ZJPud^4S zzWQXclFp(JFOFI?ybel^6%E4p`sN@4)VL%44Tl<29KXe_BH3W7aiXI^#BI494$Hkd zD71``y{sCD64O5fnZF~e72^IIxp9Q60{|*E;lGR@i*6=HvoB9|&@H|oxpa-Jpt$Si20mWc70wFW1N>v&Utsd@b-3RNFrmoct!7JIgHKZ@lU-dR>4%;OVL@%eiI zz~3SIoe3n<^2tqrkQ{3MV;zWzt+Hk5iPmR*f%C54_vF6Bkfb5VHu6-a{2NpaIxXlc zaIQ!A*1Eb87lB}ECys))c?z<)qGFrX2hn{Te<6T60bX+j$@QX{0Dw3w8}h!ZAB13| z+Ygy3R1oiRTFj6qWM4Qt)bbMHqZN{cmX8eU411?(V+o|dW(wll#8LS7;;`-77r$<3_T~!zuCGI_en6BX>pI#YANVc0 zf3wc@E>6tU@d1C+6<+FwHKYwkIZGjSitwnLhz#_Mu9NVbC^Bl0_((_z{Ef|H+jsZ_ zrYfG>o{b(v1?+2N{lM4^W(1iadcn?YeTCK%8{rcaPQ__T7Zjm#oJKQulyToTTKE&! z$cTIE(}8*b;bf#UP@F~PY1$XvCO&0QeiF2xJ~2JDSGhP}e)m3EKobXWrAK}EjIcpm zmDVdqm$TK5#pFKkm`i3+b;4J!e1);^v*;DCIoUyN8}D{1H7R!g;2-qTBPkIBv`QYU zBac2)vj-UsyIaXCnVfGeV1Ii-XQp*M{QFT`SI>-RRFQH+)&&Kj| zp{fb(8b>JnWam+=J}(mcTkE2;PDDn}mB-<%j(BEG_8Zc+qbM`@h_~W-E|vhNLh()s zr*eyUww)^FHl;`7*FX*lYb-=3?J@Z+=l0OMrH>U&!v>=t`t$UtWGj9CdbND=)NF>) zzF82#iQplgJO{(D=@qWkax!^3)cvfJ#xIDna>G+O@U@1!)i?cxp)_7wSDct%PcN_UEhkc&m(;6kg6LCt4wteB3#7Fxp4m z#YBVwB zM$=o{oyJoER;Tvp?XtR!rhc5hKj0%>^uJT?)Bf*j%D+VAe>xZVf0kgT$Ux-yj^N0I z7RILLy_)hC)Ya1AgZgpL=NwM%q`n3a$3jgpkt{)_AL|JKz?;ZJb)nq_5=~APv7UQIkAD+zqQQlgW_yo7QCJ%h9!e8Xq+l{RZD9Hu6w%5Q{CuMs49ME=B$Z= zn*<Y1C=^m)zBl9X@_OO+7a4%g*D3;bCHT8i; zVBG;LHR>T*UOl@H8+hl>BW^y^6FChLBAg@zq1oi+RkAWZQ&spqj)xtNkZvC71bJM9 zTC(CIGwG($KdJSM;b^vvm#3`eZxY%e>+(P4>;Zt6_d%hK_3Hf)7OFr)NG5|`Ht%O$ z&fM-L`bf^x*yh(CoKIrfAPR2pf<*zXV+4(Zn0VN51k-XZw4Y$A+bIg^!059sdUruF*uN~_6d84d{KI$`W3OLo6K%ebsb*c|Tr z3j9g<*qid9v51_0)oPh?^{n;p#nCJ71b&cI?;jOP6>#u$7i#R1=)Z$OHhkiil|OPw z|NN>n7Z9KwpjPZ4CTMrll0B$2arXuV-oU{hlF2J_4K}-CV8C8>d0tW(--tP~VuymX zU7#d7zv{gSmK*@+jQDrkoJd@kIQ*Y>@4s@@zo`lS8-lZOa$4jOu-PNQ|#uK-AeMKw1)`W)c z8l$^K87iTLYdn53`!Dr!=UFEaaeA*A#ZT}@LJ1n<-)jjUu|;;}l7y@+}4&C<&($8rI3 z`15@)LMtn*wW3co=blVBbn!r){{$W}KkXlD^h%3yj8UhDmV#S%CAsvFsysie&^ z+f!FobY;Soh!(g_xLYo8doH&5{mH=A3lr&>hf=|ev&}Waj`(cy{rkZJsxLK?x~RN@ zFjPK4$u?upA_pK?&j&O!1H={BZGc5Mio@t>qmqKEhhle#ST9(csIA?cUzW3rEANE# zpfjFov)q1L6_v0&_0BZ+Fq-JR?Qtx1?sEh0O}PG$@#>W*@e7*D@U9(Bb>)5kwRKqK z6A4Y3ZLi!dprUhv7%@9jseu(?rcHm?e7EoHSPC3+Ew5mjgnZKe8K0xMRk9aop957$ zoj(;{+0hDv&0%Pc(uim?5AE@s-p)&WF!Xg__*`r|k&ne52Ng0%nqo;u(`l+2404fZ zvr9{cec6Jqax|s%xrD&_6+60e;MtU-P-D>LxD~Lts98Zv7VPqb>3%YWg5&47zw|dT zW^2ebQq{i><8hOdiRNW@=5BS z%XDh{Ipc`=*^U1q@1m%J9Z@FwO0kg`3?8jce1?txDMr3`^#9`%OgO+u5Q*Eq9a6V} zBo|#c$IAO3NVCIb*0w4qfLuCwbIwG{9ap^U&%J{c*vR6yRiYTb3HN_t{fIJkh}qlf zX7Mg1{AHpO<;j~KDw=f)(5?9%$e(6C2EgJwoDCwtfyc+A?ePZibXscWW2yz=_gZKn z17$*0NObWL6_`L3M8qKrkPX2L|Ii7Pkv$AG*J3uT;GP>bO$$!XY>yH=fjsy`vqhhK5}-f_`k?Ah_tu!;)cY5qhv9rw9I zRKl_L#ub1u@$D7vTJ=S^AH&P@Qs%9e%^wz@!V@c#IMt%;2%mk<_?I+~M>7Q5;rZ|U z`|6f}sWgget3*2*P_lnL6=)6Xzw`Us@Cs8FxYwzkwnIKD|AonIUok~OTtKioD+ZUY(AOTrY?i+Ok9k0N4G|ir(^DdgH$;i^yuY`Av(KDP{yO##sN{ELsJ+ z>;B<}Z$}UQx%krf1k1!Y3VL w2lgP|BvKLp-_CZqIseP!|NlSe`f>#yu#o(aDXWxN-V#6ZGGOTvDdW%o16|3H=l}o! literal 0 HcmV?d00001 diff --git a/images/platformio-erase.png b/images/platformio-erase.png new file mode 100644 index 0000000000000000000000000000000000000000..38543e3ace61ec6a25e5101c8d515718ee1fc280 GIT binary patch literal 53687 zcmbrlby$?$*EVd6NQes3A)$1GFod*}NDSQ_Qqrw-Bi$ekL-$QfcXvy}&`8J3x99#n z-yh#U&-Xm<%W-&kTnsaFU3;%}uC>nd+(BPHOJJfCqTjoB4^#4!sKUK_57F-3dvJ~R z0Q`nTYI76(ci&DyLik?E5b+MUcw{0ZD|GK(dBpQuy~p7Cnaw9PyLB8~Br?(&d;A)f1- z2sIhUld(^;h5;N~4o4hpn?{5@uLe^jE6ZO|syWk&Ny3#4%~zg~7I7OzHqsDl(2hPe3f3bzPZ zgH;g;K0-0CSFreC$Gxd>qB&O~j0Su--0&-IsQF!6NrcO7mn@_qncH=F-`Zq4E8eMW z{BpbS?zR-y!$QYR?F@BeaE`Cv!bUeTRyZlinjFUut_Mk{t!A`pcjZ;MFjE8MY=fPp z{_}@2MeZHj#u22@R&1^37%eX2B?k^`n}fU4Df|HwBs?&$Ma~iA+ySHcgZYr4AeV!> zEsQ53R#r@~kT=YT9XYRhgKjK>d9$X!Ll8YZJsr<0>OSMb5wpAgmfQXm9=lNSwVm-i zX!Kd*aTn3WvKMkI-Kzwy)%SN;5V;;Lhxg`9I=`DTCyrVWF4BVU@{iARJO+F|=c87i zr%*)`{qbcM(InE9l@-{G`Lx?-M?VI!n$&hOD0}SF1U!ZU!6BFcdgqJ8Rf!6^ph`buMoUh4{ch#4m_TYVj5Df73 z&6jGj+ZrlXEfw+ z`tIF3C1#!GP%5YO9vlt#UxOBxI!}-!SY!eVtjNa<-bfg1;`=SS0&a5osu$+%y@3>- zad^n$z*i$BdM~q?Q*MmNt~Nz8{sTHP0r$sr%{z=&a-HUwVhra+=7CF8Ab>H<-Dt_EAw6%b+60ruee8rD>?DnZHH(D z>eG!be~;YyW@oSFty^L@7?_xp*LYt{z1hvDqbY4Xkus4MJ6d#FrV!8%DX7OHWTj(f z#x~l6;G~tY8Yyl0T80~m)3r(UN<=7a9UcmrjZsZzwVNT0j?z097fB%Uw~@cP90)6X zA3z^{fEFNe4J}gtwmgxaHd14`_8c3J_m?2Bp3zD;VP0M)@@NX+&9qr;y}Gfj47&@^ zl%N}HB5uCh`kv+0Vmm&xXGD2vCt6y02mR5~I2n~levprYSATQR(A3zd)Cqf0=k4wN z)Az_tnQ?;*c{!zFUA<`&>7eKJl?7iZ=he+>2r~;YuYJDKSvD&_zZNW&SOKTz>c_*U zW${`Kj>Yb$^vXrQ%NiRs9pE-|UIYwd@X123X?(^5_?#u%>FPdqqcb|%hl_{TVML}a#)PXI=aae3emAU>4h_l9 zlhw)S&bjJi;C7{VO>>4Z6PjN3JdCpIR=$>^|)E6iHw+;>;F$L4-r{a>zKe6ezoO%c4;$!;3iN zV`#s-SYFPPBa12Lj$L~}ct>ZdqL?AZWc7RbI#*ly3y5!u8gX`wdxt~>1VQgdDox~W zAA9Z1lpBY?<6I`#S&5V&eTIhivx$Vu)7%`MEg8*%3saR<6H>Fi6I0RO97xO(4~r_M zP-)lw#u(V+e?5%69quOcBDVhV`1fu3VePf#WMgBa?OGRw#y0l-&xvf0MfPQ++Ue($ zt_v)jn|h>~n|!TQaqeI|A3mra@AW3I8kAua^D)ib8rRYmRnu|WS_XSUq@VJnQzPq2 zv>Nak%AREHjCIx`ZJ0v-?VPotm_mt|KXC>CnR#izBxVU6wtrg5qK^ z+!oD=Z7hoZ?++a3FFgW`0>i`OfcDsSY%n!89;o*y+IVOc%I2 z9rt;H+1JKR{QC7Pe1T@La+^E!cW(PNDX%>mGL}iZF%bF3RDLaRuA_odyzSi~ z5<`W_lUpwwHa|_VT^w|$lyuQ|;Hi$by`Eh%+L*W#FU!UyTIc<*t24ngXa9a=k!iZUq)-|ug9KGtVo_Y^Y~WH}LhE!c~R zJPh2NR!2VToB96zUcuaJ<;G63sHv~4>^&jZI%$_#Sb{l&Ux_pEs*mqS@E0=A=rBx% z6RkL0m85Mwy(A)WEhOdr_AUtl@K@|to_ex>)92wd{=p%QR9*+E&t_^Qo@52o?5&3a z9DQuW0`98Ufy!wUWjJ-`c+w%u%$K{EH+*K@rSEPFT=!;J@2vAFCBk)`hxso)LC4)q zLOTbJYpv%!UG%(yGG+x{7Cabz>SY0|4??te3fyb=yaT8ZOa<-PVMoKn>?|vQS|IYU zEPhb=E`G1dLRF>}iO1z1)qnnE(rNy>t8+a=U_h1|*)?VDXwi!O%u{JSkD8wT`Atji zdAMxrR6CLrT3#9b&|t&=HiQ0b|MQ5H@8gM3-&w?(dn`F`hiSg zn}Szqe0}6e`%6A9qmutKX1~Ae55JD(ZN~R}P?zv*x!BWmKE`)?Z`&&daXzEBD(PXiF5+fHV8Llz2SZ@TGkcX~kaB65K zR~ZBT;-2laBy#7m=Y`h(=-)oAaDEumIYV#5Zc;hZ9{E9ng4{~es9JP-X*F_XWVAY& zd&8lrxk%g|>vCiMC*ia_A%b)dcT z-&_7*BtV)^ST@3@(QHr8`k!wCr@zU%-OrO&%wx0PxCgOA`>U{2_~U$Sde#>YGew!`+B5A(y(}~Q>DS1 z@O1RLkC;%Nn4A`Z7lP6~mawsBs;9^tN{T<`JR%4m>8l!xdAxBli4NbjuCR9O%3BAa z39dMgpsy__iu|sp|E#Z)xUarCJj6c#$39!3})9Uc91vE=4;5}i)|N|)joBHS#B z$A4D%1=LRhf}MkdaFQ`lA&Q(m6l`o*HbWV|w{4GRmFEdf_V(_CFgO2hkR~f?L$yL8 zZ4YEpc{%y`h(&J2+uv7id~Ie&@OD^#{5{nbESJDSK}QEuDb;3Ugk64EAGfu$1FiER zi}F1Awhu}6R}OcZ?;9OdGi-&*#W1%u8c(WI_Hy2@9JkhN_!xl##(855cLgF4&rXAW zt5n8DR~XS{SOi(SAI(%$HIS-RK9#35SYRM=`KQ(qk| z%q}Y*ou8k#2Vi&0^&c!YloM>UVBkHQe-ZK{ooVl+{LaYico{t%t$qjT!@;XT--ewq z3sFBsJ|;vgaP83)=2mZe!89~2D#N%8x#M6{6V%LuPF>baMKmw5mmc?iY}gj+@;vE%w>6a7?mI(1roWl$v@|O4K?c>#dEM;S zD!Xs$5%uh|6kl0Xcc$}-(r0IaiNVZkcJ19Gh#<#Xe8~`pm9@P&f5e4{TA3kTPn4M}j)3xthP`EEg} z|AC}q^GSQVJa{mMPF+#1vACyvHU1{O(?W^8j?izwtey8i)6vmEgHRvs;M@WJ`=9Vp z{|#03zkF#22M;edc#6y8`n1{O1}0TmqTS^B=l73FlVMmrr;?Hq3`KFt@6Nyj<#!cv zPT`Xl3;)=HDMrBo5LKD;tuzv$G;(QsJ3B6C@JVm)2a^-NzkZQJE6!~xNm;?4yp^7% z!uJaZz$WC_KH2DpIPQIsm33YXddC7<+)QHa3Vp5$GZt5PK_1QLlwWi-)=g*WfaZ8l z{u%*SsjN27T5`3Z_GfOY`UHE9cgqW=#y(db9v+LSThIMDDrjk5dR=2`j1Y}{Y**Z0 zIWJeQ!=)yLxN_rYQ^TRT8ER=f6=mh5GtsR0_;}btJ!+@4BAYzBjTxJpn*sKVXB~qf z16J@1g=%HLe%+&m$)yYMyPb<>*4ytWI5n^q0t|L{cNdQ!t#-R0&E}uHQAQ(f4_NjQhC(^7vyLWJbb8%cp2~zcA8!d- z3*qkLLkzkw*88D_%F<+wRXmjOz5#NR*K21ZB9SeZoy_5+{4^c|apOx%h&(|L;W))E zEYdxG-QV|$Tb9P<1UKMtSH!K0S}14&T54*P`@UB@Z^R_HQGj3L%bE!ad{ zGP@$EFtv|s7&|{))=^ar6jo_mG9AyA4MclI6RL7%%zydE{!wIRW~TDFb)TXfzuy<| zR`)xhq-h*>B2;GRa)Ble)RvAL3eW~wcwr*#gk zPfyi$Wm7(6jIzg)c~nhyb{d_m_rg32{riJrj2-JSNxk?83(!)bcgj76fr^1XFl}rc z%<``j`SP&OqN0YVl)1cg#(*|0-Cq6O8uCzv!X-@#b#NwVy(9DTOnwGAQW8}}zOF~N zwm!_&_g$(o8-GFjg8ckoG33EZe?mQqUj6`VvPc-IaX8OzsrhvKH$1$lREhCV&8(0C zpON!nuY<32@T*GY$u7 ze4C2gUq;AI7W-m5S9w2v?zs+8M&0fka`_bK)X_x%?Z7Qi5#O;^k7RDvPm z<>gfXvQn)d^ruR_adSkWxpL_U(TBw?!rRuE>zkV}+f<^L{&>obO-);a4b)v+=3r$L z%mGL%bS81x4M|&fhm$0|#ty&+mXy1@at;j&%z4GqPh<<4om^`--< zuhtvKsKLgLt)CC4*`02QkBf_oEGK$AX?Oyno@;Nxb01wCkH51#S%_)0E!c6*A#5?g$x^DVAclPhQKkK6;LmUa+y zl&Pk+Qf*T6Os#Q+A>v_#v{3$RYC{@#beOg^h;)Dyf>*r}Acl~)Tb~)8sDG`i&%Uwn!M8p9Wi>b}LnyAYYOU;8jrYoK4vX^gzE&*1%o?X@Ilw zvfd|@kQ2SPeUCUgrQLk~ZvPVx6biMNrrD9pXH=`e9~EuDDxl!WnA+y~2Y`^9iwlKy zwewpH634xnA6E>jM;4QYyxx~%(k-pG$#v$*s9QB)sd%<8{MLnngWQhXC4ZFnr37Kq zX`UE>NwoW7NbT6z*uP0l81ATCS4+`|Eha4NB1K@yUO_f z{TJEdO*kCBvlH}y?C29f36cStRBFVnDhUy+AcMWSsf}8C$~0? zfzJSK5w>{h3T^nH?!V%XboHH*IwXD7bX*DCo9M(7OF{jK-s67@yjt)Z9k7@G^UD7J zE&A>!4jNQc4A>YLO0llAw6q$vRw8-_3nrA5lsWQ>>gx42E6-v2FG={>xww>}dwVb# zY;AQ_DJPAqu&S!+Y=QmdzNqMEXy=gC860}8^oWUR2#xxaG|Y;pgJz(WL3KtL47YTNnaOmCx+EHP z_f!=tl_svu004hoA3_%ogs`%*%JFkbOeTNF8Wy;bv8a&$y2sF{prDY=Yc^&`i&iE5 zbnix9>@;#A`ezw2&ojTqM!ub&373wGk8RP*!oop4|i`V=KU=eo0HAl~nH*nGp}k0&b) z$^xa6GRrk!!^g(Qfs~fiD~|7nwe3FyE1>Sd%gM=k-&4|*5f!BmWh0peoLqw8Y=ue= zD?2+oBcp6zgdi#7;}G(%lK1~cKBD|mb5M{EC>y;%r5I2QAG}P9TVGhbkz5%_WLLOX zWYGS2gqd-Q#BWLt^}P_Mg@P*CWG?RLuqq{AD_AdKm7Vy^paEhmAvKlpak=N6o5IoQ zX_U8^Azh;%7a38cgAiSta#Y;N$f&}5<`#0lo}M01&uF=`Q$_px`^V#IV#fi>&rYN| ztEel^<_{L2xw-Oi(sYM$l$V!-II8MT+>jy!GiyN_#OX6SArH^wgx<{e;^q&7Qw${+0U5_xJCQU&)|#xKSyy ze)GlYaUi3_4@Pt!U4Na}G!RP~8&eP^tJ4&Zj*80Ef)+1E7Dg050wWPkF?;!Bm8DrILSs5&=mWnF*}uPk%-}YjHko{fwRvAwaakxK40?KaZM+ z5o?v&X@c^n9&XvpT$B%jC5oUZs|Lp~>i-Q9R~B!jSJ3h>pkhkto$u-B{{xc$W$Zc| zVPloVi{8kW*4E5s@zEAH=lh&tw?7c87L6m`>)9m!LR@3wy>~kMd7wXGio}~+JbP($ z`aCz)^k$o~`r38wOm&-PwD|1bfI;(-mlz?Vj#_(bYioP`JnTM+K9Oe5BLF?S8ct6= z_4VIw>N*A~ScG#``=8tASfIDFt7~pP8Tp=z9kt+LNB<&b z;Oqai^Z%Vp{=b|({u|x>KV!+Fw3t{9odX+~l?j0A2isOs(Lwa&rjj@G*KILcs6(?hZb{;b?#PQf4~Z z534R#P^gKCi(}Hf^!~TTvyl*n0@;#}pWp4`V1GT^5jkC|Q(90^2j&MLIe2F{G6W!bZ=$yfPgYo2HA1LNcHY;tjU_4BPI3aGY`s0~( z8XPgR_V)MP&fuJ;BjnuNwX3W8iDmre=H}2|DJ&A+iCSwiLrM&J<>I(xR)elIez%j8 z6Qw3nu2B(e{@29BV0awe?(gh;yof+tL}YuhXJ(R$Z@tlR$FZiWu|_@$vb#K5X>AoM z*70<=`D9?-cnpDB*S<@?HG@JY^U^)(CeGSjRySX@wKL_-amf60b)oVh+q}bRTy124aC3R4|pru<| zTeXJ0FC`=bc_yeOs^f)vd#{FNPM(k?&LZ-5de` zgD>SK(%IR$v9WOgXut4qFjs>tG~2SJEF@!n3BJkKklYUpZb+b290Pgvpzhseo8NO> zT->px*P!z~HNC^h@|VzO(yCwI-Gvwiwv4JKM@Q3#1-jbWBH7%|_rP=S_&!@Zrj3b- z5tSIe-M9AI-Pj1iGVQkL`AGr(K&a~43u%o2_6_5~;K_@4HHwQ*+yxIZCy^J(JHh?^ zDoSxSFP9zT|J zGpPiq2=ufbaZr9>y~3&uvGmLC=d&hVq0c($-@etKt;j)j0bw;c2HoL$_^)3xO#1q6 zs76*)R1|B}8X4{#OqU|PAGe5KUu`D0133EDjQ#j$9xj-uz5o3Ab9+0!ot~N+mf)vp zloV}bh(LqB-`$cE6}5MprNhT$6UwNl7|Z;tKeI>}CjR=tg9q6;$wG9l$DMBgUsUUK z*qkFB&wqEye%MsI0#-Cog5+n|=@liftFf*w`N>FyQR&+xDr)K`z?eSqL4j`?kKL0| ziO&+5-{TjC{L%c3w98j9PrF}`#WgfQ;ubgrpZDBan45o@8cq)k+&-^>vY?}*g9)Jp z=vmy$?paCdTYIyWd2;FEt-ZapR8*pb5Zrw>O5cZ*hC%ProHMPLo4t@X%gCbuL78;Y za@|(%;NW1f5N!l#zS`T{agvn;=Yh?Hm@OYc!9njt%H%Pe%L|F+y5K+MWtzr^+b7NoE>icoq4Gyq2WLX8F-O7Tz6YbF6O ztZR%Vxr9eTLy37_wihut;FkjZ|KLHohNb0dftaVKCz{C211l>lF|ke{gbnq~6nCM3 z`#IM$agZCWM_}_TJ=NF1=CM=(PVnL)K5l-9t^h4mJS!{fA^PN`gG6UXXUGPL%}YiQ zt{*;pU}lzM+6Dr=gRO0(wEJmkZi!ELP>`*YlTIy@%V=i&D_JJZe8@@m*5*`Q1p}yH zVqaf|0@|K6M%rSYhFfJ(hRMl(*>Orr?2EcOd}}KL|1`ekR;*&Q+@PDwa_)9JD=cOZ8=CBaRaNVAxadrO|oD20TD}r1F>Z%Lp3AIP_=FBA@aZ8yZ$I z;?Hi=3l%*ceX1r=LJuoxPDxG}V6W}z$(uKFqgS1X$?prx+P0SfOU+N&terA8D52Zrm~-4IZuU0q$@ z;{Qlb*AWvF16(HIbi#{QE+5u|UcIAIsZPYTo(6lF3Gv1Bk^l1LCrCdnr%93+AQrvH zCjM{)?i_P1a-q{7>swKNe*SxUdg(BWe_N2Z6*00_(@(QASK0$8x5=M@UI6R(xewU-JT;CDYRBGI?eH8r6W&CO^s&@_7;lO0(_Lovq8`H8fsR zAtm^7OAB7a0Df2(fWf<)i$d21BP4*qm9pAsk!&5&-`(R#N`)(whbhjDJpSA|dlKEb1)9$ow}&hXcBe5)L=F|%3mNf7D3JPwJu_%bSzhlKcjT@bo+Y8LHDF zi(*6^NcQWyJ}Ka!r!wL?h?OF#i-)6`DK9wAgi{o>07~_6&3Sgbr=l_hVkc1cQvXJZ zX&nUO+zw~zV8S&nUgwKro)KE)C^e4QUy&@{$yG6EbUYHxfNkpv82De2L&4Y5DQH2$BJVFTrrn@A zS>YmNEP1LZBm#efs%7ba-(4nuclY8WNDE3D_zDsxF!!!Q(9I;{Qdn1|Df)OdCguZRFA+cUkkdajx26XWt zJCmUl4mQ&x@|a<*qPdjw*f=GsLB5)GY-!^=Q<+~8SsCwm-K#Fj77iU9EcC_BCWXqS zvnzi}VCY71r@1i9TpVmg3lMWT{|S*3$QMuUxe{W;KeIi!yIhxlcvC-tU%K(y9ogp} zaYlbB7~;vv&w+0sKXiAn2gi0Y*TW&gd(PE1tQanq7#8bx9VIwRa8(|>vSDNqo z%*F5)ZCcwO2~l#oI&Vwo`#$lKlx<>U+;hH}l6s37^WrZ)$saApjMd-0hsL2qqu(sE{XFcs;+3RgNA4`RXnuuTcoRdQCHddk&MDfNt zM{VIvA{V5Pv(Cs@+$GCs&(A$f_xR_GMF(7Mz8>{v+RZojbu}#SZe7i+{}ie7W5d%h zPPq6@nHTIx{6X8Ik;`@aPte6Ba!Y4YQN#-ZflWEzAtKw)w^DfQGe-)&mfi07yRnIG zPurtUnjs;Qny!%WqYI4VzwQ^&{A|xqVwKw8hOv4AD$;e**FS%}Fv`Z6OAltbT0AJ3 zzc3O6yAJZjbEhk!g}LY*MQ2TT#7ix5oX<-KUA^ps;ncJ>Lb_z8nB;E8+%#g1OB z2x+yo?zltvbjKl&<;-*-gszCaALXXYh%BY9-u2V9L$$-~Mh(%d02%6g)14ULk+k*jlk)}~^wcZA1DFkG* z#c(RZP@Q2$F21x|iEY2xAdht)q9Uyr5FomnZ;zf!3?}bbrUxrNQ+?>+);dgv7J`Q9YJ!MPuseCz zP!5qOlE0givbyxz-|4nOtdZ>dIYpKe-rXl1?QbRbOI72s8fsc6$HZeWJ^IBQk@8c% z_*83F3Y zYrc^>*Y)9+*AG261ssgMT?NBF%xH0pNW4dW>HI9p&D6z-Tli}0``F0Yqnxhlbvd)A zEGeuj+8AWXuf12iyc!#{+k95-=$J3^9#Hi^d!2pf>7uXVOQ-am%i+PA*I8bY0eE_k zvC|m{SGIyqeBEy4YwTlhJ|Jy2pO={j`n;iM&T_Aw+TL8~|Jr&KrTKn~Al~Zs!-s>g z9b`FPY19e&I3MUUcpv!4TTl?|3N8*QJu+!-`9AQY=qSCwEGq1r1ab!;GRh*_spiH_ zP=Jd>{|dVPsGw$Wy3XWS+3E$%#X>u;v1hEfR#9OYVPzwy|Nksf;1 zGxO7PgB@c}))qtjPKmT`zA9bjNEaIb>GjaJhW6q~f|g_0mF8m7r8Tx(6#OdK97E-9 zUM|Y(j=eD(#}$HqbbzefR&fRegUvku0sto)ndrx&O^^}^xLx{m45Zh(Jgnz?o%Qqu z(}-&mHb&!b)#dak<>0GtYkn35+3m((8ACrt|K{{c!{nGq20twa|_?QsTK;%8Qjl4)VPe~m7o8480JRV zK@$q!T_DOLCGa|oR21upWCIO~{L??trPkP@Wc$4nfue~nk5T!vwS%gshXYGw<5kx{QrUl~D2keCq$$eo#aM zIwWc%Y5P+dC}=3*=J=t!)pd61T6HJDSItdf^9KxE|_R|5e0I3!oF~n12($mTG zzW_q4uyA*!T>?mq#wI3N{8Ut+!xg@M0p>P`Ss;cL=wASnOQF>M+Qx>Of zm%p1}U{q>)1`e%YVPP>kj*HN#S8Y?jc@vK+%<&HL3A5`k#gd>zOj! z-6>000jYXaRFsk*YR!X}OP0Njo3(VpcYl?A+t2`=MWlEW9)tru{geA`2$%`zl^ZjX zlKg7}gMyx6VL95`auJ3B9TIRpCN8Cb;b(A{k^*d!wW;ZQUSQMA64BSslzBcVL;4>H zXv$+EKk|tW1(zdUpD6|=$^Pzc2%B*NV5c5)?voI0@}N4e9}=N+Soa?UJ@pfhAgX4> zZACft`M#|ODkW1`|CoqM_ad}?RQ?2K>uT#w{wSCkaW0l1`peBtfWQ$qVDx?-6&7kf zxNZs@WLow1iP>+nsT+xjiP_j3`!U+v^UT@7Ccxp&Ve-$D>blSX85NW2@p|PR^XsbT zL31g=x^q=#&g0xmm#HvrMkXdEa&q0f>kBSxgyQGV2k|pDnO>pH!?C344hY|<8m4)#F3`!J(1PbU2n9Vg*2EsP)9RbZWfaPF*j{I)8J(7 zOBK4oiP9%0j|1i1IQgt5(v&7%*JR*7fw%zTklZmjBYyl7ipBfDDw4 z(HuM@5^P}?WD?wD(H8d3B z0NB$a^NDmYoqaEW5W|>{4*q6m$3o1i@2e!H-voncFwqV7_e-07^m>u+68Bla>7Y`z z6_8zk3Che|1!q=bR(#l_IjP)JBfQ*$90*P1+MN3Ian=|98}pYrAN{bwXiiK@nO-kb%0y(7ikTn5n3 zrKQ%%WWI|vz4UZ+O1<{cgmO6mYMk^38^(l%g@J7a@DIH1mq&WQ2@PC2VCyA+q*wsEBEEgh{uH=upp8q+XKoIun-+x2z|f_05SWU#w=i<^MLwgEVCVm zL-_=oln?j_o|3tP=|~5#QqQ`$Tq9ILqJdcPy4%%}xAOc}M~}JN49u|O*$%*ga?pHZ zb?W4Fcms}=g_A(=$d1o;r;S{kRS3beIVeN)IXtfI_jv-M93?6-G!A~L{Nn~l1kK&w}~ng)P8 z4$%XrV*aJ@?i;28J9)!FeIelHe*OAbJ@p(N9SppDG<(+G-oPtU9Rwd0XzW70o59FW z*Y~{-25_LP!{Nb!lqz}=1nkBgfjGbv)%YLk(*V!uXRtpu*}?WUaD_Cvo}HYZmlPC4 z(nrq){acb4j8ZAZQRW|_k(AU_etv!&*M-GJuzZoh;bekVj{l(X<0P|80b&dsG6A-f z?KOSxE&-406u^@?SU&ytbY?}2gSWhcg9Dg{z|sS8!C_hpUZ2y~CncJ)p!qj|JOZB; z#j*Ct02j|x7dVSZgz;qHzDOvq7oxGMmf&9&My=0WuGv2{G&Dls`cvO0zI2aswRWXP z-`)`ED}v0Z0!Kslz#3=%eqIj7;q96-V-|Djr%#_^5H&?3fe{3yCWua~Sc$OIf7?L! z2jQzQ8Qougb*2G+Z?Cc7uS+$J4ZuB&Oi)|B<8)_yqfP=<5%9nsW`^4ndCNOG*6_U= z>+XK4XBsLA{B&SXMxCcRCL+OF=Zh@*>pog`|2w$RA20tApHP1l_2PP$IlPwr^fuNKOmS^u)vKzy$d{*ZEnFDJC%-8Wz?$^+`tN zUxV3VNO1}4HwTAQ9=lwi%Af}d86(V2mtBiv3(#C&howMSIHV@)iwM|BL2Z-#c2W=6 zCfz_b^@$Jt#oA5i^5SmP@7{HHcmE5#6ErpG;%RAVPkiqC0ithe(W^9C`Jn#qHOtPF z>y~$xv_~5>=Q;2v@&K0uIDZy9=uOdQD%4>0B1*t$YAwelRm5$*bPK8*kl6(V1vycNm>CQ=bhAB>y8sp=NFc`NoaHtQrv5wV zyEQv{NsYVDuuCCR4nW8p%jrjHW=0tD;vrl$cSEW4?JVTvA5np9NL%=rQZy5s=(V_U zc5}M{gsH!;?DMRhQ&vQP0r?i5{}@YAXa>g$;tTXBDJg}c*f&>{15?H0m;IG zW|+8vt82XyPyzkoW5n!F2Y~rxF6Yy?*r*sHPA|mm`nuuiY@>@J*h`Zw@#ZCP7801Tqsczni|uj zM)SSMsH!@4L*z82V#^-={VNjq3XkZ@Lg zysf6-Fk_$)P+*xE7;ck$flVJkcCh@+#?8%*bgkW;PxiG%y!Xsb+zH9<#4`m zYxRi6N0^C#O9dsSlTHQ)hKF z7xUt;vLZZ3PGxxCeZ|Az=OfhlY8EeGNnV@10{!yk1s<0pu(lRzy7OBte85mtRLr4s zJX|W40$aEkgXKYRc*29(Xx-lS}~Qut=r$`C7&h0|UcGu%X}k6W z#P;(!)~ShpbRg?MdpkOF!YB%AYNp!TMWFEG5-<(H&%y2tr9$5MffS-eyUOHv4T|%7 zM#orLPoiBVvgwD^P-OG|fS3FEqTAD9-t)cVTi=Gs5A5LU*hQ`-Wo7wYPO^#B+g}(} zsj}h%1hRK>DlJmdc^TjhIz&EI1#nCQ8mk@!#DW!IKg~f0O4r5Wv|l zM@KewV`w*SbtOGOyjBeUAtCYA)mtaO6x);M> zLw$X~MJ8;zZK|T8LiJ82%JdpfHBkiU*y9)jEuyGsvLEX2hj`x3g8~jjL1iek57M`e z3aAK&64t(+o}cZ)00Eypqr#JHbL~NYMiy|lf=KRDjU>31$--{&)J>QN8Hz#nXMLu! zdlqhSNWynRmhO?)wS#+z-9PuMZxDVi@o&w77ZHT2uLY0)GQe(}n<|xV;932<(ZswQ zRh9G~6JA`!-2Qd3uj-lyl^B%4_nF3jSqOh+`QSLeHpUp3h0zuJOR{9Zz`%(!``Z#t z{EyqWfQv{*M@MdG(_`+@I!>od6r5KFctBdFn+7%M&=*3mQtWJM?9P;B!|0X--?Go% zxi4DY;(=rO(46z*lM@EoohZ4_0NdY6FV^TjdSXzmVixB%>e-MK-0#S}zlZ6_FNd>MChbyYwb)~Yl{!2EikM76Cdr@0$_CchxajCt z`1t>rj!K6aQ*yi=_w@^71Y#F^K~a$?uA0Tzpp>(x~rYc1&3b##^iy#Za@ z+xsGpCPG1Jz|A``F)@(DDJ>43*Wnw6xYHv!xzcGJFMi;2pr$tJ4Ca2J23lY;w>?%) z^>;KhPqKan#4)-#fU)@qFc%x3-t;J_Uke$l*V_|pQrd}dwNZUjMXNIh*avKje>Vr? zYunu`D&Rx-K$&vz#1Q9F(bNph2nfhi8vN97TAm7oMBr!;2M*E~YCt?MEscQfK6?5T zICvv#$g?;CwqU8uMhM zXTLBp$$R`9FF)56Y+{$xNm(k8Y6}#az^N_BhY$I|;Q$36k??o?0#-i&I#BLZW{t+n zSP)aiTFI|T_!X0occNch&} zS1^caGYvX#)amCBZs*KrfONc~{Akb0PcF3QM9GORU!c5+ zz&iuZdIbuBm;){p5)u+`A0NyoB7i%>3te4XD@O+&BTi0EKscF#qiQE-XM_Fy8sGqk z(gu!%YBz9JD&Z94F}gmRMI%`c#aBOKN^k^G_(iNQC^VFTkukOoWuu*%()XWBX41Yz zCp;rzIXyc1*x%;I{7VKryV>mg^)ueu=ic6Q)e-UWCX$kC5#;szW8;E{^R>g^(016K z_l9Uv@9;2kR|k2%la~%7b#z2AZ22w7yF)CjaBu?bV@G-Iq04%p6wh}C&Ts3Vin26W zJ$A-&_V%(44(@L60v7Cs`S0Jq4;Z4Yq0?#$q{cNFue~WSGF_Ip&ItJ&2srM2c<^HL zyWZ!|OuX(_{||5P9glV2{|}!{iZaU1F3HHI2#F3dDyyurWj2Hm8p_DdND5^;jBFVV zn?l(ll@c-}q0U@H2ou*6f4(BB;TCS3`+fQ5Kbop<5SwWACUw4T-MI)Eg{fQ3u z;lII8jW;BRhlhjx_UG`lef>a*jF$v&NujtY0gk)2G;!ugv(p8u z;QgX+CuT`PQ~@DILof?(GJZTj);E-j6n^hs1%w}fGRJ!!u~GZMcJbYZ7(vDk$VxH? zLT}+S-69hm?P@wDFhA`ZoYX3^f4>LevV!tq>@kuUpx-bm7&e|pE=_B#y6<2~; z!T=EN-0v}ffteU#?C*buo+$cu!3JghbDEe1W&*>)P7*}8eK)4rkFOspn|jZ7;c95R zIXkn;xjD)_OcrWix^*;;SfI6XYx4@I*U7jP!k{zKy6Z;+7nIn3pFiB{hpDv`)}xI_&{&W&U2#o64-Q5^HV>THpc-$uRQ39A3>*r@ZTTpZYt|^Ez-aFk z5m9sl4^p8yBNU|M09Q_wngtml%!-1-Vlx4 z{@5GKaEU1H+Ev&2@+eRF(86ZQSl1=Ly!vgE&YbWME6s< zkcfx~wT6a9ian_>^%$F#jm_}q&)lcEf-?9b;pbh?8m#ZSZN{)ddXx5}>};Wyl!5|! zLL5l;4@^$}1WjOWM#jM?=#WSUZUuVigme%J!O^R>H^nz|4esIL`B>aTAASL7E{<7Y zR9l+>(Hj|7aYqS!eHFoG(Iwsij(9=lK&VHUn3y!mE`58a^B@fZjla0X#ix|?OAD3P zLyGzC$>maV55lk@7*pjiDw*gaEEWzJ?<6E>Hg4QFrc1T>`xB?!iEQ_E`5Tq3c#9+} zYky%H8a=M7>npz5{m9nH1U6~M+9EX#+#eKX5nK%RRfeU)9v;l5J8>QC)Yss&c(o%&wj0)pe+n_K1k6 zR*-wBwr(ZKO@)*1HSRgEv?iTQwqMVR&_Aqu|JTYV zV9n*_y*-C{wii{?1W?<6%0s=1@ z8q$F~v|nFKwsmX~o*&%?(KJ0hPb4oj&XSY()Z!(Vdod{9H>$P?3=D)Ae4U?jIqf8~ z!&ui|#4k+csiJMWe}6}pr{K=kt5>6qS^LBrl`o&+M2-+MLmj4`f4f&Glo9u zLTlz^6{Q`?`4!IU&l`UM92$;m>^f{)%fEf+;)B<;Q?GHtS}Wi~9p=CUH7ZSUYbM+W zWYw{R1A#8riT=0_LPmw<1CsQFuO}C|n=n}egRyBin__;@b z8*ikbcsVH80&!u!8CVQG9GXc-GefFuAz@OJK+~#R5b;tM#KonrZv(B?@i$t=i*06q zy(L~O&`xKAFpd1oaR|Ap%pOBDc;pCvsn_-6siaG)=(wl)93C~)$JDt^`|{-rG=&^Lh4$@Z4nd!hk&|<(bg$u+bT&LRBb{@* zO?lro>Wg2c2F%E99Rg6&txFsDY0Q0CCEt~vGu@tR`s}ociDOJgcIx!sK>n=~Q_C9% zljSoh*VrCkXCy$*&hAX-B+%eCB8h-4mFN<=w-R{ppDTyM6M#yQG(X5j7HlzeWMn`hfiSywxabhmi*EX0%K;Sq#N ztvxB-d+DwV(aVet^>Gm3l$W=6>H&;v9_vds>PxD#3^doT>e`U_0hN*MruFd<@b&li zo63B7Q#gX2111JS8aD_Mht}_F`S{+S)p{=DXeK~-L3=C`dFd))hPLO#?YMoLo@fk` z&gS4-L65zYfgO~>?%k@n)g%E{3!e82*GR#KC|s1!Xj;TY5lu{_{U^F)P+!nF58+uG z9!^la!m$CTweP0-(@(w1ii%u71~6{``dQoSOF`o{R7W~sL0p>{`<}>0auN!wjEhiL z?jK7^`L_R@%vCNK-b-DlKZP|B|Y8UB^P&yAUOq%&d)<^{XgdB+MhawdWAfhKzDZH zq$w`+Q~UNK>gvvJZikMlYia3grHw!A8;i2|W|EM7K;b9`h(2E)+OlKYhFy@uqj zqWjv~G?zU+UpU7^MVWQM?`NG|lIiW`Wo?eJAb)S4xGg(jdksUWRqnevM=~hcw5=Yw zH4jr#44xH;50<+&8BlGHGg3ug%7%oI{XeD4+uQ4(o!9E?p9^u#kvaSJF|cw@c~9yJ zs|oVDb?cZgPW>c>bSr&=fxGw09dPn@^-gqu_FZjd;s>T*iBN9c+WJZ{qzu88zZTKa z|H@`PQ$DYLw(><|Z^%~6YlSvT;livpdxyS!ab5UMH>27|xoMNqcb!j~aBC-cO&u}x zad|#9E@$?px+eYfGPI8G(Vi@eZ2AI%bK?b`||gy9pG>5 zt|6VBsX@a<{JmcG3^E01G;}>f zeec?NS|%oc?*ogUCSQPxuk73x361k3!|BU+AG#cLzpWiWXCN)a-DiD`X%%I!mllzb z*cN0zcRG?!i&xo#6 zSFhcUNDVQW%HuJvRo%}8Y&jYIdMg)4HyJqJy#WPBP*vmbt)L(=OuJEJ769)hh3DR% zUV6hb;ey#~6*s{boezsINBd=`F!^A^T=!xba?)6pPo89==H=y-WTr;T^`SC+AcXKtrKU|i6@t;bk{k4;{9uIn^KX!Yh+Q;6(WDbkO2spd1A=+ zj}sF`W>ssu^k{@_8w@l=L<>60E{^DBzC$f$-?2mQFhzw&AiHOQ?dDNr~h`((`=0eOs0E-BmFJBZ*S|Co(+kV3QYQ9cGHXWblTJZGsKe? zeX>Jt72%<^p!MV7G;wLAX3f#X6wn1&W)V zdS8}5aDet(-cJ4pWD+e7IR8IDkYTPNCZB(FdjuYdZqNE|L4kN-;71oe`t+Wh0pDs^eFv zHx*qxA983UF0Kz^BVpq?fnl69R@$%OJ*g|mRF^NDb$Yir`^`M3A%u;I?#Ex7LlRPN z&)U1Q%p&ejOeG=GUaqNJ@~z2&3ZX5*VBi>7mEp^^l#-T~aKMAU;E!rm){`=mWb;yo;Ne)#uj zvgkcyWs+r%Tll6dGdC%hY3NVHIu$psx%l{-!b^@VH;cDYQ_sxLt3GV2ImLP9x0r%> zbGM^|r8cIu*&c@CcQWsH)W2@~;lC};*)HnM@S*dyyLpbCLJwhFSUMZ>u~b7#E9aj8 z(4{_OWXFC(WK}P4i1#bYbbkECo~>#kyLVrj8P&dh0|^ZKFMLFd4Mn(_=ls`MIPw@Q zQ~MEqmAAP!Q&oOedU1Z!wMLe|di(p&y(s|5&Hs%j=mKCXfHdZXW)7B9Yt}8ky3eu%#(QSMF7f_v z)w?Rs^wL;518;dUYw$>jjbHUpSazSex@Mi|2xKs{RK9N6Hyxjt^NpT|$_Z&7LZ>Th zC7&7F0I53Bz)L#S3xC>+8fRKvDDo`);}a8~ojv7T!&Y`_qE}l_FZlJKp7-rIq^w+6P|$p~&2@!p-X1_ zb#-+1n(Pw^z`e^M9zr|6`A4_Nr$ z2wc*>6mz@48b(|4A$%0!!P4>4=MeHKTGl565SyKym13qQCFeu2^P$QYvr-bNvR0f6@GuOfq(KyGRx`(ENBFT2Kg7FLP|?ZPtNjjktW_hGu0RB z%)GAcJSFQ}b^dQVb7T`TXkgBiVhy=);ZiA(L~4WY;G1zO``oN9G? zT+h$N^;hO7Y^G%`0(Pulw5qZE&BO%h!RF0+_lW*j*vX#@o$)7#kIDhkYOjw z_@W6+^Qjwf>=^iXGjlJMAm4|&A$XJbWbqBajfYuQd6;6gvuC&Z@sfhW?FAu9Oqb*u z`2@6gC<1@}FY~4_fwK+l$8?D~I`nPF0juO6pBl0@eKor$?G#f{3Y$2dA%a3QzszBA zLsC~?U;e_!^^@&i7;#|ZXf``kct?mireR>fd!T#>ZrG!eW#>Z z^buK-s^W?b@4Fsp;`qoaA8N^0rG>u7POUvOE5+}=p{Xp9U-n`L@ zeSQp3#MgaJUZHKO3UFK{`~SJ8uvC2 z!ZKNUHq!86q1S`n1w3MS+9CfaG*klX3YDSbeE_yy#6ej1mOFu=no+c0zbbe6yI>!g*>;>{nn@!X~_YG0MX2=rpyYd0Uar+VsfX#>C*{QpLY@;d2#?xMupoXvIckx+8)@< zPWCfpjsnoJ7sqc#vW$FsJ8p~z5eOixB=Dl8MZaT}Q15kmyijiW{i6f%0k^O6E&t1+ zh163$%!qWF1$WTi&hOg6}siHgr4s?pEi_=m><1aL8!Nc3+@-vh7Os9Vpe zOPQV>0LE}*bO7bVJz@C1A7qekJ#9V6~NmP$nylkD67IvIYdM z!$9II-ami0)w#k)@Jz4gY8kQGbJ~ljR{wLDpX(8D(yO3?Q!!q;dot&$v+)J>w$Y(A z4XMhII5etsy6rT6FR-+w-@iL;9ReU!+q4OPazsNzm-r2r4s1+r6(oemD6yQ(%nJZR zonDeC^#xBp%@mkLBV~weAe40?bSoht*9djzt0OhZ3F5N0xDKb9gi^|JyMBFw5LBb8|L?@5P6q&PiAar@4UwEViHe=ZAvIMl}+qGnf#e2a)JMLz_U04723x%WMtgD~Nc zEW4OaE;6R@+C_PY<~rSGd}i0-W){0nhkRw-KRgAIL)4|!ovTI8%rt!beM1!R7^G&X zvw&>^9db^TIhbU5^l0m^Z!0X{m^nGaKHpK`*|lrKDY1+CG7&PjsYkwi`TX%?u)r|f z!N1zxch>ENmEX}Z+wm5ZyayW{~cfz!l15nHsMLFr%GWc>jbg|BD`LFilo z-3=3cyGQX)=C`Ah9XU6M(No4J(Wbu4?JWAiT-EKoVhaH zG6+cv5UwOK^vf&D-&S77Mn(n|%~VrS0bsj4H5BOm>nYOQnmalqBwbvf3Pn)HjZ(k| z^*eFkk}N0t&pk4Fwk$76Wa#&wfzbMi=YAWj2@)Tb=%y`OW~ZkIAd$atVbf+_5_Q9E znPL_^AhKc79Aaa?WhXSO*tQ&;Jc8W%T7GHixu?IX>7u){e|p>4@F7!)dDl)MQ&7cw zYS5~T9yrsgt0Ofo^g3WxT~jkk;2oXVr5eAGMXG#jF&t6#_g>H?lgVSicBJ}T9N0?2 ze1_Yv-yjBl!wZ@>?da}-P)wo0gO*+w^r#;PcM9kB@EhU&$8FCDv~yK7QdL!(oj+(F zq1PF%z@Vh99Z_X=Jo?1JeWbr|0*h71PmVvDw`69OH6n*6UNMSxNx6q(y^6N5{e;QU zB%*>5j7B_*Zv?|=A>AQAeH}Wh?)SN2j&w{+JN!h>{!l~2W_~VL zF5VMsIx_8dc3|j@6p-}1UQk}H9zA9_egI|&Z3?IywhFV=H9QM2|D{XU_+&B9bzHiu zGZwWHI=0w-7uLRjyB@3onh|lrJ0w(XW+iny1TGb$T@1yiai;%kEY#7{(HUrQus0b8 z7{orsvfnvHPYTo;bIcvnaAfFdmo}JLX*DVb@Uh>$b)(H7>q#aY*~rw2I_%+5hL{7g zB%i$elcJ*Sx`*E`rrIH#QHC|-AMpRz(5j4=S=reTpy69`u(8SEx!$D_6Fa~x!VVz- zk`KFu7Hx+d2ar|p1jms$XW6bv&XwM_AN#|gX?8Og9h(BV0*da{`}c~-G|6h!*@-3*DBc8asN=R*J4689btKL#R8g?~cpcWG>P!YRHv(X#V8W8x~Y zKJX`f?f*0v?SG?fN3TH_;oNi0lT4_LMvvC59@)rNZHpJ=Hvb7J5Rq6N_oubjIjaY$ z<{zqAW9RPOk51j&`FXC{A5Cr=fQi=sL{kHZ5Gi81-7p!#N`Hyq zx#^429`w<4JjCojdIDhcnlG?Nt-bm0@bBE5RdTIo0Q-gw8zA_Aj?n(?MFQ4S(rHq#qprTvI+A0Ho| z4FK<~ERk1(0xv)TnEKqkW+*>zVsiTQJ50dpocYe5??H{-yEb+Z0~q29 zny59@)zR)5zB}nE)fU4oBs4*!TFhdPk-om`i4%+pOkcL4d?a2&9u68d6o;gB@4PV~ zfFokwB^+x7_4O!kWUQF6X^xSe9^oSqdMLfWFLlF9cwXq1VrnxmVxU{&zbDMyxM=?} zY)b&i&{2pyQ}qk|x&H9gmdDtVDza^eSnr3Dnu&P8) zw}RW|rvEVnBzYMbvD%D7N9$d}dPd)10e$YF>PFzg?EBru)YM)nK08>?Lu(dx+SoYg zi94zOYg`;FG8u2sPxM8sO9?ypxazd2_!^sld^MWb&BAILw!guL$13uvuxxnlbsVZ{ zgS-ztYT8gyNG;xp+HP6bk{eA*#2y@ixdvK7*JfdnU;;fBI>=se0|8Z43ZWFYE2a*> zLIy6GLYsftdPe5fKqp6n17PE{D&Ikt4V6RH z7iSQ<<-Ii9le&UO2?7N3!?gQEPw>9HS_aT&S&ai-%1vS4OxoDjN{kPp7w5k{(pnz$ z=d?KWeN)m^0amfiL_d)t!PR0mFl(u-tooAw&DDZ0R)XfItfHRZLI7?K@_{ctA98<) zO(X0K45^;9blUP8dG87C-CO^u$^Dr;<_x_3MYEv;?5;0A-IWxa1 z;ntF<5EPav{kotv9WI*p-T6Do>{ZCa(oz{eSUM=TELyTT-x3y{Or+FAelTwcEi0?N z=X`TgQhCUi@$qD*&6C+C%1~HRnxix=Dok-Lv?Z$^VR*Xi`3%!fllteOA=^lv@iT@4Bgg8{Dv;wPtf zl}8fo@;+k1C$}>bL%hPg$$cMox@2o){(OOOkI1nl=G?kmBaX2EDEHdxOH6U1*xBt7 z4)aWOH>Owhebh~5=w|D}034Oi#K|~fn`Gf2~2S;+QFw$Hr56C}39v+0t8ggq=;suqSdJIKmfEW>Z zR`kJwuX(cs;QIz2#PUf(lia$|h@H{>PlsmtK5YJ0aPZ9BoUG?eY%qY9ohP=0Fn^w$ zj7LkCae0C}t?rQhol{gh)2WzRE$?y7gI;-3Dc-ZatLTURm3Bb{Wx=Brql9A@6AAcrIrkXrNPo1)6g5C>*{)-Egy|%qBfH)V- z4|48LaG8khYsAz%82QNfYW%L{z7q^%Ui4?Z-^m2JcdV<}w(WiQ))c%24hBC109*+! zb9iIt)y%6j2a@j(O4O)7SF*Av(c#(G#o02ZWri(*E5=r3D2ucOXGvxTu$yXgt2<#?0Xaxd_Fv1Gt$~M z;6!ouY%aPnv?z;ItvC~-v1n24vXx10VAQ=S1a+O%&rEL|-Nv9Dl=qEh>sA|qwLfp& zM(@E>`$-B(?J6F?XOc?tm+N`}^m*aShKH9p{u~TqkGq~Qx`Mr4ygM`b1P51@rv*{7 z=X&0kII-y*H86-J%Zy*6;5c|DD;=#I5%tt`F&N!tL#WeFL4hZgm8enfpQzCpyV93< zhPI*TV+atN{_w#ph4bXe9#E!BU!RP3@X6v>R?f=Q9Le0dxwbsagK)Ik%L}eg z#!8McPO~jKXP-bkqPdIaa@20NBXamI+N$>7q=?XX{D13cn}$oDE#;W(ykYO?IFW5w zXkucLVyp`r%dEfRZ>7s5X&pMf6DLTjs+RmAPBjjH?2D7~7B~L7!FgyU0_Ln&6 zGO$a+AtV3&`8q=Kq0*_{$3UoQAdbCkSn8QfPaw z*-+oD{?|p{`g1(CqzfI0KOizowT+9%KRQ_5QT#nf!>^*M>cGT| z#-I3I&=K{Wta-XL*AG!;WWn{cFqyuJ{V@s{ z0_AqgM&CADA%6aS?%zKEs?TU+GCS%~8DWCbgI2T_ z8_10EwxGe^yy5pgLequXhIWjbkPG+KZ!R78bvqJ%=MK}_Eq>rvjdN`|I^y_P&h|wNAsHhsZj5FceUue+P)HI3AcOpc-PwNcina)Nn9UT|@itNJV=a^p@JyoK= zef{;^8E0?$a;SFHSrW3YJO@E{inSfdkn4%ON{D0sR0OcUlT9Sb2Nr)IvG7s?xo7PO zIk4<5dBO?ZCWH$D<3Y@l*l|FJsvFgDTOkD4#m3EWQ!*@R1EMaF)&gI8So*HHUf|$Lh_(oa@m2+S3obj_|c>Kp8XUg!Dxz3pf#RKvP zhzN{=kU519h^92{OxRz9XRk~i>U@nA*F3l-*P5%z38jGJJ0M8^89N}H-V_|}>rb0D zvD^-G4JavCFGpUT8=_QQrC+u=>)6|q;Q%PB=a+ViA>YeBbx%)MxA46AfNvu}H7-rB zrP*Z&RVp6u!^7@4U^M^b!*raed8J8W=V@@iD5VwHPguqJ;4N4^QPAXJ{9S=UI7|w9X*pD^bfJUD?&eiP8QOoA5T%rY?bVl zoa3a%W5Ux*k;2PtQAL}QlDdb0--B|_NV3v>BPLkppkiYTU+^~))7LwuhqNyPGj>h1zSh4sjW9#U#s-XD-AV|Ky{xh~MpRE6q?!tE zX8iUT*(0`_wy+B)t7vQIR}KKi#cl>LmR!3Z3I$zrym2W)FrQWZ*fFGHmZhahi;Iiz z-(Pmu-32(UP{|xCmfEuF>MBMlTNubS56$+N-svJBLC281y!?TwTR73|*9pFjo~i?0GaMXaW6l!oXWfEx2t8RN zRfU&t)f#TnO0X}QGjILYm>2tnwzRJ+_welYK8+Cu>Rp^TiYTZ*Q_m zN)*@dOh3O&6_SR`;uq*^zIyMAY+yy#40nXGw7vMcx0ulHE7@^G_amd(?j!+ES=DK1Hm zujh5g0;^djw&FE>=SJdf78bgeaGh%-2Guy&LmJ}F_Lt~ii6s~4 zY)~lst+rzCE(t;9SIrYtr0>Y=ENOW|xh*a}Y~1D_5^Fn2R&9cHcQFvS4k+Bx*6p)1 z0KiL^E_ulA=UK~0)F{q`*Utt$^8J8;>1FyPkS(?VE0&R);eVw-MDFX$S5_RbT9cI= zrx~sku>uK%apgXOXEB)c4%Jp}lxeyD!8S@*M|=10T*-0!nf)ZsJ!vD%O_MWmggYzE zp9WUhDTEEfdqL|9kxx;&T0?z3k3r))pV#IHTZQ<)ZH zLR@Zpe?MDD-?nJhz4kSCKWP2vwkhmt+=1tzH9qSya}}gNkndu8x6ZdV^3p^Rrj*AV zQ&qh~!Q_%uDW8lC#l@He134i9Be1TRmOhP+K6W(ZJy{Kch`ljRHF!PGR=0EH_RYxX z{`RinmMp{0t3^eUD%aqhSKFi}N=du;tvlS7hlb}6#f(Ye@VpJv1(_o2modQe;XA6` z3JV^nAcqU|L4-c{84@^2hrSyYVIS$D9k0V!VMjBRks* zb#`UebVdK^o)f+TtQZ%Z6yB9|G z-vQgH&4=Jn7Z)B9>uc>FWX0=k!fG;LqcBTXGC@w1QM zyDSnho*TQr{}=!`_0oPyB`3JR>ZM@b2D{12wS3h^sLokaEcG-c8|wkW2nLzb2W7hvPfY0+Oil zp=+;{N6q*lf+1jpUOYh9gJRHQ18Tlyfc-(Isvm#?R#dc8bd^w7Qz z7>GhhyeAB8hy^3gJ8AA73{_%eWPA`zd9%PVYYUsS1@8koWh<(VA35bF{D8urp`A4N zt9i19MzNNM+u*^!@bHTcAJ|Ks`pH_Msddy5mxn$*zs);{J#bm?($=Zrt-;sqGf0tP z*~Lc7$=PQuXzopS+ba8DB77o~{uKA`zW3Lj-cKfrF zSB2MRj{?1S&qa{W@(dpAXR_eTPV9$*Q_RKHwMrCV?8Gl9)1TP|UoX{7O}je~?f0aZ zwXKNQ(IY$~q54>fk4@CNH8uKzfg!HQ#-^sW;j7EADK*f)PQLl~O> zAi}>=`aEqerQY3DNHX`x3+v%LQ>~F(xTbl{%N>l;();(nae3GUWl1JgR;F;tvu9V3 zYBljoanV+g#|XfCH`RFW?+bLzwMe3OT+{h@6;9WCl$J({?n`NFnysp%K0)N#qq6)k zH`fIapFx+lB_Ot|xyX4+?0^^9XTxkm4eBx{Fxc>jh--tfVh^e^MLM)fc(-$mgu{8SrFrhQReqGSCay(z&BlLHo!-Rv}R`-!q18b z9q?&J_}f)+g=}>DWjg8|aZ!AC^zRamQF}?KUBKPaA;w=wPUHW1Lcp8GkjrY+Yt|^< zx1k^XHaN(=^tn0?PIDMP3`4(Sv-G8Qb(1pZ4a!SmJ8hRAYux)IYUA2?_sLAz`Y!92 zr?oV_D&W=xfI;qZ@zdB_3vd3Ra`7N>wWIW896(rYaw2DonK8HN*n6YXeNGoj<4w2; zEky@OO;cT6T;ovR8tIT_)zpFl_02Yd0Vn;fO?i^GBI8==AB}I|lRX3-9aECZvybqD zV)vX5r`+)bNjqokn{+!xZn8p!AzSe@938TtlYlZ;>1*58T*@2V)U!)4?4+ufwt7Ku z!c4H6=fa_y)L)$LnvqM_fMILtsbJU*WFN^CJRZ_DiN9as!3+BxC} zhlA$3-`uJFt+v@+hp4-cR!p%%Y#jK|XI)Z__x#d#J>j9lzl9JoGbTfY+hKEVoUQKM z9lsv8qL4o+0{=-welNZ!PYv0Tuv+Fd9HM8HvLAxElAvC$e;KIgFSfBG>_m*@8^6z1P<+riAt%%Pw^j)`RyqB4Dbn8sZ%-H@6Yid1y6cSMPgWpvo7 z@BIovV1uVf!OYx2o){oi4j-0Zb}x$5JtuSoSfyrjB$5=TXJ%seOR(M>g;=W3n5*Le zmTh7k0EfIMky!{wLCR9;GjCU*jX0a!Z+h?}tB$hv!a zK9qP|UT)z>Ac^d>ynoc_dCwp_Oj%aoJ9sQ--Mf4sfL|j^H#8d>cfx{>(FxPp(A1r` zZ+EO0-=MQ^Pa;ni8+tj-da?vgh0hI*``LZjDgz!XKzypm zp-Uz0x?O zjuQwtbP&*y-DL_K4Xx9)6aJ7{be8mV!~toq=uoDIrF>NT+1Gv%6%bID+cz{idR6a6 zwci#tmf!&VeO{8w8Q1|2=?LxF6Y*_NMI>lO*w47B&3!+7{-(GSmV9tR5)Al6!B~#? zx@&bY;{U5!`pKo-A|!;eP;W#CLtkGX5>e2n|5*;!r~?2unG|wJRENPq4hE3H8h`yd z#Ngy03I=-(8OITAkP+v|g^=JsQu++fEP#1f_hO2{6JEiL5)TD5(K&6oW-f3@&@hXB zCw`p|E?|91?zWA|&?~dcxn)DnT4e_JI*@a4I&WczlmN0Xh6 z= zGRilV1mEC(($Bm-?;!$BiS3<_)8ZT-32sb=3u_Zhelzf!-&yekJoWtjI@>pS=DZ3g z9Gf0IF#Ce-Sr|Ycu85?q?0<{=JWNtmAK;ct2Tbi4%w&3Ly)Xj*r%jgkh7&zT~2SZQRW+|eYs~yILL61qq!TjV$@ggYuU~hEWKkhK!PAyW_))wp2 zud9{3Crb$U2Vr6=d%TagLW7qsA_vgZ7EXoVo3g5@yRs{SkYYwn!~UZB-J#Za^VM)S zl~b^%yvOkj@;u_kQ1)Gj*9bAkM&Cg|zxuiwph`gXM}&#h4Ay+p&OtJ`%}rf9vW3&Y zu$~b>qd%6^dd?2=k==XtG`)GVY5yK6DSfHpqk_j$n`U>w?cLhCcYc5gE422G?ECKj zc%qzDKH4vH?OMOaHS}c%RTLS2J$qAl<;yokm0YeptJVWOB*X6?-x+B+0Yf>Y04CGv z?QyI@U2yrm&Xu$4y$F5l4~gt2cYKZzWK9wW5?*VU4UTr13rnAS2SDAy&3+@N7Pk4K z-si8>cgKpFA9%NY(qLZXS@ZMmnqTV29ty9M-k|UvOq=6oM}x{bbbxOhYZw_Au!Du2 zJ&zh>cWveCy~43W2>w}ga;SIoPA!M7uz80@hE}LlG~*1GEbztq%SI#Rro?G0{#>HOt? zAnYnHy((8sRFp_F%+o!Y?E3n#n-l$}q0cDBJ&_ z;ZZLus89Xl;^GVon=f7NzMcy1xi;xz$alA;#aUBe;svLB3l+d5fyRRXqS`1bYWwBO zJx*5H3WxrxzHYZs9f{ZC;VC?|*Zca6?s7A}0|3UJcbW9z;F^%WP|kBVTJ|As#BsBv zMQg86?>^Uy+5R$zIR;A4iSQu+*?lO2e_~kd|C@T``8@b7v=wweaha_)Fanyy2)3yDx6- zJRqd`dYkr9E@;N4KBgfx4!1dH>VmwyzpPdGqpXdcdh_VmAb8+0jtxDx zbY4jl>AFCxsi>}&5!AlH&h=E=k00hGJw)VlxXalsm7gGVC~nFxisg0=^V(tHyz>AS zPV%}(gMaaw zA-BiAeQTWi=$zjkj}Z;S*0h1k-zb66ztL+r~ zh`+thZIs(NaU(BG&vn}-ioU0`zs&wU&CKFGAr{xN++G(R({lI9zFxsR-ljtV_MqOhy)QTFL4 z_5kXPg}oVK@l;rkMn~)GINeftx4pwd5-cI7Wrkv_DmM1AZx2RhQ{Jx&Zf;)(DoX9kBav`!whvk2 z4v%&L1>}E0sBfJd*&aWZbY6cn@vpc+f>B_s4rP3ZY#;hWJJd5BJyJbQ1G9?6FQf5l zANGo45`Al;3GHEVN(%E2+p6oP4(V$n?&iIZ{9y@)Th$yy)mNLoaC`zPV%(9*js zxS=Ip)BO~RW{`{6M9jCyT=CcLJ93bRr~k_Xvm5VSm`_)@X>Gm~hjjFptr>ExO)xHI?eZQWvd9PyphEqjO0yXDHgO09Ydi`0{Xf(W+xy!V?a7X~FG5B?ol z*PZ<*vd-CMr21xgZ-2T2>!8|6n+p4#yEo~FhHeEloYlQCFDG1N_MEUtnMtO^a|&&|yz)8#?=fTQx# zriP>>9_raLZbe1T$V*dHror__!nJ0TGZd$e-p}}zV6(JQ#sAk=z@bKzvI~Zrw`}P; z7h_|l!BfTMh$dC$-g>&pyJr&W!@Pseghb5#NF%13d}H1-Cxy$8#|LC=ndrZmyw7L8 z=}z1=d;4ZMK_Wtq19)5OR?hE*W;RVMgw56&tI_7}N7%VLsrF+lYfO}+Px_P8@4LTY z&nZTf5@hCKMXI#iBlC#+_ut}(800#W~IScb7$MLeGw_L?-^;w{z$ED^)8$!p7SOdg^s31)m^uFB;oRP1YHm-AlQLcoH8*1tEI41^fffk58)K)S|K5DICoftq>#UPAjGWl zC6Z#Sw7->&Bp@TNfiuj_c`RgCU{FvHQYDn$c63+{H`_WU0r0XrcTIEpgKq~U;g@Gd zugQP?PZKb;58wYU1Moo|mj5{aCbMYXEE}Zw>tc;fRoJc=3eH+Qu8&O07Sk1%nkEz$I0TTbMGnx2iY&bZXAO< zKx$QYa9FeI9aY8N35o6;4QV-(^;ndMP^OpK-Gt4qE!Cs{?&=PB_91nh z#rk^qCM~wl-2nj5`MzQOXr}9PIUdQE-cu!4_d5i!V!{I7did~7lVt!oz6brDI0E@A zX~qlM%*ZPt(ShWNiU}h#*P=3R9kXe^Zp9H%MDjyKacCWBzfd^WUb1o`jug5h(7Z-fnwD;W+mS7JXyG`J3;az$?X#C^ zx!5x4wf%!2Vd>0$HW9~#p$2clIBEbJjQg>MBXa(l~K$bqMtC5|O~zhsZJYc&Imy5%T>@#^)AWg>C-n48PMk!t+{Ahx z|HQ|8Ajtu)GJ}fiZ5i6hj`RDHh7&^vc>e5X(5tvk$Hn~RSU@sY3 z$T*gjDtw##q|+8EDuIo>Nk^-M=50j?!Itd$Z|V+fV9-rM>^!PAv5S5z2DgxfjVIW^~`cI$#-%RQMWb{X3sq@aXY1`$1qbC(DYO_01i3Eh= zjaPJCZu~uc!+d`Cz8n!oZflu2{hD*O?HO@>#-6&@W^9;LwD_;WvBXDlE@1F+_rfC) zMyIbkE_tz5O)mTT6zDRjvRs1x%pQ?anH0JjKUCw_qM7J2~R zg5!`1`TKrj1_pW>1+^~H-F$3!@$~ZxotvFKTn3&KR3g$xl#*X2w*W!I##!}x_%3ox zR}xBiVk|zEDS!X_oAloQw}G@ASlGZ@6Xb5C-Ao@z2m&aB1vHJIG}Tv0I6}D>Y*e|x zpz<703g*b#txQZO&z&n)15v@t%lq=h3sHU8W{}4rV({GoI}%v>Z36ZY<`uJq)fGoh z?hAT1I9U3dr=9~4dQZYzSrSGxzv5QkTEa%OQ<>tETi z3pTmcv4+mh5<@cN7jy|$+Yiyx*AvTj?4dpOo^CNO;;rCvPNO)eRK56rR75CLq zRlVK1CZdFZ#FiEeq*G9&Qvs3Mu<33o>25Y9p@bqzh)9Qow3Kv9OG<-;q+8<7t-o{c zckVsoJAd3U?)4uX0~~v;wb%Q;b3XG4Q&WJ`z-2_WhHEKBFI##ePGVM!R+(&I{Mr;m zCCiq=M*?dCn3n$}O21-gd;pFBAG-c=7Z`2$PwoO(veSd=I7>bN#?&(0f#UzK;>tO! z9c@Fm4JfLhbllqF$k+b$-dPw=8xk1a?1cDiS{@u;=Yd_;(oa6x?<+ioeXwBrPE&Lr z^k}ho!ICN+jJZyyuWnXeVPNS0uA9pEUl#hgdB6#srooa(xc%jjNF)f+Bm9AH3nfF_ z4N0&ei%~7fK?D56H6*Ws%G?F|H+jV^*uK-!&UAbPyR7OM%Hg%28Z^Z*#~C1;UV7Fv zAu99791^qjzx;xJxS^G(=ykz~jo}Ha)}AFe7bq)ZEr%%09DpUq3%$X$XJ7zwe{aOd zJoiuFv=~0O$8wKxsRCR$$SNjnfUQ?}A2VQ?);GU=%Jl97k1Wtdea+h%_PQYUzq=Q3 zWyvBUOUL5w!DAhZ8%`0SWmG2xfh$!bc=`v__bvtCi~;#VJWjqs!G}37YrZ0~(;*gi zO4t~+rk_S=>c`#E8~2A?Y3tGU4h|S2(257&U%RE`GN=SP2#ELrZ5p81KS0QDZoULZ zGq8i_O^-o}2*RM(_ngMsvRoivVytxAQr2s06|-7toTu0%FUpvf3pt8@%39m4sduwRdwIro-qOYBrKfeP#2t?CKxIZVQ_ zyCn~x2*u-C0)+>1$K~- z?VSY6BJ-Vf=(9IjD>{-CI@Yk4dm|!p8KEv?V`Jmy?ynqWVr9h-H2?-7ye)s|>eet( zwge$>&&sHI|GNhuP57%&!kS7*-f0AhF|tQGH8mB=H`uoD@bLcl3>fp^OCwF2twFvx zGdo)ihBNSnIJvl(-GPdyxRiFn$wf;^DeK{nD=Mc zGl`#W{_k6qtFaXvK?0WqO&hm>z=%F4Y)t8ADT_V>Y6}fM++sp<@{>Cc92|=KG+4HQ zbwlt^hTY8`$ZmoW=WemqAAWiZP>e(FoWN`si?F`VI6FOIWN64qzD%Iz__-anwzLSk zY-lO=AQS%lK+n}zs5Pt)4p!bj?k^KzEiPyixS9HjHE_pQ-yXz9SqqDcj1Oc{DUHB| z1#@$H4SGd-&y;|nTfn+`&^+aXRt=)|k6k075yCQpL%>;HL-kz-u;EPQeglsMFbJ%f z=@QsU{A^`Z(u|0AkpX*ikw_Pr5O5T;wdIItsA7fV2AutY&Pgy4OG}X40+Ilf5}<8?#n44uT%Z_qb$25b;$45Xy#;2C_oi5ObyY~n zBAU1{#;BwM4B`xq;UW4Qes|}^`gd>6H11FN)PW3@feaWMq@fo~Ud}Wt(iI}zNw6$AsNlSIpc*HS=Q{(ZGABMBo`gA1&>P2rRyzF`At5qIWPEkF==BDo zE!;+OiX>1?-zk2?xiXO1&;bU685HSlZEmjk@Ikgc zQhXXbStJm#%<=8|obNJy*wsE)!9pw0{Nred+bLon}j-bjo?I2DGAdifx7M_evYwoAZ>DZ z>5-sDTlFl;hg2oqmCK}^lo!k>o>#K#U}|(+j}P~8B^VMw(xsH4yj-xQ|9W|uKWxHnlMC4v&l`6lGFCAzpp+lNwmtVg0Yq)lD}7<*L}zQh%dq$401wU zQr6Xw52U7l{0K-?R(5D#N=I4&8A_5a56QybgD5Vonb$?k;$pMzNsgrjeg>=ia&}i% zR+6zGt;cqNh8&DKYh$|+CJCN&WNH$Ix1VW0J)yhNzyJqHI60d*LtD>@ zGGwfmmbS&N-zZ%#?{`;u{MffT=*d+Z9iorXlkVXiHwm$y^ca69kN5QnWLZAu^c)## zEwvgR8z1-CubKiAE>H@hzYrfmQC7KR@lx;*N$D?TXgK>>h4^s1jtwUBJ5YhzeKQ_V z5CE45Vi;&LGaUdp;GuH)rxM4A)qcMPK9D_sGXh0)f2 z1BZbZuSnjH<-zc}{WP8n0JV@(?v%ER0AeO$vcJFB=j5anbBa~(*jh(tBJ=Ge$-{FI z#*@_*CqFq(99C49;WMpV1PGQSAtDO1D=XzR0>H^af7%!_6g!#Oh5fn=1~h*VNEWp{zhy9=m@#O{ z!rX1BszF2}fA#N8Y$g@h-@_+dcmF*m3Emn|smKhS9yNY7kg2Hm$xaN}$@OXKj{{Gg z6gdu~SJPbx^D|$Lfm4Km^b#-uL2`h}zTJe035$-D3`hNm#A($&OCSwo2@1BF&}Yv8 zM8+UR?fYbTUm4Cc1SQ_#=Z76lwIneJYj}q4bQ%wc2@mg(xGZ#?<)*o%B?ctmE32z8 zXNT>EuA^utLX5B&S@YCjyta}<4sY_k*Ie>&~T?Slv?i(kPQYP=#zyIr^N&|d-;My?HvzIW z+B<1|MazQx#D6V0M76|WK5V|@ZJbjji;3CBSn)gzx}YpsU_bJgnM;MW?srHuo_yjj z^DYe{7=T;*W89_nrrgZj4_L4)62a!BV=U_VbMrJ{1sAPQr_g$%_+7wJrTgwm5S|G2 zeb>$I>-zX9si_9LD~l$Od$ELc875<-qM}j)v+~M8pErBX613vX;&+ONoEXn>Z$SsL zwX-At0Cne+3xpDRI&ClTn=~t1mP*&@!Ib7wbL)o>t;4$GiP43kdnw1@PzMSE1tjRY zve*0RV%XT(^9u?R$inf56#X^kD`P$xzIc6Dk~>wcmZ{3jZ|y2|XTtt$-M9YlltiJ> zFF!umY>WcjsmSAdn9{xv*!3B+k?V57>L0W$EjD~o*W4lHj;yn}PS5p0H5>FO?HHl! z{QIXE;N4X4JWMZ!2WlRz;o6J~w4hWUm(H;0^4!=;oP8PN3$7C%TI9}Pm4!LuyXt}@ zB;=6P0X&wph)y_4LjtdvhBgo9AMpgwY-~i4XDHv6PP4TzHy8D3WZ?xL8T3u4h+CPY z75OqUGrtRttRNgmJHR#oq(Uf69BDidq7Du}b5T6aS9C^t<5+eD9%JHGPlyE0fHmi( zAR!EhEKQA#(S##jxu;LW+4XAgyR2*X%>clSxHu+-N4T&&V73!}>Nw=1c^^ZOcxUq^ zkzaFl&CH__ocOSaY>NknK>y)vJC*8vd{7M zTL-GMy`ydt@i^cMK|m~qlt*f6u1s@Mnn5yj2)JdoBA;JNVImEKjH9;7bz>2W{&&za z=b}{MmcdfCS6N3#$h0#Nd@;>S`I%XAIMrE&P1;|8P1x-06=!E>aQ6_X7lAge4nm=a z_2`u*%Kmfr83_ zfjm_GsP+y;y(;It4Fku77dtYgnqH8ai{kfv;oHO*FD3bV;O+55x6QdT3MkaCfXics z*C7`h+IIjHmO_tb1#m&Ysc0}~TfK$TPQ_n)5A5S$zur37N&}uW9o3t+^6`Te`1D#`=+ml1Vf@X=w&ek_FMVkFB$ZO4X$v|JX^KKR+e zK?ll=+;c3X>HP(EUm~t%WZ(wQ<0{VffbnS2TkjQXOG|7}?D6|n-2(}F2h`@qb2QrB z$c?kIgTRKauzaUiBciJ1d9&u8k^PzR0w>0|L&c3t>;~#BdOO`rx(9M zrL3p-Rw6`rnB$oOK;&2Dz$p@h^@f}RqejFf)1-nH%BQ*u(5bCLhCxrBJi!J9*B#8_ zv7&MPIk{YHto8Nj8?HP%MH$0f80<3nYllil($d%jpdWld zFAI_0P(FW;icr)M$sA`je0)`?*+7h2BEKO&^c&-|cOVYiU?g0CHDk}&oOy> zO;+p5gK5?(r`0lrq{@7>sP?z}R8&dT)mpPsCMFr5+}@Q#QUQvRd+z6a{;kovqrG<@ z8bJEXNpn}(FH2*l$S5dyKlAZW4WH@Mco*_YhylAb;obMSxt(^LXvstdT7xi!lmKtl znVFfyFfDH$)6QPY(%JV(kHHSJw|9DNjdc~L_o_;|M{-5Q1y$y_q;a;B(n7PI0vVDf zc1G?nW_?*qUzlL1M(A-ogQ)?2t590ll8U;znd=pm2m=_xr(Hs8W5#_R>v$0l)O+2E zK`#l{>l=GvRE-_``P3bL4jj;H&KTF3E5#0X-KwOfN#@k4aFF^_CNEv3=fo%Xmrjq* z&k`5&mvh=GV9zo8L!2U!COcDgNl4 z2540Bpf~T-%#!8c-~S8@tQAmNxo+_kKe%xBz2Myq!dR->xYuTcdU|vd>eOwx${McP z`5mHezbrb%>Ea%ek$!cmzX>F`yXm>P+U1WaI%8`HmN+Igf`n5w<+D`VW3F;m2SZUF z5LDm#D)&v;x!1$s9rRxQWo*iC@+K%b<;TYd&G|7)l}QS@y-QBF5}{CgKYK^p1xbzb zj4D>oev6;UC@8JZJo#X$V4a>S71*zd>wOjk%0cFJ_TPiWQ#my+y`|;3aIdPe(pm8? zLt0zdGo`m^G_Jf_Hn|dC0x|~*8a~Qv!qUST*dm$}f$DnlP^tk=3VZR$s3;jIo)H7C zt6r-;5U5)8GlVvbTmBRij2yw0Vo7m?Iqs5~qY{o40V5cewh&N}v=CgwsQ_<!h)^^)K08l%KI?}vsxAcsX(vMWFZSpNX6G1Zb96X-@H=r1iO%6 zy9HVzF!Xn}w;@VPr;z@1_&FS$SV1iJ{NLJ}mD;e(k`$36zm2+2H8_>s? z?t2oBB`3G&2jNk$Q{P$hdoq3;<-HHiY(-8*7626h2wfY}r=#3Y7lMB^Okqj4EL?OE zU}-u!+YIGj`*n3u251|J5N9FRd^&mUZ-+9pFGYO3U%RT{_kxyP- zoX|!jh8yu&^k0{3YibH4W?XA}1}{)Bx#RZ!KE?M7J59o6rKNdV`xFzHxtNlV9uT5F znxAh2&4SNC<3`Nu=t=BtpR(g^V(2}Z7tFn&(x(jTX%%b%>jhe(=tMmBa>02Yqy!PJ zaRn`8lt;e+d?U^S+B~qD8II9ukdi_`U4THz*sS{jrZVx&O3EDq(k)AI7W*J9>jiOx z^^+&|%8HL3eHkUC!RDyCYo224>F&0%s0fo}K)TL9#E!@CH#T6_UY?qIn#N9-f{h$s zV*gc==XiHlSIztPIO7wAGh~e+DfXNM7Xox>`7FQw+Mendz4w8EY?-cV==b;(x7@== z23?>bkC6~?_cJM(V6Q0M5N&kc5pOvSgT()I)YfrTzxgD}FS;4{Je(IUKiygb`9 zTiGH*q4v+H7QOd!ulitRzmgA(8Cjoo-qH$1w^Fj6EUZ?2oA%!3o1i+#F_x6vr_%kC zq4`gJeEmO_&a;ifN7IeNumJZj|JT3vfzIb!g@;qO= z;^${SJ)Xy4-0%ejT4WUJMiLH{_zwt|82b9v5kjgUm(Ih(1G-#cr|g}vQmf(?1z6JR zHW_^%Aj(cf*#WGAWSy~>Lm3d0l^YlN#&!1MYm>N#8M#w)Gc#O1$A>Ux<>w!!6_J%% za#lZ|p856>INgqw+rG`6@~Q`Xh~>tOc^Gj*%xJUT51>w9D?&K9;iRcFqbWgzMn=-W zn_9JD>ZGUyp2Ui?s~FRfS}z%IZ{gy;pYuKKH@8hpY9PREvDk3BKSOSH*jA&AHKSb7 z!s6xH!<*sZNoGby&l6lUhC=Y$x`a}cvxr3D_d)RvSjMeKo?2R3ELdPmx5X@?(==}} zGA%tFEcBGjpQynZ?W=!%%)@AiM;fXVNJs!USV@`?u6jUZ=c7r-I4~=rCUM)EHH*F+ zP1QRyQq%xuww)6d+eW3DHI{1GORU!44wymxTwel>J=FVsg0U{bMg83@1*b6aKE&+^f3g1Aq z*W6{;tiiKVyV|uVE6V~97C6z-VgiJ?Od68k9(q794TvmzUf+cV=@@)#xB)Y1N(l@5 zI2%lQrUfL&P>r{IZwW7S`csYL9!ZFRJx;;&!Qp0O5VR7lLTEk>ZJ$WC+sjer_!lqU zby@cWt~OXJ7Zh;(?0v2%>}MP*#YtPDPjTr|t@ue`;JLZ##t@$x!*ei^|3c4oEWEyN z@EMQ%zT1Ml6!BYjs4d=ZBFB=0KOW<8+~1g++v(zOo}GkHEV{Ci68fjGm?WJkPZ|3I ze;!)!!JM~1F}Wbj^kMK7l+&XUnH3doU9U=8dBG1(&oc&Iy@1mxH6NC!9I?4MptQj_u&gCO{Y;+(Re|-o9w3 zUVpXFytg%{^!nE>3E4)*JCsa}CA8-^F%6`)RYHb;hfIvCTpHiEI;h5w0`5 z9c~^T9h323B>VZ*uRK^m`&2lLAD3-2W_VeXI*aUP#NitPZoy^Y1O4@HBPAszWo36> zcLNNNo|Z0lH!MjW}+dp6HRK{kb*(r4D723_rU7xD05qRq;}vr(}D z9#g2wi(68;J}^leQD`ihVSGc--zcVAzCO>UHR-)klN%U#zIgYh{mXW=(-rxsnOM+| zT)>w$MYuAbfrquQkRMJBHAC9@#p%RE#1@MMAz``paFK?y;#~Fd+@epYg=7=8Jg|nj zgj_fEha*lGmX^ldn7BcAm;UT51J=W*frt=>|LN>{`33p48c?0GniK&Yq_tn6tW1YE zFUm?E9e^<2Ujq~N{rfnKDySP|e#jiMTc(if_Cw!q76)jO2r7QU3K?W2aY0A2kjJAT7}$D)-7bk$27|e|`R31` z()eRApKO(ex%2OX@5wM>5NJPpsQH8md>46zkCl{4JE62-A>D&HHyU@gXqA?apWi6# z8)LRRcz?aPK|?Jh-|P;hXSAxaitVp^rx*tZ2aCTxQCnE?<^?oHKNItb@;ZC$OcVon z4Lj28zAB|PM`*A_(5-eQ{-r-!{GxmkQ*i5ztLK-9!Y^N>?IoVj+qHAt zz61hl_%$?232wDu- ztIt(mlQ`ZhmoNELQDMYRzO%b)VP(a_ArgraXidy`9MP1!xp^19f4jp2(YIV1+i<q*YKgCp~W{^Z2wU!VQaL%SnI#7(f&>O_TT=fzZc46RCPH_Bs%(aO#gpXdb}g> z_JY@O!i(4Kt*y}trtRI6um={p?`{`^a~bal0LLfbC=wkuJ3AZC;e)(0fdk`V1qB7E z_2nM{0ynB)xYzdsI`CLPbHDjngAz5iWU`{Fs?B?!X|4fyscjGu->0w7$sJc(9D~fM zu@k$^f&*zf004tuiu>;fn0PqX$o%@H@R(`M1dNW&IXAB|Zqt)pqav7d!-gjpbIaL; zVM*4sY*jAsZ3D6lK6P_*nNmPRS?V_86ht#VdcWBft96uLK=NEQ*T z`A->y%uEORRdj*kW1gKA5fAhZ^~`rG_Oh z`g`r~?R9s0Vr}5)BC@lYfxiHs)TffAI$H?w*J0;Rhfhx>CTjhue05n_OqT;x5&XdtMtU$!!WQT~f z=KYtlC(3D6*Lx|IiJxB`ELuDtLnR7Hxd}qRMR8~#M1n{8pP5TYfyoev%U}zt)Z^~@j7s4 zK5GYN18{kK_|X~q$BYbF)_Ev~014HoPMKyYq9+;rmwE^CY5zeV3v{Z2D;_-Xk;H}A zsZB)@r#pOnk#r)oR-(D}N1P?uJHHpR3gC8+a(VcocEGz#6f zVW7y#;dXCoodl{Ah9KM&Z@DT5qQi7uXWVYx%CxP$ty|~a2yKd>v*$>EzdunSjIu{9 zPDRTB8n?2tf-La%2B_>HB?V~(R4S9p$qNe$d{#pYLB=K~URzRcU=)PoyO)+`%SmQ( znhWn~-S2h57l7xRw8ds%;cQf=wWcXC>18=bU8pQ zyV@sK0EGwtz9`sVw=+#M-tpt3pRPT|tQsC^L@8(C!(Qaoq>V41OE*sDQE4$iB|Qwl zC%O~Pr8}>qnqkJ6ZSwpsIlK1K^mH`v=;|-fbtY3K#mB>56s+O_4ILy|89rY#%YwLS zTsk+m5EGru;$r1**8Mzd^v>Wmdv(Cy|4d*K^eYpu*`a2Y%j1O}2)aD^pa-1F4eYqLdNpElT*RN_26lyM(BBmO9#5%vU6u1oHf#Q!Y%OVB_ z1I^k(jXA;%z&nsS{gL#NhkYOJa?`-T$EeKa->&gi*!qRB(O^0tm(gtB?AxdOq-rqp z4-Tgi4hs~6_)ZkeUeLLI^{x146{V)9r+dG7k_CaiT%Z3A(UmKV-Z#4HXX01yk$0?z zz8-#ic*wyOiB1f#aCH@U4`SSvHRM6$Mahe=e!fVWS=5I{ZIt6IY%N$A5|uqt7i( zddZFKX#c+11N7FkEC%CD0QFX@CL%)KFi-Uy0RaIxk)y?`TsFu@mq2Sn=Tp56QWY7< zCRH8oZ~&4)$G5amLGS6OJmmww#V&x&|Cg`8W5m0wYK+4rkSf_I*u?KwO_Rq9|B}L9OBr#g1)v zxFukqo}P!F?AK{%M6P=KfC!@iuy{1Z@8(qu(~{mB0Ml^clxNjNp@O1AxBwx0ltjL^ zx+(~mR4xw}*J&A1PkY}!Y3P-p1BJZ=U?YD%qZ^=lzlfJaODlX~+`*al3I+d3jLbsM zTe@4dgejF6Lk$fLkc?@Z>@25ZfvVjqu*ESxjgx*n!}>o*(Vv;(+Cki)2=Wlvl~mrJ zgW~<^OoK@0E54kX8X=zTWLTCvVvo*Tzb1i8jm!JqGm1DiETGXGg5Z69LuC;#lvmCf zC#C?74d?I+{d4v8Dv%>sdqm!G^oqx@$}38Vt{!&~9CRl8`r5|FFJ$2!{aB-wJow!r z@-wowMYep2$XZsCdZ!w;9S1UG+Tf%e$bq{X%Q$KCkXlOi3V;lwG?}NrI>;oTHBL;1okUaRW1d&u!+Q! zav^pvXPM8pV-2^)%QvDG&id-BYHG&6e0h77UrI(sWcRDe-X5cI4Mj(MMr*&$ZFoyq zt=-{xu~|Po3f0%nIJTsKX>ue8_#fU`VMFY~`N+o08(44di!E7h+`tC(Mc4pWlIAax zgTa-CLmy1aU&LW!8oxZF@c{S+=HyU80L!EmGeHxvsVKz7RX;UFXQDd*AQ0_V9W3X zRWDnz|0UNf0&ef0>29ua7LeO^T%MI#yNwSHI{g?E;m|#l7Zvq|GwdF#vfTs3fwgp6zy(Ej@H z8DM$r#!MGkL^O?$%M3XcT1XZFCW!@4xlcp*N3bg7==2EQz3a8DQ1r>A%%~*<-Y$U{ zts7KOBQ`fReH|RUW=!8W6X36z2j+qaLXJd&L%FDM(dQtmb~XM_C<(g$Us00V{W#(z z{)7w^luDm7TW}frM?&bl0Ux9?)XG6-Ksqr!k`gDGMSX=!4jGKUytFh@=|oi)RKFTR zK}*YSwm-Kv`V=h|Ji~Ek&ma$(^!6kJFfrnnzV)rvxR+*;l-)bUZPYMjaI~`nLf|j( z^H}JPRFIRiva*tpwy?I22n!RphO?QBg8woX1II>T?kaj!v^dRZL~ISb6X8@@k%Je= z=1~GD6B*P|cHb}dwG0lDCEck^-1$*{i;Ljm%bVGDKn?@;1*h>RStTXn_pmV2#?m2B z+wh*z7ks7j6DHY|jXBz|P>&2bxub;1P>25(_&7%?d1JIk`Ps8aiBNVj2zn$O16x$5 zb8yw$&+K4xCe0UhDX8X?d7$0*K0>9}{A;nJig<%R zM7sm(@nx}#|Abk~sn_t6)l#tZIr9akcfRXUAjx01teZ4ZBbWBM>MGBl1-N6W@g(;QzLwIQmmjRJ!eEtfCfx`IO$0 zuMonef6r+}6>e=*D#MakjS-G=s53z?TA&&CDwWYDWBJ-TV*SN&KZSU#W*%_nViO=y zFVifl=RWpxBLV&gZ~?4HrswA)5hWh`HZhSfWZBzkcDa|WMoJ{U|A_kL?Q%5@YJS@fkz z6@LW>u5etnrJk02n2B)12m$gR^`XYWWrw{RxYq7lv(2!-nsg{ny06v&lD>77r-71+ zs+pkFk7?PV9ekKO;>(M?w+g$VfJkHYNEFrfx=8rOa%Y5Z=p*!67>agHtpbBe%R!&( zt7vHn!_gNnOjd_#A_x%y2jm$XwXLf^n7_g|kq9?Okz9mZ#`NYAe~@b$b>o5&%v+4F zVrzr7TChmSdB-5&xU>z#z>8OI=IT`K0r(~_CkN`vQ$)cBe1?*jZ6gg7d3dJ8 z$jG!`H6qY-G)><^Ml|AKvj8x1L-u!l8afUYm9b`{#ia Kv<%|<{{I6AL Date: Sat, 27 Feb 2021 13:17:18 +0800 Subject: [PATCH 183/258] move channel and settings protos --- proto | 2 +- src/mesh/PhoneAPI.cpp | 18 +- src/mesh/PhoneAPI.h | 2 +- src/mesh/generated/admin.pb.h | 2 + src/mesh/generated/apponly.pb.h | 1 + src/mesh/generated/channel.pb.c | 17 ++ src/mesh/generated/channel.pb.h | 125 +++++++++++ src/mesh/generated/deviceonly.pb.h | 2 + src/mesh/generated/mesh.pb.c | 18 -- src/mesh/generated/mesh.pb.h | 333 +--------------------------- src/mesh/generated/radioconfig.pb.c | 19 ++ src/mesh/generated/radioconfig.pb.h | 268 ++++++++++++++++++++++ 12 files changed, 438 insertions(+), 369 deletions(-) create mode 100644 src/mesh/generated/channel.pb.c create mode 100644 src/mesh/generated/channel.pb.h create mode 100644 src/mesh/generated/radioconfig.pb.c create mode 100644 src/mesh/generated/radioconfig.pb.h diff --git a/proto b/proto index 83e00e564..3edb02dab 160000 --- a/proto +++ b/proto @@ -1 +1 @@ -Subproject commit 83e00e564d3973b594a46e786b62eed2823e02ed +Subproject commit 3edb02dabb9b8b72d90bbbb7233b557c09391b87 diff --git a/src/mesh/PhoneAPI.cpp b/src/mesh/PhoneAPI.cpp index 7f63fc18e..a7797c255 100644 --- a/src/mesh/PhoneAPI.cpp +++ b/src/mesh/PhoneAPI.cpp @@ -124,24 +124,11 @@ size_t PhoneAPI::getFromRadio(uint8_t *buf) : (gps && gps->isConnected()); // Update with latest GPS connect info fromRadioScratch.which_payloadVariant = FromRadio_my_info_tag; fromRadioScratch.my_info = myNodeInfo; - state = STATE_SEND_RADIO; + state = STATE_SEND_NODEINFO; service.refreshMyNodeInfo(); // Update my NodeInfo because the client will be asking for it soon. break; - case STATE_SEND_RADIO: - fromRadioScratch.which_payloadVariant = FromRadio_radio_tag; - - fromRadioScratch.radio = radioConfig; - - // 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). - fromRadioScratch.radio.preferences.ls_secs = getPref_ls_secs(); - - state = STATE_SEND_NODEINFO; - break; - case STATE_SEND_NODEINFO: { const NodeInfo *info = nodeInfoForPhone; nodeInfoForPhone = NULL; // We just consumed a nodeinfo, will need a new one next time @@ -218,9 +205,6 @@ bool PhoneAPI::available() nodeInfoForPhone = nodeDB.readNextInfo(); return true; // Always say we have something, because we might need to advance our state machine - case STATE_SEND_RADIO: - return true; - case STATE_SEND_COMPLETE_ID: return true; diff --git a/src/mesh/PhoneAPI.h b/src/mesh/PhoneAPI.h index 19c5d0583..094e9830b 100644 --- a/src/mesh/PhoneAPI.h +++ b/src/mesh/PhoneAPI.h @@ -23,7 +23,7 @@ class PhoneAPI STATE_LEGACY, // (no longer used) old default state - until Android apps are all updated, uses the old BLE API STATE_SEND_NOTHING, // (Eventual) Initial state, don't send anything until the client starts asking for config STATE_SEND_MY_INFO, // send our my info record - STATE_SEND_RADIO, + // STATE_SEND_RADIO, // in 1.2 we now send this as a regular mesh packet // STATE_SEND_OWNER, no need to send Owner specially, it is just part of the nodedb STATE_SEND_NODEINFO, // states progress in this order as the device sends to to the client STATE_SEND_COMPLETE_ID, diff --git a/src/mesh/generated/admin.pb.h b/src/mesh/generated/admin.pb.h index 36696f717..f9be1cada 100644 --- a/src/mesh/generated/admin.pb.h +++ b/src/mesh/generated/admin.pb.h @@ -5,6 +5,8 @@ #define PB_ADMIN_PB_H_INCLUDED #include #include "mesh.pb.h" +#include "radioconfig.pb.h" +#include "channel.pb.h" #if PB_PROTO_HEADER_VERSION != 40 #error Regenerate this file with the current version of nanopb generator. diff --git a/src/mesh/generated/apponly.pb.h b/src/mesh/generated/apponly.pb.h index af527f0c8..89fe235da 100644 --- a/src/mesh/generated/apponly.pb.h +++ b/src/mesh/generated/apponly.pb.h @@ -5,6 +5,7 @@ #define PB_APPONLY_PB_H_INCLUDED #include #include "mesh.pb.h" +#include "channel.pb.h" #if PB_PROTO_HEADER_VERSION != 40 #error Regenerate this file with the current version of nanopb generator. diff --git a/src/mesh/generated/channel.pb.c b/src/mesh/generated/channel.pb.c new file mode 100644 index 000000000..329314dae --- /dev/null +++ b/src/mesh/generated/channel.pb.c @@ -0,0 +1,17 @@ +/* Automatically generated nanopb constant definitions */ +/* Generated by nanopb-0.4.4 */ + +#include "channel.pb.h" +#if PB_PROTO_HEADER_VERSION != 40 +#error Regenerate this file with the current version of nanopb generator. +#endif + +PB_BIND(ChannelSettings, ChannelSettings, AUTO) + + +PB_BIND(Channel, Channel, AUTO) + + + + + diff --git a/src/mesh/generated/channel.pb.h b/src/mesh/generated/channel.pb.h new file mode 100644 index 000000000..151495be1 --- /dev/null +++ b/src/mesh/generated/channel.pb.h @@ -0,0 +1,125 @@ +/* Automatically generated nanopb header */ +/* Generated by nanopb-0.4.4 */ + +#ifndef PB_CHANNEL_PB_H_INCLUDED +#define PB_CHANNEL_PB_H_INCLUDED +#include + +#if PB_PROTO_HEADER_VERSION != 40 +#error Regenerate this file with the current version of nanopb generator. +#endif + +/* Enum definitions */ +typedef enum _ChannelSettings_ModemConfig { + ChannelSettings_ModemConfig_Bw125Cr45Sf128 = 0, + ChannelSettings_ModemConfig_Bw500Cr45Sf128 = 1, + ChannelSettings_ModemConfig_Bw31_25Cr48Sf512 = 2, + ChannelSettings_ModemConfig_Bw125Cr48Sf4096 = 3 +} ChannelSettings_ModemConfig; + +typedef enum _Channel_Role { + Channel_Role_DISABLED = 0, + Channel_Role_PRIMARY = 1, + Channel_Role_SECONDARY = 2 +} Channel_Role; + +/* Struct definitions */ +typedef PB_BYTES_ARRAY_T(32) ChannelSettings_psk_t; +typedef struct _ChannelSettings { + int8_t tx_power; + ChannelSettings_ModemConfig modem_config; + ChannelSettings_psk_t psk; + char name[12]; + uint16_t bandwidth; + uint32_t spread_factor; + uint8_t coding_rate; + uint8_t channel_num; + uint32_t id; + bool uplink_enabled; + bool downlink_enabled; +} ChannelSettings; + +typedef struct _Channel { + uint8_t index; + bool has_settings; + ChannelSettings settings; + Channel_Role role; +} Channel; + + +/* Helper constants for enums */ +#define _ChannelSettings_ModemConfig_MIN ChannelSettings_ModemConfig_Bw125Cr45Sf128 +#define _ChannelSettings_ModemConfig_MAX ChannelSettings_ModemConfig_Bw125Cr48Sf4096 +#define _ChannelSettings_ModemConfig_ARRAYSIZE ((ChannelSettings_ModemConfig)(ChannelSettings_ModemConfig_Bw125Cr48Sf4096+1)) + +#define _Channel_Role_MIN Channel_Role_DISABLED +#define _Channel_Role_MAX Channel_Role_SECONDARY +#define _Channel_Role_ARRAYSIZE ((Channel_Role)(Channel_Role_SECONDARY+1)) + + +#ifdef __cplusplus +extern "C" { +#endif + +/* Initializer values for message structs */ +#define ChannelSettings_init_default {0, _ChannelSettings_ModemConfig_MIN, {0, {0}}, "", 0, 0, 0, 0, 0, 0, 0} +#define Channel_init_default {0, false, ChannelSettings_init_default, _Channel_Role_MIN} +#define ChannelSettings_init_zero {0, _ChannelSettings_ModemConfig_MIN, {0, {0}}, "", 0, 0, 0, 0, 0, 0, 0} +#define Channel_init_zero {0, false, ChannelSettings_init_zero, _Channel_Role_MIN} + +/* Field tags (for use in manual encoding/decoding) */ +#define ChannelSettings_tx_power_tag 1 +#define ChannelSettings_modem_config_tag 3 +#define ChannelSettings_psk_tag 4 +#define ChannelSettings_name_tag 5 +#define ChannelSettings_bandwidth_tag 6 +#define ChannelSettings_spread_factor_tag 7 +#define ChannelSettings_coding_rate_tag 8 +#define ChannelSettings_channel_num_tag 9 +#define ChannelSettings_id_tag 10 +#define ChannelSettings_uplink_enabled_tag 16 +#define ChannelSettings_downlink_enabled_tag 17 +#define Channel_index_tag 1 +#define Channel_settings_tag 2 +#define Channel_role_tag 3 + +/* Struct field encoding specification for nanopb */ +#define ChannelSettings_FIELDLIST(X, a) \ +X(a, STATIC, SINGULAR, INT32, tx_power, 1) \ +X(a, STATIC, SINGULAR, UENUM, modem_config, 3) \ +X(a, STATIC, SINGULAR, BYTES, psk, 4) \ +X(a, STATIC, SINGULAR, STRING, name, 5) \ +X(a, STATIC, SINGULAR, UINT32, bandwidth, 6) \ +X(a, STATIC, SINGULAR, UINT32, spread_factor, 7) \ +X(a, STATIC, SINGULAR, UINT32, coding_rate, 8) \ +X(a, STATIC, SINGULAR, UINT32, channel_num, 9) \ +X(a, STATIC, SINGULAR, FIXED32, id, 10) \ +X(a, STATIC, SINGULAR, BOOL, uplink_enabled, 16) \ +X(a, STATIC, SINGULAR, BOOL, downlink_enabled, 17) +#define ChannelSettings_CALLBACK NULL +#define ChannelSettings_DEFAULT NULL + +#define Channel_FIELDLIST(X, a) \ +X(a, STATIC, SINGULAR, UINT32, index, 1) \ +X(a, STATIC, OPTIONAL, MESSAGE, settings, 2) \ +X(a, STATIC, SINGULAR, UENUM, role, 3) +#define Channel_CALLBACK NULL +#define Channel_DEFAULT NULL +#define Channel_settings_MSGTYPE ChannelSettings + +extern const pb_msgdesc_t ChannelSettings_msg; +extern const pb_msgdesc_t Channel_msg; + +/* Defines for backwards compatibility with code written before nanopb-0.4.0 */ +#define ChannelSettings_fields &ChannelSettings_msg +#define Channel_fields &Channel_msg + +/* Maximum encoded size of messages (where known) */ +#define ChannelSettings_size 87 +#define Channel_size 94 + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif diff --git a/src/mesh/generated/deviceonly.pb.h b/src/mesh/generated/deviceonly.pb.h index 1e4443af5..52420a376 100644 --- a/src/mesh/generated/deviceonly.pb.h +++ b/src/mesh/generated/deviceonly.pb.h @@ -5,6 +5,8 @@ #define PB_DEVICEONLY_PB_H_INCLUDED #include #include "mesh.pb.h" +#include "radioconfig.pb.h" +#include "channel.pb.h" #if PB_PROTO_HEADER_VERSION != 40 #error Regenerate this file with the current version of nanopb generator. diff --git a/src/mesh/generated/mesh.pb.c b/src/mesh/generated/mesh.pb.c index c4fd0d8e5..ab27832f8 100644 --- a/src/mesh/generated/mesh.pb.c +++ b/src/mesh/generated/mesh.pb.c @@ -24,18 +24,6 @@ PB_BIND(Data, Data, 2) PB_BIND(MeshPacket, MeshPacket, 2) -PB_BIND(ChannelSettings, ChannelSettings, AUTO) - - -PB_BIND(Channel, Channel, AUTO) - - -PB_BIND(RadioConfig, RadioConfig, 2) - - -PB_BIND(RadioConfig_UserPreferences, RadioConfig_UserPreferences, 2) - - PB_BIND(NodeInfo, NodeInfo, AUTO) @@ -57,9 +45,3 @@ PB_BIND(ToRadio, ToRadio, 2) - - - - - - diff --git a/src/mesh/generated/mesh.pb.h b/src/mesh/generated/mesh.pb.h index 79e14f26a..a8f36a140 100644 --- a/src/mesh/generated/mesh.pb.h +++ b/src/mesh/generated/mesh.pb.h @@ -16,52 +16,6 @@ typedef enum _Constants { Constants_DATA_PAYLOAD_LEN = 240 } Constants; -typedef enum _RegionCode { - RegionCode_Unset = 0, - RegionCode_US = 1, - RegionCode_EU433 = 2, - RegionCode_EU865 = 3, - RegionCode_CN = 4, - RegionCode_JP = 5, - RegionCode_ANZ = 6, - RegionCode_KR = 7, - RegionCode_TW = 8 -} RegionCode; - -typedef enum _ChargeCurrent { - ChargeCurrent_MAUnset = 0, - ChargeCurrent_MA100 = 1, - ChargeCurrent_MA190 = 2, - ChargeCurrent_MA280 = 3, - ChargeCurrent_MA360 = 4, - ChargeCurrent_MA450 = 5, - ChargeCurrent_MA550 = 6, - ChargeCurrent_MA630 = 7, - ChargeCurrent_MA700 = 8, - ChargeCurrent_MA780 = 9, - ChargeCurrent_MA880 = 10, - ChargeCurrent_MA960 = 11, - ChargeCurrent_MA1000 = 12, - ChargeCurrent_MA1080 = 13, - ChargeCurrent_MA1160 = 14, - ChargeCurrent_MA1240 = 15, - ChargeCurrent_MA1320 = 16 -} ChargeCurrent; - -typedef enum _GpsOperation { - GpsOperation_GpsOpUnset = 0, - GpsOperation_GpsOpStationary = 1, - GpsOperation_GpsOpMobile = 2, - GpsOperation_GpsOpTimeOnly = 3, - GpsOperation_GpsOpDisabled = 4 -} GpsOperation; - -typedef enum _LocationSharing { - LocationSharing_LocUnset = 0, - LocationSharing_LocEnabled = 1, - LocationSharing_LocDisabled = 2 -} LocationSharing; - typedef enum _CriticalErrorCode { CriticalErrorCode_None = 0, CriticalErrorCode_TxWatchdog = 1, @@ -95,19 +49,6 @@ typedef enum _MeshPacket_Priority { MeshPacket_Priority_MAX = 127 } MeshPacket_Priority; -typedef enum _ChannelSettings_ModemConfig { - ChannelSettings_ModemConfig_Bw125Cr45Sf128 = 0, - ChannelSettings_ModemConfig_Bw500Cr45Sf128 = 1, - ChannelSettings_ModemConfig_Bw31_25Cr48Sf512 = 2, - ChannelSettings_ModemConfig_Bw125Cr48Sf4096 = 3 -} ChannelSettings_ModemConfig; - -typedef enum _Channel_Role { - Channel_Role_DISABLED = 0, - Channel_Role_PRIMARY = 1, - Channel_Role_SECONDARY = 2 -} Channel_Role; - typedef enum _LogRecord_Level { LogRecord_Level_UNSET = 0, LogRecord_Level_CRITICAL = 50, @@ -119,21 +60,6 @@ typedef enum _LogRecord_Level { } LogRecord_Level; /* Struct definitions */ -typedef PB_BYTES_ARRAY_T(32) ChannelSettings_psk_t; -typedef struct _ChannelSettings { - int8_t tx_power; - ChannelSettings_ModemConfig modem_config; - ChannelSettings_psk_t psk; - char name[12]; - uint16_t bandwidth; - uint32_t spread_factor; - uint8_t coding_rate; - uint8_t channel_num; - uint32_t id; - bool uplink_enabled; - bool downlink_enabled; -} ChannelSettings; - typedef PB_BYTES_ARRAY_T(237) Data_payload_t; typedef struct _Data { PortNum portnum; @@ -174,57 +100,6 @@ typedef struct _Position { uint32_t time; } Position; -typedef struct _RadioConfig_UserPreferences { - uint32_t position_broadcast_secs; - uint32_t send_owner_interval; - uint32_t wait_bluetooth_secs; - uint32_t screen_on_secs; - uint32_t phone_timeout_secs; - uint32_t phone_sds_timeout_sec; - uint32_t mesh_sds_timeout_secs; - uint32_t sds_secs; - uint32_t ls_secs; - uint32_t min_wake_secs; - char wifi_ssid[33]; - char wifi_password[64]; - bool wifi_ap_mode; - RegionCode region; - ChargeCurrent charge_current; - LocationSharing location_share; - GpsOperation gps_operation; - uint32_t gps_update_interval; - uint32_t gps_attempt_time; - bool is_router; - bool is_low_power; - bool fixed_position; - bool factory_reset; - bool debug_log_enabled; - pb_size_t ignore_incoming_count; - uint32_t ignore_incoming[3]; - bool serialplugin_enabled; - bool serialplugin_echo; - uint32_t serialplugin_rxd; - uint32_t serialplugin_txd; - uint32_t serialplugin_timeout; - uint32_t serialplugin_mode; - bool ext_notification_plugin_enabled; - uint32_t ext_notification_plugin_output_ms; - uint32_t ext_notification_plugin_output; - bool ext_notification_plugin_active; - bool ext_notification_plugin_alert_message; - bool ext_notification_plugin_alert_bell; - bool range_test_plugin_enabled; - uint32_t range_test_plugin_sender; - bool range_test_plugin_save; - bool store_forward_plugin_enabled; - uint32_t store_forward_plugin_records; - bool environmental_measurement_plugin_measurement_enabled; - bool environmental_measurement_plugin_screen_enabled; - uint32_t environmental_measurement_plugin_read_error_count_threshold; - uint32_t environmental_measurement_plugin_update_interval; - uint32_t environmental_measurement_plugin_recovery_interval; -} RadioConfig_UserPreferences; - typedef struct _RouteDiscovery { pb_size_t route_count; uint32_t route[8]; @@ -237,13 +112,6 @@ typedef struct _User { pb_byte_t macaddr[6]; } User; -typedef struct _Channel { - uint8_t index; - bool has_settings; - ChannelSettings settings; - Channel_Role role; -} Channel; - typedef PB_BYTES_ARRAY_T(256) MeshPacket_encrypted_t; typedef struct _MeshPacket { uint32_t from; @@ -272,11 +140,6 @@ typedef struct _NodeInfo { float snr; } NodeInfo; -typedef struct _RadioConfig { - bool has_preferences; - RadioConfig_UserPreferences preferences; -} RadioConfig; - typedef struct _Routing { pb_size_t which_variant; union { @@ -292,11 +155,9 @@ typedef struct _FromRadio { union { MyNodeInfo my_info; NodeInfo node_info; - RadioConfig radio; LogRecord log_record; uint32_t config_complete_id; bool rebooted; - Channel channel; MeshPacket packet; }; } FromRadio; @@ -315,22 +176,6 @@ typedef struct _ToRadio { #define _Constants_MAX Constants_DATA_PAYLOAD_LEN #define _Constants_ARRAYSIZE ((Constants)(Constants_DATA_PAYLOAD_LEN+1)) -#define _RegionCode_MIN RegionCode_Unset -#define _RegionCode_MAX RegionCode_TW -#define _RegionCode_ARRAYSIZE ((RegionCode)(RegionCode_TW+1)) - -#define _ChargeCurrent_MIN ChargeCurrent_MAUnset -#define _ChargeCurrent_MAX ChargeCurrent_MA1320 -#define _ChargeCurrent_ARRAYSIZE ((ChargeCurrent)(ChargeCurrent_MA1320+1)) - -#define _GpsOperation_MIN GpsOperation_GpsOpUnset -#define _GpsOperation_MAX GpsOperation_GpsOpDisabled -#define _GpsOperation_ARRAYSIZE ((GpsOperation)(GpsOperation_GpsOpDisabled+1)) - -#define _LocationSharing_MIN LocationSharing_LocUnset -#define _LocationSharing_MAX LocationSharing_LocDisabled -#define _LocationSharing_ARRAYSIZE ((LocationSharing)(LocationSharing_LocDisabled+1)) - #define _CriticalErrorCode_MIN CriticalErrorCode_None #define _CriticalErrorCode_MAX CriticalErrorCode_TransmitFailed #define _CriticalErrorCode_ARRAYSIZE ((CriticalErrorCode)(CriticalErrorCode_TransmitFailed+1)) @@ -343,14 +188,6 @@ typedef struct _ToRadio { #define _MeshPacket_Priority_MAX MeshPacket_Priority_MAX #define _MeshPacket_Priority_ARRAYSIZE ((MeshPacket_Priority)(MeshPacket_Priority_MAX+1)) -#define _ChannelSettings_ModemConfig_MIN ChannelSettings_ModemConfig_Bw125Cr45Sf128 -#define _ChannelSettings_ModemConfig_MAX ChannelSettings_ModemConfig_Bw125Cr48Sf4096 -#define _ChannelSettings_ModemConfig_ARRAYSIZE ((ChannelSettings_ModemConfig)(ChannelSettings_ModemConfig_Bw125Cr48Sf4096+1)) - -#define _Channel_Role_MIN Channel_Role_DISABLED -#define _Channel_Role_MAX Channel_Role_SECONDARY -#define _Channel_Role_ARRAYSIZE ((Channel_Role)(Channel_Role_SECONDARY+1)) - #define _LogRecord_Level_MIN LogRecord_Level_UNSET #define _LogRecord_Level_MAX LogRecord_Level_CRITICAL #define _LogRecord_Level_ARRAYSIZE ((LogRecord_Level)(LogRecord_Level_CRITICAL+1)) @@ -367,10 +204,6 @@ extern "C" { #define Routing_init_default {0, {RouteDiscovery_init_default}} #define Data_init_default {_PortNum_MIN, {0, {0}}, 0, 0, 0, 0} #define MeshPacket_init_default {0, 0, 0, 0, {Data_init_default}, 0, 0, 0, 0, 0, _MeshPacket_Priority_MIN} -#define ChannelSettings_init_default {0, _ChannelSettings_ModemConfig_MIN, {0, {0}}, "", 0, 0, 0, 0, 0, 0, 0} -#define Channel_init_default {0, false, ChannelSettings_init_default, _Channel_Role_MIN} -#define RadioConfig_init_default {false, RadioConfig_UserPreferences_init_default} -#define RadioConfig_UserPreferences_init_default {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, "", "", 0, _RegionCode_MIN, _ChargeCurrent_MIN, _LocationSharing_MIN, _GpsOperation_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, 0, 0, 0, 0, 0} #define NodeInfo_init_default {0, false, User_init_default, false, Position_init_default, 0, 0} #define MyNodeInfo_init_default {0, 0, 0, "", "", "", _CriticalErrorCode_MIN, 0, 0, 0, 0, 0} #define LogRecord_init_default {"", 0, "", _LogRecord_Level_MIN} @@ -382,10 +215,6 @@ extern "C" { #define Routing_init_zero {0, {RouteDiscovery_init_zero}} #define Data_init_zero {_PortNum_MIN, {0, {0}}, 0, 0, 0, 0} #define MeshPacket_init_zero {0, 0, 0, 0, {Data_init_zero}, 0, 0, 0, 0, 0, _MeshPacket_Priority_MIN} -#define ChannelSettings_init_zero {0, _ChannelSettings_ModemConfig_MIN, {0, {0}}, "", 0, 0, 0, 0, 0, 0, 0} -#define Channel_init_zero {0, false, ChannelSettings_init_zero, _Channel_Role_MIN} -#define RadioConfig_init_zero {false, RadioConfig_UserPreferences_init_zero} -#define RadioConfig_UserPreferences_init_zero {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, "", "", 0, _RegionCode_MIN, _ChargeCurrent_MIN, _LocationSharing_MIN, _GpsOperation_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, 0, 0, 0, 0, 0} #define NodeInfo_init_zero {0, false, User_init_zero, false, Position_init_zero, 0, 0} #define MyNodeInfo_init_zero {0, 0, 0, "", "", "", _CriticalErrorCode_MIN, 0, 0, 0, 0, 0} #define LogRecord_init_zero {"", 0, "", _LogRecord_Level_MIN} @@ -393,17 +222,6 @@ extern "C" { #define ToRadio_init_zero {0, {MeshPacket_init_zero}} /* Field tags (for use in manual encoding/decoding) */ -#define ChannelSettings_tx_power_tag 1 -#define ChannelSettings_modem_config_tag 3 -#define ChannelSettings_psk_tag 4 -#define ChannelSettings_name_tag 5 -#define ChannelSettings_bandwidth_tag 6 -#define ChannelSettings_spread_factor_tag 7 -#define ChannelSettings_coding_rate_tag 8 -#define ChannelSettings_channel_num_tag 9 -#define ChannelSettings_id_tag 10 -#define ChannelSettings_uplink_enabled_tag 16 -#define ChannelSettings_downlink_enabled_tag 17 #define Data_portnum_tag 1 #define Data_payload_tag 2 #define Data_want_response_tag 3 @@ -431,61 +249,11 @@ extern "C" { #define Position_altitude_tag 3 #define Position_battery_level_tag 4 #define Position_time_tag 9 -#define RadioConfig_UserPreferences_position_broadcast_secs_tag 1 -#define RadioConfig_UserPreferences_send_owner_interval_tag 2 -#define RadioConfig_UserPreferences_wait_bluetooth_secs_tag 4 -#define RadioConfig_UserPreferences_screen_on_secs_tag 5 -#define RadioConfig_UserPreferences_phone_timeout_secs_tag 6 -#define RadioConfig_UserPreferences_phone_sds_timeout_sec_tag 7 -#define RadioConfig_UserPreferences_mesh_sds_timeout_secs_tag 8 -#define RadioConfig_UserPreferences_sds_secs_tag 9 -#define RadioConfig_UserPreferences_ls_secs_tag 10 -#define RadioConfig_UserPreferences_min_wake_secs_tag 11 -#define RadioConfig_UserPreferences_wifi_ssid_tag 12 -#define RadioConfig_UserPreferences_wifi_password_tag 13 -#define RadioConfig_UserPreferences_wifi_ap_mode_tag 14 -#define RadioConfig_UserPreferences_region_tag 15 -#define RadioConfig_UserPreferences_charge_current_tag 16 -#define RadioConfig_UserPreferences_location_share_tag 32 -#define RadioConfig_UserPreferences_gps_operation_tag 33 -#define RadioConfig_UserPreferences_gps_update_interval_tag 34 -#define RadioConfig_UserPreferences_gps_attempt_time_tag 36 -#define RadioConfig_UserPreferences_is_router_tag 37 -#define RadioConfig_UserPreferences_is_low_power_tag 38 -#define RadioConfig_UserPreferences_fixed_position_tag 39 -#define RadioConfig_UserPreferences_factory_reset_tag 100 -#define RadioConfig_UserPreferences_debug_log_enabled_tag 101 -#define RadioConfig_UserPreferences_ignore_incoming_tag 103 -#define RadioConfig_UserPreferences_serialplugin_enabled_tag 120 -#define RadioConfig_UserPreferences_serialplugin_echo_tag 121 -#define RadioConfig_UserPreferences_serialplugin_rxd_tag 122 -#define RadioConfig_UserPreferences_serialplugin_txd_tag 123 -#define RadioConfig_UserPreferences_serialplugin_timeout_tag 124 -#define RadioConfig_UserPreferences_serialplugin_mode_tag 125 -#define RadioConfig_UserPreferences_ext_notification_plugin_enabled_tag 126 -#define RadioConfig_UserPreferences_ext_notification_plugin_output_ms_tag 127 -#define RadioConfig_UserPreferences_ext_notification_plugin_output_tag 128 -#define RadioConfig_UserPreferences_ext_notification_plugin_active_tag 129 -#define RadioConfig_UserPreferences_ext_notification_plugin_alert_message_tag 130 -#define RadioConfig_UserPreferences_ext_notification_plugin_alert_bell_tag 131 -#define RadioConfig_UserPreferences_range_test_plugin_enabled_tag 132 -#define RadioConfig_UserPreferences_range_test_plugin_sender_tag 133 -#define RadioConfig_UserPreferences_range_test_plugin_save_tag 134 -#define RadioConfig_UserPreferences_store_forward_plugin_enabled_tag 136 -#define RadioConfig_UserPreferences_store_forward_plugin_records_tag 137 -#define RadioConfig_UserPreferences_environmental_measurement_plugin_measurement_enabled_tag 140 -#define RadioConfig_UserPreferences_environmental_measurement_plugin_screen_enabled_tag 141 -#define RadioConfig_UserPreferences_environmental_measurement_plugin_read_error_count_threshold_tag 142 -#define RadioConfig_UserPreferences_environmental_measurement_plugin_update_interval_tag 143 -#define RadioConfig_UserPreferences_environmental_measurement_plugin_recovery_interval_tag 144 #define RouteDiscovery_route_tag 2 #define User_id_tag 1 #define User_long_name_tag 2 #define User_short_name_tag 3 #define User_macaddr_tag 4 -#define Channel_index_tag 1 -#define Channel_settings_tag 2 -#define Channel_role_tag 3 #define MeshPacket_from_tag 1 #define MeshPacket_to_tag 2 #define MeshPacket_channel_tag 3 @@ -502,18 +270,15 @@ extern "C" { #define NodeInfo_position_tag 3 #define NodeInfo_next_hop_tag 5 #define NodeInfo_snr_tag 7 -#define RadioConfig_preferences_tag 1 #define Routing_route_request_tag 1 #define Routing_route_reply_tag 2 #define Routing_error_reason_tag 3 #define FromRadio_num_tag 1 #define FromRadio_my_info_tag 3 #define FromRadio_node_info_tag 4 -#define FromRadio_radio_tag 6 #define FromRadio_log_record_tag 7 #define FromRadio_config_complete_id_tag 8 #define FromRadio_rebooted_tag 9 -#define FromRadio_channel_tag 10 #define FromRadio_packet_tag 11 #define ToRadio_packet_tag 2 #define ToRadio_want_config_id_tag 100 @@ -576,86 +341,6 @@ X(a, STATIC, SINGULAR, UENUM, priority, 12) #define MeshPacket_DEFAULT NULL #define MeshPacket_payloadVariant_decoded_MSGTYPE Data -#define ChannelSettings_FIELDLIST(X, a) \ -X(a, STATIC, SINGULAR, INT32, tx_power, 1) \ -X(a, STATIC, SINGULAR, UENUM, modem_config, 3) \ -X(a, STATIC, SINGULAR, BYTES, psk, 4) \ -X(a, STATIC, SINGULAR, STRING, name, 5) \ -X(a, STATIC, SINGULAR, UINT32, bandwidth, 6) \ -X(a, STATIC, SINGULAR, UINT32, spread_factor, 7) \ -X(a, STATIC, SINGULAR, UINT32, coding_rate, 8) \ -X(a, STATIC, SINGULAR, UINT32, channel_num, 9) \ -X(a, STATIC, SINGULAR, FIXED32, id, 10) \ -X(a, STATIC, SINGULAR, BOOL, uplink_enabled, 16) \ -X(a, STATIC, SINGULAR, BOOL, downlink_enabled, 17) -#define ChannelSettings_CALLBACK NULL -#define ChannelSettings_DEFAULT NULL - -#define Channel_FIELDLIST(X, a) \ -X(a, STATIC, SINGULAR, UINT32, index, 1) \ -X(a, STATIC, OPTIONAL, MESSAGE, settings, 2) \ -X(a, STATIC, SINGULAR, UENUM, role, 3) -#define Channel_CALLBACK NULL -#define Channel_DEFAULT NULL -#define Channel_settings_MSGTYPE ChannelSettings - -#define RadioConfig_FIELDLIST(X, a) \ -X(a, STATIC, OPTIONAL, MESSAGE, preferences, 1) -#define RadioConfig_CALLBACK NULL -#define RadioConfig_DEFAULT NULL -#define RadioConfig_preferences_MSGTYPE RadioConfig_UserPreferences - -#define RadioConfig_UserPreferences_FIELDLIST(X, a) \ -X(a, STATIC, SINGULAR, UINT32, position_broadcast_secs, 1) \ -X(a, STATIC, SINGULAR, UINT32, send_owner_interval, 2) \ -X(a, STATIC, SINGULAR, UINT32, wait_bluetooth_secs, 4) \ -X(a, STATIC, SINGULAR, UINT32, screen_on_secs, 5) \ -X(a, STATIC, SINGULAR, UINT32, phone_timeout_secs, 6) \ -X(a, STATIC, SINGULAR, UINT32, phone_sds_timeout_sec, 7) \ -X(a, STATIC, SINGULAR, UINT32, mesh_sds_timeout_secs, 8) \ -X(a, STATIC, SINGULAR, UINT32, sds_secs, 9) \ -X(a, STATIC, SINGULAR, UINT32, ls_secs, 10) \ -X(a, STATIC, SINGULAR, UINT32, min_wake_secs, 11) \ -X(a, STATIC, SINGULAR, STRING, wifi_ssid, 12) \ -X(a, STATIC, SINGULAR, STRING, wifi_password, 13) \ -X(a, STATIC, SINGULAR, BOOL, wifi_ap_mode, 14) \ -X(a, STATIC, SINGULAR, UENUM, region, 15) \ -X(a, STATIC, SINGULAR, UENUM, charge_current, 16) \ -X(a, STATIC, SINGULAR, UENUM, location_share, 32) \ -X(a, STATIC, SINGULAR, UENUM, gps_operation, 33) \ -X(a, STATIC, SINGULAR, UINT32, gps_update_interval, 34) \ -X(a, STATIC, SINGULAR, UINT32, gps_attempt_time, 36) \ -X(a, STATIC, SINGULAR, BOOL, is_router, 37) \ -X(a, STATIC, SINGULAR, BOOL, is_low_power, 38) \ -X(a, STATIC, SINGULAR, BOOL, fixed_position, 39) \ -X(a, STATIC, SINGULAR, BOOL, factory_reset, 100) \ -X(a, STATIC, SINGULAR, BOOL, debug_log_enabled, 101) \ -X(a, STATIC, REPEATED, UINT32, ignore_incoming, 103) \ -X(a, STATIC, SINGULAR, BOOL, serialplugin_enabled, 120) \ -X(a, STATIC, SINGULAR, BOOL, serialplugin_echo, 121) \ -X(a, STATIC, SINGULAR, UINT32, serialplugin_rxd, 122) \ -X(a, STATIC, SINGULAR, UINT32, serialplugin_txd, 123) \ -X(a, STATIC, SINGULAR, UINT32, serialplugin_timeout, 124) \ -X(a, STATIC, SINGULAR, UINT32, serialplugin_mode, 125) \ -X(a, STATIC, SINGULAR, BOOL, ext_notification_plugin_enabled, 126) \ -X(a, STATIC, SINGULAR, UINT32, ext_notification_plugin_output_ms, 127) \ -X(a, STATIC, SINGULAR, UINT32, ext_notification_plugin_output, 128) \ -X(a, STATIC, SINGULAR, BOOL, ext_notification_plugin_active, 129) \ -X(a, STATIC, SINGULAR, BOOL, ext_notification_plugin_alert_message, 130) \ -X(a, STATIC, SINGULAR, BOOL, ext_notification_plugin_alert_bell, 131) \ -X(a, STATIC, SINGULAR, BOOL, range_test_plugin_enabled, 132) \ -X(a, STATIC, SINGULAR, UINT32, range_test_plugin_sender, 133) \ -X(a, STATIC, SINGULAR, BOOL, range_test_plugin_save, 134) \ -X(a, STATIC, SINGULAR, BOOL, store_forward_plugin_enabled, 136) \ -X(a, STATIC, SINGULAR, UINT32, store_forward_plugin_records, 137) \ -X(a, STATIC, SINGULAR, BOOL, environmental_measurement_plugin_measurement_enabled, 140) \ -X(a, STATIC, SINGULAR, BOOL, environmental_measurement_plugin_screen_enabled, 141) \ -X(a, STATIC, SINGULAR, UINT32, environmental_measurement_plugin_read_error_count_threshold, 142) \ -X(a, STATIC, SINGULAR, UINT32, environmental_measurement_plugin_update_interval, 143) \ -X(a, STATIC, SINGULAR, UINT32, environmental_measurement_plugin_recovery_interval, 144) -#define RadioConfig_UserPreferences_CALLBACK NULL -#define RadioConfig_UserPreferences_DEFAULT NULL - #define NodeInfo_FIELDLIST(X, a) \ X(a, STATIC, SINGULAR, UINT32, num, 1) \ X(a, STATIC, OPTIONAL, MESSAGE, user, 2) \ @@ -695,19 +380,15 @@ X(a, STATIC, SINGULAR, UENUM, level, 4) X(a, STATIC, SINGULAR, UINT32, num, 1) \ X(a, STATIC, ONEOF, MESSAGE, (payloadVariant,my_info,my_info), 3) \ X(a, STATIC, ONEOF, MESSAGE, (payloadVariant,node_info,node_info), 4) \ -X(a, STATIC, ONEOF, MESSAGE, (payloadVariant,radio,radio), 6) \ X(a, STATIC, ONEOF, MESSAGE, (payloadVariant,log_record,log_record), 7) \ X(a, STATIC, ONEOF, UINT32, (payloadVariant,config_complete_id,config_complete_id), 8) \ X(a, STATIC, ONEOF, BOOL, (payloadVariant,rebooted,rebooted), 9) \ -X(a, STATIC, ONEOF, MESSAGE, (payloadVariant,channel,channel), 10) \ X(a, STATIC, ONEOF, MESSAGE, (payloadVariant,packet,packet), 11) #define FromRadio_CALLBACK NULL #define FromRadio_DEFAULT NULL #define FromRadio_payloadVariant_my_info_MSGTYPE MyNodeInfo #define FromRadio_payloadVariant_node_info_MSGTYPE NodeInfo -#define FromRadio_payloadVariant_radio_MSGTYPE RadioConfig #define FromRadio_payloadVariant_log_record_MSGTYPE LogRecord -#define FromRadio_payloadVariant_channel_MSGTYPE Channel #define FromRadio_payloadVariant_packet_MSGTYPE MeshPacket #define ToRadio_FIELDLIST(X, a) \ @@ -723,10 +404,6 @@ 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 MeshPacket_msg; -extern const pb_msgdesc_t ChannelSettings_msg; -extern const pb_msgdesc_t Channel_msg; -extern const pb_msgdesc_t RadioConfig_msg; -extern const pb_msgdesc_t RadioConfig_UserPreferences_msg; extern const pb_msgdesc_t NodeInfo_msg; extern const pb_msgdesc_t MyNodeInfo_msg; extern const pb_msgdesc_t LogRecord_msg; @@ -740,10 +417,6 @@ extern const pb_msgdesc_t ToRadio_msg; #define Routing_fields &Routing_msg #define Data_fields &Data_msg #define MeshPacket_fields &MeshPacket_msg -#define ChannelSettings_fields &ChannelSettings_msg -#define Channel_fields &Channel_msg -#define RadioConfig_fields &RadioConfig_msg -#define RadioConfig_UserPreferences_fields &RadioConfig_UserPreferences_msg #define NodeInfo_fields &NodeInfo_msg #define MyNodeInfo_fields &MyNodeInfo_msg #define LogRecord_fields &LogRecord_msg @@ -757,14 +430,10 @@ extern const pb_msgdesc_t ToRadio_msg; #define Routing_size 42 #define Data_size 260 #define MeshPacket_size 298 -#define ChannelSettings_size 87 -#define Channel_size 94 -#define RadioConfig_size 335 -#define RadioConfig_UserPreferences_size 332 #define NodeInfo_size 130 #define MyNodeInfo_size 89 #define LogRecord_size 81 -#define FromRadio_size 344 +#define FromRadio_size 307 #define ToRadio_size 301 #ifdef __cplusplus diff --git a/src/mesh/generated/radioconfig.pb.c b/src/mesh/generated/radioconfig.pb.c new file mode 100644 index 000000000..85aa7aa18 --- /dev/null +++ b/src/mesh/generated/radioconfig.pb.c @@ -0,0 +1,19 @@ +/* Automatically generated nanopb constant definitions */ +/* Generated by nanopb-0.4.4 */ + +#include "radioconfig.pb.h" +#if PB_PROTO_HEADER_VERSION != 40 +#error Regenerate this file with the current version of nanopb generator. +#endif + +PB_BIND(RadioConfig, RadioConfig, 2) + + +PB_BIND(RadioConfig_UserPreferences, RadioConfig_UserPreferences, 2) + + + + + + + diff --git a/src/mesh/generated/radioconfig.pb.h b/src/mesh/generated/radioconfig.pb.h new file mode 100644 index 000000000..b8a6bfd7a --- /dev/null +++ b/src/mesh/generated/radioconfig.pb.h @@ -0,0 +1,268 @@ +/* Automatically generated nanopb header */ +/* Generated by nanopb-0.4.4 */ + +#ifndef PB_RADIOCONFIG_PB_H_INCLUDED +#define PB_RADIOCONFIG_PB_H_INCLUDED +#include + +#if PB_PROTO_HEADER_VERSION != 40 +#error Regenerate this file with the current version of nanopb generator. +#endif + +/* Enum definitions */ +typedef enum _RegionCode { + RegionCode_Unset = 0, + RegionCode_US = 1, + RegionCode_EU433 = 2, + RegionCode_EU865 = 3, + RegionCode_CN = 4, + RegionCode_JP = 5, + RegionCode_ANZ = 6, + RegionCode_KR = 7, + RegionCode_TW = 8 +} RegionCode; + +typedef enum _ChargeCurrent { + ChargeCurrent_MAUnset = 0, + ChargeCurrent_MA100 = 1, + ChargeCurrent_MA190 = 2, + ChargeCurrent_MA280 = 3, + ChargeCurrent_MA360 = 4, + ChargeCurrent_MA450 = 5, + ChargeCurrent_MA550 = 6, + ChargeCurrent_MA630 = 7, + ChargeCurrent_MA700 = 8, + ChargeCurrent_MA780 = 9, + ChargeCurrent_MA880 = 10, + ChargeCurrent_MA960 = 11, + ChargeCurrent_MA1000 = 12, + ChargeCurrent_MA1080 = 13, + ChargeCurrent_MA1160 = 14, + ChargeCurrent_MA1240 = 15, + ChargeCurrent_MA1320 = 16 +} ChargeCurrent; + +typedef enum _GpsOperation { + GpsOperation_GpsOpUnset = 0, + GpsOperation_GpsOpStationary = 1, + GpsOperation_GpsOpMobile = 2, + GpsOperation_GpsOpTimeOnly = 3, + GpsOperation_GpsOpDisabled = 4 +} GpsOperation; + +typedef enum _LocationSharing { + LocationSharing_LocUnset = 0, + LocationSharing_LocEnabled = 1, + LocationSharing_LocDisabled = 2 +} LocationSharing; + +/* Struct definitions */ +typedef struct _RadioConfig_UserPreferences { + uint32_t position_broadcast_secs; + uint32_t send_owner_interval; + uint32_t wait_bluetooth_secs; + uint32_t screen_on_secs; + uint32_t phone_timeout_secs; + uint32_t phone_sds_timeout_sec; + uint32_t mesh_sds_timeout_secs; + uint32_t sds_secs; + uint32_t ls_secs; + uint32_t min_wake_secs; + char wifi_ssid[33]; + char wifi_password[64]; + bool wifi_ap_mode; + RegionCode region; + ChargeCurrent charge_current; + LocationSharing location_share; + GpsOperation gps_operation; + uint32_t gps_update_interval; + uint32_t gps_attempt_time; + bool is_router; + bool is_low_power; + bool fixed_position; + bool factory_reset; + bool debug_log_enabled; + pb_size_t ignore_incoming_count; + uint32_t ignore_incoming[3]; + bool serialplugin_enabled; + bool serialplugin_echo; + uint32_t serialplugin_rxd; + uint32_t serialplugin_txd; + uint32_t serialplugin_timeout; + uint32_t serialplugin_mode; + bool ext_notification_plugin_enabled; + uint32_t ext_notification_plugin_output_ms; + uint32_t ext_notification_plugin_output; + bool ext_notification_plugin_active; + bool ext_notification_plugin_alert_message; + bool ext_notification_plugin_alert_bell; + bool range_test_plugin_enabled; + uint32_t range_test_plugin_sender; + bool range_test_plugin_save; + bool store_forward_plugin_enabled; + uint32_t store_forward_plugin_records; + bool environmental_measurement_plugin_measurement_enabled; + bool environmental_measurement_plugin_screen_enabled; + uint32_t environmental_measurement_plugin_read_error_count_threshold; + uint32_t environmental_measurement_plugin_update_interval; + uint32_t environmental_measurement_plugin_recovery_interval; +} RadioConfig_UserPreferences; + +typedef struct _RadioConfig { + bool has_preferences; + RadioConfig_UserPreferences preferences; +} RadioConfig; + + +/* Helper constants for enums */ +#define _RegionCode_MIN RegionCode_Unset +#define _RegionCode_MAX RegionCode_TW +#define _RegionCode_ARRAYSIZE ((RegionCode)(RegionCode_TW+1)) + +#define _ChargeCurrent_MIN ChargeCurrent_MAUnset +#define _ChargeCurrent_MAX ChargeCurrent_MA1320 +#define _ChargeCurrent_ARRAYSIZE ((ChargeCurrent)(ChargeCurrent_MA1320+1)) + +#define _GpsOperation_MIN GpsOperation_GpsOpUnset +#define _GpsOperation_MAX GpsOperation_GpsOpDisabled +#define _GpsOperation_ARRAYSIZE ((GpsOperation)(GpsOperation_GpsOpDisabled+1)) + +#define _LocationSharing_MIN LocationSharing_LocUnset +#define _LocationSharing_MAX LocationSharing_LocDisabled +#define _LocationSharing_ARRAYSIZE ((LocationSharing)(LocationSharing_LocDisabled+1)) + + +#ifdef __cplusplus +extern "C" { +#endif + +/* Initializer values for message structs */ +#define RadioConfig_init_default {false, RadioConfig_UserPreferences_init_default} +#define RadioConfig_UserPreferences_init_default {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, "", "", 0, _RegionCode_MIN, _ChargeCurrent_MIN, _LocationSharing_MIN, _GpsOperation_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, 0, 0, 0, 0, 0} +#define RadioConfig_init_zero {false, RadioConfig_UserPreferences_init_zero} +#define RadioConfig_UserPreferences_init_zero {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, "", "", 0, _RegionCode_MIN, _ChargeCurrent_MIN, _LocationSharing_MIN, _GpsOperation_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, 0, 0, 0, 0, 0} + +/* Field tags (for use in manual encoding/decoding) */ +#define RadioConfig_UserPreferences_position_broadcast_secs_tag 1 +#define RadioConfig_UserPreferences_send_owner_interval_tag 2 +#define RadioConfig_UserPreferences_wait_bluetooth_secs_tag 4 +#define RadioConfig_UserPreferences_screen_on_secs_tag 5 +#define RadioConfig_UserPreferences_phone_timeout_secs_tag 6 +#define RadioConfig_UserPreferences_phone_sds_timeout_sec_tag 7 +#define RadioConfig_UserPreferences_mesh_sds_timeout_secs_tag 8 +#define RadioConfig_UserPreferences_sds_secs_tag 9 +#define RadioConfig_UserPreferences_ls_secs_tag 10 +#define RadioConfig_UserPreferences_min_wake_secs_tag 11 +#define RadioConfig_UserPreferences_wifi_ssid_tag 12 +#define RadioConfig_UserPreferences_wifi_password_tag 13 +#define RadioConfig_UserPreferences_wifi_ap_mode_tag 14 +#define RadioConfig_UserPreferences_region_tag 15 +#define RadioConfig_UserPreferences_charge_current_tag 16 +#define RadioConfig_UserPreferences_location_share_tag 32 +#define RadioConfig_UserPreferences_gps_operation_tag 33 +#define RadioConfig_UserPreferences_gps_update_interval_tag 34 +#define RadioConfig_UserPreferences_gps_attempt_time_tag 36 +#define RadioConfig_UserPreferences_is_router_tag 37 +#define RadioConfig_UserPreferences_is_low_power_tag 38 +#define RadioConfig_UserPreferences_fixed_position_tag 39 +#define RadioConfig_UserPreferences_factory_reset_tag 100 +#define RadioConfig_UserPreferences_debug_log_enabled_tag 101 +#define RadioConfig_UserPreferences_ignore_incoming_tag 103 +#define RadioConfig_UserPreferences_serialplugin_enabled_tag 120 +#define RadioConfig_UserPreferences_serialplugin_echo_tag 121 +#define RadioConfig_UserPreferences_serialplugin_rxd_tag 122 +#define RadioConfig_UserPreferences_serialplugin_txd_tag 123 +#define RadioConfig_UserPreferences_serialplugin_timeout_tag 124 +#define RadioConfig_UserPreferences_serialplugin_mode_tag 125 +#define RadioConfig_UserPreferences_ext_notification_plugin_enabled_tag 126 +#define RadioConfig_UserPreferences_ext_notification_plugin_output_ms_tag 127 +#define RadioConfig_UserPreferences_ext_notification_plugin_output_tag 128 +#define RadioConfig_UserPreferences_ext_notification_plugin_active_tag 129 +#define RadioConfig_UserPreferences_ext_notification_plugin_alert_message_tag 130 +#define RadioConfig_UserPreferences_ext_notification_plugin_alert_bell_tag 131 +#define RadioConfig_UserPreferences_range_test_plugin_enabled_tag 132 +#define RadioConfig_UserPreferences_range_test_plugin_sender_tag 133 +#define RadioConfig_UserPreferences_range_test_plugin_save_tag 134 +#define RadioConfig_UserPreferences_store_forward_plugin_enabled_tag 136 +#define RadioConfig_UserPreferences_store_forward_plugin_records_tag 137 +#define RadioConfig_UserPreferences_environmental_measurement_plugin_measurement_enabled_tag 140 +#define RadioConfig_UserPreferences_environmental_measurement_plugin_screen_enabled_tag 141 +#define RadioConfig_UserPreferences_environmental_measurement_plugin_read_error_count_threshold_tag 142 +#define RadioConfig_UserPreferences_environmental_measurement_plugin_update_interval_tag 143 +#define RadioConfig_UserPreferences_environmental_measurement_plugin_recovery_interval_tag 144 +#define RadioConfig_preferences_tag 1 + +/* Struct field encoding specification for nanopb */ +#define RadioConfig_FIELDLIST(X, a) \ +X(a, STATIC, OPTIONAL, MESSAGE, preferences, 1) +#define RadioConfig_CALLBACK NULL +#define RadioConfig_DEFAULT NULL +#define RadioConfig_preferences_MSGTYPE RadioConfig_UserPreferences + +#define RadioConfig_UserPreferences_FIELDLIST(X, a) \ +X(a, STATIC, SINGULAR, UINT32, position_broadcast_secs, 1) \ +X(a, STATIC, SINGULAR, UINT32, send_owner_interval, 2) \ +X(a, STATIC, SINGULAR, UINT32, wait_bluetooth_secs, 4) \ +X(a, STATIC, SINGULAR, UINT32, screen_on_secs, 5) \ +X(a, STATIC, SINGULAR, UINT32, phone_timeout_secs, 6) \ +X(a, STATIC, SINGULAR, UINT32, phone_sds_timeout_sec, 7) \ +X(a, STATIC, SINGULAR, UINT32, mesh_sds_timeout_secs, 8) \ +X(a, STATIC, SINGULAR, UINT32, sds_secs, 9) \ +X(a, STATIC, SINGULAR, UINT32, ls_secs, 10) \ +X(a, STATIC, SINGULAR, UINT32, min_wake_secs, 11) \ +X(a, STATIC, SINGULAR, STRING, wifi_ssid, 12) \ +X(a, STATIC, SINGULAR, STRING, wifi_password, 13) \ +X(a, STATIC, SINGULAR, BOOL, wifi_ap_mode, 14) \ +X(a, STATIC, SINGULAR, UENUM, region, 15) \ +X(a, STATIC, SINGULAR, UENUM, charge_current, 16) \ +X(a, STATIC, SINGULAR, UENUM, location_share, 32) \ +X(a, STATIC, SINGULAR, UENUM, gps_operation, 33) \ +X(a, STATIC, SINGULAR, UINT32, gps_update_interval, 34) \ +X(a, STATIC, SINGULAR, UINT32, gps_attempt_time, 36) \ +X(a, STATIC, SINGULAR, BOOL, is_router, 37) \ +X(a, STATIC, SINGULAR, BOOL, is_low_power, 38) \ +X(a, STATIC, SINGULAR, BOOL, fixed_position, 39) \ +X(a, STATIC, SINGULAR, BOOL, factory_reset, 100) \ +X(a, STATIC, SINGULAR, BOOL, debug_log_enabled, 101) \ +X(a, STATIC, REPEATED, UINT32, ignore_incoming, 103) \ +X(a, STATIC, SINGULAR, BOOL, serialplugin_enabled, 120) \ +X(a, STATIC, SINGULAR, BOOL, serialplugin_echo, 121) \ +X(a, STATIC, SINGULAR, UINT32, serialplugin_rxd, 122) \ +X(a, STATIC, SINGULAR, UINT32, serialplugin_txd, 123) \ +X(a, STATIC, SINGULAR, UINT32, serialplugin_timeout, 124) \ +X(a, STATIC, SINGULAR, UINT32, serialplugin_mode, 125) \ +X(a, STATIC, SINGULAR, BOOL, ext_notification_plugin_enabled, 126) \ +X(a, STATIC, SINGULAR, UINT32, ext_notification_plugin_output_ms, 127) \ +X(a, STATIC, SINGULAR, UINT32, ext_notification_plugin_output, 128) \ +X(a, STATIC, SINGULAR, BOOL, ext_notification_plugin_active, 129) \ +X(a, STATIC, SINGULAR, BOOL, ext_notification_plugin_alert_message, 130) \ +X(a, STATIC, SINGULAR, BOOL, ext_notification_plugin_alert_bell, 131) \ +X(a, STATIC, SINGULAR, BOOL, range_test_plugin_enabled, 132) \ +X(a, STATIC, SINGULAR, UINT32, range_test_plugin_sender, 133) \ +X(a, STATIC, SINGULAR, BOOL, range_test_plugin_save, 134) \ +X(a, STATIC, SINGULAR, BOOL, store_forward_plugin_enabled, 136) \ +X(a, STATIC, SINGULAR, UINT32, store_forward_plugin_records, 137) \ +X(a, STATIC, SINGULAR, BOOL, environmental_measurement_plugin_measurement_enabled, 140) \ +X(a, STATIC, SINGULAR, BOOL, environmental_measurement_plugin_screen_enabled, 141) \ +X(a, STATIC, SINGULAR, UINT32, environmental_measurement_plugin_read_error_count_threshold, 142) \ +X(a, STATIC, SINGULAR, UINT32, environmental_measurement_plugin_update_interval, 143) \ +X(a, STATIC, SINGULAR, UINT32, environmental_measurement_plugin_recovery_interval, 144) +#define RadioConfig_UserPreferences_CALLBACK NULL +#define RadioConfig_UserPreferences_DEFAULT NULL + +extern const pb_msgdesc_t RadioConfig_msg; +extern const pb_msgdesc_t RadioConfig_UserPreferences_msg; + +/* Defines for backwards compatibility with code written before nanopb-0.4.0 */ +#define RadioConfig_fields &RadioConfig_msg +#define RadioConfig_UserPreferences_fields &RadioConfig_UserPreferences_msg + +/* Maximum encoded size of messages (where known) */ +#define RadioConfig_size 335 +#define RadioConfig_UserPreferences_size 332 + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif From a51c08bfb1e5cac09c2cdebf80606248e25ef460 Mon Sep 17 00:00:00 2001 From: Kevin Hester Date: Sat, 27 Feb 2021 14:42:07 +0800 Subject: [PATCH 184/258] todo updated --- docs/software/TODO.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/docs/software/TODO.md b/docs/software/TODO.md index 481799cc1..a5924c199 100644 --- a/docs/software/TODO.md +++ b/docs/software/TODO.md @@ -18,8 +18,9 @@ You probably don't care about this section - skip to the next one. * DONE test single channel without python * DONE Use "default" for name if name is empty * DONE fix python data packet receiving (nothing showing in log?) -* implement 'get channels' Admin plugin operation -* use get-channels from python +* DONE implement 'get channels' Admin plugin operation +* DONE use get-channels from python +* use get channels & get settings from android * use set-channel from python * combine acks and responses in a single message if possible (do routing plugin LAST and drop ACK if someone else has already replied) * use portuino TCP connection to debug with python API @@ -31,7 +32,7 @@ You probably don't care about this section - skip to the next one. * add gui in android app for setting region * warn in python api if we are too new to talk to the device code * make a post warning about 1.2, telling how to stay on old android & python clients. link to this from the android dialog message and python version warning. -* "FIXME - move the radioconfig/user/channel READ operations into SettingsMessage as well" +* DONE "FIXME - move the radioconfig/user/channel READ operations into SettingsMessage as well" * DONE scrub protobufs to make sure they are absoloute minimum wiresize (in particular Data, ChannelSets and positions) * change syncword * allow chaning packets in single transmission - to increase airtime efficiency and amortize packet overhead From 52d85c9a41819fc3edbb5825a44664ac8cc86da3 Mon Sep 17 00:00:00 2001 From: Jm Casler Date: Sat, 27 Feb 2021 22:34:53 -0800 Subject: [PATCH 185/258] Partial work from laptop -- non-routers can send a heartbeat --- src/plugins/esp32/StoreForwardPlugin.cpp | 20 +++++++++++++++----- src/plugins/esp32/StoreForwardPlugin.h | 5 +++++ 2 files changed, 20 insertions(+), 5 deletions(-) diff --git a/src/plugins/esp32/StoreForwardPlugin.cpp b/src/plugins/esp32/StoreForwardPlugin.cpp index 0550b7af0..031f32b4f 100644 --- a/src/plugins/esp32/StoreForwardPlugin.cpp +++ b/src/plugins/esp32/StoreForwardPlugin.cpp @@ -66,12 +66,13 @@ int32_t StoreForwardPlugin::runOnce() } } else { - DEBUG_MSG("Initializing Store & Forward Plugin - Enabled but is_router is not turned on.\n"); - DEBUG_MSG( - "Initializing Store & Forward Plugin - If you want to use this plugin, you must also turn on is_router.\n"); - // Non-Router + /* + * If the plugin is turned on and is_router is not enabled, then we'll send a heartbeat every + * few minutes. + */ + storeForwardPluginRadio->sendPayloadHeartbeat(); - return (30 * 1000); + return (3 * 60 * 1000); } } else { @@ -235,6 +236,15 @@ void StoreForwardPluginRadio::sendPayload(NodeNum dest, bool wantReplies) service.sendToMesh(p); } +void StoreForwardPluginRadio::sendPayloadHeartbeat(NodeNum dest, bool wantReplies) +{ + MeshPacket *p = allocReply(); + p->to = dest; + p->decoded.want_response = wantReplies; + + service.sendToMesh(p); +} + bool StoreForwardPluginRadio::handleReceived(const MeshPacket &mp) { #ifndef NO_ESP32 diff --git a/src/plugins/esp32/StoreForwardPlugin.h b/src/plugins/esp32/StoreForwardPlugin.h index e49b38fe9..d2a2879c8 100644 --- a/src/plugins/esp32/StoreForwardPlugin.h +++ b/src/plugins/esp32/StoreForwardPlugin.h @@ -63,6 +63,11 @@ class StoreForwardPluginRadio : public SinglePortPlugin */ void sendPayload(NodeNum dest = NODENUM_BROADCAST, bool wantReplies = false); + /** + * Send our payload into the mesh + */ + void sendPayloadHeartbeat(NodeNum dest = NODENUM_BROADCAST, bool wantReplies = false); + protected: virtual MeshPacket *allocReply(); From ef32ac5cd4e4694792025bc1a9b51ea7708fb0f7 Mon Sep 17 00:00:00 2001 From: Jm Date: Sun, 28 Feb 2021 11:55:54 -0800 Subject: [PATCH 186/258] Update rangetest docs with api example --- docs/software/plugins/RangeTestPlugin.md | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/docs/software/plugins/RangeTestPlugin.md b/docs/software/plugins/RangeTestPlugin.md index ee7732175..ab2f2c4df 100644 --- a/docs/software/plugins/RangeTestPlugin.md +++ b/docs/software/plugins/RangeTestPlugin.md @@ -45,6 +45,18 @@ Recommended settings for a sender at different radio settings: Medium ... range_test_plugin_sender = 15 Short Fast ... range_test_plugin_sender = 15 +## Python API Examples + +### Sender + + meshtastic --set range_test_plugin_enabled 1 + meshtastic --set range_test_plugin_sender 60 + +### Receiver + + meshtastic --set range_test_plugin_enabled 1 + meshtastic --set range_test_plugin_save 1 + ## Other things to keep in mind Be sure to turn off either the plugin configured as a sender or the device where the plugin setup as sender when not in use. This will use a lot of time on air and will spam your channel. From 9b45749bf0da5b7afddb22a13581d31edf374bc3 Mon Sep 17 00:00:00 2001 From: Kevin Hester Date: Mon, 1 Mar 2021 08:33:01 +0800 Subject: [PATCH 187/258] 1.1.50 --- version.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version.properties b/version.properties index 6c1503acd..ffb00973a 100644 --- a/version.properties +++ b/version.properties @@ -1,4 +1,4 @@ [VERSION] major = 1 minor = 1 -build = 48 +build = 50 From 2cf704abe09b4267e0a62aa57741294392f22e58 Mon Sep 17 00:00:00 2001 From: Jm Date: Sun, 28 Feb 2021 19:35:00 -0800 Subject: [PATCH 188/258] Crashes after 7 seconds. --- src/plugins/esp32/StoreForwardPlugin.cpp | 67 ++++++++++++++---------- 1 file changed, 40 insertions(+), 27 deletions(-) diff --git a/src/plugins/esp32/StoreForwardPlugin.cpp b/src/plugins/esp32/StoreForwardPlugin.cpp index 031f32b4f..ff763130c 100644 --- a/src/plugins/esp32/StoreForwardPlugin.cpp +++ b/src/plugins/esp32/StoreForwardPlugin.cpp @@ -26,26 +26,23 @@ int32_t StoreForwardPlugin::runOnce() without having to configure it from the PythonAPI or WebUI. */ - // radioConfig.preferences.store_forward_plugin_enabled = 1; - // radioConfig.preferences.is_router = 1; + radioConfig.preferences.store_forward_plugin_enabled = 1; + radioConfig.preferences.is_router = 0; if (radioConfig.preferences.store_forward_plugin_enabled) { if (firstTime) { - /* - */ + firstTime = 0; if (radioConfig.preferences.is_router) { - DEBUG_MSG("Initializing Store & Forward Plugin - Enabled\n"); + DEBUG_MSG("Initializing Store & Forward Plugin - Enabled as Router\n"); // Router if (ESP.getPsramSize()) { if (ESP.getFreePsram() >= 2048 * 1024) { // Do the startup here storeForwardPluginRadio = new StoreForwardPluginRadio(); - firstTime = 0; - this->populatePSRAM(); // packetHistory[0].bytes; @@ -66,22 +63,30 @@ int32_t StoreForwardPlugin::runOnce() } } else { - /* - * If the plugin is turned on and is_router is not enabled, then we'll send a heartbeat every - * few minutes. - */ - storeForwardPluginRadio->sendPayloadHeartbeat(); - - return (3 * 60 * 1000); + DEBUG_MSG("Initializing Store & Forward Plugin - Enabled as Client\n"); + return (5 * 1000); } } else { - // What do we do if it's not our first time? - // Maybe some cleanup functions? - this->sawNodeReport(); - this->historyReport(); - return (10 * 1000); + if (radioConfig.preferences.is_router) { + // Maybe some cleanup functions? + this->sawNodeReport(); + this->historyReport(); + return (10 * 1000); + } else { + /* + * If the plugin is turned on and is_router is not enabled, then we'll send a heartbeat every + * few minutes. + */ + + DEBUG_MSG("Store & Forward Plugin - Sending heartbeat\n"); + + // storeForwardPluginRadio->sendPayloadHeartbeat(); + storeForwardPluginRadio->sendPayload(); + + return (1 * 60 * 1000); + } } } else { @@ -221,24 +226,32 @@ void StoreForwardPlugin::sawNodeReport() MeshPacket *StoreForwardPluginRadio::allocReply() { - - auto reply = allocDataPacket(); // Allocate a packet for sending - - return reply; + //auto reply = allocDataPacket(); // Allocate a packet for sending + //return reply; } void StoreForwardPluginRadio::sendPayload(NodeNum dest, bool wantReplies) { - MeshPacket *p = allocReply(); + MeshPacket *p = this->allocReply(); + /* p->to = dest; p->decoded.want_response = wantReplies; - service.sendToMesh(p); + p->want_ack = true; +*/ + // static char heartbeatString[20]; + // snprintf(heartbeatString, sizeof(heartbeatString), "1"); + + // p->decoded.data.payload.size = strlen(heartbeatString); // You must specify how many bytes are in the reply + // memcpy(p->decoded.data.payload.bytes, "1", 1); + + // service.sendToMesh(p); } void StoreForwardPluginRadio::sendPayloadHeartbeat(NodeNum dest, bool wantReplies) { - MeshPacket *p = allocReply(); + DEBUG_MSG("Sending S&F Heartbeat\n"); + MeshPacket *p = this->allocReply(); p->to = dest; p->decoded.want_response = wantReplies; @@ -292,7 +305,7 @@ bool StoreForwardPluginRadio::handleReceived(const MeshPacket &mp) } if ((millis() - sawTime) > STOREFORWARD_SEND_HISTORY_SHORT) { - // Node has been away for a while. + // Node has been away for a while. storeForwardPlugin->historySend(sawTime, mp.from); } } From f6761d637f55b73454ae64ab9842909062613e58 Mon Sep 17 00:00:00 2001 From: Kevin Hester Date: Tue, 2 Mar 2021 11:46:00 +0800 Subject: [PATCH 189/258] proto update --- proto | 2 +- src/mesh/generated/mesh.pb.h | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/proto b/proto index 3edb02dab..2def8ece6 160000 --- a/proto +++ b/proto @@ -1 +1 @@ -Subproject commit 3edb02dabb9b8b72d90bbbb7233b557c09391b87 +Subproject commit 2def8ece61f792a2d7c4fb9297727b0efb4bf555 diff --git a/src/mesh/generated/mesh.pb.h b/src/mesh/generated/mesh.pb.h index a8f36a140..c92a44f2b 100644 --- a/src/mesh/generated/mesh.pb.h +++ b/src/mesh/generated/mesh.pb.h @@ -275,7 +275,7 @@ extern "C" { #define Routing_error_reason_tag 3 #define FromRadio_num_tag 1 #define FromRadio_my_info_tag 3 -#define FromRadio_node_info_tag 4 +#define FromRadio_node_info_tag 5 #define FromRadio_log_record_tag 7 #define FromRadio_config_complete_id_tag 8 #define FromRadio_rebooted_tag 9 @@ -379,7 +379,7 @@ X(a, STATIC, SINGULAR, UENUM, level, 4) #define FromRadio_FIELDLIST(X, a) \ X(a, STATIC, SINGULAR, UINT32, num, 1) \ X(a, STATIC, ONEOF, MESSAGE, (payloadVariant,my_info,my_info), 3) \ -X(a, STATIC, ONEOF, MESSAGE, (payloadVariant,node_info,node_info), 4) \ +X(a, STATIC, ONEOF, MESSAGE, (payloadVariant,node_info,node_info), 5) \ X(a, STATIC, ONEOF, MESSAGE, (payloadVariant,log_record,log_record), 7) \ X(a, STATIC, ONEOF, UINT32, (payloadVariant,config_complete_id,config_complete_id), 8) \ X(a, STATIC, ONEOF, BOOL, (payloadVariant,rebooted,rebooted), 9) \ From 082101f99f6f7c8ad7a1e36465c608bd81426dbf Mon Sep 17 00:00:00 2001 From: Kevin Hester Date: Tue, 2 Mar 2021 12:44:48 +0800 Subject: [PATCH 190/258] wire compat --- proto | 2 +- src/mesh/generated/mesh.pb.h | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/proto b/proto index 2def8ece6..7de496ffe 160000 --- a/proto +++ b/proto @@ -1 +1 @@ -Subproject commit 2def8ece61f792a2d7c4fb9297727b0efb4bf555 +Subproject commit 7de496ffe941f88e9d99c2ef2c7bc01f79efe11e diff --git a/src/mesh/generated/mesh.pb.h b/src/mesh/generated/mesh.pb.h index c92a44f2b..a8f36a140 100644 --- a/src/mesh/generated/mesh.pb.h +++ b/src/mesh/generated/mesh.pb.h @@ -275,7 +275,7 @@ extern "C" { #define Routing_error_reason_tag 3 #define FromRadio_num_tag 1 #define FromRadio_my_info_tag 3 -#define FromRadio_node_info_tag 5 +#define FromRadio_node_info_tag 4 #define FromRadio_log_record_tag 7 #define FromRadio_config_complete_id_tag 8 #define FromRadio_rebooted_tag 9 @@ -379,7 +379,7 @@ X(a, STATIC, SINGULAR, UENUM, level, 4) #define FromRadio_FIELDLIST(X, a) \ X(a, STATIC, SINGULAR, UINT32, num, 1) \ X(a, STATIC, ONEOF, MESSAGE, (payloadVariant,my_info,my_info), 3) \ -X(a, STATIC, ONEOF, MESSAGE, (payloadVariant,node_info,node_info), 5) \ +X(a, STATIC, ONEOF, MESSAGE, (payloadVariant,node_info,node_info), 4) \ X(a, STATIC, ONEOF, MESSAGE, (payloadVariant,log_record,log_record), 7) \ X(a, STATIC, ONEOF, UINT32, (payloadVariant,config_complete_id,config_complete_id), 8) \ X(a, STATIC, ONEOF, BOOL, (payloadVariant,rebooted,rebooted), 9) \ From fbdf1f19f0e8e96169c314f3d56c88422a18fcf4 Mon Sep 17 00:00:00 2001 From: Kevin Hester Date: Tue, 2 Mar 2021 12:46:19 +0800 Subject: [PATCH 191/258] add (editable) android warning landing page --- docs/software/android-too-old.md | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 docs/software/android-too-old.md diff --git a/docs/software/android-too-old.md b/docs/software/android-too-old.md new file mode 100644 index 000000000..2e2f2c766 --- /dev/null +++ b/docs/software/android-too-old.md @@ -0,0 +1,11 @@ +# Your android application needs updating + +Hi. + +If you've landed here that means your android application is too old for the running device firmware. Usually our updates are backwards compatible, but in this special circumstance it is not. Sorry. + +Probably, what this means is that you installed the **alpha test** version of the firmware from github. We really love people helping with development by running the alpha test binaries. But if you aren't ready to sign up for that right now, please go back to [github](https://github.com/meshtastic/Meshtastic-device/releases) and install the latest **not alpha** 1.1.x firmware. + +If you **do** intend to run the alpha test please opt-in to receive the alpha test version of the android application. + +If you have problems/questions please post in our [forum](https://meshtastic.discourse.group) and some nice person will probably help. \ No newline at end of file From 2ac410600456d9e739678f7a80ef33d46aa6d9b8 Mon Sep 17 00:00:00 2001 From: Kevin Hester Date: Tue, 2 Mar 2021 12:51:28 +0800 Subject: [PATCH 192/258] add play store link --- docs/software/android-too-old.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/software/android-too-old.md b/docs/software/android-too-old.md index 2e2f2c766..4f0c2403b 100644 --- a/docs/software/android-too-old.md +++ b/docs/software/android-too-old.md @@ -6,6 +6,8 @@ If you've landed here that means your android application is too old for the run Probably, what this means is that you installed the **alpha test** version of the firmware from github. We really love people helping with development by running the alpha test binaries. But if you aren't ready to sign up for that right now, please go back to [github](https://github.com/meshtastic/Meshtastic-device/releases) and install the latest **not alpha** 1.1.x firmware. -If you **do** intend to run the alpha test please opt-in to receive the alpha test version of the android application. +If you **do** intend to run the alpha test please [opt-in](https://play.google.com/apps/testing/com.geeksville.mesh) to receive the alpha test version of the android application. + +If you are willing to be an alpha tester, please keep an eye on our forum where we post frequent release notes. We also will actively help you with any bugs you might encounter (along our shared journey of new feature goodness). If you have problems/questions please post in our [forum](https://meshtastic.discourse.group) and some nice person will probably help. \ No newline at end of file From e884ace0ab941c649b9d3fa60deef5b958e0a54b Mon Sep 17 00:00:00 2001 From: Kevin Hester Date: Tue, 2 Mar 2021 15:16:22 +0800 Subject: [PATCH 193/258] show build name --- bin/program-release-tbeam.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/bin/program-release-tbeam.sh b/bin/program-release-tbeam.sh index 037431678..7870680fd 100755 --- a/bin/program-release-tbeam.sh +++ b/bin/program-release-tbeam.sh @@ -3,4 +3,5 @@ set -e VERSION=`bin/buildinfo.py` +echo Installing release/latest/bins/firmware-tbeam-US-$VERSION.bin esptool.py --baud 921600 write_flash 0x10000 release/latest/bins/firmware-tbeam-US-$VERSION.bin From 866125f2abaf7e35c315d74fcc98a55b1a9fe23d Mon Sep 17 00:00:00 2001 From: Kevin Hester Date: Tue, 2 Mar 2021 15:37:56 +0800 Subject: [PATCH 194/258] fix release script for universal builds --- bin/build-all.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/build-all.sh b/bin/build-all.sh index d9a6393e4..fae51feee 100755 --- a/bin/build-all.sh +++ b/bin/build-all.sh @@ -94,7 +94,7 @@ pio run --environment tbeam -t buildfs cp .pio/build/tbeam/spiffs.bin $OUTDIR/bins/universal/spiffs-$VERSION.bin # keep the bins in archive also -cp $OUTDIR/bins/firmware* $OUTDIR/bins/universal/spiffs* $OUTDIR/elfs/firmware* $OUTDIR/bins/universal/firmware* $OUTDIR/elfs/universal/firmware* $ARCHIVEDIR +cp $OUTDIR/bins/universal/spiffs* $OUTDIR/bins/universal/firmware* $OUTDIR/elfs/universal/firmware* $ARCHIVEDIR echo Updating android bins $OUTDIR/forandroid rm -rf $OUTDIR/forandroid @@ -115,6 +115,6 @@ XML echo Generating $ARCHIVEDIR/firmware-$VERSION.zip rm -f $ARCHIVEDIR/firmware-$VERSION.zip -zip --junk-paths $ARCHIVEDIR/firmware-$VERSION.zip $ARCHIVEDIR/spiffs-$VERSION.bin $OUTDIR/bins/firmware-*-$VERSION.* images/system-info.bin bin/device-install.sh bin/device-update.sh +zip --junk-paths $ARCHIVEDIR/firmware-$VERSION.zip $ARCHIVEDIR/spiffs-$VERSION.bin $OUTDIR/bins/universal/firmware-*-$VERSION.* images/system-info.bin bin/device-install.sh bin/device-update.sh echo BUILT ALL From 92e05bc4381d4db668791d51a80ebe12abe16e59 Mon Sep 17 00:00:00 2001 From: Kevin Hester Date: Wed, 3 Mar 2021 11:46:09 +0800 Subject: [PATCH 195/258] release to devs --- bin/program-release-tbeam.sh | 5 +++-- docs/software/TODO.md | 29 +++++++++++++++++++++-------- proto | 2 +- src/mesh/RadioLibInterface.h | 9 ++++++--- src/mesh/generated/deviceonly.pb.h | 4 ++-- 5 files changed, 33 insertions(+), 16 deletions(-) diff --git a/bin/program-release-tbeam.sh b/bin/program-release-tbeam.sh index 7870680fd..615ec66dc 100755 --- a/bin/program-release-tbeam.sh +++ b/bin/program-release-tbeam.sh @@ -2,6 +2,7 @@ set -e VERSION=`bin/buildinfo.py` +FILENAME=release/latest/bins/universal/firmware-tbeam-$VERSION.bin -echo Installing release/latest/bins/firmware-tbeam-US-$VERSION.bin -esptool.py --baud 921600 write_flash 0x10000 release/latest/bins/firmware-tbeam-US-$VERSION.bin +echo Installing $FILENAME +esptool.py --baud 921600 write_flash 0x10000 $FILENAME diff --git a/docs/software/TODO.md b/docs/software/TODO.md index a5924c199..b47fdb95b 100644 --- a/docs/software/TODO.md +++ b/docs/software/TODO.md @@ -20,21 +20,35 @@ You probably don't care about this section - skip to the next one. * DONE fix python data packet receiving (nothing showing in log?) * DONE implement 'get channels' Admin plugin operation * DONE use get-channels from python -* use get channels & get settings from android +* DONE use get channels & get settings from android * use set-channel from python +* DONE make settings changes from python work +* DONE pthon should stop fetching channels once we've reached our first empty channel definition (hasSettings == true) +* DONE add check for old devices with new API library +* DONE release python api +* DONE release protobufs +* DONE release to developers +* fix 1.1.50 android debug panel display +* add gui in android app for setting region +* stress test channel download from python, sometimes it seems like we don't get all replies +* investigate @mc-hamster report of heap corruption +* use set-channel from android +* DONE use set-user from android * combine acks and responses in a single message if possible (do routing plugin LAST and drop ACK if someone else has already replied) +* don't send packets we received from the phone BACK TOWARDS THE PHONE (possibly use fromnode 0 for packets the phone sends?) * use portuino TCP connection to debug with python API * make python tests more exhaustive * document the relationship between want_response (indicating remote node received it) and want_ack (indicating that this message should be sent reliably - and also get acks from the first rx node and naks if it is never delivered) -* test multi channel +* stress test multi channel * pick default random admin key +* DONE android should stop fetching channels once we've reached our first empty channel definition (hasSettings == true) +* add channel restrictions for plugins (and restrict routing plugin to the "control" channel) * restrict gpio & serial & settings operations to the admin channel (unless local to the current node) -* add gui in android app for setting region * warn in python api if we are too new to talk to the device code * make a post warning about 1.2, telling how to stay on old android & python clients. link to this from the android dialog message and python version warning. * DONE "FIXME - move the radioconfig/user/channel READ operations into SettingsMessage as well" * DONE scrub protobufs to make sure they are absoloute minimum wiresize (in particular Data, ChannelSets and positions) -* change syncword +* DONE change syncword (now ox2b) * allow chaning packets in single transmission - to increase airtime efficiency and amortize packet overhead * DONE move most parts of meshpacket into the Data packet, so that we can chain multiple Data for sending when they all have a common destination and key. * when selecting a MeshPacket for transmit, scan the TX queue for any Data packets we can merge together as a WirePayload. In the low level send/rx code expand that into multiple MeshPackets as needed (thus 'hiding' from MeshPacket that over the wire we send multiple datapackets @@ -45,15 +59,14 @@ You probably don't care about this section - skip to the next one. * DONE move acks into routing * DONE make all subpackets different versions of data * DONE move routing control into a data packet -* have phoneapi done via plugin +* have phoneapi done via plugin (will allow multiple simultaneous API clients - stop disabling BLE while using phone API) * DONE figure out how to add micro_delta to position, make it so that phone apps don't need to understand it? * only send battery updates a max of once a minute * add python channel selection for sending * DONE record recevied channel in meshpacket * test remote settings operations (confirm it works 3 hops away) -* add channel restrictions for plugins (and restrict routing plugin to the "control" channel) -* make a primaryChannel global and properly maintain it when the phone sends setChannel -* move setCrypto call into packet send and packet decode code +* DONE make a primaryChannel global and properly maintain it when the phone sends setChannel +* DONE move setCrypto call into packet send and packet decode code * implement 'small location diffs' change * move battery level out of position? * DOUBLE CHECK android app can still upgrade 1.1 and 1.0 loads diff --git a/proto b/proto index 7de496ffe..94bd0aae4 160000 --- a/proto +++ b/proto @@ -1 +1 @@ -Subproject commit 7de496ffe941f88e9d99c2ef2c7bc01f79efe11e +Subproject commit 94bd0aae44e2c16c7776289225c804100c856cd4 diff --git a/src/mesh/RadioLibInterface.h b/src/mesh/RadioLibInterface.h index 726e81b37..cd46968ce 100644 --- a/src/mesh/RadioLibInterface.h +++ b/src/mesh/RadioLibInterface.h @@ -80,10 +80,13 @@ class RadioLibInterface : public RadioInterface, protected concurrency::Notified protected: /** - * FIXME, use a meshtastic sync word, but hashed with the Channel name. Currently picking the same default - * the RF95 used (0x14). Note: do not use 0x34 - that is reserved for lorawan + * We use a meshtastic sync word, but hashed with the Channel name. For releases before 1.2 we used 0x12 (or for very old loads 0x14) + * Note: do not use 0x34 - that is reserved for lorawan + * + * We now use 0x2b (so that someday we can possibly use NOT 2b - because that would be funny pun). We will be staying with this code + * for a long time. */ - uint8_t syncWord = SX126X_SYNC_WORD_PRIVATE; + const uint8_t syncWord = 0x2b; float currentLimit = 100; // FIXME diff --git a/src/mesh/generated/deviceonly.pb.h b/src/mesh/generated/deviceonly.pb.h index 52420a376..a1e6de3af 100644 --- a/src/mesh/generated/deviceonly.pb.h +++ b/src/mesh/generated/deviceonly.pb.h @@ -52,7 +52,7 @@ extern "C" { #define DeviceState_version_tag 8 #define DeviceState_no_save_tag 9 #define DeviceState_did_gps_reset_tag 11 -#define DeviceState_channels_tag 12 +#define DeviceState_channels_tag 13 /* Struct field encoding specification for nanopb */ #define DeviceState_FIELDLIST(X, a) \ @@ -65,7 +65,7 @@ X(a, STATIC, OPTIONAL, MESSAGE, rx_text_message, 7) \ X(a, STATIC, SINGULAR, UINT32, version, 8) \ X(a, STATIC, SINGULAR, BOOL, no_save, 9) \ X(a, STATIC, SINGULAR, BOOL, did_gps_reset, 11) \ -X(a, STATIC, REPEATED, MESSAGE, channels, 12) +X(a, STATIC, REPEATED, MESSAGE, channels, 13) #define DeviceState_CALLBACK NULL #define DeviceState_DEFAULT NULL #define DeviceState_radio_MSGTYPE RadioConfig From 076251e6a8309e62e24b25a2a34a13d3efac19eb Mon Sep 17 00:00:00 2001 From: Kevin Hester Date: Wed, 3 Mar 2021 11:49:09 +0800 Subject: [PATCH 196/258] todo cleanup --- docs/software/TODO.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/software/TODO.md b/docs/software/TODO.md index b47fdb95b..5942aa438 100644 --- a/docs/software/TODO.md +++ b/docs/software/TODO.md @@ -2,7 +2,7 @@ You probably don't care about this section - skip to the next one. -1.2 cleanup & multichannel support: +## 1.2 cleanup & multichannel support: * DONE call RouterPlugin for *all* packets - not just Router packets * DONE generate channel hash from the name of the channel+the psk (not just one or the other) @@ -44,8 +44,8 @@ You probably don't care about this section - skip to the next one. * DONE android should stop fetching channels once we've reached our first empty channel definition (hasSettings == true) * add channel restrictions for plugins (and restrict routing plugin to the "control" channel) * restrict gpio & serial & settings operations to the admin channel (unless local to the current node) -* warn in python api if we are too new to talk to the device code -* make a post warning about 1.2, telling how to stay on old android & python clients. link to this from the android dialog message and python version warning. +* DONE warn in python api if we are too new to talk to the device code +* DONE make a post warning about 1.2, telling how to stay on old android & python clients. link to this from the android dialog message and python version warning. * DONE "FIXME - move the radioconfig/user/channel READ operations into SettingsMessage as well" * DONE scrub protobufs to make sure they are absoloute minimum wiresize (in particular Data, ChannelSets and positions) * DONE change syncword (now ox2b) From a3343bc1af13931e6c68d6578e95486b76db90e3 Mon Sep 17 00:00:00 2001 From: Jm Casler Date: Tue, 2 Mar 2021 20:46:21 -0800 Subject: [PATCH 197/258] Revert "Merge pull request #73 from meshtastic/master" This reverts commit ee04d57a7f4ec94c6ba8a872d6b1ffb5aa96c562. From 2af9e1431e6adeba112d30b60a37e809fd56d219 Mon Sep 17 00:00:00 2001 From: Charles Crossan Date: Sat, 27 Feb 2021 23:23:50 -0500 Subject: [PATCH 198/258] Improvements to EnvironmentalMeasurementPlugin Instead of holding onto only the last measurement, hold onto a copy of the last MeshPacket containing a measurement This will make it easier to display the last time received make DHT sensor reads more reliable user preference for Farenheit vs Celsius --- proto | 2 +- src/mesh/generated/admin.pb.h | 2 +- src/mesh/generated/deviceonly.pb.h | 2 +- src/mesh/generated/portnums.pb.h | 2 +- src/mesh/generated/radioconfig.pb.c | 1 + src/mesh/generated/radioconfig.pb.h | 27 ++++-- .../esp32/EnvironmentalMeasurementPlugin.cpp | 90 ++++++++++++++----- .../esp32/EnvironmentalMeasurementPlugin.h | 11 +-- 8 files changed, 99 insertions(+), 38 deletions(-) diff --git a/proto b/proto index 94bd0aae4..270cbdb68 160000 --- a/proto +++ b/proto @@ -1 +1 @@ -Subproject commit 94bd0aae44e2c16c7776289225c804100c856cd4 +Subproject commit 270cbdb6801761f054cb79f64b68b8a75cfb50f6 diff --git a/src/mesh/generated/admin.pb.h b/src/mesh/generated/admin.pb.h index f9be1cada..7c0ac9145 100644 --- a/src/mesh/generated/admin.pb.h +++ b/src/mesh/generated/admin.pb.h @@ -67,7 +67,7 @@ extern const pb_msgdesc_t AdminMessage_msg; #define AdminMessage_fields &AdminMessage_msg /* Maximum encoded size of messages (where known) */ -#define AdminMessage_size 338 +#define AdminMessage_size 351 #ifdef __cplusplus } /* extern "C" */ diff --git a/src/mesh/generated/deviceonly.pb.h b/src/mesh/generated/deviceonly.pb.h index a1e6de3af..dd3451849 100644 --- a/src/mesh/generated/deviceonly.pb.h +++ b/src/mesh/generated/deviceonly.pb.h @@ -82,7 +82,7 @@ extern const pb_msgdesc_t DeviceState_msg; #define DeviceState_fields &DeviceState_msg /* Maximum encoded size of messages (where known) */ -#define DeviceState_size 6156 +#define DeviceState_size 6169 #ifdef __cplusplus } /* extern "C" */ diff --git a/src/mesh/generated/portnums.pb.h b/src/mesh/generated/portnums.pb.h index 758db47a6..5904a548c 100644 --- a/src/mesh/generated/portnums.pb.h +++ b/src/mesh/generated/portnums.pb.h @@ -20,10 +20,10 @@ typedef enum _PortNum { PortNum_ADMIN_APP = 6, PortNum_REPLY_APP = 32, PortNum_IP_TUNNEL_APP = 33, - PortNum_ENVIRONMENTAL_MEASUREMENT_APP = 34, PortNum_SERIAL_APP = 64, PortNum_STORE_FORWARD_APP = 65, PortNum_RANGE_TEST_APP = 66, + PortNum_ENVIRONMENTAL_MEASUREMENT_APP = 67, PortNum_PRIVATE_APP = 256, PortNum_ATAK_FORWARDER = 257, PortNum_MAX = 511 diff --git a/src/mesh/generated/radioconfig.pb.c b/src/mesh/generated/radioconfig.pb.c index 85aa7aa18..716b804e8 100644 --- a/src/mesh/generated/radioconfig.pb.c +++ b/src/mesh/generated/radioconfig.pb.c @@ -17,3 +17,4 @@ PB_BIND(RadioConfig_UserPreferences, RadioConfig_UserPreferences, 2) + diff --git a/src/mesh/generated/radioconfig.pb.h b/src/mesh/generated/radioconfig.pb.h index b8a6bfd7a..85bfa1a2d 100644 --- a/src/mesh/generated/radioconfig.pb.h +++ b/src/mesh/generated/radioconfig.pb.h @@ -56,6 +56,10 @@ typedef enum _LocationSharing { LocationSharing_LocDisabled = 2 } LocationSharing; +typedef enum _RadioConfig_UserPreferences_EnvironmentalMeasurementSensorType { + RadioConfig_UserPreferences_EnvironmentalMeasurementSensorType_DHT11 = 0 +} RadioConfig_UserPreferences_EnvironmentalMeasurementSensorType; + /* Struct definitions */ typedef struct _RadioConfig_UserPreferences { uint32_t position_broadcast_secs; @@ -106,6 +110,9 @@ typedef struct _RadioConfig_UserPreferences { uint32_t environmental_measurement_plugin_read_error_count_threshold; uint32_t environmental_measurement_plugin_update_interval; uint32_t environmental_measurement_plugin_recovery_interval; + bool environmental_measurement_plugin_display_farenheit; + RadioConfig_UserPreferences_EnvironmentalMeasurementSensorType environmental_measurement_plugin_sensor_type; + uint32_t environmental_measurement_plugin_sensor_pin; } RadioConfig_UserPreferences; typedef struct _RadioConfig { @@ -131,6 +138,10 @@ typedef struct _RadioConfig { #define _LocationSharing_MAX LocationSharing_LocDisabled #define _LocationSharing_ARRAYSIZE ((LocationSharing)(LocationSharing_LocDisabled+1)) +#define _RadioConfig_UserPreferences_EnvironmentalMeasurementSensorType_MIN RadioConfig_UserPreferences_EnvironmentalMeasurementSensorType_DHT11 +#define _RadioConfig_UserPreferences_EnvironmentalMeasurementSensorType_MAX RadioConfig_UserPreferences_EnvironmentalMeasurementSensorType_DHT11 +#define _RadioConfig_UserPreferences_EnvironmentalMeasurementSensorType_ARRAYSIZE ((RadioConfig_UserPreferences_EnvironmentalMeasurementSensorType)(RadioConfig_UserPreferences_EnvironmentalMeasurementSensorType_DHT11+1)) + #ifdef __cplusplus extern "C" { @@ -138,9 +149,9 @@ extern "C" { /* Initializer values for message structs */ #define RadioConfig_init_default {false, RadioConfig_UserPreferences_init_default} -#define RadioConfig_UserPreferences_init_default {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, "", "", 0, _RegionCode_MIN, _ChargeCurrent_MIN, _LocationSharing_MIN, _GpsOperation_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, 0, 0, 0, 0, 0} +#define RadioConfig_UserPreferences_init_default {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, "", "", 0, _RegionCode_MIN, _ChargeCurrent_MIN, _LocationSharing_MIN, _GpsOperation_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, 0, 0, 0, 0, 0, 0, _RadioConfig_UserPreferences_EnvironmentalMeasurementSensorType_MIN, 0} #define RadioConfig_init_zero {false, RadioConfig_UserPreferences_init_zero} -#define RadioConfig_UserPreferences_init_zero {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, "", "", 0, _RegionCode_MIN, _ChargeCurrent_MIN, _LocationSharing_MIN, _GpsOperation_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, 0, 0, 0, 0, 0} +#define RadioConfig_UserPreferences_init_zero {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, "", "", 0, _RegionCode_MIN, _ChargeCurrent_MIN, _LocationSharing_MIN, _GpsOperation_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, 0, 0, 0, 0, 0, 0, _RadioConfig_UserPreferences_EnvironmentalMeasurementSensorType_MIN, 0} /* Field tags (for use in manual encoding/decoding) */ #define RadioConfig_UserPreferences_position_broadcast_secs_tag 1 @@ -190,6 +201,9 @@ extern "C" { #define RadioConfig_UserPreferences_environmental_measurement_plugin_read_error_count_threshold_tag 142 #define RadioConfig_UserPreferences_environmental_measurement_plugin_update_interval_tag 143 #define RadioConfig_UserPreferences_environmental_measurement_plugin_recovery_interval_tag 144 +#define RadioConfig_UserPreferences_environmental_measurement_plugin_display_farenheit_tag 145 +#define RadioConfig_UserPreferences_environmental_measurement_plugin_sensor_type_tag 146 +#define RadioConfig_UserPreferences_environmental_measurement_plugin_sensor_pin_tag 147 #define RadioConfig_preferences_tag 1 /* Struct field encoding specification for nanopb */ @@ -246,7 +260,10 @@ X(a, STATIC, SINGULAR, BOOL, environmental_measurement_plugin_measurement_ X(a, STATIC, SINGULAR, BOOL, environmental_measurement_plugin_screen_enabled, 141) \ X(a, STATIC, SINGULAR, UINT32, environmental_measurement_plugin_read_error_count_threshold, 142) \ X(a, STATIC, SINGULAR, UINT32, environmental_measurement_plugin_update_interval, 143) \ -X(a, STATIC, SINGULAR, UINT32, environmental_measurement_plugin_recovery_interval, 144) +X(a, STATIC, SINGULAR, UINT32, environmental_measurement_plugin_recovery_interval, 144) \ +X(a, STATIC, SINGULAR, BOOL, environmental_measurement_plugin_display_farenheit, 145) \ +X(a, STATIC, SINGULAR, UENUM, environmental_measurement_plugin_sensor_type, 146) \ +X(a, STATIC, SINGULAR, UINT32, environmental_measurement_plugin_sensor_pin, 147) #define RadioConfig_UserPreferences_CALLBACK NULL #define RadioConfig_UserPreferences_DEFAULT NULL @@ -258,8 +275,8 @@ extern const pb_msgdesc_t RadioConfig_UserPreferences_msg; #define RadioConfig_UserPreferences_fields &RadioConfig_UserPreferences_msg /* Maximum encoded size of messages (where known) */ -#define RadioConfig_size 335 -#define RadioConfig_UserPreferences_size 332 +#define RadioConfig_size 348 +#define RadioConfig_UserPreferences_size 345 #ifdef __cplusplus } /* extern "C" */ diff --git a/src/plugins/esp32/EnvironmentalMeasurementPlugin.cpp b/src/plugins/esp32/EnvironmentalMeasurementPlugin.cpp index b332efd6e..40be3f9d3 100644 --- a/src/plugins/esp32/EnvironmentalMeasurementPlugin.cpp +++ b/src/plugins/esp32/EnvironmentalMeasurementPlugin.cpp @@ -53,7 +53,8 @@ int32_t EnvironmentalMeasurementPlugin::runOnce() { radioConfig.preferences.environmental_measurement_plugin_screen_enabled = 1; radioConfig.preferences.environmental_measurement_plugin_read_error_count_threshold = 5; radioConfig.preferences.environmental_measurement_plugin_update_interval = 30; - radioConfig.preferences.environmental_measurement_plugin_recovery_interval = 600;*/ + radioConfig.preferences.environmental_measurement_plugin_recovery_interval = 60; + radioConfig.preferences.environmental_measurement_plugin_display_farenheit = true;*/ if (! (radioConfig.preferences.environmental_measurement_plugin_measurement_enabled || radioConfig.preferences.environmental_measurement_plugin_screen_enabled)){ // If this plugin is not enabled, and the user doesn't want the display screen don't waste any OSThread time on it @@ -96,6 +97,7 @@ int32_t EnvironmentalMeasurementPlugin::runOnce() { "EnvironmentalMeasurement: TEMPORARILY DISABLED; The environmental_measurement_plugin_read_error_count_threshold has been exceed: %d. Will retry reads in %d seconds\n", radioConfig.preferences.environmental_measurement_plugin_read_error_count_threshold, radioConfig.preferences.environmental_measurement_plugin_recovery_interval); + sensor_read_error_count = 0; return(radioConfig.preferences.environmental_measurement_plugin_recovery_interval*1000); } DEBUG_MSG( @@ -127,16 +129,6 @@ bool EnvironmentalMeasurementPluginRadio::wantUIFrame() { return radioConfig.preferences.environmental_measurement_plugin_screen_enabled; } -void EnvironmentalMeasurementPluginRadio::drawFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y) -{ - display->setTextAlignment(TEXT_ALIGN_LEFT); - display->setFont(FONT_MEDIUM); - display->drawString(x, y, "Environment"); - display->setFont(FONT_SMALL); - display->drawString(x, y += fontHeight(FONT_MEDIUM), lastSender+": T:"+ String(lastMeasurement.temperature,2) + " H:" + String(lastMeasurement.relative_humidity,2)); - -} - String GetSenderName(const MeshPacket &mp) { String sender; @@ -149,7 +141,64 @@ String GetSenderName(const MeshPacket &mp) { return sender; } -bool EnvironmentalMeasurementPluginRadio::handleReceivedProtobuf(const MeshPacket &mp, const EnvironmentalMeasurement *pptr) +uint32_t GetTimeSinceMeshPacket(const MeshPacket *mp) { + uint32_t now = getTime(); + + uint32_t last_seen = mp->rx_time; + int delta = (int)(now - last_seen); + if (delta < 0) // our clock must be slightly off still - not set from GPS yet + delta = 0; + + return delta; + +} + + +float CelsiusToFarenheit(float c) { + return (c*9)/5 + 32; +} + + +void EnvironmentalMeasurementPluginRadio::drawFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y) +{ + display->setTextAlignment(TEXT_ALIGN_LEFT); + display->setFont(FONT_MEDIUM); + display->drawString(x, y, "Environment"); + if (lastMeasurementPacket == nullptr) { + display->setFont(FONT_SMALL); + display->drawString(x, y += fontHeight(FONT_MEDIUM), "No measurement"); + DEBUG_MSG("EnvironmentalMeasurement: No previous measurement; not drawing frame"); + return; + } + + EnvironmentalMeasurement lastMeasurement; + + + uint32_t agoSecs = GetTimeSinceMeshPacket(lastMeasurementPacket); + String lastSender = GetSenderName(*lastMeasurementPacket); + + auto &p = lastMeasurementPacket->decoded.data; + if (!pb_decode_from_bytes(p.payload.bytes, + p.payload.size, + EnvironmentalMeasurement_fields, + &lastMeasurement)) { + display->setFont(FONT_SMALL); + display->drawString(x, y += fontHeight(FONT_MEDIUM), "Measurement Error"); + DEBUG_MSG("EnvironmentalMeasurement: unable to decode last packet"); + return; + } + + display->setFont(FONT_SMALL); + String last_temp = String(lastMeasurement.temperature,0) +"°C"; + if (radioConfig.preferences.environmental_measurement_plugin_display_farenheit){ + last_temp = String(CelsiusToFarenheit(lastMeasurement.temperature),0) +"°F";; + } + + display->drawString(x, y += fontHeight(FONT_MEDIUM), lastSender+": "+last_temp +"/"+ String(lastMeasurement.relative_humidity,0) + "%("+String(agoSecs)+"s)"); + +} + +bool EnvironmentalMeasurementPluginRadio::handleReceivedProtobuf(const MeshPacket &mp, const EnvironmentalMeasurement &p) { const EnvironmentalMeasurement &p = *pptr; @@ -174,8 +223,8 @@ bool EnvironmentalMeasurementPluginRadio::handleReceivedProtobuf(const MeshPacke DEBUG_MSG("EnvironmentalMeasurement->relative_humidity: %f\n", p.relative_humidity); DEBUG_MSG("EnvironmentalMeasurement->temperature: %f\n", p.temperature); - lastMeasurement = p; - lastSender = sender; + lastMeasurementPacket = packetPool.allocCopy(mp); + return false; // Let others look at this message also if they want } @@ -184,20 +233,19 @@ bool EnvironmentalMeasurementPluginRadio::sendOurEnvironmentalMeasurement(NodeNu EnvironmentalMeasurement m; m.barometric_pressure = 0; // TODO: Add support for barometric sensors - m.relative_humidity = dht.readHumidity(); - m.temperature = dht.readTemperature();; - DEBUG_MSG("-----------------------------------------\n"); DEBUG_MSG("EnvironmentalMeasurement: Read data\n"); - DEBUG_MSG("EnvironmentalMeasurement->relative_humidity: %f\n", m.relative_humidity); - DEBUG_MSG("EnvironmentalMeasurement->temperature: %f\n", m.temperature); - - if (isnan(m.relative_humidity) || isnan(m.temperature) ){ + if (!dht.read(true)){ sensor_read_error_count++; DEBUG_MSG("EnvironmentalMeasurement: FAILED TO READ DATA\n"); return false; } + m.relative_humidity = dht.readHumidity(); + m.temperature = dht.readTemperature(); + + DEBUG_MSG("EnvironmentalMeasurement->relative_humidity: %f\n", m.relative_humidity); + DEBUG_MSG("EnvironmentalMeasurement->temperature: %f\n", m.temperature); sensor_read_error_count = 0; diff --git a/src/plugins/esp32/EnvironmentalMeasurementPlugin.h b/src/plugins/esp32/EnvironmentalMeasurementPlugin.h index e29ea983e..4e43e46ce 100644 --- a/src/plugins/esp32/EnvironmentalMeasurementPlugin.h +++ b/src/plugins/esp32/EnvironmentalMeasurementPlugin.h @@ -27,11 +27,8 @@ class EnvironmentalMeasurementPluginRadio : public ProtobufPlugin Date: Tue, 2 Mar 2021 21:12:22 -0500 Subject: [PATCH 199/258] refactor ENV to single multi-inheritance class with cleaner user preferences Fix merge issues don't log when drawing blank frames remove useless logging re-comment stuff fix comment unused var --- .../esp32/EnvironmentalMeasurementPlugin.cpp | 83 +++++++++---------- .../esp32/EnvironmentalMeasurementPlugin.h | 56 ++++--------- 2 files changed, 54 insertions(+), 85 deletions(-) diff --git a/src/plugins/esp32/EnvironmentalMeasurementPlugin.cpp b/src/plugins/esp32/EnvironmentalMeasurementPlugin.cpp index 40be3f9d3..4ade032be 100644 --- a/src/plugins/esp32/EnvironmentalMeasurementPlugin.cpp +++ b/src/plugins/esp32/EnvironmentalMeasurementPlugin.cpp @@ -10,20 +10,10 @@ #include #include -EnvironmentalMeasurementPlugin *environmentalMeasurementPlugin; -EnvironmentalMeasurementPluginRadio *environmentalMeasurementPluginRadio; - -EnvironmentalMeasurementPlugin::EnvironmentalMeasurementPlugin() : concurrency::OSThread("EnvironmentalMeasurementPlugin") {} - -uint32_t sensor_read_error_count = 0; - -#define DHT_11_GPIO_PIN 13 #define DHT_SENSOR_MINIMUM_WAIT_TIME_BETWEEN_READS 1000 // Some sensors (the DHT11) have a minimum required duration between read attempts #define FAILED_STATE_SENSOR_READ_MULTIPLIER 10 #define DISPLAY_RECEIVEID_MEASUREMENTS_ON_SCREEN true -DHT dht(DHT_11_GPIO_PIN,DHT11); - #ifdef HAS_EINK // The screen is bigger so use bigger fonts @@ -49,12 +39,15 @@ int32_t EnvironmentalMeasurementPlugin::runOnce() { Uncomment the preferences below if you want to use the plugin without having to configure it from the PythonAPI or WebUI. */ + /*radioConfig.preferences.environmental_measurement_plugin_measurement_enabled = 1; radioConfig.preferences.environmental_measurement_plugin_screen_enabled = 1; radioConfig.preferences.environmental_measurement_plugin_read_error_count_threshold = 5; radioConfig.preferences.environmental_measurement_plugin_update_interval = 30; radioConfig.preferences.environmental_measurement_plugin_recovery_interval = 60; - radioConfig.preferences.environmental_measurement_plugin_display_farenheit = true;*/ + radioConfig.preferences.environmental_measurement_plugin_display_farenheit = true; + radioConfig.preferences.environmental_measurement_plugin_sensor_pin = 13; + radioConfig.preferences.environmental_measurement_plugin_sensor_type = RadioConfig_UserPreferences_EnvironmentalMeasurementSensorType::RadioConfig_UserPreferences_EnvironmentalMeasurementSensorType_DHT11;*/ if (! (radioConfig.preferences.environmental_measurement_plugin_measurement_enabled || radioConfig.preferences.environmental_measurement_plugin_screen_enabled)){ // If this plugin is not enabled, and the user doesn't want the display screen don't waste any OSThread time on it @@ -63,20 +56,32 @@ int32_t EnvironmentalMeasurementPlugin::runOnce() { if (firstTime) { // This is the first time the OSThread library has called this function, so do some setup - DEBUG_MSG("EnvironmentalMeasurement: Initializing\n"); - environmentalMeasurementPluginRadio = new EnvironmentalMeasurementPluginRadio(); + firstTime = 0; - // begin reading measurements from the sensor - // DHT have a max read-rate of 1HZ, so we should wait at least 1 second - // after initializing the sensor before we try to read from it. - // returning the interval here means that the next time OSThread - // calls our plugin, we'll run the other branch of this if statement - // and actually do a "sendOurEnvironmentalMeasurement()" + if (radioConfig.preferences.environmental_measurement_plugin_measurement_enabled) { + DEBUG_MSG("EnvironmentalMeasurement: Initializing\n"); // it's possible to have this plugin enabled, only for displaying values on the screen. // therefore, we should only enable the sensor loop if measurement is also enabled - dht.begin(); + switch(radioConfig.preferences.environmental_measurement_plugin_sensor_type) { + case RadioConfig_UserPreferences_EnvironmentalMeasurementSensorType_DHT11: + dht = new DHT(radioConfig.preferences.environmental_measurement_plugin_sensor_pin,DHT11); + this->dht->begin(); + this->dht->read(); + DEBUG_MSG("EnvironmentalMeasurement: Opened DHT11 on pin: %d\n",radioConfig.preferences.environmental_measurement_plugin_sensor_pin); + break; + default: + DEBUG_MSG("EnvironmentalMeasurement: Invalid sensor type selected; Disabling plugin"); + return (INT32_MAX); + break; + } + // begin reading measurements from the sensor + // DHT have a max read-rate of 1HZ, so we should wait at least 1 second + // after initializing the sensor before we try to read from it. + // returning the interval here means that the next time OSThread + // calls our plugin, we'll run the other branch of this if statement + // and actually do a "sendOurEnvironmentalMeasurement()" return(DHT_SENSOR_MINIMUM_WAIT_TIME_BETWEEN_READS); } return (INT32_MAX); @@ -112,7 +117,7 @@ int32_t EnvironmentalMeasurementPlugin::runOnce() { sensor_read_error_count, radioConfig.preferences.environmental_measurement_plugin_read_error_count_threshold-sensor_read_error_count); } - if (! environmentalMeasurementPluginRadio->sendOurEnvironmentalMeasurement() ){ + if (!sendOurEnvironmentalMeasurement() ){ // if we failed to read the sensor, then try again // as soon as we can according to the maximum polling frequency return(DHT_SENSOR_MINIMUM_WAIT_TIME_BETWEEN_READS); @@ -125,7 +130,7 @@ int32_t EnvironmentalMeasurementPlugin::runOnce() { #endif } -bool EnvironmentalMeasurementPluginRadio::wantUIFrame() { +bool EnvironmentalMeasurementPlugin::wantUIFrame() { return radioConfig.preferences.environmental_measurement_plugin_screen_enabled; } @@ -154,12 +159,12 @@ uint32_t GetTimeSinceMeshPacket(const MeshPacket *mp) { } -float CelsiusToFarenheit(float c) { +float EnvironmentalMeasurementPlugin::CelsiusToFarenheit(float c) { return (c*9)/5 + 32; } -void EnvironmentalMeasurementPluginRadio::drawFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y) +void EnvironmentalMeasurementPlugin::drawFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y) { display->setTextAlignment(TEXT_ALIGN_LEFT); display->setFont(FONT_MEDIUM); @@ -167,7 +172,7 @@ void EnvironmentalMeasurementPluginRadio::drawFrame(OLEDDisplay *display, OLEDDi if (lastMeasurementPacket == nullptr) { display->setFont(FONT_SMALL); display->drawString(x, y += fontHeight(FONT_MEDIUM), "No measurement"); - DEBUG_MSG("EnvironmentalMeasurement: No previous measurement; not drawing frame"); + //DEBUG_MSG("EnvironmentalMeasurement: No previous measurement; not drawing frame\n"); return; } @@ -177,7 +182,7 @@ void EnvironmentalMeasurementPluginRadio::drawFrame(OLEDDisplay *display, OLEDDi uint32_t agoSecs = GetTimeSinceMeshPacket(lastMeasurementPacket); String lastSender = GetSenderName(*lastMeasurementPacket); - auto &p = lastMeasurementPacket->decoded.data; + auto &p = lastMeasurementPacket->decoded; if (!pb_decode_from_bytes(p.payload.bytes, p.payload.size, EnvironmentalMeasurement_fields, @@ -198,37 +203,25 @@ void EnvironmentalMeasurementPluginRadio::drawFrame(OLEDDisplay *display, OLEDDi } -bool EnvironmentalMeasurementPluginRadio::handleReceivedProtobuf(const MeshPacket &mp, const EnvironmentalMeasurement &p) +bool EnvironmentalMeasurementPlugin::handleReceivedProtobuf(const MeshPacket &mp, const EnvironmentalMeasurement *p) { - const EnvironmentalMeasurement &p = *pptr; - if (!(radioConfig.preferences.environmental_measurement_plugin_measurement_enabled || radioConfig.preferences.environmental_measurement_plugin_screen_enabled)){ // If this plugin is not enabled in any capacity, don't handle the packet, and allow other plugins to consume return false; } - bool wasBroadcast = mp.to == NODENUM_BROADCAST; String sender = GetSenderName(mp); - - // Show new nodes on LCD screen - if (DISPLAY_RECEIVEID_MEASUREMENTS_ON_SCREEN && wasBroadcast) { - String lcd = String("Env Measured: ") +sender + "\n" + - "T: " + p.temperature + "\n" + - "H: " + p.relative_humidity + "\n"; - screen->print(lcd.c_str()); - } - DEBUG_MSG("-----------------------------------------\n"); DEBUG_MSG("EnvironmentalMeasurement: Received data from %s\n", sender); - DEBUG_MSG("EnvironmentalMeasurement->relative_humidity: %f\n", p.relative_humidity); - DEBUG_MSG("EnvironmentalMeasurement->temperature: %f\n", p.temperature); + DEBUG_MSG("EnvironmentalMeasurement->relative_humidity: %f\n", p->relative_humidity); + DEBUG_MSG("EnvironmentalMeasurement->temperature: %f\n", p->temperature); lastMeasurementPacket = packetPool.allocCopy(mp); return false; // Let others look at this message also if they want } -bool EnvironmentalMeasurementPluginRadio::sendOurEnvironmentalMeasurement(NodeNum dest, bool wantReplies) +bool EnvironmentalMeasurementPlugin::sendOurEnvironmentalMeasurement(NodeNum dest, bool wantReplies) { EnvironmentalMeasurement m; @@ -236,13 +229,13 @@ bool EnvironmentalMeasurementPluginRadio::sendOurEnvironmentalMeasurement(NodeNu DEBUG_MSG("-----------------------------------------\n"); DEBUG_MSG("EnvironmentalMeasurement: Read data\n"); - if (!dht.read(true)){ + if (!this->dht->read(true)){ sensor_read_error_count++; DEBUG_MSG("EnvironmentalMeasurement: FAILED TO READ DATA\n"); return false; } - m.relative_humidity = dht.readHumidity(); - m.temperature = dht.readTemperature(); + m.relative_humidity = this->dht->readHumidity(); + m.temperature = this->dht->readTemperature(); DEBUG_MSG("EnvironmentalMeasurement->relative_humidity: %f\n", m.relative_humidity); DEBUG_MSG("EnvironmentalMeasurement->temperature: %f\n", m.temperature); diff --git a/src/plugins/esp32/EnvironmentalMeasurementPlugin.h b/src/plugins/esp32/EnvironmentalMeasurementPlugin.h index 4e43e46ce..3123cc0f0 100644 --- a/src/plugins/esp32/EnvironmentalMeasurementPlugin.h +++ b/src/plugins/esp32/EnvironmentalMeasurementPlugin.h @@ -3,56 +3,32 @@ #include "../mesh/generated/environmental_measurement.pb.h" #include #include +#include - -class EnvironmentalMeasurementPlugin : private concurrency::OSThread -{ - bool firstTime = 1; - - public: - EnvironmentalMeasurementPlugin(); - - protected: - virtual int32_t runOnce(); -}; - -extern EnvironmentalMeasurementPlugin *environmentalMeasurementPlugin; - -/** - * EnvironmentalMeasurementPluginRadio plugin for sending/receiving environmental measurements to/from the mesh - */ -class EnvironmentalMeasurementPluginRadio : public ProtobufPlugin +class EnvironmentalMeasurementPlugin : private concurrency::OSThread, public ProtobufPlugin { public: - /** Constructor - * name is for debugging output - */ - EnvironmentalMeasurementPluginRadio() : ProtobufPlugin("EnvironmentalMeasurement", PortNum_ENVIRONMENTAL_MEASUREMENT_APP, &EnvironmentalMeasurement_msg) { + EnvironmentalMeasurementPlugin(): concurrency::OSThread("EnvironmentalMeasurementPlugin"), ProtobufPlugin("EnvironmentalMeasurement", PortNum_ENVIRONMENTAL_MEASUREMENT_APP, &EnvironmentalMeasurement_msg) { lastMeasurementPacket = nullptr; } + virtual bool wantUIFrame(); + virtual void drawFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y); + protected: + /** Called to handle a particular incoming message + @return true if you've guaranteed you've handled this message and no other handlers should be considered for it + */ + virtual bool handleReceivedProtobuf(const MeshPacket &mp, const EnvironmentalMeasurement *p); + virtual int32_t runOnce(); /** * Send our EnvironmentalMeasurement into the mesh */ bool sendOurEnvironmentalMeasurement(NodeNum dest = NODENUM_BROADCAST, bool wantReplies = false); - virtual void drawFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y); - - protected: - - /** Called to handle a particular incoming message - - @return true if you've guaranteed you've handled this message and no other handlers should be considered for it - */ - virtual bool handleReceivedProtobuf(const MeshPacket &mp, const EnvironmentalMeasurement *p); - - virtual bool wantUIFrame(); - - private: - + float CelsiusToFarenheit(float c); + bool firstTime = 1; + DHT* dht; const MeshPacket *lastMeasurementPacket; - -}; - -extern EnvironmentalMeasurementPluginRadio *environmentalMeasurementPluginRadio; \ No newline at end of file + uint32_t sensor_read_error_count = 0; +}; \ No newline at end of file From 955d03acb1859ad9108f407cfabdb01841b45223 Mon Sep 17 00:00:00 2001 From: Kevin Hester Date: Thu, 4 Mar 2021 11:28:50 +0800 Subject: [PATCH 200/258] fix symbol conflict with new nrf52 libs --- src/mesh/NodeDB.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/mesh/NodeDB.h b/src/mesh/NodeDB.h index 29c35369f..b424adcba 100644 --- a/src/mesh/NodeDB.h +++ b/src/mesh/NodeDB.h @@ -154,7 +154,7 @@ extern NodeDB nodeDB; */ // Our delay functions check for this for times that should never expire -#define DELAY_FOREVER 0xffffffff +#define NODE_DELAY_FOREVER 0xffffffff #define IF_ROUTER(routerVal, normalVal) (radioConfig.preferences.is_router ? (routerVal) : (normalVal)) @@ -168,8 +168,8 @@ PREF_GET(position_broadcast_secs, IF_ROUTER(12 * 60 * 60, 15 * 60)) PREF_GET(wait_bluetooth_secs, IF_ROUTER(1, 60)) PREF_GET(screen_on_secs, 60) -PREF_GET(mesh_sds_timeout_secs, IF_ROUTER(DELAY_FOREVER, 2 * 60 * 60)) -PREF_GET(phone_sds_timeout_sec, IF_ROUTER(DELAY_FOREVER, 2 * 60 * 60)) +PREF_GET(mesh_sds_timeout_secs, IF_ROUTER(NODE_DELAY_FOREVER, 2 * 60 * 60)) +PREF_GET(phone_sds_timeout_sec, IF_ROUTER(NODE_DELAY_FOREVER, 2 * 60 * 60)) PREF_GET(sds_secs, 365 * 24 * 60 * 60) // We default to sleeping (with bluetooth off for 5 minutes at a time). This seems to be a good tradeoff between From 56fe211466cc2cd569512bc6a940cd7e5115a3a4 Mon Sep 17 00:00:00 2001 From: Kevin Hester Date: Thu, 4 Mar 2021 11:29:55 +0800 Subject: [PATCH 201/258] 1.2.1 --- docs/software/TODO.md | 7 +++++-- version.properties | 2 +- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/docs/software/TODO.md b/docs/software/TODO.md index 5942aa438..5547110dd 100644 --- a/docs/software/TODO.md +++ b/docs/software/TODO.md @@ -29,10 +29,11 @@ You probably don't care about this section - skip to the next one. * DONE release protobufs * DONE release to developers * fix 1.1.50 android debug panel display -* add gui in android app for setting region +* warn in android app about unset regions +* use set-channel from android +* DONE add gui in android app for setting region * stress test channel download from python, sometimes it seems like we don't get all replies * investigate @mc-hamster report of heap corruption -* use set-channel from android * DONE use set-user from android * combine acks and responses in a single message if possible (do routing plugin LAST and drop ACK if someone else has already replied) * don't send packets we received from the phone BACK TOWARDS THE PHONE (possibly use fromnode 0 for packets the phone sends?) @@ -40,6 +41,8 @@ You probably don't care about this section - skip to the next one. * make python tests more exhaustive * document the relationship between want_response (indicating remote node received it) and want_ack (indicating that this message should be sent reliably - and also get acks from the first rx node and naks if it is never delivered) * stress test multi channel +* use single byte 'well known' channel names for the four default channel names (longslow etc), and for admin, gpio, etc... +* use presence of gpio channel to enable gpio ops, same for serial etc... * pick default random admin key * DONE android should stop fetching channels once we've reached our first empty channel definition (hasSettings == true) * add channel restrictions for plugins (and restrict routing plugin to the "control" channel) diff --git a/version.properties b/version.properties index c77424e6a..9d155e715 100644 --- a/version.properties +++ b/version.properties @@ -1,4 +1,4 @@ [VERSION] major = 1 minor = 2 -build = 0 +build = 1 From 2f6034b06772f3292a951d1c2b18ecd9593d8241 Mon Sep 17 00:00:00 2001 From: Kevin Hester Date: Thu, 4 Mar 2021 22:09:02 +0800 Subject: [PATCH 202/258] update todos --- docs/software/TODO.md | 31 +++++++++++++++++-------------- proto | 2 +- 2 files changed, 18 insertions(+), 15 deletions(-) diff --git a/docs/software/TODO.md b/docs/software/TODO.md index 5547110dd..b96deb3a0 100644 --- a/docs/software/TODO.md +++ b/docs/software/TODO.md @@ -21,32 +21,35 @@ You probably don't care about this section - skip to the next one. * DONE implement 'get channels' Admin plugin operation * DONE use get-channels from python * DONE use get channels & get settings from android -* use set-channel from python +* DONE use set-channel from python * DONE make settings changes from python work * DONE pthon should stop fetching channels once we've reached our first empty channel definition (hasSettings == true) * DONE add check for old devices with new API library * DONE release python api * DONE release protobufs * DONE release to developers -* fix 1.1.50 android debug panel display -* warn in android app about unset regions -* use set-channel from android -* DONE add gui in android app for setting region -* stress test channel download from python, sometimes it seems like we don't get all replies -* investigate @mc-hamster report of heap corruption -* DONE use set-user from android +* DONE fix setch-fast in python tool * combine acks and responses in a single message if possible (do routing plugin LAST and drop ACK if someone else has already replied) * don't send packets we received from the phone BACK TOWARDS THE PHONE (possibly use fromnode 0 for packets the phone sends?) -* use portuino TCP connection to debug with python API +* fix 1.1.50 android debug panel display +* DONE warn in android app about unset regions +* DONE use set-channel from android +* DONE add gui in android app for setting region +* stress test channel download from python, sometimes it seems like we don't get all replies * make python tests more exhaustive -* document the relationship between want_response (indicating remote node received it) and want_ack (indicating that this message should be sent reliably - and also get acks from the first rx node and naks if it is never delivered) -* stress test multi channel +* pick default random admin key +* exclude admin channels from URL? +* make a way to share just secondary channels via URL * use single byte 'well known' channel names for the four default channel names (longslow etc), and for admin, gpio, etc... * use presence of gpio channel to enable gpio ops, same for serial etc... -* pick default random admin key -* DONE android should stop fetching channels once we've reached our first empty channel definition (hasSettings == true) -* add channel restrictions for plugins (and restrict routing plugin to the "control" channel) * restrict gpio & serial & settings operations to the admin channel (unless local to the current node) +* add channel restrictions for plugins (and restrict routing plugin to the "control" channel) +* stress test multi channel +* investigate @mc-hamster report of heap corruption +* DONE use set-user from android +* use portuino TCP connection to debug with python API +* document the relationship between want_response (indicating remote node received it) and want_ack (indicating that this message should be sent reliably - and also get acks from the first rx node and naks if it is never delivered) +* DONE android should stop fetching channels once we've reached our first empty channel definition (hasSettings == true) * DONE warn in python api if we are too new to talk to the device code * DONE make a post warning about 1.2, telling how to stay on old android & python clients. link to this from the android dialog message and python version warning. * DONE "FIXME - move the radioconfig/user/channel READ operations into SettingsMessage as well" diff --git a/proto b/proto index 270cbdb68..ac4f53ed8 160000 --- a/proto +++ b/proto @@ -1 +1 @@ -Subproject commit 270cbdb6801761f054cb79f64b68b8a75cfb50f6 +Subproject commit ac4f53ed8c903a5bdf3d19727e96791d6be71022 From 950b32232f493d196b275fce40ea0a423d2d18b3 Mon Sep 17 00:00:00 2001 From: Kevin Hester Date: Fri, 5 Mar 2021 10:19:27 +0800 Subject: [PATCH 203/258] don't send messages the phone sent us back towards the phone --- docs/software/TODO.md | 6 +- src/graphics/Screen.cpp | 2 +- src/mesh/DSRRouter.cpp | 2 +- src/mesh/MeshPacketQueue.cpp | 2 +- src/mesh/MeshPlugin.cpp | 4 +- src/mesh/MeshService.cpp | 59 +++++++++++-------- src/mesh/MeshTypes.h | 8 ++- src/mesh/NodeDB.cpp | 10 +++- src/mesh/NodeDB.h | 1 + src/mesh/PacketHistory.cpp | 4 +- src/mesh/ReliableRouter.cpp | 10 ++-- src/mesh/ReliableRouter.h | 2 +- src/mesh/Router.cpp | 8 ++- src/plugins/ExternalNotificationPlugin.cpp | 2 +- src/plugins/NodeInfoPlugin.cpp | 2 +- src/plugins/PositionPlugin.cpp | 2 +- src/plugins/SerialPlugin.cpp | 2 +- .../esp32/EnvironmentalMeasurementPlugin.cpp | 5 +- src/plugins/esp32/RangeTestPlugin.cpp | 8 +-- src/plugins/esp32/StoreForwardPlugin.cpp | 6 +- 20 files changed, 87 insertions(+), 58 deletions(-) diff --git a/docs/software/TODO.md b/docs/software/TODO.md index b96deb3a0..dfef04277 100644 --- a/docs/software/TODO.md +++ b/docs/software/TODO.md @@ -29,13 +29,14 @@ You probably don't care about this section - skip to the next one. * DONE release protobufs * DONE release to developers * DONE fix setch-fast in python tool +* age out pendingrequests in the python API +* DONE stress test channel download from python, sometimes it seems like we don't get all replies, bug was due to simultaneous android connection * combine acks and responses in a single message if possible (do routing plugin LAST and drop ACK if someone else has already replied) -* don't send packets we received from the phone BACK TOWARDS THE PHONE (possibly use fromnode 0 for packets the phone sends?) +* DONE don't send packets we received from the phone BACK TOWARDS THE PHONE (possibly use fromnode 0 for packets the phone sends?) * fix 1.1.50 android debug panel display * DONE warn in android app about unset regions * DONE use set-channel from android * DONE add gui in android app for setting region -* stress test channel download from python, sometimes it seems like we don't get all replies * make python tests more exhaustive * pick default random admin key * exclude admin channels from URL? @@ -61,6 +62,7 @@ You probably don't care about this section - skip to the next one. * confirm we are still calling the plugins for messages inbound from the phone (or generated locally) * confirm we are still multi hop routing flood broadcasts * confirm we are still doing resends on unicast reliable packets +* add history to routed packets: https://meshtastic.discourse.group/t/packet-source-tracking/2764/2 * add support for full DSR unicast delivery * DONE move acks into routing * DONE make all subpackets different versions of data diff --git a/src/graphics/Screen.cpp b/src/graphics/Screen.cpp index d04b9960b..6e52abdde 100644 --- a/src/graphics/Screen.cpp +++ b/src/graphics/Screen.cpp @@ -229,7 +229,7 @@ static void drawTextMessageFrame(OLEDDisplay *display, OLEDDisplayUiState *state displayedNodeNum = 0; // Not currently showing a node pane MeshPacket &mp = devicestate.rx_text_message; - NodeInfo *node = nodeDB.getNode(mp.from); + NodeInfo *node = nodeDB.getNode(getFrom(&mp)); // DEBUG_MSG("drawing text message from 0x%x: %s\n", mp.from, // mp.decoded.variant.data.decoded.bytes); diff --git a/src/mesh/DSRRouter.cpp b/src/mesh/DSRRouter.cpp index 5fa6b1609..f7d8588e4 100644 --- a/src/mesh/DSRRouter.cpp +++ b/src/mesh/DSRRouter.cpp @@ -69,7 +69,7 @@ void DSRRouter::sniffReceived(const MeshPacket *p, const Routing *c) // ignore rebroadcasts. // this will also add records for any ACKs we receive for our messages if (p->to != NODENUM_BROADCAST || p->hop_limit != HOP_RELIABLE) { - addRoute(p->from, p->from, 0); // We are adjacent with zero hops + addRoute(getFrom(p), getFrom(p), 0); // We are adjacent with zero hops } if (c) diff --git a/src/mesh/MeshPacketQueue.cpp b/src/mesh/MeshPacketQueue.cpp index 56db3feb3..6c964e509 100644 --- a/src/mesh/MeshPacketQueue.cpp +++ b/src/mesh/MeshPacketQueue.cpp @@ -71,7 +71,7 @@ static PacketId findId; static bool isMyPacket(MeshPacket *p) { - return p->id == findId && p->from == findFrom; + return p->id == findId && getFrom(p) == findFrom; } /** Attempt to find and remove a packet from this queue. Returns true the packet which was removed from the queue */ diff --git a/src/mesh/MeshPlugin.cpp b/src/mesh/MeshPlugin.cpp index 6fd3c72b8..34aaa2360 100644 --- a/src/mesh/MeshPlugin.cpp +++ b/src/mesh/MeshPlugin.cpp @@ -52,7 +52,7 @@ void MeshPlugin::callPlugins(const MeshPacket &mp) // NOTE: we send a reply *even if the (non broadcast) request was from us* which is unfortunate but necessary because currently when the phone // sends things, it sends things using the local node ID as the from address. A better solution (FIXME) would be to let phones // have their own distinct addresses and we 'route' to them like any other node. - if (mp.decoded.want_response && toUs && (mp.from != ourNodeNum || mp.to == ourNodeNum)) { + if (mp.decoded.want_response && toUs && (getFrom(&mp) != ourNodeNum || mp.to == ourNodeNum)) { pi.sendResponse(mp); DEBUG_MSG("Plugin %s sent a response\n", pi.name); } @@ -94,7 +94,7 @@ void MeshPlugin::sendResponse(const MeshPacket &req) { */ void setReplyTo(MeshPacket *p, const MeshPacket &to) { assert(p->which_payloadVariant == MeshPacket_decoded_tag); // Should already be set by now - p->to = to.from; + p->to = getFrom(&to); p->want_ack = to.want_ack; p->decoded.request_id = to.id; } diff --git a/src/mesh/MeshService.cpp b/src/mesh/MeshService.cpp index 753d942df..f21742eaa 100644 --- a/src/mesh/MeshService.cpp +++ b/src/mesh/MeshService.cpp @@ -13,8 +13,8 @@ #include "RTC.h" #include "main.h" #include "mesh-pb-constants.h" -#include "plugins/PositionPlugin.h" #include "plugins/NodeInfoPlugin.h" +#include "plugins/PositionPlugin.h" #include "power.h" /* @@ -51,8 +51,6 @@ MeshService service; #include "Router.h" - - MeshService::MeshService() : toPhoneQueue(MAX_RX_TOPHONE) { // assert(MAX_RX_TOPHONE == 32); // FIXME, delete this, just checking my clever macro @@ -67,25 +65,29 @@ void MeshService::init() gpsObserver.observe(&gps->newStatus); } - int MeshService::handleFromRadio(const MeshPacket *mp) { powerFSM.trigger(EVENT_RECEIVED_PACKET); // Possibly keep the node from sleeping - printPacket("Forwarding to phone", mp); - nodeDB.updateFrom(*mp); // update our DB state based off sniffing every RX packet from the radio + if (mp->from != 0) { + printPacket("Forwarding to phone", mp); + nodeDB.updateFrom(*mp); // update our DB state based off sniffing every RX packet from the radio - fromNum++; + fromNum++; - if (toPhoneQueue.numFree() == 0) { - DEBUG_MSG("NOTE: tophone queue is full, discarding oldest\n"); - MeshPacket *d = toPhoneQueue.dequeuePtr(0); - if (d) - releaseToPool(d); + if (toPhoneQueue.numFree() == 0) { + DEBUG_MSG("NOTE: tophone queue is full, discarding oldest\n"); + MeshPacket *d = toPhoneQueue.dequeuePtr(0); + if (d) + releaseToPool(d); + } + + MeshPacket *copied = packetPool.allocCopy(*mp); + assert(toPhoneQueue.enqueue(copied, 0)); // FIXME, instead of failing for full queue, delete the oldest mssages + } + else { + DEBUG_MSG("Packet originally from phone, no need to send back that way...\n"); } - - MeshPacket *copied = packetPool.allocCopy(*mp); - assert(toPhoneQueue.enqueue(copied, 0)); // FIXME, instead of failing for full queue, delete the oldest mssages return 0; } @@ -128,8 +130,12 @@ void MeshService::reloadOwner() */ void MeshService::handleToRadio(MeshPacket &p) { - if (p.from == 0) // If the phone didn't set a sending node ID, use ours - p.from = nodeDB.getNodeNum(); + if (p.from != 0) { // We don't let phones assign nodenums to their sent messages + DEBUG_MSG("Warning: phone tried to pick a nodenum, we don't allow that.\n"); + p.from = 0; + } else { + // p.from = nodeDB.getNodeNum(); + } if (p.id == 0) p.id = generatePacketId(); // If the phone didn't supply one, then pick one @@ -151,7 +157,8 @@ void MeshService::handleToRadio(MeshPacket &p) } /** Attempt to cancel a previously sent packet from this _local_ node. Returns true if a packet was found we could cancel */ -bool MeshService::cancelSending(PacketId id) { +bool MeshService::cancelSending(PacketId id) +{ return router->cancelSending(nodeDB.getNodeNum(), id); } @@ -176,21 +183,22 @@ void MeshService::sendNetworkPing(NodeNum dest, bool wantReplies) nodeInfoPlugin->sendOurNodeInfo(dest, wantReplies); } - -NodeInfo *MeshService::refreshMyNodeInfo() { +NodeInfo *MeshService::refreshMyNodeInfo() +{ NodeInfo *node = nodeDB.getNode(nodeDB.getNodeNum()); assert(node); // We might not have a position yet for our local node, in that case, at least try to send the time - if(!node->has_position) { + if (!node->has_position) { memset(&node->position, 0, sizeof(node->position)); node->has_position = true; } - + Position &position = node->position; // Update our local node info with our position (even if we don't decide to update anyone else) - position.time = getValidTime(RTCQualityFromNet); // This nodedb timestamp might be stale, so update it if our clock is kinda valid + position.time = + getValidTime(RTCQualityFromNet); // This nodedb timestamp might be stale, so update it if our clock is kinda valid position.battery_level = powerStatus->getBatteryChargePercent(); updateBatteryLevel(position.battery_level); @@ -209,11 +217,10 @@ int MeshService::onGPSChanged(const meshtastic::GPSStatus *unused) pos.altitude = gps->altitude; pos.latitude_i = gps->latitude; pos.longitude_i = gps->longitude; - } - else { + } else { // The GPS has lost lock, if we are fixed position we should just keep using // the old position - if(radioConfig.preferences.fixed_position) { + if (radioConfig.preferences.fixed_position) { DEBUG_MSG("WARNING: Using fixed position\n"); } else { // throw away old position diff --git a/src/mesh/MeshTypes.h b/src/mesh/MeshTypes.h index 06f2bf480..e7e6265a4 100644 --- a/src/mesh/MeshTypes.h +++ b/src/mesh/MeshTypes.h @@ -32,4 +32,10 @@ typedef uint32_t PacketId; // A packet sequence number typedef int ErrorCode; /// Alloc and free packets to our global, ISR safe pool -extern Allocator &packetPool; \ No newline at end of file +extern Allocator &packetPool; + +/** + * Most (but not always) of the time we want to treat packets 'from' the local phone (where from == 0), as if they originated on the local node. + * If from is zero this function returns our node number instead + */ +NodeNum getFrom(const MeshPacket *p); \ No newline at end of file diff --git a/src/mesh/NodeDB.cpp b/src/mesh/NodeDB.cpp index 22c1ccb6f..166e159f2 100644 --- a/src/mesh/NodeDB.cpp +++ b/src/mesh/NodeDB.cpp @@ -66,6 +66,14 @@ NodeNum displayedNodeNum; NodeDB::NodeDB() : nodes(devicestate.node_db), numNodes(&devicestate.node_db_count) {} +/** + * Most (but not always) of the time we want to treat packets 'from' the local phone (where from == 0), as if they originated on the local node. + * If from is zero this function returns our node number instead + */ +NodeNum getFrom(const MeshPacket *p) { + return (p->from == 0) ? nodeDB.getNodeNum() : p->from; +} + bool NodeDB::resetRadioConfig() { bool didFactoryReset = false; @@ -406,7 +414,7 @@ void NodeDB::updateFrom(const MeshPacket &mp) if (mp.which_payloadVariant == MeshPacket_decoded_tag) { DEBUG_MSG("Update DB node 0x%x, rx_time=%u\n", mp.from, mp.rx_time); - NodeInfo *info = getOrCreateNode(mp.from); + NodeInfo *info = getOrCreateNode(getFrom(&mp)); if (mp.rx_time) { // if the packet has a valid timestamp use it to update our last_seen info->has_position = true; // at least the time is valid diff --git a/src/mesh/NodeDB.h b/src/mesh/NodeDB.h index b424adcba..e5f1b6564 100644 --- a/src/mesh/NodeDB.h +++ b/src/mesh/NodeDB.h @@ -183,3 +183,4 @@ PREF_GET(min_wake_secs, 10) * might have changed is incremented. Allows others to detect they might now be on a new channel. */ extern uint32_t radioGeneration; + diff --git a/src/mesh/PacketHistory.cpp b/src/mesh/PacketHistory.cpp index 3d1884ace..19ce41bc8 100644 --- a/src/mesh/PacketHistory.cpp +++ b/src/mesh/PacketHistory.cpp @@ -26,7 +26,7 @@ bool PacketHistory::wasSeenRecently(const MeshPacket *p, bool withUpdate) // DEBUG_MSG("Deleting old broadcast record %d\n", i); recentPackets.erase(recentPackets.begin() + i); // delete old record } else { - if (r.id == p->id && r.sender == p->from) { + if (r.id == p->id && r.sender == getFrom(p)) { DEBUG_MSG("Found existing packet record for fr=0x%x,to=0x%x,id=%d\n", p->from, p->to, p->id); // Update the time on this record to now @@ -43,7 +43,7 @@ bool PacketHistory::wasSeenRecently(const MeshPacket *p, bool withUpdate) if (withUpdate) { PacketRecord r; r.id = p->id; - r.sender = p->from; + r.sender = getFrom(p); r.rxTimeMsec = now; recentPackets.push_back(r); printPacket("Adding packet record", p); diff --git a/src/mesh/ReliableRouter.cpp b/src/mesh/ReliableRouter.cpp index da743c389..80ee97701 100644 --- a/src/mesh/ReliableRouter.cpp +++ b/src/mesh/ReliableRouter.cpp @@ -26,15 +26,15 @@ ErrorCode ReliableRouter::send(MeshPacket *p) bool ReliableRouter::shouldFilterReceived(const MeshPacket *p) { - if (p->to == NODENUM_BROADCAST && p->from == getNodeNum()) { + if (p->to == NODENUM_BROADCAST && getFrom(p) == getNodeNum()) { printPacket("Rx someone rebroadcasting for us", p); // We are seeing someone rebroadcast one of our broadcast attempts. // If this is the first time we saw this, cancel any retransmissions we have queued up and generate an internal ack for // the original sending process. - if (stopRetransmission(p->from, p->id)) { + if (stopRetransmission(getFrom(p), p->id)) { DEBUG_MSG("Someone is retransmitting for us, generate implicit ack\n"); - sendAckNak(Routing_Error_NONE, p->from, p->id); + sendAckNak(Routing_Error_NONE, getFrom(p), p->id); } } @@ -60,7 +60,7 @@ void ReliableRouter::sniffReceived(const MeshPacket *p, const Routing *c) if (p->to == ourNode) { // ignore ack/nak/want_ack packets that are not address to us (we only handle 0 hop reliability // - not DSR routing) if (p->want_ack) { - sendAckNak(Routing_Error_NONE, p->from, p->id); + sendAckNak(Routing_Error_NONE, getFrom(p), p->id); } // If the payload is valid, look for ack/nak @@ -131,7 +131,7 @@ PendingPacket *ReliableRouter::startRetransmission(MeshPacket *p) auto rec = PendingPacket(p); setNextTx(&rec); - stopRetransmission(p->from, p->id); + stopRetransmission(getFrom(p), p->id); pending[id] = rec; return &pending[id]; diff --git a/src/mesh/ReliableRouter.h b/src/mesh/ReliableRouter.h index e6a71f423..fefc85cb3 100644 --- a/src/mesh/ReliableRouter.h +++ b/src/mesh/ReliableRouter.h @@ -15,7 +15,7 @@ struct GlobalPacketId { GlobalPacketId(const MeshPacket *p) { - node = p->from; + node = getFrom(p); id = p->id; } diff --git a/src/mesh/Router.cpp b/src/mesh/Router.cpp index a6afe952e..b4bb149dd 100644 --- a/src/mesh/Router.cpp +++ b/src/mesh/Router.cpp @@ -111,7 +111,7 @@ void Router::sendAckNak(Routing_Error err, NodeNum to, PacketId idFrom) void Router::abortSendAndNak(Routing_Error err, MeshPacket *p) { DEBUG_MSG("Error=%d, returning NAK and dropping packet.\n", err); - sendAckNak(Routing_Error_NO_INTERFACE, p->from, p->id); + sendAckNak(Routing_Error_NO_INTERFACE, getFrom(p), p->id); packetPool.release(p); } @@ -155,6 +155,10 @@ ErrorCode Router::send(MeshPacket *p) if (p->to == NODENUM_BROADCAST) p->want_ack = false; + // Up until this point we might have been using 0 for the from address (if it started with the phone), but when we send over + // the lora we need to make sure we have replaced it with our local address + p->from = getFrom(p); + // If the packet hasn't yet been encrypted, do so now (it might already be encrypted if we are just forwarding it) assert(p->which_payloadVariant == MeshPacket_encrypted_tag || @@ -273,7 +277,7 @@ void Router::handleReceived(MeshPacket *p) void Router::perhapsHandleReceived(MeshPacket *p) { assert(radioConfig.has_preferences); - bool ignore = is_in_repeated(radioConfig.preferences.ignore_incoming, p->from); + bool ignore = is_in_repeated(radioConfig.preferences.ignore_incoming, getFrom(p)); if (ignore) DEBUG_MSG("Ignoring incoming message, 0x%x is in our ignore list\n", p->from); diff --git a/src/plugins/ExternalNotificationPlugin.cpp b/src/plugins/ExternalNotificationPlugin.cpp index 754259828..42865f3cc 100644 --- a/src/plugins/ExternalNotificationPlugin.cpp +++ b/src/plugins/ExternalNotificationPlugin.cpp @@ -147,7 +147,7 @@ bool ExternalNotificationPluginRadio::handleReceived(const MeshPacket &mp) auto &p = mp.decoded; - if (mp.from != nodeDB.getNodeNum()) { + if (getFrom(&mp) != nodeDB.getNodeNum()) { // TODO: This may be a problem if messages are sent in unicide, but I'm not sure if it will. // Need to know if and how this could be a problem. diff --git a/src/plugins/NodeInfoPlugin.cpp b/src/plugins/NodeInfoPlugin.cpp index 2524ffa58..82c16cbdc 100644 --- a/src/plugins/NodeInfoPlugin.cpp +++ b/src/plugins/NodeInfoPlugin.cpp @@ -12,7 +12,7 @@ bool NodeInfoPlugin::handleReceivedProtobuf(const MeshPacket &mp, const User *pp { auto p = *pptr; - nodeDB.updateUser(mp.from, p); + nodeDB.updateUser(getFrom(&mp), p); bool wasBroadcast = mp.to == NODENUM_BROADCAST; diff --git a/src/plugins/PositionPlugin.cpp b/src/plugins/PositionPlugin.cpp index 251605865..b6f76ad72 100644 --- a/src/plugins/PositionPlugin.cpp +++ b/src/plugins/PositionPlugin.cpp @@ -30,7 +30,7 @@ bool PositionPlugin::handleReceivedProtobuf(const MeshPacket &mp, const Position perhapsSetRTC(RTCQualityFromNet, &tv); } - nodeDB.updatePosition(mp.from, p); + nodeDB.updatePosition(getFrom(&mp), p); return false; // Let others look at this message also if they want } diff --git a/src/plugins/SerialPlugin.cpp b/src/plugins/SerialPlugin.cpp index 060f05ba1..c93bf8521 100644 --- a/src/plugins/SerialPlugin.cpp +++ b/src/plugins/SerialPlugin.cpp @@ -160,7 +160,7 @@ bool SerialPluginRadio::handleReceived(const MeshPacket &mp) // DEBUG_MSG("Received text msg self=0x%0x, from=0x%0x, to=0x%0x, id=%d, msg=%.*s\n", // nodeDB.getNodeNum(), mp.from, mp.to, mp.id, p.payload.size, p.payload.bytes); - if (mp.from == nodeDB.getNodeNum()) { + if (getFrom(&mp) == nodeDB.getNodeNum()) { /* * If radioConfig.preferences.serialplugin_echo is true, then echo the packets that are sent out back to the TX diff --git a/src/plugins/esp32/EnvironmentalMeasurementPlugin.cpp b/src/plugins/esp32/EnvironmentalMeasurementPlugin.cpp index 4ade032be..69482dbc7 100644 --- a/src/plugins/esp32/EnvironmentalMeasurementPlugin.cpp +++ b/src/plugins/esp32/EnvironmentalMeasurementPlugin.cpp @@ -137,8 +137,9 @@ bool EnvironmentalMeasurementPlugin::wantUIFrame() { String GetSenderName(const MeshPacket &mp) { String sender; - if (nodeDB.getNode(mp.from)){ - sender = nodeDB.getNode(mp.from)->user.short_name; + auto node = nodeDB.getNode(getFrom(&mp)); + if (node){ + sender = node->user.short_name; } else { sender = "UNK"; diff --git a/src/plugins/esp32/RangeTestPlugin.cpp b/src/plugins/esp32/RangeTestPlugin.cpp index 227deba4d..2332b687a 100644 --- a/src/plugins/esp32/RangeTestPlugin.cpp +++ b/src/plugins/esp32/RangeTestPlugin.cpp @@ -133,7 +133,7 @@ bool RangeTestPluginRadio::handleReceived(const MeshPacket &mp) // DEBUG_MSG("Received text msg self=0x%0x, from=0x%0x, to=0x%0x, id=%d, msg=%.*s\n", // nodeDB.getNodeNum(), mp.from, mp.to, mp.id, p.payload.size, p.payload.bytes); - if (mp.from != nodeDB.getNodeNum()) { + if (getFrom(&mp) != nodeDB.getNodeNum()) { // DEBUG_MSG("* * Message came from the mesh\n"); // Serial2.println("* * Message came from the mesh"); @@ -144,7 +144,7 @@ bool RangeTestPluginRadio::handleReceived(const MeshPacket &mp) */ - NodeInfo *n = nodeDB.getNode(mp.from); + NodeInfo *n = nodeDB.getNode(getFrom(&mp)); if (radioConfig.preferences.range_test_plugin_save) { appendFile(mp); @@ -209,7 +209,7 @@ bool RangeTestPluginRadio::appendFile(const MeshPacket &mp) { auto &p = mp.decoded; - NodeInfo *n = nodeDB.getNode(mp.from); + NodeInfo *n = nodeDB.getNode(getFrom(&mp)); /* DEBUG_MSG("-----------------------------------------\n"); DEBUG_MSG("p.payload.bytes \"%s\"\n", p.payload.bytes); @@ -290,7 +290,7 @@ bool RangeTestPluginRadio::appendFile(const MeshPacket &mp) fileToAppend.printf("??:??:??,"); // Time } - fileToAppend.printf("%d,", mp.from); // From + fileToAppend.printf("%d,", getFrom(&mp)); // From fileToAppend.printf("%s,", n->user.long_name); // Long Name fileToAppend.printf("%f,", n->position.latitude_i * 1e-7); // Sender Lat fileToAppend.printf("%f,", n->position.longitude_i * 1e-7); // Sender Long diff --git a/src/plugins/esp32/StoreForwardPlugin.cpp b/src/plugins/esp32/StoreForwardPlugin.cpp index d55e076bb..5340c48ae 100644 --- a/src/plugins/esp32/StoreForwardPlugin.cpp +++ b/src/plugins/esp32/StoreForwardPlugin.cpp @@ -240,12 +240,12 @@ bool StoreForwardPluginRadio::handleReceived(const MeshPacket &mp) #ifndef NO_ESP32 if (radioConfig.preferences.store_forward_plugin_enabled) { - if (mp.from != nodeDB.getNodeNum()) { + if (getFrom(&mp) != nodeDB.getNodeNum()) { // DEBUG_MSG("Store & Forward Plugin -- Print Start ---------- ---------- ---------- ---------- ----------\n\n\n"); // DEBUG_MSG("%s (id=0x%08x Fr0x%02x To0x%02x, WantAck%d, HopLim%d", prefix, p->id, p->from & 0xff, p->to & 0xff, // p->want_ack, p->hop_limit); printPacket("----- PACKET FROM RADIO -----", &mp); - uint32_t sawTime = storeForwardPlugin->sawNode(mp.from & 0xffffffff); + uint32_t sawTime = storeForwardPlugin->sawNode(getFrom(&mp) & 0xffffffff); DEBUG_MSG("We last saw this node (%u), %u sec ago\n", mp.from & 0xffffffff, (millis() - sawTime) / 1000); if (mp.decoded.portnum == PortNum_UNKNOWN_APP) { @@ -283,7 +283,7 @@ bool StoreForwardPluginRadio::handleReceived(const MeshPacket &mp) if ((millis() - sawTime) > STOREFORWARD_SEND_HISTORY_SHORT) { // Node has been away for a while. - storeForwardPlugin->historySend(sawTime, mp.from); + storeForwardPlugin->historySend(sawTime, getFrom(&mp)); } } From 0c0c0babba9d415f481cb2b46a274158e9c447f0 Mon Sep 17 00:00:00 2001 From: Kevin Hester Date: Fri, 5 Mar 2021 11:44:45 +0800 Subject: [PATCH 204/258] combine acks works --- docs/software/TODO.md | 2 +- src/mesh/FloodingRouter.cpp | 2 +- src/mesh/MeshPlugin.cpp | 64 +++++++++++++++++++++-------------- src/mesh/MeshPlugin.h | 7 ++++ src/mesh/MeshService.cpp | 27 ++++++--------- src/mesh/PhoneAPI.cpp | 1 + src/mesh/ProtobufPlugin.h | 3 +- src/mesh/ReliableRouter.cpp | 38 ++++++++++++--------- src/mesh/Router.cpp | 1 + src/plugins/Plugins.cpp | 4 ++- src/plugins/RoutingPlugin.cpp | 5 +-- 11 files changed, 91 insertions(+), 63 deletions(-) diff --git a/docs/software/TODO.md b/docs/software/TODO.md index dfef04277..622a95af3 100644 --- a/docs/software/TODO.md +++ b/docs/software/TODO.md @@ -31,7 +31,7 @@ You probably don't care about this section - skip to the next one. * DONE fix setch-fast in python tool * age out pendingrequests in the python API * DONE stress test channel download from python, sometimes it seems like we don't get all replies, bug was due to simultaneous android connection -* combine acks and responses in a single message if possible (do routing plugin LAST and drop ACK if someone else has already replied) +* DONE combine acks and responses in a single message if possible (do routing plugin LAST and drop ACK if someone else has already replied) * DONE don't send packets we received from the phone BACK TOWARDS THE PHONE (possibly use fromnode 0 for packets the phone sends?) * fix 1.1.50 android debug panel display * DONE warn in android app about unset regions diff --git a/src/mesh/FloodingRouter.cpp b/src/mesh/FloodingRouter.cpp index 049d038c7..491501e91 100644 --- a/src/mesh/FloodingRouter.cpp +++ b/src/mesh/FloodingRouter.cpp @@ -31,7 +31,7 @@ void FloodingRouter::sniffReceived(const MeshPacket *p, const Routing *c) { // If a broadcast, possibly _also_ send copies out into the mesh. // (FIXME, do something smarter than naive flooding here) - if (p->to == NODENUM_BROADCAST && p->hop_limit > 0 && p->from != getNodeNum()) { + if (p->to == NODENUM_BROADCAST && p->hop_limit > 0 && getFrom(p) != getNodeNum()) { if (p->id != 0) { MeshPacket *tosend = packetPool.allocCopy(*p); // keep a copy because we will be sending it diff --git a/src/mesh/MeshPlugin.cpp b/src/mesh/MeshPlugin.cpp index 34aaa2360..562f31c73 100644 --- a/src/mesh/MeshPlugin.cpp +++ b/src/mesh/MeshPlugin.cpp @@ -1,23 +1,28 @@ #include "MeshPlugin.h" -#include "NodeDB.h" #include "MeshService.h" +#include "NodeDB.h" #include std::vector *MeshPlugin::plugins; const MeshPacket *MeshPlugin::currentRequest; +/** + * If any of the current chain of plugins has already sent a reply, it will be here. This is useful to allow + * the RoutingPlugin to avoid sending redundant acks + */ + MeshPacket *MeshPlugin::currentReply; + MeshPlugin::MeshPlugin(const char *_name) : name(_name) { // Can't trust static initalizer order, so we check each time - if(!plugins) + if (!plugins) plugins = new std::vector(); plugins->push_back(this); } -void MeshPlugin::setup() { -} +void MeshPlugin::setup() {} MeshPlugin::~MeshPlugin() { @@ -31,6 +36,8 @@ void MeshPlugin::callPlugins(const MeshPacket &mp) assert(mp.which_payloadVariant == MeshPacket_decoded_tag); // I think we are guarnteed the packet is decoded by this point? + currentReply = NULL; // No reply yet + // Was this message directed to us specifically? Will be false if we are sniffing someone elses packets auto ourNodeNum = nodeDB.getNodeNum(); bool toUs = mp.to == NODENUM_BROADCAST || mp.to == ourNodeNum; @@ -48,15 +55,16 @@ void MeshPlugin::callPlugins(const MeshPacket &mp) bool handled = pi.handleReceived(mp); // Possibly send replies (but only if the message was directed to us specifically, i.e. not for promiscious sniffing) + // also: we only let the one plugin send a reply, once that happens, remaining plugins are not considered - // NOTE: we send a reply *even if the (non broadcast) request was from us* which is unfortunate but necessary because currently when the phone - // sends things, it sends things using the local node ID as the from address. A better solution (FIXME) would be to let phones - // have their own distinct addresses and we 'route' to them like any other node. - if (mp.decoded.want_response && toUs && (getFrom(&mp) != ourNodeNum || mp.to == ourNodeNum)) { + // NOTE: we send a reply *even if the (non broadcast) request was from us* which is unfortunate but necessary because + // currently when the phone sends things, it sends things using the local node ID as the from address. A better + // solution (FIXME) would be to let phones have their own distinct addresses and we 'route' to them like any other + // node. + if (mp.decoded.want_response && toUs && (getFrom(&mp) != ourNodeNum || mp.to == ourNodeNum) && !currentReply) { pi.sendResponse(mp); DEBUG_MSG("Plugin %s sent a response\n", pi.name); - } - else { + } else { DEBUG_MSG("Plugin %s considered\n", pi.name); } if (handled) { @@ -64,11 +72,17 @@ void MeshPlugin::callPlugins(const MeshPacket &mp) break; } } - + pi.currentRequest = NULL; } - if(!pluginFound) + if(currentReply) { + DEBUG_MSG("Sending response\n"); + service.sendToMesh(currentReply); + currentReply = NULL; + } + + if (!pluginFound) DEBUG_MSG("No plugins interested in portnum=%d\n", mp.decoded.portnum); } @@ -76,39 +90,39 @@ void MeshPlugin::callPlugins(const MeshPacket &mp) * so that subclasses can (optionally) send a response back to the original sender. Implementing this method * is optional */ -void MeshPlugin::sendResponse(const MeshPacket &req) { +void MeshPlugin::sendResponse(const MeshPacket &req) +{ auto r = allocReply(); - if(r) { - DEBUG_MSG("Sending response\n"); + if (r) { setReplyTo(r, req); - service.sendToMesh(r); - } - else { + currentReply = r; + } else { // Ignore - this is now expected behavior for routing plugin (because it ignores some replies) // DEBUG_MSG("WARNING: Client requested response but this plugin did not provide\n"); } } -/** set the destination and packet parameters of packet p intended as a reply to a particular "to" packet +/** set the destination and packet parameters of packet p intended as a reply to a particular "to" packet * This ensures that if the request packet was sent reliably, the reply is sent that way as well. -*/ -void setReplyTo(MeshPacket *p, const MeshPacket &to) { + */ +void setReplyTo(MeshPacket *p, const MeshPacket &to) +{ assert(p->which_payloadVariant == MeshPacket_decoded_tag); // Should already be set by now p->to = getFrom(&to); p->want_ack = to.want_ack; p->decoded.request_id = to.id; } -std::vector MeshPlugin::GetMeshPluginsWithUIFrames() { +std::vector MeshPlugin::GetMeshPluginsWithUIFrames() +{ - std::vector pluginsWithUIFrames; + std::vector pluginsWithUIFrames; for (auto i = plugins->begin(); i != plugins->end(); ++i) { auto &pi = **i; - if ( pi.wantUIFrame()) { + if (pi.wantUIFrame()) { DEBUG_MSG("Plugin wants a UI Frame\n"); pluginsWithUIFrames.push_back(&pi); } } return pluginsWithUIFrames; - } diff --git a/src/mesh/MeshPlugin.h b/src/mesh/MeshPlugin.h index 7220a198b..7234b6b0a 100644 --- a/src/mesh/MeshPlugin.h +++ b/src/mesh/MeshPlugin.h @@ -82,6 +82,13 @@ class MeshPlugin private: + /** + * If any of the current chain of plugins has already sent a reply, it will be here. This is useful to allow + * the RoutingPlugin to avoid sending redundant acks + */ + static MeshPacket *currentReply; + friend class ReliableRouter; + /** Messages can be received that have the want_response bit set. If set, this callback will be invoked * so that subclasses can (optionally) send a response back to the original sender. This method calls allocReply() * to generate the reply message, and if !NULL that message will be delivered to whoever sent req diff --git a/src/mesh/MeshService.cpp b/src/mesh/MeshService.cpp index f21742eaa..4dcc17859 100644 --- a/src/mesh/MeshService.cpp +++ b/src/mesh/MeshService.cpp @@ -69,26 +69,21 @@ int MeshService::handleFromRadio(const MeshPacket *mp) { powerFSM.trigger(EVENT_RECEIVED_PACKET); // Possibly keep the node from sleeping - if (mp->from != 0) { - printPacket("Forwarding to phone", mp); - nodeDB.updateFrom(*mp); // update our DB state based off sniffing every RX packet from the radio + printPacket("Forwarding to phone", mp); + nodeDB.updateFrom(*mp); // update our DB state based off sniffing every RX packet from the radio - fromNum++; + fromNum++; - if (toPhoneQueue.numFree() == 0) { - DEBUG_MSG("NOTE: tophone queue is full, discarding oldest\n"); - MeshPacket *d = toPhoneQueue.dequeuePtr(0); - if (d) - releaseToPool(d); - } - - MeshPacket *copied = packetPool.allocCopy(*mp); - assert(toPhoneQueue.enqueue(copied, 0)); // FIXME, instead of failing for full queue, delete the oldest mssages - } - else { - DEBUG_MSG("Packet originally from phone, no need to send back that way...\n"); + if (toPhoneQueue.numFree() == 0) { + DEBUG_MSG("NOTE: tophone queue is full, discarding oldest\n"); + MeshPacket *d = toPhoneQueue.dequeuePtr(0); + if (d) + releaseToPool(d); } + MeshPacket *copied = packetPool.allocCopy(*mp); + assert(toPhoneQueue.enqueue(copied, 0)); // FIXME, instead of failing for full queue, delete the oldest mssages + return 0; } diff --git a/src/mesh/PhoneAPI.cpp b/src/mesh/PhoneAPI.cpp index a7797c255..5a7666b2d 100644 --- a/src/mesh/PhoneAPI.cpp +++ b/src/mesh/PhoneAPI.cpp @@ -59,6 +59,7 @@ void PhoneAPI::handleToRadio(const uint8_t *buf, size_t bufLength) } // return (lastContactMsec != 0) && + memset(&toRadioScratch, 0, sizeof(toRadioScratch)); if (pb_decode_from_bytes(buf, bufLength, ToRadio_fields, &toRadioScratch)) { switch (toRadioScratch.which_payloadVariant) { case ToRadio_packet_tag: { diff --git a/src/mesh/ProtobufPlugin.h b/src/mesh/ProtobufPlugin.h index c68885df2..30874b24b 100644 --- a/src/mesh/ProtobufPlugin.h +++ b/src/mesh/ProtobufPlugin.h @@ -58,11 +58,12 @@ template class ProtobufPlugin : protected SinglePortPlugin // it would be better to update even if the message was destined to others. auto &p = mp.decoded; - DEBUG_MSG("Received %s from=0x%0x, id=0x%x, payloadlen=%d\n", name, mp.from, mp.id, p.payload.size); + DEBUG_MSG("Received %s from=0x%0x, id=0x%x, portnum=%d, payloadlen=%d\n", name, mp.from, mp.id, p.portnum, p.payload.size); T scratch; T *decoded = NULL; if(mp.decoded.portnum == ourPortNum) { + memset(&scratch, 0, sizeof(scratch)); if (pb_decode_from_bytes(p.payload.bytes, p.payload.size, fields, &scratch)) decoded = &scratch; else diff --git a/src/mesh/ReliableRouter.cpp b/src/mesh/ReliableRouter.cpp index 80ee97701..eb22117fd 100644 --- a/src/mesh/ReliableRouter.cpp +++ b/src/mesh/ReliableRouter.cpp @@ -2,6 +2,7 @@ #include "MeshTypes.h" #include "configuration.h" #include "mesh-pb-constants.h" +#include "MeshPlugin.h" // ReliableRouter::ReliableRouter() {} @@ -26,7 +27,8 @@ ErrorCode ReliableRouter::send(MeshPacket *p) bool ReliableRouter::shouldFilterReceived(const MeshPacket *p) { - if (p->to == NODENUM_BROADCAST && getFrom(p) == getNodeNum()) { + // Note: do not use getFrom() here, because we want to ignore messages sent from phone + if (p->to == NODENUM_BROADCAST && p->from == getNodeNum()) { printPacket("Rx someone rebroadcasting for us", p); // We are seeing someone rebroadcast one of our broadcast attempts. @@ -34,7 +36,8 @@ bool ReliableRouter::shouldFilterReceived(const MeshPacket *p) // the original sending process. if (stopRetransmission(getFrom(p), p->id)) { DEBUG_MSG("Someone is retransmitting for us, generate implicit ack\n"); - sendAckNak(Routing_Error_NONE, getFrom(p), p->id); + if(p->want_ack) + sendAckNak(Routing_Error_NONE, getFrom(p), p->id); } } @@ -60,23 +63,26 @@ void ReliableRouter::sniffReceived(const MeshPacket *p, const Routing *c) if (p->to == ourNode) { // ignore ack/nak/want_ack packets that are not address to us (we only handle 0 hop reliability // - not DSR routing) if (p->want_ack) { - sendAckNak(Routing_Error_NONE, getFrom(p), p->id); + if(MeshPlugin::currentReply) + DEBUG_MSG("Someone else has replied to this message, no need for a 2nd ack"); + else + sendAckNak(Routing_Error_NONE, getFrom(p), p->id); } - // If the payload is valid, look for ack/nak - if (c) { - PacketId ackId = c->error_reason == Routing_Error_NONE ? p->decoded.request_id : 0; - PacketId nakId = c->error_reason != Routing_Error_NONE ? p->decoded.request_id : 0; + // We consider an ack to be either a !routing packet with a request ID or a routing packet with !error + PacketId ackId = ((c && c->error_reason == Routing_Error_NONE) || !c) ? p->decoded.request_id : 0; - // 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=%d, stopping retransmissions\n", ackId); - stopRetransmission(p->to, ackId); - } else { - DEBUG_MSG("Received a nak=%d, stopping retransmissions\n", nakId); - stopRetransmission(p->to, nakId); - } + // A nak is a routing packt that has an error code + PacketId nakId = (c && c->error_reason != Routing_Error_NONE) ? p->decoded.request_id : 0; + + // 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); + stopRetransmission(p->to, ackId); + } else { + DEBUG_MSG("Received a nak for 0x%x, stopping retransmissions\n", nakId); + stopRetransmission(p->to, nakId); } } } diff --git a/src/mesh/Router.cpp b/src/mesh/Router.cpp index b4bb149dd..17f6c50f2 100644 --- a/src/mesh/Router.cpp +++ b/src/mesh/Router.cpp @@ -231,6 +231,7 @@ bool Router::perhapsDecode(MeshPacket *p) crypto->decrypt(p->from, p->id, p->encrypted.size, bytes); // Take those raw bytes and convert them back into a well structured protobuf we can understand + memset(p->decoded, 0, sizeof(p->decoded)); if (!pb_decode_from_bytes(bytes, p->encrypted.size, Data_fields, &p->decoded)) { DEBUG_MSG("Invalid protobufs in received mesh packet (bad psk?!\n"); } else { diff --git a/src/plugins/Plugins.cpp b/src/plugins/Plugins.cpp index 65f1f5f03..ca4cb52f4 100644 --- a/src/plugins/Plugins.cpp +++ b/src/plugins/Plugins.cpp @@ -20,7 +20,6 @@ */ void setupPlugins() { - routingPlugin = new RoutingPlugin(); adminPlugin = new AdminPlugin(); nodeInfoPlugin = new NodeInfoPlugin(); positionPlugin = new PositionPlugin(); @@ -48,4 +47,7 @@ void setupPlugins() // new StoreForwardPlugin(); new EnvironmentalMeasurementPlugin(); #endif + + // NOTE! This plugin must be added LAST because it likes to check for replies from other plugins and avoid sending extra acks + routingPlugin = new RoutingPlugin(); } \ No newline at end of file diff --git a/src/plugins/RoutingPlugin.cpp b/src/plugins/RoutingPlugin.cpp index 18427bdca..f6c2ea03a 100644 --- a/src/plugins/RoutingPlugin.cpp +++ b/src/plugins/RoutingPlugin.cpp @@ -9,11 +9,12 @@ RoutingPlugin *routingPlugin; bool RoutingPlugin::handleReceivedProtobuf(const MeshPacket &mp, const Routing *r) { - DEBUG_MSG("Routing sniffing", &mp); + printPacket("Routing sniffing", &mp); router->sniffReceived(&mp, r); // FIXME - move this to a non promsicious PhoneAPI plugin? - if (mp.to == NODENUM_BROADCAST || mp.to == nodeDB.getNodeNum()) { + // Note: we are careful not to send back packets that started with the phone back to the phone + if ((mp.to == NODENUM_BROADCAST || mp.to == nodeDB.getNodeNum()) && (mp.from != 0)) { printPacket("Delivering rx packet", &mp); service.handleFromRadio(&mp); } From 8739469db30139cbfffcebf5de6502ea337579e6 Mon Sep 17 00:00:00 2001 From: Kevin Hester Date: Fri, 5 Mar 2021 11:49:37 +0800 Subject: [PATCH 205/258] oops typo --- src/mesh/Router.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mesh/Router.cpp b/src/mesh/Router.cpp index 17f6c50f2..87e8e4295 100644 --- a/src/mesh/Router.cpp +++ b/src/mesh/Router.cpp @@ -231,7 +231,7 @@ bool Router::perhapsDecode(MeshPacket *p) crypto->decrypt(p->from, p->id, p->encrypted.size, bytes); // Take those raw bytes and convert them back into a well structured protobuf we can understand - memset(p->decoded, 0, sizeof(p->decoded)); + memset(&p->decoded, 0, sizeof(p->decoded)); if (!pb_decode_from_bytes(bytes, p->encrypted.size, Data_fields, &p->decoded)) { DEBUG_MSG("Invalid protobufs in received mesh packet (bad psk?!\n"); } else { From c9c44a934daad581541fc2dfbbedd340d8212013 Mon Sep 17 00:00:00 2001 From: Kevin Hester Date: Fri, 5 Mar 2021 12:37:26 +0800 Subject: [PATCH 206/258] don't generate acks for locally sourced msgs --- docs/software/TODO.md | 2 ++ src/mesh/MeshPlugin.cpp | 6 +++++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/docs/software/TODO.md b/docs/software/TODO.md index 622a95af3..d256cd15d 100644 --- a/docs/software/TODO.md +++ b/docs/software/TODO.md @@ -34,6 +34,8 @@ You probably don't care about this section - skip to the next one. * DONE combine acks and responses in a single message if possible (do routing plugin LAST and drop ACK if someone else has already replied) * DONE don't send packets we received from the phone BACK TOWARDS THE PHONE (possibly use fromnode 0 for packets the phone sends?) * fix 1.1.50 android debug panel display +* test android channel setting +* release to users * DONE warn in android app about unset regions * DONE use set-channel from android * DONE add gui in android app for setting region diff --git a/src/mesh/MeshPlugin.cpp b/src/mesh/MeshPlugin.cpp index 562f31c73..e17cc5475 100644 --- a/src/mesh/MeshPlugin.cpp +++ b/src/mesh/MeshPlugin.cpp @@ -109,7 +109,11 @@ void setReplyTo(MeshPacket *p, const MeshPacket &to) { assert(p->which_payloadVariant == MeshPacket_decoded_tag); // Should already be set by now p->to = getFrom(&to); - p->want_ack = to.want_ack; + + // No need for an ack if we are just delivering locally (it just generates an ignored ack) + p->want_ack = (to.from != 0) ? to.want_ack : false; + if(p->priority == MeshPacket_Priority_UNSET) + p->priority = MeshPacket_Priority_RELIABLE; p->decoded.request_id = to.id; } From 845dd1f9e36f7c01c2b2b8d6cde0c47dd1589b30 Mon Sep 17 00:00:00 2001 From: Kevin Hester Date: Fri, 5 Mar 2021 12:39:39 +0800 Subject: [PATCH 207/258] 1.2.4 --- version.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version.properties b/version.properties index 9d155e715..a374a8b7d 100644 --- a/version.properties +++ b/version.properties @@ -1,4 +1,4 @@ [VERSION] major = 1 minor = 2 -build = 1 +build = 4 From badfaa8545f3108c9eb08733a85919de27637aaf Mon Sep 17 00:00:00 2001 From: Kevin Hester Date: Sat, 6 Mar 2021 10:27:31 +0800 Subject: [PATCH 208/258] make error message clearer for packets that are too big --- src/mesh/mesh-pb-constants.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/mesh/mesh-pb-constants.cpp b/src/mesh/mesh-pb-constants.cpp index 337e585de..fac31872c 100644 --- a/src/mesh/mesh-pb-constants.cpp +++ b/src/mesh/mesh-pb-constants.cpp @@ -18,8 +18,8 @@ size_t pb_encode_to_bytes(uint8_t *destbuf, size_t destbufsize, const pb_msgdesc pb_ostream_t stream = pb_ostream_from_buffer(destbuf, destbufsize); if (!pb_encode(&stream, fields, src_struct)) { - DEBUG_MSG("Error: can't encode protobuf %s\n", PB_GET_ERROR(&stream)); - assert(0); // FIXME - panic + DEBUG_MSG("Panic: can't encode protobuf %s, did you make a field too large?\n", PB_GET_ERROR(&stream)); + assert(0); // If this asser fails it probably means you made a field too large for the max limits specified in mesh.options } else { return stream.bytes_written; } From d2d6b8e12ff4b9c71e27ec9e0761ab2fc9f4556e Mon Sep 17 00:00:00 2001 From: Kevin Hester Date: Sat, 6 Mar 2021 10:27:48 +0800 Subject: [PATCH 209/258] fix log formatting --- src/mesh/PhoneAPI.cpp | 2 +- src/mesh/ReliableRouter.cpp | 4 ++-- src/plugins/TextMessagePlugin.cpp | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/mesh/PhoneAPI.cpp b/src/mesh/PhoneAPI.cpp index 5a7666b2d..c9ee13b9d 100644 --- a/src/mesh/PhoneAPI.cpp +++ b/src/mesh/PhoneAPI.cpp @@ -179,7 +179,7 @@ size_t PhoneAPI::getFromRadio(uint8_t *buf) // Do we have a message from the mesh? if (fromRadioScratch.which_payloadVariant != 0) { // Encapsulate as a FromRadio packet - DEBUG_MSG("encoding toPhone packet to phone variant=%d", fromRadioScratch.which_payloadVariant); + DEBUG_MSG("encoding toPhone packet to phone variant=%d\n", fromRadioScratch.which_payloadVariant); size_t numbytes = pb_encode_to_bytes(buf, FromRadio_size, FromRadio_fields, &fromRadioScratch); DEBUG_MSG(", %d bytes\n", numbytes); return numbytes; diff --git a/src/mesh/ReliableRouter.cpp b/src/mesh/ReliableRouter.cpp index eb22117fd..e3bd983d6 100644 --- a/src/mesh/ReliableRouter.cpp +++ b/src/mesh/ReliableRouter.cpp @@ -160,14 +160,14 @@ int32_t ReliableRouter::doRetransmissions() // FIXME, handle 51 day rolloever here!!! if (p.nextTxMsec <= now) { if (p.numRetransmissions == 0) { - DEBUG_MSG("Reliable send failed, returning a nak fr=0x%x,to=0x%x,id=%d\n", p.packet->from, p.packet->to, + DEBUG_MSG("Reliable send failed, returning a nak fr=0x%x,to=0x%x,id=0x%x\n", p.packet->from, p.packet->to, p.packet->id); sendAckNak(Routing_Error_MAX_RETRANSMIT, p.packet->from, p.packet->id); // Note: we don't stop retransmission here, instead the Nak packet gets processed in sniffReceived - which // allows the DSR version to still be able to look at the PendingPacket stopRetransmission(it->first); } else { - DEBUG_MSG("Sending reliable retransmission fr=0x%x,to=0x%x,id=%d, tries left=%d\n", p.packet->from, p.packet->to, + DEBUG_MSG("Sending reliable retransmission fr=0x%x,to=0x%x,id=0x%x, tries left=%d\n", p.packet->from, p.packet->to, p.packet->id, p.numRetransmissions); // Note: we call the superclass version because we don't want to have our version of send() add a new diff --git a/src/plugins/TextMessagePlugin.cpp b/src/plugins/TextMessagePlugin.cpp index 8da2a10f9..b285363aa 100644 --- a/src/plugins/TextMessagePlugin.cpp +++ b/src/plugins/TextMessagePlugin.cpp @@ -8,7 +8,7 @@ TextMessagePlugin *textMessagePlugin; bool TextMessagePlugin::handleReceived(const MeshPacket &mp) { auto &p = mp.decoded; - DEBUG_MSG("Received text msg from=0x%0x, id=%d, msg=%.*s\n", mp.from, mp.id, p.payload.size, p.payload.bytes); + DEBUG_MSG("Received text msg from=0x%0x, id=0x%x, msg=%.*s\n", mp.from, mp.id, p.payload.size, p.payload.bytes); // We only store/display messages destined for us. // Keep a copy of the most recent text message. From 2c29e8b179e3fff3ae6c8f3443ad63976363186d Mon Sep 17 00:00:00 2001 From: Kevin Hester Date: Sat, 6 Mar 2021 10:36:30 +0800 Subject: [PATCH 210/258] make nodeinfo & position plugins optional --- src/mesh/MeshService.cpp | 21 ++++++++++++++------- src/plugins/NodeInfoPlugin.cpp | 3 +-- 2 files changed, 15 insertions(+), 9 deletions(-) diff --git a/src/mesh/MeshService.cpp b/src/mesh/MeshService.cpp index 4dcc17859..5590fa9cf 100644 --- a/src/mesh/MeshService.cpp +++ b/src/mesh/MeshService.cpp @@ -114,7 +114,8 @@ bool MeshService::reloadConfig() void MeshService::reloadOwner() { assert(nodeInfoPlugin); - nodeInfoPlugin->sendOurNodeInfo(); + if(nodeInfoPlugin) + nodeInfoPlugin->sendOurNodeInfo(); nodeDB.saveToDisk(); } @@ -170,12 +171,18 @@ void MeshService::sendNetworkPing(NodeNum dest, bool wantReplies) NodeInfo *node = nodeDB.getNode(nodeDB.getNodeNum()); assert(node); - DEBUG_MSG("Sending network ping to 0x%x, with position=%d, wantReplies=%d\n", dest, node->has_position, wantReplies); - assert(positionPlugin && nodeInfoPlugin); - if (node->has_position) - positionPlugin->sendOurPosition(dest, wantReplies); - else - nodeInfoPlugin->sendOurNodeInfo(dest, wantReplies); + if (node->has_position) { + if(positionPlugin) { + DEBUG_MSG("Sending position ping to 0x%x, wantReplies=%d\n", dest, wantReplies); + positionPlugin->sendOurPosition(dest, wantReplies); + } + } + else { + if(nodeInfoPlugin) { + DEBUG_MSG("Sending nodeinfo ping to 0x%x, wantReplies=%d\n", dest, wantReplies); + nodeInfoPlugin->sendOurNodeInfo(dest, wantReplies); + } + } } NodeInfo *MeshService::refreshMyNodeInfo() diff --git a/src/plugins/NodeInfoPlugin.cpp b/src/plugins/NodeInfoPlugin.cpp index 82c16cbdc..f5f3ae194 100644 --- a/src/plugins/NodeInfoPlugin.cpp +++ b/src/plugins/NodeInfoPlugin.cpp @@ -65,8 +65,7 @@ int32_t NodeInfoPlugin::runOnce() currentGeneration = radioGeneration; DEBUG_MSG("Sending our nodeinfo to mesh (wantReplies=%d)\n", requestReplies); - assert(nodeInfoPlugin); - nodeInfoPlugin->sendOurNodeInfo(NODENUM_BROADCAST, requestReplies); // Send our info (don't request replies) + sendOurNodeInfo(NODENUM_BROADCAST, requestReplies); // Send our info (don't request replies) return getPref_position_broadcast_secs() * 1000; } From c88b9732eb2b6245c1a1055bfc341f619ff62f4d Mon Sep 17 00:00:00 2001 From: Kevin Hester Date: Sat, 6 Mar 2021 11:13:33 +0800 Subject: [PATCH 211/258] REALLY IMPORTANT: fix bug with retransmissions not happening --- src/mesh/RadioInterface.cpp | 14 +++++++++----- src/mesh/ReliableRouter.cpp | 32 ++++++++++++++++++++++++-------- src/mesh/ReliableRouter.h | 4 +--- src/mesh/Router.cpp | 5 +++++ src/mesh/Router.h | 5 +++++ 5 files changed, 44 insertions(+), 16 deletions(-) diff --git a/src/mesh/RadioInterface.cpp b/src/mesh/RadioInterface.cpp index 7b8aec605..966b900cc 100644 --- a/src/mesh/RadioInterface.cpp +++ b/src/mesh/RadioInterface.cpp @@ -1,16 +1,16 @@ +#include "configuration.h" #include "RadioInterface.h" #include "Channels.h" #include "MeshRadio.h" #include "MeshService.h" #include "NodeDB.h" #include "assert.h" -#include "configuration.h" +#include "Router.h" #include "sleep.h" #include #include #include -#include "Channels.h" #define RDEF(name, freq, spacing, num_ch, power_limit) \ { \ @@ -119,11 +119,11 @@ uint32_t RadioInterface::getTxDelayMsec() void printPacket(const char *prefix, const MeshPacket *p) { - DEBUG_MSG("%s (id=0x%08x Fr0x%02x To0x%02x, WantAck%d, HopLim%d Ch0x%x", prefix, p->id, p->from & 0xff, p->to & 0xff, p->want_ack, - p->hop_limit, p->channel); + DEBUG_MSG("%s (id=0x%08x Fr0x%02x To0x%02x, WantAck%d, HopLim%d Ch0x%x", prefix, p->id, p->from & 0xff, p->to & 0xff, + p->want_ack, p->hop_limit, p->channel); if (p->which_payloadVariant == MeshPacket_decoded_tag) { auto &s = p->decoded; - + DEBUG_MSG(" Portnum=%d", s.portnum); if (s.want_response) @@ -332,6 +332,10 @@ void RadioInterface::deliverToReceiver(MeshPacket *p) { assert(rxDest); assert(rxDest->enqueue(p, 0)); // NOWAIT - fixme, if queue is full, delete older messages + + // Nasty hack because our threading is primitive. interfaces shouldn't need to know about routers FIXME + if (router) + router->setReceivedMessage(); } /*** diff --git a/src/mesh/ReliableRouter.cpp b/src/mesh/ReliableRouter.cpp index e3bd983d6..fd67bf3e5 100644 --- a/src/mesh/ReliableRouter.cpp +++ b/src/mesh/ReliableRouter.cpp @@ -1,8 +1,8 @@ #include "ReliableRouter.h" +#include "MeshPlugin.h" #include "MeshTypes.h" #include "configuration.h" #include "mesh-pb-constants.h" -#include "MeshPlugin.h" // ReliableRouter::ReliableRouter() {} @@ -36,7 +36,7 @@ bool ReliableRouter::shouldFilterReceived(const MeshPacket *p) // the original sending process. if (stopRetransmission(getFrom(p), p->id)) { DEBUG_MSG("Someone is retransmitting for us, generate implicit ack\n"); - if(p->want_ack) + if (p->want_ack) sendAckNak(Routing_Error_NONE, getFrom(p), p->id); } } @@ -63,7 +63,7 @@ void ReliableRouter::sniffReceived(const MeshPacket *p, const Routing *c) if (p->to == ourNode) { // ignore ack/nak/want_ack packets that are not address to us (we only handle 0 hop reliability // - not DSR routing) if (p->want_ack) { - if(MeshPlugin::currentReply) + if (MeshPlugin::currentReply) DEBUG_MSG("Someone else has replied to this message, no need for a 2nd ack"); else sendAckNak(Routing_Error_NONE, getFrom(p), p->id); @@ -136,8 +136,9 @@ PendingPacket *ReliableRouter::startRetransmission(MeshPacket *p) auto id = GlobalPacketId(p); auto rec = PendingPacket(p); - setNextTx(&rec); stopRetransmission(getFrom(p), p->id); + + setNextTx(&rec); pending[id] = rec; return &pending[id]; @@ -157,6 +158,8 @@ int32_t ReliableRouter::doRetransmissions() ++nextIt; // we use this odd pattern because we might be deleting it... auto &p = it->second; + bool stillValid = true; // assume we'll keep this record around + // FIXME, handle 51 day rolloever here!!! if (p.nextTxMsec <= now) { if (p.numRetransmissions == 0) { @@ -166,9 +169,10 @@ int32_t ReliableRouter::doRetransmissions() // Note: we don't stop retransmission here, instead the Nak packet gets processed in sniffReceived - which // allows the DSR version to still be able to look at the PendingPacket stopRetransmission(it->first); + stillValid = false; // just deleted it } else { - DEBUG_MSG("Sending reliable retransmission fr=0x%x,to=0x%x,id=0x%x, tries left=%d\n", p.packet->from, p.packet->to, - p.packet->id, p.numRetransmissions); + DEBUG_MSG("Sending reliable retransmission fr=0x%x,to=0x%x,id=0x%x, tries left=%d\n", p.packet->from, + p.packet->to, p.packet->id, p.numRetransmissions); // Note: we call the superclass version because we don't want to have our version of send() add a new // retransmission record @@ -178,8 +182,10 @@ int32_t ReliableRouter::doRetransmissions() --p.numRetransmissions; setNextTx(&p); } - } else { - // Not yet time + } + + if(stillValid) { + // Update our desired sleep delay int32_t t = p.nextTxMsec - now; d = min(t, d); @@ -187,4 +193,14 @@ int32_t ReliableRouter::doRetransmissions() } return d; +} + +void ReliableRouter::setNextTx(PendingPacket *pending) +{ + assert(iface); + auto d = iface->getRetransmissionMsec(pending->packet); + pending->nextTxMsec = millis() + d; + DEBUG_MSG("Setting next retransmission in %u msecs: ", d); + printPacket("", pending->packet); + setReceivedMessage(); // Run ASAP, so we can figure out our correct sleep time } \ No newline at end of file diff --git a/src/mesh/ReliableRouter.h b/src/mesh/ReliableRouter.h index fefc85cb3..db161b984 100644 --- a/src/mesh/ReliableRouter.h +++ b/src/mesh/ReliableRouter.h @@ -125,7 +125,5 @@ class ReliableRouter : public FloodingRouter */ int32_t doRetransmissions(); - void setNextTx(PendingPacket *pending) { - assert(iface); - pending->nextTxMsec = millis() + iface->getRetransmissionMsec(pending->packet); } + void setNextTx(PendingPacket *pending); }; diff --git a/src/mesh/Router.cpp b/src/mesh/Router.cpp index 87e8e4295..d08124b4a 100644 --- a/src/mesh/Router.cpp +++ b/src/mesh/Router.cpp @@ -115,12 +115,17 @@ void Router::abortSendAndNak(Routing_Error err, MeshPacket *p) packetPool.release(p); } +void Router::setReceivedMessage() { + setInterval(0); // Run ASAP, so we can figure out our correct sleep time +} + ErrorCode Router::sendLocal(MeshPacket *p) { // No need to deliver externally if the destination is the local node if (p->to == nodeDB.getNodeNum()) { printPacket("Enqueuing local", p); fromRadioQueue.enqueue(p); + setReceivedMessage(); return ERRNO_OK; } else if (!iface) { // We must be sending to remote nodes also, fail if no interface found diff --git a/src/mesh/Router.h b/src/mesh/Router.h index 6e6bf2c2a..6e217017b 100644 --- a/src/mesh/Router.h +++ b/src/mesh/Router.h @@ -63,6 +63,11 @@ class Router : protected concurrency::OSThread * @return our local nodenum */ NodeNum getNodeNum(); + /** Wake up the router thread ASAP, because we just queued a message for it. + * FIXME, this is kinda a hack because we don't have a nice way yet to say 'wake us because we are 'blocked on this queue' + */ + void setReceivedMessage(); + protected: friend class RoutingPlugin; From aa6b29a4b587fd0ebc8235cb7e3228240f494542 Mon Sep 17 00:00:00 2001 From: Kevin Hester Date: Sat, 6 Mar 2021 11:19:52 +0800 Subject: [PATCH 212/258] fix from address on naks --- src/mesh/ReliableRouter.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/mesh/ReliableRouter.cpp b/src/mesh/ReliableRouter.cpp index fd67bf3e5..cde08b5bb 100644 --- a/src/mesh/ReliableRouter.cpp +++ b/src/mesh/ReliableRouter.cpp @@ -163,9 +163,9 @@ int32_t ReliableRouter::doRetransmissions() // FIXME, handle 51 day rolloever here!!! if (p.nextTxMsec <= now) { if (p.numRetransmissions == 0) { - DEBUG_MSG("Reliable send failed, returning a nak fr=0x%x,to=0x%x,id=0x%x\n", p.packet->from, p.packet->to, + DEBUG_MSG("Reliable send failed, returning a nak for fr=0x%x,to=0x%x,id=0x%x\n", p.packet->from, p.packet->to, p.packet->id); - sendAckNak(Routing_Error_MAX_RETRANSMIT, p.packet->from, p.packet->id); + sendAckNak(Routing_Error_MAX_RETRANSMIT, getFrom(p.packet), p.packet->id); // Note: we don't stop retransmission here, instead the Nak packet gets processed in sniffReceived - which // allows the DSR version to still be able to look at the PendingPacket stopRetransmission(it->first); From 49b1f4c5aff5d511272b0fa20da103fee51ff504 Mon Sep 17 00:00:00 2001 From: Kevin Hester Date: Sat, 6 Mar 2021 14:21:20 +0800 Subject: [PATCH 213/258] oops - fix failed text message rx --- docs/software/TODO.md | 4 ++-- src/esp32/ESP32CryptoEngine.cpp | 2 +- src/mesh/Channels.cpp | 3 ++- src/mesh/CryptoEngine.cpp | 4 ++++ src/mesh/Router.cpp | 42 +++++++++++++++++++++++---------- 5 files changed, 38 insertions(+), 17 deletions(-) diff --git a/docs/software/TODO.md b/docs/software/TODO.md index d256cd15d..26fb08851 100644 --- a/docs/software/TODO.md +++ b/docs/software/TODO.md @@ -34,8 +34,8 @@ You probably don't care about this section - skip to the next one. * DONE combine acks and responses in a single message if possible (do routing plugin LAST and drop ACK if someone else has already replied) * DONE don't send packets we received from the phone BACK TOWARDS THE PHONE (possibly use fromnode 0 for packets the phone sends?) * fix 1.1.50 android debug panel display -* test android channel setting -* release to users +* DONE test android channel setting +* DONE release to users * DONE warn in android app about unset regions * DONE use set-channel from android * DONE add gui in android app for setting region diff --git a/src/esp32/ESP32CryptoEngine.cpp b/src/esp32/ESP32CryptoEngine.cpp index 9d86ffeb0..f04614c72 100644 --- a/src/esp32/ESP32CryptoEngine.cpp +++ b/src/esp32/ESP32CryptoEngine.cpp @@ -54,7 +54,7 @@ class ESP32CryptoEngine : public CryptoEngine static uint8_t scratch[MAX_BLOCKSIZE]; size_t nc_off = 0; - // DEBUG_MSG("ESP32 encrypt!\n"); + // DEBUG_MSG("ESP32 crypt fr=%x, num=%x, numBytes=%d!\n", fromNode, (uint32_t) packetNum, numBytes); initNonce(fromNode, packetNum); assert(numBytes <= MAX_BLOCKSIZE); memcpy(scratch, bytes, numBytes); diff --git a/src/mesh/Channels.cpp b/src/mesh/Channels.cpp index 76ea3fb92..414930182 100644 --- a/src/mesh/Channels.cpp +++ b/src/mesh/Channels.cpp @@ -275,10 +275,11 @@ const char *Channels::getPrimaryName() bool Channels::decryptForHash(ChannelIndex chIndex, ChannelHash channelHash) { if(chIndex > getNumChannels() || getHash(chIndex) != channelHash) { - DEBUG_MSG("Skipping channel %d due to invalid hash/index\n", chIndex); + // DEBUG_MSG("Skipping channel %d (hash %x) due to invalid hash/index, want=%x\n", chIndex, getHash(chIndex), channelHash); return false; } else { + DEBUG_MSG("Using channel %d (hash 0x%x)\n", chIndex, channelHash); setCrypto(chIndex); return true; } diff --git a/src/mesh/CryptoEngine.cpp b/src/mesh/CryptoEngine.cpp index 74f4b7836..59cb7ad8f 100644 --- a/src/mesh/CryptoEngine.cpp +++ b/src/mesh/CryptoEngine.cpp @@ -4,6 +4,10 @@ void CryptoEngine::setKey(const CryptoKey &k) { DEBUG_MSG("Installing AES%d key!\n", k.length * 8); + /* for(uint8_t i = 0; i < k.length; i++) + DEBUG_MSG("%02x ", k.bytes[i]); + DEBUG_MSG("\n"); */ + key = k; } diff --git a/src/mesh/Router.cpp b/src/mesh/Router.cpp index d08124b4a..8f566dffe 100644 --- a/src/mesh/Router.cpp +++ b/src/mesh/Router.cpp @@ -143,6 +143,13 @@ ErrorCode Router::sendLocal(MeshPacket *p) } } +void printBytes(const char *label, const uint8_t *p, size_t numbytes) { + DEBUG_MSG("%s: ", label); + for(size_t i = 0; i < numbytes; i++) + DEBUG_MSG("%02x ", p[i]); + DEBUG_MSG("\n"); +} + /** * Send a packet on a suitable interface. This routine will * later free() the packet to pool. This routine is not allowed to stall. @@ -173,6 +180,8 @@ ErrorCode Router::send(MeshPacket *p) if (p->which_payloadVariant == MeshPacket_decoded_tag) { static uint8_t bytes[MAX_RHPACKETLEN]; // we have to use a scratch buffer because a union + // printPacket("pre encrypt", p); // portnum valid here + size_t numbytes = pb_encode_to_bytes(bytes, sizeof(bytes), Data_fields, &p->decoded); if (numbytes > MAX_RHPACKETLEN) { @@ -180,6 +189,8 @@ ErrorCode Router::send(MeshPacket *p) return ERRNO_TOO_LARGE; } + //printBytes("plaintext", bytes, numbytes); + auto hash = channels.setActiveByIndex(p->channel); if (hash < 0) { // No suitable channel could be found for sending @@ -189,7 +200,7 @@ ErrorCode Router::send(MeshPacket *p) // Now that we are encrypting the packet channel should be the hash (no longer the index) p->channel = hash; - crypto->encrypt(p->from, p->id, numbytes, bytes); + crypto->encrypt(getFrom(p), p->id, numbytes, bytes); // Copy back into the packet and set the variant type memcpy(p->encrypted.bytes, bytes, numbytes); @@ -230,20 +241,26 @@ bool Router::perhapsDecode(MeshPacket *p) if (channels.decryptForHash(chIndex, p->channel)) { // Try to decrypt the packet if we can static uint8_t bytes[MAX_RHPACKETLEN]; + size_t rawSize = p->encrypted.size; + assert(rawSize <= sizeof(bytes)); memcpy(bytes, p->encrypted.bytes, - p->encrypted - .size); // we have to copy into a scratch buffer, because these bytes are a union with the decoded protobuf - crypto->decrypt(p->from, p->id, p->encrypted.size, bytes); + rawSize); // we have to copy into a scratch buffer, because these bytes are a union with the decoded protobuf + crypto->decrypt(p->from, p->id, rawSize, bytes); + + //printBytes("plaintext", bytes, p->encrypted.size); // Take those raw bytes and convert them back into a well structured protobuf we can understand - memset(&p->decoded, 0, sizeof(p->decoded)); - if (!pb_decode_from_bytes(bytes, p->encrypted.size, Data_fields, &p->decoded)) { - DEBUG_MSG("Invalid protobufs in received mesh packet (bad psk?!\n"); - } else { + memset(&p->decoded, 0, sizeof(p->decoded)); + if (!pb_decode_from_bytes(bytes, rawSize, Data_fields, &p->decoded)) { + DEBUG_MSG("Invalid protobufs in received mesh packet (bad psk?)!\n"); + } else if(p->decoded.portnum == PortNum_UNKNOWN_APP) { + DEBUG_MSG("Invalid portnum (bad psk?)!\n"); + } + else { // parsing was successful + p->which_payloadVariant = MeshPacket_decoded_tag; // change type to decoded p->channel = chIndex; // change to store the index instead of the hash - // printPacket("decoded message", p); - p->which_payloadVariant = MeshPacket_decoded_tag; + printPacket("decoded message", p); return true; } } @@ -268,11 +285,10 @@ void Router::handleReceived(MeshPacket *p) p->rx_time = getValidTime(RTCQualityFromNet); // store the arrival timestamp for the phone // Take those raw bytes and convert them back into a well structured protobuf we can understand - bool decoded = perhapsDecode(p); - printPacket("handleReceived", p); - DEBUG_MSG("decoded=%d\n", decoded); + bool decoded = perhapsDecode(p); if (decoded) { // parsing was successful, queue for our recipient + printPacket("handleReceived", p); // call any promiscious plugins here, make a (non promisiocous) plugin for forwarding messages to phone api // sniffReceived(p); From 7a764efc10e5856663d92634f579f5da20128efe Mon Sep 17 00:00:00 2001 From: Kevin Hester Date: Sat, 6 Mar 2021 14:30:53 +0800 Subject: [PATCH 214/258] 1.2.5 --- version.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version.properties b/version.properties index a374a8b7d..d16382f27 100644 --- a/version.properties +++ b/version.properties @@ -1,4 +1,4 @@ [VERSION] major = 1 minor = 2 -build = 4 +build = 5 From 96cfad4e579768c4fd3106c0d8a9cd3bb72704ea Mon Sep 17 00:00:00 2001 From: Kevin Hester Date: Sat, 6 Mar 2021 14:52:26 +0800 Subject: [PATCH 215/258] less logspam --- src/mesh/PhoneAPI.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/mesh/PhoneAPI.cpp b/src/mesh/PhoneAPI.cpp index c9ee13b9d..6e2ac479b 100644 --- a/src/mesh/PhoneAPI.cpp +++ b/src/mesh/PhoneAPI.cpp @@ -179,9 +179,8 @@ size_t PhoneAPI::getFromRadio(uint8_t *buf) // Do we have a message from the mesh? if (fromRadioScratch.which_payloadVariant != 0) { // Encapsulate as a FromRadio packet - DEBUG_MSG("encoding toPhone packet to phone variant=%d\n", fromRadioScratch.which_payloadVariant); size_t numbytes = pb_encode_to_bytes(buf, FromRadio_size, FromRadio_fields, &fromRadioScratch); - DEBUG_MSG(", %d bytes\n", numbytes); + // DEBUG_MSG("encoding toPhone packet to phone variant=%d, %d bytes\n", fromRadioScratch.which_payloadVariant, numbytes); return numbytes; } From 6f13966d1906927c14ff6100164fabc92d3c5e99 Mon Sep 17 00:00:00 2001 From: Kevin Hester Date: Sat, 6 Mar 2021 17:40:20 +0800 Subject: [PATCH 216/258] fix missing acks for broadcasts --- src/mesh/ReliableRouter.cpp | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/mesh/ReliableRouter.cpp b/src/mesh/ReliableRouter.cpp index cde08b5bb..962aabeb7 100644 --- a/src/mesh/ReliableRouter.cpp +++ b/src/mesh/ReliableRouter.cpp @@ -35,9 +35,10 @@ bool ReliableRouter::shouldFilterReceived(const MeshPacket *p) // If this is the first time we saw this, cancel any retransmissions we have queued up and generate an internal ack for // the original sending process. if (stopRetransmission(getFrom(p), p->id)) { - DEBUG_MSG("Someone is retransmitting for us, generate implicit ack\n"); - if (p->want_ack) - sendAckNak(Routing_Error_NONE, getFrom(p), p->id); + DEBUG_MSG("generating implicit ack\n"); + // NOTE: we do NOT check p->wantAck here because p is the INCOMING rebroadcast and that packet is not expected to be + // marked as wantAck + sendAckNak(Routing_Error_NONE, getFrom(p), p->id); } } @@ -182,9 +183,9 @@ int32_t ReliableRouter::doRetransmissions() --p.numRetransmissions; setNextTx(&p); } - } + } - if(stillValid) { + if (stillValid) { // Update our desired sleep delay int32_t t = p.nextTxMsec - now; From ba9a94d026791ca4d75eddd0b87b38692a5b4319 Mon Sep 17 00:00:00 2001 From: Kevin Hester Date: Sat, 6 Mar 2021 18:00:20 +0800 Subject: [PATCH 217/258] fix is_low_power detection --- src/PowerFSM.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/PowerFSM.cpp b/src/PowerFSM.cpp index 85e08f536..9c145499d 100644 --- a/src/PowerFSM.cpp +++ b/src/PowerFSM.cpp @@ -181,7 +181,7 @@ void PowerFSM_setup() 1) If we're powered up and there's no battery, we must be getting power externally. 2) If we detect USB power from the power management chip, we must be getting power externally. */ - bool hasPower = (powerStatus && !powerStatus->getHasBattery()) || (!isLowPower && powerStatus && powerStatus->getHasUSB()); + bool hasPower = !isLowPower && powerStatus && (!powerStatus->getHasBattery() || powerStatus->getHasUSB()); DEBUG_MSG("PowerFSM init, USB power=%d\n", hasPower); powerFSM.add_timed_transition(&stateBOOT, hasPower ? &statePOWER : &stateON, 3 * 1000, NULL, "boot timeout"); From 1f335069620b0155b537b98702bd52adde7c4582 Mon Sep 17 00:00:00 2001 From: Kevin Hester Date: Sat, 6 Mar 2021 21:10:36 +0800 Subject: [PATCH 218/258] Add RU region --- src/mesh/RadioInterface.cpp | 18 ++++++++++++++++++ src/mesh/generated/radioconfig.pb.h | 7 ++++--- 2 files changed, 22 insertions(+), 3 deletions(-) diff --git a/src/mesh/RadioInterface.cpp b/src/mesh/RadioInterface.cpp index 966b900cc..49dc69927 100644 --- a/src/mesh/RadioInterface.cpp +++ b/src/mesh/RadioInterface.cpp @@ -25,9 +25,27 @@ const RegionInfo regions[] = { RDEF(KR, 921.9f, 0.2f, 8, 0), // KR channel settings (KR920-923) Start from TTN download channel // freq. (921.9f is for download, others are for uplink) RDEF(TW, 923.0f, 0.2f, 10, 0), // TW channel settings (AS2 bandplan 923-925MHz) + RDEF(RU, 868.9f, 0.2f, 2, 20), // See notes below RDEF(Unset, 903.08f, 2.16f, 13, 0) // Assume US freqs if unset, Must be last }; +/* Notes about the RU bandplan (from @denis-d in https://meshtastic.discourse.group/t/russian-band-plan-proposal/2786/2): + +According to Annex 12 to GKRCh (National Radio Frequency Commission) decision № 18-46-03-1 (September 11th 2018) https://digital.gov.ru/uploaded/files/prilozhenie-12-k-reshenyu-gkrch-18-46-03-1.pdf 1 +We have 3 options for 868 MHz: + +864,0 - 865,0 MHz ERP 25mW, Duty Cycle 0.1% (3.6 sec in hour) or LBT (Listen Before Talk), prohibited in airports. +866,0 - 868,0 MHz ERP 25mW, Duty Cycle 1% or LBT, PSD (Power Spectrum Density) 1000mW/MHz, prohibited in airports +868,7 - 869,2 MHz ERP 100mW, Duty Cycle 10% or LBT, no resctrictions +and according to RP2-1.0.2 LoRaWAN® Regional Parameters RP2-1.0.2 LoRaWAN® Regional Parameters - LoRa Alliance® +I propose to use following meshtastic bandplan: +1 channel - central frequency 868.9MHz 125kHz band +Protective band - 75kHz +2 channel - central frequency 869.1MHz 125kHz band + +RDEF(RU, 868.9f, 0.2f, 2, 20) +*/ + const RegionInfo *myRegion; void initRegion() diff --git a/src/mesh/generated/radioconfig.pb.h b/src/mesh/generated/radioconfig.pb.h index 85bfa1a2d..9ea021f13 100644 --- a/src/mesh/generated/radioconfig.pb.h +++ b/src/mesh/generated/radioconfig.pb.h @@ -19,7 +19,8 @@ typedef enum _RegionCode { RegionCode_JP = 5, RegionCode_ANZ = 6, RegionCode_KR = 7, - RegionCode_TW = 8 + RegionCode_TW = 8, + RegionCode_RU = 9 } RegionCode; typedef enum _ChargeCurrent { @@ -123,8 +124,8 @@ typedef struct _RadioConfig { /* Helper constants for enums */ #define _RegionCode_MIN RegionCode_Unset -#define _RegionCode_MAX RegionCode_TW -#define _RegionCode_ARRAYSIZE ((RegionCode)(RegionCode_TW+1)) +#define _RegionCode_MAX RegionCode_RU +#define _RegionCode_ARRAYSIZE ((RegionCode)(RegionCode_RU+1)) #define _ChargeCurrent_MIN ChargeCurrent_MAUnset #define _ChargeCurrent_MAX ChargeCurrent_MA1320 From 64bc791e482b1d1dafc26c4fbf4f171294d7afca Mon Sep 17 00:00:00 2001 From: Kevin Hester Date: Sun, 7 Mar 2021 09:34:29 +0800 Subject: [PATCH 219/258] fix docs --- src/PowerFSM.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/PowerFSM.cpp b/src/PowerFSM.cpp index 9c145499d..09fc35e6c 100644 --- a/src/PowerFSM.cpp +++ b/src/PowerFSM.cpp @@ -178,8 +178,9 @@ void PowerFSM_setup() bool isLowPower = radioConfig.preferences.is_low_power || isRouter; /* To determine if we're externally powered, assumptions - 1) If we're powered up and there's no battery, we must be getting power externally. - 2) If we detect USB power from the power management chip, we must be getting power externally. + 1) If we're powered up and there's no battery, we must be getting power externally. (because we'd be dead otherwise) + + 2) If we detect USB power from the power management chip, we must be getting power externally. */ bool hasPower = !isLowPower && powerStatus && (!powerStatus->getHasBattery() || powerStatus->getHasUSB()); From 12a7934ca108c2cfd4b886ee4c59cdf993b4c073 Mon Sep 17 00:00:00 2001 From: Kevin Hester Date: Sun, 7 Mar 2021 09:34:35 +0800 Subject: [PATCH 220/258] add RU --- proto | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/proto b/proto index ac4f53ed8..7c025b9a4 160000 --- a/proto +++ b/proto @@ -1 +1 @@ -Subproject commit ac4f53ed8c903a5bdf3d19727e96791d6be71022 +Subproject commit 7c025b9a4d54bb410ec17ee653122861b413f177 From d014ae0bffc9283c0b4de9196984c28eedd8e585 Mon Sep 17 00:00:00 2001 From: Kevin Hester Date: Sun, 7 Mar 2021 09:51:17 +0800 Subject: [PATCH 221/258] fix ls_sleeps communication to device clients --- src/plugins/AdminPlugin.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/plugins/AdminPlugin.cpp b/src/plugins/AdminPlugin.cpp index bba1b39a9..7e0a67074 100644 --- a/src/plugins/AdminPlugin.cpp +++ b/src/plugins/AdminPlugin.cpp @@ -24,6 +24,12 @@ void AdminPlugin::handleGetRadio(const MeshPacket &req) // We create the reply here AdminMessage r = AdminMessage_init_default; r.get_radio_response = devicestate.radio; + + // 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). + r.get_radio_response.preferences.ls_secs = getPref_ls_secs(); + r.which_variant = AdminMessage_get_radio_response_tag; reply = allocDataProtobuf(r); } From f320ecbde8503e86a069c2184ac90689d3696789 Mon Sep 17 00:00:00 2001 From: Kevin Hester Date: Sun, 7 Mar 2021 09:51:51 +0800 Subject: [PATCH 222/258] 1.2.6 --- version.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version.properties b/version.properties index d16382f27..d0634458c 100644 --- a/version.properties +++ b/version.properties @@ -1,4 +1,4 @@ [VERSION] major = 1 minor = 2 -build = 5 +build = 6 From 6ceb4230337ab8be0ba6b10322571044829ffd4a Mon Sep 17 00:00:00 2001 From: Kevin Hester Date: Mon, 8 Mar 2021 12:03:04 +0800 Subject: [PATCH 223/258] TODO update --- docs/software/TODO.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/software/TODO.md b/docs/software/TODO.md index 26fb08851..b26ce9b5b 100644 --- a/docs/software/TODO.md +++ b/docs/software/TODO.md @@ -29,6 +29,7 @@ You probably don't care about this section - skip to the next one. * DONE release protobufs * DONE release to developers * DONE fix setch-fast in python tool +* turn off fault 8: https://github.com/meshtastic/Meshtastic-device/issues/734 * age out pendingrequests in the python API * DONE stress test channel download from python, sometimes it seems like we don't get all replies, bug was due to simultaneous android connection * DONE combine acks and responses in a single message if possible (do routing plugin LAST and drop ACK if someone else has already replied) From c0e180759d7d05d1c2a09e43c8e6cacb62b7af00 Mon Sep 17 00:00:00 2001 From: Kevin Hester Date: Mon, 8 Mar 2021 15:20:29 +0800 Subject: [PATCH 224/258] improve debugging on cortex m --- bin/nrf52840-gdbserver.sh | 2 +- platformio.ini | 25 ++++++++++++++++++++++--- src/nrf52/hardfault.cpp | 26 ++++++++++++++++++++++++++ 3 files changed, 49 insertions(+), 4 deletions(-) diff --git a/bin/nrf52840-gdbserver.sh b/bin/nrf52840-gdbserver.sh index 15fb8fbff..010c1003f 100755 --- a/bin/nrf52840-gdbserver.sh +++ b/bin/nrf52840-gdbserver.sh @@ -1,3 +1,3 @@ -JLinkGDBServerCLExe -if SWD -select USB -port 2331 -device NRF52840_XXAA +JLinkGDBServerCLExe -if SWD -select USB -port 2331 -device NRF52840_XXAA -SuppressInfoUpdateFW -DisableAutoUpdateFW -rtos GDBServer/RTOSPlugin_FreeRTOS diff --git a/platformio.ini b/platformio.ini index d8ef51b7f..aeab4f65b 100644 --- a/platformio.ini +++ b/platformio.ini @@ -9,13 +9,13 @@ ; https://docs.platformio.org/page/projectconf.html [platformio] -default_envs = tbeam +;default_envs = tbeam ;default_envs = tbeam0.7 ;default_envs = heltec ;default_envs = tlora-v1 ;default_envs = tlora-v2 ;default_envs = lora-relay-v1 # nrf board -;default_envs = eink +default_envs = eink ;default_envs = linux # lora-relay-v1 # nrf52840dk-geeksville # linux # or if you'd like to change the default to something like lora-relay-v1 put that here [common] @@ -184,7 +184,6 @@ src_filter = ; platform = nordicnrf52 platform = https://github.com/meshtastic/platform-nordicnrf52.git#1a2639a6b0f79b5df66bea3e3089f0d5285fdc63 extends = arduino_base -debug_tool = jlink build_type = debug ; I'm debugging with ICE a lot now ; note: liboberon provides the AES256 implementation for NRF52 (though not using the hardware acceleration of the NRF52840 - FIXME) build_flags = @@ -198,6 +197,26 @@ lib_ignore = BluetoothOTA monitor_port = /dev/ttyACM1 +# we pass in options to jlink so it can understand freertos (note: we don't use "jlink" as the tool) +debug_tool = jlink +debug_port = :2331 +# Note: the ARGUMENTS MUST BE on multiple lines. Otherwise platformio/commands/debug/helpers.py misparses everything into the "executable" +# attribute and leaves "arguments" empty +# /home/kevinh/.platformio/packages/tool-jlink/JLinkGDBServerCLExe +debug_server = + /usr/bin/JLinkGDBServerCLExe + -singlerun + -if + SWD + -select + USB + -device + nRF52840_xxAA + -port + 2331 + -rtos + GDBServer/RTOSPlugin_FreeRTOS + debug_extra_cmds = source gdbinit diff --git a/src/nrf52/hardfault.cpp b/src/nrf52/hardfault.cpp index c1a82d6ae..d63829072 100644 --- a/src/nrf52/hardfault.cpp +++ b/src/nrf52/hardfault.cpp @@ -82,8 +82,34 @@ extern "C" void HardFault_Impl(uint32_t stack[]) // while (1) ; } +#ifndef INC_FREERTOS_H +// This is a generic cortex M entrypoint that doesn't assume freertos + extern "C" void HardFault_Handler(void) { asm volatile(" mrs r0,msp\n" " b HardFault_Impl \n"); } +#else + +/* The prototype shows it is a naked function - in effect this is just an +assembly function. */ +extern "C" void HardFault_Handler( void ) __attribute__( ( naked ) ); + +/* The fault handler implementation calls a function called +prvGetRegistersFromStack(). */ +extern "C" void HardFault_Handler(void) +{ + __asm volatile + ( + " tst lr, #4 \n" + " ite eq \n" + " mrseq r0, msp \n" + " mrsne r0, psp \n" + " ldr r1, [r0, #24] \n" + " ldr r2, handler2_address_const \n" + " bx r2 \n" + " handler2_address_const: .word HardFault_Impl \n" + ); +} +#endif From 707ed75138cb17c5bbd4b299972ede38c83398d8 Mon Sep 17 00:00:00 2001 From: Kevin Hester Date: Mon, 8 Mar 2021 15:20:43 +0800 Subject: [PATCH 225/258] fix warnings found in nrf52 build --- src/RedirectablePrint.cpp | 2 +- src/mesh/Channels.cpp | 2 +- src/plugins/ExternalNotificationPlugin.cpp | 3 ++- src/plugins/SerialPlugin.cpp | 3 ++- 4 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/RedirectablePrint.cpp b/src/RedirectablePrint.cpp index c60b8a502..fd634a99f 100644 --- a/src/RedirectablePrint.cpp +++ b/src/RedirectablePrint.cpp @@ -38,7 +38,7 @@ size_t RedirectablePrint::vprintf(const char *format, va_list arg) va_end(arg); return 0; }; - if (len >= printBufLen) { + if (len >= (int) printBufLen) { delete[] printBuf; printBufLen *= 2; printBuf = new char[printBufLen]; diff --git a/src/mesh/Channels.cpp b/src/mesh/Channels.cpp index 414930182..ab0a64b37 100644 --- a/src/mesh/Channels.cpp +++ b/src/mesh/Channels.cpp @@ -13,7 +13,7 @@ Channels channels; uint8_t xorHash(const uint8_t *p, size_t len) { uint8_t code = 0; - for (int i = 0; i < len; i++) + for (size_t i = 0; i < len; i++) code ^= p[i]; return code; } diff --git a/src/plugins/ExternalNotificationPlugin.cpp b/src/plugins/ExternalNotificationPlugin.cpp index 42865f3cc..0320c7b30 100644 --- a/src/plugins/ExternalNotificationPlugin.cpp +++ b/src/plugins/ExternalNotificationPlugin.cpp @@ -114,7 +114,8 @@ int32_t ExternalNotificationPlugin::runOnce() return (INT32_MAX); } - +#else + return INT32_MAX; #endif } diff --git a/src/plugins/SerialPlugin.cpp b/src/plugins/SerialPlugin.cpp index c93bf8521..9aab876f9 100644 --- a/src/plugins/SerialPlugin.cpp +++ b/src/plugins/SerialPlugin.cpp @@ -124,7 +124,8 @@ int32_t SerialPlugin::runOnce() return (INT32_MAX); } - +#else + return INT32_MAX; #endif } From 7bbd2c0e804e361fd99e7e020fb8dd142374458f Mon Sep 17 00:00:00 2001 From: Kevin Hester Date: Mon, 8 Mar 2021 15:30:08 +0800 Subject: [PATCH 226/258] make textmessageplugin optional --- src/graphics/Screen.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/graphics/Screen.cpp b/src/graphics/Screen.cpp index 6e52abdde..c0511a8c6 100644 --- a/src/graphics/Screen.cpp +++ b/src/graphics/Screen.cpp @@ -791,7 +791,8 @@ void Screen::setup() powerStatusObserver.observe(&powerStatus->onNewStatus); gpsStatusObserver.observe(&gpsStatus->onNewStatus); nodeStatusObserver.observe(&nodeStatus->onNewStatus); - textMessageObserver.observe(textMessagePlugin); + if(textMessagePlugin) + textMessageObserver.observe(textMessagePlugin); } void Screen::forceDisplay() From 781d2f0ad635e400f6223dbc74811bb334e23da2 Mon Sep 17 00:00:00 2001 From: Kevin Hester Date: Mon, 8 Mar 2021 17:09:35 +0800 Subject: [PATCH 227/258] fix warnings --- docs/software/TODO.md | 20 ++++++++++++++++---- src/graphics/Screen.cpp | 2 ++ 2 files changed, 18 insertions(+), 4 deletions(-) diff --git a/docs/software/TODO.md b/docs/software/TODO.md index b26ce9b5b..a7d85dcfd 100644 --- a/docs/software/TODO.md +++ b/docs/software/TODO.md @@ -87,14 +87,26 @@ eink: * new battery level sensing * measure current draw * DONE: fix backlight -* USB is busted because of power enable mode? +* DONE - USB is busted because of power enable mode? +* test that board leaves bootloader always +* test USB - works in bootloader +* test LEDs +* Test BME280 +* test gps +* check GPS fast locking +* tested! dlora +* test eink backlight +* tested! eink +* test buttons +* test battery charging +* test serial flash +* send updated app and bootloader image * OHH BME280! THAT IS GREAT! * make new screen work, ask for datasheet * say I think you could ship this * leds seem busted -* usb doesn't stay connected -* check GPS works -* check GPS fast locking +* fix hw_model: "nrf52unknown" +* use larger icon for meshtastic logo * send email about variants & faster flash programming - https://github.com/geeksville/Meshtastic-esp32/commit/f110225173a77326aac029321cdb6491bfa640f6 * send PR for bootloader * fix nrf52 time/date diff --git a/src/graphics/Screen.cpp b/src/graphics/Screen.cpp index c0511a8c6..cfc059835 100644 --- a/src/graphics/Screen.cpp +++ b/src/graphics/Screen.cpp @@ -143,11 +143,13 @@ static void drawBootScreen(OLEDDisplay *display, OLEDDisplayUiState *state, int1 drawIconScreen(region, display, state, x, y); } +#ifdef HAS_EINK /// Used on eink displays while in deep sleep static void drawSleepScreen(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y) { drawIconScreen("Sleeping...", display, state, x, y); } +#endif static void drawPluginFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y) { From f8ec07209331657515f010b22227f9049c40b0fa Mon Sep 17 00:00:00 2001 From: Kevin Hester Date: Mon, 8 Mar 2021 17:10:48 +0800 Subject: [PATCH 228/258] make debug console stall until host has downloaded --- src/RedirectablePrint.cpp | 4 +++- src/main.cpp | 8 +++++++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/src/RedirectablePrint.cpp b/src/RedirectablePrint.cpp index fd634a99f..c3743b973 100644 --- a/src/RedirectablePrint.cpp +++ b/src/RedirectablePrint.cpp @@ -20,7 +20,7 @@ size_t RedirectablePrint::write(uint8_t c) { // Always send the characters to our segger JTAG debugger #ifdef SEGGER_STDOUT_CH - SEGGER_RTT_PutCharSkip(SEGGER_STDOUT_CH, c); + SEGGER_RTT_PutChar(SEGGER_STDOUT_CH, c); #endif dest->write(c); @@ -85,6 +85,8 @@ size_t RedirectablePrint::logDebug(const char *format, ...) auto thread = concurrency::OSThread::currentThread; if(thread) { print("["); + // printf("%p ", thread); + // assert(thread->ThreadName.length()); print(thread->ThreadName); print("] "); } diff --git a/src/main.cpp b/src/main.cpp index 495dc2f36..28ddb1bc1 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -279,7 +279,13 @@ void setup() concurrency::hasBeenSetup = true; #ifdef SEGGER_STDOUT_CH - SEGGER_RTT_ConfigUpBuffer(SEGGER_STDOUT_CH, NULL, NULL, 1024, SEGGER_RTT_MODE_NO_BLOCK_TRIM); + auto mode = true ? SEGGER_RTT_MODE_BLOCK_IF_FIFO_FULL : SEGGER_RTT_MODE_NO_BLOCK_TRIM; +#ifdef NRF52840_XXAA + auto buflen = 4096; // this board has a fair amount of ram +#else + auto buflen = 256; // this board has a fair amount of ram +#endif + SEGGER_RTT_ConfigUpBuffer(SEGGER_STDOUT_CH, NULL, NULL, buflen, mode); #endif #ifdef USE_SEGGER From 87ec7b09aa2bff015fc82a69182cdef25a20b3b0 Mon Sep 17 00:00:00 2001 From: Kevin Hester Date: Mon, 8 Mar 2021 18:12:21 +0800 Subject: [PATCH 229/258] add crude check for brownout --- src/mesh/generated/mesh.pb.h | 7 ++--- src/nrf52/main-nrf52.cpp | 52 +++++++++++++++++++++++++++++++++--- 2 files changed, 53 insertions(+), 6 deletions(-) diff --git a/src/mesh/generated/mesh.pb.h b/src/mesh/generated/mesh.pb.h index a8f36a140..b7df1079e 100644 --- a/src/mesh/generated/mesh.pb.h +++ b/src/mesh/generated/mesh.pb.h @@ -25,7 +25,8 @@ typedef enum _CriticalErrorCode { CriticalErrorCode_UBloxInitFailed = 5, CriticalErrorCode_NoAXP192 = 6, CriticalErrorCode_InvalidRadioSetting = 7, - CriticalErrorCode_TransmitFailed = 8 + CriticalErrorCode_TransmitFailed = 8, + CriticalErrorCode_Brownout = 9 } CriticalErrorCode; typedef enum _Routing_Error { @@ -177,8 +178,8 @@ typedef struct _ToRadio { #define _Constants_ARRAYSIZE ((Constants)(Constants_DATA_PAYLOAD_LEN+1)) #define _CriticalErrorCode_MIN CriticalErrorCode_None -#define _CriticalErrorCode_MAX CriticalErrorCode_TransmitFailed -#define _CriticalErrorCode_ARRAYSIZE ((CriticalErrorCode)(CriticalErrorCode_TransmitFailed+1)) +#define _CriticalErrorCode_MAX CriticalErrorCode_Brownout +#define _CriticalErrorCode_ARRAYSIZE ((CriticalErrorCode)(CriticalErrorCode_Brownout+1)) #define _Routing_Error_MIN Routing_Error_NONE #define _Routing_Error_MAX Routing_Error_TOO_LARGE diff --git a/src/nrf52/main-nrf52.cpp b/src/nrf52/main-nrf52.cpp index 8b7bb65b9..1ba0602b9 100644 --- a/src/nrf52/main-nrf52.cpp +++ b/src/nrf52/main-nrf52.cpp @@ -1,5 +1,6 @@ #include "NRF52Bluetooth.h" #include "configuration.h" +#include "error.h" #include "graphics/TFTDisplay.h" #include #include @@ -51,14 +52,14 @@ void getMacAddr(uint8_t *dmac) NRF52Bluetooth *nrf52Bluetooth; static bool bleOn = false; -static const bool enableBle = false; // Set to false for easier debugging +static const bool useSoftDevice = false; // Set to false for easier debugging void setBluetoothEnable(bool on) { if (on != bleOn) { if (on) { if (!nrf52Bluetooth) { - if (!enableBle) + if (!useSoftDevice) DEBUG_MSG("DISABLING NRF52 BLUETOOTH WHILE DEBUGGING\n"); else { nrf52Bluetooth = new NRF52Bluetooth(); @@ -87,6 +88,49 @@ int printf(const char *fmt, ...) #include "BQ25713.h" +void initBrownout() +{ + auto vccthresh = POWER_POFCON_THRESHOLD_V28; + auto vcchthresh = POWER_POFCON_THRESHOLDVDDH_V27; + + if (useSoftDevice) { + auto err_code = sd_power_pof_enable(POWER_POFCON_POF_Enabled); + assert(err_code == NRF_SUCCESS); + + err_code = sd_power_pof_threshold_set(vccthresh); + assert(err_code == NRF_SUCCESS); + } + else { + NRF_POWER->POFCON = POWER_POFCON_POF_Msk | (vccthresh << POWER_POFCON_THRESHOLD_Pos) | (vcchthresh << POWER_POFCON_THRESHOLDVDDH_Pos); + } +} + +void checkSDEvents() +{ + if (useSoftDevice) { + uint32_t evt; + while (NRF_ERROR_NOT_FOUND == sd_evt_get(&evt)) { + switch (evt) { + case NRF_EVT_POWER_FAILURE_WARNING: + recordCriticalError(CriticalErrorCode_Brownout); + break; + + default: + DEBUG_MSG("Unexpected SDevt %d\n", evt); + break; + } + } + } else { + if(NRF_POWER->EVENTS_POFWARN) + recordCriticalError(CriticalErrorCode_Brownout); + } +} + +void nrf52Loop() +{ + checkSDEvents(); +} + void nrf52Setup() { @@ -112,6 +156,8 @@ void nrf52Setup() // randomSeed(r); DEBUG_MSG("FIXME, call randomSeed\n"); // ::printf("TESTING PRINTF\n"); + + initBrownout(); } void cpuDeepSleep(uint64_t msecToWake) @@ -128,7 +174,7 @@ void cpuDeepSleep(uint64_t msecToWake) // https://devzone.nordicsemi.com/f/nordic-q-a/48919/ram-retention-settings-with-softdevice-enabled auto ok = sd_power_system_off(); - if(ok != NRF_SUCCESS) { + if (ok != NRF_SUCCESS) { DEBUG_MSG("FIXME: Ignoring soft device (EasyDMA pending?) and forcing system-off!\n"); NRF_POWER->SYSTEMOFF = 1; } From 2f7c2a2aead2a95e35c30741372cf13c138634eb Mon Sep 17 00:00:00 2001 From: Sacha Weatherstone Date: Tue, 9 Mar 2021 16:16:41 +1100 Subject: [PATCH 230/258] Update main.yml --- .github/workflows/main.yml | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 9c9b2fffd..dcbb213b5 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -7,11 +7,12 @@ jobs: setup: runs-on: ubuntu-latest steps: - - uses: actions/checkout@master - - name: Checkout submodules - uses: textbook/git-checkout-submodule-action@master + - name: Checkout code + uses: actions/checkout@v2 + with: + submodules: true - name: Setup Python - uses: actions/setup-python@master + uses: actions/setup-python@v2 with: python-version: 3.x - name: Install Platform IO @@ -31,4 +32,4 @@ jobs: - name: Build for lora-relay-v1 run: platformio run -e lora-relay-v1 - name: Build for linux - run: platformio run -e linux \ No newline at end of file + run: platformio run -e linux From 5835abbcf625de7c71ce4e70574278cf1480c99a Mon Sep 17 00:00:00 2001 From: Kevin Hester Date: Tue, 9 Mar 2021 15:06:28 +0800 Subject: [PATCH 231/258] fix eink leds --- variants/eink/variant.h | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/variants/eink/variant.h b/variants/eink/variant.h index 4cdb33e45..bf8a91680 100644 --- a/variants/eink/variant.h +++ b/variants/eink/variant.h @@ -99,16 +99,16 @@ extern "C" { #define NUM_ANALOG_OUTPUTS (0) // LEDs -#define PIN_LED1 (0 + 13) // red (confirmed on 1.0 board) -#define PIN_LED2 (0 + 14) // blue (seems busted!) -#define PIN_LED3 (0 + 15) // green (seems busted!) +#define PIN_LED1 (0 + 14) // 13 red (confirmed on 1.0 board) +#define PIN_LED2 (0 + 15) // 14 blue +#define PIN_LED3 (0 + 13) // 15 green #define LED_RED PIN_LED3 -#define LED_GREEN PIN_LED1 -#define LED_BLUE PIN_LED2 +#define LED_BLUE PIN_LED1 +#define LED_GREEN PIN_LED2 -#define LED_BUILTIN LED_GREEN -#define LED_CONN PIN_BLUE +#define LED_BUILTIN LED_BLUE +#define LED_CONN PIN_GREEN #define LED_STATE_ON 0 // State when LED is lit #define LED_INVERTED 1 @@ -190,7 +190,7 @@ External serial flash WP25R1635FZUIL0 // Internally the TTGO module hooks the SX1262-DIO2 in to control the TX/RX switch (which is the default for the sx1262interface // code) -// #define LORA_DISABLE_SENDING // Define this to disable transmission for testing (power testing etc...) +#define LORA_DISABLE_SENDING // Define this to disable transmission for testing (power testing etc...) /* * eink display pins From ecaae87b79f0c38f230673fac60ea65343df3c4f Mon Sep 17 00:00:00 2001 From: Kevin Hester Date: Tue, 9 Mar 2021 15:07:02 +0800 Subject: [PATCH 232/258] make screen optional --- src/plugins/NodeInfoPlugin.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/plugins/NodeInfoPlugin.cpp b/src/plugins/NodeInfoPlugin.cpp index f5f3ae194..5111d7b87 100644 --- a/src/plugins/NodeInfoPlugin.cpp +++ b/src/plugins/NodeInfoPlugin.cpp @@ -19,9 +19,11 @@ bool NodeInfoPlugin::handleReceivedProtobuf(const MeshPacket &mp, const User *pp // Show new nodes on LCD screen if (wasBroadcast) { String lcd = String("Joined: ") + p.long_name + "\n"; - screen->print(lcd.c_str()); + if(screen) + screen->print(lcd.c_str()); } + // DEBUG_MSG("did handleReceived\n"); return false; // Let others look at this message also if they want } From d841d86bbcf13435e2cf459688b205328eec84ad Mon Sep 17 00:00:00 2001 From: Kevin Hester Date: Tue, 9 Mar 2021 15:07:16 +0800 Subject: [PATCH 233/258] brownout detect --- src/main.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/main.cpp b/src/main.cpp index 28ddb1bc1..3282098ba 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -589,6 +589,9 @@ void loop() #ifndef NO_ESP32 esp32Loop(); #endif +#ifdef NRF52_SERIES + nrf52Loop(); +#endif // For debugging // if (rIf) ((RadioLibInterface *)rIf)->isActivelyReceiving(); From 5b0d8381b9b1fe9a3b51470b54b29297bd1f3f17 Mon Sep 17 00:00:00 2001 From: Kevin Hester Date: Tue, 9 Mar 2021 15:07:26 +0800 Subject: [PATCH 234/258] fxi log formatting --- src/graphics/Screen.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/graphics/Screen.cpp b/src/graphics/Screen.cpp index cfc059835..e341aea0b 100644 --- a/src/graphics/Screen.cpp +++ b/src/graphics/Screen.cpp @@ -852,7 +852,7 @@ int32_t Screen::runOnce() free(cmd.print_text); break; default: - DEBUG_MSG("BUG: invalid cmd"); + DEBUG_MSG("BUG: invalid cmd\n"); } } From 772f2a15fffc0c528f71bc7bebaa4aa035d22b75 Mon Sep 17 00:00:00 2001 From: Kevin Hester Date: Tue, 9 Mar 2021 16:45:40 +0800 Subject: [PATCH 235/258] check more error codes --- proto | 2 +- src/RedirectablePrint.cpp | 77 +++++++++++---------- src/RedirectablePrint.h | 2 + src/concurrency/BinarySemaphoreFreeRTOS.cpp | 2 + src/mesh/MemoryPool.h | 11 ++- 5 files changed, 54 insertions(+), 40 deletions(-) diff --git a/proto b/proto index 7c025b9a4..e56f2770c 160000 --- a/proto +++ b/proto @@ -1 +1 @@ -Subproject commit 7c025b9a4d54bb410ec17ee653122861b413f177 +Subproject commit e56f2770c33216ba94f289e2fb7f0b2dfd33aca2 diff --git a/src/RedirectablePrint.cpp b/src/RedirectablePrint.cpp index c3743b973..4c460d77f 100644 --- a/src/RedirectablePrint.cpp +++ b/src/RedirectablePrint.cpp @@ -1,9 +1,9 @@ #include "RedirectablePrint.h" +#include "concurrency/OSThread.h" #include "configuration.h" #include #include #include -#include "concurrency/OSThread.h" /** * A printer that doesn't go anywhere @@ -38,7 +38,7 @@ size_t RedirectablePrint::vprintf(const char *format, va_list arg) va_end(arg); return 0; }; - if (len >= (int) printBufLen) { + if (len >= (int)printBufLen) { delete[] printBuf; printBufLen *= 2; printBuf = new char[printBufLen]; @@ -55,47 +55,52 @@ size_t RedirectablePrint::vprintf(const char *format, va_list arg) size_t RedirectablePrint::logDebug(const char *format, ...) { - va_list arg; - va_start(arg, format); - - // Cope with 0 len format strings, but look for new line terminator - bool hasNewline = *format && format[strlen(format) - 1] == '\n'; - size_t r = 0; - // If we are the first message on a report, include the header - if (!isContinuationMessage) { - struct timeval tv; - if (!gettimeofday(&tv, NULL)) { - long hms = tv.tv_sec % SEC_PER_DAY; - //hms += tz.tz_dsttime * SEC_PER_HOUR; - //hms -= tz.tz_minuteswest * SEC_PER_MIN; - // mod `hms` to ensure in positive range of [0...SEC_PER_DAY) - hms = (hms + SEC_PER_DAY) % SEC_PER_DAY; + if (!inDebugPrint) { + inDebugPrint = true; - // Tear apart hms into h:m:s - int hour = hms / SEC_PER_HOUR; - int min = (hms % SEC_PER_HOUR) / SEC_PER_MIN; - int sec = (hms % SEC_PER_HOUR) % SEC_PER_MIN; // or hms % SEC_PER_MIN + va_list arg; + va_start(arg, format); - r += printf("%02d:%02d:%02d %u ", hour, min, sec, millis() / 1000); - } else - r += printf("??:??:?? %u ", millis() / 1000); + // Cope with 0 len format strings, but look for new line terminator + bool hasNewline = *format && format[strlen(format) - 1] == '\n'; - auto thread = concurrency::OSThread::currentThread; - if(thread) { - print("["); - // printf("%p ", thread); - // assert(thread->ThreadName.length()); - print(thread->ThreadName); - print("] "); + // If we are the first message on a report, include the header + if (!isContinuationMessage) { + struct timeval tv; + if (!gettimeofday(&tv, NULL)) { + long hms = tv.tv_sec % SEC_PER_DAY; + // hms += tz.tz_dsttime * SEC_PER_HOUR; + // hms -= tz.tz_minuteswest * SEC_PER_MIN; + // mod `hms` to ensure in positive range of [0...SEC_PER_DAY) + hms = (hms + SEC_PER_DAY) % SEC_PER_DAY; + + // Tear apart hms into h:m:s + int hour = hms / SEC_PER_HOUR; + int min = (hms % SEC_PER_HOUR) / SEC_PER_MIN; + int sec = (hms % SEC_PER_HOUR) % SEC_PER_MIN; // or hms % SEC_PER_MIN + + r += printf("%02d:%02d:%02d %u ", hour, min, sec, millis() / 1000); + } else + r += printf("??:??:?? %u ", millis() / 1000); + + auto thread = concurrency::OSThread::currentThread; + if (thread) { + print("["); + // printf("%p ", thread); + // assert(thread->ThreadName.length()); + print(thread->ThreadName); + print("] "); + } } + + r += vprintf(format, arg); + va_end(arg); + + isContinuationMessage = !hasNewline; + inDebugPrint = false; } - r += vprintf(format, arg); - va_end(arg); - - isContinuationMessage = !hasNewline; - return r; } \ No newline at end of file diff --git a/src/RedirectablePrint.h b/src/RedirectablePrint.h index ca208612c..1eb60199b 100644 --- a/src/RedirectablePrint.h +++ b/src/RedirectablePrint.h @@ -19,6 +19,8 @@ class RedirectablePrint : public Print /// Used to allow multiple logDebug messages to appear on a single log line bool isContinuationMessage = false; + volatile bool inDebugPrint = false; + public: RedirectablePrint(Print *_dest) : dest(_dest) {} diff --git a/src/concurrency/BinarySemaphoreFreeRTOS.cpp b/src/concurrency/BinarySemaphoreFreeRTOS.cpp index 983ee0955..3d8097455 100644 --- a/src/concurrency/BinarySemaphoreFreeRTOS.cpp +++ b/src/concurrency/BinarySemaphoreFreeRTOS.cpp @@ -1,5 +1,6 @@ #include "concurrency/BinarySemaphoreFreeRTOS.h" #include "configuration.h" +#include #ifdef HAS_FREE_RTOS @@ -9,6 +10,7 @@ namespace concurrency BinarySemaphoreFreeRTOS::BinarySemaphoreFreeRTOS() { semaphore = xSemaphoreCreateBinary(); + assert(semaphore); } BinarySemaphoreFreeRTOS::~BinarySemaphoreFreeRTOS() diff --git a/src/mesh/MemoryPool.h b/src/mesh/MemoryPool.h index dc6305d17..8023aa6bc 100644 --- a/src/mesh/MemoryPool.h +++ b/src/mesh/MemoryPool.h @@ -101,25 +101,30 @@ template class MemoryPool : public Allocator /// Return a buffer for use by others virtual void release(T *p) { - assert(dead.enqueue(p, 0)); assert(p >= buf && (size_t)(p - buf) < maxElements); // sanity check to make sure a programmer didn't free something that didn't come from this pool + assert(dead.enqueue(p, 0)); } #ifdef HAS_FREE_RTOS /// Return a buffer from an ISR, if higherPriWoken is set to true you have some work to do ;-) void releaseFromISR(T *p, BaseType_t *higherPriWoken) { - assert(dead.enqueueFromISR(p, higherPriWoken)); assert(p >= buf && (size_t)(p - buf) < maxElements); // sanity check to make sure a programmer didn't free something that didn't come from this pool + assert(dead.enqueueFromISR(p, higherPriWoken)); } #endif protected: /// Return a queable object which has been prefilled with zeros - allow timeout to wait for available buffers (you /// probably don't want this version). - virtual T *alloc(TickType_t maxWait) { return dead.dequeuePtr(maxWait); } + virtual T *alloc(TickType_t maxWait) + { + T *p = dead.dequeuePtr(maxWait); + assert(p); + return p; + } }; From 58715f454c1ccbcfa0771a5ab6c6f5e483ebc9a2 Mon Sep 17 00:00:00 2001 From: Kevin Hester Date: Wed, 10 Mar 2021 15:21:30 +0800 Subject: [PATCH 236/258] add consolePrintf for C style code --- src/SerialConsole.cpp | 12 ++++++++++-- src/SerialConsole.h | 3 +++ 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/src/SerialConsole.cpp b/src/SerialConsole.cpp index 9bb539fa5..ad1cf642a 100644 --- a/src/SerialConsole.cpp +++ b/src/SerialConsole.cpp @@ -1,13 +1,21 @@ #include "SerialConsole.h" +#include "NodeDB.h" #include "PowerFSM.h" #include "configuration.h" -#include "NodeDB.h" #include #define Port Serial SerialConsole console; +void consolePrintf(const char *format, ...) +{ + va_list arg; + va_start(arg, format); + console.vprintf(format, arg); + va_end(arg); +} + SerialConsole::SerialConsole() : StreamAPI(&Port), RedirectablePrint(&Port) { canWrite = false; // We don't send packets to our port until it has talked to us first @@ -29,7 +37,7 @@ void SerialConsole::init() void SerialConsole::handleToRadio(const uint8_t *buf, size_t len) { // Turn off debug serial printing once the API is activated, because other threads could print and corrupt packets - if(!radioConfig.preferences.debug_log_enabled) + if (!radioConfig.preferences.debug_log_enabled) setDestination(&noopPrint); canWrite = true; diff --git a/src/SerialConsole.h b/src/SerialConsole.h index 17cb16943..b4f076286 100644 --- a/src/SerialConsole.h +++ b/src/SerialConsole.h @@ -32,4 +32,7 @@ class SerialConsole : public StreamAPI, public RedirectablePrint virtual void onConnectionChanged(bool connected); }; +// A simple wrapper to allow non class aware code write to the console +void consolePrintf(const char *format, ...); + extern SerialConsole console; From 217bd934d72f1f19ee51e3455561ddf95bcee899 Mon Sep 17 00:00:00 2001 From: Kevin Hester Date: Wed, 10 Mar 2021 15:21:54 +0800 Subject: [PATCH 237/258] fix GPS fixme wrt deletion --- src/gps/GPS.cpp | 22 +++++++++++++++------- src/gps/GPS.h | 2 +- 2 files changed, 16 insertions(+), 8 deletions(-) diff --git a/src/gps/GPS.cpp b/src/gps/GPS.cpp index 04aa2c7af..abf7fc270 100644 --- a/src/gps/GPS.cpp +++ b/src/gps/GPS.cpp @@ -25,7 +25,7 @@ uint8_t GPS::i2cAddress = 0; GPS *gps; -/// Multiple GPS instances might use the same serial port (in sequence), but we can +/// Multiple GPS instances might use the same serial port (in sequence), but we can /// only init that port once. static bool didSerialInit; @@ -33,7 +33,7 @@ bool GPS::setupGPS() { if (_serial_gps && !didSerialInit) { didSerialInit = true; - + #ifdef GPS_RX_PIN _serial_gps->begin(GPS_BAUDRATE, SERIAL_8N1, GPS_RX_PIN, GPS_TX_PIN); #else @@ -73,6 +73,13 @@ bool GPS::setup() return ok; } +GPS::~GPS() +{ + // we really should unregister our sleep observer + notifySleepObserver.unobserve(); + notifyDeepSleepObserver.unobserve(); +} + // Allow defining the polarity of the WAKE output. default is active high #ifndef GPS_WAKE_ACTIVE #define GPS_WAKE_ACTIVE 1 @@ -86,8 +93,8 @@ void GPS::wake() #endif } - -void GPS::sleep() { +void GPS::sleep() +{ #ifdef PIN_GPS_WAKE digitalWrite(PIN_GPS_WAKE, GPS_WAKE_ACTIVE ? 0 : 1); pinMode(PIN_GPS_WAKE, OUTPUT); @@ -158,7 +165,8 @@ uint32_t GPS::getWakeTime() const return t; // already maxint if (t == 0) - t = radioConfig.preferences.is_router ? 5 * 60 : 15 * 60; // Allow up to 15 mins for each attempt (probably will be much less if we can find sats) or less if a router + t = radioConfig.preferences.is_router ? 5 * 60 : 15 * 60; // Allow up to 15 mins for each attempt (probably will be much + // less if we can find sats) or less if a router t *= 1000; // msecs @@ -179,8 +187,8 @@ uint32_t GPS::getSleepTime() const if (t == UINT32_MAX) return t; // already maxint - if (t == 0) // default - unset in preferences - t = radioConfig.preferences.is_router ? 24 * 60 * 60 : 2 * 60; // 2 mins or once per day for routers + if (t == 0) // default - unset in preferences + t = radioConfig.preferences.is_router ? 24 * 60 * 60 : 2 * 60; // 2 mins or once per day for routers t *= 1000; diff --git a/src/gps/GPS.h b/src/gps/GPS.h index eca2962d2..9d25b2f83 100644 --- a/src/gps/GPS.h +++ b/src/gps/GPS.h @@ -47,7 +47,7 @@ class GPS : private concurrency::OSThread GPS() : concurrency::OSThread("GPS") {} - virtual ~GPS() {} // FIXME, we really should unregister our sleep observer + virtual ~GPS(); /** We will notify this observable anytime GPS state has changed meaningfully */ Observable newStatus; From 6e37fe63434813a83de4d18f0f1a2f6d56693a1a Mon Sep 17 00:00:00 2001 From: Kevin Hester Date: Wed, 10 Mar 2021 15:24:00 +0800 Subject: [PATCH 238/258] turn radio back on --- variants/eink/variant.h | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/variants/eink/variant.h b/variants/eink/variant.h index bf8a91680..66a42421f 100644 --- a/variants/eink/variant.h +++ b/variants/eink/variant.h @@ -190,7 +190,10 @@ External serial flash WP25R1635FZUIL0 // Internally the TTGO module hooks the SX1262-DIO2 in to control the TX/RX switch (which is the default for the sx1262interface // code) -#define LORA_DISABLE_SENDING // Define this to disable transmission for testing (power testing etc...) +// #define LORA_DISABLE_SENDING // Define this to disable transmission for testing (power testing etc...) + +// #undef SX1262_CS +// #define USE_SIM_RADIO // define to not use the lora radio hardware at all /* * eink display pins From f55ac8e9c937210a25ff03163ea30078b4613704 Mon Sep 17 00:00:00 2001 From: Kevin Hester Date: Wed, 10 Mar 2021 15:29:25 +0800 Subject: [PATCH 239/258] turn off (buggy) custom_fields in tinygps, and used fixed version of lib --- docs/software/TODO.md | 5 ++++- platformio.ini | 11 +++++++---- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/docs/software/TODO.md b/docs/software/TODO.md index a7d85dcfd..1649250de 100644 --- a/docs/software/TODO.md +++ b/docs/software/TODO.md @@ -84,10 +84,13 @@ You probably don't care about this section - skip to the next one. eink: +* DONE check email of reported issues +* DONE turn off vbus driving (in bootloader) * new battery level sensing -* measure current draw +* current draw no good * DONE: fix backlight * DONE - USB is busted because of power enable mode? +* test CPU voltage? something is bad with RAM (removing eink module does not help) * test that board leaves bootloader always * test USB - works in bootloader * test LEDs diff --git a/platformio.ini b/platformio.ini index aeab4f65b..742bc6db6 100644 --- a/platformio.ini +++ b/platformio.ini @@ -9,13 +9,14 @@ ; https://docs.platformio.org/page/projectconf.html [platformio] -;default_envs = tbeam +default_envs = tbeam ;default_envs = tbeam0.7 ;default_envs = heltec ;default_envs = tlora-v1 ;default_envs = tlora-v2 ;default_envs = lora-relay-v1 # nrf board -default_envs = eink +;default_envs = eink +;default_envs = nrf52840dk-geeksville ;default_envs = linux # lora-relay-v1 # nrf52840dk-geeksville # linux # or if you'd like to change the default to something like lora-relay-v1 put that here [common] @@ -33,6 +34,8 @@ default_envs = eink extra_scripts = bin/platformio-custom.py ; note: we add src to our include search path so that lmic_project_config can override +; note: TINYGPS_OPTION_NO_CUSTOM_FIELDS is VERY important. We don't use custom fields and somewhere in that pile +; of code is a heap corruption bug! ; FIXME: fix lib/BluetoothOTA dependency back on src/ so we can remove -Isrc build_flags = -Wno-missing-field-initializers -Wno-format @@ -40,7 +43,7 @@ build_flags = -Wno-missing-field-initializers -DHW_VERSION_${sysenv.COUNTRY} -DHW_VERSION=${sysenv.HW_VERSION} -DUSE_THREAD_NAMES - -DTINYGPSPLUS_OPTION_NO_CUSTOM_FIELDS + -DTINYGPS_OPTION_NO_CUSTOM_FIELDS ; leave this commented out to avoid breaking Windows ;upload_port = /dev/ttyUSB0 @@ -74,7 +77,7 @@ lib_deps = https://github.com/meshtastic/arduino-fsm.git#2f106146071fc7bc620e1e8d4b88dc4e0266ce39 https://github.com/meshtastic/SparkFun_Ublox_Arduino_Library.git#31015a55e630a2df77d9d714669c621a5bf355ad https://github.com/meshtastic/RadioLib.git#07de964e929238949035fb0d5887026a3058df1a - https://github.com/meshtastic/TinyGPSPlus.git#9c1d584d2469523381e077b0b9c1bf868d6c0206 + https://github.com/meshtastic/TinyGPSPlus.git#f0f47067ef2f67c856475933188251c1ef615e79 https://github.com/meshtastic/AXP202X_Library.git#8404abb6d4b486748636bc6ad72d2a47baaf5460 Wire ; explicitly needed here because the AXP202 library forgets to add it SPI From 590e1471862f6d976a856292679ac54c0cf3a68e Mon Sep 17 00:00:00 2001 From: Kevin Hester Date: Thu, 11 Mar 2021 09:59:54 +0800 Subject: [PATCH 240/258] todo updates --- bin/install-eink.sh | 4 +++- docs/software/TODO.md | 5 +++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/bin/install-eink.sh b/bin/install-eink.sh index 5bfb6f1a7..b1c3d87cc 100755 --- a/bin/install-eink.sh +++ b/bin/install-eink.sh @@ -6,6 +6,8 @@ BOOTDIR=/home/kevinh/development/meshtastic/Adafruit_nRF52_Bootloader nrfjprog --eraseall -f nrf52 +# to get tool run "sudo apt-get install srecord" + # this generates an intel hex file that can be programmed into a NRF52 to tell the adafruit bootloader that the current app image is valid # Bootloader settings are at BOOTLOADER_SETTINGS (rw) : ORIGIN = 0xFF000, LENGTH = 0x1000 # first 4 bytes should be 0x01 to indicate valid app image @@ -14,7 +16,7 @@ echo "01 00 00 00 00 00 00 00" | xxd -r -p - >/tmp/bootconf.bin srec_cat /tmp/bootconf.bin -binary -offset 0xff000 -output /tmp/bootconf.hex -intel echo Generating merged hex file -mergehex -m $BOOTDIR/_build/build-ttgo_eink/ttgo_eink_bootloader-0.3.2-125-gf38f8f4-dirty_s140_6.1.1.hex .pio/build/eink/firmware.hex /tmp/bootconf.hex -o ttgo_eink_full.hex +mergehex -m $BOOTDIR/_build/build-ttgo_eink/ttgo_eink_bootloader-0.3.2-213-gf67f592-dirty_s140_6.1.1.hex .pio/build/eink/firmware.hex /tmp/bootconf.hex -o ttgo_eink_full.hex echo Telling bootloader app region is valid and telling CPU to run nrfjprog --program ttgo_eink_full.hex -f nrf52 --reset diff --git a/docs/software/TODO.md b/docs/software/TODO.md index 1649250de..eb34bbba3 100644 --- a/docs/software/TODO.md +++ b/docs/software/TODO.md @@ -40,6 +40,8 @@ You probably don't care about this section - skip to the next one. * DONE warn in android app about unset regions * DONE use set-channel from android * DONE add gui in android app for setting region +* clean up python channel usage +* use bindToChannel to limit admin access for remote nodes * make python tests more exhaustive * pick default random admin key * exclude admin channels from URL? @@ -51,6 +53,7 @@ You probably don't care about this section - skip to the next one. * stress test multi channel * investigate @mc-hamster report of heap corruption * DONE use set-user from android +* generalize the concept of "shortstrings" use it for both PSKs and well known channel names. Possibly use a ShortString class. * use portuino TCP connection to debug with python API * document the relationship between want_response (indicating remote node received it) and want_ack (indicating that this message should be sent reliably - and also get acks from the first rx node and naks if it is never delivered) * DONE android should stop fetching channels once we've reached our first empty channel definition (hasSettings == true) @@ -80,6 +83,8 @@ You probably don't care about this section - skip to the next one. * DONE move setCrypto call into packet send and packet decode code * implement 'small location diffs' change * move battery level out of position? +* consider "A special exception (FIXME, not sure if this is a good idea) - packets that arrive on the local interface + are allowed on any channel (this lets the local user do anything)." * DOUBLE CHECK android app can still upgrade 1.1 and 1.0 loads eink: From 68781492adaac223fa20aedf0405925eb0868f3d Mon Sep 17 00:00:00 2001 From: Kevin Hester Date: Thu, 11 Mar 2021 10:00:08 +0800 Subject: [PATCH 241/258] don't block on segger console --- src/main.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main.cpp b/src/main.cpp index 3282098ba..d4eaafae2 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -279,7 +279,7 @@ void setup() concurrency::hasBeenSetup = true; #ifdef SEGGER_STDOUT_CH - auto mode = true ? SEGGER_RTT_MODE_BLOCK_IF_FIFO_FULL : SEGGER_RTT_MODE_NO_BLOCK_TRIM; + auto mode = false ? SEGGER_RTT_MODE_BLOCK_IF_FIFO_FULL : SEGGER_RTT_MODE_NO_BLOCK_TRIM; #ifdef NRF52840_XXAA auto buflen = 4096; // this board has a fair amount of ram #else From 959b540c0241eb962ff2a4f469a3718a56bb5112 Mon Sep 17 00:00:00 2001 From: Kevin Hester Date: Thu, 11 Mar 2021 10:01:57 +0800 Subject: [PATCH 242/258] begin restricting admin ops to the admin channel --- src/mesh/MeshPlugin.cpp | 23 ++++++++++++++++------- src/mesh/MeshPlugin.h | 31 ++++++++++++++++++------------- src/plugins/AdminPlugin.cpp | 8 +++++--- 3 files changed, 39 insertions(+), 23 deletions(-) diff --git a/src/mesh/MeshPlugin.cpp b/src/mesh/MeshPlugin.cpp index e17cc5475..68a63116e 100644 --- a/src/mesh/MeshPlugin.cpp +++ b/src/mesh/MeshPlugin.cpp @@ -1,4 +1,5 @@ #include "MeshPlugin.h" +#include "Channels.h" #include "MeshService.h" #include "NodeDB.h" #include @@ -11,7 +12,7 @@ const MeshPacket *MeshPlugin::currentRequest; * If any of the current chain of plugins has already sent a reply, it will be here. This is useful to allow * the RoutingPlugin to avoid sending redundant acks */ - MeshPacket *MeshPlugin::currentReply; +MeshPacket *MeshPlugin::currentReply; MeshPlugin::MeshPlugin(const char *_name) : name(_name) { @@ -46,8 +47,15 @@ void MeshPlugin::callPlugins(const MeshPacket &mp) pi.currentRequest = ∓ - // We only call plugins that are interested in the packet (and the message is destined to us or we are promiscious) - bool wantsPacket = (pi.isPromiscuous || toUs) && pi.wantPacket(&mp); + /// received channel + auto ch = channels.getByIndex(mp.channel); + assert(ch.has_settings); + + /// Is the channel this packet arrived on acceptable? (security check) + bool rxChannelOk = !pi.boundChannel || (mp.from == 0) || (strcmp(ch.settings.name, pi.boundChannel) == 0); + + /// We only call plugins that are interested in the packet (and the message is destined to us or we are promiscious) + bool wantsPacket = rxChannelOk && (pi.isPromiscuous || toUs) && pi.wantPacket(&mp); // DEBUG_MSG("Plugin %s wantsPacket=%d\n", pi.name, wantsPacket); if (wantsPacket) { pluginFound = true; @@ -76,8 +84,8 @@ void MeshPlugin::callPlugins(const MeshPacket &mp) pi.currentRequest = NULL; } - if(currentReply) { - DEBUG_MSG("Sending response\n"); + if (currentReply) { + DEBUG_MSG("Sending response\n"); service.sendToMesh(currentReply); currentReply = NULL; } @@ -95,7 +103,7 @@ void MeshPlugin::sendResponse(const MeshPacket &req) auto r = allocReply(); if (r) { setReplyTo(r, req); - currentReply = r; + currentReply = r; } else { // Ignore - this is now expected behavior for routing plugin (because it ignores some replies) // DEBUG_MSG("WARNING: Client requested response but this plugin did not provide\n"); @@ -109,10 +117,11 @@ void setReplyTo(MeshPacket *p, const MeshPacket &to) { assert(p->which_payloadVariant == MeshPacket_decoded_tag); // Should already be set by now p->to = getFrom(&to); + p->channel = to.channel; // Use the same channel that the request came in on // No need for an ack if we are just delivering locally (it just generates an ignored ack) p->want_ack = (to.from != 0) ? to.want_ack : false; - if(p->priority == MeshPacket_Priority_UNSET) + if (p->priority == MeshPacket_Priority_UNSET) p->priority = MeshPacket_Priority_RELIABLE; p->decoded.request_id = to.id; } diff --git a/src/mesh/MeshPlugin.h b/src/mesh/MeshPlugin.h index 7234b6b0a..dc905a0e5 100644 --- a/src/mesh/MeshPlugin.h +++ b/src/mesh/MeshPlugin.h @@ -1,9 +1,9 @@ #pragma once #include "mesh/MeshTypes.h" -#include #include #include +#include /** A baseclass for any mesh "plugin". * * A plugin allows you to add new features to meshtastic device code, without needing to know messaging details. @@ -16,7 +16,7 @@ */ class MeshPlugin { - static std::vector *plugins; + static std::vector *plugins; public: /** Constructor @@ -37,16 +37,24 @@ class MeshPlugin protected: const char *name; - /* Most plugins only care about packets that are destined for their node (i.e. broadcasts or has their node as the specific recipient) - But some plugs might want to 'sniff' packets that are merely being routed (passing through the current node). Those plugins can set this to - true and their handleReceived() will be called for every packet. + /* Most plugins only care about packets that are destined for their node (i.e. broadcasts or has their node as the specific + recipient) But some plugs might want to 'sniff' packets that are merely being routed (passing through the current node). Those + plugins can set this to true and their handleReceived() will be called for every packet. */ bool isPromiscuous = false; + /** If a bound channel name is set, we will only accept received packets that come in on that channel. + * A special exception (FIXME, not sure if this is a good idea) - packets that arrive on the local interface + * are allowed on any channel (this lets the local user do anything). + * + * We will send responses on the same channel that the request arrived on. + */ + const char *boundChannel = NULL; + /** * If this plugin is currently handling a request currentRequest will be preset * to the packet with the request. This is mostly useful for reply handlers. - * + * * Note: this can be static because we are guaranteed to be processing only one * plugin at a time. */ @@ -78,16 +86,13 @@ class MeshPlugin */ virtual bool wantUIFrame() { return false; } - - private: - /** - * If any of the current chain of plugins has already sent a reply, it will be here. This is useful to allow + * If any of the current chain of plugins has already sent a reply, it will be here. This is useful to allow * the RoutingPlugin to avoid sending redundant acks */ static MeshPacket *currentReply; - friend class ReliableRouter; + friend class ReliableRouter; /** Messages can be received that have the want_response bit set. If set, this callback will be invoked * so that subclasses can (optionally) send a response back to the original sender. This method calls allocReply() @@ -96,7 +101,7 @@ class MeshPlugin void sendResponse(const MeshPacket &req); }; -/** set the destination and packet parameters of packet p intended as a reply to a particular "to" packet +/** set the destination and packet parameters of packet p intended as a reply to a particular "to" packet * This ensures that if the request packet was sent reliably, the reply is sent that way as well. -*/ + */ void setReplyTo(MeshPacket *p, const MeshPacket &to); \ No newline at end of file diff --git a/src/plugins/AdminPlugin.cpp b/src/plugins/AdminPlugin.cpp index 7e0a67074..f45f61655 100644 --- a/src/plugins/AdminPlugin.cpp +++ b/src/plugins/AdminPlugin.cpp @@ -8,8 +8,9 @@ AdminPlugin *adminPlugin; -void AdminPlugin::handleGetChannel(const MeshPacket &req, uint32_t channelIndex) { - if (req.decoded.want_response) { +void AdminPlugin::handleGetChannel(const MeshPacket &req, uint32_t channelIndex) +{ + if (req.decoded.want_response) { // We create the reply here AdminMessage r = AdminMessage_init_default; r.get_channel_response = channels.getByIndex(channelIndex); @@ -121,5 +122,6 @@ MeshPacket *AdminPlugin::allocReply() AdminPlugin::AdminPlugin() : ProtobufPlugin("Admin", PortNum_ADMIN_APP, AdminMessage_fields) { - // FIXME, restrict to the admin channel for rx + // restrict to the admin channel for rx + boundChannel = "admin"; } From ab9fe42f58f0c82db43b7c14b2e7cbfa3ea56c2c Mon Sep 17 00:00:00 2001 From: Kevin Hester Date: Thu, 11 Mar 2021 13:02:00 +0800 Subject: [PATCH 243/258] wip - move channels --- docs/software/TODO.md | 7 +-- proto | 2 +- src/mesh/Channels.cpp | 14 ++--- src/mesh/Channels.h | 2 +- src/mesh/NodeDB.cpp | 86 ++++++++++++++++++++---------- src/mesh/NodeDB.h | 5 +- src/mesh/PhoneAPI.cpp | 4 +- src/mesh/PhoneAPI.h | 2 +- src/mesh/generated/admin.pb.h | 8 ++- src/mesh/generated/channel.pb.h | 6 +-- src/mesh/generated/deviceonly.pb.c | 3 ++ src/mesh/generated/deviceonly.pb.h | 36 +++++++------ src/mesh/mesh-pb-constants.h | 2 +- src/plugins/AdminPlugin.cpp | 2 +- 14 files changed, 113 insertions(+), 66 deletions(-) diff --git a/docs/software/TODO.md b/docs/software/TODO.md index eb34bbba3..43ba66477 100644 --- a/docs/software/TODO.md +++ b/docs/software/TODO.md @@ -40,8 +40,9 @@ You probably don't care about this section - skip to the next one. * DONE warn in android app about unset regions * DONE use set-channel from android * DONE add gui in android app for setting region -* clean up python channel usage -* use bindToChannel to limit admin access for remote nodes +* DONE clean up python channel usage +* DONE use bindToChannel to limit admin access for remote nodes +* move channels and radio config out of device settings * make python tests more exhaustive * pick default random admin key * exclude admin channels from URL? @@ -84,7 +85,7 @@ You probably don't care about this section - skip to the next one. * implement 'small location diffs' change * move battery level out of position? * consider "A special exception (FIXME, not sure if this is a good idea) - packets that arrive on the local interface - are allowed on any channel (this lets the local user do anything)." + are allowed on any channel (this lets the local user do anything)." Probably by adding a "secure_local_interface" settings bool. * DOUBLE CHECK android app can still upgrade 1.1 and 1.0 loads eink: diff --git a/proto b/proto index e56f2770c..e6e1c5a60 160000 --- a/proto +++ b/proto @@ -1 +1 @@ -Subproject commit e56f2770c33216ba94f289e2fb7f0b2dfd33aca2 +Subproject commit e6e1c5a600147428af553304b47f25f21492965d diff --git a/src/mesh/Channels.cpp b/src/mesh/Channels.cpp index ab0a64b37..2a04c9a7b 100644 --- a/src/mesh/Channels.cpp +++ b/src/mesh/Channels.cpp @@ -161,8 +161,8 @@ int16_t Channels::setCrypto(ChannelIndex chIndex) void Channels::initDefaults() { - devicestate.channels_count = MAX_NUM_CHANNELS; - for (int i = 0; i < devicestate.channels_count; i++) + channelFile.channels_count = MAX_NUM_CHANNELS; + for (int i = 0; i < channelFile.channels_count; i++) fixupChannel(i); initDefaultChannel(0); } @@ -170,7 +170,7 @@ void Channels::initDefaults() void Channels::onConfigChanged() { // Make sure the phone hasn't mucked anything up - for (int i = 0; i < devicestate.channels_count; i++) { + for (int i = 0; i < channelFile.channels_count; i++) { Channel &ch = fixupChannel(i); if (ch.role == Channel_Role_PRIMARY) @@ -180,8 +180,8 @@ void Channels::onConfigChanged() Channel &Channels::getByIndex(ChannelIndex chIndex) { - assert(chIndex < devicestate.channels_count); - Channel *ch = devicestate.channels + chIndex; + assert(chIndex < channelFile.channels_count); + Channel *ch = channelFile.channels + chIndex; return *ch; } @@ -192,8 +192,8 @@ void Channels::setChannel(const Channel &c) // if this is the new primary, demote any existing roles if (c.role == Channel_Role_PRIMARY) for (int i = 0; i < getNumChannels(); i++) - if (devicestate.channels[i].role == Channel_Role_PRIMARY) - devicestate.channels[i].role = Channel_Role_SECONDARY; + if (channelFile.channels[i].role == Channel_Role_PRIMARY) + channelFile.channels[i].role = Channel_Role_SECONDARY; old = c; // slam in the new settings/role } diff --git a/src/mesh/Channels.h b/src/mesh/Channels.h index 547b0a581..4fbafe42b 100644 --- a/src/mesh/Channels.h +++ b/src/mesh/Channels.h @@ -44,7 +44,7 @@ class Channels /** The index of the primary channel */ ChannelIndex getPrimaryIndex() const { return primaryIndex; } - ChannelIndex getNumChannels() { return devicestate.channels_count; } + ChannelIndex getNumChannels() { return channelFile.channels_count; } /** * Generate a short suffix used to disambiguate channels that might have the same "name" entered by the human but different diff --git a/src/mesh/NodeDB.cpp b/src/mesh/NodeDB.cpp index 166e159f2..c4d58d4c3 100644 --- a/src/mesh/NodeDB.cpp +++ b/src/mesh/NodeDB.cpp @@ -30,7 +30,8 @@ NodeDB nodeDB; // we have plenty of ram so statically alloc this tempbuf (for now) EXT_RAM_ATTR DeviceState devicestate; MyNodeInfo &myNodeInfo = devicestate.my_node; -RadioConfig &radioConfig = devicestate.radio; +RadioConfig radioConfig; +ChannelFile channelFile; /** The current change # for radio settings. Starts at 0 on boot and any time the radio settings * might have changed is incremented. Allows others to detect they might now be on a new channel. @@ -67,10 +68,11 @@ NodeNum displayedNodeNum; NodeDB::NodeDB() : nodes(devicestate.node_db), numNodes(&devicestate.node_db_count) {} /** - * Most (but not always) of the time we want to treat packets 'from' the local phone (where from == 0), as if they originated on the local node. - * If from is zero this function returns our node number instead + * Most (but not always) of the time we want to treat packets 'from' the local phone (where from == 0), as if they originated on + * the local node. If from is zero this function returns our node number instead */ -NodeNum getFrom(const MeshPacket *p) { +NodeNum getFrom(const MeshPacket *p) +{ return (p->from == 0) ? nodeDB.getNodeNum() : p->from; } @@ -84,7 +86,7 @@ bool NodeDB::resetRadioConfig() DEBUG_MSG("Performing factory reset!\n"); installDefaultDeviceState(); didFactoryReset = true; - } else if (devicestate.channels_count == 0) { + } else if (channelFile.channels_count == 0) { DEBUG_MSG("Setting default channel and radio preferences!\n"); channels.initDefaults(); @@ -117,6 +119,18 @@ bool NodeDB::resetRadioConfig() return didFactoryReset; } +void NodeDB::installDefaultRadioConfig() +{ + memset(&radioConfig, 0, sizeof(radioConfig)); + radioConfig.has_preferences = true; + resetRadioConfig(); +} + +void NodeDB::installDefaultChannels() +{ + memset(&channelFile, 0, sizeof(channelFile)); +} + void NodeDB::installDefaultDeviceState() { // We try to preserve the region setting because it will really bum users out if we discard it @@ -129,14 +143,10 @@ void NodeDB::installDefaultDeviceState() // init our devicestate with valid flags so protobuf writing/reading will work devicestate.has_my_node = true; - devicestate.has_radio = true; devicestate.has_owner = true; - devicestate.radio.has_preferences = true; devicestate.node_db_count = 0; devicestate.receive_queue_count = 0; // Not yet implemented FIXME - resetRadioConfig(); - // default to no GPS, until one has been found by probing myNodeInfo.has_gps = false; myNodeInfo.message_timeout_msec = FLOOD_EXPIRE_TIME; @@ -158,6 +168,9 @@ void NodeDB::installDefaultDeviceState() radioConfig.preferences.region = oldRegionCode; if (oldRegion.length()) // If the old style region was set, try to keep it up-to-date strcpy(myNodeInfo.region, oldRegion.c_str()); + + installDefaultChannels(); + installDefaultRadioConfig(); } void NodeDB::init() @@ -241,34 +254,29 @@ void NodeDB::pickNewNodeNum() } const char *preffile = "/db.proto"; -const char *preftmp = "/db.proto.tmp"; +const char *radiofile = "/radio.proto"; +const char *channelfile = "/channels.proto"; +// const char *preftmp = "/db.proto.tmp"; -void NodeDB::loadFromDisk() +/** Load a protobuf from a file, return true for success */ +bool loadProto(const char *filename, size_t protoSize, size_t objSize, const pb_msgdesc_t *fields, void *dest_struct) { #ifdef FS // static DeviceState scratch; We no longer read into a tempbuf because this structure is 15KB of valuable RAM - auto f = FS.open(preffile); + auto f = FS.open(filename); + bool okay = false; if (f) { - DEBUG_MSG("Loading saved preferences\n"); - pb_istream_t stream = {&readcb, &f, DeviceState_size}; + DEBUG_MSG("Loading %s\n", filename); + pb_istream_t stream = {&readcb, &f, protoSize}; // DEBUG_MSG("Preload channel name=%s\n", channelSettings.name); - memset(&devicestate, 0, sizeof(devicestate)); - if (!pb_decode(&stream, DeviceState_fields, &devicestate)) { + memset(dest_struct, 0, objSize); + if (!pb_decode(&stream, fields, dest_struct)) { DEBUG_MSG("Error: can't decode protobuf %s\n", PB_GET_ERROR(&stream)); - installDefaultDeviceState(); // Our in RAM copy might now be corrupt - // FIXME - report failure to phone } else { - if (devicestate.version < DEVICESTATE_MIN_VER) { - DEBUG_MSG("Warn: devicestate is old, discarding\n"); - installDefaultDeviceState(); - } else { - DEBUG_MSG("Loaded saved preferences version %d\n", devicestate.version); - } - - // DEBUG_MSG("Postload channel name=%s\n", channelSettings.name); + okay = true; } f.close(); @@ -279,6 +287,30 @@ void NodeDB::loadFromDisk() #else DEBUG_MSG("ERROR: Filesystem not implemented\n"); #endif + return okay; +} + +void NodeDB::loadFromDisk() +{ + // static DeviceState scratch; We no longer read into a tempbuf because this structure is 15KB of valuable RAM + if (!loadProto(preffile, DeviceState_size, sizeof(devicestate), DeviceState_fields, &devicestate)) { + installDefaultDeviceState(); // Our in RAM copy might now be corrupt + } else { + if (devicestate.version < DEVICESTATE_MIN_VER) { + DEBUG_MSG("Warn: devicestate is old, discarding\n"); + installDefaultDeviceState(); + } else { + DEBUG_MSG("Loaded saved preferences version %d\n", devicestate.version); + } + } + + if (!loadProto(radiofile, RadioConfig_size, sizeof(RadioConfig), RadioConfig_fields, &radioConfig)) { + installDefaultRadioConfig(); // Our in RAM copy might now be corrupt + } + + if (!loadProto(channelfile, ChannelFile_size, sizeof(ChannelFile), ChannelFile_fields, &channelFile)) { + installDefaultRadioConfig(); // Our in RAM copy might now be corrupt + } } void NodeDB::saveToDisk() @@ -370,7 +402,7 @@ void NodeDB::updatePosition(uint32_t nodeId, const Position &p) // recorded based on the packet rxTime if (!info->position.time && p.time) info->position.time = p.time; - if(p.battery_level) + if (p.battery_level) info->position.battery_level = p.battery_level; if (p.latitude_i || p.longitude_i) { info->position.latitude_i = p.latitude_i; diff --git a/src/mesh/NodeDB.h b/src/mesh/NodeDB.h index e5f1b6564..d29837543 100644 --- a/src/mesh/NodeDB.h +++ b/src/mesh/NodeDB.h @@ -9,8 +9,9 @@ #include "mesh-pb-constants.h" extern DeviceState devicestate; +extern ChannelFile channelFile; extern MyNodeInfo &myNodeInfo; -extern RadioConfig &radioConfig; +extern RadioConfig radioConfig; extern User &owner; /// Given a node, return how many seconds in the past (vs now) that we last heard from it @@ -117,7 +118,7 @@ class NodeDB void loadFromDisk(); /// Reinit device state from scratch (not loading from disk) - void installDefaultDeviceState(); + void installDefaultDeviceState(), installDefaultRadioConfig(), installDefaultChannels(); }; /** diff --git a/src/mesh/PhoneAPI.cpp b/src/mesh/PhoneAPI.cpp index 6e2ac479b..b50381e70 100644 --- a/src/mesh/PhoneAPI.cpp +++ b/src/mesh/PhoneAPI.cpp @@ -156,7 +156,6 @@ size_t PhoneAPI::getFromRadio(uint8_t *buf) state = STATE_SEND_PACKETS; break; - case STATE_LEGACY: // Treat as the same as send packets case STATE_SEND_PACKETS: // Do we have a message from the mesh? if (packetForPhone) { @@ -208,7 +207,6 @@ bool PhoneAPI::available() case STATE_SEND_COMPLETE_ID: return true; - case STATE_LEGACY: // Treat as the same as send packets case STATE_SEND_PACKETS: { // Try to pull a new packet from the service (if we haven't already) if (!packetForPhone) @@ -236,7 +234,7 @@ int PhoneAPI::onNotify(uint32_t newValue) checkConnectionTimeout(); // a handy place to check if we've heard from the phone (since the BLE version doesn't call this // from idle) - if (state == STATE_SEND_PACKETS || state == STATE_LEGACY) { + if (state == STATE_SEND_PACKETS) { DEBUG_MSG("Telling client we have new packets %u\n", newValue); onNowHasData(newValue); } else diff --git a/src/mesh/PhoneAPI.h b/src/mesh/PhoneAPI.h index 094e9830b..6d03d2c80 100644 --- a/src/mesh/PhoneAPI.h +++ b/src/mesh/PhoneAPI.h @@ -20,7 +20,7 @@ class PhoneAPI : public Observer // FIXME, we shouldn't be inheriting from Observer, instead use CallbackObserver as a member { enum State { - STATE_LEGACY, // (no longer used) old default state - until Android apps are all updated, uses the old BLE API + STATE_UNUSED, // (no longer used) old default state - until Android apps are all updated, uses the old BLE API STATE_SEND_NOTHING, // (Eventual) Initial state, don't send anything until the client starts asking for config STATE_SEND_MY_INFO, // send our my info record // STATE_SEND_RADIO, // in 1.2 we now send this as a regular mesh packet diff --git a/src/mesh/generated/admin.pb.h b/src/mesh/generated/admin.pb.h index 7c0ac9145..d68103cea 100644 --- a/src/mesh/generated/admin.pb.h +++ b/src/mesh/generated/admin.pb.h @@ -23,6 +23,8 @@ typedef struct _AdminMessage { RadioConfig get_radio_response; uint32_t get_channel_request; Channel get_channel_response; + bool confirm_set_channel; + bool confirm_set_radio; }; } AdminMessage; @@ -43,6 +45,8 @@ extern "C" { #define AdminMessage_get_radio_response_tag 5 #define AdminMessage_get_channel_request_tag 6 #define AdminMessage_get_channel_response_tag 7 +#define AdminMessage_confirm_set_channel_tag 32 +#define AdminMessage_confirm_set_radio_tag 33 /* Struct field encoding specification for nanopb */ #define AdminMessage_FIELDLIST(X, a) \ @@ -52,7 +56,9 @@ X(a, STATIC, ONEOF, MESSAGE, (variant,set_channel,set_channel), 3) \ X(a, STATIC, ONEOF, BOOL, (variant,get_radio_request,get_radio_request), 4) \ X(a, STATIC, ONEOF, MESSAGE, (variant,get_radio_response,get_radio_response), 5) \ X(a, STATIC, ONEOF, UINT32, (variant,get_channel_request,get_channel_request), 6) \ -X(a, STATIC, ONEOF, MESSAGE, (variant,get_channel_response,get_channel_response), 7) +X(a, STATIC, ONEOF, MESSAGE, (variant,get_channel_response,get_channel_response), 7) \ +X(a, STATIC, ONEOF, BOOL, (variant,confirm_set_channel,confirm_set_channel), 32) \ +X(a, STATIC, ONEOF, BOOL, (variant,confirm_set_radio,confirm_set_radio), 33) #define AdminMessage_CALLBACK NULL #define AdminMessage_DEFAULT NULL #define AdminMessage_variant_set_radio_MSGTYPE RadioConfig diff --git a/src/mesh/generated/channel.pb.h b/src/mesh/generated/channel.pb.h index 151495be1..962e452e4 100644 --- a/src/mesh/generated/channel.pb.h +++ b/src/mesh/generated/channel.pb.h @@ -40,7 +40,7 @@ typedef struct _ChannelSettings { } ChannelSettings; typedef struct _Channel { - uint8_t index; + int8_t index; bool has_settings; ChannelSettings settings; Channel_Role role; @@ -100,7 +100,7 @@ X(a, STATIC, SINGULAR, BOOL, downlink_enabled, 17) #define ChannelSettings_DEFAULT NULL #define Channel_FIELDLIST(X, a) \ -X(a, STATIC, SINGULAR, UINT32, index, 1) \ +X(a, STATIC, SINGULAR, INT32, index, 1) \ X(a, STATIC, OPTIONAL, MESSAGE, settings, 2) \ X(a, STATIC, SINGULAR, UENUM, role, 3) #define Channel_CALLBACK NULL @@ -116,7 +116,7 @@ extern const pb_msgdesc_t Channel_msg; /* Maximum encoded size of messages (where known) */ #define ChannelSettings_size 87 -#define Channel_size 94 +#define Channel_size 102 #ifdef __cplusplus } /* extern "C" */ diff --git a/src/mesh/generated/deviceonly.pb.c b/src/mesh/generated/deviceonly.pb.c index cfb836b0a..39e044580 100644 --- a/src/mesh/generated/deviceonly.pb.c +++ b/src/mesh/generated/deviceonly.pb.c @@ -9,4 +9,7 @@ PB_BIND(DeviceState, DeviceState, 2) +PB_BIND(ChannelFile, ChannelFile, 2) + + diff --git a/src/mesh/generated/deviceonly.pb.h b/src/mesh/generated/deviceonly.pb.h index dd3451849..c4a498248 100644 --- a/src/mesh/generated/deviceonly.pb.h +++ b/src/mesh/generated/deviceonly.pb.h @@ -5,7 +5,6 @@ #define PB_DEVICEONLY_PB_H_INCLUDED #include #include "mesh.pb.h" -#include "radioconfig.pb.h" #include "channel.pb.h" #if PB_PROTO_HEADER_VERSION != 40 @@ -13,9 +12,12 @@ #endif /* Struct definitions */ +typedef struct _ChannelFile { + pb_size_t channels_count; + Channel channels[8]; +} ChannelFile; + typedef struct _DeviceState { - bool has_radio; - RadioConfig radio; bool has_my_node; MyNodeInfo my_node; bool has_owner; @@ -29,8 +31,6 @@ typedef struct _DeviceState { uint32_t version; bool no_save; bool did_gps_reset; - pb_size_t channels_count; - Channel channels[8]; } DeviceState; @@ -39,11 +39,13 @@ extern "C" { #endif /* Initializer values for message structs */ -#define DeviceState_init_default {false, RadioConfig_init_default, false, MyNodeInfo_init_default, false, User_init_default, 0, {NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default}, 0, {MeshPacket_init_default}, false, MeshPacket_init_default, 0, 0, 0, 0, {Channel_init_default, Channel_init_default, Channel_init_default, Channel_init_default, Channel_init_default, Channel_init_default, Channel_init_default, Channel_init_default}} -#define DeviceState_init_zero {false, RadioConfig_init_zero, false, MyNodeInfo_init_zero, false, User_init_zero, 0, {NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero}, 0, {MeshPacket_init_zero}, false, MeshPacket_init_zero, 0, 0, 0, 0, {Channel_init_zero, Channel_init_zero, Channel_init_zero, Channel_init_zero, Channel_init_zero, Channel_init_zero, Channel_init_zero, Channel_init_zero}} +#define DeviceState_init_default {false, MyNodeInfo_init_default, false, User_init_default, 0, {NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default}, 0, {MeshPacket_init_default}, false, MeshPacket_init_default, 0, 0, 0} +#define ChannelFile_init_default {0, {Channel_init_default, Channel_init_default, Channel_init_default, Channel_init_default, Channel_init_default, Channel_init_default, Channel_init_default, Channel_init_default}} +#define DeviceState_init_zero {false, MyNodeInfo_init_zero, false, User_init_zero, 0, {NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero}, 0, {MeshPacket_init_zero}, false, MeshPacket_init_zero, 0, 0, 0} +#define ChannelFile_init_zero {0, {Channel_init_zero, Channel_init_zero, Channel_init_zero, Channel_init_zero, Channel_init_zero, Channel_init_zero, Channel_init_zero, Channel_init_zero}} /* Field tags (for use in manual encoding/decoding) */ -#define DeviceState_radio_tag 1 +#define ChannelFile_channels_tag 1 #define DeviceState_my_node_tag 2 #define DeviceState_owner_tag 3 #define DeviceState_node_db_tag 4 @@ -52,11 +54,9 @@ extern "C" { #define DeviceState_version_tag 8 #define DeviceState_no_save_tag 9 #define DeviceState_did_gps_reset_tag 11 -#define DeviceState_channels_tag 13 /* Struct field encoding specification for nanopb */ #define DeviceState_FIELDLIST(X, a) \ -X(a, STATIC, OPTIONAL, MESSAGE, radio, 1) \ X(a, STATIC, OPTIONAL, MESSAGE, my_node, 2) \ X(a, STATIC, OPTIONAL, MESSAGE, owner, 3) \ X(a, STATIC, REPEATED, MESSAGE, node_db, 4) \ @@ -64,25 +64,31 @@ X(a, STATIC, REPEATED, MESSAGE, receive_queue, 5) \ X(a, STATIC, OPTIONAL, MESSAGE, rx_text_message, 7) \ X(a, STATIC, SINGULAR, UINT32, version, 8) \ X(a, STATIC, SINGULAR, BOOL, no_save, 9) \ -X(a, STATIC, SINGULAR, BOOL, did_gps_reset, 11) \ -X(a, STATIC, REPEATED, MESSAGE, channels, 13) +X(a, STATIC, SINGULAR, BOOL, did_gps_reset, 11) #define DeviceState_CALLBACK NULL #define DeviceState_DEFAULT NULL -#define DeviceState_radio_MSGTYPE RadioConfig #define DeviceState_my_node_MSGTYPE MyNodeInfo #define DeviceState_owner_MSGTYPE User #define DeviceState_node_db_MSGTYPE NodeInfo #define DeviceState_receive_queue_MSGTYPE MeshPacket #define DeviceState_rx_text_message_MSGTYPE MeshPacket -#define DeviceState_channels_MSGTYPE Channel + +#define ChannelFile_FIELDLIST(X, a) \ +X(a, STATIC, REPEATED, MESSAGE, channels, 1) +#define ChannelFile_CALLBACK NULL +#define ChannelFile_DEFAULT NULL +#define ChannelFile_channels_MSGTYPE Channel extern const pb_msgdesc_t DeviceState_msg; +extern const pb_msgdesc_t ChannelFile_msg; /* Defines for backwards compatibility with code written before nanopb-0.4.0 */ #define DeviceState_fields &DeviceState_msg +#define ChannelFile_fields &ChannelFile_msg /* Maximum encoded size of messages (where known) */ -#define DeviceState_size 6169 +#define DeviceState_size 5050 +#define ChannelFile_size 832 #ifdef __cplusplus } /* extern "C" */ diff --git a/src/mesh/mesh-pb-constants.h b/src/mesh/mesh-pb-constants.h index 0b2a0d6cf..c0c908495 100644 --- a/src/mesh/mesh-pb-constants.h +++ b/src/mesh/mesh-pb-constants.h @@ -18,7 +18,7 @@ #define MAX_NUM_NODES (member_size(DeviceState, node_db) / member_size(DeviceState, node_db[0])) /// Max number of channels allowed -#define MAX_NUM_CHANNELS (member_size(DeviceState, channels) / member_size(DeviceState, channels[0])) +#define MAX_NUM_CHANNELS (member_size(ChannelFile, channels) / member_size(ChannelFile, channels[0])) /// helper function for encoding a record as a protobuf, any failures to encode are fatal and we will panic /// returns the encoded packet size diff --git a/src/plugins/AdminPlugin.cpp b/src/plugins/AdminPlugin.cpp index f45f61655..0d3f7a4dc 100644 --- a/src/plugins/AdminPlugin.cpp +++ b/src/plugins/AdminPlugin.cpp @@ -24,7 +24,7 @@ void AdminPlugin::handleGetRadio(const MeshPacket &req) if (req.decoded.want_response) { // We create the reply here AdminMessage r = AdminMessage_init_default; - r.get_radio_response = devicestate.radio; + r.get_radio_response = radioConfig; // 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 From 76e2c39c634f62cda7e154b11df1338c417fdd56 Mon Sep 17 00:00:00 2001 From: Kevin Hester Date: Thu, 11 Mar 2021 17:54:16 +0800 Subject: [PATCH 244/258] completed moving prefs to new files --- proto | 2 +- src/mesh/NodeDB.cpp | 116 +++++++++++++++++------------ src/mesh/generated/deviceonly.pb.c | 6 ++ src/mesh/generated/deviceonly.pb.h | 44 ++++++++++- 4 files changed, 118 insertions(+), 50 deletions(-) diff --git a/proto b/proto index e6e1c5a60..5c1062ea8 160000 --- a/proto +++ b/proto @@ -1 +1 @@ -Subproject commit e6e1c5a600147428af553304b47f25f21492965d +Subproject commit 5c1062ea839f97cfc6d33d428a89d1702c39bd93 diff --git a/src/mesh/NodeDB.cpp b/src/mesh/NodeDB.cpp index c4d58d4c3..7d8115878 100644 --- a/src/mesh/NodeDB.cpp +++ b/src/mesh/NodeDB.cpp @@ -128,7 +128,7 @@ void NodeDB::installDefaultRadioConfig() void NodeDB::installDefaultChannels() { - memset(&channelFile, 0, sizeof(channelFile)); + memset(&channelFile, 0, sizeof(channelFile)); } void NodeDB::installDefaultDeviceState() @@ -169,8 +169,8 @@ void NodeDB::installDefaultDeviceState() if (oldRegion.length()) // If the old style region was set, try to keep it up-to-date strcpy(myNodeInfo.region, oldRegion.c_str()); - installDefaultChannels(); - installDefaultRadioConfig(); + installDefaultChannels(); + installDefaultRadioConfig(); } void NodeDB::init() @@ -199,12 +199,16 @@ void NodeDB::init() info->user = owner; info->has_user = true; + // removed from 1.2 (though we do use old values if found) // We set these _after_ loading from disk - because they come from the build and are more trusted than // what is stored in flash - if (xstr(HW_VERSION)[0]) - strncpy(myNodeInfo.region, optstr(HW_VERSION), sizeof(myNodeInfo.region)); - else - DEBUG_MSG("This build does not specify a HW_VERSION\n"); // Eventually new builds will no longer include this build flag + //if (xstr(HW_VERSION)[0]) + // strncpy(myNodeInfo.region, optstr(HW_VERSION), sizeof(myNodeInfo.region)); + // else DEBUG_MSG("This build does not specify a HW_VERSION\n"); // Eventually new builds will no longer include this build flag + + // DEBUG_MSG("legacy region %d\n", devicestate.legacyRadio.preferences.region); + if(radioConfig.preferences.region == RegionCode_Unset) + radioConfig.preferences.region = devicestate.legacyRadio.preferences.region; // Check for the old style of region code strings, if found, convert to the new enum. // Those strings will look like "1.0-EU433" @@ -222,8 +226,7 @@ void NodeDB::init() resetRadioConfig(); // If bogus settings got saved, then fix them - DEBUG_MSG("legacy_region=%s, region=%d, NODENUM=0x%x, dbsize=%d\n", myNodeInfo.region, radioConfig.preferences.region, - myNodeInfo.my_node_num, *numNodes); + DEBUG_MSG("region=%d, NODENUM=0x%x, dbsize=%d\n", radioConfig.preferences.region, myNodeInfo.my_node_num, *numNodes); } // We reserve a few nodenums for future use @@ -253,9 +256,10 @@ void NodeDB::pickNewNodeNum() myNodeInfo.my_node_num = r; } -const char *preffile = "/db.proto"; -const char *radiofile = "/radio.proto"; -const char *channelfile = "/channels.proto"; +static const char *preffileOld = "/db.proto"; +static const char *preffile = "/prefs/db.proto"; +static const char *radiofile = "/prefs/radio.proto"; +static const char *channelfile = "/prefs/channels.proto"; // const char *preftmp = "/db.proto.tmp"; /** Load a protobuf from a file, return true for success */ @@ -265,6 +269,14 @@ bool loadProto(const char *filename, size_t protoSize, size_t objSize, const pb_ // static DeviceState scratch; We no longer read into a tempbuf because this structure is 15KB of valuable RAM auto f = FS.open(filename); + + // FIXME, temporary hack until every node in the universe is 1.2 or later - look for prefs in the old location (so we can + // preserve region) + if (!f && filename == preffile) { + filename = preffileOld; + f = FS.open(filename); + } + bool okay = false; if (f) { DEBUG_MSG("Loading %s\n", filename); @@ -281,9 +293,8 @@ bool loadProto(const char *filename, size_t protoSize, size_t objSize, const pb_ f.close(); } else { - DEBUG_MSG("No saved preferences found\n"); + DEBUG_MSG("No %s preferences found\n", filename); } - #else DEBUG_MSG("ERROR: Filesystem not implemented\n"); #endif @@ -309,47 +320,60 @@ void NodeDB::loadFromDisk() } if (!loadProto(channelfile, ChannelFile_size, sizeof(ChannelFile), ChannelFile_fields, &channelFile)) { - installDefaultRadioConfig(); // Our in RAM copy might now be corrupt - } + installDefaultChannels(); // Our in RAM copy might now be corrupt + } +} + +/** Save a protobuf from a file, return true for success */ +bool saveProto(const char *filename, size_t protoSize, size_t objSize, const pb_msgdesc_t *fields, const void *dest_struct) +{ +#ifdef FS + // static DeviceState scratch; We no longer read into a tempbuf because this structure is 15KB of valuable RAM + String filenameTmp = filename; + filenameTmp += ".tmp"; + auto f = FS.open(filenameTmp.c_str(), FILE_O_WRITE); + bool okay = false; + if (f) { + DEBUG_MSG("Saving %s\n", filename); + pb_ostream_t stream = {&writecb, &f, protoSize}; + + if (!pb_encode(&stream, fields, dest_struct)) { + DEBUG_MSG("Error: can't encode protobuf %s\n", PB_GET_ERROR(&stream)); + } else { + okay = true; + } + + f.close(); + + // brief window of risk here ;-) + if (!FS.remove(filename)) + DEBUG_MSG("Warning: Can't remove old pref file\n"); + if (!FS.rename(filenameTmp.c_str(), filename)) + DEBUG_MSG("Error: can't rename new pref file\n"); + } else { + DEBUG_MSG("Can't write prefs\n"); + } +#else + DEBUG_MSG("ERROR: Filesystem not implemented\n"); +#endif + return okay; } void NodeDB::saveToDisk() { -#ifdef FS if (!devicestate.no_save) { - auto f = FS.open(preftmp, FILE_O_WRITE); - if (f) { - DEBUG_MSG("Writing preferences\n"); +#ifdef FS + FS.mkdir("/prefs"); +#endif + bool okay = saveProto(preffile, DeviceState_size, sizeof(devicestate), DeviceState_fields, &devicestate); + okay &= saveProto(radiofile, RadioConfig_size, sizeof(RadioConfig), RadioConfig_fields, &radioConfig); + okay &= saveProto(channelfile, ChannelFile_size, sizeof(ChannelFile), ChannelFile_fields, &channelFile); - pb_ostream_t stream = {&writecb, &f, SIZE_MAX, 0}; - - // DEBUG_MSG("Presave channel name=%s\n", channelSettings.name); - - devicestate.version = DEVICESTATE_CUR_VER; - if (!pb_encode(&stream, DeviceState_fields, &devicestate)) { - DEBUG_MSG("Error: can't write protobuf %s\n", PB_GET_ERROR(&stream)); - // FIXME - report failure to phone - - f.close(); - } else { - // Success - replace the old file - f.close(); - - // brief window of risk here ;-) - if (!FS.remove(preffile)) - DEBUG_MSG("Warning: Can't remove old pref file\n"); - if (!FS.rename(preftmp, preffile)) - DEBUG_MSG("Error: can't rename new pref file\n"); - } - } else { - DEBUG_MSG("ERROR: can't write prefs\n"); // FIXME report to app - } + // remove any pre 1.2 pref files, turn on after 1.2 is in beta + // if(okay) FS.remove(preffileOld); } else { DEBUG_MSG("***** DEVELOPMENT MODE - DO NOT RELEASE - not saving to flash *****\n"); } -#else - DEBUG_MSG("ERROR filesystem not implemented\n"); -#endif } const NodeInfo *NodeDB::readNextInfo() diff --git a/src/mesh/generated/deviceonly.pb.c b/src/mesh/generated/deviceonly.pb.c index 39e044580..dd2bb751f 100644 --- a/src/mesh/generated/deviceonly.pb.c +++ b/src/mesh/generated/deviceonly.pb.c @@ -6,6 +6,12 @@ #error Regenerate this file with the current version of nanopb generator. #endif +PB_BIND(LegacyRadioConfig, LegacyRadioConfig, AUTO) + + +PB_BIND(LegacyRadioConfig_LegacyPreferences, LegacyRadioConfig_LegacyPreferences, AUTO) + + PB_BIND(DeviceState, DeviceState, 2) diff --git a/src/mesh/generated/deviceonly.pb.h b/src/mesh/generated/deviceonly.pb.h index c4a498248..9c40e2110 100644 --- a/src/mesh/generated/deviceonly.pb.h +++ b/src/mesh/generated/deviceonly.pb.h @@ -6,6 +6,7 @@ #include #include "mesh.pb.h" #include "channel.pb.h" +#include "radioconfig.pb.h" #if PB_PROTO_HEADER_VERSION != 40 #error Regenerate this file with the current version of nanopb generator. @@ -17,7 +18,18 @@ typedef struct _ChannelFile { Channel channels[8]; } ChannelFile; +typedef struct _LegacyRadioConfig_LegacyPreferences { + RegionCode region; +} LegacyRadioConfig_LegacyPreferences; + +typedef struct _LegacyRadioConfig { + bool has_preferences; + LegacyRadioConfig_LegacyPreferences preferences; +} LegacyRadioConfig; + typedef struct _DeviceState { + bool has_legacyRadio; + LegacyRadioConfig legacyRadio; bool has_my_node; MyNodeInfo my_node; bool has_owner; @@ -39,13 +51,20 @@ extern "C" { #endif /* Initializer values for message structs */ -#define DeviceState_init_default {false, MyNodeInfo_init_default, false, User_init_default, 0, {NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default}, 0, {MeshPacket_init_default}, false, MeshPacket_init_default, 0, 0, 0} +#define LegacyRadioConfig_init_default {false, LegacyRadioConfig_LegacyPreferences_init_default} +#define LegacyRadioConfig_LegacyPreferences_init_default {_RegionCode_MIN} +#define DeviceState_init_default {false, LegacyRadioConfig_init_default, false, MyNodeInfo_init_default, false, User_init_default, 0, {NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default}, 0, {MeshPacket_init_default}, false, MeshPacket_init_default, 0, 0, 0} #define ChannelFile_init_default {0, {Channel_init_default, Channel_init_default, Channel_init_default, Channel_init_default, Channel_init_default, Channel_init_default, Channel_init_default, Channel_init_default}} -#define DeviceState_init_zero {false, MyNodeInfo_init_zero, false, User_init_zero, 0, {NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero}, 0, {MeshPacket_init_zero}, false, MeshPacket_init_zero, 0, 0, 0} +#define LegacyRadioConfig_init_zero {false, LegacyRadioConfig_LegacyPreferences_init_zero} +#define LegacyRadioConfig_LegacyPreferences_init_zero {_RegionCode_MIN} +#define DeviceState_init_zero {false, LegacyRadioConfig_init_zero, false, MyNodeInfo_init_zero, false, User_init_zero, 0, {NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero}, 0, {MeshPacket_init_zero}, false, MeshPacket_init_zero, 0, 0, 0} #define ChannelFile_init_zero {0, {Channel_init_zero, Channel_init_zero, Channel_init_zero, Channel_init_zero, Channel_init_zero, Channel_init_zero, Channel_init_zero, Channel_init_zero}} /* Field tags (for use in manual encoding/decoding) */ #define ChannelFile_channels_tag 1 +#define LegacyRadioConfig_LegacyPreferences_region_tag 15 +#define LegacyRadioConfig_preferences_tag 1 +#define DeviceState_legacyRadio_tag 1 #define DeviceState_my_node_tag 2 #define DeviceState_owner_tag 3 #define DeviceState_node_db_tag 4 @@ -56,7 +75,19 @@ extern "C" { #define DeviceState_did_gps_reset_tag 11 /* Struct field encoding specification for nanopb */ +#define LegacyRadioConfig_FIELDLIST(X, a) \ +X(a, STATIC, OPTIONAL, MESSAGE, preferences, 1) +#define LegacyRadioConfig_CALLBACK NULL +#define LegacyRadioConfig_DEFAULT NULL +#define LegacyRadioConfig_preferences_MSGTYPE LegacyRadioConfig_LegacyPreferences + +#define LegacyRadioConfig_LegacyPreferences_FIELDLIST(X, a) \ +X(a, STATIC, SINGULAR, UENUM, region, 15) +#define LegacyRadioConfig_LegacyPreferences_CALLBACK NULL +#define LegacyRadioConfig_LegacyPreferences_DEFAULT NULL + #define DeviceState_FIELDLIST(X, a) \ +X(a, STATIC, OPTIONAL, MESSAGE, legacyRadio, 1) \ X(a, STATIC, OPTIONAL, MESSAGE, my_node, 2) \ X(a, STATIC, OPTIONAL, MESSAGE, owner, 3) \ X(a, STATIC, REPEATED, MESSAGE, node_db, 4) \ @@ -67,6 +98,7 @@ X(a, STATIC, SINGULAR, BOOL, no_save, 9) \ X(a, STATIC, SINGULAR, BOOL, did_gps_reset, 11) #define DeviceState_CALLBACK NULL #define DeviceState_DEFAULT NULL +#define DeviceState_legacyRadio_MSGTYPE LegacyRadioConfig #define DeviceState_my_node_MSGTYPE MyNodeInfo #define DeviceState_owner_MSGTYPE User #define DeviceState_node_db_MSGTYPE NodeInfo @@ -79,15 +111,21 @@ X(a, STATIC, REPEATED, MESSAGE, channels, 1) #define ChannelFile_DEFAULT NULL #define ChannelFile_channels_MSGTYPE Channel +extern const pb_msgdesc_t LegacyRadioConfig_msg; +extern const pb_msgdesc_t LegacyRadioConfig_LegacyPreferences_msg; extern const pb_msgdesc_t DeviceState_msg; extern const pb_msgdesc_t ChannelFile_msg; /* Defines for backwards compatibility with code written before nanopb-0.4.0 */ +#define LegacyRadioConfig_fields &LegacyRadioConfig_msg +#define LegacyRadioConfig_LegacyPreferences_fields &LegacyRadioConfig_LegacyPreferences_msg #define DeviceState_fields &DeviceState_msg #define ChannelFile_fields &ChannelFile_msg /* Maximum encoded size of messages (where known) */ -#define DeviceState_size 5050 +#define LegacyRadioConfig_size 4 +#define LegacyRadioConfig_LegacyPreferences_size 2 +#define DeviceState_size 5056 #define ChannelFile_size 832 #ifdef __cplusplus From a97c2ae6ebce9e8fad99366bb27f60a080e34c22 Mon Sep 17 00:00:00 2001 From: Kevin Hester Date: Thu, 11 Mar 2021 18:29:47 +0800 Subject: [PATCH 245/258] minimize radioconfig file writes --- src/mesh/MeshService.cpp | 2 +- src/mesh/NodeDB.cpp | 12 +++++++++++- src/mesh/NodeDB.h | 2 +- src/plugins/AdminPlugin.cpp | 19 ++++++++++--------- 4 files changed, 23 insertions(+), 12 deletions(-) diff --git a/src/mesh/MeshService.cpp b/src/mesh/MeshService.cpp index 5590fa9cf..d542b21cf 100644 --- a/src/mesh/MeshService.cpp +++ b/src/mesh/MeshService.cpp @@ -104,7 +104,7 @@ bool MeshService::reloadConfig() // This will also update the region as needed bool didReset = nodeDB.resetRadioConfig(); // Don't let the phone send us fatally bad settings - configChanged.notifyObservers(NULL); + configChanged.notifyObservers(NULL); // This will cause radio hardware to change freqs etc nodeDB.saveToDisk(); return didReset; diff --git a/src/mesh/NodeDB.cpp b/src/mesh/NodeDB.cpp index 7d8115878..20a687769 100644 --- a/src/mesh/NodeDB.cpp +++ b/src/mesh/NodeDB.cpp @@ -359,6 +359,16 @@ bool saveProto(const char *filename, size_t protoSize, size_t objSize, const pb_ return okay; } +void NodeDB::saveChannelsToDisk() +{ + if (!devicestate.no_save) { +#ifdef FS + FS.mkdir("/prefs"); +#endif + saveProto(channelfile, ChannelFile_size, sizeof(ChannelFile), ChannelFile_fields, &channelFile); + } +} + void NodeDB::saveToDisk() { if (!devicestate.no_save) { @@ -367,7 +377,7 @@ void NodeDB::saveToDisk() #endif bool okay = saveProto(preffile, DeviceState_size, sizeof(devicestate), DeviceState_fields, &devicestate); okay &= saveProto(radiofile, RadioConfig_size, sizeof(RadioConfig), RadioConfig_fields, &radioConfig); - okay &= saveProto(channelfile, ChannelFile_size, sizeof(ChannelFile), ChannelFile_fields, &channelFile); + saveChannelsToDisk(); // remove any pre 1.2 pref files, turn on after 1.2 is in beta // if(okay) FS.remove(preffileOld); diff --git a/src/mesh/NodeDB.h b/src/mesh/NodeDB.h index d29837543..bd7346455 100644 --- a/src/mesh/NodeDB.h +++ b/src/mesh/NodeDB.h @@ -43,7 +43,7 @@ class NodeDB void init(); /// write to flash - void saveToDisk(); + void saveToDisk(), saveChannelsToDisk(); /** Reinit radio config if needed, because either: * a) sometimes a buggy android app might send us bogus settings or diff --git a/src/plugins/AdminPlugin.cpp b/src/plugins/AdminPlugin.cpp index 0d3f7a4dc..875b06236 100644 --- a/src/plugins/AdminPlugin.cpp +++ b/src/plugins/AdminPlugin.cpp @@ -96,21 +96,22 @@ void AdminPlugin::handleSetChannel(const Channel &cc) { channels.setChannel(cc); - bool didReset = service.reloadConfig(); - /* FIXME - do we need this still? - if (didReset) { - state = STATE_SEND_MY_INFO; // Squirt a completely new set of configs to the client - } */ + // Just update and save the channels - no need to update the radio for ! primary channel changes + if (cc.index == 0) { + // FIXME, this updates the user preferences also, which isn't needed - we really just want to notify on configChanged + service.reloadConfig(); + } + else { + channels.onConfigChanged(); // tell the radios about this change + nodeDB.saveChannelsToDisk(); + } } void AdminPlugin::handleSetRadio(const RadioConfig &r) { radioConfig = r; - bool didReset = service.reloadConfig(); - /* FIXME - do we need this still? if (didReset) { - state = STATE_SEND_MY_INFO; // Squirt a completely new set of configs to the client - } */ + service.reloadConfig(); } MeshPacket *AdminPlugin::allocReply() From 2d6261703af6a5b4520d90c7c437d3ab1c8a55f2 Mon Sep 17 00:00:00 2001 From: Kevin Hester Date: Thu, 11 Mar 2021 18:53:17 +0800 Subject: [PATCH 246/258] fix null pointer exception in storeandforwardplugin. if null the vtable is busted cc @mc-hamster. In some cases storeForwardPluginRadio can be null ;-) ~/development/meshtastic/meshtastic-esp32$ bin/exception_decoder.py -e .pio/build/tbeam/firmware.elf ex stack: 0x401db467: StoreForwardPluginRadio::sendPayload(unsigned int, bool) at /home/kevinh/development/meshtastic/meshtastic-esp32/src/plugins/esp32/StoreForwardPlugin.cpp:235 0x400e7cbd: StoreForwardPlugin::runOnce() at /home/kevinh/development/meshtastic/meshtastic-esp32/src/plugins/esp32/StoreForwardPlugin.cpp:225 0x400d4cca: concurrency::OSThread::run() at /home/kevinh/development/meshtastic/meshtastic-esp32/src/concurrency/OSThread.cpp:45 0x400f015d: ThreadController::runOrDelay() at /home/kevinh/development/meshtastic/meshtastic-esp32/.pio/libdeps/tbeam/Thread/ThreadController.cpp:153 0x400da070: loop() at /home/kevinh/development/meshtastic/meshtastic-esp32/src/main.cpp:621 0x400ff709: loopTask(void*) at /home/kevinh/.platformio/packages/framework-arduinoespressif32/cores/esp32/main.cpp:19 Signed-off-by: Kevin Hester --- src/plugins/esp32/StoreForwardPlugin.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/plugins/esp32/StoreForwardPlugin.cpp b/src/plugins/esp32/StoreForwardPlugin.cpp index 5fec31ad9..897a2c94a 100644 --- a/src/plugins/esp32/StoreForwardPlugin.cpp +++ b/src/plugins/esp32/StoreForwardPlugin.cpp @@ -83,7 +83,8 @@ int32_t StoreForwardPlugin::runOnce() DEBUG_MSG("Store & Forward Plugin - Sending heartbeat\n"); // storeForwardPluginRadio->sendPayloadHeartbeat(); - storeForwardPluginRadio->sendPayload(); + if(storeForwardPluginRadio) + storeForwardPluginRadio->sendPayload(); return (1 * 60 * 1000); } From b02212009acfeea37b71ff24cabec3b75e5a6948 Mon Sep 17 00:00:00 2001 From: Kevin Hester Date: Fri, 12 Mar 2021 14:10:36 +0800 Subject: [PATCH 247/258] progress on remote settings --- docs/software/TODO.md | 8 +- platformio.ini | 19 +- src/memtest.cpp | 318 ++++++++++++++++++++++++++++++++++ src/mesh/MeshPlugin.cpp | 18 +- src/mesh/RadioInterface.cpp | 3 + src/mesh/ReliableRouter.cpp | 8 +- src/mesh/Router.cpp | 6 +- src/mesh/Router.h | 3 +- src/mesh/generated/mesh.pb.h | 7 +- src/plugins/AdminPlugin.cpp | 2 + src/plugins/RoutingPlugin.cpp | 3 +- src/plugins/RoutingPlugin.h | 5 +- 12 files changed, 371 insertions(+), 29 deletions(-) create mode 100644 src/memtest.cpp diff --git a/docs/software/TODO.md b/docs/software/TODO.md index 43ba66477..d69aa43eb 100644 --- a/docs/software/TODO.md +++ b/docs/software/TODO.md @@ -4,6 +4,11 @@ You probably don't care about this section - skip to the next one. ## 1.2 cleanup & multichannel support: +nastybug +try again on esp32 +emittx thinks it emitted but client sees nothing. works again later +segger logs have errors in formatting that should be impossible (because not going through serial, try stalling on segger) + * DONE call RouterPlugin for *all* packets - not just Router packets * DONE generate channel hash from the name of the channel+the psk (not just one or the other) * DONE send a hint that can be used to select which channel to try and hash against with each message @@ -42,7 +47,8 @@ You probably don't care about this section - skip to the next one. * DONE add gui in android app for setting region * DONE clean up python channel usage * DONE use bindToChannel to limit admin access for remote nodes -* move channels and radio config out of device settings +* DONE move channels and radio config out of device settings +* test remote info and remote settings changes * make python tests more exhaustive * pick default random admin key * exclude admin channels from URL? diff --git a/platformio.ini b/platformio.ini index 742bc6db6..286976311 100644 --- a/platformio.ini +++ b/platformio.ini @@ -45,13 +45,6 @@ build_flags = -Wno-missing-field-initializers -DUSE_THREAD_NAMES -DTINYGPS_OPTION_NO_CUSTOM_FIELDS -; leave this commented out to avoid breaking Windows -;upload_port = /dev/ttyUSB0 -;monitor_port = /dev/ttyUSB0 - -;upload_port = /dev/cu.SLAB_USBtoUART -;monitor_port = /dev/cu.SLAB_USBtoUART - ; the default is esptool ; upload_protocol = esp-prog @@ -74,7 +67,7 @@ lib_deps = https://github.com/meshtastic/esp8266-oled-ssd1306.git#35d796226b853b0c0ff818b2f1aa3d35e7296a96 ; ESP8266_SSD1306 https://github.com/geeksville/OneButton.git ; OneButton library for non-blocking button debounce 1202 ; CRC32, explicitly needed because dependency is missing in the ble ota update lib - https://github.com/meshtastic/arduino-fsm.git#2f106146071fc7bc620e1e8d4b88dc4e0266ce39 + https://github.com/meshtastic/arduino-fsm.git#55c47b6cded91645aff05a27b6e5821d8d0f64be https://github.com/meshtastic/SparkFun_Ublox_Arduino_Library.git#31015a55e630a2df77d9d714669c621a5bf355ad https://github.com/meshtastic/RadioLib.git#07de964e929238949035fb0d5887026a3058df1a https://github.com/meshtastic/TinyGPSPlus.git#f0f47067ef2f67c856475933188251c1ef615e79 @@ -118,6 +111,13 @@ lib_ignore = segger_rtt platform_packages = framework-arduinoespressif32@https://github.com/meshtastic/arduino-esp32.git#352c8ea7cb73f10433ed139f34251979c470ad56 +; leave this commented out to avoid breaking Windows +upload_port = /dev/ttyUSB0 +;monitor_port = /dev/ttyUSB0 + +;upload_port = /dev/cu.SLAB_USBtoUART +;monitor_port = /dev/cu.SLAB_USBtoUART + ; customize the partition table ; http://docs.platformio.org/en/latest/platforms/espressif32.html#partition-tables board_build.partitions = partition-table.csv @@ -206,7 +206,8 @@ debug_port = :2331 # Note: the ARGUMENTS MUST BE on multiple lines. Otherwise platformio/commands/debug/helpers.py misparses everything into the "executable" # attribute and leaves "arguments" empty # /home/kevinh/.platformio/packages/tool-jlink/JLinkGDBServerCLExe -debug_server = +# This doesn't work yet, so not using for now +disabled_debug_server = /usr/bin/JLinkGDBServerCLExe -singlerun -if diff --git a/src/memtest.cpp b/src/memtest.cpp new file mode 100644 index 000000000..939bbc02b --- /dev/null +++ b/src/memtest.cpp @@ -0,0 +1,318 @@ +/* + * mtest - Perform a memory test + * + * (C) Copyright 2000 + * Wolfgang Denk, DENX Software Engineering, wd@denx.de. + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ +#include "configuration.h" + +/* + * Perform a memory test. A more complete alternative test can be + * configured using CONFIG_CMD_MTEST_ALTERNATIVE. The complete test + * loops until interrupted by ctrl-c or by a failure of one of the + * sub-tests. + */ +#ifdef CONFIG_CMD_MTEST_ALTERNATIVE +static int mem_test(uint32_t _start, uint32_t _end, uint32_t pattern_unused) +{ + volatile uint32_t *start = (volatile uint32_t *)_start; + volatile uint32_t *end = (volatile uint32_t *)_end; + volatile uint32_t *addr; + uint32_t val; + uint32_t readback; + vu_long addr_mask; + vu_long offset; + vu_long test_offset; + vu_long pattern; + vu_long temp; + vu_long anti_pattern; + vu_long num_words; +#ifdef CFG_MEMTEST_SCRATCH + volatile uint32_t *dummy = (vu_long *)CFG_MEMTEST_SCRATCH; +#else + volatile uint32_t *dummy = start; +#endif + int j; + int iterations = 1; + static const uint32_t bitpattern[] = { + 0x00000001, /* single bit */ + 0x00000003, /* two adjacent bits */ + 0x00000007, /* three adjacent bits */ + 0x0000000F, /* four adjacent bits */ + 0x00000005, /* two non-adjacent bits */ + 0x00000015, /* three non-adjacent bits */ + 0x00000055, /* four non-adjacent bits */ + 0xaaaaaaaa, /* alternating 1/0 */ + }; + /* XXX: enforce alignment of start and end? */ + for (;;) { + if (ctrlc()) { + putchar('\n'); + return 1; + } + printf("Iteration: %6d\r", iterations); + iterations++; + /* + * Data line test: write a pattern to the first + * location, write the 1's complement to a 'parking' + * address (changes the state of the data bus so a + * floating bus doen't give a false OK), and then + * read the value back. Note that we read it back + * into a variable because the next time we read it, + * it might be right (been there, tough to explain to + * the quality guys why it prints a failure when the + * "is" and "should be" are obviously the same in the + * error message). + * + * Rather than exhaustively testing, we test some + * patterns by shifting '1' bits through a field of + * '0's and '0' bits through a field of '1's (i.e. + * pattern and ~pattern). + */ + addr = start; + /* XXX */ + if (addr == dummy) + ++addr; + for (j = 0; j < sizeof(bitpattern) / sizeof(bitpattern[0]); j++) { + val = bitpattern[j]; + for (; val != 0; val <<= 1) { + *addr = val; + *dummy = ~val; /* clear the test data off of the bus */ + readback = *addr; + if (readback != val) { + printf("FAILURE (data line): " + "expected 0x%08lx, actual 0x%08lx at address 0x%p\n", + val, readback, addr); + } + *addr = ~val; + *dummy = val; + readback = *addr; + if (readback != ~val) { + printf("FAILURE (data line): " + "Is 0x%08lx, should be 0x%08lx at address 0x%p\n", + readback, ~val, addr); + } + } + } + /* + * Based on code whose Original Author and Copyright + * information follows: Copyright (c) 1998 by Michael + * Barr. This software is placed into the public + * domain and may be used for any purpose. However, + * this notice must not be changed or removed and no + * warranty is either expressed or implied by its + * publication or distribution. + */ + /* + * Address line test + * + * Description: Test the address bus wiring in a + * memory region by performing a walking + * 1's test on the relevant bits of the + * address and checking for aliasing. + * This test will find single-bit + * address failures such as stuck -high, + * stuck-low, and shorted pins. The base + * address and size of the region are + * selected by the caller. + * + * Notes: For best results, the selected base + * address should have enough LSB 0's to + * guarantee single address bit changes. + * For example, to test a 64-Kbyte + * region, select a base address on a + * 64-Kbyte boundary. Also, select the + * region size as a power-of-two if at + * all possible. + * + * Returns: 0 if the test succeeds, 1 if the test fails. + * + * ## NOTE ## Be sure to specify start and end + * addresses such that addr_mask has + * lots of bits set. For example an + * address range of 01000000 02000000 is + * bad while a range of 01000000 + * 01ffffff is perfect. + */ + addr_mask = ((uint32_t)end - (uint32_t)start) / sizeof(vu_long); + pattern = (vu_long)0xaaaaaaaa; + anti_pattern = (vu_long)0x55555555; + debug("%s:%d: addr mask = 0x%.8lx\n", __FUNCTION__, __LINE__, addr_mask); + /* + * Write the default pattern at each of the + * power-of-two offsets. + */ + for (offset = 1; (offset & addr_mask) != 0; offset <<= 1) + start[offset] = pattern; + /* + * Check for address bits stuck high. + */ + test_offset = 0; + start[test_offset] = anti_pattern; + for (offset = 1; (offset & addr_mask) != 0; offset <<= 1) { + temp = start[offset]; + if (temp != pattern) { + printf("\nFAILURE: Address bit stuck high @ 0x%.8lx:" + " expected 0x%.8lx, actual 0x%.8lx\n", + (uint32_t)&start[offset], pattern, temp); + return 1; + } + } + start[test_offset] = pattern; + /* + * Check for addr bits stuck low or shorted. + */ + for (test_offset = 1; (test_offset & addr_mask) != 0; test_offset <<= 1) { + start[test_offset] = anti_pattern; + for (offset = 1; (offset & addr_mask) != 0; offset <<= 1) { + temp = start[offset]; + if ((temp != pattern) && (offset != test_offset)) { + printf("\nFAILURE: Address bit stuck low or shorted @" + " 0x%.8lx: expected 0x%.8lx, actual 0x%.8lx\n", + (uint32_t)&start[offset], pattern, temp); + return 1; + } + } + start[test_offset] = pattern; + } + /* + * Description: Test the integrity of a physical + * memory device by performing an + * increment/decrement test over the + * entire region. In the process every + * storage bit in the device is tested + * as a zero and a one. The base address + * and the size of the region are + * selected by the caller. + * + * Returns: 0 if the test succeeds, 1 if the test fails. + */ + num_words = ((uint32_t)end - (uint32_t)start) / sizeof(vu_long) + 1; + /* + * Fill memory with a known pattern. + */ + for (pattern = 1, offset = 0; offset < num_words; pattern++, offset++) { + start[offset] = pattern; + } + /* + * Check each location and invert it for the second pass. + */ + for (pattern = 1, offset = 0; offset < num_words; pattern++, offset++) { + temp = start[offset]; + if (temp != pattern) { + printf("\nFAILURE (read/write) @ 0x%.8lx:" + " expected 0x%.8lx, actual 0x%.8lx)\n", + (uint32_t)&start[offset], pattern, temp); + return 1; + } + anti_pattern = ~pattern; + start[offset] = anti_pattern; + } + /* + * Check each location for the inverted pattern and zero it. + */ + for (pattern = 1, offset = 0; offset < num_words; pattern++, offset++) { + anti_pattern = ~pattern; + temp = start[offset]; + if (temp != anti_pattern) { + printf("\nFAILURE (read/write): @ 0x%.8lx:" + " expected 0x%.8lx, actual 0x%.8lx)\n", + (uint32_t)&start[offset], anti_pattern, temp); + return 1; + } + start[offset] = 0; + } + } +} +#else +static int mem_test(uint32_t _start, uint32_t _end, bool doRead = true, bool doWrite = true) +{ + volatile uint32_t *addr; + volatile uint32_t *start = (volatile uint32_t *)_start; + volatile uint32_t *end = (volatile uint32_t *)_end; + uint32_t pattern = 0; + uint32_t val; + uint32_t readback; + uint32_t incr; + int rcode = 0; + incr = 1; + + //DEBUG_MSG("memtest read=%d, write=%d\n", doRead, doWrite); + + if (doWrite) { + //DEBUG_MSG("writing\n"); + for (addr = start, val = pattern; addr < end; addr++) { + *addr = val; + val += incr; + } + } + + if (doRead) { + //DEBUG_MSG("reading\n"); + for (addr = start, val = pattern; addr < end; addr++) { + readback = *addr; + if (readback != val) { + DEBUG_MSG("Mem error @ 0x%08X: " + "found 0x%08lX, expected 0x%08lX\n", + addr, readback, val); + rcode++; + } + val += incr; + } + } + +#if 0 + /* + * Flip the pattern each time to make lots of zeros and + * then, the next time, lots of ones. We decrement + * the "negative" patterns and increment the "positive" + * patterns to preserve this feature. + */ + if(pattern & 0x80000000) { + pattern = -pattern; /* complement & increment */ + } + else { + pattern = ~pattern; + } +#endif + + return rcode; +} +#endif + +#define TESTBUF_LEN 16384 + +#include + +void doMemTest() +{ + static uint32_t *testBuf; + static int iter; + + if (!testBuf) + testBuf = (uint32_t *)malloc(TESTBUF_LEN); + + assert(testBuf); + if (mem_test((uint32_t)testBuf, ((uint32_t)testBuf) + TESTBUF_LEN, iter % 2 == 1, iter % 2 == 0) > 0) + assert(0); // FIXME report error better + + iter++; +} \ No newline at end of file diff --git a/src/mesh/MeshPlugin.cpp b/src/mesh/MeshPlugin.cpp index 68a63116e..361cad26b 100644 --- a/src/mesh/MeshPlugin.cpp +++ b/src/mesh/MeshPlugin.cpp @@ -2,6 +2,7 @@ #include "Channels.h" #include "MeshService.h" #include "NodeDB.h" +#include "plugins/RoutingPlugin.h" #include std::vector *MeshPlugin::plugins; @@ -52,7 +53,7 @@ void MeshPlugin::callPlugins(const MeshPacket &mp) assert(ch.has_settings); /// Is the channel this packet arrived on acceptable? (security check) - bool rxChannelOk = !pi.boundChannel || (mp.from == 0) || (strcmp(ch.settings.name, pi.boundChannel) == 0); + bool rxChannelOk = true || !pi.boundChannel || (mp.from == 0) || (strcmp(ch.settings.name, pi.boundChannel) == 0); /// We only call plugins that are interested in the packet (and the message is destined to us or we are promiscious) bool wantsPacket = rxChannelOk && (pi.isPromiscuous || toUs) && pi.wantPacket(&mp); @@ -84,10 +85,17 @@ void MeshPlugin::callPlugins(const MeshPacket &mp) pi.currentRequest = NULL; } - if (currentReply) { - DEBUG_MSG("Sending response\n"); - service.sendToMesh(currentReply); - currentReply = NULL; + if (mp.decoded.want_response && toUs) { + if (currentReply) { + DEBUG_MSG("Sending response\n"); + service.sendToMesh(currentReply); + currentReply = NULL; + } + else { + // No one wanted to reply to this requst, tell the requster that happened + DEBUG_MSG("No one responded, send a nak\n"); + routingPlugin->sendAckNak(Routing_Error_NO_RESPONSE, getFrom(&mp), mp.id, mp.channel); + } } if (!pluginFound) diff --git a/src/mesh/RadioInterface.cpp b/src/mesh/RadioInterface.cpp index 49dc69927..0ee235292 100644 --- a/src/mesh/RadioInterface.cpp +++ b/src/mesh/RadioInterface.cpp @@ -153,6 +153,9 @@ void printPacket(const char *prefix, const MeshPacket *p) if (s.dest != 0) DEBUG_MSG(" dest=%08x", s.dest); + if(s.request_id) + DEBUG_MSG(" requestId=%0x", s.request_id); + /* now inside Data and therefore kinda opaque if (s.which_ackVariant == SubPacket_success_id_tag) DEBUG_MSG(" successId=%08x", s.ackVariant.success_id); diff --git a/src/mesh/ReliableRouter.cpp b/src/mesh/ReliableRouter.cpp index 962aabeb7..4d4845949 100644 --- a/src/mesh/ReliableRouter.cpp +++ b/src/mesh/ReliableRouter.cpp @@ -38,7 +38,7 @@ bool ReliableRouter::shouldFilterReceived(const MeshPacket *p) DEBUG_MSG("generating implicit ack\n"); // NOTE: we do NOT check p->wantAck here because p is the INCOMING rebroadcast and that packet is not expected to be // marked as wantAck - sendAckNak(Routing_Error_NONE, getFrom(p), p->id); + sendAckNak(Routing_Error_NONE, getFrom(p), p->id, p->channel); } } @@ -65,9 +65,9 @@ void ReliableRouter::sniffReceived(const MeshPacket *p, const Routing *c) // - not DSR routing) if (p->want_ack) { if (MeshPlugin::currentReply) - DEBUG_MSG("Someone else has replied to this message, no need for a 2nd ack"); + DEBUG_MSG("Someone else has replied to this message, no need for a 2nd ack\n"); else - sendAckNak(Routing_Error_NONE, getFrom(p), p->id); + sendAckNak(Routing_Error_NONE, getFrom(p), p->id, p->channel); } // We consider an ack to be either a !routing packet with a request ID or a routing packet with !error @@ -166,7 +166,7 @@ int32_t ReliableRouter::doRetransmissions() if (p.numRetransmissions == 0) { DEBUG_MSG("Reliable send failed, returning a nak for fr=0x%x,to=0x%x,id=0x%x\n", p.packet->from, p.packet->to, p.packet->id); - sendAckNak(Routing_Error_MAX_RETRANSMIT, getFrom(p.packet), p.packet->id); + sendAckNak(Routing_Error_MAX_RETRANSMIT, getFrom(p.packet), p.packet->id, p.packet->channel); // Note: we don't stop retransmission here, instead the Nak packet gets processed in sniffReceived - which // allows the DSR version to still be able to look at the PendingPacket stopRetransmission(it->first); diff --git a/src/mesh/Router.cpp b/src/mesh/Router.cpp index 8f566dffe..52b28eb55 100644 --- a/src/mesh/Router.cpp +++ b/src/mesh/Router.cpp @@ -103,15 +103,15 @@ MeshPacket *Router::allocForSending() /** * Send an ack or a nak packet back towards whoever sent idFrom */ -void Router::sendAckNak(Routing_Error err, NodeNum to, PacketId idFrom) +void Router::sendAckNak(Routing_Error err, NodeNum to, PacketId idFrom, ChannelIndex chIndex) { - routingPlugin->sendAckNak(err, to, idFrom); + routingPlugin->sendAckNak(err, to, idFrom, chIndex); } void Router::abortSendAndNak(Routing_Error err, MeshPacket *p) { DEBUG_MSG("Error=%d, returning NAK and dropping packet.\n", err); - sendAckNak(Routing_Error_NO_INTERFACE, getFrom(p), p->id); + sendAckNak(Routing_Error_NO_INTERFACE, getFrom(p), p->id, p->channel); packetPool.release(p); } diff --git a/src/mesh/Router.h b/src/mesh/Router.h index 6e217017b..3600af361 100644 --- a/src/mesh/Router.h +++ b/src/mesh/Router.h @@ -6,6 +6,7 @@ #include "PointerQueue.h" #include "RadioInterface.h" #include "concurrency/OSThread.h" +#include "Channels.h" /** * A mesh aware router that supports multiple interfaces. @@ -106,7 +107,7 @@ class Router : protected concurrency::OSThread /** * Send an ack or a nak packet back towards whoever sent idFrom */ - void sendAckNak(Routing_Error err, NodeNum to, PacketId idFrom); + void sendAckNak(Routing_Error err, NodeNum to, PacketId idFrom, ChannelIndex chIndex); private: /** diff --git a/src/mesh/generated/mesh.pb.h b/src/mesh/generated/mesh.pb.h index b7df1079e..10487e40d 100644 --- a/src/mesh/generated/mesh.pb.h +++ b/src/mesh/generated/mesh.pb.h @@ -37,7 +37,8 @@ typedef enum _Routing_Error { Routing_Error_NO_INTERFACE = 4, Routing_Error_MAX_RETRANSMIT = 5, Routing_Error_NO_CHANNEL = 6, - Routing_Error_TOO_LARGE = 7 + Routing_Error_TOO_LARGE = 7, + Routing_Error_NO_RESPONSE = 8 } Routing_Error; typedef enum _MeshPacket_Priority { @@ -182,8 +183,8 @@ typedef struct _ToRadio { #define _CriticalErrorCode_ARRAYSIZE ((CriticalErrorCode)(CriticalErrorCode_Brownout+1)) #define _Routing_Error_MIN Routing_Error_NONE -#define _Routing_Error_MAX Routing_Error_TOO_LARGE -#define _Routing_Error_ARRAYSIZE ((Routing_Error)(Routing_Error_TOO_LARGE+1)) +#define _Routing_Error_MAX Routing_Error_NO_RESPONSE +#define _Routing_Error_ARRAYSIZE ((Routing_Error)(Routing_Error_NO_RESPONSE+1)) #define _MeshPacket_Priority_MIN MeshPacket_Priority_UNSET #define _MeshPacket_Priority_MAX MeshPacket_Priority_MAX diff --git a/src/plugins/AdminPlugin.cpp b/src/plugins/AdminPlugin.cpp index 875b06236..060b1e635 100644 --- a/src/plugins/AdminPlugin.cpp +++ b/src/plugins/AdminPlugin.cpp @@ -66,6 +66,8 @@ bool AdminPlugin::handleReceivedProtobuf(const MeshPacket &mp, const AdminMessag break; default: + // Probably a message sent by us or sent to our local node. FIXME, we should avoid scanning these messages + DEBUG_MSG("Ignoring nonrelevant admin %d\n", r->which_variant); break; } return false; // Let others look at this message also if they want diff --git a/src/plugins/RoutingPlugin.cpp b/src/plugins/RoutingPlugin.cpp index f6c2ea03a..4fe0b88d5 100644 --- a/src/plugins/RoutingPlugin.cpp +++ b/src/plugins/RoutingPlugin.cpp @@ -35,7 +35,7 @@ MeshPacket *RoutingPlugin::allocReply() return NULL; } -void RoutingPlugin::sendAckNak(Routing_Error err, NodeNum to, PacketId idFrom) +void RoutingPlugin::sendAckNak(Routing_Error err, NodeNum to, PacketId idFrom, ChannelIndex chIndex) { Routing c = Routing_init_default; @@ -47,6 +47,7 @@ void RoutingPlugin::sendAckNak(Routing_Error err, NodeNum to, PacketId idFrom) p->hop_limit = 0; // Assume just immediate neighbors for now p->to = to; p->decoded.request_id = idFrom; + p->channel = chIndex; DEBUG_MSG("Sending an err=%d,to=0x%x,idFrom=0x%x,id=0x%x\n", err, to, idFrom, p->id); router->sendLocal(p); // we sometimes send directly to the local node diff --git a/src/plugins/RoutingPlugin.h b/src/plugins/RoutingPlugin.h index a848bc9c4..ff659de2a 100644 --- a/src/plugins/RoutingPlugin.h +++ b/src/plugins/RoutingPlugin.h @@ -1,5 +1,6 @@ #pragma once #include "ProtobufPlugin.h" +#include "Channels.h" /** * Routing plugin for router control messages @@ -12,6 +13,8 @@ class RoutingPlugin : public ProtobufPlugin */ RoutingPlugin(); + void sendAckNak(Routing_Error err, NodeNum to, PacketId idFrom, ChannelIndex chIndex); + protected: friend class Router; @@ -27,8 +30,6 @@ class RoutingPlugin : public ProtobufPlugin /// Override wantPacket to say we want to see all packets, not just those for our port number virtual bool wantPacket(const MeshPacket *p) { return true; } - - void sendAckNak(Routing_Error err, NodeNum to, PacketId idFrom); }; extern RoutingPlugin *routingPlugin; \ No newline at end of file From c097852ab09da020ea0600d02abd1bd0be2141b4 Mon Sep 17 00:00:00 2001 From: Kevin Hester Date: Fri, 12 Mar 2021 15:45:28 +0800 Subject: [PATCH 248/258] SERIOUS BUG: we've been discarding devicestate when we should not --- proto | 2 +- src/mesh/NodeDB.cpp | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/proto b/proto index 5c1062ea8..e63f9713f 160000 --- a/proto +++ b/proto @@ -1 +1 @@ -Subproject commit 5c1062ea839f97cfc6d33d428a89d1702c39bd93 +Subproject commit e63f9713f73ea5c9308b7822602ea75f506b6b00 diff --git a/src/mesh/NodeDB.cpp b/src/mesh/NodeDB.cpp index 20a687769..1840aa360 100644 --- a/src/mesh/NodeDB.cpp +++ b/src/mesh/NodeDB.cpp @@ -145,6 +145,7 @@ void NodeDB::installDefaultDeviceState() devicestate.has_my_node = true; devicestate.has_owner = true; devicestate.node_db_count = 0; + devicestate.version = DEVICESTATE_CUR_VER; devicestate.receive_queue_count = 0; // Not yet implemented FIXME // default to no GPS, until one has been found by probing @@ -308,7 +309,7 @@ void NodeDB::loadFromDisk() installDefaultDeviceState(); // Our in RAM copy might now be corrupt } else { if (devicestate.version < DEVICESTATE_MIN_VER) { - DEBUG_MSG("Warn: devicestate is old, discarding\n"); + DEBUG_MSG("Warn: devicestate %d is old, discarding\n", devicestate.version); installDefaultDeviceState(); } else { DEBUG_MSG("Loaded saved preferences version %d\n", devicestate.version); From 8cd2a00a2550872fe78dddbce6f76794e84a7fc8 Mon Sep 17 00:00:00 2001 From: Kevin Hester Date: Fri, 12 Mar 2021 15:47:00 +0800 Subject: [PATCH 249/258] fix nasty bug --- docs/software/TODO.md | 7 ++----- src/mesh/StreamAPI.cpp | 8 +++++++- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/docs/software/TODO.md b/docs/software/TODO.md index d69aa43eb..9b1e77f69 100644 --- a/docs/software/TODO.md +++ b/docs/software/TODO.md @@ -4,11 +4,8 @@ You probably don't care about this section - skip to the next one. ## 1.2 cleanup & multichannel support: -nastybug -try again on esp32 -emittx thinks it emitted but client sees nothing. works again later -segger logs have errors in formatting that should be impossible (because not going through serial, try stalling on segger) - +* cdcacm bug on nrf52: emittx thinks it emitted but client sees nothing. works again later +* nrf52: segger logs have errors in formatting that should be impossible (because not going through serial, try stalling on segger) * DONE call RouterPlugin for *all* packets - not just Router packets * DONE generate channel hash from the name of the channel+the psk (not just one or the other) * DONE send a hint that can be used to select which channel to try and hash against with each message diff --git a/src/mesh/StreamAPI.cpp b/src/mesh/StreamAPI.cpp index 8015b951b..a5e36d463 100644 --- a/src/mesh/StreamAPI.cpp +++ b/src/mesh/StreamAPI.cpp @@ -71,12 +71,18 @@ void StreamAPI::writeStream() void StreamAPI::emitTxBuffer(size_t len) { if (len != 0) { + DEBUG_MSG("emit tx %d\n", len); txBuf[0] = START1; txBuf[1] = START2; txBuf[2] = (len >> 8) & 0xff; txBuf[3] = len & 0xff; - stream->write(txBuf, len + HEADER_LEN); + auto totalLen = len + HEADER_LEN; + stream->write(txBuf, totalLen); + /* for(size_t i = 0; i < totalLen; i++) { + stream->write(txBuf[i]); + // stream->flush(); + } */ } } From 1908d131cad091bf71c321259da56503627b7013 Mon Sep 17 00:00:00 2001 From: Kevin Hester Date: Fri, 12 Mar 2021 20:22:40 +0800 Subject: [PATCH 250/258] turn on access control for admin plugin, only allow remote access over special channel --- src/mesh/MeshPlugin.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mesh/MeshPlugin.cpp b/src/mesh/MeshPlugin.cpp index 361cad26b..99bf7643a 100644 --- a/src/mesh/MeshPlugin.cpp +++ b/src/mesh/MeshPlugin.cpp @@ -53,7 +53,7 @@ void MeshPlugin::callPlugins(const MeshPacket &mp) assert(ch.has_settings); /// Is the channel this packet arrived on acceptable? (security check) - bool rxChannelOk = true || !pi.boundChannel || (mp.from == 0) || (strcmp(ch.settings.name, pi.boundChannel) == 0); + bool rxChannelOk = !pi.boundChannel || (mp.from == 0) || (strcmp(ch.settings.name, pi.boundChannel) == 0); /// We only call plugins that are interested in the packet (and the message is destined to us or we are promiscious) bool wantsPacket = rxChannelOk && (pi.isPromiscuous || toUs) && pi.wantPacket(&mp); From bc7fef1d1af11030982dc6b98f38315aa6e9399c Mon Sep 17 00:00:00 2001 From: Kevin Hester Date: Fri, 12 Mar 2021 20:22:45 +0800 Subject: [PATCH 251/258] 1.2.9 --- version.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version.properties b/version.properties index d0634458c..8f23a55a3 100644 --- a/version.properties +++ b/version.properties @@ -1,4 +1,4 @@ [VERSION] major = 1 minor = 2 -build = 6 +build = 9 From 5dc5bce1b235649639d7e0b455fa6fc829c97a90 Mon Sep 17 00:00:00 2001 From: Kevin Hester Date: Fri, 12 Mar 2021 20:41:18 +0800 Subject: [PATCH 252/258] cleanup memtest --- src/memtest.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/memtest.cpp b/src/memtest.cpp index 939bbc02b..f7e3eb3e8 100644 --- a/src/memtest.cpp +++ b/src/memtest.cpp @@ -243,11 +243,11 @@ static int mem_test(uint32_t _start, uint32_t _end, uint32_t pattern_unused) } } #else -static int mem_test(uint32_t _start, uint32_t _end, bool doRead = true, bool doWrite = true) +static int mem_test(uint32_t *_start, size_t len, bool doRead = true, bool doWrite = true) { volatile uint32_t *addr; volatile uint32_t *start = (volatile uint32_t *)_start; - volatile uint32_t *end = (volatile uint32_t *)_end; + volatile uint32_t *end = start + len / sizeof(uint32_t); uint32_t pattern = 0; uint32_t val; uint32_t readback; @@ -311,7 +311,7 @@ void doMemTest() testBuf = (uint32_t *)malloc(TESTBUF_LEN); assert(testBuf); - if (mem_test((uint32_t)testBuf, ((uint32_t)testBuf) + TESTBUF_LEN, iter % 2 == 1, iter % 2 == 0) > 0) + if (mem_test(testBuf, TESTBUF_LEN, iter % 2 == 1, iter % 2 == 0) > 0) assert(0); // FIXME report error better iter++; From b7f9064f0d7e8df9615155dba442d1dcc43cdd9f Mon Sep 17 00:00:00 2001 From: Kevin Hester Date: Fri, 12 Mar 2021 20:42:22 +0800 Subject: [PATCH 253/258] turn off linux on CI for now --- .github/workflows/main.yml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index dcbb213b5..49a2bf3c6 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -31,5 +31,6 @@ jobs: run: platformio run -e heltec - name: Build for lora-relay-v1 run: platformio run -e lora-relay-v1 - - name: Build for linux - run: platformio run -e linux + # Turn off linux for now + #- name: Build for linux + # run: platformio run -e linux From a5ed6072612fae716336024d0b75ad46b89870de Mon Sep 17 00:00:00 2001 From: Kevin Hester Date: Sat, 13 Mar 2021 08:29:32 +0800 Subject: [PATCH 254/258] fix memory corruption in storeandforward --- src/plugins/esp32/StoreForwardPlugin.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/plugins/esp32/StoreForwardPlugin.cpp b/src/plugins/esp32/StoreForwardPlugin.cpp index 897a2c94a..7cb2862eb 100644 --- a/src/plugins/esp32/StoreForwardPlugin.cpp +++ b/src/plugins/esp32/StoreForwardPlugin.cpp @@ -227,14 +227,14 @@ void StoreForwardPlugin::sawNodeReport() MeshPacket *StoreForwardPluginRadio::allocReply() { - //auto reply = allocDataPacket(); // Allocate a packet for sending - //return reply; + auto reply = allocDataPacket(); // Allocate a packet for sending + return reply; // attn @mc-hamster this code was commented out and was causing memory corruption } void StoreForwardPluginRadio::sendPayload(NodeNum dest, bool wantReplies) { - MeshPacket *p = this->allocReply(); /* + MeshPacket *p = this->allocReply(); // attn @mc-hamster, I moved inside the commented block to prevent leaking memory p->to = dest; p->decoded.want_response = wantReplies; From 3e6817cd18f0a4b745e48d1f2f4d937acaa5e232 Mon Sep 17 00:00:00 2001 From: Kevin Hester Date: Sat, 13 Mar 2021 08:29:58 +0800 Subject: [PATCH 255/258] fix board reboot due to forwarding packets we don't have keys for --- src/mesh/ReliableRouter.cpp | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/mesh/ReliableRouter.cpp b/src/mesh/ReliableRouter.cpp index 4d4845949..28ad65bfa 100644 --- a/src/mesh/ReliableRouter.cpp +++ b/src/mesh/ReliableRouter.cpp @@ -34,11 +34,19 @@ bool ReliableRouter::shouldFilterReceived(const MeshPacket *p) // We are seeing someone rebroadcast one of our broadcast attempts. // If this is the first time we saw this, cancel any retransmissions we have queued up and generate an internal ack for // the original sending process. - if (stopRetransmission(getFrom(p), p->id)) { + + // FIXME - we might want to turn off this "optimization", it does save lots of airtime but it assumes that once we've heard one + // one adjacent node hear our packet that a) probably other adjacent nodes heard it and b) we can trust those nodes to reach + // our destination. Both of which might be incorrect. + auto key = GlobalPacketId(getFrom(p), p->id); + auto old = findPendingPacket(key); + if (old) { DEBUG_MSG("generating implicit ack\n"); // NOTE: we do NOT check p->wantAck here because p is the INCOMING rebroadcast and that packet is not expected to be // marked as wantAck - sendAckNak(Routing_Error_NONE, getFrom(p), p->id, p->channel); + sendAckNak(Routing_Error_NONE, getFrom(p), p->id, old->packet->channel); + + stopRetransmission(key); } } From cdd696c1ff78b0280e45a8c71f4a4681ccbfc016 Mon Sep 17 00:00:00 2001 From: Kevin Hester Date: Sat, 13 Mar 2021 08:30:07 +0800 Subject: [PATCH 256/258] todo updates --- docs/software/TODO.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/docs/software/TODO.md b/docs/software/TODO.md index 9b1e77f69..3a768e68f 100644 --- a/docs/software/TODO.md +++ b/docs/software/TODO.md @@ -4,6 +4,9 @@ You probably don't care about this section - skip to the next one. ## 1.2 cleanup & multichannel support: +* timestamps on oled screen are wrong - don't seem to be updating based on message rx +* luxon bug report - seeing rx acks for nodes that are not on the network +* channel hash suffixes are wrong on android * cdcacm bug on nrf52: emittx thinks it emitted but client sees nothing. works again later * nrf52: segger logs have errors in formatting that should be impossible (because not going through serial, try stalling on segger) * DONE call RouterPlugin for *all* packets - not just Router packets From c227143b5385faac629cb7bbd47a9efc5f336641 Mon Sep 17 00:00:00 2001 From: Kevin Hester Date: Sat, 13 Mar 2021 08:41:50 +0800 Subject: [PATCH 257/258] @mc-hamster, I think storeandforward was accidentally wrong (no worries though) --- proto | 2 +- src/mesh/generated/radioconfig.pb.h | 12 ++++++------ src/plugins/esp32/StoreForwardPlugin.cpp | 7 +++++-- 3 files changed, 12 insertions(+), 9 deletions(-) diff --git a/proto b/proto index e63f9713f..bf8ac6718 160000 --- a/proto +++ b/proto @@ -1 +1 @@ -Subproject commit e63f9713f73ea5c9308b7822602ea75f506b6b00 +Subproject commit bf8ac6718c08fe7c94a9896d91ef85572694f7b0 diff --git a/src/mesh/generated/radioconfig.pb.h b/src/mesh/generated/radioconfig.pb.h index 9ea021f13..12224b99b 100644 --- a/src/mesh/generated/radioconfig.pb.h +++ b/src/mesh/generated/radioconfig.pb.h @@ -104,7 +104,6 @@ typedef struct _RadioConfig_UserPreferences { bool range_test_plugin_enabled; uint32_t range_test_plugin_sender; bool range_test_plugin_save; - bool store_forward_plugin_enabled; uint32_t store_forward_plugin_records; bool environmental_measurement_plugin_measurement_enabled; bool environmental_measurement_plugin_screen_enabled; @@ -114,6 +113,7 @@ typedef struct _RadioConfig_UserPreferences { bool environmental_measurement_plugin_display_farenheit; RadioConfig_UserPreferences_EnvironmentalMeasurementSensorType environmental_measurement_plugin_sensor_type; uint32_t environmental_measurement_plugin_sensor_pin; + bool store_forward_plugin_enabled; } RadioConfig_UserPreferences; typedef struct _RadioConfig { @@ -150,9 +150,9 @@ extern "C" { /* Initializer values for message structs */ #define RadioConfig_init_default {false, RadioConfig_UserPreferences_init_default} -#define RadioConfig_UserPreferences_init_default {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, "", "", 0, _RegionCode_MIN, _ChargeCurrent_MIN, _LocationSharing_MIN, _GpsOperation_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, 0, 0, 0, 0, 0, 0, _RadioConfig_UserPreferences_EnvironmentalMeasurementSensorType_MIN, 0} +#define RadioConfig_UserPreferences_init_default {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, "", "", 0, _RegionCode_MIN, _ChargeCurrent_MIN, _LocationSharing_MIN, _GpsOperation_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, 0, 0, 0, 0, 0, _RadioConfig_UserPreferences_EnvironmentalMeasurementSensorType_MIN, 0, 0} #define RadioConfig_init_zero {false, RadioConfig_UserPreferences_init_zero} -#define RadioConfig_UserPreferences_init_zero {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, "", "", 0, _RegionCode_MIN, _ChargeCurrent_MIN, _LocationSharing_MIN, _GpsOperation_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, 0, 0, 0, 0, 0, 0, _RadioConfig_UserPreferences_EnvironmentalMeasurementSensorType_MIN, 0} +#define RadioConfig_UserPreferences_init_zero {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, "", "", 0, _RegionCode_MIN, _ChargeCurrent_MIN, _LocationSharing_MIN, _GpsOperation_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, 0, 0, 0, 0, 0, _RadioConfig_UserPreferences_EnvironmentalMeasurementSensorType_MIN, 0, 0} /* Field tags (for use in manual encoding/decoding) */ #define RadioConfig_UserPreferences_position_broadcast_secs_tag 1 @@ -195,7 +195,6 @@ extern "C" { #define RadioConfig_UserPreferences_range_test_plugin_enabled_tag 132 #define RadioConfig_UserPreferences_range_test_plugin_sender_tag 133 #define RadioConfig_UserPreferences_range_test_plugin_save_tag 134 -#define RadioConfig_UserPreferences_store_forward_plugin_enabled_tag 136 #define RadioConfig_UserPreferences_store_forward_plugin_records_tag 137 #define RadioConfig_UserPreferences_environmental_measurement_plugin_measurement_enabled_tag 140 #define RadioConfig_UserPreferences_environmental_measurement_plugin_screen_enabled_tag 141 @@ -205,6 +204,7 @@ extern "C" { #define RadioConfig_UserPreferences_environmental_measurement_plugin_display_farenheit_tag 145 #define RadioConfig_UserPreferences_environmental_measurement_plugin_sensor_type_tag 146 #define RadioConfig_UserPreferences_environmental_measurement_plugin_sensor_pin_tag 147 +#define RadioConfig_UserPreferences_store_forward_plugin_enabled_tag 148 #define RadioConfig_preferences_tag 1 /* Struct field encoding specification for nanopb */ @@ -255,7 +255,6 @@ X(a, STATIC, SINGULAR, BOOL, ext_notification_plugin_alert_bell, 131) \ X(a, STATIC, SINGULAR, BOOL, range_test_plugin_enabled, 132) \ X(a, STATIC, SINGULAR, UINT32, range_test_plugin_sender, 133) \ X(a, STATIC, SINGULAR, BOOL, range_test_plugin_save, 134) \ -X(a, STATIC, SINGULAR, BOOL, store_forward_plugin_enabled, 136) \ X(a, STATIC, SINGULAR, UINT32, store_forward_plugin_records, 137) \ X(a, STATIC, SINGULAR, BOOL, environmental_measurement_plugin_measurement_enabled, 140) \ X(a, STATIC, SINGULAR, BOOL, environmental_measurement_plugin_screen_enabled, 141) \ @@ -264,7 +263,8 @@ X(a, STATIC, SINGULAR, UINT32, environmental_measurement_plugin_update_inter X(a, STATIC, SINGULAR, UINT32, environmental_measurement_plugin_recovery_interval, 144) \ X(a, STATIC, SINGULAR, BOOL, environmental_measurement_plugin_display_farenheit, 145) \ X(a, STATIC, SINGULAR, UENUM, environmental_measurement_plugin_sensor_type, 146) \ -X(a, STATIC, SINGULAR, UINT32, environmental_measurement_plugin_sensor_pin, 147) +X(a, STATIC, SINGULAR, UINT32, environmental_measurement_plugin_sensor_pin, 147) \ +X(a, STATIC, SINGULAR, BOOL, store_forward_plugin_enabled, 148) #define RadioConfig_UserPreferences_CALLBACK NULL #define RadioConfig_UserPreferences_DEFAULT NULL diff --git a/src/plugins/esp32/StoreForwardPlugin.cpp b/src/plugins/esp32/StoreForwardPlugin.cpp index 7cb2862eb..28f1c6738 100644 --- a/src/plugins/esp32/StoreForwardPlugin.cpp +++ b/src/plugins/esp32/StoreForwardPlugin.cpp @@ -24,10 +24,13 @@ int32_t StoreForwardPlugin::runOnce() /* Uncomment the preferences below if you want to use the plugin without having to configure it from the PythonAPI or WebUI. - */ + attn @mc-hamster I moved this back inside the comment because I don't think it was intended to checkin. It was forcing all + nodes to be running this and turning off is_router. + radioConfig.preferences.store_forward_plugin_enabled = 1; - radioConfig.preferences.is_router = 0; + radioConfig.preferences.is_router = 0; + */ if (radioConfig.preferences.store_forward_plugin_enabled) { From 6dd65adebd42045ff304fc93207a5ebcf9b92a40 Mon Sep 17 00:00:00 2001 From: Kevin Hester Date: Sat, 13 Mar 2021 08:54:02 +0800 Subject: [PATCH 258/258] 1.2.10 --- version.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version.properties b/version.properties index 8f23a55a3..e615e8b4b 100644 --- a/version.properties +++ b/version.properties @@ -1,4 +1,4 @@ [VERSION] major = 1 minor = 2 -build = 9 +build = 10