diff --git a/.github/workflows/main_matrix.yml b/.github/workflows/main_matrix.yml
index e5ed1a71a..fd4acbdba 100644
--- a/.github/workflows/main_matrix.yml
+++ b/.github/workflows/main_matrix.yml
@@ -57,12 +57,12 @@ jobs:
sudo apt-get install -y cppcheck
- name: Setup Python
- uses: actions/setup-python@v2
+ uses: actions/setup-python@v4
with:
python-version: 3.x
- name: Cache python libs
- uses: actions/cache@v1
+ uses: actions/cache@v3
id: cache-pip # needed in if test
with:
path: ~/.cache/pip
@@ -112,12 +112,12 @@ jobs:
repository: ${{github.event.pull_request.head.repo.full_name}}
- name: Setup Python
- uses: actions/setup-python@v2
+ uses: actions/setup-python@v4
with:
python-version: 3.x
- name: Cache python libs
- uses: actions/cache@v1
+ uses: actions/cache@v3
id: cache-pip # needed in if test
with:
path: ~/.cache/pip
@@ -157,11 +157,11 @@ jobs:
token: ${{ secrets.GITHUB_TOKEN }}
- name: Get release version string
- run: echo "::set-output name=version::$(./bin/buildinfo.py long)"
+ run: echo "version=$(./bin/buildinfo.py long)" >> $GITHUB_OUTPUT
id: version
- name: Store binaries as an artifact
- uses: actions/upload-artifact@v2
+ uses: actions/upload-artifact@v3
with:
name: firmware-${{ matrix.board }}-${{ steps.version.outputs.version }}.zip
path: |
@@ -190,12 +190,12 @@ jobs:
repository: ${{github.event.pull_request.head.repo.full_name}}
- name: Setup Python
- uses: actions/setup-python@v2
+ uses: actions/setup-python@v4
with:
python-version: 3.x
- name: Cache python libs
- uses: actions/cache@v1
+ uses: actions/cache@v3
id: cache-pip # needed in if test
with:
path: ~/.cache/pip
@@ -214,16 +214,17 @@ jobs:
run: bin/build-nrf52.sh ${{ matrix.board }}
- name: Get release version string
- run: echo "::set-output name=version::$(./bin/buildinfo.py long)"
+ run: echo "version=$(./bin/buildinfo.py long)" >> $GITHUB_OUTPUT
id: version
- name: Store binaries as an artifact
- uses: actions/upload-artifact@v2
+ uses: actions/upload-artifact@v3
with:
name: firmware-${{ matrix.board }}-${{ steps.version.outputs.version }}.zip
path: |
release/*.uf2
release/*.elf
+ release/*.zip
retention-days: 90
build-rpi2040:
@@ -244,12 +245,12 @@ jobs:
repository: ${{github.event.pull_request.head.repo.full_name}}
- name: Setup Python
- uses: actions/setup-python@v2
+ uses: actions/setup-python@v4
with:
python-version: 3.x
- name: Cache python libs
- uses: actions/cache@v1
+ uses: actions/cache@v3
id: cache-pip # needed in if test
with:
path: ~/.cache/pip
@@ -268,11 +269,11 @@ jobs:
run: ./bin/build-rpi2040.sh ${{ matrix.board }}
- name: Get release version string
- run: echo "::set-output name=version::$(./bin/buildinfo.py long)"
+ run: echo "version=$(./bin/buildinfo.py long)" >> $GITHUB_OUTPUT
id: version
- name: Store binaries as an artifact
- uses: actions/upload-artifact@v2
+ uses: actions/upload-artifact@v3
with:
name: firmware-${{ matrix.board }}-${{ steps.version.outputs.version }}.zip
path: |
@@ -291,12 +292,12 @@ jobs:
repository: ${{github.event.pull_request.head.repo.full_name}}
- name: Setup Python
- uses: actions/setup-python@v2
+ uses: actions/setup-python@v4
with:
python-version: 3.x
- name: Cache python libs
- uses: actions/cache@v1
+ uses: actions/cache@v3
id: cache-pip # needed in if test
with:
path: ~/.cache/pip
@@ -326,11 +327,11 @@ jobs:
run: bin/build-native.sh
- name: Get release version string
- run: echo "::set-output name=version::$(./bin/buildinfo.py long)"
+ run: echo "version=$(./bin/buildinfo.py long)" >> $GITHUB_OUTPUT
id: version
- name: Store binaries as an artifact
- uses: actions/upload-artifact@v2
+ uses: actions/upload-artifact@v3
with:
name: firmware-native-${{ steps.version.outputs.version }}.zip
path: |
@@ -359,30 +360,31 @@ jobs:
ref: ${{github.event.pull_request.head.ref}}
repository: ${{github.event.pull_request.head.repo.full_name}}
- - uses: actions/download-artifact@v2
+ - uses: actions/download-artifact@v3
with:
path: ./
- name: Get release version string
- run: echo "::set-output name=version::$(./bin/buildinfo.py long)"
+ run: echo "version=$(./bin/buildinfo.py long)" >> $GITHUB_OUTPUT
id: version
- name: Move files up
- run: mv -b -t ./ ./*tbeam-1*/littlefs*.bin ./*tbeam-1*/bleota.bin ./**/firmware*.bin ./*t-echo*/Meshtastic_nRF52_factory_erase.uf2 ./**/firmware-*.uf2 ./**/*.elf ./**/meshtasticd_linux_amd64 ./*native*/*device-*.sh ./*native*/*device-*.bat
+ run: mv -b -t ./ ./*tbeam-1*/littlefs*.bin ./*tbeam-1*/bleota.bin ./**/firmware*.bin ./*t-echo*/Meshtastic_nRF52_factory_erase.uf2 ./**/firmware-*.uf2 ./**/firmware-*-ota.zip ./**/*.elf ./**/meshtasticd_linux_amd64 ./*native*/*device-*.sh ./*native*/*device-*.bat
- name: Repackage in single firmware zip
- uses: actions/upload-artifact@v2
+ uses: actions/upload-artifact@v3
with:
name: firmware-${{ steps.version.outputs.version }}
path: |
./*.bin
./*.uf2
+ ./firmware-*-ota.zip
./meshtasticd_linux_amd64
./device-*.sh
./device-*.bat
retention-days: 90
- - uses: actions/download-artifact@v2
+ - uses: actions/download-artifact@v3
with:
name: firmware-${{ steps.version.outputs.version }}
path: ./output
@@ -400,7 +402,7 @@ jobs:
run: zip -j -r ./firmware-${{ steps.version.outputs.version }}.zip ./output
- name: Repackage in single elfs zip
- uses: actions/upload-artifact@v2
+ uses: actions/upload-artifact@v3
with:
name: debug-elfs-${{ steps.version.outputs.version }}.zip
path: ./*.elf
@@ -424,18 +426,18 @@ jobs:
needs: [gather-artifacts, after-checks]
steps:
- name: Checkout
- uses: actions/checkout@v2
+ uses: actions/checkout@v3
- name: Setup Python
- uses: actions/setup-python@v2
+ uses: actions/setup-python@v4
with:
python-version: 3.x
- name: Get release version string
- run: echo "::set-output name=version::$(./bin/buildinfo.py long)"
+ run: echo "version=$(./bin/buildinfo.py long)" >> $GITHUB_OUTPUT
id: version
- - uses: actions/download-artifact@v2
+ - uses: actions/download-artifact@v3
with:
name: firmware-${{ steps.version.outputs.version }}
path: ./output
@@ -448,7 +450,7 @@ jobs:
- name: Zip firmware
run: zip -j -r ./firmware-${{ steps.version.outputs.version }}.zip ./output
- - uses: actions/download-artifact@v2
+ - uses: actions/download-artifact@v3
with:
name: debug-elfs-${{ steps.version.outputs.version }}.zip
path: ./elfs
@@ -466,7 +468,7 @@ jobs:
with:
draft: true
prerelease: true
- release_name: Meshtastic Device ${{ steps.version.outputs.version }} alpha - Public Preview
+ release_name: Meshtastic Device ${{ steps.version.outputs.version }} Alpha
tag_name: v${{ steps.version.outputs.version }}
body: |
Autogenerated by github action, developer should edit as required before publishing...
diff --git a/arch/esp32/esp32.ini b/arch/esp32/esp32.ini
index d2e2fd9c5..798fb3d5a 100644
--- a/arch/esp32/esp32.ini
+++ b/arch/esp32/esp32.ini
@@ -1,7 +1,7 @@
; Common settings for ESP targes, mixin with extends = esp32_base
[esp32_base]
extends = arduino_base
-platform = espressif32@^5.2.0
+platform = platformio/espressif32@^5.2.0
build_src_filter =
${arduino_base.build_src_filter} - - -
upload_speed = 921600
diff --git a/arch/esp32/esp32s3.ini b/arch/esp32/esp32s3.ini
index e19b9aaf7..8dc6d0b62 100644
--- a/arch/esp32/esp32s3.ini
+++ b/arch/esp32/esp32s3.ini
@@ -1,6 +1,6 @@
[esp32s3_base]
extends = arduino_base
-platform = espressif32@^5.2.0
+platform = platformio/espressif32@^5.2.0
build_src_filter =
${arduino_base.build_src_filter} - - -
upload_speed = 961200
diff --git a/arch/nrf52/nrf52.ini b/arch/nrf52/nrf52.ini
index a79ebda48..f4e2af236 100644
--- a/arch/nrf52/nrf52.ini
+++ b/arch/nrf52/nrf52.ini
@@ -1,11 +1,9 @@
[nrf52_base]
; Instead of the standard nordicnrf52 platform, we use our fork which has our added variant files
-; platform = nordicnrf52 ;pending https://github.com/platformio/builder-framework-arduino-nrf5/pull/7
-platform = https://github.com/meshtastic/platform-nordicnrf52.git#merge
+platform = platformio/nordicnrf52@^9.4.0
extends = arduino_base
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 =
${arduino_base.build_flags} -Wno-unused-variable
-Isrc/platform/nrf52
diff --git a/arch/nrf52/nrf52840.ini b/arch/nrf52/nrf52840.ini
index 29c32e795..14cc1d1e1 100644
--- a/arch/nrf52/nrf52840.ini
+++ b/arch/nrf52/nrf52840.ini
@@ -4,7 +4,7 @@ build_flags = ${nrf52_base.build_flags}
lib_deps =
${arduino_base.lib_deps}
${environmental_base.lib_deps}
- https://github.com/Kongduino/Adafruit_nRFCrypto.git#20fc7fdaf086bd70e901c007dd23c6e8856aec25
+ https://github.com/Kongduino/Adafruit_nRFCrypto.git#e31a8825ea3300b163a0a3c1ddd5de34e10e1371
; Note: By default no lora device is created for this build - it uses a simulated interface
[env:nrf52840dk]
diff --git a/arch/rp2040/rp2040.ini b/arch/rp2040/rp2040.ini
index 6660cccd2..9eea340bf 100644
--- a/arch/rp2040/rp2040.ini
+++ b/arch/rp2040/rp2040.ini
@@ -1,6 +1,6 @@
; Common settings for rp2040 Processor based targets
[rp2040_base]
-platform = https://github.com/maxgerhardt/platform-raspberrypi.git
+platform = https://github.com/maxgerhardt/platform-raspberrypi.git#5ce1a228e7cae453f366deb8962252b9b7356bbc
extends = arduino_base
board_build.core = earlephilhower
board_build.filesystem_size = 0.5m
diff --git a/arch/stm32/stm32wl5e.ini b/arch/stm32/stm32wl5e.ini
index fc3f42ba7..d13750fdb 100644
--- a/arch/stm32/stm32wl5e.ini
+++ b/arch/stm32/stm32wl5e.ini
@@ -1,5 +1,5 @@
[stm32wl5e_base]
-platform = ststm32
+platform = platformio/ststm32@^15.4.1
board = generic_wl5e
framework = arduino
build_type = debug
diff --git a/bin/build-nrf52.sh b/bin/build-nrf52.sh
index 2202564e7..76972b100 100755
--- a/bin/build-nrf52.sh
+++ b/bin/build-nrf52.sh
@@ -26,7 +26,9 @@ basename=firmware-$1-$VERSION
pio run --environment $1 # -v
SRCELF=.pio/build/$1/firmware.elf
+DFUPKG=.pio/build/$1/firmware.zip
cp $SRCELF $OUTDIR/$basename.elf
+cp $DFUPKG $OUTDIR/$basename-ota.zip
echo "Generating NRF52 uf2 file"
SRCHEX=.pio/build/$1/firmware.hex
diff --git a/platformio.ini b/platformio.ini
index 36ffc27fe..1f97cfb19 100644
--- a/platformio.ini
+++ b/platformio.ini
@@ -2,7 +2,8 @@
; https://docs.platformio.org/page/projectconf.html
[platformio]
-default_envs = tbeam
+;default_envs = tbeam
+;default_envs = pico
;default_envs = tbeam-s3-core
;default_envs = tbeam0.7
;default_envs = heltec-v1
@@ -56,6 +57,9 @@ lib_deps =
; Used for the code analysis in PIO Home / Inspect
check_tool = cppcheck
check_skip_packages = yes
+check_flags =
+ --common-flag
+ cppcheck: --enable=--inline-suppr
; Common settings for conventional (non Portduino) Arduino targets
[arduino_base]
@@ -64,6 +68,7 @@ lib_deps =
${env.lib_deps}
; Portduino is using meshtastic fork for now
jgromes/RadioLib@5.4.1
+ https://github.com/caveman99/SparkFun_ATECCX08a_Arduino_Library.git#008e7f9d40bad66b2f7a0074aaac05b7c424339d
build_flags = ${env.build_flags} -Os
-DRADIOLIB_SPI_PARANOID=0
@@ -88,4 +93,5 @@ lib_deps =
adafruit/Adafruit MCP9808 Library@^2.0.0
adafruit/Adafruit INA260 Library@^1.5.0
adafruit/Adafruit INA219@^1.2.0
-
+ adafruit/Adafruit SHTC3 Library@^1.0.0
+ adafruit/Adafruit LPS2X@^2.0.4
\ No newline at end of file
diff --git a/protobufs b/protobufs
index 256f11954..d0559bfa3 160000
--- a/protobufs
+++ b/protobufs
@@ -1 +1 @@
-Subproject commit 256f11954b7c8fcb9dc4481771c24559925bf32a
+Subproject commit d0559bfa3c31023ed2f2aa3807b6a0a1da9a6feb
diff --git a/src/BluetoothCommon.cpp b/src/BluetoothCommon.cpp
index 0eda2080e..728b6f360 100644
--- a/src/BluetoothCommon.cpp
+++ b/src/BluetoothCommon.cpp
@@ -7,7 +7,7 @@ const uint8_t MESH_SERVICE_UUID_16[16u] = {0xfd, 0xea, 0x73, 0xe2, 0xca, 0x5d, 0
0x1f, 0x46, 0xa8, 0x15, 0x18, 0xb2, 0xa1, 0x6b};
const uint8_t TORADIO_UUID_16[16u] = {0xe7, 0x01, 0x44, 0x12, 0x66, 0x78, 0xdd, 0xa1,
0xad, 0x4d, 0x9e, 0x12, 0xd2, 0x76, 0x5c, 0xf7};
-const uint8_t FROMRADIO_UUID_16[16u] = {0xd5, 0x54, 0xe4, 0xc5, 0x25, 0xc5, 0x31, 0xa5,
- 0x55, 0x4a, 0x02, 0xee, 0xc2, 0xbc, 0xa2, 0x8b};
+const uint8_t FROMRADIO_UUID_16[16u] = {0x02, 0x00, 0x12, 0xac, 0x42, 0x02, 0x78, 0xb8,
+ 0xed, 0x11, 0x93, 0x49, 0x9e, 0xe6, 0x55, 0x2c};
const uint8_t FROMNUM_UUID_16[16u] = {0x53, 0x44, 0xe3, 0x47, 0x75, 0xaa, 0x70, 0xa6,
0x66, 0x4f, 0x00, 0xa8, 0x8c, 0xa1, 0x9d, 0xed};
\ No newline at end of file
diff --git a/src/BluetoothCommon.h b/src/BluetoothCommon.h
index 26c7b2cef..4352eba13 100644
--- a/src/BluetoothCommon.h
+++ b/src/BluetoothCommon.h
@@ -9,7 +9,7 @@
#define MESH_SERVICE_UUID "6ba1b218-15a8-461f-9fa8-5dcae273eafd"
#define TORADIO_UUID "f75c76d2-129e-4dad-a1dd-7866124401e7"
-#define FROMRADIO_UUID "8ba2bcc2-ee02-4a55-a531-c525c5e454d5"
+#define FROMRADIO_UUID "2c55e69e-4993-11ed-b878-0242ac120002"
#define FROMNUM_UUID "ed9da18c-a800-4f66-a670-aa7547e34453"
// NRF52 wants these constants as byte arrays
diff --git a/src/RedirectablePrint.cpp b/src/RedirectablePrint.cpp
index d1972d2ad..de9b95027 100644
--- a/src/RedirectablePrint.cpp
+++ b/src/RedirectablePrint.cpp
@@ -49,6 +49,13 @@ size_t RedirectablePrint::vprintf(const char *format, va_list arg)
if (len < 0) return 0;
+ // If the resulting string is longer than sizeof(printBuf)-1 characters, the remaining characters are still counted for the return value
+
+ if (len > sizeof(printBuf) - 1) {
+ len = sizeof(printBuf) - 1;
+ printBuf[sizeof(printBuf) - 2] = '\n';
+ }
+
len = Print::write(printBuf, len);
return len;
}
@@ -103,4 +110,4 @@ size_t RedirectablePrint::logDebug(const char *format, ...)
}
return r;
-}
\ No newline at end of file
+}
diff --git a/src/configuration.h b/src/configuration.h
index 524dbec36..9374c29d4 100644
--- a/src/configuration.h
+++ b/src/configuration.h
@@ -110,6 +110,16 @@ along with this program. If not, see .
#define INA_ADDR_ALTERNATE 0x41
#define QMC6310_ADDR 0x1C
#define QMI8658_ADDR 0x6B
+#define SHTC3_ADDR 0x70
+#define LPS22HB_ADDR 0x5C
+#define LPS22HB_ADDR_ALT 0x5D
+
+// -----------------------------------------------------------------------------
+// Security
+// -----------------------------------------------------------------------------
+
+#define ATECC608B_ADDR 0x35
+
// -----------------------------------------------------------------------------
// GPS
// -----------------------------------------------------------------------------
diff --git a/src/detect/i2cScan.h b/src/detect/i2cScan.h
index 3adb44277..6fc9d67d3 100644
--- a/src/detect/i2cScan.h
+++ b/src/detect/i2cScan.h
@@ -9,6 +9,41 @@
#endif
#if HAS_WIRE
+
+void printATECCInfo()
+{
+#ifndef ARCH_PORTDUINO
+ atecc.readConfigZone(false);
+
+ DEBUG_MSG("ATECC608B Serial Number: ");
+ for (int i = 0 ; i < 9 ; i++) {
+ DEBUG_MSG("%02x",atecc.serialNumber[i]);
+ }
+
+ DEBUG_MSG(", Rev Number: ");
+ for (int i = 0 ; i < 4 ; i++) {
+ DEBUG_MSG("%02x",atecc.revisionNumber[i]);
+ }
+ DEBUG_MSG("\n");
+
+ DEBUG_MSG("ATECC608B Config %s",atecc.configLockStatus ? "Locked" : "Unlocked");
+ DEBUG_MSG(", Data %s",atecc.dataOTPLockStatus ? "Locked" : "Unlocked");
+ DEBUG_MSG(", Slot 0 %s\n",atecc.slot0LockStatus ? "Locked" : "Unlocked");
+
+ if (atecc.configLockStatus && atecc.dataOTPLockStatus && atecc.slot0LockStatus) {
+ if (atecc.generatePublicKey() == false) {
+ DEBUG_MSG("ATECC608B Error generating public key\n");
+ } else {
+ DEBUG_MSG("ATECC608B Public Key: ");
+ for (int i = 0 ; i < 64 ; i++) {
+ DEBUG_MSG("%02x",atecc.publicKey64Bytes[i]);
+ }
+ DEBUG_MSG("\n");
+ }
+ }
+#endif
+}
+
uint16_t getRegisterValue(uint8_t address, uint8_t reg, uint8_t length) {
uint16_t value = 0x00;
Wire.beginTransmission(address);
@@ -79,6 +114,17 @@ void scanI2Cdevice(void)
DEBUG_MSG("unknown display found\n");
}
}
+#ifndef ARCH_PORTDUINO
+ if (addr == ATECC608B_ADDR){
+ keystore_found = addr;
+ if (atecc.begin(keystore_found) == true) {
+ DEBUG_MSG("ATECC608B initialized\n");
+ } else {
+ DEBUG_MSG("ATECC608B initialization failed\n");
+ }
+ printATECCInfo();
+ }
+#endif
#ifdef RV3028_RTC
if (addr == RV3028_RTC){
rtc_found = addr;
@@ -145,14 +191,22 @@ void scanI2Cdevice(void)
nodeTelemetrySensorsMap[TelemetrySensorType_MCP9808] = addr;
DEBUG_MSG("MCP9808 sensor found at address 0x%x\n", (uint8_t)addr);
}
- if(addr == QMC6310_ADDR){
+ if (addr == QMC6310_ADDR) {
DEBUG_MSG("QMC6310 3-Axis magnetic sensor found at address 0x%x\n", (uint8_t)addr);
nodeTelemetrySensorsMap[TelemetrySensorType_QMC6310] = addr;
}
- if(addr == QMI8658_ADDR){
+ if (addr == QMI8658_ADDR) {
DEBUG_MSG("QMI8658 6-Axis inertial measurement sensor found at address 0x%x\n", (uint8_t)addr);
nodeTelemetrySensorsMap[TelemetrySensorType_QMI8658] = addr;
}
+ if (addr == SHTC3_ADDR) {
+ DEBUG_MSG("SHTC3 sensor found at address 0x%x\n", (uint8_t)addr);
+ nodeTelemetrySensorsMap[TelemetrySensorType_SHTC3] = addr;
+ }
+ if (addr == LPS22HB_ADDR || addr == LPS22HB_ADDR_ALT) {
+ DEBUG_MSG("LPS22HB sensor found at address 0x%x\n", (uint8_t)addr);
+ nodeTelemetrySensorsMap[TelemetrySensorType_LPS22] = addr;
+ }
} else if (err == 4) {
DEBUG_MSG("Unknow error at address 0x%x\n", addr);
}
diff --git a/src/gps/NMEAWPL.cpp b/src/gps/NMEAWPL.cpp
new file mode 100644
index 000000000..95e69343b
--- /dev/null
+++ b/src/gps/NMEAWPL.cpp
@@ -0,0 +1,76 @@
+#include "NMEAWPL.h"
+
+/* -------------------------------------------
+ * 1 2 3 4 5 6
+ * | | | | | |
+ * $--WPL,llll.ll,a,yyyyy.yy,a,c--c*hh
+ *
+ * Field Number:
+ * 1 Latitude
+ * 2 N or S (North or South)
+ * 3 Longitude
+ * 4 E or W (East or West)
+ * 5 Waypoint name
+ * 6 Checksum
+ * -------------------------------------------
+ */
+
+uint printWPL(char *buf, const Position &pos, const char *name)
+{
+ uint len = sprintf(buf, "$GNWPL,%07.2f,%c,%08.2f,%c,%s", pos.latitude_i * 1e-5, pos.latitude_i < 0 ? 'S' : 'N', pos.longitude_i * 1e-5, pos.longitude_i < 0 ? 'W' : 'E', name);
+ uint chk = 0;
+ for (uint i = 1; i < len; i++) {
+ chk ^= buf[i];
+ }
+ len += sprintf(buf + len, "*%02X\r\n", chk);
+ return len;
+}
+
+/* -------------------------------------------
+ * 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
+ * | | | | | | | | | | | | | | |
+ * $--GGA,hhmmss.ss,ddmm.mm,a,ddmm.mm,a,x,xx,x.x,x.x,M,x.x,M,x.x,xxxx*hh
+ *
+ * Field Number:
+ * 1 UTC of this position report, hh is hours, mm is minutes, ss.ss is seconds.
+ * 2 Latitude
+ * 3 N or S (North or South)
+ * 4 Longitude
+ * 5 E or W (East or West)
+ * 6 GPS Quality Indicator (non null)
+ * 7 Number of satellites in use, 00 - 12
+ * 8 Horizontal Dilution of precision (meters)
+ * 9 Antenna Altitude above/below mean-sea-level (geoid) (in meters)
+ * 10 Units of antenna altitude, meters
+ * 11 Geoidal separation, the difference between the WGS-84 earth ellipsoid and mean-sea-level (geoid), "-" means mean-sea-level below ellipsoid
+ * 12 Units of geoidal separation, meters
+ * 13 Age of differential GPS data, time in seconds since last SC104 type 1 or 9 update, null field when DGPS is not used
+ * 14 Differential reference station ID, 0000-1023
+ * 15 Checksum
+ * -------------------------------------------
+ */
+
+uint printGGA(char *buf, const Position &pos)
+{
+ uint len = sprintf(buf, "$GNGGA,%06u.%03u,%07.2f,%c,%08.2f,%c,%u,%02u,%04u,%04d,%c,%04d,%c,%d,%04d",
+ pos.time / 1000,
+ pos.time % 1000,
+ pos.latitude_i * 1e-5, pos.latitude_i < 0 ? 'S' : 'N',
+ pos.longitude_i * 1e-5, pos.longitude_i < 0 ? 'W' : 'E',
+ pos.fix_type,
+ pos.sats_in_view,
+ pos.HDOP,
+ pos.altitude,
+ 'M',
+ pos.altitude_geoidal_separation,
+ 'M',
+ 0,
+ 0);
+
+ uint chk = 0;
+ for (uint i = 1; i < len; i++) {
+ chk ^= buf[i];
+ }
+ len += sprintf(buf + len, "*%02X\r\n", chk);
+ return len;
+}
\ No newline at end of file
diff --git a/src/gps/NMEAWPL.h b/src/gps/NMEAWPL.h
new file mode 100644
index 000000000..853c850eb
--- /dev/null
+++ b/src/gps/NMEAWPL.h
@@ -0,0 +1,7 @@
+#pragma once
+
+#include
+#include "main.h"
+
+uint printWPL(char *buf, const Position &pos, const char *name);
+uint printGGA(char *buf, const Position &pos);
diff --git a/src/gps/RTC.h b/src/gps/RTC.h
index f2df3c757..527b31f46 100644
--- a/src/gps/RTC.h
+++ b/src/gps/RTC.h
@@ -16,7 +16,7 @@ enum RTCQuality {
RTCQualityFromNet = 2,
/// Our time is based on NTP
- RTCQualityNTP= 3,
+ RTCQualityNTP = 3,
/// Our time is based on our own GPS
RTCQualityGPS = 4
diff --git a/src/graphics/Screen.cpp b/src/graphics/Screen.cpp
index 601b83f9c..0f6c96f0f 100644
--- a/src/graphics/Screen.cpp
+++ b/src/graphics/Screen.cpp
@@ -84,10 +84,6 @@ static char ourId[5];
// GeoCoord object for the screen
GeoCoord geoCoord;
-// OEM Config File
-static const char *oemConfigFile = "/oem/oem.proto";
-OEMStore oemStore;
-
#ifdef SHOW_REDRAWS
static bool heartbeat = false;
#endif
@@ -928,9 +924,6 @@ void Screen::setup()
dispdev.setDetected(screen_model);
#endif
- // Load OEM config from Proto file if existent
- loadProto(oemConfigFile, OEMStore_size, sizeof(oemConfigFile), OEMStore_fields, &oemStore);
-
// Initialising the UI will init the display too.
ui.init();
diff --git a/src/main.cpp b/src/main.cpp
index c9ed47818..d4d76cc3b 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -45,6 +45,7 @@
#include "RF95Interface.h"
#include "SX1262Interface.h"
#include "SX1268Interface.h"
+#include "SX1281Interface.h"
#if !HAS_RADIO && defined(ARCH_PORTDUINO)
#include "platform/portduino/SimRadio.h"
#endif
@@ -80,6 +81,14 @@ uint8_t kb_model;
// The I2C address of the RTC Module (if found)
uint8_t rtc_found;
+bool rIf_wide_lora = false;
+
+// Keystore Chips
+uint8_t keystore_found;
+#ifndef ARCH_PORTDUINO
+ATECCX08A atecc;
+#endif
+
bool eink_found = true;
uint32_t serialSinceMsec;
@@ -279,12 +288,10 @@ void setup()
power->setup(); // Must be after status handler is installed, so that handler gets notified of the initial configuration
/*
- * Repeat the scanning for I2C devices after power initialization.
+ * Repeat the scanning for I2C devices after power initialization or look for 'latecomers'.
* Boards with an PMU need to be powered on to correctly scan to the device address, such as t-beam-s3-core
*/
- if ((HW_VENDOR == HardwareModel_LILYGO_TBEAM_S3_CORE) || (HW_VENDOR == HardwareModel_TBEAM)) {
- scanI2Cdevice();
- }
+ scanI2Cdevice();
// Init our SPI controller (must be before screen and lora)
initSPI();
@@ -364,6 +371,20 @@ void setup()
}
#endif
+#if defined(USE_SX1281) && !defined(ARCH_PORTDUINO)
+ if (!rIf) {
+ rIf = new SX1281Interface(SX126X_CS, SX126X_DIO1, SX126X_RESET, SX126X_BUSY, SPI);
+ if (!rIf->init()) {
+ DEBUG_MSG("Warning: Failed to find SX1281 radio\n");
+ delete rIf;
+ rIf = NULL;
+ } else {
+ DEBUG_MSG("SX1281 Radio init succeeded, using SX1281 radio\n");
+ rIf_wide_lora = true;
+ }
+ }
+#endif
+
#if defined(USE_SX1262)
if (!rIf) {
rIf = new SX1262Interface(SX126X_CS, SX126X_DIO1, SX126X_RESET, SX126X_BUSY, SPI);
diff --git a/src/main.h b/src/main.h
index f3f9c62c9..bd24dec76 100644
--- a/src/main.h
+++ b/src/main.h
@@ -6,18 +6,27 @@
#include "PowerStatus.h"
#include "graphics/Screen.h"
#include "mesh/generated/telemetry.pb.h"
+#ifndef ARCH_PORTDUINO
+#include
+#endif
extern uint8_t screen_found;
extern uint8_t screen_model;
extern uint8_t cardkb_found;
extern uint8_t kb_model;
extern uint8_t rtc_found;
+extern uint8_t keystore_found;
+extern bool rIf_wide_lora;
extern bool eink_found;
extern bool pmu_found;
extern bool isCharging;
extern bool isUSBPowered;
+#ifndef ARCH_PORTDUINO
+extern ATECCX08A atecc;
+#endif
+
extern uint8_t nodeTelemetrySensorsMap[TelemetrySensorType_QMI8658+1];
extern int TCPPort; // set by Portduino
diff --git a/src/mesh/Channels.cpp b/src/mesh/Channels.cpp
index a87d66b14..200184720 100644
--- a/src/mesh/Channels.cpp
+++ b/src/mesh/Channels.cpp
@@ -62,13 +62,6 @@ Channel &Channels::fixupChannel(ChannelIndex chIndex)
// 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;
- } */
}
hashes[chIndex] = generateHash(chIndex);
@@ -124,7 +117,22 @@ CryptoKey Channels::getKey(ChannelIndex chIndex)
DEBUG_MSG("Expanding short PSK #%d\n", pskIndex);
if (pskIndex == 0)
k.length = 0; // Turn off encryption
- else {
+ else if (oemStore.oem_aes_key.size > 1) {
+ // Use the OEM key
+ DEBUG_MSG("Using OEM Key with %d bytes\n", oemStore.oem_aes_key.size);
+ memcpy(k.bytes, oemStore.oem_aes_key.bytes , oemStore.oem_aes_key.size);
+ k.length = oemStore.oem_aes_key.size;
+ // Bump up the last byte of PSK as needed
+ uint8_t *last = k.bytes + oemStore.oem_aes_key.size - 1;
+ *last = *last + pskIndex - 1; // index of 1 means no change vs defaultPSK
+ if (k.length < 16) {
+ DEBUG_MSG("Warning: OEM provided a too short AES128 key - padding\n");
+ k.length = 16;
+ } else if (k.length < 32 && k.length != 16) {
+ DEBUG_MSG("Warning: OEM provided a too short AES256 key - padding\n");
+ k.length = 32;
+ }
+ } else {
memcpy(k.bytes, defaultpsk, sizeof(defaultpsk));
k.length = sizeof(defaultpsk);
// Bump up the last byte of PSK as needed
diff --git a/src/mesh/InterfacesTemplates.cpp b/src/mesh/InterfacesTemplates.cpp
index 2c8d9b290..6707813db 100644
--- a/src/mesh/InterfacesTemplates.cpp
+++ b/src/mesh/InterfacesTemplates.cpp
@@ -1,7 +1,13 @@
#include "SX126xInterface.h"
#include "SX126xInterface.cpp"
+#include "SX128xInterface.h"
+#include "SX128xInterface.cpp"
// We need this declaration for proper linking in derived classes
template class SX126xInterface;
template class SX126xInterface;
-template class SX126xInterface;
\ No newline at end of file
+template class SX126xInterface;
+
+#if !defined(ARCH_PORTDUINO)
+template class SX128xInterface;
+#endif
\ No newline at end of file
diff --git a/src/mesh/MeshModule.cpp b/src/mesh/MeshModule.cpp
index 63f2a4358..7b204ae49 100644
--- a/src/mesh/MeshModule.cpp
+++ b/src/mesh/MeshModule.cpp
@@ -112,7 +112,7 @@ void MeshModule::callPlugins(const MeshPacket &mp, RxSource src)
bool rxChannelOk = !pi.boundChannel || (mp.from == 0) ||
!ch ||
strlen(ch->settings.name) > 0 ||
- (strcmp(ch->settings.name, pi.boundChannel) == 0);
+ (strcasecmp(ch->settings.name, pi.boundChannel) == 0);
if (!rxChannelOk) {
// no one should have already replied!
diff --git a/src/mesh/MeshRadio.h b/src/mesh/MeshRadio.h
index 961d62192..2cb7f4e6d 100644
--- a/src/mesh/MeshRadio.h
+++ b/src/mesh/MeshRadio.h
@@ -15,6 +15,7 @@ struct RegionInfo {
uint8_t powerLimit; // Or zero for not set
bool audioPermitted;
bool freqSwitching;
+ bool wideLora;
const char *name; // EU433 etc
};
diff --git a/src/mesh/MeshService.cpp b/src/mesh/MeshService.cpp
index 31d26b625..d5c7c4a19 100644
--- a/src/mesh/MeshService.cpp
+++ b/src/mesh/MeshService.cpp
@@ -283,3 +283,8 @@ int MeshService::onGPSChanged(const meshtastic::GPSStatus *newStatus)
return 0;
}
+
+bool MeshService::isToPhoneQueueEmpty()
+{
+ return toPhoneQueue.isEmpty();
+}
\ No newline at end of file
diff --git a/src/mesh/MeshService.h b/src/mesh/MeshService.h
index ffa8c06ec..24ec1c0bc 100644
--- a/src/mesh/MeshService.h
+++ b/src/mesh/MeshService.h
@@ -89,6 +89,8 @@ class MeshService
/// Send a packet to the phone
void sendToPhone(MeshPacket *p);
+ bool isToPhoneQueueEmpty();
+
private:
/// Called when our gps position has changed - updates nodedb and sends Location message out into the mesh
/// returns 0 to allow futher processing
diff --git a/src/mesh/NodeDB.cpp b/src/mesh/NodeDB.cpp
index 92115d127..8a7ee6086 100644
--- a/src/mesh/NodeDB.cpp
+++ b/src/mesh/NodeDB.cpp
@@ -38,6 +38,7 @@ MyNodeInfo &myNodeInfo = devicestate.my_node;
LocalConfig config;
LocalModuleConfig moduleConfig;
ChannelFile channelFile;
+OEMStore oemStore;
/** 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.
@@ -129,6 +130,8 @@ bool NodeDB::factoryReset()
// second, install default state (this will deal with the duplicate mac address issue)
installDefaultDeviceState();
installDefaultConfig();
+ installDefaultModuleConfig();
+ installDefaultChannels();
// third, write everything to disk
saveToDisk();
#ifdef ARCH_ESP32
@@ -354,6 +357,8 @@ static const char *prefFileName = "/prefs/db.proto";
static const char *configFileName = "/prefs/config.proto";
static const char *moduleConfigFileName = "/prefs/module.proto";
static const char *channelFileName = "/prefs/channels.proto";
+static const char *oemConfigFile = "/oem/oem.proto";
+
/** 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)
@@ -433,6 +438,9 @@ void NodeDB::loadFromDisk()
DEBUG_MSG("Loaded saved channelFile version %d\n", channelFile.version);
}
}
+
+ if (loadProto(oemConfigFile, OEMStore_size, sizeof(OEMStore), OEMStore_fields, &oemStore))
+ DEBUG_MSG("Loaded OEMStore\n");
}
/** Save a protobuf from a file, return true for success */
diff --git a/src/mesh/NodeDB.h b/src/mesh/NodeDB.h
index 574d6fe54..6b9744565 100644
--- a/src/mesh/NodeDB.h
+++ b/src/mesh/NodeDB.h
@@ -26,6 +26,7 @@ extern ChannelFile channelFile;
extern MyNodeInfo &myNodeInfo;
extern LocalConfig config;
extern LocalModuleConfig moduleConfig;
+extern OEMStore oemStore;
extern User &owner;
/// Given a node, return how many seconds in the past (vs now) that we last heard from it
diff --git a/src/mesh/PhoneAPI.cpp b/src/mesh/PhoneAPI.cpp
index a725e6283..2f060889a 100644
--- a/src/mesh/PhoneAPI.cpp
+++ b/src/mesh/PhoneAPI.cpp
@@ -79,17 +79,17 @@ bool PhoneAPI::handleToRadio(const uint8_t *buf, size_t bufLength)
memset(&toRadioScratch, 0, sizeof(toRadioScratch));
if (pb_decode_from_bytes(buf, bufLength, ToRadio_fields, &toRadioScratch)) {
switch (toRadioScratch.which_payload_variant) {
- case ToRadio_packet_tag:
- return handleToRadioPacket(toRadioScratch.packet);
- case ToRadio_want_config_id_tag:
- config_nonce = toRadioScratch.want_config_id;
- DEBUG_MSG("Client wants config, nonce=%u\n", config_nonce);
- handleStartConfig();
- break;
- case ToRadio_disconnect_tag:
- DEBUG_MSG("Disconnecting from phone\n");
- close();
- break;
+ case ToRadio_packet_tag:
+ return handleToRadioPacket(toRadioScratch.packet);
+ case ToRadio_want_config_id_tag:
+ config_nonce = toRadioScratch.want_config_id;
+ DEBUG_MSG("Client wants config, nonce=%u\n", config_nonce);
+ handleStartConfig();
+ break;
+ case ToRadio_disconnect_tag:
+ DEBUG_MSG("Disconnecting from phone\n");
+ close();
+ break;
default:
// Ignore nop messages
// DEBUG_MSG("Error: unexpected ToRadio variant\n");
@@ -109,8 +109,10 @@ bool PhoneAPI::handleToRadio(const uint8_t *buf, size_t bufLength)
*
* Our sending states progress in the following sequence (the client app ASSUMES THIS SEQUENCE, DO NOT CHANGE IT):
* STATE_SEND_MY_INFO, // send our my info record
+ * STATE_SEND_CHANNELS
* STATE_SEND_NODEINFO, // states progress in this order as the device sends to the client
STATE_SEND_CONFIG,
+ STATE_SEND_MODULE_CONFIG,
STATE_SEND_COMPLETE_ID,
STATE_SEND_PACKETS // send packets or debug strings
*/
@@ -128,7 +130,7 @@ size_t PhoneAPI::getFromRadio(uint8_t *buf)
case STATE_SEND_NOTHING:
DEBUG_MSG("getFromRadio=STATE_SEND_NOTHING\n");
break;
-
+
case STATE_SEND_MY_INFO:
DEBUG_MSG("getFromRadio=STATE_SEND_MY_INFO\n");
// If the user has specified they don't want our node to share its location, make sure to tell the phone
@@ -154,51 +156,63 @@ size_t PhoneAPI::getFromRadio(uint8_t *buf)
// Stay in current state until done sending nodeinfos
} else {
DEBUG_MSG("Done sending nodeinfos\n");
- state = STATE_SEND_CONFIG;
+ state = STATE_SEND_CHANNELS;
// Go ahead and send that ID right now
return getFromRadio(buf);
}
break;
}
+ case STATE_SEND_CHANNELS:
+ DEBUG_MSG("getFromRadio=STATE_SEND_CHANNELS\n");
+ fromRadioScratch.which_payload_variant = FromRadio_channel_tag;
+ fromRadioScratch.channel = channels.getByIndex(config_state);
+ config_state++;
+ // Advance when we have sent all of our Channels
+ if (config_state >= MAX_NUM_CHANNELS) {
+ state = STATE_SEND_CONFIG;
+ config_state = Config_device_tag;
+ }
+ break;
+
case STATE_SEND_CONFIG:
DEBUG_MSG("getFromRadio=STATE_SEND_CONFIG\n");
fromRadioScratch.which_payload_variant = FromRadio_config_tag;
switch (config_state) {
- case Config_device_tag:
- fromRadioScratch.config.which_payload_variant = Config_device_tag;
- fromRadioScratch.config.payload_variant.device = config.device;
- break;
- case Config_position_tag:
- fromRadioScratch.config.which_payload_variant = Config_position_tag;
- fromRadioScratch.config.payload_variant.position = config.position;
- break;
- case Config_power_tag:
- fromRadioScratch.config.which_payload_variant = Config_power_tag;
- fromRadioScratch.config.payload_variant.power = config.power;
- fromRadioScratch.config.payload_variant.power.ls_secs = default_ls_secs;
- break;
- case Config_network_tag:
- fromRadioScratch.config.which_payload_variant = Config_network_tag;
- fromRadioScratch.config.payload_variant.network = config.network;
- break;
- case Config_display_tag:
- fromRadioScratch.config.which_payload_variant = Config_display_tag;
- fromRadioScratch.config.payload_variant.display = config.display;
- break;
- case Config_lora_tag:
- fromRadioScratch.config.which_payload_variant = Config_lora_tag;
- fromRadioScratch.config.payload_variant.lora = config.lora;
- break;
- case Config_bluetooth_tag:
- fromRadioScratch.config.which_payload_variant = Config_bluetooth_tag;
- fromRadioScratch.config.payload_variant.bluetooth = config.bluetooth;
- break;
+ case Config_device_tag:
+ fromRadioScratch.config.which_payload_variant = Config_device_tag;
+ fromRadioScratch.config.payload_variant.device = config.device;
+ break;
+ case Config_position_tag:
+ fromRadioScratch.config.which_payload_variant = Config_position_tag;
+ fromRadioScratch.config.payload_variant.position = config.position;
+ break;
+ case Config_power_tag:
+ fromRadioScratch.config.which_payload_variant = Config_power_tag;
+ fromRadioScratch.config.payload_variant.power = config.power;
+ fromRadioScratch.config.payload_variant.power.ls_secs = default_ls_secs;
+ break;
+ case Config_network_tag:
+ fromRadioScratch.config.which_payload_variant = Config_network_tag;
+ fromRadioScratch.config.payload_variant.network = config.network;
+ break;
+ case Config_display_tag:
+ fromRadioScratch.config.which_payload_variant = Config_display_tag;
+ fromRadioScratch.config.payload_variant.display = config.display;
+ break;
+ case Config_lora_tag:
+ fromRadioScratch.config.which_payload_variant = Config_lora_tag;
+ fromRadioScratch.config.payload_variant.lora = config.lora;
+ break;
+ case Config_bluetooth_tag:
+ fromRadioScratch.config.which_payload_variant = Config_bluetooth_tag;
+ fromRadioScratch.config.payload_variant.bluetooth = config.bluetooth;
+ break;
}
// NOTE: The phone app needs to know the ls_secs value so it can properly expect sleep behavior.
// So even if we internally use 0 to represent 'use default' we still need to send the value we are
// using to the app (so that even old phone apps work with new device loads).
-
+
config_state++;
// Advance when we have sent all of our config objects
if (config_state > Config_bluetooth_tag) {
@@ -211,37 +225,37 @@ size_t PhoneAPI::getFromRadio(uint8_t *buf)
DEBUG_MSG("getFromRadio=STATE_SEND_MODULECONFIG\n");
fromRadioScratch.which_payload_variant = FromRadio_moduleConfig_tag;
switch (config_state) {
- case ModuleConfig_mqtt_tag:
- fromRadioScratch.moduleConfig.which_payload_variant = ModuleConfig_mqtt_tag;
- fromRadioScratch.moduleConfig.payload_variant.mqtt = moduleConfig.mqtt;
- break;
- case ModuleConfig_serial_tag:
- fromRadioScratch.moduleConfig.which_payload_variant = ModuleConfig_serial_tag;
- fromRadioScratch.moduleConfig.payload_variant.serial = moduleConfig.serial;
- break;
- case ModuleConfig_external_notification_tag:
- fromRadioScratch.moduleConfig.which_payload_variant = ModuleConfig_external_notification_tag;
- fromRadioScratch.moduleConfig.payload_variant.external_notification = moduleConfig.external_notification;
- break;
- case ModuleConfig_range_test_tag:
- fromRadioScratch.moduleConfig.which_payload_variant = ModuleConfig_range_test_tag;
- fromRadioScratch.moduleConfig.payload_variant.range_test = moduleConfig.range_test;
- break;
- case ModuleConfig_telemetry_tag:
- fromRadioScratch.moduleConfig.which_payload_variant = ModuleConfig_telemetry_tag;
- fromRadioScratch.moduleConfig.payload_variant.telemetry = moduleConfig.telemetry;
- break;
- case ModuleConfig_canned_message_tag:
- fromRadioScratch.moduleConfig.which_payload_variant = ModuleConfig_canned_message_tag;
- fromRadioScratch.moduleConfig.payload_variant.canned_message = moduleConfig.canned_message;
- break;
+ case ModuleConfig_mqtt_tag:
+ fromRadioScratch.moduleConfig.which_payload_variant = ModuleConfig_mqtt_tag;
+ fromRadioScratch.moduleConfig.payload_variant.mqtt = moduleConfig.mqtt;
+ break;
+ case ModuleConfig_serial_tag:
+ fromRadioScratch.moduleConfig.which_payload_variant = ModuleConfig_serial_tag;
+ fromRadioScratch.moduleConfig.payload_variant.serial = moduleConfig.serial;
+ break;
+ case ModuleConfig_external_notification_tag:
+ fromRadioScratch.moduleConfig.which_payload_variant = ModuleConfig_external_notification_tag;
+ fromRadioScratch.moduleConfig.payload_variant.external_notification = moduleConfig.external_notification;
+ break;
+ case ModuleConfig_range_test_tag:
+ fromRadioScratch.moduleConfig.which_payload_variant = ModuleConfig_range_test_tag;
+ fromRadioScratch.moduleConfig.payload_variant.range_test = moduleConfig.range_test;
+ break;
+ case ModuleConfig_telemetry_tag:
+ fromRadioScratch.moduleConfig.which_payload_variant = ModuleConfig_telemetry_tag;
+ fromRadioScratch.moduleConfig.payload_variant.telemetry = moduleConfig.telemetry;
+ break;
+ case ModuleConfig_canned_message_tag:
+ fromRadioScratch.moduleConfig.which_payload_variant = ModuleConfig_canned_message_tag;
+ fromRadioScratch.moduleConfig.payload_variant.canned_message = moduleConfig.canned_message;
+ break;
}
config_state++;
// Advance when we have sent all of our ModuleConfig objects
if (config_state > ModuleConfig_canned_message_tag) {
state = STATE_SEND_COMPLETE_ID;
- config_state = Config_device_tag;
+ config_state = 0;
}
break;
@@ -274,7 +288,8 @@ size_t PhoneAPI::getFromRadio(uint8_t *buf)
if (fromRadioScratch.which_payload_variant != 0) {
// Encapsulate as a FromRadio packet
size_t numbytes = pb_encode_to_bytes(buf, FromRadio_size, FromRadio_fields, &fromRadioScratch);
- // DEBUG_MSG("encoding toPhone packet to phone variant=%d, %d bytes\n", fromRadioScratch.which_payloadVariant, numbytes);
+
+ DEBUG_MSG("encoding toPhone packet to phone variant=%d, %d bytes\n", fromRadioScratch.which_payload_variant, numbytes);
return numbytes;
}
@@ -282,7 +297,7 @@ size_t PhoneAPI::getFromRadio(uint8_t *buf)
return 0;
}
-void PhoneAPI::handleDisconnect()
+void PhoneAPI::handleDisconnect()
{
DEBUG_MSG("PhoneAPI disconnect\n");
}
@@ -301,26 +316,25 @@ void PhoneAPI::releasePhonePacket()
bool PhoneAPI::available()
{
switch (state) {
- case STATE_SEND_NOTHING:
- return false;
- case STATE_SEND_MY_INFO:
- return true;
- case STATE_SEND_CONFIG:
- return true;
- case STATE_SEND_MODULECONFIG:
- return true;
- case STATE_SEND_NODEINFO:
- if (!nodeInfoForPhone)
- nodeInfoForPhone = nodeDB.readNextInfo();
- return true; // Always say we have something, because we might need to advance our state machine
- case STATE_SEND_COMPLETE_ID:
- return true;
- case STATE_SEND_PACKETS: {
- if (!packetForPhone)
- packetForPhone = service.getForPhone();
- bool hasPacket = !!packetForPhone;
- // DEBUG_MSG("available hasPacket=%d\n", hasPacket);
- return hasPacket;
+ case STATE_SEND_NOTHING:
+ return false;
+ case STATE_SEND_MY_INFO:
+ case STATE_SEND_CHANNELS:
+ case STATE_SEND_CONFIG:
+ case STATE_SEND_MODULECONFIG:
+ case STATE_SEND_COMPLETE_ID:
+ return true;
+ case STATE_SEND_NODEINFO:
+ if (!nodeInfoForPhone)
+ nodeInfoForPhone = nodeDB.readNextInfo();
+ return true; // Always say we have something, because we might need to advance our state machine
+
+ case STATE_SEND_PACKETS: {
+ if (!packetForPhone)
+ packetForPhone = service.getForPhone();
+ bool hasPacket = !!packetForPhone;
+ // DEBUG_MSG("available hasPacket=%d\n", hasPacket);
+ return hasPacket;
}
default:
assert(0); // unexpected state - FIXME, make an error code and reboot
diff --git a/src/mesh/PhoneAPI.h b/src/mesh/PhoneAPI.h
index fb372bde1..cbac5f688 100644
--- a/src/mesh/PhoneAPI.h
+++ b/src/mesh/PhoneAPI.h
@@ -16,13 +16,13 @@
* Eventually there should be once instance of this class for each live connection (because it has a bit of state
* for that connection)
*/
-class PhoneAPI
- : public Observer // FIXME, we shouldn't be inheriting from Observer, instead use CallbackObserver as a member
+class PhoneAPI : public Observer // FIXME, we shouldn't be inheriting from Observer, instead use CallbackObserver as a member
{
enum State {
STATE_SEND_NOTHING, // Initial state, don't send anything until the client starts asking for config
STATE_SEND_MY_INFO, // send our my info record
STATE_SEND_NODEINFO, // states progress in this order as the device sends to to the client
+ STATE_SEND_CHANNELS, // Send all channels
STATE_SEND_CONFIG, // Replacement for the old Radioconfig
STATE_SEND_MODULECONFIG, // Send Module specific config
STATE_SEND_COMPLETE_ID,
@@ -31,7 +31,7 @@ class PhoneAPI
State state = STATE_SEND_NOTHING;
- int8_t config_state = Config_device_tag;
+ uint8_t config_state = 0;
/**
* Each packet sent to the phone has an incrementing count
diff --git a/src/mesh/RadioInterface.cpp b/src/mesh/RadioInterface.cpp
index 1a6ad856d..07bb01108 100644
--- a/src/mesh/RadioInterface.cpp
+++ b/src/mesh/RadioInterface.cpp
@@ -6,15 +6,16 @@
#include "Router.h"
#include "assert.h"
#include "configuration.h"
+#include "main.h"
#include "sleep.h"
#include
#include
#include
-#define RDEF(name, freq_start, freq_end, duty_cycle, spacing, power_limit, audio_permitted, frequency_switching) \
+#define RDEF(name, freq_start, freq_end, duty_cycle, spacing, power_limit, audio_permitted, frequency_switching, wide_lora) \
{ \
Config_LoRaConfig_RegionCode_##name, freq_start, freq_end, duty_cycle, spacing, power_limit, audio_permitted, \
- frequency_switching, #name \
+ frequency_switching, wide_lora, #name \
}
const RegionInfo regions[] = {
@@ -22,12 +23,12 @@ const RegionInfo regions[] = {
https://link.springer.com/content/pdf/bbm%3A978-1-4842-4357-2%2F1.pdf
https://www.thethingsnetwork.org/docs/lorawan/regional-parameters/
*/
- RDEF(US, 902.0f, 928.0f, 100, 0, 30, true, false),
+ RDEF(US, 902.0f, 928.0f, 100, 0, 30, true, false, false),
/*
https://lora-alliance.org/wp-content/uploads/2020/11/lorawan_regional_parameters_v1.0.3reva_0.pdf
*/
- RDEF(EU_433, 433.0f, 434.0f, 10, 0, 12, true, false),
+ RDEF(EU_433, 433.0f, 434.0f, 10, 0, 12, true, false, false),
/*
https://www.thethingsnetwork.org/docs/lorawan/duty-cycle/
@@ -43,23 +44,23 @@ const RegionInfo regions[] = {
(Please refer to section 4.21 in the following document)
https://ec.europa.eu/growth/tools-databases/tris/index.cfm/ro/search/?trisaction=search.detail&year=2021&num=528&dLang=EN
*/
- RDEF(EU_868, 869.4f, 869.65f, 10, 0, 27, false, false),
+ RDEF(EU_868, 869.4f, 869.65f, 10, 0, 27, false, false, false),
/*
https://lora-alliance.org/wp-content/uploads/2020/11/lorawan_regional_parameters_v1.0.3reva_0.pdf
*/
- RDEF(CN, 470.0f, 510.0f, 100, 0, 19, true, false),
+ RDEF(CN, 470.0f, 510.0f, 100, 0, 19, true, false, false),
/*
https://lora-alliance.org/wp-content/uploads/2020/11/lorawan_regional_parameters_v1.0.3reva_0.pdf
*/
- RDEF(JP, 920.8f, 927.8f, 100, 0, 16, true, false),
+ RDEF(JP, 920.8f, 927.8f, 100, 0, 16, true, false, false),
/*
https://www.iot.org.au/wp/wp-content/uploads/2016/12/IoTSpectrumFactSheet.pdf
https://iotalliance.org.nz/wp-content/uploads/sites/4/2019/05/IoT-Spectrum-in-NZ-Briefing-Paper.pdf
*/
- RDEF(ANZ, 915.0f, 928.0f, 100, 0, 30, true, false),
+ RDEF(ANZ, 915.0f, 928.0f, 100, 0, 30, true, false, false),
/*
https://digital.gov.ru/uploaded/files/prilozhenie-12-k-reshenyu-gkrch-18-46-03-1.pdf
@@ -67,38 +68,44 @@ const RegionInfo regions[] = {
Note:
- We do LBT, so 100% is allowed.
*/
- RDEF(RU, 868.7f, 869.2f, 100, 0, 20, true, false),
+ RDEF(RU, 868.7f, 869.2f, 100, 0, 20, true, false, false),
/*
???
*/
- RDEF(KR, 920.0f, 923.0f, 100, 0, 0, true, false),
+ RDEF(KR, 920.0f, 923.0f, 100, 0, 0, true, false, false),
/*
???
*/
- RDEF(TW, 920.0f, 925.0f, 100, 0, 0, true, false),
+ RDEF(TW, 920.0f, 925.0f, 100, 0, 0, true, false, false),
/*
https://lora-alliance.org/wp-content/uploads/2020/11/lorawan_regional_parameters_v1.0.3reva_0.pdf
*/
- RDEF(IN, 865.0f, 867.0f, 100, 0, 30, true, false),
+ RDEF(IN, 865.0f, 867.0f, 100, 0, 30, true, false, false),
/*
https://rrf.rsm.govt.nz/smart-web/smart/page/-smart/domain/licence/LicenceSummary.wdk?id=219752
https://iotalliance.org.nz/wp-content/uploads/sites/4/2019/05/IoT-Spectrum-in-NZ-Briefing-Paper.pdf
*/
- RDEF(NZ_865, 864.0f, 868.0f, 100, 0, 0, true, false),
+ RDEF(NZ_865, 864.0f, 868.0f, 100, 0, 0, true, false, false),
/*
https://lora-alliance.org/wp-content/uploads/2020/11/lorawan_regional_parameters_v1.0.3reva_0.pdf
*/
- RDEF(TH, 920.0f, 925.0f, 100, 0, 16, true, false),
+ RDEF(TH, 920.0f, 925.0f, 100, 0, 16, true, false, false),
+
+ /*
+ 2.4 GHZ WLAN Band equivalent. Only for SX128x chips.
+ */
+
+ RDEF(LORA_24, 2400.0f, 2483.5f, 100, 0, 10, true, false, true),
/*
This needs to be last. Same as US.
*/
- RDEF(UNSET, 902.0f, 928.0f, 100, 0, 30, true, false)
+ RDEF(UNSET, 902.0f, 928.0f, 100, 0, 30, true, false, false)
};
@@ -355,39 +362,40 @@ void RadioInterface::applyModemConfig()
// No Sync Words in LORA mode
Config_LoRaConfig &loraConfig = config.lora;
if (loraConfig.spread_factor == 0) {
+
switch (loraConfig.modem_preset) {
case Config_LoRaConfig_ModemPreset_SHORT_FAST:
- bw = 250;
+ bw = (myRegion->wideLora && rIf_wide_lora) ? 800 : 250;
cr = 8;
sf = 7;
break;
case Config_LoRaConfig_ModemPreset_SHORT_SLOW:
- bw = 250;
+ bw = (myRegion->wideLora && rIf_wide_lora) ? 800 : 250;
cr = 8;
sf = 8;
break;
case Config_LoRaConfig_ModemPreset_MEDIUM_FAST:
- bw = 250;
+ bw = (myRegion->wideLora && rIf_wide_lora) ? 800 : 250;
cr = 8;
sf = 9;
break;
case Config_LoRaConfig_ModemPreset_MEDIUM_SLOW:
- bw = 250;
+ bw = (myRegion->wideLora && rIf_wide_lora) ? 800 : 250;
cr = 8;
sf = 10;
break;
case Config_LoRaConfig_ModemPreset_LONG_FAST:
- bw = 250;
+ bw = (myRegion->wideLora && rIf_wide_lora) ? 800 : 250;
cr = 8;
sf = 11;
break;
case Config_LoRaConfig_ModemPreset_LONG_SLOW:
- bw = 125;
+ bw = (myRegion->wideLora && rIf_wide_lora) ? 400 : 125;
cr = 8;
sf = 12;
break;
case Config_LoRaConfig_ModemPreset_VERY_LONG_SLOW:
- bw = 31.25;
+ bw = (myRegion->wideLora && rIf_wide_lora) ? 200 : 31.25;
cr = 8;
sf = 12;
break;
@@ -415,14 +423,14 @@ void RadioInterface::applyModemConfig()
power = 17; // Default to default power if we don't have a valid power
// Set final tx_power back onto config
- loraConfig.tx_power = power;
+ loraConfig.tx_power = (int8_t)power; // cppcheck-suppress assignmentAddressToInteger
// Calculate the number of channels
uint32_t numChannels = floor((myRegion->freqEnd - myRegion->freqStart) / (myRegion->spacing + (bw / 1000)));
// If user has manually specified a channel num, then use that, otherwise generate one by hashing the name
const char *channelName = channels.getName(channels.getPrimaryIndex());
- int channel_num = loraConfig.channel_num ? loraConfig.channel_num - 1 : hash(channelName) % numChannels;
+ int channel_num = (loraConfig.channel_num ? loraConfig.channel_num - 1 : hash(channelName)) % numChannels;
// Old frequency selection formula
// float freq = myRegion->freqStart + ((((myRegion->freqEnd - myRegion->freqStart) / numChannels) / 2) * channel_num);
diff --git a/src/mesh/ReliableRouter.cpp b/src/mesh/ReliableRouter.cpp
index f77e2a455..e42f2cdef 100644
--- a/src/mesh/ReliableRouter.cpp
+++ b/src/mesh/ReliableRouter.cpp
@@ -63,7 +63,7 @@ bool ReliableRouter::shouldFilterReceived(MeshPacket *p)
sendAckNak(Routing_Error_NONE, getFrom(p), p->id, p->channel);
DEBUG_MSG("acking a repeated want_ack packet\n");
}
- } else if (wasSeenRecently(p, false) && p->hop_limit == HOP_RELIABLE && !MeshModule::currentReply) {
+ } else if (wasSeenRecently(p, false) && p->hop_limit == HOP_RELIABLE && !MeshModule::currentReply && p->to != nodeDB.getNodeNum()) {
// retransmission on broadcast has hop_limit still equal to HOP_RELIABLE
DEBUG_MSG("Resending implicit ack for a repeated floodmsg\n");
MeshPacket *tosend = packetPool.allocCopy(*p);
diff --git a/src/mesh/SX1281Interface.cpp b/src/mesh/SX1281Interface.cpp
new file mode 100644
index 000000000..50805cfe0
--- /dev/null
+++ b/src/mesh/SX1281Interface.cpp
@@ -0,0 +1,13 @@
+#include "configuration.h"
+#include "SX1281Interface.h"
+#include "error.h"
+
+#if !defined(ARCH_PORTDUINO)
+
+SX1281Interface::SX1281Interface(RADIOLIB_PIN_TYPE cs, RADIOLIB_PIN_TYPE irq, RADIOLIB_PIN_TYPE rst, RADIOLIB_PIN_TYPE busy,
+ SPIClass &spi)
+ : SX128xInterface(cs, irq, rst, busy, spi)
+{
+}
+
+#endif
\ No newline at end of file
diff --git a/src/mesh/SX1281Interface.h b/src/mesh/SX1281Interface.h
new file mode 100644
index 000000000..3bd65309a
--- /dev/null
+++ b/src/mesh/SX1281Interface.h
@@ -0,0 +1,17 @@
+#pragma once
+
+#include "SX128xInterface.h"
+
+/**
+ * Our adapter for SX1281 radios
+ */
+
+#if !defined(ARCH_PORTDUINO)
+
+class SX1281Interface : public SX128xInterface
+{
+ public:
+ SX1281Interface(RADIOLIB_PIN_TYPE cs, RADIOLIB_PIN_TYPE irq, RADIOLIB_PIN_TYPE rst, RADIOLIB_PIN_TYPE busy, SPIClass &spi);
+};
+
+#endif
\ No newline at end of file
diff --git a/src/mesh/SX128xInterface.cpp b/src/mesh/SX128xInterface.cpp
new file mode 100644
index 000000000..10d791847
--- /dev/null
+++ b/src/mesh/SX128xInterface.cpp
@@ -0,0 +1,247 @@
+#include "configuration.h"
+#include "SX128xInterface.h"
+#include "error.h"
+
+#if !defined(ARCH_PORTDUINO)
+
+// Particular boards might define a different max power based on what their hardware can do
+#ifndef SX128X_MAX_POWER
+#define SX128X_MAX_POWER 22
+#endif
+
+template
+SX128xInterface::SX128xInterface(RADIOLIB_PIN_TYPE cs, RADIOLIB_PIN_TYPE irq, RADIOLIB_PIN_TYPE rst, RADIOLIB_PIN_TYPE busy,
+ SPIClass &spi)
+ : RadioLibInterface(cs, irq, rst, busy, spi, &lora), lora(&module)
+{
+}
+
+/// Initialise the Driver transport hardware and software.
+/// Make sure the Driver is properly configured before calling init().
+/// \return true if initialisation succeeded.
+template
+bool SX128xInterface::init()
+{
+#ifdef SX128X_POWER_EN
+ digitalWrite(SX128X_POWER_EN, HIGH);
+ pinMode(SX128X_POWER_EN, OUTPUT);
+#endif
+
+#ifdef SX128X_RXEN // set not rx or tx mode
+ digitalWrite(SX128X_RXEN, LOW); // Set low before becoming an output
+ pinMode(SX128X_RXEN, OUTPUT);
+#endif
+#ifdef SX128X_TXEN
+ digitalWrite(SX128X_TXEN, LOW);
+ pinMode(SX128X_TXEN, OUTPUT);
+#endif
+
+ RadioLibInterface::init();
+
+ if (power == 0)
+ power = SX128X_MAX_POWER;
+
+ if (power > SX128X_MAX_POWER) // This chip has lower power limits than some
+ power = SX128X_MAX_POWER;
+
+ limitPower();
+
+ int res = lora.begin(getFreq(), bw, sf, cr, syncWord, power, preambleLength);
+ // \todo Display actual typename of the adapter, not just `SX128x`
+ DEBUG_MSG("SX128x init result %d\n", res);
+
+ DEBUG_MSG("Frequency set to %f\n", getFreq());
+ DEBUG_MSG("Bandwidth set to %f\n", bw);
+ DEBUG_MSG("Power output set to %d\n", power);
+
+#ifdef SX128X_TXEN
+ // lora.begin sets Dio2 as RF switch control, which is not true if we are manually controlling RX and TX
+ if (res == RADIOLIB_ERR_NONE)
+ res = lora.setDio2AsRfSwitch(true);
+#endif
+
+ if (res == RADIOLIB_ERR_NONE)
+ res = lora.setCRC(RADIOLIB_SX128X_LORA_CRC_ON);
+
+ if (res == RADIOLIB_ERR_NONE)
+ startReceive(); // start receiving
+
+ return res == RADIOLIB_ERR_NONE;
+}
+
+template
+bool SX128xInterface::reconfigure()
+{
+ RadioLibInterface::reconfigure();
+
+ // set mode to standby
+ setStandby();
+
+ // configure publicly accessible settings
+ int err = lora.setSpreadingFactor(sf);
+ if (err != RADIOLIB_ERR_NONE)
+ RECORD_CRITICALERROR(CriticalErrorCode_INVALID_RADIO_SETTING);
+
+ err = lora.setBandwidth(bw);
+ if (err != RADIOLIB_ERR_NONE)
+ RECORD_CRITICALERROR(CriticalErrorCode_INVALID_RADIO_SETTING);
+
+ err = lora.setCodingRate(cr);
+ if (err != RADIOLIB_ERR_NONE)
+ RECORD_CRITICALERROR(CriticalErrorCode_INVALID_RADIO_SETTING);
+
+ // Hmm - seems to lower SNR when the signal levels are high. Leaving off for now...
+ // TODO: Confirm gain registers are okay now
+ // err = lora.setRxGain(true);
+ // assert(err == RADIOLIB_ERR_NONE);
+
+ err = lora.setSyncWord(syncWord);
+ assert(err == RADIOLIB_ERR_NONE);
+
+ err = lora.setPreambleLength(preambleLength);
+ assert(err == RADIOLIB_ERR_NONE);
+
+ err = lora.setFrequency(getFreq());
+ if (err != RADIOLIB_ERR_NONE)
+ RECORD_CRITICALERROR(CriticalErrorCode_INVALID_RADIO_SETTING);
+
+ if (power > 22) // This chip has lower power limits than some
+ power = 22;
+ err = lora.setOutputPower(power);
+ assert(err == RADIOLIB_ERR_NONE);
+
+ startReceive(); // restart receiving
+
+ return RADIOLIB_ERR_NONE;
+}
+
+template
+void INTERRUPT_ATTR SX128xInterface::disableInterrupt()
+{
+ lora.clearDio1Action();
+}
+
+template
+void SX128xInterface::setStandby()
+{
+ checkNotification(); // handle any pending interrupts before we force standby
+
+ int err = lora.standby();
+ assert(err == RADIOLIB_ERR_NONE);
+
+#ifdef SX128X_RXEN // we have RXEN/TXEN control - turn off RX and TX power
+ digitalWrite(SX128X_RXEN, LOW);
+#endif
+#ifdef SX128X_TXEN
+ digitalWrite(SX128X_TXEN, LOW);
+#endif
+
+ isReceiving = false; // If we were receiving, not any more
+ disableInterrupt();
+ completeSending(); // If we were sending, not anymore
+}
+
+/**
+ * Add SNR data to received messages
+ */
+template
+void SX128xInterface::addReceiveMetadata(MeshPacket *mp)
+{
+ // DEBUG_MSG("PacketStatus %x\n", lora.getPacketStatus());
+ mp->rx_snr = lora.getSNR();
+ mp->rx_rssi = lround(lora.getRSSI());
+}
+
+/** We override to turn on transmitter power as needed.
+ */
+template
+void SX128xInterface::configHardwareForSend()
+{
+#ifdef SX128X_TXEN // we have RXEN/TXEN control - turn on TX power / off RX power
+ digitalWrite(SX128X_TXEN, HIGH);
+#endif
+#ifdef SX128X_RXEN
+ digitalWrite(SX128X_RXEN, LOW);
+#endif
+
+ RadioLibInterface::configHardwareForSend();
+}
+
+// For power draw measurements, helpful to force radio to stay sleeping
+// #define SLEEP_ONLY
+
+template
+void SX128xInterface::startReceive()
+{
+#ifdef SLEEP_ONLY
+ sleep();
+#else
+
+ setStandby();
+
+#ifdef SX128X_RXEN // we have RXEN/TXEN control - turn on RX power / off TX power
+ digitalWrite(SX128X_RXEN, HIGH);
+#endif
+#ifdef SX128X_TXEN
+ digitalWrite(SX128X_TXEN, LOW);
+#endif
+
+ int err = lora.startReceive();
+
+ assert(err == RADIOLIB_ERR_NONE);
+
+ isReceiving = true;
+
+ // Must be done AFTER, starting transmit, because startTransmit clears (possibly stale) interrupt pending register bits
+ enableInterrupt(isrRxLevel0);
+#endif
+}
+
+/** Could we send right now (i.e. either not actively receving or transmitting)? */
+template
+bool SX128xInterface::isChannelActive()
+{
+ // check if we can detect a LoRa preamble on the current channel
+ int16_t result;
+
+ setStandby();
+ result = lora.scanChannel();
+ if (result == RADIOLIB_PREAMBLE_DETECTED)
+ return true;
+
+ assert(result != RADIOLIB_ERR_WRONG_MODEM);
+
+ return false;
+}
+
+/** Could we send right now (i.e. either not actively receving or transmitting)? */
+template
+bool SX128xInterface::isActivelyReceiving()
+{
+ return isChannelActive();
+}
+
+template
+bool SX128xInterface::sleep()
+{
+ // Not keeping config is busted - next time nrf52 board boots lora sending fails tcxo related? - see datasheet
+ // \todo Display actual typename of the adapter, not just `SX128x`
+ DEBUG_MSG("SX128x entering sleep mode (FIXME, don't keep config)\n");
+ setStandby(); // Stop any pending operations
+
+ // turn off TCXO if it was powered
+ // FIXME - this isn't correct
+ // lora.setTCXO(0);
+
+ // put chipset into sleep mode (we've already disabled interrupts by now)
+ bool keepConfig = true;
+ lora.sleep(keepConfig); // Note: we do not keep the config, full reinit will be needed
+
+#ifdef SX128X_POWER_EN
+ digitalWrite(SX128X_POWER_EN, LOW);
+#endif
+
+ return true;
+}
+
+#endif
\ No newline at end of file
diff --git a/src/mesh/SX128xInterface.h b/src/mesh/SX128xInterface.h
new file mode 100644
index 000000000..d01dfc510
--- /dev/null
+++ b/src/mesh/SX128xInterface.h
@@ -0,0 +1,75 @@
+#pragma once
+
+#if !defined(ARCH_PORTDUINO)
+
+#include "RadioLibInterface.h"
+
+/**
+ * \brief Adapter for SX128x radio family. Implements common logic for child classes.
+ * \tparam T RadioLib module type for SX128x: SX1281.
+ */
+template
+class SX128xInterface : public RadioLibInterface
+{
+ public:
+ SX128xInterface(RADIOLIB_PIN_TYPE cs, RADIOLIB_PIN_TYPE irq, RADIOLIB_PIN_TYPE rst, RADIOLIB_PIN_TYPE busy, SPIClass &spi);
+
+ /// Initialise the Driver transport hardware and software.
+ /// Make sure the Driver is properly configured before calling init().
+ /// \return true if initialisation succeeded.
+ virtual bool init() override;
+
+ /// Apply any radio provisioning changes
+ /// Make sure the Driver is properly configured before calling init().
+ /// \return true if initialisation succeeded.
+ virtual bool reconfigure() override;
+
+ /// Prepare hardware for sleep. Call this _only_ for deep sleep, not needed for light sleep.
+ virtual bool sleep() override;
+
+ protected:
+
+ float currentLimit = 140; // Higher OCP limit for SX128x PA
+
+ /**
+ * Specific module instance
+ */
+ T lora;
+
+ /**
+ * Glue functions called from ISR land
+ */
+ virtual void disableInterrupt() override;
+
+ /**
+ * Enable a particular ISR callback glue function
+ */
+ virtual void enableInterrupt(void (*callback)()) { lora.setDio1Action(callback); }
+
+ /** can we detect a LoRa preamble on the current channel? */
+ virtual bool isChannelActive() override;
+
+ /** are we actively receiving a packet (only called during receiving state) */
+ virtual bool isActivelyReceiving() override;
+
+ /**
+ * Start waiting to receive a message
+ */
+ virtual void startReceive() override;
+
+ /**
+ * We override to turn on transmitter power as needed.
+ */
+ virtual void configHardwareForSend() override;
+
+ /**
+ * Add SNR data to received messages
+ */
+ virtual void addReceiveMetadata(MeshPacket *mp) override;
+
+ virtual void setStandby() override;
+
+ private:
+};
+
+#endif
\ No newline at end of file
diff --git a/src/mesh/SinglePortModule.h b/src/mesh/SinglePortModule.h
index 2e587cb89..57db73221 100644
--- a/src/mesh/SinglePortModule.h
+++ b/src/mesh/SinglePortModule.h
@@ -18,6 +18,9 @@ class SinglePortModule : public MeshModule
SinglePortModule(const char *_name, PortNum _ourPortNum) : MeshModule(_name), ourPortNum(_ourPortNum) {}
protected:
+ uint32_t max_channel_util_percent = 40;
+ uint32_t polite_channel_util_percent = 25;
+
/**
* @return true if you want to receive the specified portnum
*/
diff --git a/src/mesh/generated/admin.pb.h b/src/mesh/generated/admin.pb.h
index 9392c19a0..9b93bfd44 100644
--- a/src/mesh/generated/admin.pb.h
+++ b/src/mesh/generated/admin.pb.h
@@ -59,8 +59,6 @@ typedef struct _AdminMessage {
AdminMessage_ModuleConfigType get_module_config_request;
/* Send the current Config in the response to this message. */
ModuleConfig get_module_config_response;
- /* Send all channels in the response to this message */
- bool get_all_channel_request;
/* Get the Canned Message Module messages in the response to this message. */
bool get_canned_message_module_messages_request;
/* Get the Canned Message Module messages in the response to this message. */
@@ -139,7 +137,6 @@ extern "C" {
#define AdminMessage_get_config_response_tag 6
#define AdminMessage_get_module_config_request_tag 7
#define AdminMessage_get_module_config_response_tag 8
-#define AdminMessage_get_all_channel_request_tag 9
#define AdminMessage_get_canned_message_module_messages_request_tag 10
#define AdminMessage_get_canned_message_module_messages_response_tag 11
#define AdminMessage_get_device_metadata_request_tag 12
@@ -170,7 +167,6 @@ X(a, STATIC, ONEOF, UENUM, (payload_variant,get_config_request,get_confi
X(a, STATIC, ONEOF, MESSAGE, (payload_variant,get_config_response,get_config_response), 6) \
X(a, STATIC, ONEOF, UENUM, (payload_variant,get_module_config_request,get_module_config_request), 7) \
X(a, STATIC, ONEOF, MESSAGE, (payload_variant,get_module_config_response,get_module_config_response), 8) \
-X(a, STATIC, ONEOF, BOOL, (payload_variant,get_all_channel_request,get_all_channel_request), 9) \
X(a, STATIC, ONEOF, BOOL, (payload_variant,get_canned_message_module_messages_request,get_canned_message_module_messages_request), 10) \
X(a, STATIC, ONEOF, STRING, (payload_variant,get_canned_message_module_messages_response,get_canned_message_module_messages_response), 11) \
X(a, STATIC, ONEOF, BOOL, (payload_variant,get_device_metadata_request,get_device_metadata_request), 12) \
diff --git a/src/mesh/generated/apponly.pb.h b/src/mesh/generated/apponly.pb.h
index 36bff5ad4..63f3cf3bf 100644
--- a/src/mesh/generated/apponly.pb.h
+++ b/src/mesh/generated/apponly.pb.h
@@ -54,7 +54,7 @@ extern const pb_msgdesc_t ChannelSet_msg;
#define ChannelSet_fields &ChannelSet_msg
/* Maximum encoded size of messages (where known) */
-#define ChannelSet_size 581
+#define ChannelSet_size 582
#ifdef __cplusplus
} /* extern "C" */
diff --git a/src/mesh/generated/config.pb.h b/src/mesh/generated/config.pb.h
index bc06b53ec..940771580 100644
--- a/src/mesh/generated/config.pb.h
+++ b/src/mesh/generated/config.pb.h
@@ -64,7 +64,8 @@ typedef enum _Config_LoRaConfig_RegionCode {
Config_LoRaConfig_RegionCode_RU = 9,
Config_LoRaConfig_RegionCode_IN = 10,
Config_LoRaConfig_RegionCode_NZ_865 = 11,
- Config_LoRaConfig_RegionCode_TH = 12
+ Config_LoRaConfig_RegionCode_TH = 12,
+ Config_LoRaConfig_RegionCode_LORA_24 = 13
} Config_LoRaConfig_RegionCode;
typedef enum _Config_LoRaConfig_ModemPreset {
@@ -116,7 +117,7 @@ typedef struct _Config_LoRaConfig {
uint32_t hop_limit;
bool tx_enabled;
int8_t tx_power;
- uint8_t channel_num;
+ uint16_t channel_num;
pb_size_t ignore_incoming_count;
uint32_t ignore_incoming[3];
} Config_LoRaConfig;
@@ -186,8 +187,8 @@ typedef struct _Config {
#define _Config_DisplayConfig_DisplayUnits_ARRAYSIZE ((Config_DisplayConfig_DisplayUnits)(Config_DisplayConfig_DisplayUnits_IMPERIAL+1))
#define _Config_LoRaConfig_RegionCode_MIN Config_LoRaConfig_RegionCode_UNSET
-#define _Config_LoRaConfig_RegionCode_MAX Config_LoRaConfig_RegionCode_TH
-#define _Config_LoRaConfig_RegionCode_ARRAYSIZE ((Config_LoRaConfig_RegionCode)(Config_LoRaConfig_RegionCode_TH+1))
+#define _Config_LoRaConfig_RegionCode_MAX Config_LoRaConfig_RegionCode_LORA_24
+#define _Config_LoRaConfig_RegionCode_ARRAYSIZE ((Config_LoRaConfig_RegionCode)(Config_LoRaConfig_RegionCode_LORA_24+1))
#define _Config_LoRaConfig_ModemPreset_MIN Config_LoRaConfig_ModemPreset_LONG_FAST
#define _Config_LoRaConfig_ModemPreset_MAX Config_LoRaConfig_ModemPreset_SHORT_FAST
@@ -387,7 +388,7 @@ extern const pb_msgdesc_t Config_BluetoothConfig_msg;
#define Config_BluetoothConfig_size 10
#define Config_DeviceConfig_size 6
#define Config_DisplayConfig_size 20
-#define Config_LoRaConfig_size 67
+#define Config_LoRaConfig_size 68
#define Config_NetworkConfig_size 137
#define Config_PositionConfig_size 30
#define Config_PowerConfig_size 43
diff --git a/src/mesh/generated/deviceonly.pb.h b/src/mesh/generated/deviceonly.pb.h
index e7ee26e8f..87a7c8cec 100644
--- a/src/mesh/generated/deviceonly.pb.h
+++ b/src/mesh/generated/deviceonly.pb.h
@@ -69,6 +69,7 @@ typedef struct _DeviceState {
} DeviceState;
typedef PB_BYTES_ARRAY_T(2048) OEMStore_oem_icon_bits_t;
+typedef PB_BYTES_ARRAY_T(32) OEMStore_oem_aes_key_t;
/* This can be used for customizing the firmware distribution. If populated,
show a secondary bootup screen with cuatom logo and text for 2.5 seconds. */
typedef struct _OEMStore {
@@ -82,6 +83,8 @@ typedef struct _OEMStore {
ScreenFonts oem_font;
/* Use this font for the OEM text. */
char oem_text[40];
+ /* The default device encryption key, 16 or 32 byte */
+ OEMStore_oem_aes_key_t oem_aes_key;
} OEMStore;
@@ -98,10 +101,10 @@ extern "C" {
/* 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, 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, 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}, 0}
-#define OEMStore_init_default {0, 0, {0, {0}}, _ScreenFonts_MIN, ""}
+#define OEMStore_init_default {0, 0, {0, {0}}, _ScreenFonts_MIN, "", {0, {0}}}
#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, 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, 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}, 0}
-#define OEMStore_init_zero {0, 0, {0, {0}}, _ScreenFonts_MIN, ""}
+#define OEMStore_init_zero {0, 0, {0, {0}}, _ScreenFonts_MIN, "", {0, {0}}}
/* Field tags (for use in manual encoding/decoding) */
#define ChannelFile_channels_tag 1
@@ -119,6 +122,7 @@ extern "C" {
#define OEMStore_oem_icon_bits_tag 3
#define OEMStore_oem_font_tag 4
#define OEMStore_oem_text_tag 5
+#define OEMStore_oem_aes_key_tag 6
/* Struct field encoding specification for nanopb */
#define DeviceState_FIELDLIST(X, a) \
@@ -150,7 +154,8 @@ X(a, STATIC, SINGULAR, UINT32, oem_icon_width, 1) \
X(a, STATIC, SINGULAR, UINT32, oem_icon_height, 2) \
X(a, STATIC, SINGULAR, BYTES, oem_icon_bits, 3) \
X(a, STATIC, SINGULAR, UENUM, oem_font, 4) \
-X(a, STATIC, SINGULAR, STRING, oem_text, 5)
+X(a, STATIC, SINGULAR, STRING, oem_text, 5) \
+X(a, STATIC, SINGULAR, BYTES, oem_aes_key, 6)
#define OEMStore_CALLBACK NULL
#define OEMStore_DEFAULT NULL
@@ -166,7 +171,7 @@ extern const pb_msgdesc_t OEMStore_msg;
/* Maximum encoded size of messages (where known) */
#define ChannelFile_size 638
#define DeviceState_size 21800
-#define OEMStore_size 2106
+#define OEMStore_size 2140
#ifdef __cplusplus
} /* extern "C" */
diff --git a/src/mesh/generated/localonly.pb.h b/src/mesh/generated/localonly.pb.h
index afbe06afe..d4c5fb012 100644
--- a/src/mesh/generated/localonly.pb.h
+++ b/src/mesh/generated/localonly.pb.h
@@ -144,7 +144,7 @@ extern const pb_msgdesc_t LocalModuleConfig_msg;
#define LocalModuleConfig_fields &LocalModuleConfig_msg
/* Maximum encoded size of messages (where known) */
-#define LocalConfig_size 334
+#define LocalConfig_size 335
#define LocalModuleConfig_size 270
#ifdef __cplusplus
diff --git a/src/mesh/generated/mesh.pb.h b/src/mesh/generated/mesh.pb.h
index 6849fac85..ee72ff504 100644
--- a/src/mesh/generated/mesh.pb.h
+++ b/src/mesh/generated/mesh.pb.h
@@ -4,6 +4,7 @@
#ifndef PB_MESH_PB_H_INCLUDED
#define PB_MESH_PB_H_INCLUDED
#include
+#include "channel.pb.h"
#include "config.pb.h"
#include "module_config.pb.h"
#include "portnums.pb.h"
@@ -652,6 +653,8 @@ typedef struct _FromRadio {
bool rebooted;
/* Include module config */
ModuleConfig moduleConfig;
+ /* One packet is sent for each channel */
+ Channel channel;
};
} FromRadio;
@@ -854,6 +857,7 @@ extern "C" {
#define FromRadio_config_complete_id_tag 7
#define FromRadio_rebooted_tag 8
#define FromRadio_moduleConfig_tag 9
+#define FromRadio_channel_tag 10
#define ToRadio_packet_tag 1
#define ToRadio_peer_info_tag 2
#define ToRadio_want_config_id_tag 3
@@ -1001,7 +1005,8 @@ X(a, STATIC, ONEOF, MESSAGE, (payload_variant,config,config), 5) \
X(a, STATIC, ONEOF, MESSAGE, (payload_variant,log_record,log_record), 6) \
X(a, STATIC, ONEOF, UINT32, (payload_variant,config_complete_id,config_complete_id), 7) \
X(a, STATIC, ONEOF, BOOL, (payload_variant,rebooted,rebooted), 8) \
-X(a, STATIC, ONEOF, MESSAGE, (payload_variant,moduleConfig,moduleConfig), 9)
+X(a, STATIC, ONEOF, MESSAGE, (payload_variant,moduleConfig,moduleConfig), 9) \
+X(a, STATIC, ONEOF, MESSAGE, (payload_variant,channel,channel), 10)
#define FromRadio_CALLBACK NULL
#define FromRadio_DEFAULT NULL
#define FromRadio_payload_variant_packet_MSGTYPE MeshPacket
@@ -1010,6 +1015,7 @@ X(a, STATIC, ONEOF, MESSAGE, (payload_variant,moduleConfig,moduleConfig),
#define FromRadio_payload_variant_config_MSGTYPE Config
#define FromRadio_payload_variant_log_record_MSGTYPE LogRecord
#define FromRadio_payload_variant_moduleConfig_MSGTYPE ModuleConfig
+#define FromRadio_payload_variant_channel_MSGTYPE Channel
#define ToRadio_FIELDLIST(X, a) \
X(a, STATIC, ONEOF, MESSAGE, (payload_variant,packet,packet), 1) \
diff --git a/src/mesh/generated/module_config.pb.h b/src/mesh/generated/module_config.pb.h
index 36ac24750..b0f14eea2 100644
--- a/src/mesh/generated/module_config.pb.h
+++ b/src/mesh/generated/module_config.pb.h
@@ -33,7 +33,8 @@ typedef enum _ModuleConfig_SerialConfig_Serial_Mode {
ModuleConfig_SerialConfig_Serial_Mode_DEFAULT = 0,
ModuleConfig_SerialConfig_Serial_Mode_SIMPLE = 1,
ModuleConfig_SerialConfig_Serial_Mode_PROTO = 2,
- ModuleConfig_SerialConfig_Serial_Mode_TEXTMSG = 3
+ ModuleConfig_SerialConfig_Serial_Mode_TEXTMSG = 3,
+ ModuleConfig_SerialConfig_Serial_Mode_NMEA = 4
} ModuleConfig_SerialConfig_Serial_Mode;
typedef enum _ModuleConfig_CannedMessageConfig_InputEventChar {
@@ -140,8 +141,8 @@ typedef struct _ModuleConfig {
#define _ModuleConfig_SerialConfig_Serial_Baud_ARRAYSIZE ((ModuleConfig_SerialConfig_Serial_Baud)(ModuleConfig_SerialConfig_Serial_Baud_BAUD_921600+1))
#define _ModuleConfig_SerialConfig_Serial_Mode_MIN ModuleConfig_SerialConfig_Serial_Mode_DEFAULT
-#define _ModuleConfig_SerialConfig_Serial_Mode_MAX ModuleConfig_SerialConfig_Serial_Mode_TEXTMSG
-#define _ModuleConfig_SerialConfig_Serial_Mode_ARRAYSIZE ((ModuleConfig_SerialConfig_Serial_Mode)(ModuleConfig_SerialConfig_Serial_Mode_TEXTMSG+1))
+#define _ModuleConfig_SerialConfig_Serial_Mode_MAX ModuleConfig_SerialConfig_Serial_Mode_NMEA
+#define _ModuleConfig_SerialConfig_Serial_Mode_ARRAYSIZE ((ModuleConfig_SerialConfig_Serial_Mode)(ModuleConfig_SerialConfig_Serial_Mode_NMEA+1))
#define _ModuleConfig_CannedMessageConfig_InputEventChar_MIN ModuleConfig_CannedMessageConfig_InputEventChar_NONE
#define _ModuleConfig_CannedMessageConfig_InputEventChar_MAX ModuleConfig_CannedMessageConfig_InputEventChar_BACK
diff --git a/src/mesh/http/ContentHandler.cpp b/src/mesh/http/ContentHandler.cpp
index 6763d70fe..91f88dda0 100644
--- a/src/mesh/http/ContentHandler.cpp
+++ b/src/mesh/http/ContentHandler.cpp
@@ -79,8 +79,8 @@ void registerHandlers(HTTPServer *insecureServer, HTTPSServer *secureServer)
ResourceNode *nodeHotspotAndroid = new ResourceNode("/generate_204", "GET", &handleHotspot);
ResourceNode *nodeAdmin = new ResourceNode("/admin", "GET", &handleAdmin);
- ResourceNode *nodeAdminSettings = new ResourceNode("/admin/settings", "GET", &handleAdminSettings);
- ResourceNode *nodeAdminSettingsApply = new ResourceNode("/admin/settings/apply", "POST", &handleAdminSettingsApply);
+ // ResourceNode *nodeAdminSettings = new ResourceNode("/admin/settings", "GET", &handleAdminSettings);
+ // ResourceNode *nodeAdminSettingsApply = new ResourceNode("/admin/settings/apply", "POST", &handleAdminSettingsApply);
// ResourceNode *nodeAdminFs = new ResourceNode("/admin/fs", "GET", &handleFs);
// ResourceNode *nodeUpdateFs = new ResourceNode("/admin/fs/update", "POST", &handleUpdateFs);
// ResourceNode *nodeDeleteFs = new ResourceNode("/admin/fs/delete", "GET", &handleDeleteFsContent);
@@ -113,8 +113,8 @@ void registerHandlers(HTTPServer *insecureServer, HTTPSServer *secureServer)
// secureServer->registerNode(nodeDeleteFs);
secureServer->registerNode(nodeAdmin);
// secureServer->registerNode(nodeAdminFs);
- secureServer->registerNode(nodeAdminSettings);
- secureServer->registerNode(nodeAdminSettingsApply);
+ // secureServer->registerNode(nodeAdminSettings);
+ // secureServer->registerNode(nodeAdminSettingsApply);
secureServer->registerNode(nodeRoot); // This has to be last
// Insecure nodes
@@ -134,8 +134,8 @@ void registerHandlers(HTTPServer *insecureServer, HTTPSServer *secureServer)
// insecureServer->registerNode(nodeDeleteFs);
insecureServer->registerNode(nodeAdmin);
// insecureServer->registerNode(nodeAdminFs);
- insecureServer->registerNode(nodeAdminSettings);
- insecureServer->registerNode(nodeAdminSettingsApply);
+ // insecureServer->registerNode(nodeAdminSettings);
+ // insecureServer->registerNode(nodeAdminSettingsApply);
insecureServer->registerNode(nodeRoot); // This has to be last
}
@@ -694,8 +694,8 @@ void handleAdmin(HTTPRequest *req, HTTPResponse *res)
res->setHeader("Access-Control-Allow-Methods", "GET");
res->println("Meshtastic
\n");
- res->println("Settings
\n");
- res->println("Manage Web Content
\n");
+ // res->println("Settings
\n");
+ // res->println("Manage Web Content
\n");
res->println("Device Report
\n");
}
diff --git a/src/mesh/http/WiFiAPClient.cpp b/src/mesh/http/WiFiAPClient.cpp
index b169f8ca8..4a4ac05a9 100644
--- a/src/mesh/http/WiFiAPClient.cpp
+++ b/src/mesh/http/WiFiAPClient.cpp
@@ -43,40 +43,25 @@ bool APStartupComplete = 0;
static bool needReconnect = true; // If we create our reconnector, run it once at the beginning
-// FIXME, veto light sleep if we have a TCP server running
-#if 0
-class WifiSleepObserver : public Observer {
-protected:
-
- /// Return 0 if sleep is okay
- virtual int onNotify(uint32_t newValue) {
-
- }
-};
-
-static WifiSleepObserver wifiSleepObserver;
-//preflightSleepObserver.observe(&preflightSleep);
-#endif
-
static int32_t reconnectWiFi()
{
const char *wifiName = config.network.wifi_ssid;
const char *wifiPsw = config.network.wifi_psk;
if (config.network.wifi_enabled && needReconnect && !WiFi.isConnected()) {
- // if (radioConfig.has_preferences && needReconnect && !WiFi.isConnected()) {
-
+
if (!*wifiPsw) // Treat empty password as no password
wifiPsw = NULL;
if (*wifiName) {
needReconnect = false;
+ // Make sure we clear old connection credentials
+ WiFi.disconnect(false, true);
+
DEBUG_MSG("... Reconnecting to WiFi access point\n");
WiFi.mode(WIFI_MODE_STA);
WiFi.begin(wifiName, wifiPsw);
-
- // Starting timeClient;
}
}
diff --git a/src/modules/AdminModule.cpp b/src/modules/AdminModule.cpp
index 883ed0ac3..6a10c618a 100644
--- a/src/modules/AdminModule.cpp
+++ b/src/modules/AdminModule.cpp
@@ -101,9 +101,7 @@ bool AdminModule::handleReceivedProtobuf(const MeshPacket &mp, AdminMessage *r)
* Other
*/
case AdminMessage_reboot_seconds_tag: {
- int32_t s = r->reboot_seconds;
- DEBUG_MSG("Rebooting in %d seconds\n", s);
- rebootAtMsec = (s < 0) ? 0 : (millis() + s * 1000);
+ reboot(r->reboot_seconds);
break;
}
case AdminMessage_reboot_ota_seconds_tag: {
@@ -135,13 +133,13 @@ bool AdminModule::handleReceivedProtobuf(const MeshPacket &mp, AdminMessage *r)
case AdminMessage_factory_reset_tag: {
DEBUG_MSG("Initiating factory reset\n");
nodeDB.factoryReset();
- rebootAtMsec = millis() + (5 * 1000);
+ reboot(5);
break;
}
case AdminMessage_nodedb_reset_tag: {
DEBUG_MSG("Initiating node-db reset\n");
nodeDB.resetNodes();
- rebootAtMsec = millis() + (5 * 1000);
+ reboot(5);
break;
}
#ifdef ARCH_PORTDUINO
@@ -196,14 +194,12 @@ void AdminModule::handleSetOwner(const User &o)
if (changed) { // If nothing really changed, don't broadcast on the network or write to flash
service.reloadOwner();
DEBUG_MSG("Rebooting due to owner changes\n");
- screen->startRebootScreen();
- rebootAtMsec = millis() + (5 * 1000);
+ reboot(5);
}
}
void AdminModule::handleSetConfig(const Config &c)
{
- bool requiresReboot = false;
bool isRouter = (config.device.role == Config_DeviceConfig_Role_ROUTER);
bool isRegionUnset = (config.lora.region == Config_LoRaConfig_RegionCode_UNSET);
@@ -218,12 +214,13 @@ void AdminModule::handleSetConfig(const Config &c)
nodeDB.initConfigIntervals();
nodeDB.initModuleConfigIntervals();
}
- requiresReboot = true;
break;
case Config_position_tag:
DEBUG_MSG("Setting config: Position\n");
config.has_position = true;
config.position = c.payload_variant.position;
+ // Save nodedb as well in case we got a fixed position packet
+ nodeDB.saveToDisk(SEGMENT_DEVICESTATE);
break;
case Config_power_tag:
DEBUG_MSG("Setting config: Power\n");
@@ -234,7 +231,6 @@ void AdminModule::handleSetConfig(const Config &c)
DEBUG_MSG("Setting config: WiFi\n");
config.has_network = true;
config.network = c.payload_variant.network;
- requiresReboot = true;
break;
case Config_display_tag:
DEBUG_MSG("Setting config: Display\n");
@@ -249,23 +245,16 @@ void AdminModule::handleSetConfig(const Config &c)
config.lora.region > Config_LoRaConfig_RegionCode_UNSET) {
config.lora.tx_enabled = true;
}
- requiresReboot = true;
break;
case Config_bluetooth_tag:
DEBUG_MSG("Setting config: Bluetooth\n");
config.has_bluetooth = true;
config.bluetooth = c.payload_variant.bluetooth;
- requiresReboot = true;
break;
}
service.reloadConfig(SEGMENT_CONFIG);
- // Reboot 5 seconds after a config that requires rebooting is set
- if (requiresReboot) {
- DEBUG_MSG("Rebooting due to config changes\n");
- screen->startRebootScreen();
- rebootAtMsec = millis() + (5 * 1000);
- }
+ reboot(5);
}
void AdminModule::handleSetModuleConfig(const ModuleConfig &c)
@@ -307,8 +296,9 @@ void AdminModule::handleSetModuleConfig(const ModuleConfig &c)
moduleConfig.canned_message = c.payload_variant.canned_message;
break;
}
-
+
service.reloadConfig(SEGMENT_MODULECONFIG);
+ reboot(5);
}
void AdminModule::handleSetChannel(const Channel &cc)
@@ -468,6 +458,13 @@ void AdminModule::handleGetChannel(const MeshPacket &req, uint32_t channelIndex)
}
}
+void AdminModule::reboot(int32_t seconds)
+{
+ DEBUG_MSG("Rebooting in %d seconds\n", seconds);
+ screen->startRebootScreen();
+ rebootAtMsec = (seconds < 0) ? 0 : (millis() + seconds * 1000);
+}
+
AdminModule::AdminModule() : ProtobufModule("Admin", PortNum_ADMIN_APP, AdminMessage_fields)
{
// restrict to the admin channel for rx
diff --git a/src/modules/AdminModule.h b/src/modules/AdminModule.h
index 9a87c7f9e..dd81c3218 100644
--- a/src/modules/AdminModule.h
+++ b/src/modules/AdminModule.h
@@ -37,6 +37,7 @@ class AdminModule : public ProtobufModule
void handleSetConfig(const Config &c);
void handleSetModuleConfig(const ModuleConfig &c);
void handleSetChannel();
+ void reboot(int32_t seconds);
};
extern AdminModule *adminModule;
diff --git a/src/modules/CannedMessageModule.cpp b/src/modules/CannedMessageModule.cpp
index 29ea20257..b00dfb796 100644
--- a/src/modules/CannedMessageModule.cpp
+++ b/src/modules/CannedMessageModule.cpp
@@ -225,7 +225,7 @@ int32_t CannedMessageModule::runOnce()
this->cursor = 0;
this->destSelect = false;
this->notifyObservers(&e);
- } else if (((this->runState == CANNED_MESSAGE_RUN_STATE_ACTIVE) || (this->runState == CANNED_MESSAGE_RUN_STATE_FREETEXT)) && (millis() - this->lastTouchMillis) > INACTIVATE_AFTER_MS) {
+ } else if (((this->runState == CANNED_MESSAGE_RUN_STATE_ACTIVE) || (this->runState == CANNED_MESSAGE_RUN_STATE_FREETEXT)) && ((millis() - this->lastTouchMillis) > INACTIVATE_AFTER_MS)) {
// Reset module
DEBUG_MSG("Reset due to lack of activity.\n");
e.frameChanged = true;
@@ -430,6 +430,8 @@ void CannedMessageModule::drawFrame(OLEDDisplay *display, OLEDDisplayUiState *st
{
displayedNodeNum = 0; // Not currently showing a node pane
+ char buffer[50];
+
if (cannedMessageModule->runState == CANNED_MESSAGE_RUN_STATE_SENDING_ACTIVE) {
display->setTextAlignment(TEXT_ALIGN_CENTER);
display->setFont(FONT_MEDIUM);
@@ -445,7 +447,6 @@ void CannedMessageModule::drawFrame(OLEDDisplay *display, OLEDDisplayUiState *st
display->fillRect(0 + x, 0 + y, x + display->getWidth(), y + FONT_HEIGHT_SMALL);
display->setColor(BLACK);
}
- char buffer[50];
display->drawStringf(0 + x, 0 + y, buffer, "To: %s", cannedMessageModule->getNodeName(this->dest));
// used chars right aligned
sprintf(buffer, "%d left", Constants_DATA_PAYLOAD_LEN - this->freetext.length());
@@ -456,11 +457,13 @@ void CannedMessageModule::drawFrame(OLEDDisplay *display, OLEDDisplayUiState *st
if (this->messagesCount > 0) {
display->setTextAlignment(TEXT_ALIGN_LEFT);
display->setFont(FONT_SMALL);
- display->drawString(0 + x, 0 + y, cannedMessageModule->getPrevMessage());
- display->setFont(FONT_MEDIUM);
- display->drawString(0 + x, 0 + y + FONT_HEIGHT_SMALL, cannedMessageModule->getCurrentMessage());
- display->setFont(FONT_SMALL);
- display->drawString(0 + x, 0 + y + FONT_HEIGHT_MEDIUM, cannedMessageModule->getNextMessage());
+ display->drawStringf(0 + x, 0 + y, buffer, "To: %s", cannedMessageModule->getNodeName(this->dest));
+ display->drawString(0 + x, 0 + y + FONT_HEIGHT_SMALL, cannedMessageModule->getPrevMessage());
+ display->fillRect(0 + x, 0 + y + FONT_HEIGHT_SMALL * 2, x + display->getWidth(), y + FONT_HEIGHT_SMALL);
+ display->setColor(BLACK);
+ display->drawString(0 + x, 0 + y + FONT_HEIGHT_SMALL * 2, cannedMessageModule->getCurrentMessage());
+ display->setColor(WHITE);
+ display->drawString(0 + x, 0 + y + FONT_HEIGHT_SMALL * 3, cannedMessageModule->getNextMessage());
}
}
}
diff --git a/src/modules/CannedMessageModule.h b/src/modules/CannedMessageModule.h
index b9ef5c413..2edef4655 100644
--- a/src/modules/CannedMessageModule.h
+++ b/src/modules/CannedMessageModule.h
@@ -87,4 +87,4 @@ class CannedMessageModule :
};
extern CannedMessageModule *cannedMessageModule;
-#endif
\ No newline at end of file
+#endif
diff --git a/src/modules/Modules.cpp b/src/modules/Modules.cpp
index 91f3f2edd..986a375df 100644
--- a/src/modules/Modules.cpp
+++ b/src/modules/Modules.cpp
@@ -60,13 +60,15 @@ void setupModules()
new DeviceTelemetryModule();
new EnvironmentTelemetryModule();
#endif
+#if (defined(ARCH_ESP32) || defined(ARCH_NRF52)) && !defined(TTGO_T_ECHO)
+ new SerialModule();
+#endif
#ifdef ARCH_ESP32
// Only run on an esp32 based device.
/*
Maintained by MC Hamster (Jm Casler) jm@casler.org
*/
- new SerialModule();
new ExternalNotificationModule();
storeForwardModule = new StoreForwardModule();
diff --git a/src/modules/PositionModule.cpp b/src/modules/PositionModule.cpp
index 572d7063b..5159de278 100644
--- a/src/modules/PositionModule.cpp
+++ b/src/modules/PositionModule.cpp
@@ -108,7 +108,7 @@ MeshPacket *PositionModule::allocReply()
// 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) {
+ if (getRTCQuality() < RTCQualityDevice) {
DEBUG_MSG("Stripping time %u from position send\n", p.time);
p.time = 0;
} else
@@ -144,7 +144,7 @@ int32_t PositionModule::runOnce()
if (lastGpsSend == 0 || (now - lastGpsSend) >= intervalMs) {
// Only send packets if the channel is less than 40% utilized.
- if (airTime->channelUtilizationPercent() < 40) {
+ if (airTime->channelUtilizationPercent() < max_channel_util_percent) {
if (node->has_position && (node->position.latitude_i != 0 || node->position.longitude_i != 0)) {
lastGpsSend = now;
@@ -165,7 +165,7 @@ int32_t PositionModule::runOnce()
} else if (config.position.position_broadcast_smart_enabled) {
// Only send packets if the channel is less than 25% utilized.
- if (airTime->channelUtilizationPercent() < 25) {
+ if (airTime->channelUtilizationPercent() < polite_channel_util_percent) {
NodeInfo *node2 = service.refreshMyNodeInfo(); // should guarantee there is now a position
diff --git a/src/modules/SerialModule.cpp b/src/modules/SerialModule.cpp
index 59f489d52..05ed44cd7 100644
--- a/src/modules/SerialModule.cpp
+++ b/src/modules/SerialModule.cpp
@@ -2,6 +2,7 @@
#include "MeshService.h"
#include "NodeDB.h"
#include "RTC.h"
+#include "NMEAWPL.h"
#include "Router.h"
#include "configuration.h"
#include
@@ -40,7 +41,7 @@
KNOWN PROBLEMS
* Until the module 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.
+ * Will not work on T-Echo and the Linux device targets.
*/
@@ -62,16 +63,19 @@ char serialStringChar[Constants_DATA_PAYLOAD_LEN];
SerialModuleRadio::SerialModuleRadio() : MeshModule("SerialModuleRadio")
{
- // restrict to the admin channel for rx
- boundChannel = Channels::serialChannel;
switch (moduleConfig.serial.mode)
{
case ModuleConfig_SerialConfig_Serial_Mode_TEXTMSG:
ourPortNum = PortNum_TEXT_MESSAGE_APP;
break;
+ case ModuleConfig_SerialConfig_Serial_Mode_NMEA:
+ ourPortNum = PortNum_POSITION_APP;
+ break;
default:
ourPortNum = PortNum_SERIAL_APP;
+ // restrict to the serial channel for rx
+ boundChannel = Channels::serialChannel;
break;
}
}
@@ -175,15 +179,25 @@ int32_t SerialModule::runOnce()
firstTime = 0;
} else {
- String serialString;
- while (Serial2.available()) {
- serialString = Serial2.readString();
- serialString.toCharArray(serialStringChar, Constants_DATA_PAYLOAD_LEN);
+ // in NMEA mode send out GGA every 2 seconds, Don't read from Port
+ if (moduleConfig.serial.mode == ModuleConfig_SerialConfig_Serial_Mode_NMEA) {
+ if (millis() - lastNmeaTime > 2000) {
+ lastNmeaTime = millis();
+ printGGA(outbuf, nodeDB.getNode(myNodeInfo.my_node_num)->position);
+ Serial2.printf("%s", outbuf);
+ }
+ } else {
+ String serialString;
- serialModuleRadio->sendPayload();
+ while (Serial2.available()) {
+ serialString = Serial2.readString();
+ serialString.toCharArray(serialStringChar, Constants_DATA_PAYLOAD_LEN);
- DEBUG_MSG("Received: %s\n", serialStringChar);
+ serialModuleRadio->sendPayload();
+
+ DEBUG_MSG("Received: %s\n", serialStringChar);
+ }
}
}
@@ -191,7 +205,7 @@ int32_t SerialModule::runOnce()
} else {
DEBUG_MSG("Serial Module Disabled\n");
- return (INT32_MAX);
+ return INT32_MAX;
}
#else
return INT32_MAX;
@@ -255,6 +269,19 @@ ProcessMessage SerialModuleRadio::handleReceived(const MeshPacket &mp)
} else if (moduleConfig.serial.mode == ModuleConfig_SerialConfig_Serial_Mode_PROTO) {
// TODO this needs to be implemented
+ } else if (moduleConfig.serial.mode == ModuleConfig_SerialConfig_Serial_Mode_NMEA) {
+ // Decode the Payload some more
+ Position scratch;
+ Position *decoded = NULL;
+ if (mp.which_payload_variant == MeshPacket_decoded_tag && mp.decoded.portnum == ourPortNum) {
+ memset(&scratch, 0, sizeof(scratch));
+ if (pb_decode_from_bytes(p.payload.bytes, p.payload.size, Position_fields, &scratch)) {
+ decoded = &scratch;
+ }
+ // send position packet as WPL to the serial port
+ printWPL(outbuf, *decoded, nodeDB.getNode(getFrom(&mp))->user.long_name);
+ Serial2.printf("%s", outbuf);
+ }
}
}
diff --git a/src/modules/SerialModule.h b/src/modules/SerialModule.h
index e93cb5952..0130bbe2d 100644
--- a/src/modules/SerialModule.h
+++ b/src/modules/SerialModule.h
@@ -11,6 +11,8 @@
class SerialModule : private concurrency::OSThread
{
bool firstTime = 1;
+ unsigned long lastNmeaTime = millis();
+ char outbuf[90] = "";
public:
SerialModule();
@@ -28,6 +30,7 @@ extern SerialModule *serialModule;
class SerialModuleRadio : public MeshModule
{
uint32_t lastRxID = 0;
+ char outbuf[90] = "";
public:
SerialModuleRadio();
diff --git a/src/modules/Telemetry/DeviceTelemetry.cpp b/src/modules/Telemetry/DeviceTelemetry.cpp
index 612cf6c1f..f3d787682 100644
--- a/src/modules/Telemetry/DeviceTelemetry.cpp
+++ b/src/modules/Telemetry/DeviceTelemetry.cpp
@@ -9,19 +9,23 @@
#include "main.h"
#include
#include
+#include "MeshService.h"
int32_t DeviceTelemetryModule::runOnce()
{
#ifndef ARCH_PORTDUINO
- if (firstTime) {
- // This is the first time the OSThread library has called this function, so do some setup
- firstTime = 0;
- DEBUG_MSG("Device Telemetry: Initializing\n");
+ uint32_t now = millis();
+ if ((lastSentToMesh == 0 ||
+ (now - lastSentToMesh) >= getConfiguredOrDefaultMs(moduleConfig.telemetry.device_update_interval)) &&
+ airTime->channelUtilizationPercent() < max_channel_util_percent) {
+ sendTelemetry();
+ lastSentToMesh = now;
+ } else if (service.isToPhoneQueueEmpty()) {
+ // Just send to phone when it's not our time to send to mesh yet
+ // Only send while queue is empty (phone assumed connected)
+ sendTelemetry(NODENUM_BROADCAST, true);
}
- sendOurTelemetry();
- // OSThread library. Multiply the preference value by 1000 to convert seconds to miliseconds
-
- return getConfiguredOrDefaultMs(moduleConfig.telemetry.device_update_interval);
+ return sendToPhoneIntervalMs;
#endif
}
@@ -29,14 +33,13 @@ bool DeviceTelemetryModule::handleReceivedProtobuf(const MeshPacket &mp, Telemet
{
if (t->which_variant == Telemetry_device_metrics_tag) {
const char *sender = getSenderShortName(mp);
-
- DEBUG_MSG("-----------------------------------------\n");
- DEBUG_MSG("Device Telemetry: Received data from %s\n", sender);
- DEBUG_MSG("Telemetry->time: %i\n", t->time);
- DEBUG_MSG("Telemetry->air_util_tx: %f\n", t->variant.device_metrics.air_util_tx);
- DEBUG_MSG("Telemetry->battery_level: %i\n", t->variant.device_metrics.battery_level);
- DEBUG_MSG("Telemetry->channel_utilization: %f\n", t->variant.device_metrics.channel_utilization);
- DEBUG_MSG("Telemetry->voltage: %f\n", t->variant.device_metrics.voltage);
+
+ DEBUG_MSG("(Received from %s): air_util_tx=%f, channel_utilization=%f, battery_level=%i, voltage=%f\n",
+ sender,
+ t->variant.device_metrics.air_util_tx,
+ t->variant.device_metrics.channel_utilization,
+ t->variant.device_metrics.battery_level,
+ t->variant.device_metrics.voltage);
lastMeasurementPacket = packetPool.allocCopy(mp);
@@ -45,7 +48,7 @@ bool DeviceTelemetryModule::handleReceivedProtobuf(const MeshPacket &mp, Telemet
return false; // Let others look at this message also if they want
}
-bool DeviceTelemetryModule::sendOurTelemetry(NodeNum dest, bool wantReplies)
+bool DeviceTelemetryModule::sendTelemetry(NodeNum dest, bool phoneOnly)
{
Telemetry t;
@@ -57,22 +60,25 @@ bool DeviceTelemetryModule::sendOurTelemetry(NodeNum dest, bool wantReplies)
t.variant.device_metrics.channel_utilization = myNodeInfo.channel_utilization;
t.variant.device_metrics.voltage = powerStatus->getBatteryVoltageMv() / 1000.0;
- DEBUG_MSG("-----------------------------------------\n");
- DEBUG_MSG("Device Telemetry: Read data\n");
-
- DEBUG_MSG("Telemetry->time: %i\n", t.time);
- DEBUG_MSG("Telemetry->air_util_tx: %f\n", t.variant.device_metrics.air_util_tx);
- DEBUG_MSG("Telemetry->battery_level: %i\n", t.variant.device_metrics.battery_level);
- DEBUG_MSG("Telemetry->channel_utilization: %f\n", t.variant.device_metrics.channel_utilization);
- DEBUG_MSG("Telemetry->voltage: %f\n", t.variant.device_metrics.voltage);
+ DEBUG_MSG("(Sending): air_util_tx=%f, channel_utilization=%f, battery_level=%i, voltage=%f\n",
+ t.variant.device_metrics.air_util_tx,
+ t.variant.device_metrics.channel_utilization,
+ t.variant.device_metrics.battery_level,
+ t.variant.device_metrics.voltage);
MeshPacket *p = allocDataProtobuf(t);
p->to = dest;
- p->decoded.want_response = wantReplies;
+ p->decoded.want_response = false;
+ p->priority = MeshPacket_Priority_MIN;
lastMeasurementPacket = packetPool.allocCopy(*p);
- DEBUG_MSG("Device Telemetry: Sending packet to mesh\n");
- service.sendToMesh(p, RX_SRC_LOCAL, true);
nodeDB.updateTelemetry(nodeDB.getNodeNum(), t, RX_SRC_LOCAL);
+ if (phoneOnly) {
+ DEBUG_MSG("Sending packet to phone\n");
+ service.sendToPhone(p);
+ } else {
+ DEBUG_MSG("Sending packet to mesh\n");
+ service.sendToMesh(p, RX_SRC_LOCAL, true);
+ }
return true;
}
diff --git a/src/modules/Telemetry/DeviceTelemetry.h b/src/modules/Telemetry/DeviceTelemetry.h
index 1a10ffcfa..0fb33ceee 100644
--- a/src/modules/Telemetry/DeviceTelemetry.h
+++ b/src/modules/Telemetry/DeviceTelemetry.h
@@ -11,7 +11,8 @@ class DeviceTelemetryModule : private concurrency::OSThread, public ProtobufModu
DeviceTelemetryModule()
: concurrency::OSThread("DeviceTelemetryModule"), ProtobufModule("DeviceTelemetry", PortNum_TELEMETRY_APP, &Telemetry_msg)
{
- lastMeasurementPacket = nullptr;
+ lastMeasurementPacket = nullptr;
+ setIntervalFromNow(10 * 1000);
}
virtual bool wantUIFrame() { return false; }
@@ -24,9 +25,10 @@ class DeviceTelemetryModule : private concurrency::OSThread, public ProtobufModu
/**
* Send our Telemetry into the mesh
*/
- bool sendOurTelemetry(NodeNum dest = NODENUM_BROADCAST, bool wantReplies = false);
+ bool sendTelemetry(NodeNum dest = NODENUM_BROADCAST, bool phoneOnly = false);
private:
- bool firstTime = 1;
+ uint32_t sendToPhoneIntervalMs = SECONDS_IN_MINUTE * 1000; // Send to phone every minute
+ uint32_t lastSentToMesh = 0;
const MeshPacket *lastMeasurementPacket;
};
diff --git a/src/modules/Telemetry/EnvironmentTelemetry.cpp b/src/modules/Telemetry/EnvironmentTelemetry.cpp
index 36e6a8176..cd5cd03bc 100644
--- a/src/modules/Telemetry/EnvironmentTelemetry.cpp
+++ b/src/modules/Telemetry/EnvironmentTelemetry.cpp
@@ -9,6 +9,7 @@
#include "main.h"
#include
#include
+#include "MeshService.h"
// Sensors
#include "Sensor/BMP280Sensor.h"
@@ -17,6 +18,8 @@
#include "Sensor/MCP9808Sensor.h"
#include "Sensor/INA260Sensor.h"
#include "Sensor/INA219Sensor.h"
+#include "Sensor/SHTC3Sensor.h"
+#include "Sensor/LPS22HBSensor.h"
BMP280Sensor bmp280Sensor;
BME280Sensor bme280Sensor;
@@ -24,6 +27,8 @@ BME680Sensor bme680Sensor;
MCP9808Sensor mcp9808Sensor;
INA260Sensor ina260Sensor;
INA219Sensor ina219Sensor;
+SHTC3Sensor shtc3Sensor;
+LPS22HBSensor lps22hbSensor;
#define FAILED_STATE_SENSOR_READ_MULTIPLIER 10
#define DISPLAY_RECEIVEID_MEASUREMENTS_ON_SCREEN true
@@ -83,21 +88,31 @@ int32_t EnvironmentTelemetryModule::runOnce()
result = ina260Sensor.runOnce();
if (ina219Sensor.hasSensor())
result = ina219Sensor.runOnce();
+ if (shtc3Sensor.hasSensor())
+ result = shtc3Sensor.runOnce();
+ if (lps22hbSensor.hasSensor()) {
+ result = lps22hbSensor.runOnce();
+ }
}
return result;
} else {
// if we somehow got to a second run of this module with measurement disabled, then just wait forever
if (!moduleConfig.telemetry.environment_measurement_enabled)
return result;
- // this is not the first time OSThread library has called this function
- // so just do what we intend to do on the interval
- if (!sendOurTelemetry()) {
- // if we failed to read the sensor, then try again
- // as soon as we can according to the maximum polling frequency
- return DEFAULT_SENSOR_MINIMUM_WAIT_TIME_BETWEEN_READS;
+
+ uint32_t now = millis();
+ if ((lastSentToMesh == 0 ||
+ (now - lastSentToMesh) >= getConfiguredOrDefaultMs(moduleConfig.telemetry.environment_update_interval)) &&
+ airTime->channelUtilizationPercent() < max_channel_util_percent) {
+ sendTelemetry();
+ lastSentToMesh = now;
+ } else if (service.isToPhoneQueueEmpty()) {
+ // Just send to phone when it's not our time to send to mesh yet
+ // Only send while queue is empty (phone assumed connected)
+ sendTelemetry(NODENUM_BROADCAST, true);
}
}
- return getConfiguredOrDefaultMs(moduleConfig.telemetry.environment_update_interval);
+ return sendToPhoneIntervalMs;
#endif
}
@@ -143,7 +158,7 @@ void EnvironmentTelemetryModule::drawFrame(OLEDDisplay *display, OLEDDisplayUiSt
if (!pb_decode_from_bytes(p.payload.bytes, p.payload.size, Telemetry_fields, &lastMeasurement)) {
display->setFont(FONT_SMALL);
display->drawString(x, y += fontHeight(FONT_MEDIUM), "Measurement Error");
- DEBUG_MSG("Environment Telemetry: unable to decode last packet");
+ DEBUG_MSG("Unable to decode last packet");
return;
}
@@ -168,15 +183,14 @@ bool EnvironmentTelemetryModule::handleReceivedProtobuf(const MeshPacket &mp, Te
if (t->which_variant == Telemetry_environment_metrics_tag) {
const char *sender = getSenderShortName(mp);
- DEBUG_MSG("-----------------------------------------\n");
- DEBUG_MSG("Environment Telemetry: Received data from %s\n", sender);
- DEBUG_MSG("Telemetry->time: %i\n", t->time);
- DEBUG_MSG("Telemetry->barometric_pressure: %f\n", t->variant.environment_metrics.barometric_pressure);
- DEBUG_MSG("Telemetry->current: %f\n", t->variant.environment_metrics.current);
- DEBUG_MSG("Telemetry->gas_resistance: %f\n", t->variant.environment_metrics.gas_resistance);
- DEBUG_MSG("Telemetry->relative_humidity: %f\n", t->variant.environment_metrics.relative_humidity);
- DEBUG_MSG("Telemetry->temperature: %f\n", t->variant.environment_metrics.temperature);
- DEBUG_MSG("Telemetry->voltage: %f\n", t->variant.environment_metrics.voltage);
+ DEBUG_MSG("(Received from %s): barometric_pressure=%f, current=%f, gas_resistance=%f, relative_humidity=%f, temperature=%f, voltage=%f\n",
+ sender,
+ t->variant.environment_metrics.barometric_pressure,
+ t->variant.environment_metrics.current,
+ t->variant.environment_metrics.gas_resistance,
+ t->variant.environment_metrics.relative_humidity,
+ t->variant.environment_metrics.temperature,
+ t->variant.environment_metrics.voltage);
lastMeasurementPacket = packetPool.allocCopy(mp);
}
@@ -184,7 +198,7 @@ bool EnvironmentTelemetryModule::handleReceivedProtobuf(const MeshPacket &mp, Te
return false; // Let others look at this message also if they want
}
-bool EnvironmentTelemetryModule::sendOurTelemetry(NodeNum dest, bool wantReplies)
+bool EnvironmentTelemetryModule::sendTelemetry(NodeNum dest, bool phoneOnly)
{
Telemetry m;
m.time = getTime();
@@ -197,9 +211,10 @@ bool EnvironmentTelemetryModule::sendOurTelemetry(NodeNum dest, bool wantReplies
m.variant.environment_metrics.temperature = 0;
m.variant.environment_metrics.voltage = 0;
- DEBUG_MSG("-----------------------------------------\n");
- DEBUG_MSG("Environment Telemetry: Read data\n");
-
+ if (lps22hbSensor.hasSensor())
+ lps22hbSensor.getMetrics(&m);
+ if (shtc3Sensor.hasSensor())
+ shtc3Sensor.getMetrics(&m);
if (bmp280Sensor.hasSensor())
bmp280Sensor.getMetrics(&m);
if (bme280Sensor.hasSensor())
@@ -213,22 +228,28 @@ bool EnvironmentTelemetryModule::sendOurTelemetry(NodeNum dest, bool wantReplies
if (ina260Sensor.hasSensor())
ina260Sensor.getMetrics(&m);
- DEBUG_MSG("Telemetry->time: %i\n", m.time);
- DEBUG_MSG("Telemetry->barometric_pressure: %f\n", m.variant.environment_metrics.barometric_pressure);
- DEBUG_MSG("Telemetry->current: %f\n", m.variant.environment_metrics.current);
- DEBUG_MSG("Telemetry->gas_resistance: %f\n", m.variant.environment_metrics.gas_resistance);
- DEBUG_MSG("Telemetry->relative_humidity: %f\n", m.variant.environment_metrics.relative_humidity);
- DEBUG_MSG("Telemetry->temperature: %f\n", m.variant.environment_metrics.temperature);
- DEBUG_MSG("Telemetry->voltage: %f\n", m.variant.environment_metrics.voltage);
+ DEBUG_MSG("(Sending): barometric_pressure=%f, current=%f, gas_resistance=%f, relative_humidity=%f, temperature=%f, voltage=%f\n",
+ m.variant.environment_metrics.barometric_pressure,
+ m.variant.environment_metrics.current,
+ m.variant.environment_metrics.gas_resistance,
+ m.variant.environment_metrics.relative_humidity,
+ m.variant.environment_metrics.temperature,
+ m.variant.environment_metrics.voltage);
sensor_read_error_count = 0;
MeshPacket *p = allocDataProtobuf(m);
p->to = dest;
- p->decoded.want_response = wantReplies;
+ p->decoded.want_response = false;
+ p->priority = MeshPacket_Priority_MIN;
lastMeasurementPacket = packetPool.allocCopy(*p);
- DEBUG_MSG("Environment Telemetry: Sending packet to mesh");
- service.sendToMesh(p, RX_SRC_LOCAL, true);
+ if (phoneOnly) {
+ DEBUG_MSG("Sending packet to phone\n");
+ service.sendToPhone(p);
+ } else {
+ DEBUG_MSG("Sending packet to mesh\n");
+ service.sendToMesh(p, RX_SRC_LOCAL, true);
+ }
return true;
}
diff --git a/src/modules/Telemetry/EnvironmentTelemetry.h b/src/modules/Telemetry/EnvironmentTelemetry.h
index e1a612288..c081ead51 100644
--- a/src/modules/Telemetry/EnvironmentTelemetry.h
+++ b/src/modules/Telemetry/EnvironmentTelemetry.h
@@ -12,7 +12,8 @@ class EnvironmentTelemetryModule : private concurrency::OSThread, public Protobu
: concurrency::OSThread("EnvironmentTelemetryModule"),
ProtobufModule("EnvironmentTelemetry", PortNum_TELEMETRY_APP, &Telemetry_msg)
{
- lastMeasurementPacket = nullptr;
+ lastMeasurementPacket = nullptr;
+ setIntervalFromNow(10 * 1000);
}
virtual bool wantUIFrame() override;
#if !HAS_SCREEN
@@ -30,11 +31,13 @@ class EnvironmentTelemetryModule : private concurrency::OSThread, public Protobu
/**
* Send our Telemetry into the mesh
*/
- bool sendOurTelemetry(NodeNum dest = NODENUM_BROADCAST, bool wantReplies = false);
+ bool sendTelemetry(NodeNum dest = NODENUM_BROADCAST, bool wantReplies = false);
private:
float CelsiusToFahrenheit(float c);
bool firstTime = 1;
const MeshPacket *lastMeasurementPacket;
+ uint32_t sendToPhoneIntervalMs = SECONDS_IN_MINUTE * 1000; // Send to phone every minute
+ uint32_t lastSentToMesh = 0;
uint32_t sensor_read_error_count = 0;
};
diff --git a/src/modules/Telemetry/Sensor/LPS22HBSensor.cpp b/src/modules/Telemetry/Sensor/LPS22HBSensor.cpp
new file mode 100644
index 000000000..1209c1435
--- /dev/null
+++ b/src/modules/Telemetry/Sensor/LPS22HBSensor.cpp
@@ -0,0 +1,36 @@
+#include "../mesh/generated/telemetry.pb.h"
+#include "configuration.h"
+#include "TelemetrySensor.h"
+#include "LPS22HBSensor.h"
+#include
+#include
+
+LPS22HBSensor::LPS22HBSensor() :
+ TelemetrySensor(TelemetrySensorType_LPS22, "LPS22HB")
+{
+}
+
+int32_t LPS22HBSensor::runOnce() {
+ DEBUG_MSG("Init sensor: %s\n", sensorName);
+ if (!hasSensor()) {
+ return DEFAULT_SENSOR_MINIMUM_WAIT_TIME_BETWEEN_READS;
+ }
+ status = lps22hb.begin_I2C(nodeTelemetrySensorsMap[sensorType]);
+ return initI2CSensor();
+}
+
+void LPS22HBSensor::setup()
+{
+ lps22hb.setDataRate(LPS22_RATE_10_HZ);
+}
+
+bool LPS22HBSensor::getMetrics(Telemetry *measurement) {
+ sensors_event_t temp;
+ sensors_event_t pressure;
+ lps22hb.getEvent(&pressure, &temp);
+
+ measurement->variant.environment_metrics.temperature = temp.temperature;
+ measurement->variant.environment_metrics.barometric_pressure = pressure.pressure;
+
+ return true;
+}
\ No newline at end of file
diff --git a/src/modules/Telemetry/Sensor/LPS22HBSensor.h b/src/modules/Telemetry/Sensor/LPS22HBSensor.h
new file mode 100644
index 000000000..1ded032fb
--- /dev/null
+++ b/src/modules/Telemetry/Sensor/LPS22HBSensor.h
@@ -0,0 +1,17 @@
+#include "../mesh/generated/telemetry.pb.h"
+#include "TelemetrySensor.h"
+#include
+#include
+
+class LPS22HBSensor : virtual public TelemetrySensor {
+private:
+ Adafruit_LPS22 lps22hb;
+
+protected:
+ virtual void setup() override;
+
+public:
+ LPS22HBSensor();
+ virtual int32_t runOnce() override;
+ virtual bool getMetrics(Telemetry *measurement) override;
+};
\ No newline at end of file
diff --git a/src/modules/Telemetry/Sensor/SHTC3Sensor.cpp b/src/modules/Telemetry/Sensor/SHTC3Sensor.cpp
new file mode 100644
index 000000000..b3a76ba91
--- /dev/null
+++ b/src/modules/Telemetry/Sensor/SHTC3Sensor.cpp
@@ -0,0 +1,34 @@
+#include "../mesh/generated/telemetry.pb.h"
+#include "configuration.h"
+#include "TelemetrySensor.h"
+#include "SHTC3Sensor.h"
+#include
+
+SHTC3Sensor::SHTC3Sensor() :
+ TelemetrySensor(TelemetrySensorType_SHTC3, "SHTC3")
+{
+}
+
+int32_t SHTC3Sensor::runOnce() {
+ DEBUG_MSG("Init sensor: %s\n", sensorName);
+ if (!hasSensor()) {
+ return DEFAULT_SENSOR_MINIMUM_WAIT_TIME_BETWEEN_READS;
+ }
+ status = shtc3.begin();
+ return initI2CSensor();
+}
+
+void SHTC3Sensor::setup()
+{
+ // Set up oversampling and filter initialization
+}
+
+bool SHTC3Sensor::getMetrics(Telemetry *measurement) {
+ sensors_event_t humidity, temp;
+ shtc3.getEvent(&humidity, &temp);
+
+ measurement->variant.environment_metrics.temperature = temp.temperature;
+ measurement->variant.environment_metrics.relative_humidity = humidity.relative_humidity;
+
+ return true;
+}
\ No newline at end of file
diff --git a/src/modules/Telemetry/Sensor/SHTC3Sensor.h b/src/modules/Telemetry/Sensor/SHTC3Sensor.h
new file mode 100644
index 000000000..28a1648bb
--- /dev/null
+++ b/src/modules/Telemetry/Sensor/SHTC3Sensor.h
@@ -0,0 +1,16 @@
+#include "../mesh/generated/telemetry.pb.h"
+#include "TelemetrySensor.h"
+#include
+
+class SHTC3Sensor : virtual public TelemetrySensor {
+private:
+ Adafruit_SHTC3 shtc3 = Adafruit_SHTC3();
+
+protected:
+ virtual void setup() override;
+
+public:
+ SHTC3Sensor();
+ virtual int32_t runOnce() override;
+ virtual bool getMetrics(Telemetry *measurement) override;
+};
\ No newline at end of file
diff --git a/src/modules/esp32/StoreForwardModule.cpp b/src/modules/esp32/StoreForwardModule.cpp
index 95aeef709..e51296824 100644
--- a/src/modules/esp32/StoreForwardModule.cpp
+++ b/src/modules/esp32/StoreForwardModule.cpp
@@ -27,7 +27,7 @@ int32_t StoreForwardModule::runOnce()
if (this->busy) {
// Only send packets if the channel is less than 25% utilized.
- if (airTime->channelUtilizationPercent() < 25) {
+ if (airTime->channelUtilizationPercent() < polite_channel_util_percent) {
// DEBUG_MSG("--- --- --- In busy loop 1 %d\n", this->packetHistoryTXQueue_index);
storeForwardModule->sendPayload(this->busyTo, this->packetHistoryTXQueue_index);
diff --git a/src/mqtt/MQTT.cpp b/src/mqtt/MQTT.cpp
index 7087c58c8..7deba4668 100644
--- a/src/mqtt/MQTT.cpp
+++ b/src/mqtt/MQTT.cpp
@@ -27,8 +27,9 @@ void MQTT::onPublish(char *topic, byte *payload, unsigned int length)
{
// parsing ServiceEnvelope
ServiceEnvelope e = ServiceEnvelope_init_default;
- if (!pb_decode_from_bytes(payload, length, ServiceEnvelope_fields, &e) && moduleConfig.mqtt.json_enabled) {
- // check if this is a json payload message
+
+ if (moduleConfig.mqtt.json_enabled && (strncmp(topic, jsonTopic.c_str(), jsonTopic.length()) == 0)) {
+ // check if this is a json payload message by comparing the topic start
using namespace json11;
char payloadStr[length + 1];
memcpy(payloadStr, payload, length);
@@ -36,36 +37,37 @@ void MQTT::onPublish(char *topic, byte *payload, unsigned int length)
std::string err;
auto json = Json::parse(payloadStr, err);
if (err.empty()) {
- DEBUG_MSG("Received json payload on MQTT, parsing..\n");
+ DEBUG_MSG("JSON Received on MQTT, parsing..\n");
// check if it is a valid envelope
- if (json.object_items().count("sender") != 0 && json.object_items().count("payload") != 0) {
+ if (json.object_items().count("sender") != 0 && json.object_items().count("payload") != 0 && json["type"].string_value().compare("sendtext") == 0) {
// this is a valid envelope
if (json["sender"].string_value().compare(owner.id) != 0) {
std::string jsonPayloadStr = json["payload"].dump();
- DEBUG_MSG("Received json payload %s, length %u\n", jsonPayloadStr.c_str(), jsonPayloadStr.length());
- // FIXME Not sure we need to be doing this
+ DEBUG_MSG("JSON payload %s, length %u\n", jsonPayloadStr.c_str(), jsonPayloadStr.length());
+
// construct protobuf data packet using TEXT_MESSAGE, send it to the mesh
- // MeshPacket *p = router->allocForSending();
- // p->decoded.portnum = PortNum_TEXT_MESSAGE_APP;
- // if (jsonPayloadStr.length() <= sizeof(p->decoded.payload.bytes)) {
- // memcpy(p->decoded.payload.bytes, jsonPayloadStr.c_str(), jsonPayloadStr.length());
- // p->decoded.payload.size = jsonPayloadStr.length();
- // MeshPacket *packet = packetPool.allocCopy(*p);
- // service.sendToMesh(packet, RX_SRC_LOCAL);
- // } else {
- // DEBUG_MSG("Received MQTT json payload too long, dropping\n");
- // }
+ MeshPacket *p = router->allocForSending();
+ p->decoded.portnum = PortNum_TEXT_MESSAGE_APP;
+ if (jsonPayloadStr.length() <= sizeof(p->decoded.payload.bytes)) {
+ memcpy(p->decoded.payload.bytes, jsonPayloadStr.c_str(), jsonPayloadStr.length());
+ p->decoded.payload.size = jsonPayloadStr.length();
+ MeshPacket *packet = packetPool.allocCopy(*p);
+ service.sendToMesh(packet, RX_SRC_LOCAL);
+ } else {
+ DEBUG_MSG("Received MQTT json payload too long, dropping\n");
+ }
} else {
- DEBUG_MSG("Ignoring downlink message we originally sent.\n");
+ DEBUG_MSG("JSON Ignoring downlink message we originally sent.\n");
}
} else {
- DEBUG_MSG("Received json payload on MQTT but not a valid envelope\n");
+ DEBUG_MSG("JSON Received payload on MQTT but not a valid envelope\n");
}
} else {
// no json, this is an invalid payload
DEBUG_MSG("Invalid MQTT service envelope, topic %s, len %u!\n", topic, length);
}
} else {
+ pb_decode_from_bytes(payload, length, ServiceEnvelope_fields, &e);
if (strcmp(e.gateway_id, owner.id) == 0)
DEBUG_MSG("Ignoring downlink message we originally sent.\n");
else {
@@ -243,7 +245,7 @@ void MQTT::onSend(const MeshPacket &mp, ChannelIndex chIndex)
auto jsonString = this->downstreamPacketToJson((MeshPacket *)&mp);
if (jsonString.length() != 0) {
String topicJson = jsonTopic + channelId + "/" + owner.id;
- DEBUG_MSG("publish json message to %s, %u bytes: %s\n", topicJson.c_str(), jsonString.length(), jsonString.c_str());
+ DEBUG_MSG("JSON publish message to %s, %u bytes: %s\n", topicJson.c_str(), jsonString.length(), jsonString.c_str());
pubSub.publish(topicJson.c_str(), jsonString.c_str(), false);
}
}
@@ -251,7 +253,7 @@ void MQTT::onSend(const MeshPacket &mp, ChannelIndex chIndex)
}
// converts a downstream packet into a json message
-String MQTT::downstreamPacketToJson(MeshPacket *mp)
+std::string MQTT::downstreamPacketToJson(MeshPacket *mp)
{
using namespace json11;
@@ -279,7 +281,7 @@ String MQTT::downstreamPacketToJson(MeshPacket *mp)
// if it isn't, then we need to create a json object
// with the string as the value
DEBUG_MSG("text message payload is of type plaintext\n");
- msgPayload = Json::object({{"text", payloadStr}});
+ msgPayload = Json::object{{"text", payloadStr}};
}
break;
}
@@ -396,8 +398,8 @@ String MQTT::downstreamPacketToJson(MeshPacket *mp)
};
// serialize and return it
- static std::string jsonStr = jsonObj.dump();
+ std::string jsonStr = jsonObj.dump();
DEBUG_MSG("serialized json message: %s\n", jsonStr.c_str());
- return jsonStr.c_str();
+ return jsonStr;
}
diff --git a/src/mqtt/MQTT.h b/src/mqtt/MQTT.h
index cfb68354e..9d80c7d91 100644
--- a/src/mqtt/MQTT.h
+++ b/src/mqtt/MQTT.h
@@ -58,7 +58,7 @@ class MQTT : private concurrency::OSThread
void onPublish(char *topic, byte *payload, unsigned int length);
/// Called when a new publish arrives from the MQTT server
- String downstreamPacketToJson(MeshPacket *mp);
+ std::string downstreamPacketToJson(MeshPacket *mp);
/// Return 0 if sleep is okay, veto sleep if we are connected to pubsub server
// int preflightSleepCb(void *unused = NULL) { return pubSub.connected() ? 1 : 0; }
diff --git a/src/platform/esp32/BleOta.cpp b/src/platform/esp32/BleOta.cpp
index 8062eede6..ef93a240b 100644
--- a/src/platform/esp32/BleOta.cpp
+++ b/src/platform/esp32/BleOta.cpp
@@ -5,16 +5,13 @@
static const String MESHTASTIC_OTA_APP_PROJECT_NAME("Meshtastic-OTA");
const esp_partition_t* BleOta::findEspOtaAppPartition() {
- const esp_partition_t *part
- = esp_partition_find_first(ESP_PARTITION_TYPE_APP, ESP_PARTITION_SUBTYPE_APP_OTA_1, nullptr);
+ const esp_partition_t *part = esp_partition_find_first(ESP_PARTITION_TYPE_APP, ESP_PARTITION_SUBTYPE_APP_OTA_0, nullptr);
esp_app_desc_t app_desc;
esp_err_t ret = ESP_ERROR_CHECK_WITHOUT_ABORT(esp_ota_get_partition_description(part, &app_desc));
if (ret != ESP_OK || MESHTASTIC_OTA_APP_PROJECT_NAME != app_desc.project_name) {
- part
- = esp_partition_find_first(ESP_PARTITION_TYPE_APP, ESP_PARTITION_SUBTYPE_APP_OTA_1,
- nullptr);
+ part = esp_partition_find_first(ESP_PARTITION_TYPE_APP, ESP_PARTITION_SUBTYPE_APP_OTA_1, nullptr);
ret = ESP_ERROR_CHECK_WITHOUT_ABORT(esp_ota_get_partition_description(part, &app_desc));
}
diff --git a/src/platform/esp32/main-esp32.cpp b/src/platform/esp32/main-esp32.cpp
index 134d89332..9e8990d97 100644
--- a/src/platform/esp32/main-esp32.cpp
+++ b/src/platform/esp32/main-esp32.cpp
@@ -4,6 +4,7 @@
#include "main.h"
#include "nimble/NimbleBluetooth.h"
+#include "BleOta.h"
#include "mesh/http/WiFiAPClient.h"
#include "sleep.h"
@@ -63,6 +64,12 @@ void esp32Setup()
preferences.putUInt("rebootCounter", rebootCounter);
preferences.end();
DEBUG_MSG("Number of Device Reboots: %d\n", rebootCounter);
+ String BLEOTA=BleOta::getOtaAppVersion();
+ if (BLEOTA.isEmpty()) {
+ DEBUG_MSG("No OTA firmware available\n");
+ }else{
+ DEBUG_MSG("OTA firmware version %s\n", BLEOTA);
+ }
// enableModemSleep();
diff --git a/src/platform/nrf52/NRF52Bluetooth.cpp b/src/platform/nrf52/NRF52Bluetooth.cpp
index bfa3887ed..acb26071f 100644
--- a/src/platform/nrf52/NRF52Bluetooth.cpp
+++ b/src/platform/nrf52/NRF52Bluetooth.cpp
@@ -244,6 +244,9 @@ void NRF52Bluetooth::setup()
Bluefruit.Periph.setConnectCallback(onConnect);
Bluefruit.Periph.setDisconnectCallback(onDisconnect);
+ bledfu.setPermission(SECMODE_ENC_WITH_MITM, SECMODE_ENC_WITH_MITM);
+ bledfu.begin(); // Install the DFU helper
+
// Configure and Start the Device Information Service
DEBUG_MSG("Configuring the Device Information Service\n");
bledis.setModel(optstr(HW_VERSION));
@@ -254,7 +257,7 @@ void NRF52Bluetooth::setup()
DEBUG_MSG("Configuring the Battery Service\n");
blebas.begin();
blebas.write(0); // Unknown battery level for now
- bledfu.begin(); // Install the DFU helper
+
// Setup the Heart Rate Monitor service using
// BLEService and BLECharacteristic classes
diff --git a/variants/rak11200/variant.h b/variants/rak11200/variant.h
index 6886a3ad3..0962d4f45 100644
--- a/variants/rak11200/variant.h
+++ b/variants/rak11200/variant.h
@@ -59,7 +59,7 @@ static const uint8_t SCK = 33;
// https://docs.rakwireless.com/Product-Categories/WisBlock/RAK13300/
-#define LORA_DIO0 26 // a No connect on the SX1262/SX1268 module
+#define LORA_DIO0 -1 // a No connect on the SX1262/SX1268 module
#define LORA_RESET WB_IO4 // RST for SX1276, and for SX1262/SX1268
#define LORA_DIO1 WB_IO6 // IRQ for SX1262/SX1268
#define LORA_DIO2 WB_IO5 // BUSY for SX1262/SX1268
diff --git a/variants/pico/platformio.ini b/variants/rpipico/platformio.ini
similarity index 90%
rename from variants/pico/platformio.ini
rename to variants/rpipico/platformio.ini
index 4f238fa14..122fbd42f 100644
--- a/variants/pico/platformio.ini
+++ b/variants/rpipico/platformio.ini
@@ -1,12 +1,12 @@
[env:pico]
extends = rp2040_base
-board = pico
+board = rpipico
upload_protocol = picotool
# add our variants files to the include and src paths
build_flags = ${rp2040_base.build_flags}
-DPRIVATE_HW
- -Ivariants/pico
+ -Ivariants/rpipico
-DARDUINO_AVR_NANO_EVERY
-DDEBUG_RP2040_WIRE
-DDEBUG_RP2040_SPI
diff --git a/variants/pico/variant.h b/variants/rpipico/variant.h
similarity index 100%
rename from variants/pico/variant.h
rename to variants/rpipico/variant.h
diff --git a/variants/rpipicow/platformio.ini b/variants/rpipicow/platformio.ini
new file mode 100644
index 000000000..697ec1caa
--- /dev/null
+++ b/variants/rpipicow/platformio.ini
@@ -0,0 +1,17 @@
+[env:picow]
+extends = rp2040_base
+board = rpipicow
+upload_protocol = picotool
+
+# add our variants files to the include and src paths
+build_flags = ${rp2040_base.build_flags}
+ -DPRIVATE_HW
+ -Ivariants/rpipicow
+ -DARDUINO_AVR_NANO_EVERY
+ -DDEBUG_RP2040_WIRE
+ -DDEBUG_RP2040_SPI
+ -DDEBUG_RP2040_CORE
+ -DDEBUG_RP2040_PORT=Serial
+ -DUSE_TINYUSB
+lib_deps =
+ ${rp2040_base.lib_deps}
\ No newline at end of file
diff --git a/variants/rpipicow/variant.h b/variants/rpipicow/variant.h
new file mode 100644
index 000000000..d620a356b
--- /dev/null
+++ b/variants/rpipicow/variant.h
@@ -0,0 +1,52 @@
+// #define RADIOLIB_CUSTOM_ARDUINO 1
+// #define RADIOLIB_TONE_UNSUPPORTED 1
+// #define RADIOLIB_SOFTWARE_SERIAL_UNSUPPORTED 1
+
+#define ARDUINO_ARCH_AVR
+
+#define CBC 0
+#define CTR 1
+#define ECB 0
+
+#define NO_GPS 1
+#define USE_SH1106 1
+#undef GPS_SERIAL_NUM
+
+// #define I2C_SDA 6
+// #define I2C_SCL 7
+
+#define BUTTON_PIN 17
+#define EXT_NOTIFY_OUT 4
+
+#define BATTERY_PIN 26
+// ratio of voltage divider = 3.0 (R17=200k, R18=100k)
+#define ADC_MULTIPLIER 3.1 // 3.0 + a bit for being optimistic
+
+#define USE_RF95
+#define USE_SX1262
+
+#undef RF95_SCK
+#undef RF95_MISO
+#undef RF95_MOSI
+#undef RF95_NSS
+
+#define RF95_SCK 10
+#define RF95_MISO 12
+#define RF95_MOSI 11
+#define RF95_NSS 3
+
+#define LORA_DIO0 RADIOLIB_NC
+#define LORA_RESET 15
+#define LORA_DIO1 20
+#define LORA_DIO2 2
+#define LORA_DIO3 RADIOLIB_NC
+
+#ifdef USE_SX1262
+#define SX126X_CS RF95_NSS
+#define SX126X_DIO1 LORA_DIO1
+#define SX126X_BUSY LORA_DIO2
+#define SX126X_RESET LORA_RESET
+#define SX126X_E22
+#endif
+
+#include
\ No newline at end of file
diff --git a/version.properties b/version.properties
index f1a44dd8a..750a9609f 100644
--- a/version.properties
+++ b/version.properties
@@ -1,4 +1,4 @@
[VERSION]
major = 1
minor = 3
-build = 43
+build = 47