From 1ec0e750a3296eadb28bb0e57a4a5e3bab439a94 Mon Sep 17 00:00:00 2001 From: HarukiToreda <116696711+HarukiToreda@users.noreply.github.com> Date: Sat, 18 May 2024 22:14:22 -0400 Subject: [PATCH 01/65] Added fix for ESP32 --- src/detect/ScanI2C.cpp | 30 +++++++++++++++++++++++++++++- src/detect/ScanI2C.h | 1 + src/main.cpp | 3 +++ src/main.h | 3 ++- 4 files changed, 35 insertions(+), 2 deletions(-) diff --git a/src/detect/ScanI2C.cpp b/src/detect/ScanI2C.cpp index 149bb95f05..941fdf3e89 100644 --- a/src/detect/ScanI2C.cpp +++ b/src/detect/ScanI2C.cpp @@ -1,4 +1,6 @@ #include "ScanI2C.h" +#include "main.h" +#include const ScanI2C::DeviceAddress ScanI2C::ADDRESS_NONE = ScanI2C::DeviceAddress(); const ScanI2C::FoundDevice ScanI2C::DEVICE_NONE = ScanI2C::FoundDevice(ScanI2C::DeviceType::NONE, ADDRESS_NONE); @@ -27,7 +29,33 @@ ScanI2C::FoundDevice ScanI2C::firstRTC() const ScanI2C::DeviceType types[] = {RTC_RV3028, RTC_PCF8563}; return firstOfOrNONE(2, types); } - +bool performScanForCardKB() { + // Example I2C scan code for CardKB (adjust as needed) + Wire.beginTransmission(CARDKB_I2C_ADDRESS); + if (Wire.endTransmission() == 0) { + return true; // CardKB detected + } + return false; // CardKB not detected +} +void scanForCardKB() { + const int maxRetries = 10; // Maximum number of retries + const int retryDelay = 100; // Delay between retries in milliseconds + + for (int i = 0; i < maxRetries; ++i) { + // Perform the scan (example scan code, adjust as needed) + cardKBDetected = performScanForCardKB(); + + if (cardKBDetected) { + Serial.println("CardKB Keyboard detected."); + break; + } + + delay(retryDelay); // Wait before the next retry + } + if (!cardKBDetected) { + Serial.println("CardKB Keyboard not detected. Canned Message Module Disabled."); + } +} ScanI2C::FoundDevice ScanI2C::firstKeyboard() const { ScanI2C::DeviceType types[] = {CARDKB, TDECKKB, BBQ10KB, RAK14004}; diff --git a/src/detect/ScanI2C.h b/src/detect/ScanI2C.h index 6c01b91000..15668aecb2 100644 --- a/src/detect/ScanI2C.h +++ b/src/detect/ScanI2C.h @@ -2,6 +2,7 @@ #include #include +bool performScanForCardKB(); class ScanI2C { diff --git a/src/main.cpp b/src/main.cpp index 4a9fef5d08..a3e9258baa 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -35,6 +35,8 @@ #include // #include +bool cardKBDetected = false; +void scanForCardKB(); #ifdef ARCH_ESP32 #if !MESHTASTIC_EXCLUDE_WEBSERVER #include "mesh/http/WebServer.h" @@ -374,6 +376,7 @@ void setup() // otherwise keyboard and touch screen will not work delay(800); #endif +scanForCardKB(); // Initial scan for CardKB // Currently only the tbeam has a PMU // PMU initialization needs to be placed before i2c scanning diff --git a/src/main.h b/src/main.h index db05a47347..737d424a73 100644 --- a/src/main.h +++ b/src/main.h @@ -21,7 +21,7 @@ extern NimbleBluetooth *nimbleBluetooth; #include "NRF52Bluetooth.h" extern NRF52Bluetooth *nrf52Bluetooth; #endif - +extern bool cardKBDetected; #if ARCH_PORTDUINO extern HardwareSPI *DisplaySPI; extern HardwareSPI *LoraSPI; @@ -39,6 +39,7 @@ extern bool pmu_found; extern bool isCharging; extern bool isUSBPowered; +#define CARDKB_I2C_ADDRESS 0x5F // Replace 0x5F with the actual address if different #if !defined(ARCH_PORTDUINO) && !defined(ARCH_STM32WL) extern ATECCX08A atecc; #endif From a5fdb663e25055292bef3042110e9b8b77d9bf01 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20G=C3=B6ttgens?= Date: Sun, 19 May 2024 19:32:08 +0200 Subject: [PATCH 02/65] change the main scan class so they scan only for wanted bits - UNTESTED --- src/detect/ScanI2C.cpp | 31 ++--------------------------- src/detect/ScanI2C.h | 2 +- src/detect/ScanI2CTwoWire.cpp | 13 ++++++++++-- src/detect/ScanI2CTwoWire.h | 4 +++- src/input/kbI2cBase.cpp | 37 +++++++++++++++++++++++++++++++++-- src/main.cpp | 3 --- src/main.h | 3 +-- 7 files changed, 53 insertions(+), 40 deletions(-) diff --git a/src/detect/ScanI2C.cpp b/src/detect/ScanI2C.cpp index 941fdf3e89..7d0a836531 100644 --- a/src/detect/ScanI2C.cpp +++ b/src/detect/ScanI2C.cpp @@ -1,6 +1,4 @@ #include "ScanI2C.h" -#include "main.h" -#include const ScanI2C::DeviceAddress ScanI2C::ADDRESS_NONE = ScanI2C::DeviceAddress(); const ScanI2C::FoundDevice ScanI2C::DEVICE_NONE = ScanI2C::FoundDevice(ScanI2C::DeviceType::NONE, ADDRESS_NONE); @@ -8,6 +6,7 @@ const ScanI2C::FoundDevice ScanI2C::DEVICE_NONE = ScanI2C::FoundDevice(ScanI2C:: ScanI2C::ScanI2C() = default; void ScanI2C::scanPort(ScanI2C::I2CPort port) {} +void ScanI2C::scanPort(ScanI2C::I2CPort port, int *address) {} void ScanI2C::setSuppressScreen() { @@ -29,33 +28,7 @@ ScanI2C::FoundDevice ScanI2C::firstRTC() const ScanI2C::DeviceType types[] = {RTC_RV3028, RTC_PCF8563}; return firstOfOrNONE(2, types); } -bool performScanForCardKB() { - // Example I2C scan code for CardKB (adjust as needed) - Wire.beginTransmission(CARDKB_I2C_ADDRESS); - if (Wire.endTransmission() == 0) { - return true; // CardKB detected - } - return false; // CardKB not detected -} -void scanForCardKB() { - const int maxRetries = 10; // Maximum number of retries - const int retryDelay = 100; // Delay between retries in milliseconds - - for (int i = 0; i < maxRetries; ++i) { - // Perform the scan (example scan code, adjust as needed) - cardKBDetected = performScanForCardKB(); - - if (cardKBDetected) { - Serial.println("CardKB Keyboard detected."); - break; - } - - delay(retryDelay); // Wait before the next retry - } - if (!cardKBDetected) { - Serial.println("CardKB Keyboard not detected. Canned Message Module Disabled."); - } -} + ScanI2C::FoundDevice ScanI2C::firstKeyboard() const { ScanI2C::DeviceType types[] = {CARDKB, TDECKKB, BBQ10KB, RAK14004}; diff --git a/src/detect/ScanI2C.h b/src/detect/ScanI2C.h index 15668aecb2..4aa4549cc8 100644 --- a/src/detect/ScanI2C.h +++ b/src/detect/ScanI2C.h @@ -2,7 +2,6 @@ #include #include -bool performScanForCardKB(); class ScanI2C { @@ -82,6 +81,7 @@ class ScanI2C ScanI2C(); virtual void scanPort(ScanI2C::I2CPort); + virtual void scanPort(ScanI2C::I2CPort, int *); /* * A bit of a hack, this tells the scanner not to tell later systems there is a screen to avoid enabling it. diff --git a/src/detect/ScanI2CTwoWire.cpp b/src/detect/ScanI2CTwoWire.cpp index 7828dfb586..f7068ee025 100644 --- a/src/detect/ScanI2CTwoWire.cpp +++ b/src/detect/ScanI2CTwoWire.cpp @@ -135,7 +135,7 @@ uint16_t ScanI2CTwoWire::getRegisterValue(const ScanI2CTwoWire::RegisterLocation type = T; \ break; -void ScanI2CTwoWire::scanPort(I2CPort port) +void ScanI2CTwoWire::scanPort(I2CPort port, int *address) { concurrency::LockGuard guard((concurrency::Lock *)&lock); @@ -163,6 +163,10 @@ void ScanI2CTwoWire::scanPort(I2CPort port) #endif for (addr.address = 1; addr.address < 127; addr.address++) { + // Skip the address if it is not requested oon a partial scan + if (sizeof(address) > 0 && addr.address != *address) { + continue; + } i2cBus->beginTransmission(addr.address); #ifdef ARCH_PORTDUINO if (i2cBus->read() != -1) @@ -353,6 +357,11 @@ void ScanI2CTwoWire::scanPort(I2CPort port) } } +void ScanI2CTwoWire::scanPort(I2CPort port) +{ + scanPort(port, nullptr); +} + TwoWire *ScanI2CTwoWire::fetchI2CBus(ScanI2C::DeviceAddress address) const { if (address.port == ScanI2C::I2CPort::WIRE) { @@ -369,4 +378,4 @@ TwoWire *ScanI2CTwoWire::fetchI2CBus(ScanI2C::DeviceAddress address) const size_t ScanI2CTwoWire::countDevices() const { return foundDevices.size(); -} +} \ No newline at end of file diff --git a/src/detect/ScanI2CTwoWire.h b/src/detect/ScanI2CTwoWire.h index 9acd736d2e..a7c19c7791 100644 --- a/src/detect/ScanI2CTwoWire.h +++ b/src/detect/ScanI2CTwoWire.h @@ -16,6 +16,8 @@ class ScanI2CTwoWire : public ScanI2C public: void scanPort(ScanI2C::I2CPort) override; + void scanPort(ScanI2C::I2CPort, int *) override; + ScanI2C::FoundDevice find(ScanI2C::DeviceType) const override; TwoWire *fetchI2CBus(ScanI2C::DeviceAddress) const; @@ -53,4 +55,4 @@ class ScanI2CTwoWire : public ScanI2C uint16_t getRegisterValue(const RegisterLocation &, ResponseWidth) const; DeviceType probeOLED(ScanI2C::DeviceAddress) const; -}; +}; \ No newline at end of file diff --git a/src/input/kbI2cBase.cpp b/src/input/kbI2cBase.cpp index af7c96b206..55f435fda7 100644 --- a/src/input/kbI2cBase.cpp +++ b/src/input/kbI2cBase.cpp @@ -1,6 +1,7 @@ #include "kbI2cBase.h" #include "configuration.h" #include "detect/ScanI2C.h" +#include "detect/ScanI2CTwoWire.h" extern ScanI2C::DeviceAddress cardkb_found; extern uint8_t kb_model; @@ -30,8 +31,40 @@ uint8_t read_from_14004(TwoWire *i2cBus, uint8_t reg, uint8_t *data, uint8_t len int32_t KbI2cBase::runOnce() { if (cardkb_found.address == 0x00) { - // Input device is not detected. - return INT32_MAX; + // Input device is not detected. Rescan now. + auto i2cScanner = std::unique_ptr(new ScanI2CTwoWire()); + int i2caddr_scan[] = {CARDKB_ADDR, TDECK_KB_ADDR, BBQ10_KB_ADDR}; +#if defined(I2C_SDA1) + i2cScanner->scanPort(ScanI2C::I2CPort::WIRE1, i2caddr_scan); +#endif + i2cScanner->scanPort(ScanI2C::I2CPort::WIRE, i2caddr_scan); + auto kb_info = i2cScanner->firstKeyboard(); + + if (kb_info.type != ScanI2C::DeviceType::NONE) { + cardkb_found = kb_info.address; + switch (kb_info.type) { + case ScanI2C::DeviceType::RAK14004: + kb_model = 0x02; + break; + case ScanI2C::DeviceType::CARDKB: + kb_model = 0x00; + break; + case ScanI2C::DeviceType::TDECKKB: + // assign an arbitrary value to distinguish from other models + kb_model = 0x10; + break; + case ScanI2C::DeviceType::BBQ10KB: + // assign an arbitrary value to distinguish from other models + kb_model = 0x11; + break; + default: + // use this as default since it's also just zero + LOG_WARN("kb_info.type is unknown(0x%02x), setting kb_model=0x00\n", kb_info.type); + kb_model = 0x00; + } + } + if (cardkb_found.address == 0x00) + return INT32_MAX; } if (!i2cBus) { diff --git a/src/main.cpp b/src/main.cpp index a3e9258baa..4a9fef5d08 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -35,8 +35,6 @@ #include // #include -bool cardKBDetected = false; -void scanForCardKB(); #ifdef ARCH_ESP32 #if !MESHTASTIC_EXCLUDE_WEBSERVER #include "mesh/http/WebServer.h" @@ -376,7 +374,6 @@ void setup() // otherwise keyboard and touch screen will not work delay(800); #endif -scanForCardKB(); // Initial scan for CardKB // Currently only the tbeam has a PMU // PMU initialization needs to be placed before i2c scanning diff --git a/src/main.h b/src/main.h index 737d424a73..db05a47347 100644 --- a/src/main.h +++ b/src/main.h @@ -21,7 +21,7 @@ extern NimbleBluetooth *nimbleBluetooth; #include "NRF52Bluetooth.h" extern NRF52Bluetooth *nrf52Bluetooth; #endif -extern bool cardKBDetected; + #if ARCH_PORTDUINO extern HardwareSPI *DisplaySPI; extern HardwareSPI *LoraSPI; @@ -39,7 +39,6 @@ extern bool pmu_found; extern bool isCharging; extern bool isUSBPowered; -#define CARDKB_I2C_ADDRESS 0x5F // Replace 0x5F with the actual address if different #if !defined(ARCH_PORTDUINO) && !defined(ARCH_STM32WL) extern ATECCX08A atecc; #endif From 3a628047ef40f34060e8c8f7e5132d24be45bcad Mon Sep 17 00:00:00 2001 From: HarukiToreda <116696711+HarukiToreda@users.noreply.github.com> Date: Sat, 18 May 2024 22:14:22 -0400 Subject: [PATCH 03/65] Added fix for ESP32 --- src/detect/ScanI2C.cpp | 30 +++++++++++++++++++++++++++++- src/detect/ScanI2C.h | 1 + src/main.cpp | 3 +++ src/main.h | 3 ++- 4 files changed, 35 insertions(+), 2 deletions(-) diff --git a/src/detect/ScanI2C.cpp b/src/detect/ScanI2C.cpp index 149bb95f05..941fdf3e89 100644 --- a/src/detect/ScanI2C.cpp +++ b/src/detect/ScanI2C.cpp @@ -1,4 +1,6 @@ #include "ScanI2C.h" +#include "main.h" +#include const ScanI2C::DeviceAddress ScanI2C::ADDRESS_NONE = ScanI2C::DeviceAddress(); const ScanI2C::FoundDevice ScanI2C::DEVICE_NONE = ScanI2C::FoundDevice(ScanI2C::DeviceType::NONE, ADDRESS_NONE); @@ -27,7 +29,33 @@ ScanI2C::FoundDevice ScanI2C::firstRTC() const ScanI2C::DeviceType types[] = {RTC_RV3028, RTC_PCF8563}; return firstOfOrNONE(2, types); } - +bool performScanForCardKB() { + // Example I2C scan code for CardKB (adjust as needed) + Wire.beginTransmission(CARDKB_I2C_ADDRESS); + if (Wire.endTransmission() == 0) { + return true; // CardKB detected + } + return false; // CardKB not detected +} +void scanForCardKB() { + const int maxRetries = 10; // Maximum number of retries + const int retryDelay = 100; // Delay between retries in milliseconds + + for (int i = 0; i < maxRetries; ++i) { + // Perform the scan (example scan code, adjust as needed) + cardKBDetected = performScanForCardKB(); + + if (cardKBDetected) { + Serial.println("CardKB Keyboard detected."); + break; + } + + delay(retryDelay); // Wait before the next retry + } + if (!cardKBDetected) { + Serial.println("CardKB Keyboard not detected. Canned Message Module Disabled."); + } +} ScanI2C::FoundDevice ScanI2C::firstKeyboard() const { ScanI2C::DeviceType types[] = {CARDKB, TDECKKB, BBQ10KB, RAK14004}; diff --git a/src/detect/ScanI2C.h b/src/detect/ScanI2C.h index 6c01b91000..15668aecb2 100644 --- a/src/detect/ScanI2C.h +++ b/src/detect/ScanI2C.h @@ -2,6 +2,7 @@ #include #include +bool performScanForCardKB(); class ScanI2C { diff --git a/src/main.cpp b/src/main.cpp index 4a9fef5d08..a3e9258baa 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -35,6 +35,8 @@ #include // #include +bool cardKBDetected = false; +void scanForCardKB(); #ifdef ARCH_ESP32 #if !MESHTASTIC_EXCLUDE_WEBSERVER #include "mesh/http/WebServer.h" @@ -374,6 +376,7 @@ void setup() // otherwise keyboard and touch screen will not work delay(800); #endif +scanForCardKB(); // Initial scan for CardKB // Currently only the tbeam has a PMU // PMU initialization needs to be placed before i2c scanning diff --git a/src/main.h b/src/main.h index db05a47347..737d424a73 100644 --- a/src/main.h +++ b/src/main.h @@ -21,7 +21,7 @@ extern NimbleBluetooth *nimbleBluetooth; #include "NRF52Bluetooth.h" extern NRF52Bluetooth *nrf52Bluetooth; #endif - +extern bool cardKBDetected; #if ARCH_PORTDUINO extern HardwareSPI *DisplaySPI; extern HardwareSPI *LoraSPI; @@ -39,6 +39,7 @@ extern bool pmu_found; extern bool isCharging; extern bool isUSBPowered; +#define CARDKB_I2C_ADDRESS 0x5F // Replace 0x5F with the actual address if different #if !defined(ARCH_PORTDUINO) && !defined(ARCH_STM32WL) extern ATECCX08A atecc; #endif From a37f309c0379dfa161f2dae41f319acdc0b3d0b3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20G=C3=B6ttgens?= Date: Sun, 19 May 2024 19:32:08 +0200 Subject: [PATCH 04/65] change the main scan class so they scan only for wanted bits - UNTESTED --- src/detect/ScanI2C.cpp | 31 ++--------------------------- src/detect/ScanI2C.h | 2 +- src/detect/ScanI2CTwoWire.cpp | 13 ++++++++++-- src/detect/ScanI2CTwoWire.h | 4 +++- src/input/kbI2cBase.cpp | 37 +++++++++++++++++++++++++++++++++-- src/main.cpp | 3 --- src/main.h | 3 +-- 7 files changed, 53 insertions(+), 40 deletions(-) diff --git a/src/detect/ScanI2C.cpp b/src/detect/ScanI2C.cpp index 941fdf3e89..7d0a836531 100644 --- a/src/detect/ScanI2C.cpp +++ b/src/detect/ScanI2C.cpp @@ -1,6 +1,4 @@ #include "ScanI2C.h" -#include "main.h" -#include const ScanI2C::DeviceAddress ScanI2C::ADDRESS_NONE = ScanI2C::DeviceAddress(); const ScanI2C::FoundDevice ScanI2C::DEVICE_NONE = ScanI2C::FoundDevice(ScanI2C::DeviceType::NONE, ADDRESS_NONE); @@ -8,6 +6,7 @@ const ScanI2C::FoundDevice ScanI2C::DEVICE_NONE = ScanI2C::FoundDevice(ScanI2C:: ScanI2C::ScanI2C() = default; void ScanI2C::scanPort(ScanI2C::I2CPort port) {} +void ScanI2C::scanPort(ScanI2C::I2CPort port, int *address) {} void ScanI2C::setSuppressScreen() { @@ -29,33 +28,7 @@ ScanI2C::FoundDevice ScanI2C::firstRTC() const ScanI2C::DeviceType types[] = {RTC_RV3028, RTC_PCF8563}; return firstOfOrNONE(2, types); } -bool performScanForCardKB() { - // Example I2C scan code for CardKB (adjust as needed) - Wire.beginTransmission(CARDKB_I2C_ADDRESS); - if (Wire.endTransmission() == 0) { - return true; // CardKB detected - } - return false; // CardKB not detected -} -void scanForCardKB() { - const int maxRetries = 10; // Maximum number of retries - const int retryDelay = 100; // Delay between retries in milliseconds - - for (int i = 0; i < maxRetries; ++i) { - // Perform the scan (example scan code, adjust as needed) - cardKBDetected = performScanForCardKB(); - - if (cardKBDetected) { - Serial.println("CardKB Keyboard detected."); - break; - } - - delay(retryDelay); // Wait before the next retry - } - if (!cardKBDetected) { - Serial.println("CardKB Keyboard not detected. Canned Message Module Disabled."); - } -} + ScanI2C::FoundDevice ScanI2C::firstKeyboard() const { ScanI2C::DeviceType types[] = {CARDKB, TDECKKB, BBQ10KB, RAK14004}; diff --git a/src/detect/ScanI2C.h b/src/detect/ScanI2C.h index 15668aecb2..4aa4549cc8 100644 --- a/src/detect/ScanI2C.h +++ b/src/detect/ScanI2C.h @@ -2,7 +2,6 @@ #include #include -bool performScanForCardKB(); class ScanI2C { @@ -82,6 +81,7 @@ class ScanI2C ScanI2C(); virtual void scanPort(ScanI2C::I2CPort); + virtual void scanPort(ScanI2C::I2CPort, int *); /* * A bit of a hack, this tells the scanner not to tell later systems there is a screen to avoid enabling it. diff --git a/src/detect/ScanI2CTwoWire.cpp b/src/detect/ScanI2CTwoWire.cpp index 7828dfb586..f7068ee025 100644 --- a/src/detect/ScanI2CTwoWire.cpp +++ b/src/detect/ScanI2CTwoWire.cpp @@ -135,7 +135,7 @@ uint16_t ScanI2CTwoWire::getRegisterValue(const ScanI2CTwoWire::RegisterLocation type = T; \ break; -void ScanI2CTwoWire::scanPort(I2CPort port) +void ScanI2CTwoWire::scanPort(I2CPort port, int *address) { concurrency::LockGuard guard((concurrency::Lock *)&lock); @@ -163,6 +163,10 @@ void ScanI2CTwoWire::scanPort(I2CPort port) #endif for (addr.address = 1; addr.address < 127; addr.address++) { + // Skip the address if it is not requested oon a partial scan + if (sizeof(address) > 0 && addr.address != *address) { + continue; + } i2cBus->beginTransmission(addr.address); #ifdef ARCH_PORTDUINO if (i2cBus->read() != -1) @@ -353,6 +357,11 @@ void ScanI2CTwoWire::scanPort(I2CPort port) } } +void ScanI2CTwoWire::scanPort(I2CPort port) +{ + scanPort(port, nullptr); +} + TwoWire *ScanI2CTwoWire::fetchI2CBus(ScanI2C::DeviceAddress address) const { if (address.port == ScanI2C::I2CPort::WIRE) { @@ -369,4 +378,4 @@ TwoWire *ScanI2CTwoWire::fetchI2CBus(ScanI2C::DeviceAddress address) const size_t ScanI2CTwoWire::countDevices() const { return foundDevices.size(); -} +} \ No newline at end of file diff --git a/src/detect/ScanI2CTwoWire.h b/src/detect/ScanI2CTwoWire.h index 9acd736d2e..a7c19c7791 100644 --- a/src/detect/ScanI2CTwoWire.h +++ b/src/detect/ScanI2CTwoWire.h @@ -16,6 +16,8 @@ class ScanI2CTwoWire : public ScanI2C public: void scanPort(ScanI2C::I2CPort) override; + void scanPort(ScanI2C::I2CPort, int *) override; + ScanI2C::FoundDevice find(ScanI2C::DeviceType) const override; TwoWire *fetchI2CBus(ScanI2C::DeviceAddress) const; @@ -53,4 +55,4 @@ class ScanI2CTwoWire : public ScanI2C uint16_t getRegisterValue(const RegisterLocation &, ResponseWidth) const; DeviceType probeOLED(ScanI2C::DeviceAddress) const; -}; +}; \ No newline at end of file diff --git a/src/input/kbI2cBase.cpp b/src/input/kbI2cBase.cpp index af7c96b206..55f435fda7 100644 --- a/src/input/kbI2cBase.cpp +++ b/src/input/kbI2cBase.cpp @@ -1,6 +1,7 @@ #include "kbI2cBase.h" #include "configuration.h" #include "detect/ScanI2C.h" +#include "detect/ScanI2CTwoWire.h" extern ScanI2C::DeviceAddress cardkb_found; extern uint8_t kb_model; @@ -30,8 +31,40 @@ uint8_t read_from_14004(TwoWire *i2cBus, uint8_t reg, uint8_t *data, uint8_t len int32_t KbI2cBase::runOnce() { if (cardkb_found.address == 0x00) { - // Input device is not detected. - return INT32_MAX; + // Input device is not detected. Rescan now. + auto i2cScanner = std::unique_ptr(new ScanI2CTwoWire()); + int i2caddr_scan[] = {CARDKB_ADDR, TDECK_KB_ADDR, BBQ10_KB_ADDR}; +#if defined(I2C_SDA1) + i2cScanner->scanPort(ScanI2C::I2CPort::WIRE1, i2caddr_scan); +#endif + i2cScanner->scanPort(ScanI2C::I2CPort::WIRE, i2caddr_scan); + auto kb_info = i2cScanner->firstKeyboard(); + + if (kb_info.type != ScanI2C::DeviceType::NONE) { + cardkb_found = kb_info.address; + switch (kb_info.type) { + case ScanI2C::DeviceType::RAK14004: + kb_model = 0x02; + break; + case ScanI2C::DeviceType::CARDKB: + kb_model = 0x00; + break; + case ScanI2C::DeviceType::TDECKKB: + // assign an arbitrary value to distinguish from other models + kb_model = 0x10; + break; + case ScanI2C::DeviceType::BBQ10KB: + // assign an arbitrary value to distinguish from other models + kb_model = 0x11; + break; + default: + // use this as default since it's also just zero + LOG_WARN("kb_info.type is unknown(0x%02x), setting kb_model=0x00\n", kb_info.type); + kb_model = 0x00; + } + } + if (cardkb_found.address == 0x00) + return INT32_MAX; } if (!i2cBus) { diff --git a/src/main.cpp b/src/main.cpp index a3e9258baa..4a9fef5d08 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -35,8 +35,6 @@ #include // #include -bool cardKBDetected = false; -void scanForCardKB(); #ifdef ARCH_ESP32 #if !MESHTASTIC_EXCLUDE_WEBSERVER #include "mesh/http/WebServer.h" @@ -376,7 +374,6 @@ void setup() // otherwise keyboard and touch screen will not work delay(800); #endif -scanForCardKB(); // Initial scan for CardKB // Currently only the tbeam has a PMU // PMU initialization needs to be placed before i2c scanning diff --git a/src/main.h b/src/main.h index 737d424a73..db05a47347 100644 --- a/src/main.h +++ b/src/main.h @@ -21,7 +21,7 @@ extern NimbleBluetooth *nimbleBluetooth; #include "NRF52Bluetooth.h" extern NRF52Bluetooth *nrf52Bluetooth; #endif -extern bool cardKBDetected; + #if ARCH_PORTDUINO extern HardwareSPI *DisplaySPI; extern HardwareSPI *LoraSPI; @@ -39,7 +39,6 @@ extern bool pmu_found; extern bool isCharging; extern bool isUSBPowered; -#define CARDKB_I2C_ADDRESS 0x5F // Replace 0x5F with the actual address if different #if !defined(ARCH_PORTDUINO) && !defined(ARCH_STM32WL) extern ATECCX08A atecc; #endif From dca8615eaade72d847866058ce75795a17b1b38a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20G=C3=B6ttgens?= Date: Fri, 24 May 2024 22:59:31 +0200 Subject: [PATCH 05/65] change type to 8 bit uint --- src/detect/ScanI2C.cpp | 2 +- src/detect/ScanI2C.h | 2 +- src/detect/ScanI2CTwoWire.cpp | 6 +++--- src/detect/ScanI2CTwoWire.h | 2 +- src/input/kbI2cBase.cpp | 2 +- 5 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/detect/ScanI2C.cpp b/src/detect/ScanI2C.cpp index 7d0a836531..f3057c81a2 100644 --- a/src/detect/ScanI2C.cpp +++ b/src/detect/ScanI2C.cpp @@ -6,7 +6,7 @@ const ScanI2C::FoundDevice ScanI2C::DEVICE_NONE = ScanI2C::FoundDevice(ScanI2C:: ScanI2C::ScanI2C() = default; void ScanI2C::scanPort(ScanI2C::I2CPort port) {} -void ScanI2C::scanPort(ScanI2C::I2CPort port, int *address) {} +void ScanI2C::scanPort(ScanI2C::I2CPort port, uint8_t *address) {} void ScanI2C::setSuppressScreen() { diff --git a/src/detect/ScanI2C.h b/src/detect/ScanI2C.h index 4aa4549cc8..64c9ddbc28 100644 --- a/src/detect/ScanI2C.h +++ b/src/detect/ScanI2C.h @@ -81,7 +81,7 @@ class ScanI2C ScanI2C(); virtual void scanPort(ScanI2C::I2CPort); - virtual void scanPort(ScanI2C::I2CPort, int *); + virtual void scanPort(ScanI2C::I2CPort, uint8_t *); /* * A bit of a hack, this tells the scanner not to tell later systems there is a screen to avoid enabling it. diff --git a/src/detect/ScanI2CTwoWire.cpp b/src/detect/ScanI2CTwoWire.cpp index f7068ee025..06b94d6af9 100644 --- a/src/detect/ScanI2CTwoWire.cpp +++ b/src/detect/ScanI2CTwoWire.cpp @@ -135,7 +135,7 @@ uint16_t ScanI2CTwoWire::getRegisterValue(const ScanI2CTwoWire::RegisterLocation type = T; \ break; -void ScanI2CTwoWire::scanPort(I2CPort port, int *address) +void ScanI2CTwoWire::scanPort(I2CPort port, uint8_t *address) { concurrency::LockGuard guard((concurrency::Lock *)&lock); @@ -163,8 +163,8 @@ void ScanI2CTwoWire::scanPort(I2CPort port, int *address) #endif for (addr.address = 1; addr.address < 127; addr.address++) { - // Skip the address if it is not requested oon a partial scan - if (sizeof(address) > 0 && addr.address != *address) { + // Skip the address if it is not requested on a partial scan + if (address != nullptr && *address != addr.address) { continue; } i2cBus->beginTransmission(addr.address); diff --git a/src/detect/ScanI2CTwoWire.h b/src/detect/ScanI2CTwoWire.h index a7c19c7791..332afbf64e 100644 --- a/src/detect/ScanI2CTwoWire.h +++ b/src/detect/ScanI2CTwoWire.h @@ -16,7 +16,7 @@ class ScanI2CTwoWire : public ScanI2C public: void scanPort(ScanI2C::I2CPort) override; - void scanPort(ScanI2C::I2CPort, int *) override; + void scanPort(ScanI2C::I2CPort, uint8_t *) override; ScanI2C::FoundDevice find(ScanI2C::DeviceType) const override; diff --git a/src/input/kbI2cBase.cpp b/src/input/kbI2cBase.cpp index 55f435fda7..135de17166 100644 --- a/src/input/kbI2cBase.cpp +++ b/src/input/kbI2cBase.cpp @@ -33,7 +33,7 @@ int32_t KbI2cBase::runOnce() if (cardkb_found.address == 0x00) { // Input device is not detected. Rescan now. auto i2cScanner = std::unique_ptr(new ScanI2CTwoWire()); - int i2caddr_scan[] = {CARDKB_ADDR, TDECK_KB_ADDR, BBQ10_KB_ADDR}; + uint8_t i2caddr_scan[] = {CARDKB_ADDR, TDECK_KB_ADDR, BBQ10_KB_ADDR}; #if defined(I2C_SDA1) i2cScanner->scanPort(ScanI2C::I2CPort::WIRE1, i2caddr_scan); #endif From c46c3427f0c6ae8809e0aec3a731792f724dcd85 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20G=C3=B6ttgens?= Date: Sat, 25 May 2024 12:37:55 +0200 Subject: [PATCH 06/65] Iterate through uint array --- src/detect/ScanI2C.cpp | 2 +- src/detect/ScanI2C.h | 2 +- src/detect/ScanI2CTwoWire.cpp | 21 +++++++++++++++------ src/detect/ScanI2CTwoWire.h | 2 +- src/input/kbI2cBase.cpp | 5 +++-- 5 files changed, 21 insertions(+), 11 deletions(-) diff --git a/src/detect/ScanI2C.cpp b/src/detect/ScanI2C.cpp index f3057c81a2..525780af66 100644 --- a/src/detect/ScanI2C.cpp +++ b/src/detect/ScanI2C.cpp @@ -6,7 +6,7 @@ const ScanI2C::FoundDevice ScanI2C::DEVICE_NONE = ScanI2C::FoundDevice(ScanI2C:: ScanI2C::ScanI2C() = default; void ScanI2C::scanPort(ScanI2C::I2CPort port) {} -void ScanI2C::scanPort(ScanI2C::I2CPort port, uint8_t *address) {} +void ScanI2C::scanPort(ScanI2C::I2CPort port, uint8_t *address, uint8_t asize) {} void ScanI2C::setSuppressScreen() { diff --git a/src/detect/ScanI2C.h b/src/detect/ScanI2C.h index 64c9ddbc28..4084c44797 100644 --- a/src/detect/ScanI2C.h +++ b/src/detect/ScanI2C.h @@ -81,7 +81,7 @@ class ScanI2C ScanI2C(); virtual void scanPort(ScanI2C::I2CPort); - virtual void scanPort(ScanI2C::I2CPort, uint8_t *); + virtual void scanPort(ScanI2C::I2CPort, uint8_t *, uint8_t); /* * A bit of a hack, this tells the scanner not to tell later systems there is a screen to avoid enabling it. diff --git a/src/detect/ScanI2CTwoWire.cpp b/src/detect/ScanI2CTwoWire.cpp index 06b94d6af9..3376d23beb 100644 --- a/src/detect/ScanI2CTwoWire.cpp +++ b/src/detect/ScanI2CTwoWire.cpp @@ -14,6 +14,15 @@ #define XPOWERS_AXP192_AXP2101_ADDRESS 0x34 #endif +bool in_array(uint8_t *array, int size, uint8_t lookfor) +{ + int i; + for (i = 0; i < size; i++) + if (lookfor == array[i]) + return true; + return false; +} + ScanI2C::FoundDevice ScanI2CTwoWire::find(ScanI2C::DeviceType type) const { concurrency::LockGuard guard((concurrency::Lock *)&lock); @@ -135,7 +144,7 @@ uint16_t ScanI2CTwoWire::getRegisterValue(const ScanI2CTwoWire::RegisterLocation type = T; \ break; -void ScanI2CTwoWire::scanPort(I2CPort port, uint8_t *address) +void ScanI2CTwoWire::scanPort(I2CPort port, uint8_t *address, uint8_t asize) { concurrency::LockGuard guard((concurrency::Lock *)&lock); @@ -163,10 +172,10 @@ void ScanI2CTwoWire::scanPort(I2CPort port, uint8_t *address) #endif for (addr.address = 1; addr.address < 127; addr.address++) { - // Skip the address if it is not requested on a partial scan - if (address != nullptr && *address != addr.address) { - continue; - } + if (asize != 0) + if (in_array(address, asize, addr.address)) + continue; + i2cBus->beginTransmission(addr.address); #ifdef ARCH_PORTDUINO if (i2cBus->read() != -1) @@ -359,7 +368,7 @@ void ScanI2CTwoWire::scanPort(I2CPort port, uint8_t *address) void ScanI2CTwoWire::scanPort(I2CPort port) { - scanPort(port, nullptr); + scanPort(port, nullptr, 0); } TwoWire *ScanI2CTwoWire::fetchI2CBus(ScanI2C::DeviceAddress address) const diff --git a/src/detect/ScanI2CTwoWire.h b/src/detect/ScanI2CTwoWire.h index 332afbf64e..82b48f6b47 100644 --- a/src/detect/ScanI2CTwoWire.h +++ b/src/detect/ScanI2CTwoWire.h @@ -16,7 +16,7 @@ class ScanI2CTwoWire : public ScanI2C public: void scanPort(ScanI2C::I2CPort) override; - void scanPort(ScanI2C::I2CPort, uint8_t *) override; + void scanPort(ScanI2C::I2CPort, uint8_t *, uint8_t) override; ScanI2C::FoundDevice find(ScanI2C::DeviceType) const override; diff --git a/src/input/kbI2cBase.cpp b/src/input/kbI2cBase.cpp index 135de17166..ce22edb93d 100644 --- a/src/input/kbI2cBase.cpp +++ b/src/input/kbI2cBase.cpp @@ -34,10 +34,11 @@ int32_t KbI2cBase::runOnce() // Input device is not detected. Rescan now. auto i2cScanner = std::unique_ptr(new ScanI2CTwoWire()); uint8_t i2caddr_scan[] = {CARDKB_ADDR, TDECK_KB_ADDR, BBQ10_KB_ADDR}; + uint8_t i2caddr_asize = 3; #if defined(I2C_SDA1) - i2cScanner->scanPort(ScanI2C::I2CPort::WIRE1, i2caddr_scan); + i2cScanner->scanPort(ScanI2C::I2CPort::WIRE1, i2caddr_scan, i2caddr_asize); #endif - i2cScanner->scanPort(ScanI2C::I2CPort::WIRE, i2caddr_scan); + i2cScanner->scanPort(ScanI2C::I2CPort::WIRE, i2caddr_scan, i2caddr_asize); auto kb_info = i2cScanner->firstKeyboard(); if (kb_info.type != ScanI2C::DeviceType::NONE) { From 8b1b6faf896df177f585b2cb5f7799341815911d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michael=20Gjels=C3=B8?= <36234524+gjelsoe@users.noreply.github.com> Date: Tue, 11 Jun 2024 21:51:39 +0200 Subject: [PATCH 07/65] Added Radiomaster Bandit Nano and Radiomaster Bandit Micro to default_envs. (#4077) Added Radiomaster Bandit Micro, it shares the same code and settings as Bandit Nano --- platformio.ini | 2 ++ .../platformio.ini | 19 +++++++++++++++++++ 2 files changed, 21 insertions(+) create mode 100644 variants/radiomaster_900_bandit_micro/platformio.ini diff --git a/platformio.ini b/platformio.ini index 85bce32794..7ed794a6ed 100644 --- a/platformio.ini +++ b/platformio.ini @@ -31,6 +31,8 @@ default_envs = tbeam ;default_envs = rak4631 ;default_envs = rak10701 ;default_envs = wio-e5 +;default_envs = radiomaster_900_bandit_nano +;default_envs = radiomaster_900_bandit_micro extra_configs = arch/*/*.ini diff --git a/variants/radiomaster_900_bandit_micro/platformio.ini b/variants/radiomaster_900_bandit_micro/platformio.ini new file mode 100644 index 0000000000..9e54f58591 --- /dev/null +++ b/variants/radiomaster_900_bandit_micro/platformio.ini @@ -0,0 +1,19 @@ +; +; This uses the same code and settings as the Radio Master Bandit Nano (https://www.radiomasterrc.com/products/bandit-nano-expresslrs-rf-module) +; +; Link to the unit : https://www.radiomasterrc.com/products/bandit-micro-expresslrs-rf-module +; +[env:radiomaster_900_bandit_micro] +extends = esp32_base +board = esp32doit-devkit-v1 +build_flags = + ${esp32_base.build_flags} + -DRADIOMASTER_900_BANDIT_NANO + -DVTABLES_IN_FLASH=1 + -DCONFIG_DISABLE_HAL_LOCKS=1 + -O2 + -Ivariants/radiomaster_900_bandit_nano +board_build.f_cpu = 240000000L +upload_protocol = esptool +lib_deps = + ${esp32_base.lib_deps} \ No newline at end of file From 7f2647abb18303c1e1af8325fbd53e3129e221dd Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Tue, 11 Jun 2024 14:52:02 -0500 Subject: [PATCH 08/65] [create-pull-request] automated change (#4078) Co-authored-by: jp-bennett <5630967+jp-bennett@users.noreply.github.com> --- protobufs | 2 +- src/mesh/generated/meshtastic/config.pb.cpp | 1 + src/mesh/generated/meshtastic/config.pb.h | 36 ++++++++++++++++--- src/mesh/generated/meshtastic/deviceonly.pb.h | 2 +- src/mesh/generated/meshtastic/localonly.pb.h | 2 +- 5 files changed, 36 insertions(+), 7 deletions(-) diff --git a/protobufs b/protobufs index a641c5ce4f..8c8048798c 160000 --- a/protobufs +++ b/protobufs @@ -1 +1 @@ -Subproject commit a641c5ce4fca158d18ca3cffc92ac7a10f9b6a04 +Subproject commit 8c8048798c1b1773b9d8f2c32eb3f4c9e72f8218 diff --git a/src/mesh/generated/meshtastic/config.pb.cpp b/src/mesh/generated/meshtastic/config.pb.cpp index f05e47573e..bb82198c05 100644 --- a/src/mesh/generated/meshtastic/config.pb.cpp +++ b/src/mesh/generated/meshtastic/config.pb.cpp @@ -46,3 +46,4 @@ PB_BIND(meshtastic_Config_BluetoothConfig, meshtastic_Config_BluetoothConfig, AU + diff --git a/src/mesh/generated/meshtastic/config.pb.h b/src/mesh/generated/meshtastic/config.pb.h index 0830ed851e..781538d11e 100644 --- a/src/mesh/generated/meshtastic/config.pb.h +++ b/src/mesh/generated/meshtastic/config.pb.h @@ -182,6 +182,25 @@ typedef enum _meshtastic_Config_DisplayConfig_DisplayMode { meshtastic_Config_DisplayConfig_DisplayMode_COLOR = 3 } meshtastic_Config_DisplayConfig_DisplayMode; +typedef enum _meshtastic_Config_DisplayConfig_CompassOrientation { + /* The compass and the display are in the same orientation. */ + meshtastic_Config_DisplayConfig_CompassOrientation_DEGREES_0 = 0, + /* Rotate the compass by 90 degrees. */ + meshtastic_Config_DisplayConfig_CompassOrientation_DEGREES_90 = 1, + /* Rotate the compass by 180 degrees. */ + meshtastic_Config_DisplayConfig_CompassOrientation_DEGREES_180 = 2, + /* Rotate the compass by 270 degrees. */ + meshtastic_Config_DisplayConfig_CompassOrientation_DEGREES_270 = 3, + /* Don't rotate the compass, but invert the result. */ + meshtastic_Config_DisplayConfig_CompassOrientation_DEGREES_0_INVERTED = 4, + /* Rotate the compass by 90 degrees and invert. */ + meshtastic_Config_DisplayConfig_CompassOrientation_DEGREES_90_INVERTED = 5, + /* Rotate the compass by 180 degrees and invert. */ + meshtastic_Config_DisplayConfig_CompassOrientation_DEGREES_180_INVERTED = 6, + /* Rotate the compass by 270 degrees and invert. */ + meshtastic_Config_DisplayConfig_CompassOrientation_DEGREES_270_INVERTED = 7 +} meshtastic_Config_DisplayConfig_CompassOrientation; + typedef enum _meshtastic_Config_LoRaConfig_RegionCode { /* Region is not set */ meshtastic_Config_LoRaConfig_RegionCode_UNSET = 0, @@ -413,6 +432,8 @@ typedef struct _meshtastic_Config_DisplayConfig { bool heading_bold; /* Should we wake the screen up on accelerometer detected motion or tap */ bool wake_on_tap_or_motion; + /* Indicates how to rotate or invert the compass output to accurate display on the display. */ + meshtastic_Config_DisplayConfig_CompassOrientation compass_orientation; } meshtastic_Config_DisplayConfig; /* Lora Config */ @@ -547,6 +568,10 @@ extern "C" { #define _meshtastic_Config_DisplayConfig_DisplayMode_MAX meshtastic_Config_DisplayConfig_DisplayMode_COLOR #define _meshtastic_Config_DisplayConfig_DisplayMode_ARRAYSIZE ((meshtastic_Config_DisplayConfig_DisplayMode)(meshtastic_Config_DisplayConfig_DisplayMode_COLOR+1)) +#define _meshtastic_Config_DisplayConfig_CompassOrientation_MIN meshtastic_Config_DisplayConfig_CompassOrientation_DEGREES_0 +#define _meshtastic_Config_DisplayConfig_CompassOrientation_MAX meshtastic_Config_DisplayConfig_CompassOrientation_DEGREES_270_INVERTED +#define _meshtastic_Config_DisplayConfig_CompassOrientation_ARRAYSIZE ((meshtastic_Config_DisplayConfig_CompassOrientation)(meshtastic_Config_DisplayConfig_CompassOrientation_DEGREES_270_INVERTED+1)) + #define _meshtastic_Config_LoRaConfig_RegionCode_MIN meshtastic_Config_LoRaConfig_RegionCode_UNSET #define _meshtastic_Config_LoRaConfig_RegionCode_MAX meshtastic_Config_LoRaConfig_RegionCode_SG_923 #define _meshtastic_Config_LoRaConfig_RegionCode_ARRAYSIZE ((meshtastic_Config_LoRaConfig_RegionCode)(meshtastic_Config_LoRaConfig_RegionCode_SG_923+1)) @@ -573,6 +598,7 @@ extern "C" { #define meshtastic_Config_DisplayConfig_units_ENUMTYPE meshtastic_Config_DisplayConfig_DisplayUnits #define meshtastic_Config_DisplayConfig_oled_ENUMTYPE meshtastic_Config_DisplayConfig_OledType #define meshtastic_Config_DisplayConfig_displaymode_ENUMTYPE meshtastic_Config_DisplayConfig_DisplayMode +#define meshtastic_Config_DisplayConfig_compass_orientation_ENUMTYPE meshtastic_Config_DisplayConfig_CompassOrientation #define meshtastic_Config_LoRaConfig_modem_preset_ENUMTYPE meshtastic_Config_LoRaConfig_ModemPreset #define meshtastic_Config_LoRaConfig_region_ENUMTYPE meshtastic_Config_LoRaConfig_RegionCode @@ -587,7 +613,7 @@ extern "C" { #define meshtastic_Config_PowerConfig_init_default {0, 0, 0, 0, 0, 0, 0, 0} #define meshtastic_Config_NetworkConfig_init_default {0, "", "", "", 0, _meshtastic_Config_NetworkConfig_AddressMode_MIN, false, meshtastic_Config_NetworkConfig_IpV4Config_init_default, ""} #define meshtastic_Config_NetworkConfig_IpV4Config_init_default {0, 0, 0, 0} -#define meshtastic_Config_DisplayConfig_init_default {0, _meshtastic_Config_DisplayConfig_GpsCoordinateFormat_MIN, 0, 0, 0, _meshtastic_Config_DisplayConfig_DisplayUnits_MIN, _meshtastic_Config_DisplayConfig_OledType_MIN, _meshtastic_Config_DisplayConfig_DisplayMode_MIN, 0, 0} +#define meshtastic_Config_DisplayConfig_init_default {0, _meshtastic_Config_DisplayConfig_GpsCoordinateFormat_MIN, 0, 0, 0, _meshtastic_Config_DisplayConfig_DisplayUnits_MIN, _meshtastic_Config_DisplayConfig_OledType_MIN, _meshtastic_Config_DisplayConfig_DisplayMode_MIN, 0, 0, _meshtastic_Config_DisplayConfig_CompassOrientation_MIN} #define meshtastic_Config_LoRaConfig_init_default {0, _meshtastic_Config_LoRaConfig_ModemPreset_MIN, 0, 0, 0, 0, _meshtastic_Config_LoRaConfig_RegionCode_MIN, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0}, 0} #define meshtastic_Config_BluetoothConfig_init_default {0, _meshtastic_Config_BluetoothConfig_PairingMode_MIN, 0} #define meshtastic_Config_init_zero {0, {meshtastic_Config_DeviceConfig_init_zero}} @@ -596,7 +622,7 @@ extern "C" { #define meshtastic_Config_PowerConfig_init_zero {0, 0, 0, 0, 0, 0, 0, 0} #define meshtastic_Config_NetworkConfig_init_zero {0, "", "", "", 0, _meshtastic_Config_NetworkConfig_AddressMode_MIN, false, meshtastic_Config_NetworkConfig_IpV4Config_init_zero, ""} #define meshtastic_Config_NetworkConfig_IpV4Config_init_zero {0, 0, 0, 0} -#define meshtastic_Config_DisplayConfig_init_zero {0, _meshtastic_Config_DisplayConfig_GpsCoordinateFormat_MIN, 0, 0, 0, _meshtastic_Config_DisplayConfig_DisplayUnits_MIN, _meshtastic_Config_DisplayConfig_OledType_MIN, _meshtastic_Config_DisplayConfig_DisplayMode_MIN, 0, 0} +#define meshtastic_Config_DisplayConfig_init_zero {0, _meshtastic_Config_DisplayConfig_GpsCoordinateFormat_MIN, 0, 0, 0, _meshtastic_Config_DisplayConfig_DisplayUnits_MIN, _meshtastic_Config_DisplayConfig_OledType_MIN, _meshtastic_Config_DisplayConfig_DisplayMode_MIN, 0, 0, _meshtastic_Config_DisplayConfig_CompassOrientation_MIN} #define meshtastic_Config_LoRaConfig_init_zero {0, _meshtastic_Config_LoRaConfig_ModemPreset_MIN, 0, 0, 0, 0, _meshtastic_Config_LoRaConfig_RegionCode_MIN, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0}, 0} #define meshtastic_Config_BluetoothConfig_init_zero {0, _meshtastic_Config_BluetoothConfig_PairingMode_MIN, 0} @@ -656,6 +682,7 @@ extern "C" { #define meshtastic_Config_DisplayConfig_displaymode_tag 8 #define meshtastic_Config_DisplayConfig_heading_bold_tag 9 #define meshtastic_Config_DisplayConfig_wake_on_tap_or_motion_tag 10 +#define meshtastic_Config_DisplayConfig_compass_orientation_tag 11 #define meshtastic_Config_LoRaConfig_use_preset_tag 1 #define meshtastic_Config_LoRaConfig_modem_preset_tag 2 #define meshtastic_Config_LoRaConfig_bandwidth_tag 3 @@ -778,7 +805,8 @@ X(a, STATIC, SINGULAR, UENUM, units, 6) \ X(a, STATIC, SINGULAR, UENUM, oled, 7) \ X(a, STATIC, SINGULAR, UENUM, displaymode, 8) \ X(a, STATIC, SINGULAR, BOOL, heading_bold, 9) \ -X(a, STATIC, SINGULAR, BOOL, wake_on_tap_or_motion, 10) +X(a, STATIC, SINGULAR, BOOL, wake_on_tap_or_motion, 10) \ +X(a, STATIC, SINGULAR, UENUM, compass_orientation, 11) #define meshtastic_Config_DisplayConfig_CALLBACK NULL #define meshtastic_Config_DisplayConfig_DEFAULT NULL @@ -834,7 +862,7 @@ extern const pb_msgdesc_t meshtastic_Config_BluetoothConfig_msg; #define MESHTASTIC_MESHTASTIC_CONFIG_PB_H_MAX_SIZE meshtastic_Config_size #define meshtastic_Config_BluetoothConfig_size 10 #define meshtastic_Config_DeviceConfig_size 100 -#define meshtastic_Config_DisplayConfig_size 28 +#define meshtastic_Config_DisplayConfig_size 30 #define meshtastic_Config_LoRaConfig_size 80 #define meshtastic_Config_NetworkConfig_IpV4Config_size 20 #define meshtastic_Config_NetworkConfig_size 196 diff --git a/src/mesh/generated/meshtastic/deviceonly.pb.h b/src/mesh/generated/meshtastic/deviceonly.pb.h index a5cbc42a5d..0e3e28ba1b 100644 --- a/src/mesh/generated/meshtastic/deviceonly.pb.h +++ b/src/mesh/generated/meshtastic/deviceonly.pb.h @@ -308,7 +308,7 @@ extern const pb_msgdesc_t meshtastic_OEMStore_msg; #define MESHTASTIC_MESHTASTIC_DEVICEONLY_PB_H_MAX_SIZE meshtastic_OEMStore_size #define meshtastic_ChannelFile_size 718 #define meshtastic_NodeInfoLite_size 166 -#define meshtastic_OEMStore_size 3368 +#define meshtastic_OEMStore_size 3370 #define meshtastic_PositionLite_size 28 #ifdef __cplusplus diff --git a/src/mesh/generated/meshtastic/localonly.pb.h b/src/mesh/generated/meshtastic/localonly.pb.h index 1b8123ef5f..160202d9bd 100644 --- a/src/mesh/generated/meshtastic/localonly.pb.h +++ b/src/mesh/generated/meshtastic/localonly.pb.h @@ -181,7 +181,7 @@ extern const pb_msgdesc_t meshtastic_LocalModuleConfig_msg; /* Maximum encoded size of messages (where known) */ #define MESHTASTIC_MESHTASTIC_LOCALONLY_PB_H_MAX_SIZE meshtastic_LocalModuleConfig_size -#define meshtastic_LocalConfig_size 537 +#define meshtastic_LocalConfig_size 539 #define meshtastic_LocalModuleConfig_size 685 #ifdef __cplusplus From 0852a170a3b6a10b69fc88963ef267faeda11a07 Mon Sep 17 00:00:00 2001 From: Jonathan Bennett Date: Tue, 11 Jun 2024 17:47:45 -0500 Subject: [PATCH 09/65] Add support for BMX160/RAK12034 compass module (#4021) --- src/AccelerometerThread.h | 81 ++- src/Fusion/Fusion.h | 32 ++ src/Fusion/FusionAhrs.c | 542 ++++++++++++++++++ src/Fusion/FusionAhrs.h | 112 ++++ src/Fusion/FusionAxes.h | 188 ++++++ src/Fusion/FusionCalibration.h | 49 ++ src/Fusion/FusionCompass.c | 51 ++ src/Fusion/FusionCompass.h | 26 + src/Fusion/FusionConvention.h | 25 + src/Fusion/FusionMath.h | 503 ++++++++++++++++ src/Fusion/FusionOffset.c | 80 +++ src/Fusion/FusionOffset.h | 40 ++ src/configuration.h | 1 + src/detect/ScanI2C.cpp | 4 +- src/detect/ScanI2C.h | 3 +- src/detect/ScanI2CTwoWire.cpp | 1 + src/graphics/Screen.cpp | 8 +- src/graphics/Screen.h | 13 + src/main.h | 6 +- variants/rak4631/platformio.ini | 1 + variants/rak4631_epaper/platformio.ini | 1 + variants/rak4631_epaper_onrxtx/platformio.ini | 3 +- 22 files changed, 1760 insertions(+), 10 deletions(-) create mode 100644 src/Fusion/Fusion.h create mode 100644 src/Fusion/FusionAhrs.c create mode 100644 src/Fusion/FusionAhrs.h create mode 100644 src/Fusion/FusionAxes.h create mode 100644 src/Fusion/FusionCalibration.h create mode 100644 src/Fusion/FusionCompass.c create mode 100644 src/Fusion/FusionCompass.h create mode 100644 src/Fusion/FusionConvention.h create mode 100644 src/Fusion/FusionMath.h create mode 100644 src/Fusion/FusionOffset.c create mode 100644 src/Fusion/FusionOffset.h diff --git a/src/AccelerometerThread.h b/src/AccelerometerThread.h index ad40cd9bd9..f03752cad7 100644 --- a/src/AccelerometerThread.h +++ b/src/AccelerometerThread.h @@ -14,6 +14,10 @@ #include #include #include +#ifdef RAK_4631 +#include "Fusion/Fusion.h" +#include +#endif #define ACCELEROMETER_CHECK_INTERVAL_MS 100 #define ACCELEROMETER_CLICK_THRESHOLD 40 @@ -50,12 +54,13 @@ class AccelerometerThread : public concurrency::OSThread return; } acceleremoter_type = type; - +#ifndef RAK_4631 if (!config.display.wake_on_tap_or_motion && !config.device.double_tap_as_button_press) { LOG_DEBUG("AccelerometerThread disabling due to no interested configurations\n"); disable(); return; } +#endif init(); } @@ -87,6 +92,71 @@ class AccelerometerThread : public concurrency::OSThread wakeScreen(); return 500; } +#ifdef RAK_4631 + } else if (acceleremoter_type == ScanI2C::DeviceType::BMX160) { + sBmx160SensorData_t magAccel; + sBmx160SensorData_t gAccel; + + /* Get a new sensor event */ + bmx160.getAllData(&magAccel, NULL, &gAccel); + + // expirimental calibrate routine. Limited to between 10 and 30 seconds after boot + if (millis() > 10 * 1000 && millis() < 30 * 1000) { + if (magAccel.x > highestX) + highestX = magAccel.x; + if (magAccel.x < lowestX) + lowestX = magAccel.x; + if (magAccel.y > highestY) + highestY = magAccel.y; + if (magAccel.y < lowestY) + lowestY = magAccel.y; + if (magAccel.z > highestZ) + highestZ = magAccel.z; + if (magAccel.z < lowestZ) + lowestZ = magAccel.z; + } + + int highestRealX = highestX - (highestX + lowestX) / 2; + + magAccel.x -= (highestX + lowestX) / 2; + magAccel.y -= (highestY + lowestY) / 2; + magAccel.z -= (highestZ + lowestZ) / 2; + FusionVector ga, ma; + ga.axis.x = -gAccel.x; // default location for the BMX160 is on the rear of the board + ga.axis.y = -gAccel.y; + ga.axis.z = gAccel.z; + ma.axis.x = -magAccel.x; + ma.axis.y = -magAccel.y; + ma.axis.z = magAccel.z * 3; + + // If we're set to one of the inverted positions + if (config.display.compass_orientation > meshtastic_Config_DisplayConfig_CompassOrientation_DEGREES_270) { + ma = FusionAxesSwap(ma, FusionAxesAlignmentNXNYPZ); + ga = FusionAxesSwap(ga, FusionAxesAlignmentNXNYPZ); + } + + float heading = FusionCompassCalculateHeading(FusionConventionNed, ga, ma); + + switch (config.display.compass_orientation) { + case meshtastic_Config_DisplayConfig_CompassOrientation_DEGREES_0: + break; + case meshtastic_Config_DisplayConfig_CompassOrientation_DEGREES_90: + case meshtastic_Config_DisplayConfig_CompassOrientation_DEGREES_90_INVERTED: + heading += 90; + break; + case meshtastic_Config_DisplayConfig_CompassOrientation_DEGREES_180: + case meshtastic_Config_DisplayConfig_CompassOrientation_DEGREES_180_INVERTED: + heading += 180; + break; + case meshtastic_Config_DisplayConfig_CompassOrientation_DEGREES_270: + case meshtastic_Config_DisplayConfig_CompassOrientation_DEGREES_270_INVERTED: + heading += 270; + break; + } + + screen->setHeading(heading); + +#endif } else if (acceleremoter_type == ScanI2C::DeviceType::LSM6DS3 && lsm.shake()) { wakeScreen(); return 500; @@ -149,6 +219,11 @@ class AccelerometerThread : public concurrency::OSThread bmaSensor.enableTiltIRQ(); // It corresponds to isDoubleClick interrupt bmaSensor.enableWakeupIRQ(); +#ifdef RAK_4631 + } else if (acceleremoter_type == ScanI2C::DeviceType::BMX160 && bmx160.begin()) { + bmx160.ODR_Config(BMX160_ACCEL_ODR_100HZ, BMX160_GYRO_ODR_100HZ); // set output data rate + +#endif } else if (acceleremoter_type == ScanI2C::DeviceType::LSM6DS3 && lsm.begin_I2C(accelerometer_found.address)) { LOG_DEBUG("LSM6DS3 initializing\n"); // Default threshold of 2G, less sensitive options are 4, 8 or 16G @@ -179,6 +254,10 @@ class AccelerometerThread : public concurrency::OSThread Adafruit_LIS3DH lis; Adafruit_LSM6DS3TRC lsm; SensorBMA423 bmaSensor; +#ifdef RAK_4631 + RAK_BMX160 bmx160; + float highestX = 0, lowestX = 0, highestY = 0, lowestY = 0, highestZ = 0, lowestZ = 0; +#endif bool BMA_IRQ = false; }; diff --git a/src/Fusion/Fusion.h b/src/Fusion/Fusion.h new file mode 100644 index 0000000000..48f5198c5a --- /dev/null +++ b/src/Fusion/Fusion.h @@ -0,0 +1,32 @@ +/** + * @file Fusion.h + * @author Seb Madgwick + * @brief Main header file for the Fusion library. This is the only file that + * needs to be included when using the library. + */ + +#ifndef FUSION_H +#define FUSION_H + +//------------------------------------------------------------------------------ +// Includes + +#ifdef __cplusplus +extern "C" { +#endif + +#include "FusionAhrs.h" +#include "FusionAxes.h" +#include "FusionCalibration.h" +#include "FusionCompass.h" +#include "FusionConvention.h" +#include "FusionMath.h" +#include "FusionOffset.h" + +#ifdef __cplusplus +} +#endif + +#endif +//------------------------------------------------------------------------------ +// End of file diff --git a/src/Fusion/FusionAhrs.c b/src/Fusion/FusionAhrs.c new file mode 100644 index 0000000000..d6c1d02155 --- /dev/null +++ b/src/Fusion/FusionAhrs.c @@ -0,0 +1,542 @@ +/** + * @file FusionAhrs.c + * @author Seb Madgwick + * @brief AHRS algorithm to combine gyroscope, accelerometer, and magnetometer + * measurements into a single measurement of orientation relative to the Earth. + */ + +//------------------------------------------------------------------------------ +// Includes + +#include "FusionAhrs.h" +#include // FLT_MAX +#include // atan2f, cosf, fabsf, powf, sinf + +//------------------------------------------------------------------------------ +// Definitions + +/** + * @brief Initial gain used during the initialisation. + */ +#define INITIAL_GAIN (10.0f) + +/** + * @brief Initialisation period in seconds. + */ +#define INITIALISATION_PERIOD (3.0f) + +//------------------------------------------------------------------------------ +// Function declarations + +static inline FusionVector HalfGravity(const FusionAhrs *const ahrs); + +static inline FusionVector HalfMagnetic(const FusionAhrs *const ahrs); + +static inline FusionVector Feedback(const FusionVector sensor, const FusionVector reference); + +static inline int Clamp(const int value, const int min, const int max); + +//------------------------------------------------------------------------------ +// Functions + +/** + * @brief Initialises the AHRS algorithm structure. + * @param ahrs AHRS algorithm structure. + */ +void FusionAhrsInitialise(FusionAhrs *const ahrs) +{ + const FusionAhrsSettings settings = { + .convention = FusionConventionNwu, + .gain = 0.5f, + .gyroscopeRange = 0.0f, + .accelerationRejection = 90.0f, + .magneticRejection = 90.0f, + .recoveryTriggerPeriod = 0, + }; + FusionAhrsSetSettings(ahrs, &settings); + FusionAhrsReset(ahrs); +} + +/** + * @brief Resets the AHRS algorithm. This is equivalent to reinitialising the + * algorithm while maintaining the current settings. + * @param ahrs AHRS algorithm structure. + */ +void FusionAhrsReset(FusionAhrs *const ahrs) +{ + ahrs->quaternion = FUSION_IDENTITY_QUATERNION; + ahrs->accelerometer = FUSION_VECTOR_ZERO; + ahrs->initialising = true; + ahrs->rampedGain = INITIAL_GAIN; + ahrs->angularRateRecovery = false; + ahrs->halfAccelerometerFeedback = FUSION_VECTOR_ZERO; + ahrs->halfMagnetometerFeedback = FUSION_VECTOR_ZERO; + ahrs->accelerometerIgnored = false; + ahrs->accelerationRecoveryTrigger = 0; + ahrs->accelerationRecoveryTimeout = ahrs->settings.recoveryTriggerPeriod; + ahrs->magnetometerIgnored = false; + ahrs->magneticRecoveryTrigger = 0; + ahrs->magneticRecoveryTimeout = ahrs->settings.recoveryTriggerPeriod; +} + +/** + * @brief Sets the AHRS algorithm settings. + * @param ahrs AHRS algorithm structure. + * @param settings Settings. + */ +void FusionAhrsSetSettings(FusionAhrs *const ahrs, const FusionAhrsSettings *const settings) +{ + ahrs->settings.convention = settings->convention; + ahrs->settings.gain = settings->gain; + ahrs->settings.gyroscopeRange = settings->gyroscopeRange == 0.0f ? FLT_MAX : 0.98f * settings->gyroscopeRange; + ahrs->settings.accelerationRejection = settings->accelerationRejection == 0.0f + ? FLT_MAX + : powf(0.5f * sinf(FusionDegreesToRadians(settings->accelerationRejection)), 2); + ahrs->settings.magneticRejection = + settings->magneticRejection == 0.0f ? FLT_MAX : powf(0.5f * sinf(FusionDegreesToRadians(settings->magneticRejection)), 2); + ahrs->settings.recoveryTriggerPeriod = settings->recoveryTriggerPeriod; + ahrs->accelerationRecoveryTimeout = ahrs->settings.recoveryTriggerPeriod; + ahrs->magneticRecoveryTimeout = ahrs->settings.recoveryTriggerPeriod; + if ((settings->gain == 0.0f) || + (settings->recoveryTriggerPeriod == 0)) { // disable acceleration and magnetic rejection features if gain is zero + ahrs->settings.accelerationRejection = FLT_MAX; + ahrs->settings.magneticRejection = FLT_MAX; + } + if (ahrs->initialising == false) { + ahrs->rampedGain = ahrs->settings.gain; + } + ahrs->rampedGainStep = (INITIAL_GAIN - ahrs->settings.gain) / INITIALISATION_PERIOD; +} + +/** + * @brief Updates the AHRS algorithm using the gyroscope, accelerometer, and + * magnetometer measurements. + * @param ahrs AHRS algorithm structure. + * @param gyroscope Gyroscope measurement in degrees per second. + * @param accelerometer Accelerometer measurement in g. + * @param magnetometer Magnetometer measurement in arbitrary units. + * @param deltaTime Delta time in seconds. + */ +void FusionAhrsUpdate(FusionAhrs *const ahrs, const FusionVector gyroscope, const FusionVector accelerometer, + const FusionVector magnetometer, const float deltaTime) +{ +#define Q ahrs->quaternion.element + + // Store accelerometer + ahrs->accelerometer = accelerometer; + + // Reinitialise if gyroscope range exceeded + if ((fabsf(gyroscope.axis.x) > ahrs->settings.gyroscopeRange) || (fabsf(gyroscope.axis.y) > ahrs->settings.gyroscopeRange) || + (fabsf(gyroscope.axis.z) > ahrs->settings.gyroscopeRange)) { + const FusionQuaternion quaternion = ahrs->quaternion; + FusionAhrsReset(ahrs); + ahrs->quaternion = quaternion; + ahrs->angularRateRecovery = true; + } + + // Ramp down gain during initialisation + if (ahrs->initialising) { + ahrs->rampedGain -= ahrs->rampedGainStep * deltaTime; + if ((ahrs->rampedGain < ahrs->settings.gain) || (ahrs->settings.gain == 0.0f)) { + ahrs->rampedGain = ahrs->settings.gain; + ahrs->initialising = false; + ahrs->angularRateRecovery = false; + } + } + + // Calculate direction of gravity indicated by algorithm + const FusionVector halfGravity = HalfGravity(ahrs); + + // Calculate accelerometer feedback + FusionVector halfAccelerometerFeedback = FUSION_VECTOR_ZERO; + ahrs->accelerometerIgnored = true; + if (FusionVectorIsZero(accelerometer) == false) { + + // Calculate accelerometer feedback scaled by 0.5 + ahrs->halfAccelerometerFeedback = Feedback(FusionVectorNormalise(accelerometer), halfGravity); + + // Don't ignore accelerometer if acceleration error below threshold + if (ahrs->initialising || + ((FusionVectorMagnitudeSquared(ahrs->halfAccelerometerFeedback) <= ahrs->settings.accelerationRejection))) { + ahrs->accelerometerIgnored = false; + ahrs->accelerationRecoveryTrigger -= 9; + } else { + ahrs->accelerationRecoveryTrigger += 1; + } + + // Don't ignore accelerometer during acceleration recovery + if (ahrs->accelerationRecoveryTrigger > ahrs->accelerationRecoveryTimeout) { + ahrs->accelerationRecoveryTimeout = 0; + ahrs->accelerometerIgnored = false; + } else { + ahrs->accelerationRecoveryTimeout = ahrs->settings.recoveryTriggerPeriod; + } + ahrs->accelerationRecoveryTrigger = Clamp(ahrs->accelerationRecoveryTrigger, 0, ahrs->settings.recoveryTriggerPeriod); + + // Apply accelerometer feedback + if (ahrs->accelerometerIgnored == false) { + halfAccelerometerFeedback = ahrs->halfAccelerometerFeedback; + } + } + + // Calculate magnetometer feedback + FusionVector halfMagnetometerFeedback = FUSION_VECTOR_ZERO; + ahrs->magnetometerIgnored = true; + if (FusionVectorIsZero(magnetometer) == false) { + + // Calculate direction of magnetic field indicated by algorithm + const FusionVector halfMagnetic = HalfMagnetic(ahrs); + + // Calculate magnetometer feedback scaled by 0.5 + ahrs->halfMagnetometerFeedback = + Feedback(FusionVectorNormalise(FusionVectorCrossProduct(halfGravity, magnetometer)), halfMagnetic); + + // Don't ignore magnetometer if magnetic error below threshold + if (ahrs->initialising || + ((FusionVectorMagnitudeSquared(ahrs->halfMagnetometerFeedback) <= ahrs->settings.magneticRejection))) { + ahrs->magnetometerIgnored = false; + ahrs->magneticRecoveryTrigger -= 9; + } else { + ahrs->magneticRecoveryTrigger += 1; + } + + // Don't ignore magnetometer during magnetic recovery + if (ahrs->magneticRecoveryTrigger > ahrs->magneticRecoveryTimeout) { + ahrs->magneticRecoveryTimeout = 0; + ahrs->magnetometerIgnored = false; + } else { + ahrs->magneticRecoveryTimeout = ahrs->settings.recoveryTriggerPeriod; + } + ahrs->magneticRecoveryTrigger = Clamp(ahrs->magneticRecoveryTrigger, 0, ahrs->settings.recoveryTriggerPeriod); + + // Apply magnetometer feedback + if (ahrs->magnetometerIgnored == false) { + halfMagnetometerFeedback = ahrs->halfMagnetometerFeedback; + } + } + + // Convert gyroscope to radians per second scaled by 0.5 + const FusionVector halfGyroscope = FusionVectorMultiplyScalar(gyroscope, FusionDegreesToRadians(0.5f)); + + // Apply feedback to gyroscope + const FusionVector adjustedHalfGyroscope = FusionVectorAdd( + halfGyroscope, + FusionVectorMultiplyScalar(FusionVectorAdd(halfAccelerometerFeedback, halfMagnetometerFeedback), ahrs->rampedGain)); + + // Integrate rate of change of quaternion + ahrs->quaternion = FusionQuaternionAdd( + ahrs->quaternion, + FusionQuaternionMultiplyVector(ahrs->quaternion, FusionVectorMultiplyScalar(adjustedHalfGyroscope, deltaTime))); + + // Normalise quaternion + ahrs->quaternion = FusionQuaternionNormalise(ahrs->quaternion); +#undef Q +} + +/** + * @brief Returns the direction of gravity scaled by 0.5. + * @param ahrs AHRS algorithm structure. + * @return Direction of gravity scaled by 0.5. + */ +static inline FusionVector HalfGravity(const FusionAhrs *const ahrs) +{ +#define Q ahrs->quaternion.element + switch (ahrs->settings.convention) { + case FusionConventionNwu: + case FusionConventionEnu: { + const FusionVector halfGravity = {.axis = { + .x = Q.x * Q.z - Q.w * Q.y, + .y = Q.y * Q.z + Q.w * Q.x, + .z = Q.w * Q.w - 0.5f + Q.z * Q.z, + }}; // third column of transposed rotation matrix scaled by 0.5 + return halfGravity; + } + case FusionConventionNed: { + const FusionVector halfGravity = {.axis = { + .x = Q.w * Q.y - Q.x * Q.z, + .y = -1.0f * (Q.y * Q.z + Q.w * Q.x), + .z = 0.5f - Q.w * Q.w - Q.z * Q.z, + }}; // third column of transposed rotation matrix scaled by -0.5 + return halfGravity; + } + } + return FUSION_VECTOR_ZERO; // avoid compiler warning +#undef Q +} + +/** + * @brief Returns the direction of the magnetic field scaled by 0.5. + * @param ahrs AHRS algorithm structure. + * @return Direction of the magnetic field scaled by 0.5. + */ +static inline FusionVector HalfMagnetic(const FusionAhrs *const ahrs) +{ +#define Q ahrs->quaternion.element + switch (ahrs->settings.convention) { + case FusionConventionNwu: { + const FusionVector halfMagnetic = {.axis = { + .x = Q.x * Q.y + Q.w * Q.z, + .y = Q.w * Q.w - 0.5f + Q.y * Q.y, + .z = Q.y * Q.z - Q.w * Q.x, + }}; // second column of transposed rotation matrix scaled by 0.5 + return halfMagnetic; + } + case FusionConventionEnu: { + const FusionVector halfMagnetic = {.axis = { + .x = 0.5f - Q.w * Q.w - Q.x * Q.x, + .y = Q.w * Q.z - Q.x * Q.y, + .z = -1.0f * (Q.x * Q.z + Q.w * Q.y), + }}; // first column of transposed rotation matrix scaled by -0.5 + return halfMagnetic; + } + case FusionConventionNed: { + const FusionVector halfMagnetic = {.axis = { + .x = -1.0f * (Q.x * Q.y + Q.w * Q.z), + .y = 0.5f - Q.w * Q.w - Q.y * Q.y, + .z = Q.w * Q.x - Q.y * Q.z, + }}; // second column of transposed rotation matrix scaled by -0.5 + return halfMagnetic; + } + } + return FUSION_VECTOR_ZERO; // avoid compiler warning +#undef Q +} + +/** + * @brief Returns the feedback. + * @param sensor Sensor. + * @param reference Reference. + * @return Feedback. + */ +static inline FusionVector Feedback(const FusionVector sensor, const FusionVector reference) +{ + if (FusionVectorDotProduct(sensor, reference) < 0.0f) { // if error is >90 degrees + return FusionVectorNormalise(FusionVectorCrossProduct(sensor, reference)); + } + return FusionVectorCrossProduct(sensor, reference); +} + +/** + * @brief Returns a value limited to maximum and minimum. + * @param value Value. + * @param min Minimum value. + * @param max Maximum value. + * @return Value limited to maximum and minimum. + */ +static inline int Clamp(const int value, const int min, const int max) +{ + if (value < min) { + return min; + } + if (value > max) { + return max; + } + return value; +} + +/** + * @brief Updates the AHRS algorithm using the gyroscope and accelerometer + * measurements only. + * @param ahrs AHRS algorithm structure. + * @param gyroscope Gyroscope measurement in degrees per second. + * @param accelerometer Accelerometer measurement in g. + * @param deltaTime Delta time in seconds. + */ +void FusionAhrsUpdateNoMagnetometer(FusionAhrs *const ahrs, const FusionVector gyroscope, const FusionVector accelerometer, + const float deltaTime) +{ + + // Update AHRS algorithm + FusionAhrsUpdate(ahrs, gyroscope, accelerometer, FUSION_VECTOR_ZERO, deltaTime); + + // Zero heading during initialisation + if (ahrs->initialising) { + FusionAhrsSetHeading(ahrs, 0.0f); + } +} + +/** + * @brief Updates the AHRS algorithm using the gyroscope, accelerometer, and + * heading measurements. + * @param ahrs AHRS algorithm structure. + * @param gyroscope Gyroscope measurement in degrees per second. + * @param accelerometer Accelerometer measurement in g. + * @param heading Heading measurement in degrees. + * @param deltaTime Delta time in seconds. + */ +void FusionAhrsUpdateExternalHeading(FusionAhrs *const ahrs, const FusionVector gyroscope, const FusionVector accelerometer, + const float heading, const float deltaTime) +{ +#define Q ahrs->quaternion.element + + // Calculate roll + const float roll = atan2f(Q.w * Q.x + Q.y * Q.z, 0.5f - Q.y * Q.y - Q.x * Q.x); + + // Calculate magnetometer + const float headingRadians = FusionDegreesToRadians(heading); + const float sinHeadingRadians = sinf(headingRadians); + const FusionVector magnetometer = {.axis = { + .x = cosf(headingRadians), + .y = -1.0f * cosf(roll) * sinHeadingRadians, + .z = sinHeadingRadians * sinf(roll), + }}; + + // Update AHRS algorithm + FusionAhrsUpdate(ahrs, gyroscope, accelerometer, magnetometer, deltaTime); +#undef Q +} + +/** + * @brief Returns the quaternion describing the sensor relative to the Earth. + * @param ahrs AHRS algorithm structure. + * @return Quaternion describing the sensor relative to the Earth. + */ +FusionQuaternion FusionAhrsGetQuaternion(const FusionAhrs *const ahrs) +{ + return ahrs->quaternion; +} + +/** + * @brief Sets the quaternion describing the sensor relative to the Earth. + * @param ahrs AHRS algorithm structure. + * @param quaternion Quaternion describing the sensor relative to the Earth. + */ +void FusionAhrsSetQuaternion(FusionAhrs *const ahrs, const FusionQuaternion quaternion) +{ + ahrs->quaternion = quaternion; +} + +/** + * @brief Returns the linear acceleration measurement equal to the accelerometer + * measurement with the 1 g of gravity removed. + * @param ahrs AHRS algorithm structure. + * @return Linear acceleration measurement in g. + */ +FusionVector FusionAhrsGetLinearAcceleration(const FusionAhrs *const ahrs) +{ +#define Q ahrs->quaternion.element + + // Calculate gravity in the sensor coordinate frame + const FusionVector gravity = {.axis = { + .x = 2.0f * (Q.x * Q.z - Q.w * Q.y), + .y = 2.0f * (Q.y * Q.z + Q.w * Q.x), + .z = 2.0f * (Q.w * Q.w - 0.5f + Q.z * Q.z), + }}; // third column of transposed rotation matrix + + // Remove gravity from accelerometer measurement + switch (ahrs->settings.convention) { + case FusionConventionNwu: + case FusionConventionEnu: { + return FusionVectorSubtract(ahrs->accelerometer, gravity); + } + case FusionConventionNed: { + return FusionVectorAdd(ahrs->accelerometer, gravity); + } + } + return FUSION_VECTOR_ZERO; // avoid compiler warning +#undef Q +} + +/** + * @brief Returns the Earth acceleration measurement equal to accelerometer + * measurement in the Earth coordinate frame with the 1 g of gravity removed. + * @param ahrs AHRS algorithm structure. + * @return Earth acceleration measurement in g. + */ +FusionVector FusionAhrsGetEarthAcceleration(const FusionAhrs *const ahrs) +{ +#define Q ahrs->quaternion.element +#define A ahrs->accelerometer.axis + + // Calculate accelerometer measurement in the Earth coordinate frame + const float qwqw = Q.w * Q.w; // calculate common terms to avoid repeated operations + const float qwqx = Q.w * Q.x; + const float qwqy = Q.w * Q.y; + const float qwqz = Q.w * Q.z; + const float qxqy = Q.x * Q.y; + const float qxqz = Q.x * Q.z; + const float qyqz = Q.y * Q.z; + FusionVector accelerometer = {.axis = { + .x = 2.0f * ((qwqw - 0.5f + Q.x * Q.x) * A.x + (qxqy - qwqz) * A.y + (qxqz + qwqy) * A.z), + .y = 2.0f * ((qxqy + qwqz) * A.x + (qwqw - 0.5f + Q.y * Q.y) * A.y + (qyqz - qwqx) * A.z), + .z = 2.0f * ((qxqz - qwqy) * A.x + (qyqz + qwqx) * A.y + (qwqw - 0.5f + Q.z * Q.z) * A.z), + }}; // rotation matrix multiplied with the accelerometer + + // Remove gravity from accelerometer measurement + switch (ahrs->settings.convention) { + case FusionConventionNwu: + case FusionConventionEnu: + accelerometer.axis.z -= 1.0f; + break; + case FusionConventionNed: + accelerometer.axis.z += 1.0f; + break; + } + return accelerometer; +#undef Q +#undef A +} + +/** + * @brief Returns the AHRS algorithm internal states. + * @param ahrs AHRS algorithm structure. + * @return AHRS algorithm internal states. + */ +FusionAhrsInternalStates FusionAhrsGetInternalStates(const FusionAhrs *const ahrs) +{ + const FusionAhrsInternalStates internalStates = { + .accelerationError = FusionRadiansToDegrees(FusionAsin(2.0f * FusionVectorMagnitude(ahrs->halfAccelerometerFeedback))), + .accelerometerIgnored = ahrs->accelerometerIgnored, + .accelerationRecoveryTrigger = + ahrs->settings.recoveryTriggerPeriod == 0 + ? 0.0f + : (float)ahrs->accelerationRecoveryTrigger / (float)ahrs->settings.recoveryTriggerPeriod, + .magneticError = FusionRadiansToDegrees(FusionAsin(2.0f * FusionVectorMagnitude(ahrs->halfMagnetometerFeedback))), + .magnetometerIgnored = ahrs->magnetometerIgnored, + .magneticRecoveryTrigger = ahrs->settings.recoveryTriggerPeriod == 0 + ? 0.0f + : (float)ahrs->magneticRecoveryTrigger / (float)ahrs->settings.recoveryTriggerPeriod, + }; + return internalStates; +} + +/** + * @brief Returns the AHRS algorithm flags. + * @param ahrs AHRS algorithm structure. + * @return AHRS algorithm flags. + */ +FusionAhrsFlags FusionAhrsGetFlags(const FusionAhrs *const ahrs) +{ + const FusionAhrsFlags flags = { + .initialising = ahrs->initialising, + .angularRateRecovery = ahrs->angularRateRecovery, + .accelerationRecovery = ahrs->accelerationRecoveryTrigger > ahrs->accelerationRecoveryTimeout, + .magneticRecovery = ahrs->magneticRecoveryTrigger > ahrs->magneticRecoveryTimeout, + }; + return flags; +} + +/** + * @brief Sets the heading of the orientation measurement provided by the AHRS + * algorithm. This function can be used to reset drift in heading when the AHRS + * algorithm is being used without a magnetometer. + * @param ahrs AHRS algorithm structure. + * @param heading Heading angle in degrees. + */ +void FusionAhrsSetHeading(FusionAhrs *const ahrs, const float heading) +{ +#define Q ahrs->quaternion.element + const float yaw = atan2f(Q.w * Q.z + Q.x * Q.y, 0.5f - Q.y * Q.y - Q.z * Q.z); + const float halfYawMinusHeading = 0.5f * (yaw - FusionDegreesToRadians(heading)); + const FusionQuaternion rotation = {.element = { + .w = cosf(halfYawMinusHeading), + .x = 0.0f, + .y = 0.0f, + .z = -1.0f * sinf(halfYawMinusHeading), + }}; + ahrs->quaternion = FusionQuaternionMultiply(rotation, ahrs->quaternion); +#undef Q +} + +//------------------------------------------------------------------------------ +// End of file diff --git a/src/Fusion/FusionAhrs.h b/src/Fusion/FusionAhrs.h new file mode 100644 index 0000000000..aa2326e431 --- /dev/null +++ b/src/Fusion/FusionAhrs.h @@ -0,0 +1,112 @@ +/** + * @file FusionAhrs.h + * @author Seb Madgwick + * @brief AHRS algorithm to combine gyroscope, accelerometer, and magnetometer + * measurements into a single measurement of orientation relative to the Earth. + */ + +#ifndef FUSION_AHRS_H +#define FUSION_AHRS_H + +//------------------------------------------------------------------------------ +// Includes + +#include "FusionConvention.h" +#include "FusionMath.h" +#include + +//------------------------------------------------------------------------------ +// Definitions + +/** + * @brief AHRS algorithm settings. + */ +typedef struct { + FusionConvention convention; + float gain; + float gyroscopeRange; + float accelerationRejection; + float magneticRejection; + unsigned int recoveryTriggerPeriod; +} FusionAhrsSettings; + +/** + * @brief AHRS algorithm structure. Structure members are used internally and + * must not be accessed by the application. + */ +typedef struct { + FusionAhrsSettings settings; + FusionQuaternion quaternion; + FusionVector accelerometer; + bool initialising; + float rampedGain; + float rampedGainStep; + bool angularRateRecovery; + FusionVector halfAccelerometerFeedback; + FusionVector halfMagnetometerFeedback; + bool accelerometerIgnored; + int accelerationRecoveryTrigger; + int accelerationRecoveryTimeout; + bool magnetometerIgnored; + int magneticRecoveryTrigger; + int magneticRecoveryTimeout; +} FusionAhrs; + +/** + * @brief AHRS algorithm internal states. + */ +typedef struct { + float accelerationError; + bool accelerometerIgnored; + float accelerationRecoveryTrigger; + float magneticError; + bool magnetometerIgnored; + float magneticRecoveryTrigger; +} FusionAhrsInternalStates; + +/** + * @brief AHRS algorithm flags. + */ +typedef struct { + bool initialising; + bool angularRateRecovery; + bool accelerationRecovery; + bool magneticRecovery; +} FusionAhrsFlags; + +//------------------------------------------------------------------------------ +// Function declarations + +void FusionAhrsInitialise(FusionAhrs *const ahrs); + +void FusionAhrsReset(FusionAhrs *const ahrs); + +void FusionAhrsSetSettings(FusionAhrs *const ahrs, const FusionAhrsSettings *const settings); + +void FusionAhrsUpdate(FusionAhrs *const ahrs, const FusionVector gyroscope, const FusionVector accelerometer, + const FusionVector magnetometer, const float deltaTime); + +void FusionAhrsUpdateNoMagnetometer(FusionAhrs *const ahrs, const FusionVector gyroscope, const FusionVector accelerometer, + const float deltaTime); + +void FusionAhrsUpdateExternalHeading(FusionAhrs *const ahrs, const FusionVector gyroscope, const FusionVector accelerometer, + const float heading, const float deltaTime); + +FusionQuaternion FusionAhrsGetQuaternion(const FusionAhrs *const ahrs); + +void FusionAhrsSetQuaternion(FusionAhrs *const ahrs, const FusionQuaternion quaternion); + +FusionVector FusionAhrsGetLinearAcceleration(const FusionAhrs *const ahrs); + +FusionVector FusionAhrsGetEarthAcceleration(const FusionAhrs *const ahrs); + +FusionAhrsInternalStates FusionAhrsGetInternalStates(const FusionAhrs *const ahrs); + +FusionAhrsFlags FusionAhrsGetFlags(const FusionAhrs *const ahrs); + +void FusionAhrsSetHeading(FusionAhrs *const ahrs, const float heading); + +#endif + +//------------------------------------------------------------------------------ +// End of file diff --git a/src/Fusion/FusionAxes.h b/src/Fusion/FusionAxes.h new file mode 100644 index 0000000000..9673c88ff2 --- /dev/null +++ b/src/Fusion/FusionAxes.h @@ -0,0 +1,188 @@ +/** + * @file FusionAxes.h + * @author Seb Madgwick + * @brief Swaps sensor axes for alignment with the body axes. + */ + +#ifndef FUSION_AXES_H +#define FUSION_AXES_H + +//------------------------------------------------------------------------------ +// Includes + +#include "FusionMath.h" + +//------------------------------------------------------------------------------ +// Definitions + +/** + * @brief Axes alignment describing the sensor axes relative to the body axes. + * For example, if the body X axis is aligned with the sensor Y axis and the + * body Y axis is aligned with sensor X axis but pointing the opposite direction + * then alignment is +Y-X+Z. + */ +typedef enum { + FusionAxesAlignmentPXPYPZ, /* +X+Y+Z */ + FusionAxesAlignmentPXNZPY, /* +X-Z+Y */ + FusionAxesAlignmentPXNYNZ, /* +X-Y-Z */ + FusionAxesAlignmentPXPZNY, /* +X+Z-Y */ + FusionAxesAlignmentNXPYNZ, /* -X+Y-Z */ + FusionAxesAlignmentNXPZPY, /* -X+Z+Y */ + FusionAxesAlignmentNXNYPZ, /* -X-Y+Z */ + FusionAxesAlignmentNXNZNY, /* -X-Z-Y */ + FusionAxesAlignmentPYNXPZ, /* +Y-X+Z */ + FusionAxesAlignmentPYNZNX, /* +Y-Z-X */ + FusionAxesAlignmentPYPXNZ, /* +Y+X-Z */ + FusionAxesAlignmentPYPZPX, /* +Y+Z+X */ + FusionAxesAlignmentNYPXPZ, /* -Y+X+Z */ + FusionAxesAlignmentNYNZPX, /* -Y-Z+X */ + FusionAxesAlignmentNYNXNZ, /* -Y-X-Z */ + FusionAxesAlignmentNYPZNX, /* -Y+Z-X */ + FusionAxesAlignmentPZPYNX, /* +Z+Y-X */ + FusionAxesAlignmentPZPXPY, /* +Z+X+Y */ + FusionAxesAlignmentPZNYPX, /* +Z-Y+X */ + FusionAxesAlignmentPZNXNY, /* +Z-X-Y */ + FusionAxesAlignmentNZPYPX, /* -Z+Y+X */ + FusionAxesAlignmentNZNXPY, /* -Z-X+Y */ + FusionAxesAlignmentNZNYNX, /* -Z-Y-X */ + FusionAxesAlignmentNZPXNY, /* -Z+X-Y */ +} FusionAxesAlignment; + +//------------------------------------------------------------------------------ +// Inline functions + +/** + * @brief Swaps sensor axes for alignment with the body axes. + * @param sensor Sensor axes. + * @param alignment Axes alignment. + * @return Sensor axes aligned with the body axes. + */ +static inline FusionVector FusionAxesSwap(const FusionVector sensor, const FusionAxesAlignment alignment) +{ + FusionVector result; + switch (alignment) { + case FusionAxesAlignmentPXPYPZ: + break; + case FusionAxesAlignmentPXNZPY: + result.axis.x = +sensor.axis.x; + result.axis.y = -sensor.axis.z; + result.axis.z = +sensor.axis.y; + return result; + case FusionAxesAlignmentPXNYNZ: + result.axis.x = +sensor.axis.x; + result.axis.y = -sensor.axis.y; + result.axis.z = -sensor.axis.z; + return result; + case FusionAxesAlignmentPXPZNY: + result.axis.x = +sensor.axis.x; + result.axis.y = +sensor.axis.z; + result.axis.z = -sensor.axis.y; + return result; + case FusionAxesAlignmentNXPYNZ: + result.axis.x = -sensor.axis.x; + result.axis.y = +sensor.axis.y; + result.axis.z = -sensor.axis.z; + return result; + case FusionAxesAlignmentNXPZPY: + result.axis.x = -sensor.axis.x; + result.axis.y = +sensor.axis.z; + result.axis.z = +sensor.axis.y; + return result; + case FusionAxesAlignmentNXNYPZ: + result.axis.x = -sensor.axis.x; + result.axis.y = -sensor.axis.y; + result.axis.z = +sensor.axis.z; + return result; + case FusionAxesAlignmentNXNZNY: + result.axis.x = -sensor.axis.x; + result.axis.y = -sensor.axis.z; + result.axis.z = -sensor.axis.y; + return result; + case FusionAxesAlignmentPYNXPZ: + result.axis.x = +sensor.axis.y; + result.axis.y = -sensor.axis.x; + result.axis.z = +sensor.axis.z; + return result; + case FusionAxesAlignmentPYNZNX: + result.axis.x = +sensor.axis.y; + result.axis.y = -sensor.axis.z; + result.axis.z = -sensor.axis.x; + return result; + case FusionAxesAlignmentPYPXNZ: + result.axis.x = +sensor.axis.y; + result.axis.y = +sensor.axis.x; + result.axis.z = -sensor.axis.z; + return result; + case FusionAxesAlignmentPYPZPX: + result.axis.x = +sensor.axis.y; + result.axis.y = +sensor.axis.z; + result.axis.z = +sensor.axis.x; + return result; + case FusionAxesAlignmentNYPXPZ: + result.axis.x = -sensor.axis.y; + result.axis.y = +sensor.axis.x; + result.axis.z = +sensor.axis.z; + return result; + case FusionAxesAlignmentNYNZPX: + result.axis.x = -sensor.axis.y; + result.axis.y = -sensor.axis.z; + result.axis.z = +sensor.axis.x; + return result; + case FusionAxesAlignmentNYNXNZ: + result.axis.x = -sensor.axis.y; + result.axis.y = -sensor.axis.x; + result.axis.z = -sensor.axis.z; + return result; + case FusionAxesAlignmentNYPZNX: + result.axis.x = -sensor.axis.y; + result.axis.y = +sensor.axis.z; + result.axis.z = -sensor.axis.x; + return result; + case FusionAxesAlignmentPZPYNX: + result.axis.x = +sensor.axis.z; + result.axis.y = +sensor.axis.y; + result.axis.z = -sensor.axis.x; + return result; + case FusionAxesAlignmentPZPXPY: + result.axis.x = +sensor.axis.z; + result.axis.y = +sensor.axis.x; + result.axis.z = +sensor.axis.y; + return result; + case FusionAxesAlignmentPZNYPX: + result.axis.x = +sensor.axis.z; + result.axis.y = -sensor.axis.y; + result.axis.z = +sensor.axis.x; + return result; + case FusionAxesAlignmentPZNXNY: + result.axis.x = +sensor.axis.z; + result.axis.y = -sensor.axis.x; + result.axis.z = -sensor.axis.y; + return result; + case FusionAxesAlignmentNZPYPX: + result.axis.x = -sensor.axis.z; + result.axis.y = +sensor.axis.y; + result.axis.z = +sensor.axis.x; + return result; + case FusionAxesAlignmentNZNXPY: + result.axis.x = -sensor.axis.z; + result.axis.y = -sensor.axis.x; + result.axis.z = +sensor.axis.y; + return result; + case FusionAxesAlignmentNZNYNX: + result.axis.x = -sensor.axis.z; + result.axis.y = -sensor.axis.y; + result.axis.z = -sensor.axis.x; + return result; + case FusionAxesAlignmentNZPXNY: + result.axis.x = -sensor.axis.z; + result.axis.y = +sensor.axis.x; + result.axis.z = -sensor.axis.y; + return result; + } + return sensor; // avoid compiler warning +} + +#endif + +//------------------------------------------------------------------------------ +// End of file diff --git a/src/Fusion/FusionCalibration.h b/src/Fusion/FusionCalibration.h new file mode 100644 index 0000000000..be7102b73e --- /dev/null +++ b/src/Fusion/FusionCalibration.h @@ -0,0 +1,49 @@ +/** + * @file FusionCalibration.h + * @author Seb Madgwick + * @brief Gyroscope, accelerometer, and magnetometer calibration models. + */ + +#ifndef FUSION_CALIBRATION_H +#define FUSION_CALIBRATION_H + +//------------------------------------------------------------------------------ +// Includes + +#include "FusionMath.h" + +//------------------------------------------------------------------------------ +// Inline functions + +/** + * @brief Gyroscope and accelerometer calibration model. + * @param uncalibrated Uncalibrated measurement. + * @param misalignment Misalignment matrix. + * @param sensitivity Sensitivity. + * @param offset Offset. + * @return Calibrated measurement. + */ +static inline FusionVector FusionCalibrationInertial(const FusionVector uncalibrated, const FusionMatrix misalignment, + const FusionVector sensitivity, const FusionVector offset) +{ + return FusionMatrixMultiplyVector(misalignment, + FusionVectorHadamardProduct(FusionVectorSubtract(uncalibrated, offset), sensitivity)); +} + +/** + * @brief Magnetometer calibration model. + * @param uncalibrated Uncalibrated measurement. + * @param softIronMatrix Soft-iron matrix. + * @param hardIronOffset Hard-iron offset. + * @return Calibrated measurement. + */ +static inline FusionVector FusionCalibrationMagnetic(const FusionVector uncalibrated, const FusionMatrix softIronMatrix, + const FusionVector hardIronOffset) +{ + return FusionMatrixMultiplyVector(softIronMatrix, FusionVectorSubtract(uncalibrated, hardIronOffset)); +} + +#endif + +//------------------------------------------------------------------------------ +// End of file diff --git a/src/Fusion/FusionCompass.c b/src/Fusion/FusionCompass.c new file mode 100644 index 0000000000..6a6f9591a6 --- /dev/null +++ b/src/Fusion/FusionCompass.c @@ -0,0 +1,51 @@ +/** + * @file FusionCompass.c + * @author Seb Madgwick + * @brief Tilt-compensated compass to calculate the magnetic heading using + * accelerometer and magnetometer measurements. + */ + +//------------------------------------------------------------------------------ +// Includes + +#include "FusionCompass.h" +#include "FusionAxes.h" +#include // atan2f + +//------------------------------------------------------------------------------ +// Functions + +/** + * @brief Calculates the magnetic heading. + * @param convention Earth axes convention. + * @param accelerometer Accelerometer measurement in any calibrated units. + * @param magnetometer Magnetometer measurement in any calibrated units. + * @return Heading angle in degrees. + */ +float FusionCompassCalculateHeading(const FusionConvention convention, const FusionVector accelerometer, + const FusionVector magnetometer) +{ + switch (convention) { + case FusionConventionNwu: { + const FusionVector west = FusionVectorNormalise(FusionVectorCrossProduct(accelerometer, magnetometer)); + const FusionVector north = FusionVectorNormalise(FusionVectorCrossProduct(west, accelerometer)); + return FusionRadiansToDegrees(atan2f(west.axis.x, north.axis.x)); + } + case FusionConventionEnu: { + const FusionVector west = FusionVectorNormalise(FusionVectorCrossProduct(accelerometer, magnetometer)); + const FusionVector north = FusionVectorNormalise(FusionVectorCrossProduct(west, accelerometer)); + const FusionVector east = FusionVectorMultiplyScalar(west, -1.0f); + return FusionRadiansToDegrees(atan2f(north.axis.x, east.axis.x)); + } + case FusionConventionNed: { + const FusionVector up = FusionVectorMultiplyScalar(accelerometer, -1.0f); + const FusionVector west = FusionVectorNormalise(FusionVectorCrossProduct(up, magnetometer)); + const FusionVector north = FusionVectorNormalise(FusionVectorCrossProduct(west, up)); + return FusionRadiansToDegrees(atan2f(west.axis.x, north.axis.x)); + } + } + return 0; // avoid compiler warning +} + +//------------------------------------------------------------------------------ +// End of file diff --git a/src/Fusion/FusionCompass.h b/src/Fusion/FusionCompass.h new file mode 100644 index 0000000000..a3d0b466aa --- /dev/null +++ b/src/Fusion/FusionCompass.h @@ -0,0 +1,26 @@ +/** + * @file FusionCompass.h + * @author Seb Madgwick + * @brief Tilt-compensated compass to calculate the magnetic heading using + * accelerometer and magnetometer measurements. + */ + +#ifndef FUSION_COMPASS_H +#define FUSION_COMPASS_H + +//------------------------------------------------------------------------------ +// Includes + +#include "FusionConvention.h" +#include "FusionMath.h" + +//------------------------------------------------------------------------------ +// Function declarations + +float FusionCompassCalculateHeading(const FusionConvention convention, const FusionVector accelerometer, + const FusionVector magnetometer); + +#endif + +//------------------------------------------------------------------------------ +// End of file diff --git a/src/Fusion/FusionConvention.h b/src/Fusion/FusionConvention.h new file mode 100644 index 0000000000..0b0d43adc6 --- /dev/null +++ b/src/Fusion/FusionConvention.h @@ -0,0 +1,25 @@ +/** + * @file FusionConvention.h + * @author Seb Madgwick + * @brief Earth axes convention. + */ + +#ifndef FUSION_CONVENTION_H +#define FUSION_CONVENTION_H + +//------------------------------------------------------------------------------ +// Definitions + +/** + * @brief Earth axes convention. + */ +typedef enum { + FusionConventionNwu, /* North-West-Up */ + FusionConventionEnu, /* East-North-Up */ + FusionConventionNed, /* North-East-Down */ +} FusionConvention; + +#endif + +//------------------------------------------------------------------------------ +// End of file diff --git a/src/Fusion/FusionMath.h b/src/Fusion/FusionMath.h new file mode 100644 index 0000000000..c3fc34b2d5 --- /dev/null +++ b/src/Fusion/FusionMath.h @@ -0,0 +1,503 @@ +/** + * @file FusionMath.h + * @author Seb Madgwick + * @brief Math library. + */ + +#ifndef FUSION_MATH_H +#define FUSION_MATH_H + +//------------------------------------------------------------------------------ +// Includes + +#include // M_PI, sqrtf, atan2f, asinf +#include +#include + +//------------------------------------------------------------------------------ +// Definitions + +/** + * @brief 3D vector. + */ +typedef union { + float array[3]; + + struct { + float x; + float y; + float z; + } axis; +} FusionVector; + +/** + * @brief Quaternion. + */ +typedef union { + float array[4]; + + struct { + float w; + float x; + float y; + float z; + } element; +} FusionQuaternion; + +/** + * @brief 3x3 matrix in row-major order. + * See http://en.wikipedia.org/wiki/Row-major_order + */ +typedef union { + float array[3][3]; + + struct { + float xx; + float xy; + float xz; + float yx; + float yy; + float yz; + float zx; + float zy; + float zz; + } element; +} FusionMatrix; + +/** + * @brief Euler angles. Roll, pitch, and yaw correspond to rotations around + * X, Y, and Z respectively. + */ +typedef union { + float array[3]; + + struct { + float roll; + float pitch; + float yaw; + } angle; +} FusionEuler; + +/** + * @brief Vector of zeros. + */ +#define FUSION_VECTOR_ZERO ((FusionVector){.array = {0.0f, 0.0f, 0.0f}}) + +/** + * @brief Vector of ones. + */ +#define FUSION_VECTOR_ONES ((FusionVector){.array = {1.0f, 1.0f, 1.0f}}) + +/** + * @brief Identity quaternion. + */ +#define FUSION_IDENTITY_QUATERNION ((FusionQuaternion){.array = {1.0f, 0.0f, 0.0f, 0.0f}}) + +/** + * @brief Identity matrix. + */ +#define FUSION_IDENTITY_MATRIX ((FusionMatrix){.array = {{1.0f, 0.0f, 0.0f}, {0.0f, 1.0f, 0.0f}, {0.0f, 0.0f, 1.0f}}}) + +/** + * @brief Euler angles of zero. + */ +#define FUSION_EULER_ZERO ((FusionEuler){.array = {0.0f, 0.0f, 0.0f}}) + +/** + * @brief Pi. May not be defined in math.h. + */ +#ifndef M_PI +#define M_PI (3.14159265358979323846) +#endif + +/** + * @brief Include this definition or add as a preprocessor definition to use + * normal square root operations. + */ +// #define FUSION_USE_NORMAL_SQRT + +//------------------------------------------------------------------------------ +// Inline functions - Degrees and radians conversion + +/** + * @brief Converts degrees to radians. + * @param degrees Degrees. + * @return Radians. + */ +static inline float FusionDegreesToRadians(const float degrees) +{ + return degrees * ((float)M_PI / 180.0f); +} + +/** + * @brief Converts radians to degrees. + * @param radians Radians. + * @return Degrees. + */ +static inline float FusionRadiansToDegrees(const float radians) +{ + return radians * (180.0f / (float)M_PI); +} + +//------------------------------------------------------------------------------ +// Inline functions - Arc sine + +/** + * @brief Returns the arc sine of the value. + * @param value Value. + * @return Arc sine of the value. + */ +static inline float FusionAsin(const float value) +{ + if (value <= -1.0f) { + return (float)M_PI / -2.0f; + } + if (value >= 1.0f) { + return (float)M_PI / 2.0f; + } + return asinf(value); +} + +//------------------------------------------------------------------------------ +// Inline functions - Fast inverse square root + +#ifndef FUSION_USE_NORMAL_SQRT + +/** + * @brief Calculates the reciprocal of the square root. + * See https://pizer.wordpress.com/2008/10/12/fast-inverse-square-root/ + * @param x Operand. + * @return Reciprocal of the square root of x. + */ +static inline float FusionFastInverseSqrt(const float x) +{ + + typedef union { + float f; + int32_t i; + } Union32; + + Union32 union32 = {.f = x}; + union32.i = 0x5F1F1412 - (union32.i >> 1); + return union32.f * (1.69000231f - 0.714158168f * x * union32.f * union32.f); +} + +#endif + +//------------------------------------------------------------------------------ +// Inline functions - Vector operations + +/** + * @brief Returns true if the vector is zero. + * @param vector Vector. + * @return True if the vector is zero. + */ +static inline bool FusionVectorIsZero(const FusionVector vector) +{ + return (vector.axis.x == 0.0f) && (vector.axis.y == 0.0f) && (vector.axis.z == 0.0f); +} + +/** + * @brief Returns the sum of two vectors. + * @param vectorA Vector A. + * @param vectorB Vector B. + * @return Sum of two vectors. + */ +static inline FusionVector FusionVectorAdd(const FusionVector vectorA, const FusionVector vectorB) +{ + const FusionVector result = {.axis = { + .x = vectorA.axis.x + vectorB.axis.x, + .y = vectorA.axis.y + vectorB.axis.y, + .z = vectorA.axis.z + vectorB.axis.z, + }}; + return result; +} + +/** + * @brief Returns vector B subtracted from vector A. + * @param vectorA Vector A. + * @param vectorB Vector B. + * @return Vector B subtracted from vector A. + */ +static inline FusionVector FusionVectorSubtract(const FusionVector vectorA, const FusionVector vectorB) +{ + const FusionVector result = {.axis = { + .x = vectorA.axis.x - vectorB.axis.x, + .y = vectorA.axis.y - vectorB.axis.y, + .z = vectorA.axis.z - vectorB.axis.z, + }}; + return result; +} + +/** + * @brief Returns the sum of the elements. + * @param vector Vector. + * @return Sum of the elements. + */ +static inline float FusionVectorSum(const FusionVector vector) +{ + return vector.axis.x + vector.axis.y + vector.axis.z; +} + +/** + * @brief Returns the multiplication of a vector by a scalar. + * @param vector Vector. + * @param scalar Scalar. + * @return Multiplication of a vector by a scalar. + */ +static inline FusionVector FusionVectorMultiplyScalar(const FusionVector vector, const float scalar) +{ + const FusionVector result = {.axis = { + .x = vector.axis.x * scalar, + .y = vector.axis.y * scalar, + .z = vector.axis.z * scalar, + }}; + return result; +} + +/** + * @brief Calculates the Hadamard product (element-wise multiplication). + * @param vectorA Vector A. + * @param vectorB Vector B. + * @return Hadamard product. + */ +static inline FusionVector FusionVectorHadamardProduct(const FusionVector vectorA, const FusionVector vectorB) +{ + const FusionVector result = {.axis = { + .x = vectorA.axis.x * vectorB.axis.x, + .y = vectorA.axis.y * vectorB.axis.y, + .z = vectorA.axis.z * vectorB.axis.z, + }}; + return result; +} + +/** + * @brief Returns the cross product. + * @param vectorA Vector A. + * @param vectorB Vector B. + * @return Cross product. + */ +static inline FusionVector FusionVectorCrossProduct(const FusionVector vectorA, const FusionVector vectorB) +{ +#define A vectorA.axis +#define B vectorB.axis + const FusionVector result = {.axis = { + .x = A.y * B.z - A.z * B.y, + .y = A.z * B.x - A.x * B.z, + .z = A.x * B.y - A.y * B.x, + }}; + return result; +#undef A +#undef B +} + +/** + * @brief Returns the dot product. + * @param vectorA Vector A. + * @param vectorB Vector B. + * @return Dot product. + */ +static inline float FusionVectorDotProduct(const FusionVector vectorA, const FusionVector vectorB) +{ + return FusionVectorSum(FusionVectorHadamardProduct(vectorA, vectorB)); +} + +/** + * @brief Returns the vector magnitude squared. + * @param vector Vector. + * @return Vector magnitude squared. + */ +static inline float FusionVectorMagnitudeSquared(const FusionVector vector) +{ + return FusionVectorSum(FusionVectorHadamardProduct(vector, vector)); +} + +/** + * @brief Returns the vector magnitude. + * @param vector Vector. + * @return Vector magnitude. + */ +static inline float FusionVectorMagnitude(const FusionVector vector) +{ + return sqrtf(FusionVectorMagnitudeSquared(vector)); +} + +/** + * @brief Returns the normalised vector. + * @param vector Vector. + * @return Normalised vector. + */ +static inline FusionVector FusionVectorNormalise(const FusionVector vector) +{ +#ifdef FUSION_USE_NORMAL_SQRT + const float magnitudeReciprocal = 1.0f / sqrtf(FusionVectorMagnitudeSquared(vector)); +#else + const float magnitudeReciprocal = FusionFastInverseSqrt(FusionVectorMagnitudeSquared(vector)); +#endif + return FusionVectorMultiplyScalar(vector, magnitudeReciprocal); +} + +//------------------------------------------------------------------------------ +// Inline functions - Quaternion operations + +/** + * @brief Returns the sum of two quaternions. + * @param quaternionA Quaternion A. + * @param quaternionB Quaternion B. + * @return Sum of two quaternions. + */ +static inline FusionQuaternion FusionQuaternionAdd(const FusionQuaternion quaternionA, const FusionQuaternion quaternionB) +{ + const FusionQuaternion result = {.element = { + .w = quaternionA.element.w + quaternionB.element.w, + .x = quaternionA.element.x + quaternionB.element.x, + .y = quaternionA.element.y + quaternionB.element.y, + .z = quaternionA.element.z + quaternionB.element.z, + }}; + return result; +} + +/** + * @brief Returns the multiplication of two quaternions. + * @param quaternionA Quaternion A (to be post-multiplied). + * @param quaternionB Quaternion B (to be pre-multiplied). + * @return Multiplication of two quaternions. + */ +static inline FusionQuaternion FusionQuaternionMultiply(const FusionQuaternion quaternionA, const FusionQuaternion quaternionB) +{ +#define A quaternionA.element +#define B quaternionB.element + const FusionQuaternion result = {.element = { + .w = A.w * B.w - A.x * B.x - A.y * B.y - A.z * B.z, + .x = A.w * B.x + A.x * B.w + A.y * B.z - A.z * B.y, + .y = A.w * B.y - A.x * B.z + A.y * B.w + A.z * B.x, + .z = A.w * B.z + A.x * B.y - A.y * B.x + A.z * B.w, + }}; + return result; +#undef A +#undef B +} + +/** + * @brief Returns the multiplication of a quaternion with a vector. This is a + * normal quaternion multiplication where the vector is treated a + * quaternion with a W element value of zero. The quaternion is post- + * multiplied by the vector. + * @param quaternion Quaternion. + * @param vector Vector. + * @return Multiplication of a quaternion with a vector. + */ +static inline FusionQuaternion FusionQuaternionMultiplyVector(const FusionQuaternion quaternion, const FusionVector vector) +{ +#define Q quaternion.element +#define V vector.axis + const FusionQuaternion result = {.element = { + .w = -Q.x * V.x - Q.y * V.y - Q.z * V.z, + .x = Q.w * V.x + Q.y * V.z - Q.z * V.y, + .y = Q.w * V.y - Q.x * V.z + Q.z * V.x, + .z = Q.w * V.z + Q.x * V.y - Q.y * V.x, + }}; + return result; +#undef Q +#undef V +} + +/** + * @brief Returns the normalised quaternion. + * @param quaternion Quaternion. + * @return Normalised quaternion. + */ +static inline FusionQuaternion FusionQuaternionNormalise(const FusionQuaternion quaternion) +{ +#define Q quaternion.element +#ifdef FUSION_USE_NORMAL_SQRT + const float magnitudeReciprocal = 1.0f / sqrtf(Q.w * Q.w + Q.x * Q.x + Q.y * Q.y + Q.z * Q.z); +#else + const float magnitudeReciprocal = FusionFastInverseSqrt(Q.w * Q.w + Q.x * Q.x + Q.y * Q.y + Q.z * Q.z); +#endif + const FusionQuaternion result = {.element = { + .w = Q.w * magnitudeReciprocal, + .x = Q.x * magnitudeReciprocal, + .y = Q.y * magnitudeReciprocal, + .z = Q.z * magnitudeReciprocal, + }}; + return result; +#undef Q +} + +//------------------------------------------------------------------------------ +// Inline functions - Matrix operations + +/** + * @brief Returns the multiplication of a matrix with a vector. + * @param matrix Matrix. + * @param vector Vector. + * @return Multiplication of a matrix with a vector. + */ +static inline FusionVector FusionMatrixMultiplyVector(const FusionMatrix matrix, const FusionVector vector) +{ +#define R matrix.element + const FusionVector result = {.axis = { + .x = R.xx * vector.axis.x + R.xy * vector.axis.y + R.xz * vector.axis.z, + .y = R.yx * vector.axis.x + R.yy * vector.axis.y + R.yz * vector.axis.z, + .z = R.zx * vector.axis.x + R.zy * vector.axis.y + R.zz * vector.axis.z, + }}; + return result; +#undef R +} + +//------------------------------------------------------------------------------ +// Inline functions - Conversion operations + +/** + * @brief Converts a quaternion to a rotation matrix. + * @param quaternion Quaternion. + * @return Rotation matrix. + */ +static inline FusionMatrix FusionQuaternionToMatrix(const FusionQuaternion quaternion) +{ +#define Q quaternion.element + const float qwqw = Q.w * Q.w; // calculate common terms to avoid repeated operations + const float qwqx = Q.w * Q.x; + const float qwqy = Q.w * Q.y; + const float qwqz = Q.w * Q.z; + const float qxqy = Q.x * Q.y; + const float qxqz = Q.x * Q.z; + const float qyqz = Q.y * Q.z; + const FusionMatrix matrix = {.element = { + .xx = 2.0f * (qwqw - 0.5f + Q.x * Q.x), + .xy = 2.0f * (qxqy - qwqz), + .xz = 2.0f * (qxqz + qwqy), + .yx = 2.0f * (qxqy + qwqz), + .yy = 2.0f * (qwqw - 0.5f + Q.y * Q.y), + .yz = 2.0f * (qyqz - qwqx), + .zx = 2.0f * (qxqz - qwqy), + .zy = 2.0f * (qyqz + qwqx), + .zz = 2.0f * (qwqw - 0.5f + Q.z * Q.z), + }}; + return matrix; +#undef Q +} + +/** + * @brief Converts a quaternion to ZYX Euler angles in degrees. + * @param quaternion Quaternion. + * @return Euler angles in degrees. + */ +static inline FusionEuler FusionQuaternionToEuler(const FusionQuaternion quaternion) +{ +#define Q quaternion.element + const float halfMinusQySquared = 0.5f - Q.y * Q.y; // calculate common terms to avoid repeated operations + const FusionEuler euler = {.angle = { + .roll = FusionRadiansToDegrees(atan2f(Q.w * Q.x + Q.y * Q.z, halfMinusQySquared - Q.x * Q.x)), + .pitch = FusionRadiansToDegrees(FusionAsin(2.0f * (Q.w * Q.y - Q.z * Q.x))), + .yaw = FusionRadiansToDegrees(atan2f(Q.w * Q.z + Q.x * Q.y, halfMinusQySquared - Q.z * Q.z)), + }}; + return euler; +#undef Q +} + +#endif + +//------------------------------------------------------------------------------ +// End of file diff --git a/src/Fusion/FusionOffset.c b/src/Fusion/FusionOffset.c new file mode 100644 index 0000000000..d4334c874f --- /dev/null +++ b/src/Fusion/FusionOffset.c @@ -0,0 +1,80 @@ +/** + * @file FusionOffset.c + * @author Seb Madgwick + * @brief Gyroscope offset correction algorithm for run-time calibration of the + * gyroscope offset. + */ + +//------------------------------------------------------------------------------ +// Includes + +#include "FusionOffset.h" +#include // fabsf + +//------------------------------------------------------------------------------ +// Definitions + +/** + * @brief Cutoff frequency in Hz. + */ +#define CUTOFF_FREQUENCY (0.02f) + +/** + * @brief Timeout in seconds. + */ +#define TIMEOUT (5) + +/** + * @brief Threshold in degrees per second. + */ +#define THRESHOLD (3.0f) + +//------------------------------------------------------------------------------ +// Functions + +/** + * @brief Initialises the gyroscope offset algorithm. + * @param offset Gyroscope offset algorithm structure. + * @param sampleRate Sample rate in Hz. + */ +void FusionOffsetInitialise(FusionOffset *const offset, const unsigned int sampleRate) +{ + offset->filterCoefficient = 2.0f * (float)M_PI * CUTOFF_FREQUENCY * (1.0f / (float)sampleRate); + offset->timeout = TIMEOUT * sampleRate; + offset->timer = 0; + offset->gyroscopeOffset = FUSION_VECTOR_ZERO; +} + +/** + * @brief Updates the gyroscope offset algorithm and returns the corrected + * gyroscope measurement. + * @param offset Gyroscope offset algorithm structure. + * @param gyroscope Gyroscope measurement in degrees per second. + * @return Corrected gyroscope measurement in degrees per second. + */ +FusionVector FusionOffsetUpdate(FusionOffset *const offset, FusionVector gyroscope) +{ + + // Subtract offset from gyroscope measurement + gyroscope = FusionVectorSubtract(gyroscope, offset->gyroscopeOffset); + + // Reset timer if gyroscope not stationary + if ((fabsf(gyroscope.axis.x) > THRESHOLD) || (fabsf(gyroscope.axis.y) > THRESHOLD) || (fabsf(gyroscope.axis.z) > THRESHOLD)) { + offset->timer = 0; + return gyroscope; + } + + // Increment timer while gyroscope stationary + if (offset->timer < offset->timeout) { + offset->timer++; + return gyroscope; + } + + // Adjust offset if timer has elapsed + offset->gyroscopeOffset = + FusionVectorAdd(offset->gyroscopeOffset, FusionVectorMultiplyScalar(gyroscope, offset->filterCoefficient)); + return gyroscope; +} + +//------------------------------------------------------------------------------ +// End of file diff --git a/src/Fusion/FusionOffset.h b/src/Fusion/FusionOffset.h new file mode 100644 index 0000000000..51ae4a8967 --- /dev/null +++ b/src/Fusion/FusionOffset.h @@ -0,0 +1,40 @@ +/** + * @file FusionOffset.h + * @author Seb Madgwick + * @brief Gyroscope offset correction algorithm for run-time calibration of the + * gyroscope offset. + */ + +#ifndef FUSION_OFFSET_H +#define FUSION_OFFSET_H + +//------------------------------------------------------------------------------ +// Includes + +#include "FusionMath.h" + +//------------------------------------------------------------------------------ +// Definitions + +/** + * @brief Gyroscope offset algorithm structure. Structure members are used + * internally and must not be accessed by the application. + */ +typedef struct { + float filterCoefficient; + unsigned int timeout; + unsigned int timer; + FusionVector gyroscopeOffset; +} FusionOffset; + +//------------------------------------------------------------------------------ +// Function declarations + +void FusionOffsetInitialise(FusionOffset *const offset, const unsigned int sampleRate); + +FusionVector FusionOffsetUpdate(FusionOffset *const offset, FusionVector gyroscope); + +#endif + +//------------------------------------------------------------------------------ +// End of file diff --git a/src/configuration.h b/src/configuration.h index 462210cf2b..62c48a205f 100644 --- a/src/configuration.h +++ b/src/configuration.h @@ -144,6 +144,7 @@ along with this program. If not, see . #define LIS3DH_ADR 0x18 #define BMA423_ADDR 0x19 #define LSM6DS3_ADDR 0x6A +#define BMX160_ADDR 0x69 // ----------------------------------------------------------------------------- // LED diff --git a/src/detect/ScanI2C.cpp b/src/detect/ScanI2C.cpp index 149bb95f05..3231f70545 100644 --- a/src/detect/ScanI2C.cpp +++ b/src/detect/ScanI2C.cpp @@ -36,8 +36,8 @@ ScanI2C::FoundDevice ScanI2C::firstKeyboard() const ScanI2C::FoundDevice ScanI2C::firstAccelerometer() const { - ScanI2C::DeviceType types[] = {MPU6050, LIS3DH, BMA423, LSM6DS3}; - return firstOfOrNONE(4, types); + ScanI2C::DeviceType types[] = {MPU6050, LIS3DH, BMA423, LSM6DS3, BMX160}; + return firstOfOrNONE(5, types); } ScanI2C::FoundDevice ScanI2C::find(ScanI2C::DeviceType) const diff --git a/src/detect/ScanI2C.h b/src/detect/ScanI2C.h index 13dd667632..20994ede1d 100644 --- a/src/detect/ScanI2C.h +++ b/src/detect/ScanI2C.h @@ -49,7 +49,8 @@ class ScanI2C OPT3001, MLX90632, AHT10, - DFROBOT_LARK, + BMX160, + DFROBOT_LARK } DeviceType; // typedef uint8_t DeviceAddress; diff --git a/src/detect/ScanI2CTwoWire.cpp b/src/detect/ScanI2CTwoWire.cpp index 86099ad192..f800a9963f 100644 --- a/src/detect/ScanI2CTwoWire.cpp +++ b/src/detect/ScanI2CTwoWire.cpp @@ -342,6 +342,7 @@ void ScanI2CTwoWire::scanPort(I2CPort port) SCAN_SIMPLE_CASE(PMSA0031_ADDR, PMSA0031, "PMSA0031 air quality sensor found\n") SCAN_SIMPLE_CASE(MPU6050_ADDR, MPU6050, "MPU6050 accelerometer found\n"); + SCAN_SIMPLE_CASE(BMX160_ADDR, BMX160, "BMX160 accelerometer found\n"); SCAN_SIMPLE_CASE(BMA423_ADDR, BMA423, "BMA423 accelerometer found\n"); SCAN_SIMPLE_CASE(LSM6DS3_ADDR, LSM6DS3, "LSM6DS3 accelerometer found at address 0x%x\n", (uint8_t)addr.address); SCAN_SIMPLE_CASE(TCA9555_ADDR, TCA9555, "TCA9555 I2C expander found\n"); diff --git a/src/graphics/Screen.cpp b/src/graphics/Screen.cpp index 1c9484f622..5a892bbfbf 100644 --- a/src/graphics/Screen.cpp +++ b/src/graphics/Screen.cpp @@ -1516,9 +1516,13 @@ static void drawNodeInfo(OLEDDisplay *display, OLEDDisplayUiState *state, int16_ } bool hasNodeHeading = false; - if (ourNode && hasValidPosition(ourNode)) { + if (ourNode && (hasValidPosition(ourNode) || screen->hasHeading())) { const meshtastic_PositionLite &op = ourNode->position; - float myHeading = estimatedHeading(DegD(op.latitude_i), DegD(op.longitude_i)); + float myHeading; + if (screen->hasHeading()) + myHeading = (screen->getHeading()) * PI / 180; // gotta convert compass degrees to Radians + else + myHeading = estimatedHeading(DegD(op.latitude_i), DegD(op.longitude_i)); drawCompassNorth(display, compassX, compassY, myHeading); if (hasValidPosition(node)) { diff --git a/src/graphics/Screen.h b/src/graphics/Screen.h index 7f8d078e78..f4d7197152 100644 --- a/src/graphics/Screen.h +++ b/src/graphics/Screen.h @@ -204,6 +204,17 @@ class Screen : public concurrency::OSThread enqueueCmd(cmd); } + // Function to allow the AccelerometerThread to set the heading if a sensor provides it + // Mutex needed? + void setHeading(long _heading) + { + hasCompass = true; + compassHeading = _heading; + } + + bool hasHeading() { return hasCompass; } + + long getHeading() { return compassHeading; } // functions for display brightness void increaseBrightness(); void decreaseBrightness(); @@ -428,6 +439,8 @@ class Screen : public concurrency::OSThread // Implementation to Adjust Brightness uint8_t brightness = BRIGHTNESS_DEFAULT; // H = 254, MH = 192, ML = 130 L = 103 + bool hasCompass = false; + float compassHeading; /// Holds state for debug information DebugInfo debugInfo; diff --git a/src/main.h b/src/main.h index db05a47347..2ef7edb3a9 100644 --- a/src/main.h +++ b/src/main.h @@ -53,6 +53,9 @@ extern Adafruit_DRV2605 drv; extern AudioThread *audioThread; #endif +// Global Screen singleton. +extern graphics::Screen *screen; + #if !defined(ARCH_PORTDUINO) && !defined(ARCH_STM32WL) && !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR #include "AccelerometerThread.h" extern AccelerometerThread *accelerometerThread; @@ -62,9 +65,6 @@ extern bool isVibrating; extern int TCPPort; // set by Portduino -// Global Screen singleton. -extern graphics::Screen *screen; - // extern Observable newPowerStatus; //TODO: move this to main-esp32.cpp somehow or a helper class // extern meshtastic::PowerStatus *powerStatus; diff --git a/variants/rak4631/platformio.ini b/variants/rak4631/platformio.ini index f64811429e..24f209b01a 100644 --- a/variants/rak4631/platformio.ini +++ b/variants/rak4631/platformio.ini @@ -16,6 +16,7 @@ lib_deps = melopero/Melopero RV3028@^1.1.0 https://github.com/RAKWireless/RAK13800-W5100S.git#1.0.2 rakwireless/RAKwireless NCP5623 RGB LED library@^1.0.2 + beegee-tokyo/RAKwireless RAK12034@^1.0.0 debug_tool = jlink ; If not set we will default to uploading over serial (first it forces bootloader entry by talking 1200bps to cdcacm) ;upload_protocol = jlink \ No newline at end of file diff --git a/variants/rak4631_epaper/platformio.ini b/variants/rak4631_epaper/platformio.ini index 1ca9a21575..08342dcf7c 100644 --- a/variants/rak4631_epaper/platformio.ini +++ b/variants/rak4631_epaper/platformio.ini @@ -13,6 +13,7 @@ lib_deps = zinggjm/GxEPD2@^1.4.9 melopero/Melopero RV3028@^1.1.0 rakwireless/RAKwireless NCP5623 RGB LED library@^1.0.2 + beegee-tokyo/RAKwireless RAK12034@^1.0.0 debug_tool = jlink ; If not set we will default to uploading over serial (first it forces bootloader entry by talking 1200bps to cdcacm) ;upload_protocol = jlink \ No newline at end of file diff --git a/variants/rak4631_epaper_onrxtx/platformio.ini b/variants/rak4631_epaper_onrxtx/platformio.ini index e0a0a5a58e..f7035a1b1b 100644 --- a/variants/rak4631_epaper_onrxtx/platformio.ini +++ b/variants/rak4631_epaper_onrxtx/platformio.ini @@ -15,7 +15,8 @@ lib_deps = zinggjm/GxEPD2@^1.5.1 melopero/Melopero RV3028@^1.1.0 rakwireless/RAKwireless NCP5623 RGB LED library@^1.0.2 + beegee-tokyo/RAKwireless RAK12034@^1.0.0 debug_tool = jlink ; If not set we will default to uploading over serial (first it forces bootloader entry by talking 1200bps to cdcacm) ;upload_protocol = jlink -;upload_port = /dev/ttyACM3 +;upload_port = /dev/ttyACM3 \ No newline at end of file From e63278cf431f9d403c79d8006a750a967208a3d0 Mon Sep 17 00:00:00 2001 From: Tavis Date: Tue, 11 Jun 2024 15:13:17 -1000 Subject: [PATCH 10/65] add wind speed and direction to json --- src/mqtt/MQTT.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/mqtt/MQTT.cpp b/src/mqtt/MQTT.cpp index f3eda6d7ca..566eb352db 100644 --- a/src/mqtt/MQTT.cpp +++ b/src/mqtt/MQTT.cpp @@ -675,6 +675,8 @@ std::string MQTT::meshPacketToJson(meshtastic_MeshPacket *mp) msgPayload["lux"] = new JSONValue(decoded->variant.environment_metrics.lux); msgPayload["white_lux"] = new JSONValue(decoded->variant.environment_metrics.white_lux); msgPayload["iaq"] = new JSONValue((uint)decoded->variant.environment_metrics.iaq); + msgPayload["wind_speed"] = new JSONValue((uint)decoded->variant.environment_metrics.wind_speed); + msgPayload["wind_direction"] = new JSONValue((uint)decoded->variant.environment_metrics.wind_direction); } else if (decoded->which_variant == meshtastic_Telemetry_power_metrics_tag) { msgPayload["voltage_ch1"] = new JSONValue(decoded->variant.power_metrics.ch1_voltage); msgPayload["current_ch1"] = new JSONValue(decoded->variant.power_metrics.ch1_current); From d60d1d74477a5ad3f5d6785b8157f255bb0bbfd4 Mon Sep 17 00:00:00 2001 From: todd-herbert Date: Wed, 12 Jun 2024 23:34:00 +1200 Subject: [PATCH 11/65] Workaround to disable bluetooth on NRF52 (#4055) * Workaround to allow bluetooth disable on NRF52 * Use miminum tx power for bluetooth * Reorganize * Instantiate nrf52Bluetooth correctly.. * Change log message --- src/platform/nrf52/NRF52Bluetooth.cpp | 12 +++++++ src/platform/nrf52/NRF52Bluetooth.h | 1 + src/platform/nrf52/main-nrf52.cpp | 51 ++++++++++++++++++--------- 3 files changed, 48 insertions(+), 16 deletions(-) diff --git a/src/platform/nrf52/NRF52Bluetooth.cpp b/src/platform/nrf52/NRF52Bluetooth.cpp index 39898ab259..4c25f38ea3 100644 --- a/src/platform/nrf52/NRF52Bluetooth.cpp +++ b/src/platform/nrf52/NRF52Bluetooth.cpp @@ -215,6 +215,18 @@ void NRF52Bluetooth::shutdown() Bluefruit.Advertising.stop(); } +void NRF52Bluetooth::startDisabled() +{ + // Setup Bluetooth + nrf52Bluetooth->setup(); + + // Shutdown bluetooth for minimum power draw + Bluefruit.Advertising.stop(); + Bluefruit.setTxPower(-40); // Minimum power + + LOG_INFO("Disabling NRF52 Bluetooth. (Workaround: tx power min, advertising stopped)\n"); +} + bool NRF52Bluetooth::isConnected() { return Bluefruit.connected(connectionHandle); diff --git a/src/platform/nrf52/NRF52Bluetooth.h b/src/platform/nrf52/NRF52Bluetooth.h index 11e18c1272..450af47f91 100644 --- a/src/platform/nrf52/NRF52Bluetooth.h +++ b/src/platform/nrf52/NRF52Bluetooth.h @@ -8,6 +8,7 @@ class NRF52Bluetooth : BluetoothApi public: void setup(); void shutdown(); + void startDisabled(); void resumeAdvertising(); void clearBonds(); bool isConnected(); diff --git a/src/platform/nrf52/main-nrf52.cpp b/src/platform/nrf52/main-nrf52.cpp index 9cc52a7de8..1f2c6867d5 100644 --- a/src/platform/nrf52/main-nrf52.cpp +++ b/src/platform/nrf52/main-nrf52.cpp @@ -68,28 +68,47 @@ static const bool useSoftDevice = true; // Set to false for easier debugging #if !MESHTASTIC_EXCLUDE_BLUETOOTH void setBluetoothEnable(bool enable) { - if (enable && config.bluetooth.enabled) { - if (!useSoftDevice) { + // For debugging use: don't use bluetooth + if (!useSoftDevice) { + if (enable) LOG_INFO("DISABLING NRF52 BLUETOOTH WHILE DEBUGGING\n"); - } else { - if (!nrf52Bluetooth) { - LOG_DEBUG("Initializing NRF52 Bluetooth\n"); - nrf52Bluetooth = new NRF52Bluetooth(); - nrf52Bluetooth->setup(); - - // We delay brownout init until after BLE because BLE starts soft device - initBrownout(); - } else { - nrf52Bluetooth->resumeAdvertising(); - } + return; + } + + // If user disabled bluetooth: init then disable advertising & reduce power + // Workaround. Avoid issue where device hangs several days after boot.. + // Allegedly, no significant increase in power consumption + if (!config.bluetooth.enabled) { + static bool initialized = false; + if (!initialized) { + nrf52Bluetooth = new NRF52Bluetooth(); + nrf52Bluetooth->startDisabled(); + initBrownout(); + initialized = true; } - } else { - if (nrf52Bluetooth) { - nrf52Bluetooth->shutdown(); + return; + } + + if (enable) { + // If not yet set-up + if (!nrf52Bluetooth) { + LOG_DEBUG("Initializing NRF52 Bluetooth\n"); + nrf52Bluetooth = new NRF52Bluetooth(); + nrf52Bluetooth->setup(); + + // We delay brownout init until after BLE because BLE starts soft device + initBrownout(); } + // Already setup, apparently + else + nrf52Bluetooth->resumeAdvertising(); } + // Disable (if previously set-up) + else if (nrf52Bluetooth) + nrf52Bluetooth->shutdown(); } #else +#warning NRF52 "Bluetooth disable" workaround does not apply to builds with MESHTASTIC_EXCLUDE_BLUETOOTH void setBluetoothEnable(bool enable) {} #endif /** From 992d1c42e6d73f46e818fb8178d8e067d48bdec0 Mon Sep 17 00:00:00 2001 From: Jan Veeh <33117982+craft4tnt@users.noreply.github.com> Date: Wed, 12 Jun 2024 13:43:50 +0200 Subject: [PATCH 12/65] changed CFG-PM config message to use external signal (#4062) --- src/gps/ubx.h | 61 ++++++++++++++++++++++++++++----------------------- 1 file changed, 33 insertions(+), 28 deletions(-) diff --git a/src/gps/ubx.h b/src/gps/ubx.h index 0a382a8a3d..df03c16345 100644 --- a/src/gps/ubx.h +++ b/src/gps/ubx.h @@ -319,6 +319,7 @@ const uint8_t GPS::_message_SAVE[] = { // As the M10 has no flash, the best we can do to preserve the config is to set it in RAM and BBR. // BBR will survive a restart, and power off for a while, but modules with small backup // batteries or super caps will not retain the config for a long power off time. +// for all configurations using sleep / low power modes, V_BCKP needs to be hooked to permanent power for fast aquisition after sleep // VALSET Commands for M10 // Please refer to the M10 Protocol Specification: @@ -327,40 +328,44 @@ const uint8_t GPS::_message_SAVE[] = { // and: // https://content.u-blox.com/sites/default/files/u-blox-M10-ROM-5.10_ReleaseNotes_UBX-22001426.pdf // for interesting insights. +// +// Integration manual: +// https://content.u-blox.com/sites/default/files/documents/SAM-M10Q_IntegrationManual_UBX-22020019.pdf +// has details on low-power modes + /* CFG-PM2 has been replaced by many CFG-PM commands -OPERATEMODE E1 2 (0 | 1 | 2) -POSUPDATEPERIOD U4 1000ms for M10 must be >= 5s try 5 -ACQPERIOD U4 10 seems ok for M10 def ok -GRIDOFFSET U4 0 seems ok for M10 def ok -ONTIME U2 1 will try 1 -MINACQTIME U1 0 will try 0 def ok -MAXACQTIME U1 stick with default of 0 def ok -DONOTENTEROFF L 1 stay at 1 -WAITTIMEFIX L 1 stay with 1 -UPDATEEPH L 1 changed to 1 for gps rework default is 1 -EXTINTWAKE L 0 no ext ints -EXTINTBACKUP L 0 no ext ints -EXTINTINACTIVE L 0 no ext ints -EXTINTACTIVITY U4 0 no ext ints -LIMITPEAKCURRENT L 1 stay with 1 -*/ -// CFG-PMS has been removed +CFG-PMS has been removed + +CFG-PM-OPERATEMODE E1 (0 | 1 | 2) -> 1 (PSMOO), because sporadic position updates are required instead of continous tracking <10s (PSMCT) +CFG-PM-POSUPDATEPERIOD U4 -> 0ms, no self-timed wakup because receiver power mode is controlled via "software standby mode" by legacy UBX-RXM-PMREQ request +CFG-PM-ACQPERIOD U4 -> 0ms, because receiver power mode is controlled via "software standby mode" by legacy UBX-RXM-PMREQ request +CFG-PM-ONTIME U4 -> 0ms, optional I guess +CFG-PM-EXTINTBACKUP L -> 1, force receiver into BACKUP mode when EXTINT (should be connected to GPS_EN_PIN) pin is "low" + +This is required because the receiver never enters low power mode if microcontroller is in deep-sleep. +Maybe the changing UART_RX levels trigger a wakeup but even with UBX-RXM-PMREQ[12] = 0x00 (all external wakeup sources disabled) the receivcer remains +in aquisition state -> potentially a bug + +Workaround: Control the EXTINT pin by the GPS_EN_PIN signal + +As mentioned in the M10 operational issues down below, power save won't allow the use of BDS B1C. +CFG-SIGNAL-BDS_B1C_ENA L -> 0 // Ram layer config message: -// b5 62 06 8a 26 00 00 01 00 00 01 00 d0 20 02 02 00 d0 40 05 00 00 00 05 00 d0 30 01 00 08 00 d0 10 01 09 00 d0 10 01 10 00 d0 -// 10 01 8b de +// 01 01 00 00 01 00 D0 20 01 02 00 D0 40 00 00 00 00 03 00 D0 40 00 00 00 00 05 00 D0 30 00 00 0D 00 D0 10 01 // BBR layer config message: -// b5 62 06 8a 26 00 00 02 00 00 01 00 d0 20 02 02 00 d0 40 05 00 00 00 05 00 d0 30 01 00 08 00 d0 10 01 09 00 d0 10 01 10 00 d0 -// 10 01 8c 03 - -const uint8_t GPS::_message_VALSET_PM_RAM[] = {0x00, 0x01, 0x00, 0x00, 0x01, 0x00, 0xd0, 0x20, 0x02, 0x02, 0x00, 0xd0, 0x40, - 0x05, 0x00, 0x00, 0x00, 0x05, 0x00, 0xd0, 0x30, 0x01, 0x00, 0x08, 0x00, 0xd0, - 0x10, 0x01, 0x09, 0x00, 0xd0, 0x10, 0x01, 0x10, 0x00, 0xd0, 0x10, 0x01}; -const uint8_t GPS::_message_VALSET_PM_BBR[] = {0x00, 0x02, 0x00, 0x00, 0x01, 0x00, 0xd0, 0x20, 0x02, 0x02, 0x00, 0xd0, 0x40, - 0x05, 0x00, 0x00, 0x00, 0x05, 0x00, 0xd0, 0x30, 0x01, 0x00, 0x08, 0x00, 0xd0, - 0x10, 0x01, 0x09, 0x00, 0xd0, 0x10, 0x01, 0x10, 0x00, 0xd0, 0x10, 0x01}; +// 01 02 00 00 01 00 D0 20 01 02 00 D0 40 00 00 00 00 03 00 D0 40 00 00 00 00 05 00 D0 30 00 00 0D 00 D0 10 01 +*/ +const uint8_t GPS::_message_VALSET_PM_RAM[] = {0x01, 0x01, 0x00, 0x00, 0x0F, 0x00, 0x31, 0x10, 0x00, 0x01, 0x00, 0xD0, 0x20, + 0x01, 0x02, 0x00, 0xD0, 0x40, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0xD0, 0x40, + 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0xD0, 0x30, 0x00, 0x00, 0x0D, 0x00, 0xD0, + 0x10, 0x01}; +const uint8_t GPS::_message_VALSET_PM_BBR[] = {0x01, 0x02, 0x00, 0x00, 0x0F, 0x00, 0x31, 0x10, 0x00, 0x01, 0x00, 0xD0, 0x20, + 0x01, 0x02, 0x00, 0xD0, 0x40, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0xD0, 0x40, + 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0xD0, 0x30, 0x00, 0x00, 0x0D, 0x00, 0xD0, + 0x10, 0x01}; /* CFG-ITFM replaced by 5 valset messages which can be combined into one for RAM and one for BBR From b09cee118c5f17c9d9e38473896b041776a3faea Mon Sep 17 00:00:00 2001 From: Ben Meadors Date: Wed, 12 Jun 2024 06:57:11 -0500 Subject: [PATCH 13/65] Trunk --- src/gps/ubx.h | 31 +++++++++++++++---------------- 1 file changed, 15 insertions(+), 16 deletions(-) diff --git a/src/gps/ubx.h b/src/gps/ubx.h index df03c16345..0852c331d0 100644 --- a/src/gps/ubx.h +++ b/src/gps/ubx.h @@ -319,7 +319,8 @@ const uint8_t GPS::_message_SAVE[] = { // As the M10 has no flash, the best we can do to preserve the config is to set it in RAM and BBR. // BBR will survive a restart, and power off for a while, but modules with small backup // batteries or super caps will not retain the config for a long power off time. -// for all configurations using sleep / low power modes, V_BCKP needs to be hooked to permanent power for fast aquisition after sleep +// for all configurations using sleep / low power modes, V_BCKP needs to be hooked to permanent power for fast aquisition after +// sleep // VALSET Commands for M10 // Please refer to the M10 Protocol Specification: @@ -337,15 +338,15 @@ const uint8_t GPS::_message_SAVE[] = { CFG-PM2 has been replaced by many CFG-PM commands CFG-PMS has been removed -CFG-PM-OPERATEMODE E1 (0 | 1 | 2) -> 1 (PSMOO), because sporadic position updates are required instead of continous tracking <10s (PSMCT) -CFG-PM-POSUPDATEPERIOD U4 -> 0ms, no self-timed wakup because receiver power mode is controlled via "software standby mode" by legacy UBX-RXM-PMREQ request -CFG-PM-ACQPERIOD U4 -> 0ms, because receiver power mode is controlled via "software standby mode" by legacy UBX-RXM-PMREQ request -CFG-PM-ONTIME U4 -> 0ms, optional I guess -CFG-PM-EXTINTBACKUP L -> 1, force receiver into BACKUP mode when EXTINT (should be connected to GPS_EN_PIN) pin is "low" +CFG-PM-OPERATEMODE E1 (0 | 1 | 2) -> 1 (PSMOO), because sporadic position updates are required instead of continous tracking <10s +(PSMCT) CFG-PM-POSUPDATEPERIOD U4 -> 0ms, no self-timed wakup because receiver power mode is controlled via "software standby +mode" by legacy UBX-RXM-PMREQ request CFG-PM-ACQPERIOD U4 -> 0ms, because receiver power mode is controlled via "software standby +mode" by legacy UBX-RXM-PMREQ request CFG-PM-ONTIME U4 -> 0ms, optional I guess CFG-PM-EXTINTBACKUP L -> 1, force receiver into +BACKUP mode when EXTINT (should be connected to GPS_EN_PIN) pin is "low" This is required because the receiver never enters low power mode if microcontroller is in deep-sleep. -Maybe the changing UART_RX levels trigger a wakeup but even with UBX-RXM-PMREQ[12] = 0x00 (all external wakeup sources disabled) the receivcer remains -in aquisition state -> potentially a bug +Maybe the changing UART_RX levels trigger a wakeup but even with UBX-RXM-PMREQ[12] = 0x00 (all external wakeup sources disabled) +the receivcer remains in aquisition state -> potentially a bug Workaround: Control the EXTINT pin by the GPS_EN_PIN signal @@ -358,14 +359,12 @@ CFG-SIGNAL-BDS_B1C_ENA L -> 0 // BBR layer config message: // 01 02 00 00 01 00 D0 20 01 02 00 D0 40 00 00 00 00 03 00 D0 40 00 00 00 00 05 00 D0 30 00 00 0D 00 D0 10 01 */ -const uint8_t GPS::_message_VALSET_PM_RAM[] = {0x01, 0x01, 0x00, 0x00, 0x0F, 0x00, 0x31, 0x10, 0x00, 0x01, 0x00, 0xD0, 0x20, - 0x01, 0x02, 0x00, 0xD0, 0x40, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0xD0, 0x40, - 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0xD0, 0x30, 0x00, 0x00, 0x0D, 0x00, 0xD0, - 0x10, 0x01}; -const uint8_t GPS::_message_VALSET_PM_BBR[] = {0x01, 0x02, 0x00, 0x00, 0x0F, 0x00, 0x31, 0x10, 0x00, 0x01, 0x00, 0xD0, 0x20, - 0x01, 0x02, 0x00, 0xD0, 0x40, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0xD0, 0x40, - 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0xD0, 0x30, 0x00, 0x00, 0x0D, 0x00, 0xD0, - 0x10, 0x01}; +const uint8_t GPS::_message_VALSET_PM_RAM[] = {0x01, 0x01, 0x00, 0x00, 0x0F, 0x00, 0x31, 0x10, 0x00, 0x01, 0x00, 0xD0, 0x20, 0x01, + 0x02, 0x00, 0xD0, 0x40, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0xD0, 0x40, 0x00, 0x00, + 0x00, 0x00, 0x05, 0x00, 0xD0, 0x30, 0x00, 0x00, 0x0D, 0x00, 0xD0, 0x10, 0x01}; +const uint8_t GPS::_message_VALSET_PM_BBR[] = {0x01, 0x02, 0x00, 0x00, 0x0F, 0x00, 0x31, 0x10, 0x00, 0x01, 0x00, 0xD0, 0x20, 0x01, + 0x02, 0x00, 0xD0, 0x40, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0xD0, 0x40, 0x00, 0x00, + 0x00, 0x00, 0x05, 0x00, 0xD0, 0x30, 0x00, 0x00, 0x0D, 0x00, 0xD0, 0x10, 0x01}; /* CFG-ITFM replaced by 5 valset messages which can be combined into one for RAM and one for BBR From 5b1d3ed173fc1eddd8dc8e494095e4353223ccfe Mon Sep 17 00:00:00 2001 From: Heltec-Aaron-Lee Date: Wed, 12 Jun 2024 20:21:26 +0800 Subject: [PATCH 14/65] Add Heltec Capsule Sensor V3 to source code --- platformio.ini | 1 + src/ButtonThread.cpp | 4 ++ src/Power.cpp | 25 +++++++---- src/platform/esp32/architecture.h | 2 + .../heltec_capsule_sensor_v3/platformio.ini | 11 +++++ variants/heltec_capsule_sensor_v3/variant.h | 42 +++++++++++++++++++ 6 files changed, 78 insertions(+), 7 deletions(-) create mode 100644 variants/heltec_capsule_sensor_v3/platformio.ini create mode 100644 variants/heltec_capsule_sensor_v3/variant.h diff --git a/platformio.ini b/platformio.ini index 7ed794a6ed..9c29d2d677 100644 --- a/platformio.ini +++ b/platformio.ini @@ -33,6 +33,7 @@ default_envs = tbeam ;default_envs = wio-e5 ;default_envs = radiomaster_900_bandit_nano ;default_envs = radiomaster_900_bandit_micro +;default_envs = heltec_capsule_sensor_v3 extra_configs = arch/*/*.ini diff --git a/src/ButtonThread.cpp b/src/ButtonThread.cpp index 7e678d69d7..4b3bb3fbc5 100644 --- a/src/ButtonThread.cpp +++ b/src/ButtonThread.cpp @@ -41,7 +41,11 @@ ButtonThread::ButtonThread() : OSThread("Button") } #elif defined(BUTTON_PIN) int pin = config.device.button_gpio ? config.device.button_gpio : BUTTON_PIN; // Resolved button pin +#if defined(HELTEC_CAPSULE_SENSOR_V3) + this->userButton = OneButton(pin, false, false); +#else this->userButton = OneButton(pin, true, true); +#endif LOG_DEBUG("Using GPIO%02d for button\n", pin); #endif diff --git a/src/Power.cpp b/src/Power.cpp index b80d8a0d57..d80bfd55cd 100644 --- a/src/Power.cpp +++ b/src/Power.cpp @@ -335,13 +335,20 @@ class AnalogBatteryLevel : public HasBatteryLevel virtual bool isVbusIn() override { #ifdef EXT_PWR_DETECT - // if external powered that pin will be pulled up - if (digitalRead(EXT_PWR_DETECT) == HIGH) { - return true; - } - // if it's not HIGH - check the battery + #ifdef HELTEC_CAPSULE_SENSOR_V3 + // if external powered that pin will be pulled down + if (digitalRead(EXT_PWR_DETECT) == LOW) { + return true; + } + // if it's not LOW - check the battery + #else + // if external powered that pin will be pulled up + if (digitalRead(EXT_PWR_DETECT) == HIGH) { + return true; + } + // if it's not HIGH - check the battery + #endif #endif - return getBattVoltage() > chargingVolt; } @@ -421,7 +428,11 @@ Power::Power() : OSThread("Power") bool Power::analogInit() { #ifdef EXT_PWR_DETECT - pinMode(EXT_PWR_DETECT, INPUT); + #ifdef HELTEC_CAPSULE_SENSOR_V3 + pinMode(EXT_PWR_DETECT, INPUT_PULLUP); + #else + pinMode(EXT_PWR_DETECT, INPUT); + #endif #endif #ifdef EXT_CHRG_DETECT pinMode(EXT_CHRG_DETECT, ext_chrg_detect_mode); diff --git a/src/platform/esp32/architecture.h b/src/platform/esp32/architecture.h index 824c11bdd3..c979d016cb 100644 --- a/src/platform/esp32/architecture.h +++ b/src/platform/esp32/architecture.h @@ -147,6 +147,8 @@ #define HW_VENDOR meshtastic_HardwareModel_WIPHONE #elif defined(RADIOMASTER_900_BANDIT_NANO) #define HW_VENDOR meshtastic_HardwareModel_RADIOMASTER_900_BANDIT_NANO +#elif defined(HELTEC_CAPSULE_SENSOR_V3) +#define HW_VENDOR meshtastic_HardwareModel_HELTEC_CAPSULE_SENSOR_V3 #endif // ----------------------------------------------------------------------------- diff --git a/variants/heltec_capsule_sensor_v3/platformio.ini b/variants/heltec_capsule_sensor_v3/platformio.ini new file mode 100644 index 0000000000..f1aef925dc --- /dev/null +++ b/variants/heltec_capsule_sensor_v3/platformio.ini @@ -0,0 +1,11 @@ +[env:heltec_capsule_sensor_v3] +extends = esp32s3_base +board = heltec_wifi_lora_32_V3 +board_check = true + +build_flags = + ${esp32s3_base.build_flags} -I variants/heltec_capsule_sensor_v3 + -D HELTEC_CAPSULE_SENSOR_V3 + -D GPS_POWER_TOGGLE ; comment this line to disable triple press function on the user button to turn off gps entirely. + ;-D DEBUG_DISABLED ; uncomment this line to disable DEBUG output + diff --git a/variants/heltec_capsule_sensor_v3/variant.h b/variants/heltec_capsule_sensor_v3/variant.h new file mode 100644 index 0000000000..0d5ab73cfb --- /dev/null +++ b/variants/heltec_capsule_sensor_v3/variant.h @@ -0,0 +1,42 @@ +#define LED_PIN 33 +#define LED_PIN2 34 +#define EXT_PWR_DETECT 35 + +#define BUTTON_PIN 18 + +#define BATTERY_PIN 7 // A battery voltage measurement pin, voltage divider connected here to measure battery voltage +#define ADC_CHANNEL ADC1_GPIO7_CHANNEL +#define ADC_ATTENUATION ADC_ATTEN_DB_2_5 // lower dB for high resistance voltage divider +#define ADC_MULTIPLIER (4.9 * 1.045) +#define ADC_CTRL 36 // active HIGH, powers the voltage divider. Only on 1.1 +#define ADC_CTRL_ENABLED HIGH + +#undef GPS_RX_PIN +#undef GPS_TX_PIN +#define GPS_RX_PIN 5 +#define GPS_TX_PIN 4 +#define PIN_GPS_RESET 3 +#define GPS_RESET_MODE LOW +#define PIN_GPS_PPS 1 +#define PIN_GPS_EN 21 +#define GPS_EN_ACTIVE HIGH + +#define USE_SX1262 +#define LORA_DIO0 -1 // a No connect on the SX1262 module +#define LORA_RESET 12 +#define LORA_DIO1 14 // SX1262 IRQ +#define LORA_DIO2 13 // SX1262 BUSY +#define LORA_DIO3 // Not connected on PCB, but internally on the TTGO SX1262, if DIO3 is high the TXCO is enabled + +#define LORA_SCK 9 +#define LORA_MISO 11 +#define LORA_MOSI 10 +#define LORA_CS 8 + +#define SX126X_CS LORA_CS +#define SX126X_DIO1 LORA_DIO1 +#define SX126X_BUSY LORA_DIO2 +#define SX126X_RESET LORA_RESET + +#define SX126X_DIO2_AS_RF_SWITCH +#define SX126X_DIO3_TCXO_VOLTAGE 1.8 From c7769274dd417017bf06a01e5215e61054567cfd Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Wed, 12 Jun 2024 07:23:54 -0500 Subject: [PATCH 15/65] [create-pull-request] automated change (#4085) Co-authored-by: thebentern <9000580+thebentern@users.noreply.github.com> --- protobufs | 2 +- src/mesh/generated/meshtastic/mesh.pb.h | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/protobufs b/protobufs index 8c8048798c..8f4faf76e5 160000 --- a/protobufs +++ b/protobufs @@ -1 +1 @@ -Subproject commit 8c8048798c1b1773b9d8f2c32eb3f4c9e72f8218 +Subproject commit 8f4faf76e52c2ef63c582c26642d312d9781b7c0 diff --git a/src/mesh/generated/meshtastic/mesh.pb.h b/src/mesh/generated/meshtastic/mesh.pb.h index ad97cb80f8..0e9e6a28d7 100644 --- a/src/mesh/generated/meshtastic/mesh.pb.h +++ b/src/mesh/generated/meshtastic/mesh.pb.h @@ -161,6 +161,8 @@ typedef enum _meshtastic_HardwareModel { /* RadioMaster 900 Bandit Nano, https://www.radiomasterrc.com/products/bandit-nano-expresslrs-rf-module ESP32-D0WDQ6 With SX1276/SKY66122, SSD1306 OLED and No GPS */ meshtastic_HardwareModel_RADIOMASTER_900_BANDIT_NANO = 64, + /* Heltec Capsule Sensor V3 with ESP32-S3 CPU, Portable LoRa device that can replace GNSS modules or sensors */ + meshtastic_HardwareModel_HELTEC_CAPSULE_SENSOR_V3 = 65, /* ------------------------------------------------------------------------------------------------------------------------------------------ Reserved ID For developing private Ports. These will show up in live traffic sparsely, so we can use a high number. Keep it within 8 bits. ------------------------------------------------------------------------------------------------------------------------------------------ */ From 871f6854b5751b88fbb3b3905970125f6ffb4285 Mon Sep 17 00:00:00 2001 From: John Gorkos - AB0OO Date: Wed, 12 Jun 2024 08:22:01 -0700 Subject: [PATCH 16/65] feature-mqtt: add hop_start and hop_limit to MQTT uplink --- src/mqtt/MQTT.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/mqtt/MQTT.cpp b/src/mqtt/MQTT.cpp index 566eb352db..905c2b7d34 100644 --- a/src/mqtt/MQTT.cpp +++ b/src/mqtt/MQTT.cpp @@ -902,7 +902,9 @@ std::string MQTT::meshPacketToJson(meshtastic_MeshPacket *mp) jsonObj["snr"] = new JSONValue((float)mp->rx_snr); if (mp->hop_start != 0 && mp->hop_limit <= mp->hop_start) jsonObj["hops_away"] = new JSONValue((unsigned int)(mp->hop_start - mp->hop_limit)); - + jsonObj["hop_start"] = new JSONValue((unsigned int)(mp->hop_start)); + jsonObj["hop_limit"] = new JSONValue((unsigned int)(mp->hop_limit)); + // serialize and write it to the stream JSONValue *value = new JSONValue(jsonObj); std::string jsonStr = value->Stringify(); From d80bcd7d67df2876b9536cd1418bec64171269e9 Mon Sep 17 00:00:00 2001 From: John Gorkos - AB0OO Date: Wed, 12 Jun 2024 12:59:52 -0700 Subject: [PATCH 17/65] adding only hop_start, per @GUVWAF --- src/mqtt/MQTT.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/mqtt/MQTT.cpp b/src/mqtt/MQTT.cpp index 905c2b7d34..4f685cd7a6 100644 --- a/src/mqtt/MQTT.cpp +++ b/src/mqtt/MQTT.cpp @@ -903,7 +903,6 @@ std::string MQTT::meshPacketToJson(meshtastic_MeshPacket *mp) if (mp->hop_start != 0 && mp->hop_limit <= mp->hop_start) jsonObj["hops_away"] = new JSONValue((unsigned int)(mp->hop_start - mp->hop_limit)); jsonObj["hop_start"] = new JSONValue((unsigned int)(mp->hop_start)); - jsonObj["hop_limit"] = new JSONValue((unsigned int)(mp->hop_limit)); // serialize and write it to the stream JSONValue *value = new JSONValue(jsonObj); From b42185c722c27e17523bf2474079915f8eca7f04 Mon Sep 17 00:00:00 2001 From: John Gorkos - AB0OO Date: Wed, 12 Jun 2024 13:02:01 -0700 Subject: [PATCH 18/65] included hop_start in conditional for hop_away --- src/mqtt/MQTT.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/mqtt/MQTT.cpp b/src/mqtt/MQTT.cpp index 4f685cd7a6..d93166ce94 100644 --- a/src/mqtt/MQTT.cpp +++ b/src/mqtt/MQTT.cpp @@ -900,9 +900,10 @@ std::string MQTT::meshPacketToJson(meshtastic_MeshPacket *mp) jsonObj["rssi"] = new JSONValue((int)mp->rx_rssi); if (mp->rx_snr != 0) jsonObj["snr"] = new JSONValue((float)mp->rx_snr); - if (mp->hop_start != 0 && mp->hop_limit <= mp->hop_start) + if (mp->hop_start != 0 && mp->hop_limit <= mp->hop_start) { jsonObj["hops_away"] = new JSONValue((unsigned int)(mp->hop_start - mp->hop_limit)); - jsonObj["hop_start"] = new JSONValue((unsigned int)(mp->hop_start)); + jsonObj["hop_start"] = new JSONValue((unsigned int)(mp->hop_start)); + } // serialize and write it to the stream JSONValue *value = new JSONValue(jsonObj); From f7433eb4ee772477493545800da88eafc1455e96 Mon Sep 17 00:00:00 2001 From: John Gorkos - AB0OO Date: Wed, 12 Jun 2024 14:36:38 -0700 Subject: [PATCH 19/65] trunk formatting --- src/mqtt/MQTT.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mqtt/MQTT.cpp b/src/mqtt/MQTT.cpp index d93166ce94..9f9ac5c243 100644 --- a/src/mqtt/MQTT.cpp +++ b/src/mqtt/MQTT.cpp @@ -904,7 +904,7 @@ std::string MQTT::meshPacketToJson(meshtastic_MeshPacket *mp) jsonObj["hops_away"] = new JSONValue((unsigned int)(mp->hop_start - mp->hop_limit)); jsonObj["hop_start"] = new JSONValue((unsigned int)(mp->hop_start)); } - + // serialize and write it to the stream JSONValue *value = new JSONValue(jsonObj); std::string jsonStr = value->Stringify(); From 26d4d06e2a2359d35f349eaf15b6a703058bacff Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 13 Jun 2024 08:39:38 -0500 Subject: [PATCH 20/65] [create-pull-request] automated change (#4093) Co-authored-by: caveman99 <25002+caveman99@users.noreply.github.com> --- protobufs | 2 +- .../generated/meshtastic/telemetry.pb.cpp | 3 ++ src/mesh/generated/meshtastic/telemetry.pb.h | 30 +++++++++++++++++-- 3 files changed, 31 insertions(+), 4 deletions(-) diff --git a/protobufs b/protobufs index 8f4faf76e5..260d24318d 160000 --- a/protobufs +++ b/protobufs @@ -1 +1 @@ -Subproject commit 8f4faf76e52c2ef63c582c26642d312d9781b7c0 +Subproject commit 260d24318d811518171ed2916c94c0cfd94eb9d4 diff --git a/src/mesh/generated/meshtastic/telemetry.pb.cpp b/src/mesh/generated/meshtastic/telemetry.pb.cpp index 6388e37a0a..c93483a152 100644 --- a/src/mesh/generated/meshtastic/telemetry.pb.cpp +++ b/src/mesh/generated/meshtastic/telemetry.pb.cpp @@ -21,5 +21,8 @@ PB_BIND(meshtastic_AirQualityMetrics, meshtastic_AirQualityMetrics, AUTO) PB_BIND(meshtastic_Telemetry, meshtastic_Telemetry, AUTO) +PB_BIND(meshtastic_Nau7802Config, meshtastic_Nau7802Config, AUTO) + + diff --git a/src/mesh/generated/meshtastic/telemetry.pb.h b/src/mesh/generated/meshtastic/telemetry.pb.h index 02b0bdd6dd..47961cd7dc 100644 --- a/src/mesh/generated/meshtastic/telemetry.pb.h +++ b/src/mesh/generated/meshtastic/telemetry.pb.h @@ -61,7 +61,9 @@ typedef enum _meshtastic_TelemetrySensorType { /* AHT10 Integrated temperature and humidity sensor */ meshtastic_TelemetrySensorType_AHT10 = 23, /* DFRobot Lark Weather station (temperature, humidity, pressure, wind speed and direction) */ - meshtastic_TelemetrySensorType_DFROBOT_LARK = 24 + meshtastic_TelemetrySensorType_DFROBOT_LARK = 24, + /* NAU7802 Scale Chip or compatible */ + meshtastic_TelemetrySensorType_NAU7802 = 25 } meshtastic_TelemetrySensorType; /* Struct definitions */ @@ -174,6 +176,14 @@ typedef struct _meshtastic_Telemetry { } variant; } meshtastic_Telemetry; +/* NAU7802 Telemetry configuration, for saving to flash */ +typedef struct _meshtastic_Nau7802Config { + /* The offset setting for the NAU7802 */ + int32_t zeroOffset; + /* The calibration factor for the NAU7802 */ + float calibrationFactor; +} meshtastic_Nau7802Config; + #ifdef __cplusplus extern "C" { @@ -181,8 +191,9 @@ extern "C" { /* Helper constants for enums */ #define _meshtastic_TelemetrySensorType_MIN meshtastic_TelemetrySensorType_SENSOR_UNSET -#define _meshtastic_TelemetrySensorType_MAX meshtastic_TelemetrySensorType_DFROBOT_LARK -#define _meshtastic_TelemetrySensorType_ARRAYSIZE ((meshtastic_TelemetrySensorType)(meshtastic_TelemetrySensorType_DFROBOT_LARK+1)) +#define _meshtastic_TelemetrySensorType_MAX meshtastic_TelemetrySensorType_NAU7802 +#define _meshtastic_TelemetrySensorType_ARRAYSIZE ((meshtastic_TelemetrySensorType)(meshtastic_TelemetrySensorType_NAU7802+1)) + @@ -196,11 +207,13 @@ extern "C" { #define meshtastic_PowerMetrics_init_default {0, 0, 0, 0, 0, 0} #define meshtastic_AirQualityMetrics_init_default {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} #define meshtastic_Telemetry_init_default {0, 0, {meshtastic_DeviceMetrics_init_default}} +#define meshtastic_Nau7802Config_init_default {0, 0} #define meshtastic_DeviceMetrics_init_zero {0, 0, 0, 0, 0} #define meshtastic_EnvironmentMetrics_init_zero {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} #define meshtastic_PowerMetrics_init_zero {0, 0, 0, 0, 0, 0} #define meshtastic_AirQualityMetrics_init_zero {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} #define meshtastic_Telemetry_init_zero {0, 0, {meshtastic_DeviceMetrics_init_zero}} +#define meshtastic_Nau7802Config_init_zero {0, 0} /* Field tags (for use in manual encoding/decoding) */ #define meshtastic_DeviceMetrics_battery_level_tag 1 @@ -245,6 +258,8 @@ extern "C" { #define meshtastic_Telemetry_environment_metrics_tag 3 #define meshtastic_Telemetry_air_quality_metrics_tag 4 #define meshtastic_Telemetry_power_metrics_tag 5 +#define meshtastic_Nau7802Config_zeroOffset_tag 1 +#define meshtastic_Nau7802Config_calibrationFactor_tag 2 /* Struct field encoding specification for nanopb */ #define meshtastic_DeviceMetrics_FIELDLIST(X, a) \ @@ -313,11 +328,18 @@ X(a, STATIC, ONEOF, MESSAGE, (variant,power_metrics,variant.power_metrics) #define meshtastic_Telemetry_variant_air_quality_metrics_MSGTYPE meshtastic_AirQualityMetrics #define meshtastic_Telemetry_variant_power_metrics_MSGTYPE meshtastic_PowerMetrics +#define meshtastic_Nau7802Config_FIELDLIST(X, a) \ +X(a, STATIC, SINGULAR, INT32, zeroOffset, 1) \ +X(a, STATIC, SINGULAR, FLOAT, calibrationFactor, 2) +#define meshtastic_Nau7802Config_CALLBACK NULL +#define meshtastic_Nau7802Config_DEFAULT NULL + extern const pb_msgdesc_t meshtastic_DeviceMetrics_msg; extern const pb_msgdesc_t meshtastic_EnvironmentMetrics_msg; extern const pb_msgdesc_t meshtastic_PowerMetrics_msg; extern const pb_msgdesc_t meshtastic_AirQualityMetrics_msg; extern const pb_msgdesc_t meshtastic_Telemetry_msg; +extern const pb_msgdesc_t meshtastic_Nau7802Config_msg; /* Defines for backwards compatibility with code written before nanopb-0.4.0 */ #define meshtastic_DeviceMetrics_fields &meshtastic_DeviceMetrics_msg @@ -325,12 +347,14 @@ extern const pb_msgdesc_t meshtastic_Telemetry_msg; #define meshtastic_PowerMetrics_fields &meshtastic_PowerMetrics_msg #define meshtastic_AirQualityMetrics_fields &meshtastic_AirQualityMetrics_msg #define meshtastic_Telemetry_fields &meshtastic_Telemetry_msg +#define meshtastic_Nau7802Config_fields &meshtastic_Nau7802Config_msg /* Maximum encoded size of messages (where known) */ #define MESHTASTIC_MESHTASTIC_TELEMETRY_PB_H_MAX_SIZE meshtastic_Telemetry_size #define meshtastic_AirQualityMetrics_size 72 #define meshtastic_DeviceMetrics_size 27 #define meshtastic_EnvironmentMetrics_size 68 +#define meshtastic_Nau7802Config_size 16 #define meshtastic_PowerMetrics_size 30 #define meshtastic_Telemetry_size 79 From 75d5cd2c356eaa2ff76b1b360325091a92b44d89 Mon Sep 17 00:00:00 2001 From: caveman99 <25002+caveman99@users.noreply.github.com> Date: Thu, 13 Jun 2024 14:50:21 +0000 Subject: [PATCH 21/65] [create-pull-request] automated change --- protobufs | 2 +- src/mesh/generated/meshtastic/telemetry.pb.h | 14 +++++++++----- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/protobufs b/protobufs index 260d24318d..ab576a4a12 160000 --- a/protobufs +++ b/protobufs @@ -1 +1 @@ -Subproject commit 260d24318d811518171ed2916c94c0cfd94eb9d4 +Subproject commit ab576a4a122c1a1d0a3c2235b0a0cf3bd4a83c65 diff --git a/src/mesh/generated/meshtastic/telemetry.pb.h b/src/mesh/generated/meshtastic/telemetry.pb.h index 47961cd7dc..28d3687548 100644 --- a/src/mesh/generated/meshtastic/telemetry.pb.h +++ b/src/mesh/generated/meshtastic/telemetry.pb.h @@ -113,6 +113,8 @@ typedef struct _meshtastic_EnvironmentMetrics { uint16_t wind_direction; /* Wind speed in m/s */ float wind_speed; + /* Weight in KG */ + float weight; } meshtastic_EnvironmentMetrics; /* Power Metrics (voltage / current / etc) */ @@ -203,13 +205,13 @@ extern "C" { /* Initializer values for message structs */ #define meshtastic_DeviceMetrics_init_default {0, 0, 0, 0, 0} -#define meshtastic_EnvironmentMetrics_init_default {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} +#define meshtastic_EnvironmentMetrics_init_default {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} #define meshtastic_PowerMetrics_init_default {0, 0, 0, 0, 0, 0} #define meshtastic_AirQualityMetrics_init_default {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} #define meshtastic_Telemetry_init_default {0, 0, {meshtastic_DeviceMetrics_init_default}} #define meshtastic_Nau7802Config_init_default {0, 0} #define meshtastic_DeviceMetrics_init_zero {0, 0, 0, 0, 0} -#define meshtastic_EnvironmentMetrics_init_zero {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} +#define meshtastic_EnvironmentMetrics_init_zero {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} #define meshtastic_PowerMetrics_init_zero {0, 0, 0, 0, 0, 0} #define meshtastic_AirQualityMetrics_init_zero {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} #define meshtastic_Telemetry_init_zero {0, 0, {meshtastic_DeviceMetrics_init_zero}} @@ -235,6 +237,7 @@ extern "C" { #define meshtastic_EnvironmentMetrics_uv_lux_tag 12 #define meshtastic_EnvironmentMetrics_wind_direction_tag 13 #define meshtastic_EnvironmentMetrics_wind_speed_tag 14 +#define meshtastic_EnvironmentMetrics_weight_tag 15 #define meshtastic_PowerMetrics_ch1_voltage_tag 1 #define meshtastic_PowerMetrics_ch1_current_tag 2 #define meshtastic_PowerMetrics_ch2_voltage_tag 3 @@ -285,7 +288,8 @@ X(a, STATIC, SINGULAR, FLOAT, white_lux, 10) \ X(a, STATIC, SINGULAR, FLOAT, ir_lux, 11) \ X(a, STATIC, SINGULAR, FLOAT, uv_lux, 12) \ X(a, STATIC, SINGULAR, UINT32, wind_direction, 13) \ -X(a, STATIC, SINGULAR, FLOAT, wind_speed, 14) +X(a, STATIC, SINGULAR, FLOAT, wind_speed, 14) \ +X(a, STATIC, SINGULAR, FLOAT, weight, 15) #define meshtastic_EnvironmentMetrics_CALLBACK NULL #define meshtastic_EnvironmentMetrics_DEFAULT NULL @@ -353,10 +357,10 @@ extern const pb_msgdesc_t meshtastic_Nau7802Config_msg; #define MESHTASTIC_MESHTASTIC_TELEMETRY_PB_H_MAX_SIZE meshtastic_Telemetry_size #define meshtastic_AirQualityMetrics_size 72 #define meshtastic_DeviceMetrics_size 27 -#define meshtastic_EnvironmentMetrics_size 68 +#define meshtastic_EnvironmentMetrics_size 73 #define meshtastic_Nau7802Config_size 16 #define meshtastic_PowerMetrics_size 30 -#define meshtastic_Telemetry_size 79 +#define meshtastic_Telemetry_size 80 #ifdef __cplusplus } /* extern "C" */ From 85bca8a32a09d75d786a16d8908c0582389a1d7d Mon Sep 17 00:00:00 2001 From: Ben Meadors Date: Thu, 13 Jun 2024 11:13:18 -0500 Subject: [PATCH 22/65] Update lark to ref to clear C++ warning --- platformio.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platformio.ini b/platformio.ini index 9c29d2d677..2064bac483 100644 --- a/platformio.ini +++ b/platformio.ini @@ -143,4 +143,4 @@ lib_deps = ClosedCube OPT3001@^1.1.2 emotibit/EmotiBit MLX90632@^1.0.8 dfrobot/DFRobot_RTU@^1.0.3 - https://github.com/meshtastic/DFRobot_LarkWeatherStation#0e884fc86b7a0b602c7ff3d26b893b997f15c6ac \ No newline at end of file + https://github.com/meshtastic/DFRobot_LarkWeatherStation#dee914270dc7cb3e43fbf034edd85a63a16a12ee \ No newline at end of file From 16b41b51af7ea2ae3b0c9ad4e3b0afb4e0051797 Mon Sep 17 00:00:00 2001 From: Ben Meadors Date: Thu, 13 Jun 2024 12:05:14 -0500 Subject: [PATCH 23/65] Update OLED ref --- platformio.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platformio.ini b/platformio.ini index 2064bac483..34471fc54e 100644 --- a/platformio.ini +++ b/platformio.ini @@ -78,7 +78,7 @@ monitor_speed = 115200 lib_deps = jgromes/RadioLib@~6.6.0 - https://github.com/meshtastic/esp8266-oled-ssd1306.git#ee628ee6c9588d4c56c9e3da35f0fc9448ad54a8 ; ESP8266_SSD1306 + https://github.com/meshtastic/esp8266-oled-ssd1306.git#69ba98fa30e67b12d4577b121f210f3eb7049d6b ; ESP8266_SSD1306 mathertel/OneButton@^2.5.0 ; OneButton library for non-blocking button debounce https://github.com/meshtastic/arduino-fsm.git#7db3702bf0cfe97b783d6c72595e3f38e0b19159 https://github.com/meshtastic/TinyGPSPlus.git#71a82db35f3b973440044c476d4bcdc673b104f4 From 39c9f92c6e7ee1639051a967d761ed5d642f4fcd Mon Sep 17 00:00:00 2001 From: todd-herbert Date: Sat, 15 Jun 2024 01:28:01 +1200 Subject: [PATCH 24/65] GPS: short update intervals, lock-time prediction (#4070) * Refactor GPSPowerState enum Identifies a case where the GPS hardware is awake, but an update is not yet desired * Change terminology * Clear old lock-time prediction on triple press * Use exponential smoothing to predict lock time * Rename averageLockTime to predictedLockTime * Attempt: Send PMREQ with duration 0 on MCU deep-sleep * Attempt 2: Send PMREQ with duration 0 on MCU deep-sleep * Revert "Attempt 2: Send PMREQ with duration 0 on MCU deep-sleep" This reverts commit 8b697cd2a445355dcfab5b33e0ce7a3128cab151. * Revert "Attempt: Send PMREQ with duration 0 on MCU deep-sleep" This reverts commit 9d29ec7603a88056b9115796b29b5023165a93bb. --- src/gps/GPS.cpp | 97 +++++++++++++++++++++++++++++++++---------------- src/gps/GPS.h | 11 +++--- 2 files changed, 71 insertions(+), 37 deletions(-) diff --git a/src/gps/GPS.cpp b/src/gps/GPS.cpp index 17088910ae..8d46742baa 100644 --- a/src/gps/GPS.cpp +++ b/src/gps/GPS.cpp @@ -28,6 +28,12 @@ #define GPS_STANDBY_THRESHOLD_MINUTES 15 #endif +// How many seconds of sleep make it worthwhile for the GPS to use powered-on standby +// Shorter than this, and we'll just wait instead +#ifndef GPS_IDLE_THRESHOLD_SECONDS +#define GPS_IDLE_THRESHOLD_SECONDS 10 +#endif + #if defined(NRF52840_XXAA) || defined(NRF52833_XXAA) || defined(ARCH_ESP32) || defined(ARCH_PORTDUINO) HardwareSerial *GPS::_serial_gps = &Serial1; #else @@ -776,14 +782,22 @@ void GPS::setGPSPower(bool on, bool standbyOnly, uint32_t sleepTime) { // Record the current powerState if (on) - powerState = GPS_AWAKE; - else if (!on && standbyOnly) + powerState = GPS_ACTIVE; + else if (!enabled) // User has disabled with triple press + powerState = GPS_OFF; + else if (sleepTime <= GPS_IDLE_THRESHOLD_SECONDS * 1000UL) + powerState = GPS_IDLE; + else if (standbyOnly) powerState = GPS_STANDBY; else powerState = GPS_OFF; LOG_DEBUG("GPS::powerState=%d\n", powerState); + // If the next update is due *really soon*, don't actually power off or enter standby. Just wait it out. + if (!on && powerState == GPS_IDLE) + return; + if (on) { clearBuffer(); // drop any old data waiting in the buffer before re-enabling if (en_gpio) @@ -880,54 +894,69 @@ void GPS::setConnected() void GPS::setAwake(bool wantAwake) { - // If user has disabled GPS, make sure it is off, not just in standby + // If user has disabled GPS, make sure it is off, not just in standby or idle if (!wantAwake && !enabled && powerState != GPS_OFF) { setGPSPower(false, false, 0); return; } // If GPS power state needs to change - if ((wantAwake && powerState != GPS_AWAKE) || (!wantAwake && powerState == GPS_AWAKE)) { + if ((wantAwake && powerState != GPS_ACTIVE) || (!wantAwake && powerState == GPS_ACTIVE)) { LOG_DEBUG("WANT GPS=%d\n", wantAwake); // Calculate how long it takes to get a GPS lock if (wantAwake) { + // Record the time we start looking for a lock lastWakeStartMsec = millis(); } else { + // Record by how much we missed our ideal target postion.gps_update_interval (for logging only) + // Need to calculate this before we update lastSleepStartMsec, to make the new prediction + int32_t lateByMsec = (int32_t)(millis() - lastSleepStartMsec) - (int32_t)getSleepTime(); + + // Record the time we finish looking for a lock lastSleepStartMsec = millis(); - if (GPSCycles == 1) { // Skipping initial lock time, as it will likely be much longer than average - averageLockTime = lastSleepStartMsec - lastWakeStartMsec; - } else if (GPSCycles > 1) { - averageLockTime += ((int32_t)(lastSleepStartMsec - lastWakeStartMsec) - averageLockTime) / (int32_t)GPSCycles; + + // How long did it take to get GPS lock this time? + uint32_t lockTime = lastSleepStartMsec - lastWakeStartMsec; + + // Update the lock-time prediction + // Used pre-emptively, attempting to hit target of gps.position_update_interval + switch (GPSCycles) { + case 0: + LOG_DEBUG("Initial GPS lock took %ds\n", lockTime / 1000); + break; + case 1: + predictedLockTime = lockTime; // Avoid slow ramp-up - start with a real value + LOG_DEBUG("GPS Lock took %ds\n", lockTime / 1000); + break; + default: + // Predict lock-time using exponential smoothing: respond slowly to changes + predictedLockTime = (lockTime * 0.2) + (predictedLockTime * 0.8); // Latest lock time has 20% weight on prediction + LOG_INFO("GPS Lock took %ds. %s by %ds. Next lock predicted to take %ds.\n", lockTime / 1000, + (lateByMsec > 0) ? "Late" : "Early", abs(lateByMsec) / 1000, predictedLockTime / 1000); } GPSCycles++; - LOG_DEBUG("GPS Lock took %d, average %d\n", (lastSleepStartMsec - lastWakeStartMsec) / 1000, averageLockTime / 1000); } + // How long to wait before attempting next GPS update + // Aims to hit position.gps_update_interval by using the lock-time prediction + uint32_t compensatedSleepTime = (getSleepTime() > predictedLockTime) ? (getSleepTime() - predictedLockTime) : 0; + // If long interval between updates: power off between updates - if ((int32_t)getSleepTime() - averageLockTime > GPS_STANDBY_THRESHOLD_MINUTES * MS_IN_MINUTE) { - setGPSPower(wantAwake, false, getSleepTime() - averageLockTime); - return; + if (compensatedSleepTime > GPS_STANDBY_THRESHOLD_MINUTES * MS_IN_MINUTE) { + setGPSPower(wantAwake, false, getSleepTime() - predictedLockTime); } - // If waking frequently: standby only. Would use more power trying to reacquire lock each time - else if ((int32_t)getSleepTime() - averageLockTime > 10000) { // 10 seconds is enough for standby + // If waking relatively frequently: don't power off. Would use more energy trying to reacquire lock each time + // We'll either use a "powered-on" standby, or just wait it out, depending on how soon the next update is due + // Will decide which inside setGPSPower method + else { #ifdef GPS_UC6580 - setGPSPower(wantAwake, false, getSleepTime() - averageLockTime); + setGPSPower(wantAwake, false, compensatedSleepTime); #else - setGPSPower(wantAwake, true, getSleepTime() - averageLockTime); + setGPSPower(wantAwake, true, compensatedSleepTime); #endif - return; } - - // Gradually recover from an abnormally long "time to get lock" - if (averageLockTime > 20000) { - averageLockTime -= 1000; // eventually want to sleep again. - } - - // Make sure we don't have a fallthrough where GPS is stuck off - if (wantAwake) - setGPSPower(true, true, 0); } } @@ -1033,14 +1062,14 @@ int32_t GPS::runOnce() uint32_t timeAsleep = now - lastSleepStartMsec; auto sleepTime = getSleepTime(); - if (powerState != GPS_AWAKE && (sleepTime != UINT32_MAX) && - ((timeAsleep > sleepTime) || (isInPowersave && timeAsleep > (sleepTime - averageLockTime)))) { + if (powerState != GPS_ACTIVE && (sleepTime != UINT32_MAX) && + ((timeAsleep > sleepTime) || (isInPowersave && timeAsleep > (sleepTime - predictedLockTime)))) { // We now want to be awake - so wake up the GPS setAwake(true); } // While we are awake - if (powerState == GPS_AWAKE) { + if (powerState == GPS_ACTIVE) { // LOG_DEBUG("looking for location\n"); // If we've already set time from the GPS, no need to ask the GPS bool gotTime = (getRTCQuality() >= RTCQualityGPS); @@ -1086,7 +1115,7 @@ int32_t GPS::runOnce() // 9600bps is approx 1 byte per msec, so considering our buffer size we never need to wake more often than 200ms // if not awake we can run super infrquently (once every 5 secs?) to see if we need to wake. - return (powerState == GPS_AWAKE) ? GPS_THREAD_INTERVAL : 5000; + return (powerState == GPS_ACTIVE) ? GPS_THREAD_INTERVAL : 5000; } // clear the GPS rx buffer as quickly as possible @@ -1617,9 +1646,9 @@ bool GPS::whileIdle() { unsigned int charsInBuf = 0; bool isValid = false; - if (powerState != GPS_AWAKE) { + if (powerState != GPS_ACTIVE) { clearBuffer(); - return (powerState == GPS_AWAKE); + return (powerState == GPS_ACTIVE); } #ifdef SERIAL_BUFFER_SIZE if (_serial_gps->available() >= SERIAL_BUFFER_SIZE - 1) { @@ -1650,6 +1679,10 @@ bool GPS::whileIdle() } void GPS::enable() { + // Clear the old lock-time prediction + GPSCycles = 0; + predictedLockTime = 0; + enabled = true; setInterval(GPS_THREAD_INTERVAL); setAwake(true); diff --git a/src/gps/GPS.h b/src/gps/GPS.h index e9ec111a75..34e1844c35 100644 --- a/src/gps/GPS.h +++ b/src/gps/GPS.h @@ -39,9 +39,10 @@ typedef enum { } GPS_RESPONSE; enum GPSPowerState : uint8_t { - GPS_OFF = 0, - GPS_AWAKE = 1, - GPS_STANDBY = 2, + GPS_OFF = 0, // Physically powered off + GPS_ACTIVE = 1, // Awake and want a position + GPS_STANDBY = 2, // Physically powered on, but soft-sleeping + GPS_IDLE = 3, // Awake, but not wanting another position yet }; // Generate a string representation of DOP @@ -72,7 +73,7 @@ class GPS : private concurrency::OSThread uint32_t rx_gpio = 0; uint32_t tx_gpio = 0; uint32_t en_gpio = 0; - int32_t averageLockTime = 0; + int32_t predictedLockTime = 0; uint32_t GPSCycles = 0; int speedSelect = 0; @@ -93,7 +94,7 @@ class GPS : private concurrency::OSThread bool GPSInitFinished = false; // Init thread finished? bool GPSInitStarted = false; // Init thread finished? - GPSPowerState powerState = GPS_OFF; // GPS_AWAKE if we want a location right now + GPSPowerState powerState = GPS_OFF; // GPS_ACTIVE if we want a location right now uint8_t numSatellites = 0; From 1a5227c8266ee0eaac5f6b4388f62706648db72a Mon Sep 17 00:00:00 2001 From: Wolfgang Nagele Date: Fri, 14 Jun 2024 17:45:16 +0200 Subject: [PATCH 25/65] Ensure data directory ownership is with mesh user (#4097) --- Dockerfile | 1 + 1 file changed, 1 insertion(+) diff --git a/Dockerfile b/Dockerfile index fee6c62d4b..08cb3925d2 100644 --- a/Dockerfile +++ b/Dockerfile @@ -48,6 +48,7 @@ USER mesh WORKDIR /home/mesh COPY --from=builder /tmp/firmware/release/meshtasticd /home/mesh/ +RUN mkdir data VOLUME /home/mesh/data CMD [ "sh", "-cx", "./meshtasticd -d /home/mesh/data --hwid=${HWID:-$RANDOM}" ] From 8b8e056b7bcce9f4ee3e4256c6c94a724e1d190f Mon Sep 17 00:00:00 2001 From: Ben Meadors Date: Fri, 14 Jun 2024 16:27:49 -0500 Subject: [PATCH 26/65] Added (excluded) Dropzone Module for more comprehensive module example (#4098) * DropzoneModule hello world * Buttoning things up * Exclude by default * Upstream refs * Cleanup * Add modules folder to path * Case and path matters * Exclude from header * Guard --- platformio.ini | 1 + src/modules/DropzoneModule.cpp | 95 +++++++++++++++++++ src/modules/DropzoneModule.h | 37 ++++++++ src/modules/Modules.cpp | 9 ++ .../Telemetry/Sensor/DFRobotLarkSensor.h | 5 + src/modules/Telemetry/UnitConversions.cpp | 21 ++++ src/modules/Telemetry/UnitConversions.h | 10 ++ 7 files changed, 178 insertions(+) create mode 100644 src/modules/DropzoneModule.cpp create mode 100644 src/modules/DropzoneModule.h create mode 100644 src/modules/Telemetry/UnitConversions.cpp create mode 100644 src/modules/Telemetry/UnitConversions.h diff --git a/platformio.ini b/platformio.ini index 34471fc54e..0de3e25c92 100644 --- a/platformio.ini +++ b/platformio.ini @@ -73,6 +73,7 @@ build_flags = -Wno-missing-field-initializers -DRADIOLIB_EXCLUDE_FSK4 -DRADIOLIB_EXCLUDE_APRS -DRADIOLIB_EXCLUDE_LORAWAN + -DMESHTASTIC_EXCLUDE_DROPZONE=1 monitor_speed = 115200 diff --git a/src/modules/DropzoneModule.cpp b/src/modules/DropzoneModule.cpp new file mode 100644 index 0000000000..8c5b5dcdd8 --- /dev/null +++ b/src/modules/DropzoneModule.cpp @@ -0,0 +1,95 @@ +#if !MESHTASTIC_EXCLUDE_DROPZONE + +#include "DropzoneModule.h" +#include "MeshService.h" +#include "configuration.h" +#include "gps/GeoCoord.h" +#include "gps/RTC.h" +#include "main.h" + +#include + +#include "modules/Telemetry/Sensor/DFRobotLarkSensor.h" +#include "modules/Telemetry/UnitConversions.h" + +#include + +DropzoneModule *dropzoneModule; + +int32_t DropzoneModule::runOnce() +{ + // Send on a 5 second delay from receiving the matching request + if (startSendConditions != 0 && (startSendConditions + 5000U) < millis()) { + service.sendToMesh(sendConditions(), RX_SRC_LOCAL); + startSendConditions = 0; + } + // Run every second to check if we need to send conditions + return 1000; +} + +ProcessMessage DropzoneModule::handleReceived(const meshtastic_MeshPacket &mp) +{ + auto &p = mp.decoded; + char matchCompare[54]; + auto incomingMessage = reinterpret_cast(p.payload.bytes); + sprintf(matchCompare, "%s conditions", owner.short_name); + if (strncasecmp(incomingMessage, matchCompare, strlen(matchCompare)) == 0) { + LOG_DEBUG("Received dropzone conditions request\n"); + startSendConditions = millis(); + } + + sprintf(matchCompare, "%s conditions", owner.long_name); + if (strncasecmp(incomingMessage, matchCompare, strlen(matchCompare)) == 0) { + LOG_DEBUG("Received dropzone conditions request\n"); + startSendConditions = millis(); + } + return ProcessMessage::CONTINUE; +} + +meshtastic_MeshPacket *DropzoneModule::sendConditions() +{ + char replyStr[200]; + /* + CLOSED @ {HH:MM:SS}z + Wind 2 kts @ 125° + 29.25 inHg 72°C + */ + uint32_t rtc_sec = getValidTime(RTCQuality::RTCQualityDevice, true); + int hour = 0, min = 0, sec = 0; + if (rtc_sec > 0) { + long hms = rtc_sec % SEC_PER_DAY; + hms = (hms + SEC_PER_DAY) % SEC_PER_DAY; + + hour = hms / SEC_PER_HOUR; + min = (hms % SEC_PER_HOUR) / SEC_PER_MIN; + sec = (hms % SEC_PER_HOUR) % SEC_PER_MIN; + } + + // Check if the dropzone is open or closed by reading the analog pin + // If pin is connected to GND (below 100 should be lower than floating voltage), + // the dropzone is open + auto dropzoneStatus = analogRead(A1) < 100 ? "OPEN" : "CLOSED"; + auto reply = allocDataPacket(); + + auto node = nodeDB->getMeshNode(nodeDB->getNodeNum()); + if (sensor.hasSensor()) { + meshtastic_Telemetry telemetry = meshtastic_Telemetry_init_zero; + sensor.getMetrics(&telemetry); + auto windSpeed = UnitConversions::MetersPerSecondToKnots(telemetry.variant.environment_metrics.wind_speed); + auto windDirection = telemetry.variant.environment_metrics.wind_direction; + auto temp = telemetry.variant.environment_metrics.temperature; + auto baro = UnitConversions::HectoPascalToInchesOfMercury(telemetry.variant.environment_metrics.barometric_pressure); + sprintf(replyStr, "%s @ %02d:%02d:%02dz\nWind %.2f kts @ %d°\nBaro %.2f inHg %.2f°C", dropzoneStatus, hour, min, sec, + windSpeed, windDirection, baro, temp); + } else { + LOG_ERROR("No sensor found\n"); + sprintf(replyStr, "%s @ %02d:%02d:%02d\nNo sensor found", dropzoneStatus, hour, min, sec); + } + LOG_DEBUG("Conditions reply: %s\n", replyStr); + reply->decoded.payload.size = strlen(replyStr); // You must specify how many bytes are in the reply + memcpy(reply->decoded.payload.bytes, replyStr, reply->decoded.payload.size); + + return reply; +} + +#endif \ No newline at end of file diff --git a/src/modules/DropzoneModule.h b/src/modules/DropzoneModule.h new file mode 100644 index 0000000000..28f54ee0f2 --- /dev/null +++ b/src/modules/DropzoneModule.h @@ -0,0 +1,37 @@ +#pragma once +#if !MESHTASTIC_EXCLUDE_DROPZONE +#include "SinglePortModule.h" +#include "modules/Telemetry/Sensor/DFRobotLarkSensor.h" + +/** + * An example module that replies to a message with the current conditions + * and status at the dropzone when it receives a text message mentioning it's name followed by "conditions" + */ +class DropzoneModule : public SinglePortModule, private concurrency::OSThread +{ + DFRobotLarkSensor sensor; + + public: + /** Constructor + * name is for debugging output + */ + DropzoneModule() : SinglePortModule("dropzone", meshtastic_PortNum_TEXT_MESSAGE_APP), concurrency::OSThread("DropzoneModule") + { + // Set up the analog pin for reading the dropzone status + pinMode(PIN_A1, INPUT); + } + + virtual int32_t runOnce() override; + + protected: + /** Called to handle a particular incoming message + */ + virtual ProcessMessage handleReceived(const meshtastic_MeshPacket &mp) override; + + private: + meshtastic_MeshPacket *sendConditions(); + uint32_t startSendConditions = 0; +}; + +extern DropzoneModule *dropzoneModule; +#endif \ No newline at end of file diff --git a/src/modules/Modules.cpp b/src/modules/Modules.cpp index e6c44fae64..1b4bbc3b4a 100644 --- a/src/modules/Modules.cpp +++ b/src/modules/Modules.cpp @@ -70,6 +70,11 @@ #include "modules/SerialModule.h" #endif #endif + +#if !MESHTASTIC_EXCLUDE_DROPZONE +#include "modules/DropzoneModule.h" +#endif + /** * Create module instances here. If you are adding a new module, you must 'new' it here (or somewhere else) */ @@ -100,6 +105,10 @@ void setupModules() #if !MESHTASTIC_EXCLUDE_ATAK atakPluginModule = new AtakPluginModule(); #endif + +#if !MESHTASTIC_EXCLUDE_DROPZONE + dropzoneModule = new DropzoneModule(); +#endif // Note: if the rest of meshtastic doesn't need to explicitly use your module, you do not need to assign the instance // to a global variable. diff --git a/src/modules/Telemetry/Sensor/DFRobotLarkSensor.h b/src/modules/Telemetry/Sensor/DFRobotLarkSensor.h index b26d690b15..7a988e84a5 100644 --- a/src/modules/Telemetry/Sensor/DFRobotLarkSensor.h +++ b/src/modules/Telemetry/Sensor/DFRobotLarkSensor.h @@ -1,3 +1,7 @@ +#pragma once + +#ifndef _MT_DFROBOTLARKSENSOR_H +#define _MT_DFROBOTLARKSENSOR_H #include "configuration.h" #if !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR @@ -21,4 +25,5 @@ class DFRobotLarkSensor : public TelemetrySensor virtual bool getMetrics(meshtastic_Telemetry *measurement) override; }; +#endif #endif \ No newline at end of file diff --git a/src/modules/Telemetry/UnitConversions.cpp b/src/modules/Telemetry/UnitConversions.cpp new file mode 100644 index 0000000000..9f40de40fc --- /dev/null +++ b/src/modules/Telemetry/UnitConversions.cpp @@ -0,0 +1,21 @@ +#include "UnitConversions.h" + +float UnitConversions::CelsiusToFahrenheit(float celcius) +{ + return (celcius * 9) / 5 + 32; +} + +float UnitConversions::MetersPerSecondToKnots(float metersPerSecond) +{ + return metersPerSecond * 1.94384; +} + +float UnitConversions::MetersPerSecondToMilesPerHour(float metersPerSecond) +{ + return metersPerSecond * 2.23694; +} + +float UnitConversions::HectoPascalToInchesOfMercury(float hectoPascal) +{ + return hectoPascal * 0.029529983071445; +} diff --git a/src/modules/Telemetry/UnitConversions.h b/src/modules/Telemetry/UnitConversions.h new file mode 100644 index 0000000000..60f9b664ae --- /dev/null +++ b/src/modules/Telemetry/UnitConversions.h @@ -0,0 +1,10 @@ +#pragma once + +class UnitConversions +{ + public: + static float CelsiusToFahrenheit(float celcius); + static float MetersPerSecondToKnots(float metersPerSecond); + static float MetersPerSecondToMilesPerHour(float metersPerSecond); + static float HectoPascalToInchesOfMercury(float hectoPascal); +}; From e55604b8e5e233548c9e160ed008be9d16b647bc Mon Sep 17 00:00:00 2001 From: "Daniel.Cao" <144674500+DanielCao0@users.noreply.github.com> Date: Sat, 15 Jun 2024 08:36:20 +0800 Subject: [PATCH 27/65] rak10701: support touchscreen (#4104) * Add the touch screen driver RAK10701 platform, lib_deps https://github.com/RAKWireless/RAK14014-FT6336U * Added RAK10701 touch screen virtual keyboard, supporting cannedMessageModule free text --- src/graphics/TFTDisplay.cpp | 25 +++++++++++++++++++++++++ src/modules/CannedMessageModule.cpp | 28 ++++++++++++++-------------- src/modules/CannedMessageModule.h | 4 ++-- variants/rak10701/platformio.ini | 2 ++ variants/rak10701/variant.h | 8 ++++---- 5 files changed, 47 insertions(+), 20 deletions(-) diff --git a/src/graphics/TFTDisplay.cpp b/src/graphics/TFTDisplay.cpp index b19e402b82..39099bd737 100644 --- a/src/graphics/TFTDisplay.cpp +++ b/src/graphics/TFTDisplay.cpp @@ -118,7 +118,15 @@ static LGFX *tft = nullptr; #elif defined(RAK14014) #include +#include TFT_eSPI *tft = nullptr; +FT6336U ft6336u; + +static uint8_t _rak14014_touch_int = false; // TP interrupt generation flag. +static void rak14014_tpIntHandle(void) +{ + _rak14014_touch_int = true; +} #elif defined(ST7789_CS) #include // Graphics and font library for ST7735 driver chip @@ -642,8 +650,12 @@ void TFTDisplay::sendCommand(uint8_t com) void TFTDisplay::setDisplayBrightness(uint8_t _brightness) { +#ifdef RAK14014 + //todo +#else tft->setBrightness(_brightness); LOG_DEBUG("Brightness is set to value: %i \n", _brightness); +#endif } void TFTDisplay::flipScreenVertically() @@ -657,6 +669,7 @@ void TFTDisplay::flipScreenVertically() bool TFTDisplay::hasTouch(void) { #ifdef RAK14014 + return true; #elif !defined(M5STACK) return tft->touch() != nullptr; #else @@ -667,6 +680,15 @@ bool TFTDisplay::hasTouch(void) bool TFTDisplay::getTouch(int16_t *x, int16_t *y) { #ifdef RAK14014 + if(_rak14014_touch_int) { + _rak14014_touch_int = false; + /* The X and Y axes have to be switched */ + *y = ft6336u.read_touch1_x(); + *x = TFT_HEIGHT - ft6336u.read_touch1_y(); + return true; + } else { + return false; + } #elif !defined(M5STACK) return tft->getTouch(x, y); #else @@ -717,6 +739,9 @@ bool TFTDisplay::connect() tft->setRotation(1); tft->setSwapBytes(true); // tft->fillScreen(TFT_BLACK); + ft6336u.begin(); + pinMode(SCREEN_TOUCH_INT, INPUT_PULLUP); + attachInterrupt(digitalPinToInterrupt(SCREEN_TOUCH_INT), rak14014_tpIntHandle, FALLING); #elif defined(T_DECK) || defined(PICOMPUTER_S3) || defined(CHATTER_2) tft->setRotation(1); // T-Deck has the TFT in landscape #elif defined(T_WATCH_S3) diff --git a/src/modules/CannedMessageModule.cpp b/src/modules/CannedMessageModule.cpp index 9b993ae5a3..f513e045f4 100644 --- a/src/modules/CannedMessageModule.cpp +++ b/src/modules/CannedMessageModule.cpp @@ -49,7 +49,7 @@ CannedMessageModule::CannedMessageModule() LOG_INFO("CannedMessageModule is enabled\n"); // T-Watch interface currently has no way to select destination type, so default to 'node' -#ifdef T_WATCH_S3 +#if defined(T_WATCH_S3) || defined(RAK14014) this->destSelect = CANNED_MESSAGE_DESTINATION_TYPE_NODE; #endif @@ -75,7 +75,7 @@ int CannedMessageModule::splitConfiguredMessages() String messages = cannedMessageModuleConfig.messages; -#ifdef T_WATCH_S3 +#if defined(T_WATCH_S3) || defined(RAK14014) String separator = messages.length() ? "|" : ""; messages = "[---- Free Text ----]" + separator + messages; @@ -144,7 +144,7 @@ int CannedMessageModule::handleInputEvent(const InputEvent *event) } if (event->inputEvent == static_cast(meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_SELECT)) { -#ifdef T_WATCH_S3 +#if defined(T_WATCH_S3) || defined(RAK14014) if (this->currentMessageIndex == 0) { this->runState = CANNED_MESSAGE_RUN_STATE_FREETEXT; @@ -170,7 +170,7 @@ int CannedMessageModule::handleInputEvent(const InputEvent *event) e.frameChanged = true; this->currentMessageIndex = -1; -#ifndef T_WATCH_S3 +#if !defined(T_WATCH_S3) && !defined(RAK14014) this->freetext = ""; // clear freetext this->cursor = 0; this->destSelect = CANNED_MESSAGE_DESTINATION_TYPE_NONE; @@ -183,7 +183,7 @@ int CannedMessageModule::handleInputEvent(const InputEvent *event) (event->inputEvent == static_cast(meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_LEFT)) || (event->inputEvent == static_cast(meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_RIGHT))) { -#ifdef T_WATCH_S3 +#if defined(T_WATCH_S3) || defined(RAK14014) if (event->inputEvent == static_cast(meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_LEFT)) { this->payload = 0xb4; } else if (event->inputEvent == static_cast(meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_RIGHT)) { @@ -283,7 +283,7 @@ int CannedMessageModule::handleInputEvent(const InputEvent *event) } } -#ifdef T_WATCH_S3 +#if defined(T_WATCH_S3) || defined(RAK14014) if (this->runState == CANNED_MESSAGE_RUN_STATE_FREETEXT) { String keyTapped = keyForCoordinates(event->touchX, event->touchY); @@ -404,7 +404,7 @@ int32_t CannedMessageModule::runOnce() this->freetext = ""; // clear freetext this->cursor = 0; -#ifndef T_WATCH_S3 +#if !defined(T_WATCH_S3) && !defined(RAK14014) this->destSelect = CANNED_MESSAGE_DESTINATION_TYPE_NONE; #endif @@ -417,7 +417,7 @@ int32_t CannedMessageModule::runOnce() this->freetext = ""; // clear freetext this->cursor = 0; -#ifndef T_WATCH_S3 +#if !defined(T_WATCH_S3) && !defined(RAK14014) this->destSelect = CANNED_MESSAGE_DESTINATION_TYPE_NONE; #endif @@ -437,7 +437,7 @@ int32_t CannedMessageModule::runOnce() powerFSM.trigger(EVENT_PRESS); return INT32_MAX; } else { -#ifdef T_WATCH_S3 +#if defined(T_WATCH_S3) || defined(RAK14014) sendText(this->dest, indexChannels[this->channel], this->messages[this->currentMessageIndex], true); #else sendText(NODENUM_BROADCAST, channels.getPrimaryIndex(), this->messages[this->currentMessageIndex], true); @@ -454,7 +454,7 @@ int32_t CannedMessageModule::runOnce() this->freetext = ""; // clear freetext this->cursor = 0; -#ifndef T_WATCH_S3 +#if !defined(T_WATCH_S3) && !defined(RAK14014) this->destSelect = CANNED_MESSAGE_DESTINATION_TYPE_NONE; #endif @@ -471,7 +471,7 @@ int32_t CannedMessageModule::runOnce() this->freetext = ""; // clear freetext this->cursor = 0; -#ifndef T_WATCH_S3 +#if !defined(T_WATCH_S3) && !defined(RAK14014) this->destSelect = CANNED_MESSAGE_DESTINATION_TYPE_NONE; #endif @@ -484,7 +484,7 @@ int32_t CannedMessageModule::runOnce() this->freetext = ""; // clear freetext this->cursor = 0; -#ifndef T_WATCH_S3 +#if !defined(T_WATCH_S3) && !defined(RAK14014) this->destSelect = CANNED_MESSAGE_DESTINATION_TYPE_NONE; #endif @@ -714,7 +714,7 @@ void CannedMessageModule::showTemporaryMessage(const String &message) setIntervalFromNow(2000); } -#ifdef T_WATCH_S3 +#if defined(T_WATCH_S3) || defined(RAK14014) String CannedMessageModule::keyForCoordinates(uint x, uint y) { @@ -949,7 +949,7 @@ void CannedMessageModule::drawFrame(OLEDDisplay *display, OLEDDisplayUiState *st display->drawString(10 + x, 0 + y + FONT_HEIGHT_SMALL, "Canned Message\nModule disabled."); } else if (cannedMessageModule->runState == CANNED_MESSAGE_RUN_STATE_FREETEXT) { -#ifdef T_WATCH_S3 +#if defined(T_WATCH_S3) || defined(RAK14014) drawKeyboard(display, state, 0, 0); #else diff --git a/src/modules/CannedMessageModule.h b/src/modules/CannedMessageModule.h index 43897e782b..00e8c2bf9a 100644 --- a/src/modules/CannedMessageModule.h +++ b/src/modules/CannedMessageModule.h @@ -98,7 +98,7 @@ class CannedMessageModule : public SinglePortModule, public Observable Date: Fri, 14 Jun 2024 19:53:47 -0500 Subject: [PATCH 28/65] Trunk --- src/graphics/TFTDisplay.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/graphics/TFTDisplay.cpp b/src/graphics/TFTDisplay.cpp index 39099bd737..8ea90c5232 100644 --- a/src/graphics/TFTDisplay.cpp +++ b/src/graphics/TFTDisplay.cpp @@ -117,8 +117,8 @@ class LGFX : public lgfx::LGFX_Device static LGFX *tft = nullptr; #elif defined(RAK14014) -#include #include +#include TFT_eSPI *tft = nullptr; FT6336U ft6336u; @@ -651,7 +651,7 @@ void TFTDisplay::sendCommand(uint8_t com) void TFTDisplay::setDisplayBrightness(uint8_t _brightness) { #ifdef RAK14014 - //todo + // todo #else tft->setBrightness(_brightness); LOG_DEBUG("Brightness is set to value: %i \n", _brightness); @@ -680,7 +680,7 @@ bool TFTDisplay::hasTouch(void) bool TFTDisplay::getTouch(int16_t *x, int16_t *y) { #ifdef RAK14014 - if(_rak14014_touch_int) { + if (_rak14014_touch_int) { _rak14014_touch_int = false; /* The X and Y axes have to be switched */ *y = ft6336u.read_touch1_x(); @@ -738,7 +738,7 @@ bool TFTDisplay::connect() #elif defined(RAK14014) tft->setRotation(1); tft->setSwapBytes(true); -// tft->fillScreen(TFT_BLACK); + // tft->fillScreen(TFT_BLACK); ft6336u.begin(); pinMode(SCREEN_TOUCH_INT, INPUT_PULLUP); attachInterrupt(digitalPinToInterrupt(SCREEN_TOUCH_INT), rak14014_tpIntHandle, FALLING); From 21d47adb8d23be4e1f5054b3b89b12b13205149f Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Sat, 15 Jun 2024 09:45:33 -0500 Subject: [PATCH 29/65] [create-pull-request] automated change (#4114) Co-authored-by: thebentern <9000580+thebentern@users.noreply.github.com> --- protobufs | 2 +- src/mesh/generated/meshtastic/admin.pb.h | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/protobufs b/protobufs index ab576a4a12..dc066c89f7 160000 --- a/protobufs +++ b/protobufs @@ -1 +1 @@ -Subproject commit ab576a4a122c1a1d0a3c2235b0a0cf3bd4a83c65 +Subproject commit dc066c89f73fce882e5a47648cba18a1967a7f56 diff --git a/src/mesh/generated/meshtastic/admin.pb.h b/src/mesh/generated/meshtastic/admin.pb.h index 2a209ad0a9..d0e643dffc 100644 --- a/src/mesh/generated/meshtastic/admin.pb.h +++ b/src/mesh/generated/meshtastic/admin.pb.h @@ -135,6 +135,8 @@ typedef struct _meshtastic_AdminMessage { bool enter_dfu_mode_request; /* Delete the file by the specified path from the device */ char delete_file_request[201]; + /* Set zero and offset for scale chips */ + uint32_t set_scale; /* Set the owner for this node */ meshtastic_User set_owner; /* Set channels (using the new API). @@ -238,6 +240,7 @@ extern "C" { #define meshtastic_AdminMessage_get_node_remote_hardware_pins_response_tag 20 #define meshtastic_AdminMessage_enter_dfu_mode_request_tag 21 #define meshtastic_AdminMessage_delete_file_request_tag 22 +#define meshtastic_AdminMessage_set_scale_tag 23 #define meshtastic_AdminMessage_set_owner_tag 32 #define meshtastic_AdminMessage_set_channel_tag 33 #define meshtastic_AdminMessage_set_config_tag 34 @@ -281,6 +284,7 @@ X(a, STATIC, ONEOF, BOOL, (payload_variant,get_node_remote_hardware_pin X(a, STATIC, ONEOF, MESSAGE, (payload_variant,get_node_remote_hardware_pins_response,get_node_remote_hardware_pins_response), 20) \ X(a, STATIC, ONEOF, BOOL, (payload_variant,enter_dfu_mode_request,enter_dfu_mode_request), 21) \ X(a, STATIC, ONEOF, STRING, (payload_variant,delete_file_request,delete_file_request), 22) \ +X(a, STATIC, ONEOF, UINT32, (payload_variant,set_scale,set_scale), 23) \ X(a, STATIC, ONEOF, MESSAGE, (payload_variant,set_owner,set_owner), 32) \ X(a, STATIC, ONEOF, MESSAGE, (payload_variant,set_channel,set_channel), 33) \ X(a, STATIC, ONEOF, MESSAGE, (payload_variant,set_config,set_config), 34) \ From 32702e2750cd8b85d2855fb443218beff920e039 Mon Sep 17 00:00:00 2001 From: Ben Meadors Date: Sat, 15 Jun 2024 09:46:15 -0500 Subject: [PATCH 30/65] Fix compiler warnings (#4112) --- src/AccelerometerThread.h | 1 + src/gps/GPS.h | 2 +- variants/rak4631/platformio.ini | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/AccelerometerThread.h b/src/AccelerometerThread.h index f03752cad7..f45511cca3 100644 --- a/src/AccelerometerThread.h +++ b/src/AccelerometerThread.h @@ -138,6 +138,7 @@ class AccelerometerThread : public concurrency::OSThread float heading = FusionCompassCalculateHeading(FusionConventionNed, ga, ma); switch (config.display.compass_orientation) { + case meshtastic_Config_DisplayConfig_CompassOrientation_DEGREES_0_INVERTED: case meshtastic_Config_DisplayConfig_CompassOrientation_DEGREES_0: break; case meshtastic_Config_DisplayConfig_CompassOrientation_DEGREES_90: diff --git a/src/gps/GPS.h b/src/gps/GPS.h index 34e1844c35..55bd42d0fb 100644 --- a/src/gps/GPS.h +++ b/src/gps/GPS.h @@ -73,7 +73,7 @@ class GPS : private concurrency::OSThread uint32_t rx_gpio = 0; uint32_t tx_gpio = 0; uint32_t en_gpio = 0; - int32_t predictedLockTime = 0; + uint32_t predictedLockTime = 0; uint32_t GPSCycles = 0; int speedSelect = 0; diff --git a/variants/rak4631/platformio.ini b/variants/rak4631/platformio.ini index 24f209b01a..4870d4b68e 100644 --- a/variants/rak4631/platformio.ini +++ b/variants/rak4631/platformio.ini @@ -16,7 +16,7 @@ lib_deps = melopero/Melopero RV3028@^1.1.0 https://github.com/RAKWireless/RAK13800-W5100S.git#1.0.2 rakwireless/RAKwireless NCP5623 RGB LED library@^1.0.2 - beegee-tokyo/RAKwireless RAK12034@^1.0.0 + https://github.com/meshtastic/RAK12034-BMX160.git#4821355fb10390ba8557dc43ca29a023bcfbb9d9 debug_tool = jlink ; If not set we will default to uploading over serial (first it forces bootloader entry by talking 1200bps to cdcacm) ;upload_protocol = jlink \ No newline at end of file From b1cf5778b4bc07ba5132125d491c8f817651781c Mon Sep 17 00:00:00 2001 From: Ben Meadors Date: Sat, 15 Jun 2024 09:46:31 -0500 Subject: [PATCH 31/65] Update nrf52 platform to 10.5.0 (#4113) --- arch/nrf52/nrf52.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/nrf52/nrf52.ini b/arch/nrf52/nrf52.ini index f41ef0edc2..1a371e9208 100644 --- a/arch/nrf52/nrf52.ini +++ b/arch/nrf52/nrf52.ini @@ -1,6 +1,6 @@ [nrf52_base] ; Instead of the standard nordicnrf52 platform, we use our fork which has our added variant files -platform = platformio/nordicnrf52@^10.4.0 +platform = platformio/nordicnrf52@^10.5.0 extends = arduino_base build_type = debug From 96be051bff6d18c45218d39d1a668e6a56cef8a0 Mon Sep 17 00:00:00 2001 From: todd-herbert Date: Sun, 16 Jun 2024 07:58:46 +1200 Subject: [PATCH 32/65] Screensaver validates short name (#4115) --- src/graphics/Screen.cpp | 37 ++++++++++++++++++++++++++++++++----- 1 file changed, 32 insertions(+), 5 deletions(-) diff --git a/src/graphics/Screen.cpp b/src/graphics/Screen.cpp index 5a892bbfbf..60168cffcf 100644 --- a/src/graphics/Screen.cpp +++ b/src/graphics/Screen.cpp @@ -277,6 +277,30 @@ static void drawFunctionOverlay(OLEDDisplay *display, OLEDDisplayUiState *state) } } +/// Check if the display can render a string (detect special chars; emoji) +static bool haveGlyphs(const char *str) +{ +#if defined(OLED_UA) || defined(OLED_RU) + // Don't want to make any assumptions about custom language support + return true; +#endif + + // Check each character with the lookup function for the OLED library + // We're not really meant to use this directly.. + bool have = true; + for (uint16_t i = 0; i < strlen(str); i++) { + uint8_t result = Screen::customFontTableLookup((uint8_t)str[i]); + // If font doesn't support a character, it is substituted for ¿ + if (result == 191 && (uint8_t)str[i] != 191) { + have = false; + break; + } + } + + LOG_DEBUG("haveGlyphs=%d\n", have); + return have; +} + #ifdef USE_EINK /// Used on eink displays while in deep sleep static void drawDeepSleepScreen(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y) @@ -301,14 +325,15 @@ static void drawScreensaverOverlay(OLEDDisplay *display, OLEDDisplayUiState *sta display->setTextAlignment(TEXT_ALIGN_LEFT); const char *pauseText = "Screen Paused"; const char *idText = owner.short_name; + const bool useId = haveGlyphs(idText); // This bool is used to hide the idText box if we can't render the short name constexpr uint16_t padding = 5; constexpr uint8_t dividerGap = 1; constexpr uint8_t imprecision = 5; // How far the box origins can drift from center. Combat burn-in. // Dimensions - const uint16_t idTextWidth = display->getStringWidth(idText, strlen(idText)); + const uint16_t idTextWidth = display->getStringWidth(idText, strlen(idText), true); // "true": handle utf8 chars const uint16_t pauseTextWidth = display->getStringWidth(pauseText, strlen(pauseText)); - const uint16_t boxWidth = padding + idTextWidth + padding + padding + pauseTextWidth + padding; + const uint16_t boxWidth = padding + (useId ? idTextWidth + padding + padding : 0) + pauseTextWidth + padding; const uint16_t boxHeight = padding + FONT_HEIGHT_SMALL + padding; // Position @@ -318,7 +343,7 @@ static void drawScreensaverOverlay(OLEDDisplay *display, OLEDDisplayUiState *sta const int16_t boxBottom = boxTop + boxHeight - 1; const int16_t idTextLeft = boxLeft + padding; const int16_t idTextTop = boxTop + padding; - const int16_t pauseTextLeft = boxLeft + padding + idTextWidth + padding + padding; + const int16_t pauseTextLeft = boxLeft + (useId ? padding + idTextWidth + padding : 0) + padding; const int16_t pauseTextTop = boxTop + padding; const int16_t dividerX = boxLeft + padding + idTextWidth + padding; const int16_t dividerTop = boxTop + 1 + dividerGap; @@ -331,12 +356,14 @@ static void drawScreensaverOverlay(OLEDDisplay *display, OLEDDisplayUiState *sta display->drawRect(boxLeft, boxTop, boxWidth, boxHeight); // Draw: Text - display->drawString(idTextLeft, idTextTop, idText); + if (useId) + display->drawString(idTextLeft, idTextTop, idText); display->drawString(pauseTextLeft, pauseTextTop, pauseText); display->drawString(pauseTextLeft + 1, pauseTextTop, pauseText); // Faux bold // Draw: divider - display->drawLine(dividerX, dividerTop, dividerX, dividerBottom); + if (useId) + display->drawLine(dividerX, dividerTop, dividerX, dividerBottom); } #endif From a38a18da0d1b8b69b092b04e2de5daf205d89f37 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20G=C3=B6ttgens?= Date: Sun, 16 Jun 2024 02:59:22 +0200 Subject: [PATCH 33/65] WIP: add NAU7802 based scale controller. (#4092) * WIP: add NAU7802 based scale controller. Needs proto commit * WIP: add NAU7802 based scale controller. Needs proto commit * telemetry uses kg, scale internally g * add sensor calibration setters --- platformio.ini | 18 ++- src/configuration.h | 1 + src/detect/ScanI2C.h | 3 +- src/detect/ScanI2CTwoWire.cpp | 1 + .../Telemetry/EnvironmentTelemetry.cpp | 121 ++++++++++++++- src/modules/Telemetry/EnvironmentTelemetry.h | 4 + .../Telemetry/Sensor/NAU7802Sensor.cpp | 143 ++++++++++++++++++ src/modules/Telemetry/Sensor/NAU7802Sensor.h | 31 ++++ .../Telemetry/Sensor/TelemetrySensor.h | 7 + 9 files changed, 318 insertions(+), 11 deletions(-) create mode 100644 src/modules/Telemetry/Sensor/NAU7802Sensor.cpp create mode 100644 src/modules/Telemetry/Sensor/NAU7802Sensor.h diff --git a/platformio.ini b/platformio.ini index 0de3e25c92..d8d398775a 100644 --- a/platformio.ini +++ b/platformio.ini @@ -122,10 +122,7 @@ lib_deps = adafruit/Adafruit BMP280 Library@^2.6.8 adafruit/Adafruit BMP085 Library@^1.2.4 adafruit/Adafruit BME280 Library@^2.2.2 - https://github.com/boschsensortec/Bosch-BSEC2-Library#v1.7.2502 - boschsensortec/BME68x Sensor Library@^1.1.40407 adafruit/Adafruit MCP9808 Library@^2.0.0 - https://github.com/KodinLanewave/INA3221@^1.0.0 adafruit/Adafruit INA260 Library@^1.5.0 adafruit/Adafruit INA219@^1.2.0 adafruit/Adafruit SHTC3 Library@^1.0.0 @@ -135,13 +132,22 @@ lib_deps = adafruit/Adafruit MPU6050@^2.2.4 adafruit/Adafruit LIS3DH@^1.2.4 adafruit/Adafruit AHTX0@^2.0.5 - lewisxhe/SensorLib@^0.2.0 adafruit/Adafruit LSM6DS@^4.7.2 - mprograms/QMC5883LCompass@^1.2.0 adafruit/Adafruit VEML7700 Library@^2.1.6 adafruit/Adafruit SHT4x Library@^1.0.4 adafruit/Adafruit TSL2591 Library@^1.4.5 + sparkfun/SparkFun Qwiic Scale NAU7802 Arduino Library@^1.0.5 ClosedCube OPT3001@^1.1.2 emotibit/EmotiBit MLX90632@^1.0.8 dfrobot/DFRobot_RTU@^1.0.3 - https://github.com/meshtastic/DFRobot_LarkWeatherStation#dee914270dc7cb3e43fbf034edd85a63a16a12ee \ No newline at end of file + + + https://github.com/boschsensortec/Bosch-BSEC2-Library#v1.7.2502 + boschsensortec/BME68x Sensor Library@^1.1.40407 + https://github.com/KodinLanewave/INA3221@^1.0.0 + lewisxhe/SensorLib@^0.2.0 + mprograms/QMC5883LCompass@^1.2.0 + + + https://github.com/meshtastic/DFRobot_LarkWeatherStation#dee914270dc7cb3e43fbf034edd85a63a16a12ee + diff --git a/src/configuration.h b/src/configuration.h index 62c48a205f..1149f344ce 100644 --- a/src/configuration.h +++ b/src/configuration.h @@ -136,6 +136,7 @@ along with this program. If not, see . #define OPT3001_ADDR_ALT 0x44 #define MLX90632_ADDR 0x3A #define DFROBOT_LARK_ADDR 0x42 +#define NAU7802_ADDR 0x2A // ----------------------------------------------------------------------------- // ACCELEROMETER diff --git a/src/detect/ScanI2C.h b/src/detect/ScanI2C.h index 20994ede1d..dcc1f40ae3 100644 --- a/src/detect/ScanI2C.h +++ b/src/detect/ScanI2C.h @@ -50,7 +50,8 @@ class ScanI2C MLX90632, AHT10, BMX160, - DFROBOT_LARK + DFROBOT_LARK, + NAU7802 } DeviceType; // typedef uint8_t DeviceAddress; diff --git a/src/detect/ScanI2CTwoWire.cpp b/src/detect/ScanI2CTwoWire.cpp index f800a9963f..6766db014f 100644 --- a/src/detect/ScanI2CTwoWire.cpp +++ b/src/detect/ScanI2CTwoWire.cpp @@ -350,6 +350,7 @@ void ScanI2CTwoWire::scanPort(I2CPort port) SCAN_SIMPLE_CASE(TSL25911_ADDR, TSL2591, "TSL2591 light sensor found\n"); SCAN_SIMPLE_CASE(OPT3001_ADDR, OPT3001, "OPT3001 light sensor found\n"); SCAN_SIMPLE_CASE(MLX90632_ADDR, MLX90632, "MLX90632 IR temp sensor found\n"); + SCAN_SIMPLE_CASE(NAU7802_ADDR, NAU7802, "NAU7802 based scale found\n"); default: LOG_INFO("Device found at address 0x%x was not able to be enumerated\n", addr.address); diff --git a/src/modules/Telemetry/EnvironmentTelemetry.cpp b/src/modules/Telemetry/EnvironmentTelemetry.cpp index 46b8a1ad80..ff32020675 100644 --- a/src/modules/Telemetry/EnvironmentTelemetry.cpp +++ b/src/modules/Telemetry/EnvironmentTelemetry.cpp @@ -27,6 +27,7 @@ #include "Sensor/LPS22HBSensor.h" #include "Sensor/MCP9808Sensor.h" #include "Sensor/MLX90632Sensor.h" +#include "Sensor/NAU7802Sensor.h" #include "Sensor/OPT3001Sensor.h" #include "Sensor/RCWL9620Sensor.h" #include "Sensor/SHT31Sensor.h" @@ -51,6 +52,7 @@ RCWL9620Sensor rcwl9620Sensor; AHT10Sensor aht10Sensor; MLX90632Sensor mlx90632Sensor; DFRobotLarkSensor dfRobotLarkSensor; +NAU7802Sensor nau7802Sensor; #define FAILED_STATE_SENSOR_READ_MULTIPLIER 10 #define DISPLAY_RECEIVEID_MEASUREMENTS_ON_SCREEN true @@ -125,6 +127,8 @@ int32_t EnvironmentTelemetryModule::runOnce() result = aht10Sensor.runOnce(); if (mlx90632Sensor.hasSensor()) result = mlx90632Sensor.runOnce(); + if (nau7802Sensor.hasSensor()) + result = nau7802Sensor.runOnce(); } return result; } else { @@ -223,12 +227,18 @@ void EnvironmentTelemetryModule::drawFrame(OLEDDisplay *display, OLEDDisplayUiSt "Volt/Cur: " + String(lastMeasurement.variant.environment_metrics.voltage, 0) + "V / " + String(lastMeasurement.variant.environment_metrics.current, 0) + "mA"); } + if (lastMeasurement.variant.environment_metrics.iaq != 0) { display->drawString(x, y += fontHeight(FONT_SMALL), "IAQ: " + String(lastMeasurement.variant.environment_metrics.iaq)); } + if (lastMeasurement.variant.environment_metrics.distance != 0) display->drawString(x, y += fontHeight(FONT_SMALL), "Water Level: " + String(lastMeasurement.variant.environment_metrics.distance, 0) + "mm"); + + if (lastMeasurement.variant.environment_metrics.weight != 0) + display->drawString(x, y += fontHeight(FONT_SMALL), + "Weight: " + String(lastMeasurement.variant.environment_metrics.weight, 0) + "kg"); } bool EnvironmentTelemetryModule::handleReceivedProtobuf(const meshtastic_MeshPacket &mp, meshtastic_Telemetry *t) @@ -245,8 +255,9 @@ bool EnvironmentTelemetryModule::handleReceivedProtobuf(const meshtastic_MeshPac LOG_INFO("(Received from %s): voltage=%f, IAQ=%d, distance=%f, lux=%f\n", sender, t->variant.environment_metrics.voltage, t->variant.environment_metrics.iaq, t->variant.environment_metrics.distance, t->variant.environment_metrics.lux); - LOG_INFO("(Received from %s): wind speed=%fm/s, direction=%d degrees\n", sender, - t->variant.environment_metrics.wind_speed, t->variant.environment_metrics.wind_direction); + LOG_INFO("(Received from %s): wind speed=%fm/s, direction=%d degrees, weight=%fkg\n", sender, + t->variant.environment_metrics.wind_speed, t->variant.environment_metrics.wind_direction, + t->variant.environment_metrics.weight); #endif // release previous packet before occupying a new spot @@ -331,6 +342,10 @@ bool EnvironmentTelemetryModule::sendTelemetry(NodeNum dest, bool phoneOnly) valid = valid && rcwl9620Sensor.getMetrics(&m); hasSensor = true; } + if (nau7802Sensor.hasSensor()) { + valid = valid && nau7802Sensor.getMetrics(&m); + hasSensor = true; + } if (aht10Sensor.hasSensor()) { if (!bmp280Sensor.hasSensor()) { valid = valid && aht10Sensor.getMetrics(&m); @@ -354,8 +369,8 @@ bool EnvironmentTelemetryModule::sendTelemetry(NodeNum dest, bool phoneOnly) LOG_INFO("(Sending): voltage=%f, IAQ=%d, distance=%f, lux=%f\n", m.variant.environment_metrics.voltage, m.variant.environment_metrics.iaq, m.variant.environment_metrics.distance, m.variant.environment_metrics.lux); - LOG_INFO("(Sending): wind speed=%fm/s, direction=%d degrees\n", m.variant.environment_metrics.wind_speed, - m.variant.environment_metrics.wind_direction); + LOG_INFO("(Sending): wind speed=%fm/s, direction=%d degrees, weight=%fkg\n", m.variant.environment_metrics.wind_speed, + m.variant.environment_metrics.wind_direction, m.variant.environment_metrics.weight); sensor_read_error_count = 0; @@ -388,4 +403,102 @@ bool EnvironmentTelemetryModule::sendTelemetry(NodeNum dest, bool phoneOnly) return valid; } +AdminMessageHandleResult EnvironmentTelemetryModule::handleAdminMessageForModule(const meshtastic_MeshPacket &mp, + meshtastic_AdminMessage *request, + meshtastic_AdminMessage *response) +{ + AdminMessageHandleResult result = AdminMessageHandleResult::NOT_HANDLED; + if (dfRobotLarkSensor.hasSensor()) { + result = dfRobotLarkSensor.handleAdminMessage(mp, request, response); + if (result != AdminMessageHandleResult::NOT_HANDLED) + return result; + } + if (sht31Sensor.hasSensor()) { + result = sht31Sensor.handleAdminMessage(mp, request, response); + if (result != AdminMessageHandleResult::NOT_HANDLED) + return result; + } + if (lps22hbSensor.hasSensor()) { + result = lps22hbSensor.handleAdminMessage(mp, request, response); + if (result != AdminMessageHandleResult::NOT_HANDLED) + return result; + } + if (shtc3Sensor.hasSensor()) { + result = shtc3Sensor.handleAdminMessage(mp, request, response); + if (result != AdminMessageHandleResult::NOT_HANDLED) + return result; + } + if (bmp085Sensor.hasSensor()) { + result = bmp085Sensor.handleAdminMessage(mp, request, response); + if (result != AdminMessageHandleResult::NOT_HANDLED) + return result; + } + if (bmp280Sensor.hasSensor()) { + result = bmp280Sensor.handleAdminMessage(mp, request, response); + if (result != AdminMessageHandleResult::NOT_HANDLED) + return result; + } + if (bme280Sensor.hasSensor()) { + result = bme280Sensor.handleAdminMessage(mp, request, response); + if (result != AdminMessageHandleResult::NOT_HANDLED) + return result; + } + if (bme680Sensor.hasSensor()) { + result = bme680Sensor.handleAdminMessage(mp, request, response); + if (result != AdminMessageHandleResult::NOT_HANDLED) + return result; + } + if (mcp9808Sensor.hasSensor()) { + result = mcp9808Sensor.handleAdminMessage(mp, request, response); + if (result != AdminMessageHandleResult::NOT_HANDLED) + return result; + } + if (ina219Sensor.hasSensor()) { + result = ina219Sensor.handleAdminMessage(mp, request, response); + if (result != AdminMessageHandleResult::NOT_HANDLED) + return result; + } + if (ina260Sensor.hasSensor()) { + result = ina260Sensor.handleAdminMessage(mp, request, response); + if (result != AdminMessageHandleResult::NOT_HANDLED) + return result; + } + if (veml7700Sensor.hasSensor()) { + result = veml7700Sensor.handleAdminMessage(mp, request, response); + if (result != AdminMessageHandleResult::NOT_HANDLED) + return result; + } + if (tsl2591Sensor.hasSensor()) { + result = tsl2591Sensor.handleAdminMessage(mp, request, response); + if (result != AdminMessageHandleResult::NOT_HANDLED) + return result; + } + if (opt3001Sensor.hasSensor()) { + result = opt3001Sensor.handleAdminMessage(mp, request, response); + if (result != AdminMessageHandleResult::NOT_HANDLED) + return result; + } + if (mlx90632Sensor.hasSensor()) { + result = mlx90632Sensor.handleAdminMessage(mp, request, response); + if (result != AdminMessageHandleResult::NOT_HANDLED) + return result; + } + if (rcwl9620Sensor.hasSensor()) { + result = rcwl9620Sensor.handleAdminMessage(mp, request, response); + if (result != AdminMessageHandleResult::NOT_HANDLED) + return result; + } + if (nau7802Sensor.hasSensor()) { + result = nau7802Sensor.handleAdminMessage(mp, request, response); + if (result != AdminMessageHandleResult::NOT_HANDLED) + return result; + } + if (aht10Sensor.hasSensor()) { + result = aht10Sensor.handleAdminMessage(mp, request, response); + if (result != AdminMessageHandleResult::NOT_HANDLED) + return result; + } + return result; +} + #endif \ No newline at end of file diff --git a/src/modules/Telemetry/EnvironmentTelemetry.h b/src/modules/Telemetry/EnvironmentTelemetry.h index cdd9491d41..ca150347e7 100644 --- a/src/modules/Telemetry/EnvironmentTelemetry.h +++ b/src/modules/Telemetry/EnvironmentTelemetry.h @@ -37,6 +37,10 @@ class EnvironmentTelemetryModule : private concurrency::OSThread, public Protobu */ bool sendTelemetry(NodeNum dest = NODENUM_BROADCAST, bool wantReplies = false); + virtual AdminMessageHandleResult handleAdminMessageForModule(const meshtastic_MeshPacket &mp, + meshtastic_AdminMessage *request, + meshtastic_AdminMessage *response) override; + private: float CelsiusToFahrenheit(float c); bool firstTime = 1; diff --git a/src/modules/Telemetry/Sensor/NAU7802Sensor.cpp b/src/modules/Telemetry/Sensor/NAU7802Sensor.cpp new file mode 100644 index 0000000000..39ac4b08b8 --- /dev/null +++ b/src/modules/Telemetry/Sensor/NAU7802Sensor.cpp @@ -0,0 +1,143 @@ +#include "configuration.h" + +#if !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR + +#include "../mesh/generated/meshtastic/telemetry.pb.h" +#include "FSCommon.h" +#include "NAU7802Sensor.h" +#include "TelemetrySensor.h" +#include +#include + +meshtastic_Nau7802Config nau7802config = meshtastic_Nau7802Config_init_zero; + +NAU7802Sensor::NAU7802Sensor() : TelemetrySensor(meshtastic_TelemetrySensorType_NAU7802, "NAU7802") {} + +int32_t NAU7802Sensor::runOnce() +{ + LOG_INFO("Init sensor: %s\n", sensorName); + if (!hasSensor()) { + return DEFAULT_SENSOR_MINIMUM_WAIT_TIME_BETWEEN_READS; + } + status = nau7802.begin(*nodeTelemetrySensorsMap[sensorType].second); + nau7802.setSampleRate(NAU7802_SPS_320); + if (!loadCalibrationData()) { + LOG_ERROR("Failed to load calibration data\n"); + } + nau7802.calibrateAFE(); + LOG_INFO("Offset: %d, Calibration factor: %.2f\n", nau7802.getZeroOffset(), nau7802.getCalibrationFactor()); + return initI2CSensor(); +} + +void NAU7802Sensor::setup() {} + +bool NAU7802Sensor::getMetrics(meshtastic_Telemetry *measurement) +{ + LOG_DEBUG("NAU7802Sensor::getMetrics\n"); + nau7802.powerUp(); + // Wait for the sensor to become ready for one second max + uint32_t start = millis(); + while (!nau7802.available()) { + delay(100); + if (millis() - start > 1000) { + nau7802.powerDown(); + return false; + } + } + // Check if we have correct calibration values after powerup + LOG_DEBUG("Offset: %d, Calibration factor: %.2f\n", nau7802.getZeroOffset(), nau7802.getCalibrationFactor()); + measurement->variant.environment_metrics.weight = nau7802.getWeight() / 1000; // sample is in kg + nau7802.powerDown(); + return true; +} + +void NAU7802Sensor::calibrate(float weight) +{ + nau7802.calculateCalibrationFactor(weight * 1000, 64); // internal sample is in grams + if (!saveCalibrationData()) { + LOG_WARN("Failed to save calibration data\n"); + } + LOG_INFO("Offset: %d, Calibration factor: %.2f\n", nau7802.getZeroOffset(), nau7802.getCalibrationFactor()); +} + +AdminMessageHandleResult NAU7802Sensor::handleAdminMessage(const meshtastic_MeshPacket &mp, meshtastic_AdminMessage *request, + meshtastic_AdminMessage *response) +{ + AdminMessageHandleResult result; + + switch (request->which_payload_variant) { + case meshtastic_AdminMessage_set_scale_tag: + if (request->set_scale == 0) { + this->tare(); + LOG_DEBUG("Client requested to tare scale\n"); + } else { + this->calibrate(request->set_scale); + LOG_DEBUG("Client requested to calibrate to %d kg\n", request->set_scale); + } + result = AdminMessageHandleResult::HANDLED; + break; + + default: + result = AdminMessageHandleResult::NOT_HANDLED; + } + + return result; +} + +void NAU7802Sensor::tare() +{ + nau7802.calculateZeroOffset(64); + if (!saveCalibrationData()) { + LOG_WARN("Failed to save calibration data\n"); + } + LOG_INFO("Offset: %d, Calibration factor: %.2f\n", nau7802.getZeroOffset(), nau7802.getCalibrationFactor()); +} + +bool NAU7802Sensor::saveCalibrationData() +{ + if (FSCom.exists(nau7802ConfigFileName) && !FSCom.remove(nau7802ConfigFileName)) { + LOG_WARN("Can't remove old state file\n"); + } + auto file = FSCom.open(nau7802ConfigFileName, FILE_O_WRITE); + nau7802config.zeroOffset = nau7802.getZeroOffset(); + nau7802config.calibrationFactor = nau7802.getCalibrationFactor(); + bool okay = false; + if (file) { + LOG_INFO("%s state write to %s.\n", sensorName, nau7802ConfigFileName); + pb_ostream_t stream = {&writecb, &file, meshtastic_Nau7802Config_size}; + + if (!pb_encode(&stream, &meshtastic_Nau7802Config_msg, &nau7802config)) { + LOG_ERROR("Error: can't encode protobuf %s\n", PB_GET_ERROR(&stream)); + } else { + okay = true; + } + file.flush(); + file.close(); + } else { + LOG_INFO("Can't write %s state (File: %s).\n", sensorName, nau7802ConfigFileName); + } + return okay; +} + +bool NAU7802Sensor::loadCalibrationData() +{ + auto file = FSCom.open(nau7802ConfigFileName, FILE_O_READ); + bool okay = false; + if (file) { + LOG_INFO("%s state read from %s.\n", sensorName, nau7802ConfigFileName); + pb_istream_t stream = {&readcb, &file, meshtastic_Nau7802Config_size}; + if (!pb_decode(&stream, &meshtastic_Nau7802Config_msg, &nau7802config)) { + LOG_ERROR("Error: can't decode protobuf %s\n", PB_GET_ERROR(&stream)); + } else { + nau7802.setZeroOffset(nau7802config.zeroOffset); + nau7802.setCalibrationFactor(nau7802config.calibrationFactor); + okay = true; + } + file.close(); + } else { + LOG_INFO("No %s state found (File: %s).\n", sensorName, nau7802ConfigFileName); + } + return okay; +} + +#endif \ No newline at end of file diff --git a/src/modules/Telemetry/Sensor/NAU7802Sensor.h b/src/modules/Telemetry/Sensor/NAU7802Sensor.h new file mode 100644 index 0000000000..c53a3b31a7 --- /dev/null +++ b/src/modules/Telemetry/Sensor/NAU7802Sensor.h @@ -0,0 +1,31 @@ +#include "MeshModule.h" +#include "configuration.h" + +#if !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR + +#include "../mesh/generated/meshtastic/telemetry.pb.h" +#include "TelemetrySensor.h" +#include + +class NAU7802Sensor : public TelemetrySensor +{ + private: + NAU7802 nau7802; + + protected: + virtual void setup() override; + const char *nau7802ConfigFileName = "/prefs/nau7802.dat"; + bool saveCalibrationData(); + bool loadCalibrationData(); + + public: + NAU7802Sensor(); + virtual int32_t runOnce() override; + virtual bool getMetrics(meshtastic_Telemetry *measurement) override; + void tare(); + void calibrate(float weight); + AdminMessageHandleResult handleAdminMessage(const meshtastic_MeshPacket &mp, meshtastic_AdminMessage *request, + meshtastic_AdminMessage *response) override; +}; + +#endif \ No newline at end of file diff --git a/src/modules/Telemetry/Sensor/TelemetrySensor.h b/src/modules/Telemetry/Sensor/TelemetrySensor.h index 35cb7965d3..da376ad31a 100644 --- a/src/modules/Telemetry/Sensor/TelemetrySensor.h +++ b/src/modules/Telemetry/Sensor/TelemetrySensor.h @@ -4,6 +4,7 @@ #pragma once #include "../mesh/generated/meshtastic/telemetry.pb.h" +#include "MeshModule.h" #include "NodeDB.h" #include @@ -42,6 +43,12 @@ class TelemetrySensor virtual void setup(); public: + virtual AdminMessageHandleResult handleAdminMessage(const meshtastic_MeshPacket &mp, meshtastic_AdminMessage *request, + meshtastic_AdminMessage *response) + { + return AdminMessageHandleResult::NOT_HANDLED; + } + bool hasSensor() { return nodeTelemetrySensorsMap[sensorType].first > 0; } virtual int32_t runOnce() = 0; From d7c52c33b93101c1ce15cdb6471f8513516b1cbe Mon Sep 17 00:00:00 2001 From: beegee-tokyo Date: Sun, 16 Jun 2024 14:24:36 +0800 Subject: [PATCH 34/65] Add RAK2560/RAK9154 --- .vscode/extensions.json | 7 +- platformio.ini | 1 + src/Power.cpp | 33 +++ .../Telemetry/Sensor/RAK9154Sensor.cpp | 189 ++++++++++++++++++ src/modules/Telemetry/Sensor/RAK9154Sensor.h | 18 ++ src/power.h | 5 + variants/rak2560/create_uf2.py | 105 ++++++++++ variants/rak2560/platformio.ini | 27 +++ variants/rak4631/variant.h | 32 ++- 9 files changed, 410 insertions(+), 7 deletions(-) create mode 100644 src/modules/Telemetry/Sensor/RAK9154Sensor.cpp create mode 100644 src/modules/Telemetry/Sensor/RAK9154Sensor.h create mode 100644 variants/rak2560/create_uf2.py create mode 100644 variants/rak2560/platformio.ini diff --git a/.vscode/extensions.json b/.vscode/extensions.json index 4fc84fa780..080e70d08b 100644 --- a/.vscode/extensions.json +++ b/.vscode/extensions.json @@ -2,8 +2,9 @@ // See http://go.microsoft.com/fwlink/?LinkId=827846 // for the documentation about the extensions.json format "recommendations": [ - "ms-vscode.cpptools", - "platformio.platformio-ide", - "trunk.io" + "platformio.platformio-ide" ], + "unwantedRecommendations": [ + "ms-vscode.cpptools-extension-pack" + ] } diff --git a/platformio.ini b/platformio.ini index d8d398775a..a1beb8e7c5 100644 --- a/platformio.ini +++ b/platformio.ini @@ -29,6 +29,7 @@ default_envs = tbeam ;default_envs = meshtastic-dr-dev ;default_envs = m5stack-coreink ;default_envs = rak4631 +;default_envs = rak2560 ;default_envs = rak10701 ;default_envs = wio-e5 ;default_envs = radiomaster_900_bandit_nano diff --git a/src/Power.cpp b/src/Power.cpp index d80bfd55cd..18dbfebe4d 100644 --- a/src/Power.cpp +++ b/src/Power.cpp @@ -75,6 +75,10 @@ INA219Sensor ina219Sensor; INA3221Sensor ina3221Sensor; #endif +#if HAS_RAKPROT && !defined(ARCH_PORTDUINO) +RAK9154Sensor rak9154Sensor; +#endif + #ifdef HAS_PMU #include "XPowersAXP192.tpp" #include "XPowersAXP2101.tpp" @@ -145,6 +149,12 @@ class AnalogBatteryLevel : public HasBatteryLevel */ virtual int getBatteryPercent() override { +#if defined(HAS_RAKPROT) && !defined(ARCH_PORTDUINO) && !defined(HAS_PMU) + if (hasRAK()) { + return rak9154Sensor.getBusBatteryPercent(); + } +#endif + float v = getBattVoltage(); if (v < noBatVolt) @@ -184,6 +194,12 @@ class AnalogBatteryLevel : public HasBatteryLevel virtual uint16_t getBattVoltage() override { +#if defined(HAS_RAKPROT) && !defined(ARCH_PORTDUINO) && !defined(HAS_PMU) + if (hasRAK()) { + return getRAKVoltage(); + } +#endif + #if HAS_TELEMETRY && !defined(ARCH_PORTDUINO) && !defined(HAS_PMU) && !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR if (hasINA()) { LOG_DEBUG("Using INA on I2C addr 0x%x for device battery voltage\n", config.power.device_battery_ina_address); @@ -356,6 +372,11 @@ class AnalogBatteryLevel : public HasBatteryLevel /// we can't be smart enough to say 'full'? virtual bool isCharging() override { +#if defined(HAS_RAKPROT) && !defined(ARCH_PORTDUINO) && !defined(HAS_PMU) + if (hasRAK()) { + return (rak9154Sensor.isCharging()) ? OptTrue : OptFalse; + } +#endif #ifdef EXT_CHRG_DETECT return digitalRead(EXT_CHRG_DETECT) == ext_chrg_detect_value; #else @@ -379,6 +400,18 @@ class AnalogBatteryLevel : public HasBatteryLevel float last_read_value = (OCV[NUM_OCV_POINTS - 1] * NUM_CELLS); uint32_t last_read_time_ms = 0; +#if defined(HAS_RAKPROT) + + uint16_t getRAKVoltage() { return rak9154Sensor.getBusVoltageMv(); } + + bool hasRAK() + { + if (!rak9154Sensor.isInitialized()) + return rak9154Sensor.runOnce() > 0; + return rak9154Sensor.isRunning(); + } +#endif + #if HAS_TELEMETRY && !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR && !defined(ARCH_PORTDUINO) uint16_t getINAVoltage() { diff --git a/src/modules/Telemetry/Sensor/RAK9154Sensor.cpp b/src/modules/Telemetry/Sensor/RAK9154Sensor.cpp new file mode 100644 index 0000000000..52d8190070 --- /dev/null +++ b/src/modules/Telemetry/Sensor/RAK9154Sensor.cpp @@ -0,0 +1,189 @@ +#include "RAK9154Sensor.h" +#include "../mesh/generated/meshtastic/telemetry.pb.h" +#include "TelemetrySensor.h" +#include "configuration.h" + +#include +#include "concurrency/Periodic.h" + +using namespace concurrency; + +#define BOOT_DATA_REQ + +RAK9154Sensor::RAK9154Sensor() : TelemetrySensor(meshtastic_TelemetrySensorType_SENSOR_UNSET, "RAK1954") {} + +static Periodic *onewirePeriodic; + +static SoftwareHalfSerial mySerial(HALF_UART_PIN); // Wire pin P0.15 + +static uint8_t buff[0x100]; +static uint16_t bufflen = 0; + +static int16_t dc_cur = 0; +static uint16_t dc_vol = 0; +static uint8_t dc_prec = 0; +static uint8_t provision = 0; + +static void onewire_evt(const uint8_t pid, const uint8_t sid, const SNHUBAPI_EVT_E eid, uint8_t *msg, uint16_t len) +{ + switch (eid) + { + case SNHUBAPI_EVT_RECV_REQ: + case SNHUBAPI_EVT_RECV_RSP: + break; + + case SNHUBAPI_EVT_QSEND: + mySerial.write(msg, len); + break; + + case SNHUBAPI_EVT_ADD_SID: + // LOG_INFO("+ADD:SID:[%02x]\r\n", msg[0]); + break; + + case SNHUBAPI_EVT_ADD_PID: + // LOG_INFO("+ADD:PID:[%02x]\r\n", msg[0]); +#ifdef BOOT_DATA_REQ + provision = msg[0]; +#endif + break; + + case SNHUBAPI_EVT_GET_INTV: + break; + + case SNHUBAPI_EVT_GET_ENABLE: + break; + + case SNHUBAPI_EVT_SDATA_REQ: + + // LOG_INFO("+EVT:PID[%02x],IPSO[%02x]\r\n",pid,msg[0]); + // for( uint16_t i=1; i 100) + { + dc_prec = 100; + } + break; + case RAK_IPSO_DC_CURRENT: + dc_cur = (msg[2] << 8) + msg[1]; + break; + case RAK_IPSO_DC_VOLTAGE: + dc_vol = (msg[2] << 8) + msg[1]; + dc_vol *= 10; + break; + default: + break; + } + + break; + case SNHUBAPI_EVT_REPORT: + + // LOG_INFO("+EVT:PID[%02x],IPSO[%02x]\r\n",pid,msg[0]); + // for( uint16_t i=1; i 100) + { + dc_prec = 100; + } + break; + case RAK_IPSO_DC_CURRENT: + dc_cur = (msg[1] << 8) + msg[2]; + break; + case RAK_IPSO_DC_VOLTAGE: + dc_vol = (msg[1] << 8) + msg[2]; + dc_vol *= 10; + break; + default: + break; + } + + break; + + case SNHUBAPI_EVT_CHKSUM_ERR: + LOG_INFO("+ERR:CHKSUM\r\n"); + break; + + case SNHUBAPI_EVT_SEQ_ERR: + LOG_INFO("+ERR:SEQUCE\r\n"); + break; + + default: + break; + } +} + +static int32_t onewireHandle() +{ + if (provision != 0) + { + RakSNHub_Protocl_API.get.data(provision); + provision = 0; + } + + while (mySerial.available()) + { + char a = mySerial.read(); + buff[bufflen++] = a; + delay(2); // continue data, timeout=2ms + } + + if (bufflen != 0) + { + RakSNHub_Protocl_API.process((uint8_t *)buff, bufflen); + bufflen = 0; + } + + return 50; +} + +int32_t RAK9154Sensor::runOnce() +{ + onewirePeriodic = new Periodic("onewireHandle", onewireHandle); + + mySerial.begin(9600); + + RakSNHub_Protocl_API.init(onewire_evt); + + status = true; + initialized = true; + return 0; +} + +void RAK9154Sensor::setup() +{ + // Set up oversampling and filter initialization +} + +bool RAK9154Sensor::getMetrics(meshtastic_Telemetry *measurement) +{ + return true; +} + +uint16_t RAK9154Sensor::getBusVoltageMv() +{ + return dc_vol; +} + +int RAK9154Sensor::getBusBatteryPercent() +{ + return (int)dc_prec; +} + +bool RAK9154Sensor::isCharging() +{ + return (dc_cur > 0) ? true : false; +} diff --git a/src/modules/Telemetry/Sensor/RAK9154Sensor.h b/src/modules/Telemetry/Sensor/RAK9154Sensor.h new file mode 100644 index 0000000000..cfe31780a9 --- /dev/null +++ b/src/modules/Telemetry/Sensor/RAK9154Sensor.h @@ -0,0 +1,18 @@ +#include "../mesh/generated/meshtastic/telemetry.pb.h" +#include "TelemetrySensor.h" +#include "VoltageSensor.h" + +class RAK9154Sensor : public TelemetrySensor, VoltageSensor +{ + private: + protected: + virtual void setup() override; + + public: + RAK9154Sensor(); + virtual int32_t runOnce() override; + virtual bool getMetrics(meshtastic_Telemetry *measurement) override; + virtual uint16_t getBusVoltageMv() override; + int getBusBatteryPercent(); + bool isCharging(); +}; \ No newline at end of file diff --git a/src/power.h b/src/power.h index 8d14ed7f8d..94bf21cc2e 100644 --- a/src/power.h +++ b/src/power.h @@ -46,6 +46,11 @@ extern INA219Sensor ina219Sensor; extern INA3221Sensor ina3221Sensor; #endif +#if HAS_RAKPROT && !defined(ARCH_PORTDUINO) +#include "modules/Telemetry/Sensor/RAK9154Sensor.h" +extern RAK9154Sensor rak9154Sensor; +#endif + class Power : private concurrency::OSThread { diff --git a/variants/rak2560/create_uf2.py b/variants/rak2560/create_uf2.py new file mode 100644 index 0000000000..d14eaea029 --- /dev/null +++ b/variants/rak2560/create_uf2.py @@ -0,0 +1,105 @@ +import sys +import struct + +Import("env") + +# Parse input and create UF2 file +def create_uf2(source, target, env): + # source_hex = target[0].get_abspath() + source_hex = target[0].get_string(False) + source_hex = '.\\'+source_hex + print("#########################################################") + print("Create UF2 from "+source_hex) + print("#########################################################") + # print("Source: " + source_hex) + target = source_hex.replace(".hex", "") + target = target + ".uf2" + # print("Target: " + target) + + with open(source_hex, mode='rb') as f: + inpbuf = f.read() + + outbuf = convert_from_hex_to_uf2(inpbuf.decode("utf-8")) + + write_file(target, outbuf) + print("#########################################################") + print(target + " is ready to flash to target device") + print("#########################################################") + + +# Add callback after .hex file was created +env.AddPostAction("$BUILD_DIR/${PROGNAME}.hex", create_uf2) + +# UF2 creation taken from uf2conv.py +UF2_MAGIC_START0 = 0x0A324655 # "UF2\n" +UF2_MAGIC_START1 = 0x9E5D5157 # Randomly selected +UF2_MAGIC_END = 0x0AB16F30 # Ditto + +familyid = 0xADA52840 + + +class Block: + def __init__(self, addr): + self.addr = addr + self.bytes = bytearray(256) + + def encode(self, blockno, numblocks): + global familyid + flags = 0x0 + if familyid: + flags |= 0x2000 + hd = struct.pack(" + + + +lib_deps = + ${nrf52840_base.lib_deps} + ${networking_base.lib_deps} + melopero/Melopero RV3028@^1.1.0 + https://github.com/RAKWireless/RAK13800-W5100S.git#1.0.2 + rakwireless/RAKwireless NCP5623 RGB LED library@^1.0.2 + beegee-tokyo/RAKwireless RAK12034@^1.0.0 + https://github.com/beegee-tokyo/RAK-OneWireSerial.git +debug_tool = jlink +; If not set we will default to uploading over serial (first it forces bootloader entry by talking 1200bps to cdcacm) +;upload_protocol = jlink +extra_scripts = + ${env.extra_scripts} + ../firmware/variants/rak2560/create_uf2.py \ No newline at end of file diff --git a/variants/rak4631/variant.h b/variants/rak4631/variant.h index bc55413368..e9f1a18651 100644 --- a/variants/rak4631/variant.h +++ b/variants/rak4631/variant.h @@ -100,9 +100,9 @@ static const uint8_t AREF = PIN_AREF; #define PIN_SERIAL1_RX (15) #define PIN_SERIAL1_TX (16) -// Connected to Jlink CDC -#define PIN_SERIAL2_RX (8) -#define PIN_SERIAL2_TX (6) +// Connected to Serial 2 +#define PIN_SERIAL2_RX (19) +#define PIN_SERIAL2_TX (20) /* * SPI Interfaces @@ -228,9 +228,18 @@ SO GPIO 39/TXEN MAY NOT BE DEFINED FOR SUCCESSFUL OPERATION OF THE SX1262 - TG // #define PIN_GPS_EN PIN_3V3_EN #define PIN_GPS_PPS (17) // Pulse per second input from the GPS +// On RAK2560 the GPS is be on a different UART +#ifdef HAS_RAKPROT +// #define GPS_RX_PIN PIN_SERIAL2_RX +// #define GPS_TX_PIN PIN_SERIAL2_TX +// #define PIN_GPS_EN PIN_3V3_EN +// Disable GPS +#define MESHTASTIC_EXCLUDE_GPS 1 +#else + // Enable GPS #define GPS_RX_PIN PIN_SERIAL1_RX #define GPS_TX_PIN PIN_SERIAL1_TX - +#endif // Define pin to enable GPS toggle (set GPIO to LOW) via user button triple press // RAK12002 RTC Module @@ -257,6 +266,21 @@ SO GPIO 39/TXEN MAY NOT BE DEFINED FOR SUCCESSFUL OPERATION OF THE SX1262 - TG #define RAK_4631 1 +#ifdef HAS_RAKPROT + +#define HALF_UART_PIN PIN_SERIAL1_RX + +#if defined(GPS_RX_PIN) && (GPS_RX_PIN == HALF_UART_PIN) +#error pin 15 collision + +#endif + +#if defined(GPS_TX_PIN) && (GPS_RX_PIN == HALF_UART_PIN) +#error pin 15 collision +#endif + +#endif + #define PIN_ETHERNET_RESET 21 #define PIN_ETHERNET_SS PIN_EINK_CS #define ETH_SPI_PORT SPI1 From 5e01b4251fd8848deb9b5896a841eaa0e6f29585 Mon Sep 17 00:00:00 2001 From: beegee-tokyo Date: Sun, 16 Jun 2024 15:46:37 +0800 Subject: [PATCH 35/65] Fix build error for none RAK2560 devices --- src/modules/Telemetry/Sensor/RAK9154Sensor.cpp | 2 ++ src/modules/Telemetry/Sensor/RAK9154Sensor.h | 4 +++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/modules/Telemetry/Sensor/RAK9154Sensor.cpp b/src/modules/Telemetry/Sensor/RAK9154Sensor.cpp index 52d8190070..4a317045bb 100644 --- a/src/modules/Telemetry/Sensor/RAK9154Sensor.cpp +++ b/src/modules/Telemetry/Sensor/RAK9154Sensor.cpp @@ -1,3 +1,4 @@ +#ifdef HAS_RAKPROT #include "RAK9154Sensor.h" #include "../mesh/generated/meshtastic/telemetry.pb.h" #include "TelemetrySensor.h" @@ -187,3 +188,4 @@ bool RAK9154Sensor::isCharging() { return (dc_cur > 0) ? true : false; } +#endif // HAS_RAKPROT \ No newline at end of file diff --git a/src/modules/Telemetry/Sensor/RAK9154Sensor.h b/src/modules/Telemetry/Sensor/RAK9154Sensor.h index cfe31780a9..5f5a927412 100644 --- a/src/modules/Telemetry/Sensor/RAK9154Sensor.h +++ b/src/modules/Telemetry/Sensor/RAK9154Sensor.h @@ -1,3 +1,4 @@ +#ifdef HAS_RAKPROT #include "../mesh/generated/meshtastic/telemetry.pb.h" #include "TelemetrySensor.h" #include "VoltageSensor.h" @@ -15,4 +16,5 @@ class RAK9154Sensor : public TelemetrySensor, VoltageSensor virtual uint16_t getBusVoltageMv() override; int getBusBatteryPercent(); bool isCharging(); -}; \ No newline at end of file +}; +#endif // HAS_RAKPROT \ No newline at end of file From 27bb3506d390c2a77cd52a8ceae7f04c60cafce4 Mon Sep 17 00:00:00 2001 From: HarukiToreda <116696711+HarukiToreda@users.noreply.github.com> Date: Sat, 18 May 2024 22:14:22 -0400 Subject: [PATCH 36/65] Added fix for ESP32 --- src/detect/ScanI2C.cpp | 30 +++++++++++++++++++++++++++++- src/detect/ScanI2C.h | 1 + src/main.cpp | 3 +++ src/main.h | 3 ++- 4 files changed, 35 insertions(+), 2 deletions(-) diff --git a/src/detect/ScanI2C.cpp b/src/detect/ScanI2C.cpp index 3231f70545..ad0171118e 100644 --- a/src/detect/ScanI2C.cpp +++ b/src/detect/ScanI2C.cpp @@ -1,4 +1,6 @@ #include "ScanI2C.h" +#include "main.h" +#include const ScanI2C::DeviceAddress ScanI2C::ADDRESS_NONE = ScanI2C::DeviceAddress(); const ScanI2C::FoundDevice ScanI2C::DEVICE_NONE = ScanI2C::FoundDevice(ScanI2C::DeviceType::NONE, ADDRESS_NONE); @@ -27,7 +29,33 @@ ScanI2C::FoundDevice ScanI2C::firstRTC() const ScanI2C::DeviceType types[] = {RTC_RV3028, RTC_PCF8563}; return firstOfOrNONE(2, types); } - +bool performScanForCardKB() { + // Example I2C scan code for CardKB (adjust as needed) + Wire.beginTransmission(CARDKB_I2C_ADDRESS); + if (Wire.endTransmission() == 0) { + return true; // CardKB detected + } + return false; // CardKB not detected +} +void scanForCardKB() { + const int maxRetries = 10; // Maximum number of retries + const int retryDelay = 100; // Delay between retries in milliseconds + + for (int i = 0; i < maxRetries; ++i) { + // Perform the scan (example scan code, adjust as needed) + cardKBDetected = performScanForCardKB(); + + if (cardKBDetected) { + Serial.println("CardKB Keyboard detected."); + break; + } + + delay(retryDelay); // Wait before the next retry + } + if (!cardKBDetected) { + Serial.println("CardKB Keyboard not detected. Canned Message Module Disabled."); + } +} ScanI2C::FoundDevice ScanI2C::firstKeyboard() const { ScanI2C::DeviceType types[] = {CARDKB, TDECKKB, BBQ10KB, RAK14004}; diff --git a/src/detect/ScanI2C.h b/src/detect/ScanI2C.h index dcc1f40ae3..ee691e8648 100644 --- a/src/detect/ScanI2C.h +++ b/src/detect/ScanI2C.h @@ -2,6 +2,7 @@ #include #include +bool performScanForCardKB(); class ScanI2C { diff --git a/src/main.cpp b/src/main.cpp index 6797c83759..9529ca7b31 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -35,6 +35,8 @@ #include // #include +bool cardKBDetected = false; +void scanForCardKB(); #ifdef ARCH_ESP32 #if !MESHTASTIC_EXCLUDE_WEBSERVER #include "mesh/http/WebServer.h" @@ -376,6 +378,7 @@ void setup() // otherwise keyboard and touch screen will not work delay(800); #endif +scanForCardKB(); // Initial scan for CardKB // Currently only the tbeam has a PMU // PMU initialization needs to be placed before i2c scanning diff --git a/src/main.h b/src/main.h index 2ef7edb3a9..b1e1ac4645 100644 --- a/src/main.h +++ b/src/main.h @@ -21,7 +21,7 @@ extern NimbleBluetooth *nimbleBluetooth; #include "NRF52Bluetooth.h" extern NRF52Bluetooth *nrf52Bluetooth; #endif - +extern bool cardKBDetected; #if ARCH_PORTDUINO extern HardwareSPI *DisplaySPI; extern HardwareSPI *LoraSPI; @@ -39,6 +39,7 @@ extern bool pmu_found; extern bool isCharging; extern bool isUSBPowered; +#define CARDKB_I2C_ADDRESS 0x5F // Replace 0x5F with the actual address if different #if !defined(ARCH_PORTDUINO) && !defined(ARCH_STM32WL) extern ATECCX08A atecc; #endif From dbb254ba7a5c442aab440af19c2ea1a20327a48d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20G=C3=B6ttgens?= Date: Sun, 19 May 2024 19:32:08 +0200 Subject: [PATCH 37/65] change the main scan class so they scan only for wanted bits - UNTESTED --- src/detect/ScanI2C.cpp | 31 ++--------------------------- src/detect/ScanI2C.h | 2 +- src/detect/ScanI2CTwoWire.cpp | 11 ++++++++++- src/detect/ScanI2CTwoWire.h | 4 +++- src/input/kbI2cBase.cpp | 37 +++++++++++++++++++++++++++++++++-- src/main.cpp | 3 --- src/main.h | 3 +-- 7 files changed, 52 insertions(+), 39 deletions(-) diff --git a/src/detect/ScanI2C.cpp b/src/detect/ScanI2C.cpp index ad0171118e..9c3a186441 100644 --- a/src/detect/ScanI2C.cpp +++ b/src/detect/ScanI2C.cpp @@ -1,6 +1,4 @@ #include "ScanI2C.h" -#include "main.h" -#include const ScanI2C::DeviceAddress ScanI2C::ADDRESS_NONE = ScanI2C::DeviceAddress(); const ScanI2C::FoundDevice ScanI2C::DEVICE_NONE = ScanI2C::FoundDevice(ScanI2C::DeviceType::NONE, ADDRESS_NONE); @@ -8,6 +6,7 @@ const ScanI2C::FoundDevice ScanI2C::DEVICE_NONE = ScanI2C::FoundDevice(ScanI2C:: ScanI2C::ScanI2C() = default; void ScanI2C::scanPort(ScanI2C::I2CPort port) {} +void ScanI2C::scanPort(ScanI2C::I2CPort port, int *address) {} void ScanI2C::setSuppressScreen() { @@ -29,33 +28,7 @@ ScanI2C::FoundDevice ScanI2C::firstRTC() const ScanI2C::DeviceType types[] = {RTC_RV3028, RTC_PCF8563}; return firstOfOrNONE(2, types); } -bool performScanForCardKB() { - // Example I2C scan code for CardKB (adjust as needed) - Wire.beginTransmission(CARDKB_I2C_ADDRESS); - if (Wire.endTransmission() == 0) { - return true; // CardKB detected - } - return false; // CardKB not detected -} -void scanForCardKB() { - const int maxRetries = 10; // Maximum number of retries - const int retryDelay = 100; // Delay between retries in milliseconds - - for (int i = 0; i < maxRetries; ++i) { - // Perform the scan (example scan code, adjust as needed) - cardKBDetected = performScanForCardKB(); - - if (cardKBDetected) { - Serial.println("CardKB Keyboard detected."); - break; - } - - delay(retryDelay); // Wait before the next retry - } - if (!cardKBDetected) { - Serial.println("CardKB Keyboard not detected. Canned Message Module Disabled."); - } -} + ScanI2C::FoundDevice ScanI2C::firstKeyboard() const { ScanI2C::DeviceType types[] = {CARDKB, TDECKKB, BBQ10KB, RAK14004}; diff --git a/src/detect/ScanI2C.h b/src/detect/ScanI2C.h index ee691e8648..1facb897a2 100644 --- a/src/detect/ScanI2C.h +++ b/src/detect/ScanI2C.h @@ -2,7 +2,6 @@ #include #include -bool performScanForCardKB(); class ScanI2C { @@ -89,6 +88,7 @@ class ScanI2C ScanI2C(); virtual void scanPort(ScanI2C::I2CPort); + virtual void scanPort(ScanI2C::I2CPort, int *); /* * A bit of a hack, this tells the scanner not to tell later systems there is a screen to avoid enabling it. diff --git a/src/detect/ScanI2CTwoWire.cpp b/src/detect/ScanI2CTwoWire.cpp index 6766db014f..dd70db8b77 100644 --- a/src/detect/ScanI2CTwoWire.cpp +++ b/src/detect/ScanI2CTwoWire.cpp @@ -135,7 +135,7 @@ uint16_t ScanI2CTwoWire::getRegisterValue(const ScanI2CTwoWire::RegisterLocation type = T; \ break; -void ScanI2CTwoWire::scanPort(I2CPort port) +void ScanI2CTwoWire::scanPort(I2CPort port, int *address) { concurrency::LockGuard guard((concurrency::Lock *)&lock); @@ -163,6 +163,10 @@ void ScanI2CTwoWire::scanPort(I2CPort port) #endif for (addr.address = 1; addr.address < 127; addr.address++) { + // Skip the address if it is not requested oon a partial scan + if (sizeof(address) > 0 && addr.address != *address) { + continue; + } i2cBus->beginTransmission(addr.address); #ifdef ARCH_PORTDUINO if (i2cBus->read() != -1) @@ -367,6 +371,11 @@ void ScanI2CTwoWire::scanPort(I2CPort port) } } +void ScanI2CTwoWire::scanPort(I2CPort port) +{ + scanPort(port, nullptr); +} + TwoWire *ScanI2CTwoWire::fetchI2CBus(ScanI2C::DeviceAddress address) const { if (address.port == ScanI2C::I2CPort::WIRE) { diff --git a/src/detect/ScanI2CTwoWire.h b/src/detect/ScanI2CTwoWire.h index 9acd736d2e..a7c19c7791 100644 --- a/src/detect/ScanI2CTwoWire.h +++ b/src/detect/ScanI2CTwoWire.h @@ -16,6 +16,8 @@ class ScanI2CTwoWire : public ScanI2C public: void scanPort(ScanI2C::I2CPort) override; + void scanPort(ScanI2C::I2CPort, int *) override; + ScanI2C::FoundDevice find(ScanI2C::DeviceType) const override; TwoWire *fetchI2CBus(ScanI2C::DeviceAddress) const; @@ -53,4 +55,4 @@ class ScanI2CTwoWire : public ScanI2C uint16_t getRegisterValue(const RegisterLocation &, ResponseWidth) const; DeviceType probeOLED(ScanI2C::DeviceAddress) const; -}; +}; \ No newline at end of file diff --git a/src/input/kbI2cBase.cpp b/src/input/kbI2cBase.cpp index af7c96b206..55f435fda7 100644 --- a/src/input/kbI2cBase.cpp +++ b/src/input/kbI2cBase.cpp @@ -1,6 +1,7 @@ #include "kbI2cBase.h" #include "configuration.h" #include "detect/ScanI2C.h" +#include "detect/ScanI2CTwoWire.h" extern ScanI2C::DeviceAddress cardkb_found; extern uint8_t kb_model; @@ -30,8 +31,40 @@ uint8_t read_from_14004(TwoWire *i2cBus, uint8_t reg, uint8_t *data, uint8_t len int32_t KbI2cBase::runOnce() { if (cardkb_found.address == 0x00) { - // Input device is not detected. - return INT32_MAX; + // Input device is not detected. Rescan now. + auto i2cScanner = std::unique_ptr(new ScanI2CTwoWire()); + int i2caddr_scan[] = {CARDKB_ADDR, TDECK_KB_ADDR, BBQ10_KB_ADDR}; +#if defined(I2C_SDA1) + i2cScanner->scanPort(ScanI2C::I2CPort::WIRE1, i2caddr_scan); +#endif + i2cScanner->scanPort(ScanI2C::I2CPort::WIRE, i2caddr_scan); + auto kb_info = i2cScanner->firstKeyboard(); + + if (kb_info.type != ScanI2C::DeviceType::NONE) { + cardkb_found = kb_info.address; + switch (kb_info.type) { + case ScanI2C::DeviceType::RAK14004: + kb_model = 0x02; + break; + case ScanI2C::DeviceType::CARDKB: + kb_model = 0x00; + break; + case ScanI2C::DeviceType::TDECKKB: + // assign an arbitrary value to distinguish from other models + kb_model = 0x10; + break; + case ScanI2C::DeviceType::BBQ10KB: + // assign an arbitrary value to distinguish from other models + kb_model = 0x11; + break; + default: + // use this as default since it's also just zero + LOG_WARN("kb_info.type is unknown(0x%02x), setting kb_model=0x00\n", kb_info.type); + kb_model = 0x00; + } + } + if (cardkb_found.address == 0x00) + return INT32_MAX; } if (!i2cBus) { diff --git a/src/main.cpp b/src/main.cpp index 9529ca7b31..6797c83759 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -35,8 +35,6 @@ #include // #include -bool cardKBDetected = false; -void scanForCardKB(); #ifdef ARCH_ESP32 #if !MESHTASTIC_EXCLUDE_WEBSERVER #include "mesh/http/WebServer.h" @@ -378,7 +376,6 @@ void setup() // otherwise keyboard and touch screen will not work delay(800); #endif -scanForCardKB(); // Initial scan for CardKB // Currently only the tbeam has a PMU // PMU initialization needs to be placed before i2c scanning diff --git a/src/main.h b/src/main.h index b1e1ac4645..2ef7edb3a9 100644 --- a/src/main.h +++ b/src/main.h @@ -21,7 +21,7 @@ extern NimbleBluetooth *nimbleBluetooth; #include "NRF52Bluetooth.h" extern NRF52Bluetooth *nrf52Bluetooth; #endif -extern bool cardKBDetected; + #if ARCH_PORTDUINO extern HardwareSPI *DisplaySPI; extern HardwareSPI *LoraSPI; @@ -39,7 +39,6 @@ extern bool pmu_found; extern bool isCharging; extern bool isUSBPowered; -#define CARDKB_I2C_ADDRESS 0x5F // Replace 0x5F with the actual address if different #if !defined(ARCH_PORTDUINO) && !defined(ARCH_STM32WL) extern ATECCX08A atecc; #endif From ce9e63a2cb21ad943d708ae69fc6a0cbb62e5807 Mon Sep 17 00:00:00 2001 From: HarukiToreda <116696711+HarukiToreda@users.noreply.github.com> Date: Sat, 18 May 2024 22:14:22 -0400 Subject: [PATCH 38/65] Added fix for ESP32 --- src/detect/ScanI2C.cpp | 30 +++++++++++++++++++++++++++++- src/detect/ScanI2C.h | 1 + src/main.cpp | 3 +++ src/main.h | 3 ++- 4 files changed, 35 insertions(+), 2 deletions(-) diff --git a/src/detect/ScanI2C.cpp b/src/detect/ScanI2C.cpp index 9c3a186441..51718b15fa 100644 --- a/src/detect/ScanI2C.cpp +++ b/src/detect/ScanI2C.cpp @@ -1,4 +1,6 @@ #include "ScanI2C.h" +#include "main.h" +#include const ScanI2C::DeviceAddress ScanI2C::ADDRESS_NONE = ScanI2C::DeviceAddress(); const ScanI2C::FoundDevice ScanI2C::DEVICE_NONE = ScanI2C::FoundDevice(ScanI2C::DeviceType::NONE, ADDRESS_NONE); @@ -28,7 +30,33 @@ ScanI2C::FoundDevice ScanI2C::firstRTC() const ScanI2C::DeviceType types[] = {RTC_RV3028, RTC_PCF8563}; return firstOfOrNONE(2, types); } - +bool performScanForCardKB() { + // Example I2C scan code for CardKB (adjust as needed) + Wire.beginTransmission(CARDKB_I2C_ADDRESS); + if (Wire.endTransmission() == 0) { + return true; // CardKB detected + } + return false; // CardKB not detected +} +void scanForCardKB() { + const int maxRetries = 10; // Maximum number of retries + const int retryDelay = 100; // Delay between retries in milliseconds + + for (int i = 0; i < maxRetries; ++i) { + // Perform the scan (example scan code, adjust as needed) + cardKBDetected = performScanForCardKB(); + + if (cardKBDetected) { + Serial.println("CardKB Keyboard detected."); + break; + } + + delay(retryDelay); // Wait before the next retry + } + if (!cardKBDetected) { + Serial.println("CardKB Keyboard not detected. Canned Message Module Disabled."); + } +} ScanI2C::FoundDevice ScanI2C::firstKeyboard() const { ScanI2C::DeviceType types[] = {CARDKB, TDECKKB, BBQ10KB, RAK14004}; diff --git a/src/detect/ScanI2C.h b/src/detect/ScanI2C.h index 1facb897a2..1c2fe73c6c 100644 --- a/src/detect/ScanI2C.h +++ b/src/detect/ScanI2C.h @@ -2,6 +2,7 @@ #include #include +bool performScanForCardKB(); class ScanI2C { diff --git a/src/main.cpp b/src/main.cpp index 6797c83759..9529ca7b31 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -35,6 +35,8 @@ #include // #include +bool cardKBDetected = false; +void scanForCardKB(); #ifdef ARCH_ESP32 #if !MESHTASTIC_EXCLUDE_WEBSERVER #include "mesh/http/WebServer.h" @@ -376,6 +378,7 @@ void setup() // otherwise keyboard and touch screen will not work delay(800); #endif +scanForCardKB(); // Initial scan for CardKB // Currently only the tbeam has a PMU // PMU initialization needs to be placed before i2c scanning diff --git a/src/main.h b/src/main.h index 2ef7edb3a9..b1e1ac4645 100644 --- a/src/main.h +++ b/src/main.h @@ -21,7 +21,7 @@ extern NimbleBluetooth *nimbleBluetooth; #include "NRF52Bluetooth.h" extern NRF52Bluetooth *nrf52Bluetooth; #endif - +extern bool cardKBDetected; #if ARCH_PORTDUINO extern HardwareSPI *DisplaySPI; extern HardwareSPI *LoraSPI; @@ -39,6 +39,7 @@ extern bool pmu_found; extern bool isCharging; extern bool isUSBPowered; +#define CARDKB_I2C_ADDRESS 0x5F // Replace 0x5F with the actual address if different #if !defined(ARCH_PORTDUINO) && !defined(ARCH_STM32WL) extern ATECCX08A atecc; #endif From 2eb3cfd5e033afb27c687bba0b194b94036d3cac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20G=C3=B6ttgens?= Date: Sun, 19 May 2024 19:32:08 +0200 Subject: [PATCH 39/65] change the main scan class so they scan only for wanted bits - UNTESTED --- src/detect/ScanI2C.cpp | 30 +----------------------------- src/detect/ScanI2C.h | 1 - src/main.cpp | 3 --- src/main.h | 3 +-- 4 files changed, 2 insertions(+), 35 deletions(-) diff --git a/src/detect/ScanI2C.cpp b/src/detect/ScanI2C.cpp index 51718b15fa..9c3a186441 100644 --- a/src/detect/ScanI2C.cpp +++ b/src/detect/ScanI2C.cpp @@ -1,6 +1,4 @@ #include "ScanI2C.h" -#include "main.h" -#include const ScanI2C::DeviceAddress ScanI2C::ADDRESS_NONE = ScanI2C::DeviceAddress(); const ScanI2C::FoundDevice ScanI2C::DEVICE_NONE = ScanI2C::FoundDevice(ScanI2C::DeviceType::NONE, ADDRESS_NONE); @@ -30,33 +28,7 @@ ScanI2C::FoundDevice ScanI2C::firstRTC() const ScanI2C::DeviceType types[] = {RTC_RV3028, RTC_PCF8563}; return firstOfOrNONE(2, types); } -bool performScanForCardKB() { - // Example I2C scan code for CardKB (adjust as needed) - Wire.beginTransmission(CARDKB_I2C_ADDRESS); - if (Wire.endTransmission() == 0) { - return true; // CardKB detected - } - return false; // CardKB not detected -} -void scanForCardKB() { - const int maxRetries = 10; // Maximum number of retries - const int retryDelay = 100; // Delay between retries in milliseconds - - for (int i = 0; i < maxRetries; ++i) { - // Perform the scan (example scan code, adjust as needed) - cardKBDetected = performScanForCardKB(); - - if (cardKBDetected) { - Serial.println("CardKB Keyboard detected."); - break; - } - - delay(retryDelay); // Wait before the next retry - } - if (!cardKBDetected) { - Serial.println("CardKB Keyboard not detected. Canned Message Module Disabled."); - } -} + ScanI2C::FoundDevice ScanI2C::firstKeyboard() const { ScanI2C::DeviceType types[] = {CARDKB, TDECKKB, BBQ10KB, RAK14004}; diff --git a/src/detect/ScanI2C.h b/src/detect/ScanI2C.h index 1c2fe73c6c..1facb897a2 100644 --- a/src/detect/ScanI2C.h +++ b/src/detect/ScanI2C.h @@ -2,7 +2,6 @@ #include #include -bool performScanForCardKB(); class ScanI2C { diff --git a/src/main.cpp b/src/main.cpp index 9529ca7b31..6797c83759 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -35,8 +35,6 @@ #include // #include -bool cardKBDetected = false; -void scanForCardKB(); #ifdef ARCH_ESP32 #if !MESHTASTIC_EXCLUDE_WEBSERVER #include "mesh/http/WebServer.h" @@ -378,7 +376,6 @@ void setup() // otherwise keyboard and touch screen will not work delay(800); #endif -scanForCardKB(); // Initial scan for CardKB // Currently only the tbeam has a PMU // PMU initialization needs to be placed before i2c scanning diff --git a/src/main.h b/src/main.h index b1e1ac4645..2ef7edb3a9 100644 --- a/src/main.h +++ b/src/main.h @@ -21,7 +21,7 @@ extern NimbleBluetooth *nimbleBluetooth; #include "NRF52Bluetooth.h" extern NRF52Bluetooth *nrf52Bluetooth; #endif -extern bool cardKBDetected; + #if ARCH_PORTDUINO extern HardwareSPI *DisplaySPI; extern HardwareSPI *LoraSPI; @@ -39,7 +39,6 @@ extern bool pmu_found; extern bool isCharging; extern bool isUSBPowered; -#define CARDKB_I2C_ADDRESS 0x5F // Replace 0x5F with the actual address if different #if !defined(ARCH_PORTDUINO) && !defined(ARCH_STM32WL) extern ATECCX08A atecc; #endif From ba14ffb8d393662f59481489af7c252a28dd60ef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20G=C3=B6ttgens?= Date: Fri, 24 May 2024 22:59:31 +0200 Subject: [PATCH 40/65] change type to 8 bit uint --- src/detect/ScanI2C.cpp | 2 +- src/detect/ScanI2C.h | 2 +- src/detect/ScanI2CTwoWire.cpp | 6 +++--- src/detect/ScanI2CTwoWire.h | 2 +- src/input/kbI2cBase.cpp | 2 +- 5 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/detect/ScanI2C.cpp b/src/detect/ScanI2C.cpp index 9c3a186441..03b93e0685 100644 --- a/src/detect/ScanI2C.cpp +++ b/src/detect/ScanI2C.cpp @@ -6,7 +6,7 @@ const ScanI2C::FoundDevice ScanI2C::DEVICE_NONE = ScanI2C::FoundDevice(ScanI2C:: ScanI2C::ScanI2C() = default; void ScanI2C::scanPort(ScanI2C::I2CPort port) {} -void ScanI2C::scanPort(ScanI2C::I2CPort port, int *address) {} +void ScanI2C::scanPort(ScanI2C::I2CPort port, uint8_t *address) {} void ScanI2C::setSuppressScreen() { diff --git a/src/detect/ScanI2C.h b/src/detect/ScanI2C.h index 1facb897a2..5c75a9deeb 100644 --- a/src/detect/ScanI2C.h +++ b/src/detect/ScanI2C.h @@ -88,7 +88,7 @@ class ScanI2C ScanI2C(); virtual void scanPort(ScanI2C::I2CPort); - virtual void scanPort(ScanI2C::I2CPort, int *); + virtual void scanPort(ScanI2C::I2CPort, uint8_t *); /* * A bit of a hack, this tells the scanner not to tell later systems there is a screen to avoid enabling it. diff --git a/src/detect/ScanI2CTwoWire.cpp b/src/detect/ScanI2CTwoWire.cpp index dd70db8b77..95e273b85f 100644 --- a/src/detect/ScanI2CTwoWire.cpp +++ b/src/detect/ScanI2CTwoWire.cpp @@ -135,7 +135,7 @@ uint16_t ScanI2CTwoWire::getRegisterValue(const ScanI2CTwoWire::RegisterLocation type = T; \ break; -void ScanI2CTwoWire::scanPort(I2CPort port, int *address) +void ScanI2CTwoWire::scanPort(I2CPort port, uint8_t *address) { concurrency::LockGuard guard((concurrency::Lock *)&lock); @@ -163,8 +163,8 @@ void ScanI2CTwoWire::scanPort(I2CPort port, int *address) #endif for (addr.address = 1; addr.address < 127; addr.address++) { - // Skip the address if it is not requested oon a partial scan - if (sizeof(address) > 0 && addr.address != *address) { + // Skip the address if it is not requested on a partial scan + if (address != nullptr && *address != addr.address) { continue; } i2cBus->beginTransmission(addr.address); diff --git a/src/detect/ScanI2CTwoWire.h b/src/detect/ScanI2CTwoWire.h index a7c19c7791..332afbf64e 100644 --- a/src/detect/ScanI2CTwoWire.h +++ b/src/detect/ScanI2CTwoWire.h @@ -16,7 +16,7 @@ class ScanI2CTwoWire : public ScanI2C public: void scanPort(ScanI2C::I2CPort) override; - void scanPort(ScanI2C::I2CPort, int *) override; + void scanPort(ScanI2C::I2CPort, uint8_t *) override; ScanI2C::FoundDevice find(ScanI2C::DeviceType) const override; diff --git a/src/input/kbI2cBase.cpp b/src/input/kbI2cBase.cpp index 55f435fda7..135de17166 100644 --- a/src/input/kbI2cBase.cpp +++ b/src/input/kbI2cBase.cpp @@ -33,7 +33,7 @@ int32_t KbI2cBase::runOnce() if (cardkb_found.address == 0x00) { // Input device is not detected. Rescan now. auto i2cScanner = std::unique_ptr(new ScanI2CTwoWire()); - int i2caddr_scan[] = {CARDKB_ADDR, TDECK_KB_ADDR, BBQ10_KB_ADDR}; + uint8_t i2caddr_scan[] = {CARDKB_ADDR, TDECK_KB_ADDR, BBQ10_KB_ADDR}; #if defined(I2C_SDA1) i2cScanner->scanPort(ScanI2C::I2CPort::WIRE1, i2caddr_scan); #endif From a453d7f52c80ea6887714b2415c1cac8f138806e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20G=C3=B6ttgens?= Date: Sat, 25 May 2024 12:37:55 +0200 Subject: [PATCH 41/65] Iterate through uint array --- src/detect/ScanI2C.cpp | 2 +- src/detect/ScanI2C.h | 2 +- src/detect/ScanI2CTwoWire.cpp | 21 +++++++++++++++------ src/detect/ScanI2CTwoWire.h | 2 +- src/input/kbI2cBase.cpp | 5 +++-- 5 files changed, 21 insertions(+), 11 deletions(-) diff --git a/src/detect/ScanI2C.cpp b/src/detect/ScanI2C.cpp index 03b93e0685..73bdf973b0 100644 --- a/src/detect/ScanI2C.cpp +++ b/src/detect/ScanI2C.cpp @@ -6,7 +6,7 @@ const ScanI2C::FoundDevice ScanI2C::DEVICE_NONE = ScanI2C::FoundDevice(ScanI2C:: ScanI2C::ScanI2C() = default; void ScanI2C::scanPort(ScanI2C::I2CPort port) {} -void ScanI2C::scanPort(ScanI2C::I2CPort port, uint8_t *address) {} +void ScanI2C::scanPort(ScanI2C::I2CPort port, uint8_t *address, uint8_t asize) {} void ScanI2C::setSuppressScreen() { diff --git a/src/detect/ScanI2C.h b/src/detect/ScanI2C.h index 5c75a9deeb..711e8bee54 100644 --- a/src/detect/ScanI2C.h +++ b/src/detect/ScanI2C.h @@ -88,7 +88,7 @@ class ScanI2C ScanI2C(); virtual void scanPort(ScanI2C::I2CPort); - virtual void scanPort(ScanI2C::I2CPort, uint8_t *); + virtual void scanPort(ScanI2C::I2CPort, uint8_t *, uint8_t); /* * A bit of a hack, this tells the scanner not to tell later systems there is a screen to avoid enabling it. diff --git a/src/detect/ScanI2CTwoWire.cpp b/src/detect/ScanI2CTwoWire.cpp index 95e273b85f..b045905098 100644 --- a/src/detect/ScanI2CTwoWire.cpp +++ b/src/detect/ScanI2CTwoWire.cpp @@ -14,6 +14,15 @@ #define XPOWERS_AXP192_AXP2101_ADDRESS 0x34 #endif +bool in_array(uint8_t *array, int size, uint8_t lookfor) +{ + int i; + for (i = 0; i < size; i++) + if (lookfor == array[i]) + return true; + return false; +} + ScanI2C::FoundDevice ScanI2CTwoWire::find(ScanI2C::DeviceType type) const { concurrency::LockGuard guard((concurrency::Lock *)&lock); @@ -135,7 +144,7 @@ uint16_t ScanI2CTwoWire::getRegisterValue(const ScanI2CTwoWire::RegisterLocation type = T; \ break; -void ScanI2CTwoWire::scanPort(I2CPort port, uint8_t *address) +void ScanI2CTwoWire::scanPort(I2CPort port, uint8_t *address, uint8_t asize) { concurrency::LockGuard guard((concurrency::Lock *)&lock); @@ -163,10 +172,10 @@ void ScanI2CTwoWire::scanPort(I2CPort port, uint8_t *address) #endif for (addr.address = 1; addr.address < 127; addr.address++) { - // Skip the address if it is not requested on a partial scan - if (address != nullptr && *address != addr.address) { - continue; - } + if (asize != 0) + if (in_array(address, asize, addr.address)) + continue; + i2cBus->beginTransmission(addr.address); #ifdef ARCH_PORTDUINO if (i2cBus->read() != -1) @@ -373,7 +382,7 @@ void ScanI2CTwoWire::scanPort(I2CPort port, uint8_t *address) void ScanI2CTwoWire::scanPort(I2CPort port) { - scanPort(port, nullptr); + scanPort(port, nullptr, 0); } TwoWire *ScanI2CTwoWire::fetchI2CBus(ScanI2C::DeviceAddress address) const diff --git a/src/detect/ScanI2CTwoWire.h b/src/detect/ScanI2CTwoWire.h index 332afbf64e..82b48f6b47 100644 --- a/src/detect/ScanI2CTwoWire.h +++ b/src/detect/ScanI2CTwoWire.h @@ -16,7 +16,7 @@ class ScanI2CTwoWire : public ScanI2C public: void scanPort(ScanI2C::I2CPort) override; - void scanPort(ScanI2C::I2CPort, uint8_t *) override; + void scanPort(ScanI2C::I2CPort, uint8_t *, uint8_t) override; ScanI2C::FoundDevice find(ScanI2C::DeviceType) const override; diff --git a/src/input/kbI2cBase.cpp b/src/input/kbI2cBase.cpp index 135de17166..ce22edb93d 100644 --- a/src/input/kbI2cBase.cpp +++ b/src/input/kbI2cBase.cpp @@ -34,10 +34,11 @@ int32_t KbI2cBase::runOnce() // Input device is not detected. Rescan now. auto i2cScanner = std::unique_ptr(new ScanI2CTwoWire()); uint8_t i2caddr_scan[] = {CARDKB_ADDR, TDECK_KB_ADDR, BBQ10_KB_ADDR}; + uint8_t i2caddr_asize = 3; #if defined(I2C_SDA1) - i2cScanner->scanPort(ScanI2C::I2CPort::WIRE1, i2caddr_scan); + i2cScanner->scanPort(ScanI2C::I2CPort::WIRE1, i2caddr_scan, i2caddr_asize); #endif - i2cScanner->scanPort(ScanI2C::I2CPort::WIRE, i2caddr_scan); + i2cScanner->scanPort(ScanI2C::I2CPort::WIRE, i2caddr_scan, i2caddr_asize); auto kb_info = i2cScanner->firstKeyboard(); if (kb_info.type != ScanI2C::DeviceType::NONE) { From 85d621d9c6d2c54117559e24a2c7c33c21fe80fa Mon Sep 17 00:00:00 2001 From: beegee-tokyo Date: Sun, 16 Jun 2024 19:45:17 +0800 Subject: [PATCH 42/65] Move RAK9154 to variants, fix json --- .vscode/extensions.json | 7 ++-- platformio.ini | 4 +- src/power.h | 42 ++++++++++--------- .../rak2560}/RAK9154Sensor.cpp | 6 +-- .../rak2560}/RAK9154Sensor.h | 7 +++- variants/rak2560/platformio.ini | 2 +- 6 files changed, 36 insertions(+), 32 deletions(-) rename {src/modules/Telemetry/Sensor => variants/rak2560}/RAK9154Sensor.cpp (96%) rename {src/modules/Telemetry/Sensor => variants/rak2560}/RAK9154Sensor.h (71%) diff --git a/.vscode/extensions.json b/.vscode/extensions.json index 080e70d08b..b50c95349d 100644 --- a/.vscode/extensions.json +++ b/.vscode/extensions.json @@ -2,9 +2,8 @@ // See http://go.microsoft.com/fwlink/?LinkId=827846 // for the documentation about the extensions.json format "recommendations": [ - "platformio.platformio-ide" + "ms-vscode.cpptools", + "platformio.platformio-ide", + "trunk.io" ], - "unwantedRecommendations": [ - "ms-vscode.cpptools-extension-pack" - ] } diff --git a/platformio.ini b/platformio.ini index a1beb8e7c5..55329e5787 100644 --- a/platformio.ini +++ b/platformio.ini @@ -2,7 +2,7 @@ ; 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 @@ -29,7 +29,7 @@ default_envs = tbeam ;default_envs = meshtastic-dr-dev ;default_envs = m5stack-coreink ;default_envs = rak4631 -;default_envs = rak2560 +default_envs = rak2560 ;default_envs = rak10701 ;default_envs = wio-e5 ;default_envs = radiomaster_900_bandit_nano diff --git a/src/power.h b/src/power.h index 94bf21cc2e..c343a45ebd 100644 --- a/src/power.h +++ b/src/power.h @@ -2,6 +2,8 @@ #include "PowerStatus.h" #include "concurrency/OSThread.h" #include "configuration.h" +#include "../variants/rak2560/RAK9154Sensor.h" + #ifdef ARCH_ESP32 #include #include @@ -47,38 +49,38 @@ extern INA3221Sensor ina3221Sensor; #endif #if HAS_RAKPROT && !defined(ARCH_PORTDUINO) -#include "modules/Telemetry/Sensor/RAK9154Sensor.h" +#include "../variants/rak2560/RAK9154Sensor.h" extern RAK9154Sensor rak9154Sensor; #endif class Power : private concurrency::OSThread { - public: - Observable newStatus; +public: + Observable newStatus; - Power(); + Power(); - void shutdown(); - void readPowerStatus(); - virtual bool setup(); - virtual int32_t runOnce() override; - void setStatusHandler(meshtastic::PowerStatus *handler) { statusHandler = handler; } - const uint16_t OCV[11] = {OCV_ARRAY}; + void shutdown(); + void readPowerStatus(); + virtual bool setup(); + virtual int32_t runOnce() override; + void setStatusHandler(meshtastic::PowerStatus *handler) { statusHandler = handler; } + const uint16_t OCV[11] = {OCV_ARRAY}; - protected: - meshtastic::PowerStatus *statusHandler; +protected: + meshtastic::PowerStatus *statusHandler; - /// Setup a xpowers chip axp192/axp2101, return true if found - bool axpChipInit(); - /// Setup a simple ADC input based battery sensor - bool analogInit(); + /// Setup a xpowers chip axp192/axp2101, return true if found + bool axpChipInit(); + /// Setup a simple ADC input based battery sensor + bool analogInit(); - private: - // open circuit voltage lookup table - uint8_t low_voltage_counter; +private: + // open circuit voltage lookup table + uint8_t low_voltage_counter; #ifdef DEBUG_HEAP - uint32_t lastheap; + uint32_t lastheap; #endif }; diff --git a/src/modules/Telemetry/Sensor/RAK9154Sensor.cpp b/variants/rak2560/RAK9154Sensor.cpp similarity index 96% rename from src/modules/Telemetry/Sensor/RAK9154Sensor.cpp rename to variants/rak2560/RAK9154Sensor.cpp index 4a317045bb..15a172c182 100644 --- a/src/modules/Telemetry/Sensor/RAK9154Sensor.cpp +++ b/variants/rak2560/RAK9154Sensor.cpp @@ -1,7 +1,7 @@ -#ifdef HAS_RAKPROT -#include "RAK9154Sensor.h" +#ifdef HAS_RAKPROT +#include "../variants/rak2560/RAK9154Sensor.h" #include "../mesh/generated/meshtastic/telemetry.pb.h" -#include "TelemetrySensor.h" +#include "../modules/Telemetry/Sensor/TelemetrySensor.h" #include "configuration.h" #include diff --git a/src/modules/Telemetry/Sensor/RAK9154Sensor.h b/variants/rak2560/RAK9154Sensor.h similarity index 71% rename from src/modules/Telemetry/Sensor/RAK9154Sensor.h rename to variants/rak2560/RAK9154Sensor.h index 5f5a927412..6c6f304d67 100644 --- a/src/modules/Telemetry/Sensor/RAK9154Sensor.h +++ b/variants/rak2560/RAK9154Sensor.h @@ -1,7 +1,9 @@ #ifdef HAS_RAKPROT +#ifndef _RAK9154SENSOR_H +#define _RAK9154SENSOR_H 1 #include "../mesh/generated/meshtastic/telemetry.pb.h" -#include "TelemetrySensor.h" -#include "VoltageSensor.h" +#include "../modules/Telemetry/Sensor/TelemetrySensor.h" +#include "../modules/Telemetry/Sensor/VoltageSensor.h" class RAK9154Sensor : public TelemetrySensor, VoltageSensor { @@ -17,4 +19,5 @@ class RAK9154Sensor : public TelemetrySensor, VoltageSensor int getBusBatteryPercent(); bool isCharging(); }; +#endif // _RAK9154SENSOR_H #endif // HAS_RAKPROT \ No newline at end of file diff --git a/variants/rak2560/platformio.ini b/variants/rak2560/platformio.ini index b33f7dcef5..1734bc75c8 100644 --- a/variants/rak2560/platformio.ini +++ b/variants/rak2560/platformio.ini @@ -10,7 +10,7 @@ build_flags = ${nrf52840_base.build_flags} -Ivariants/rak4631 -D RAK_4631 -DEINK_WIDTH=250 -DEINK_HEIGHT=122 -DHAS_RAKPROT=1 ; Define if RAk OneWireSerial is used (disables GPS) -build_src_filter = ${nrf52_base.build_src_filter} +<../variants/rak4631> + + + +build_src_filter = ${nrf52_base.build_src_filter} +<../variants/rak4631> +<../variants/rak2560> + + + lib_deps = ${nrf52840_base.lib_deps} ${networking_base.lib_deps} From 471ee78a5e86fa8b5b61705d61606ce9216f7f06 Mon Sep 17 00:00:00 2001 From: thebentern <9000580+thebentern@users.noreply.github.com> Date: Sun, 16 Jun 2024 12:25:52 +0000 Subject: [PATCH 43/65] [create-pull-request] automated change --- protobufs | 2 +- src/mesh/generated/meshtastic/mesh.pb.h | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/protobufs b/protobufs index dc066c89f7..0c90a6814f 160000 --- a/protobufs +++ b/protobufs @@ -1 +1 @@ -Subproject commit dc066c89f73fce882e5a47648cba18a1967a7f56 +Subproject commit 0c90a6814fdd959a35bb6cf8e958e74d48e8a601 diff --git a/src/mesh/generated/meshtastic/mesh.pb.h b/src/mesh/generated/meshtastic/mesh.pb.h index 0e9e6a28d7..f5fc8661af 100644 --- a/src/mesh/generated/meshtastic/mesh.pb.h +++ b/src/mesh/generated/meshtastic/mesh.pb.h @@ -67,6 +67,8 @@ typedef enum _meshtastic_HardwareModel { meshtastic_HardwareModel_WIPHONE = 20, /* WIO Tracker WM1110 family from Seeed Studio. Includes wio-1110-tracker and wio-1110-sdk */ meshtastic_HardwareModel_WIO_WM1110 = 21, + /* RAK2560 Solar base station based on RAK4630 */ + meshtastic_HardwareModel_RAK2560 = 22, /* B&Q Consulting Station Edition G1: https://uniteng.com/wiki/doku.php?id=meshtastic:station */ meshtastic_HardwareModel_STATION_G1 = 25, /* RAK11310 (RP2040 + SX1262) */ From f50073ed9f351c4b59f8756125efda40452e9562 Mon Sep 17 00:00:00 2001 From: beegee-tokyo Date: Sun, 16 Jun 2024 21:06:38 +0800 Subject: [PATCH 44/65] Separate RAK4631 and RAK2560 variants --- platformio.ini | 4 +- variants/rak2560/platformio.ini | 7 +- variants/rak2560/variant.cpp | 45 +++++ variants/rak2560/variant.h | 280 ++++++++++++++++++++++++++++++++ variants/rak4631/variant.h | 149 +++++++---------- 5 files changed, 392 insertions(+), 93 deletions(-) create mode 100644 variants/rak2560/variant.cpp create mode 100644 variants/rak2560/variant.h diff --git a/platformio.ini b/platformio.ini index 55329e5787..a1beb8e7c5 100644 --- a/platformio.ini +++ b/platformio.ini @@ -2,7 +2,7 @@ ; 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 @@ -29,7 +29,7 @@ ;default_envs = meshtastic-dr-dev ;default_envs = m5stack-coreink ;default_envs = rak4631 -default_envs = rak2560 +;default_envs = rak2560 ;default_envs = rak10701 ;default_envs = wio-e5 ;default_envs = radiomaster_900_bandit_nano diff --git a/variants/rak2560/platformio.ini b/variants/rak2560/platformio.ini index 1734bc75c8..71b235aaca 100644 --- a/variants/rak2560/platformio.ini +++ b/variants/rak2560/platformio.ini @@ -3,14 +3,11 @@ extends = nrf52840_base board = wiscore_rak4631 board_check = true -build_flags = ${nrf52840_base.build_flags} -Ivariants/rak4631 -D RAK_4631 +build_flags = ${nrf52840_base.build_flags} -Ivariants/rak2560 -D RAK_4631 -L "${platformio.libdeps_dir}/${this.__env__}/bsec2/src/cortex-m4/fpv4-sp-d16-hard" -DGPS_POWER_TOGGLE ; comment this line to disable triple press function on the user button to turn off gps entirely. - -DEINK_DISPLAY_MODEL=GxEPD2_213_BN - -DEINK_WIDTH=250 - -DEINK_HEIGHT=122 -DHAS_RAKPROT=1 ; Define if RAk OneWireSerial is used (disables GPS) -build_src_filter = ${nrf52_base.build_src_filter} +<../variants/rak4631> +<../variants/rak2560> + + + +build_src_filter = ${nrf52_base.build_src_filter} +<../variants/rak2560> + + + lib_deps = ${nrf52840_base.lib_deps} ${networking_base.lib_deps} diff --git a/variants/rak2560/variant.cpp b/variants/rak2560/variant.cpp new file mode 100644 index 0000000000..e84b60b3b9 --- /dev/null +++ b/variants/rak2560/variant.cpp @@ -0,0 +1,45 @@ +/* + Copyright (c) 2014-2015 Arduino LLC. All right reserved. + Copyright (c) 2016 Sandeep Mistry All right reserved. + Copyright (c) 2018, Adafruit Industries (adafruit.com) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include "variant.h" +#include "nrf.h" +#include "wiring_constants.h" +#include "wiring_digital.h" + +const uint32_t g_ADigitalPinMap[] = { + // P0 + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, + + // P1 + 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47}; + +void initVariant() +{ + // LED1 & LED2 + pinMode(PIN_LED1, OUTPUT); + ledOff(PIN_LED1); + + pinMode(PIN_LED2, OUTPUT); + ledOff(PIN_LED2); + + // 3V3 Power Rail + pinMode(PIN_3V3_EN, OUTPUT); + digitalWrite(PIN_3V3_EN, HIGH); +} diff --git a/variants/rak2560/variant.h b/variants/rak2560/variant.h new file mode 100644 index 0000000000..7187c8a50b --- /dev/null +++ b/variants/rak2560/variant.h @@ -0,0 +1,280 @@ +/* + Copyright (c) 2014-2015 Arduino LLC. All right reserved. + Copyright (c) 2016 Sandeep Mistry All right reserved. + Copyright (c) 2018, Adafruit Industries (adafruit.com) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the GNU Lesser General Public License for more details. + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef _VARIANT_RAK4630_ +#define _VARIANT_RAK4630_ + +#define RAK4630 + +/** Master clock frequency */ +#define VARIANT_MCK (64000000ul) + +#define USE_LFXO // Board uses 32khz crystal for LF +// define USE_LFRC // Board uses RC for LF + +/*---------------------------------------------------------------------------- + * Headers + *----------------------------------------------------------------------------*/ + +#include "WVariant.h" + +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus + +// Number of pins defined in PinDescription array +#define PINS_COUNT (48) +#define NUM_DIGITAL_PINS (48) +#define NUM_ANALOG_INPUTS (6) +#define NUM_ANALOG_OUTPUTS (0) + +// LEDs +#define PIN_LED1 (35) +#define PIN_LED2 (36) + +#define LED_BUILTIN PIN_LED1 +#define LED_CONN PIN_LED2 + +#define LED_GREEN PIN_LED1 +#define LED_BLUE PIN_LED2 + +#define LED_STATE_ON 1 // State when LED is litted + +/* + * Buttons + */ + +#define PIN_BUTTON1 9 // Pin for button on E-ink button module or IO expansion +#define BUTTON_NEED_PULLUP +#define PIN_BUTTON2 12 +#define PIN_BUTTON3 24 +#define PIN_BUTTON4 25 + +/* + * Analog pins + */ +#define PIN_A0 (5) +#define PIN_A1 (31) +#define PIN_A2 (28) +#define PIN_A3 (29) +#define PIN_A4 (30) +#define PIN_A5 (31) +#define PIN_A6 (0xff) +#define PIN_A7 (0xff) + +static const uint8_t A0 = PIN_A0; +static const uint8_t A1 = PIN_A1; +static const uint8_t A2 = PIN_A2; +static const uint8_t A3 = PIN_A3; +static const uint8_t A4 = PIN_A4; +static const uint8_t A5 = PIN_A5; +static const uint8_t A6 = PIN_A6; +static const uint8_t A7 = PIN_A7; +#define ADC_RESOLUTION 14 + +// Other pins +#define PIN_AREF (2) +#define PIN_NFC1 (9) +#define PIN_NFC2 (10) + +static const uint8_t AREF = PIN_AREF; + +/* + * Serial interfaces + */ +#define PIN_SERIAL1_RX (15) +#define PIN_SERIAL1_TX (16) + +// Connected to Serial 2 +#define PIN_SERIAL2_RX (19) +#define PIN_SERIAL2_TX (20) + +/* + * SPI Interfaces + */ +#define SPI_INTERFACES_COUNT 2 + +#define PIN_SPI_MISO (45) +#define PIN_SPI_MOSI (44) +#define PIN_SPI_SCK (43) + +#define PIN_SPI1_MISO (29) // (0 + 29) +#define PIN_SPI1_MOSI (30) // (0 + 30) +#define PIN_SPI1_SCK (3) // (0 + 3) + +static const uint8_t SS = 42; +static const uint8_t MOSI = PIN_SPI_MOSI; +static const uint8_t MISO = PIN_SPI_MISO; +static const uint8_t SCK = PIN_SPI_SCK; + +/* + * eink display pins + */ + +#define PIN_EINK_CS (0 + 26) +#define PIN_EINK_BUSY (0 + 4) +#define PIN_EINK_DC (0 + 17) +#define PIN_EINK_RES (-1) +#define PIN_EINK_SCLK (0 + 3) +#define PIN_EINK_MOSI (0 + 30) // also called SDI + +// #define USE_EINK + +/* + * Wire Interfaces + */ +#define WIRE_INTERFACES_COUNT 1 + +#define PIN_WIRE_SDA (13) +#define PIN_WIRE_SCL (14) + +// QSPI Pins +#define PIN_QSPI_SCK 3 +#define PIN_QSPI_CS 26 +#define PIN_QSPI_IO0 30 +#define PIN_QSPI_IO1 29 +#define PIN_QSPI_IO2 28 +#define PIN_QSPI_IO3 2 + +/* @note RAK5005-O GPIO mapping to RAK4631 GPIO ports + RAK5005-O <-> nRF52840 + IO1 <-> P0.17 (Arduino GPIO number 17) + IO2 <-> P1.02 (Arduino GPIO number 34) + IO3 <-> P0.21 (Arduino GPIO number 21) + IO4 <-> P0.04 (Arduino GPIO number 4) + IO5 <-> P0.09 (Arduino GPIO number 9) + IO6 <-> P0.10 (Arduino GPIO number 10) + IO7 <-> P0.28 (Arduino GPIO number 28) + SW1 <-> P0.01 (Arduino GPIO number 1) + A0 <-> P0.04/AIN2 (Arduino Analog A2 + A1 <-> P0.31/AIN7 (Arduino Analog A7 + SPI_CS <-> P0.26 (Arduino GPIO number 26) + */ + +// RAK4630 LoRa module + +/* Setup of the SX1262 LoRa module ( https://docs.rakwireless.com/Product-Categories/WisBlock/RAK4631/Datasheet/ ) + +P1.10 NSS SPI NSS (Arduino GPIO number 42) +P1.11 SCK SPI CLK (Arduino GPIO number 43) +P1.12 MOSI SPI MOSI (Arduino GPIO number 44) +P1.13 MISO SPI MISO (Arduino GPIO number 45) +P1.14 BUSY BUSY signal (Arduino GPIO number 46) +P1.15 DIO1 DIO1 event interrupt (Arduino GPIO number 47) +P1.06 NRESET NRESET manual reset of the SX1262 (Arduino GPIO number 38) + +Important for successful SX1262 initialization: + +* Setup DIO2 to control the antenna switch +* Setup DIO3 to control the TCXO power supply +* Setup the SX1262 to use it's DCDC regulator and not the LDO +* RAK4630 schematics show GPIO P1.07 connected to the antenna switch, but it should not be initialized, as DIO2 will do the +control of the antenna switch + +SO GPIO 39/TXEN MAY NOT BE DEFINED FOR SUCCESSFUL OPERATION OF THE SX1262 - TG + +*/ + +#define DETECTION_SENSOR_EN 4 + +#define USE_SX1262 +#define SX126X_CS (42) +#define SX126X_DIO1 (47) +#define SX126X_BUSY (46) +#define SX126X_RESET (38) +// #define SX126X_TXEN (39) +// #define SX126X_RXEN (37) +#define SX126X_POWER_EN (37) +// DIO2 controlls an antenna switch and the TCXO voltage is controlled by DIO3 +#define SX126X_DIO2_AS_RF_SWITCH +#define SX126X_DIO3_TCXO_VOLTAGE 1.8 + +// Testing USB detection +#define NRF_APM + +// enables 3.3V periphery like GPS or IO Module +// Do not toggle this for GPS power savings +#define PIN_3V3_EN (34) + +// RAK1910 GPS module +// If using the wisblock GPS module and pluged into Port A on WisBlock base +// IO1 is hooked to PPS (pin 12 on header) = gpio 17 +// IO2 is hooked to GPS RESET = gpio 34, but it can not be used to this because IO2 is ALSO used to control 3V3_S power (1 is on). +// Therefore must be 1 to keep peripherals powered +// Power is on the controllable 3V3_S rail +// #define PIN_GPS_RESET (34) +// #define PIN_GPS_EN PIN_3V3_EN +#define PIN_GPS_PPS (17) // Pulse per second input from the GPS + +// On RAK2560 the GPS is be on a different UART +// #define GPS_RX_PIN PIN_SERIAL2_RX +// #define GPS_TX_PIN PIN_SERIAL2_TX +// #define PIN_GPS_EN PIN_3V3_EN +// Disable GPS +#define MESHTASTIC_EXCLUDE_GPS 1 +// Define pin to enable GPS toggle (set GPIO to LOW) via user button triple press + +// RAK12002 RTC Module +#define RV3028_RTC (uint8_t)0b1010010 + +// RAK18001 Buzzer in Slot C +// #define PIN_BUZZER 21 // IO3 is PWM2 +// NEW: set this via protobuf instead! + +// Battery +// The battery sense is hooked to pin A0 (5) +#define BATTERY_PIN PIN_A0 +// and has 12 bit resolution +#define BATTERY_SENSE_RESOLUTION_BITS 12 +#define BATTERY_SENSE_RESOLUTION 4096.0 +#undef AREF_VOLTAGE +#define AREF_VOLTAGE 3.0 +#define VBAT_AR_INTERNAL AR_INTERNAL_3_0 +#define ADC_MULTIPLIER 1.73 + +#define HAS_RTC 1 + +#define HAS_ETHERNET 1 + +#define RAK_4631 1 + +#define HALF_UART_PIN PIN_SERIAL1_RX + +#if defined(GPS_RX_PIN) && (GPS_RX_PIN == HALF_UART_PIN) +#error pin 15 collision + +#endif + +#if defined(GPS_TX_PIN) && (GPS_RX_PIN == HALF_UART_PIN) +#error pin 15 collision +#endif + +#define PIN_ETHERNET_RESET 21 +#define PIN_ETHERNET_SS PIN_EINK_CS +#define ETH_SPI_PORT SPI1 +#define AQ_SET_PIN 10 + +#ifdef __cplusplus +} +#endif + +/*---------------------------------------------------------------------------- + * Arduino objects - C++ only + *----------------------------------------------------------------------------*/ + +#endif \ No newline at end of file diff --git a/variants/rak4631/variant.h b/variants/rak4631/variant.h index e9f1a18651..2ce1b960aa 100644 --- a/variants/rak4631/variant.h +++ b/variants/rak4631/variant.h @@ -34,7 +34,8 @@ #include "WVariant.h" #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif // __cplusplus // Number of pins defined in PinDescription array @@ -55,9 +56,9 @@ extern "C" { #define LED_STATE_ON 1 // State when LED is litted -/* - * Buttons - */ + /* + * Buttons + */ #define PIN_BUTTON1 9 // Pin for button on E-ink button module or IO expansion #define BUTTON_NEED_PULLUP @@ -77,14 +78,14 @@ extern "C" { #define PIN_A6 (0xff) #define PIN_A7 (0xff) -static const uint8_t A0 = PIN_A0; -static const uint8_t A1 = PIN_A1; -static const uint8_t A2 = PIN_A2; -static const uint8_t A3 = PIN_A3; -static const uint8_t A4 = PIN_A4; -static const uint8_t A5 = PIN_A5; -static const uint8_t A6 = PIN_A6; -static const uint8_t A7 = PIN_A7; + static const uint8_t A0 = PIN_A0; + static const uint8_t A1 = PIN_A1; + static const uint8_t A2 = PIN_A2; + static const uint8_t A3 = PIN_A3; + static const uint8_t A4 = PIN_A4; + static const uint8_t A5 = PIN_A5; + static const uint8_t A6 = PIN_A6; + static const uint8_t A7 = PIN_A7; #define ADC_RESOLUTION 14 // Other pins @@ -92,7 +93,7 @@ static const uint8_t A7 = PIN_A7; #define PIN_NFC1 (9) #define PIN_NFC2 (10) -static const uint8_t AREF = PIN_AREF; + static const uint8_t AREF = PIN_AREF; /* * Serial interfaces @@ -100,9 +101,9 @@ static const uint8_t AREF = PIN_AREF; #define PIN_SERIAL1_RX (15) #define PIN_SERIAL1_TX (16) -// Connected to Serial 2 -#define PIN_SERIAL2_RX (19) -#define PIN_SERIAL2_TX (20) +// Connected to Jlink CDC +#define PIN_SERIAL2_RX (8) +#define PIN_SERIAL2_TX (6) /* * SPI Interfaces @@ -117,14 +118,14 @@ static const uint8_t AREF = PIN_AREF; #define PIN_SPI1_MOSI (30) // (0 + 30) #define PIN_SPI1_SCK (3) // (0 + 3) -static const uint8_t SS = 42; -static const uint8_t MOSI = PIN_SPI_MOSI; -static const uint8_t MISO = PIN_SPI_MISO; -static const uint8_t SCK = PIN_SPI_SCK; + static const uint8_t SS = 42; + static const uint8_t MOSI = PIN_SPI_MOSI; + static const uint8_t MISO = PIN_SPI_MISO; + static const uint8_t SCK = PIN_SPI_SCK; -/* - * eink display pins - */ + /* + * eink display pins + */ #define PIN_EINK_CS (0 + 26) #define PIN_EINK_BUSY (0 + 4) @@ -158,44 +159,44 @@ static const uint8_t SCK = PIN_SPI_SCK; #define EXTERNAL_FLASH_DEVICES IS25LP080D #define EXTERNAL_FLASH_USE_QSPI -/* @note RAK5005-O GPIO mapping to RAK4631 GPIO ports - RAK5005-O <-> nRF52840 - IO1 <-> P0.17 (Arduino GPIO number 17) - IO2 <-> P1.02 (Arduino GPIO number 34) - IO3 <-> P0.21 (Arduino GPIO number 21) - IO4 <-> P0.04 (Arduino GPIO number 4) - IO5 <-> P0.09 (Arduino GPIO number 9) - IO6 <-> P0.10 (Arduino GPIO number 10) - IO7 <-> P0.28 (Arduino GPIO number 28) - SW1 <-> P0.01 (Arduino GPIO number 1) - A0 <-> P0.04/AIN2 (Arduino Analog A2 - A1 <-> P0.31/AIN7 (Arduino Analog A7 - SPI_CS <-> P0.26 (Arduino GPIO number 26) - */ - -// RAK4630 LoRa module - -/* Setup of the SX1262 LoRa module ( https://docs.rakwireless.com/Product-Categories/WisBlock/RAK4631/Datasheet/ ) - -P1.10 NSS SPI NSS (Arduino GPIO number 42) -P1.11 SCK SPI CLK (Arduino GPIO number 43) -P1.12 MOSI SPI MOSI (Arduino GPIO number 44) -P1.13 MISO SPI MISO (Arduino GPIO number 45) -P1.14 BUSY BUSY signal (Arduino GPIO number 46) -P1.15 DIO1 DIO1 event interrupt (Arduino GPIO number 47) -P1.06 NRESET NRESET manual reset of the SX1262 (Arduino GPIO number 38) - -Important for successful SX1262 initialization: - -* Setup DIO2 to control the antenna switch -* Setup DIO3 to control the TCXO power supply -* Setup the SX1262 to use it's DCDC regulator and not the LDO -* RAK4630 schematics show GPIO P1.07 connected to the antenna switch, but it should not be initialized, as DIO2 will do the -control of the antenna switch - -SO GPIO 39/TXEN MAY NOT BE DEFINED FOR SUCCESSFUL OPERATION OF THE SX1262 - TG - -*/ + /* @note RAK5005-O GPIO mapping to RAK4631 GPIO ports + RAK5005-O <-> nRF52840 + IO1 <-> P0.17 (Arduino GPIO number 17) + IO2 <-> P1.02 (Arduino GPIO number 34) + IO3 <-> P0.21 (Arduino GPIO number 21) + IO4 <-> P0.04 (Arduino GPIO number 4) + IO5 <-> P0.09 (Arduino GPIO number 9) + IO6 <-> P0.10 (Arduino GPIO number 10) + IO7 <-> P0.28 (Arduino GPIO number 28) + SW1 <-> P0.01 (Arduino GPIO number 1) + A0 <-> P0.04/AIN2 (Arduino Analog A2 + A1 <-> P0.31/AIN7 (Arduino Analog A7 + SPI_CS <-> P0.26 (Arduino GPIO number 26) + */ + + // RAK4630 LoRa module + + /* Setup of the SX1262 LoRa module ( https://docs.rakwireless.com/Product-Categories/WisBlock/RAK4631/Datasheet/ ) + + P1.10 NSS SPI NSS (Arduino GPIO number 42) + P1.11 SCK SPI CLK (Arduino GPIO number 43) + P1.12 MOSI SPI MOSI (Arduino GPIO number 44) + P1.13 MISO SPI MISO (Arduino GPIO number 45) + P1.14 BUSY BUSY signal (Arduino GPIO number 46) + P1.15 DIO1 DIO1 event interrupt (Arduino GPIO number 47) + P1.06 NRESET NRESET manual reset of the SX1262 (Arduino GPIO number 38) + + Important for successful SX1262 initialization: + + * Setup DIO2 to control the antenna switch + * Setup DIO3 to control the TCXO power supply + * Setup the SX1262 to use it's DCDC regulator and not the LDO + * RAK4630 schematics show GPIO P1.07 connected to the antenna switch, but it should not be initialized, as DIO2 will do the + control of the antenna switch + + SO GPIO 39/TXEN MAY NOT BE DEFINED FOR SUCCESSFUL OPERATION OF THE SX1262 - TG + + */ #define DETECTION_SENSOR_EN 4 @@ -228,18 +229,9 @@ SO GPIO 39/TXEN MAY NOT BE DEFINED FOR SUCCESSFUL OPERATION OF THE SX1262 - TG // #define PIN_GPS_EN PIN_3V3_EN #define PIN_GPS_PPS (17) // Pulse per second input from the GPS -// On RAK2560 the GPS is be on a different UART -#ifdef HAS_RAKPROT -// #define GPS_RX_PIN PIN_SERIAL2_RX -// #define GPS_TX_PIN PIN_SERIAL2_TX -// #define PIN_GPS_EN PIN_3V3_EN -// Disable GPS -#define MESHTASTIC_EXCLUDE_GPS 1 -#else - // Enable GPS #define GPS_RX_PIN PIN_SERIAL1_RX #define GPS_TX_PIN PIN_SERIAL1_TX -#endif + // Define pin to enable GPS toggle (set GPIO to LOW) via user button triple press // RAK12002 RTC Module @@ -266,21 +258,6 @@ SO GPIO 39/TXEN MAY NOT BE DEFINED FOR SUCCESSFUL OPERATION OF THE SX1262 - TG #define RAK_4631 1 -#ifdef HAS_RAKPROT - -#define HALF_UART_PIN PIN_SERIAL1_RX - -#if defined(GPS_RX_PIN) && (GPS_RX_PIN == HALF_UART_PIN) -#error pin 15 collision - -#endif - -#if defined(GPS_TX_PIN) && (GPS_RX_PIN == HALF_UART_PIN) -#error pin 15 collision -#endif - -#endif - #define PIN_ETHERNET_RESET 21 #define PIN_ETHERNET_SS PIN_EINK_CS #define ETH_SPI_PORT SPI1 From ceb884cf1827ac13205b1bc605c42cced4d5a95e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20G=C3=B6ttgens?= Date: Sun, 16 Jun 2024 16:29:45 +0200 Subject: [PATCH 45/65] trunk fmt --- src/Power.cpp | 36 ++--- src/power.h | 40 ++--- variants/rak2560/RAK9154Sensor.cpp | 248 ++++++++++++++--------------- variants/rak2560/create_uf2.py | 35 ++-- variants/rak4631/variant.h | 117 +++++++------- 5 files changed, 238 insertions(+), 238 deletions(-) diff --git a/src/Power.cpp b/src/Power.cpp index 18dbfebe4d..18a527cee7 100644 --- a/src/Power.cpp +++ b/src/Power.cpp @@ -351,19 +351,19 @@ class AnalogBatteryLevel : public HasBatteryLevel virtual bool isVbusIn() override { #ifdef EXT_PWR_DETECT - #ifdef HELTEC_CAPSULE_SENSOR_V3 - // if external powered that pin will be pulled down - if (digitalRead(EXT_PWR_DETECT) == LOW) { - return true; - } - // if it's not LOW - check the battery - #else - // if external powered that pin will be pulled up - if (digitalRead(EXT_PWR_DETECT) == HIGH) { - return true; - } - // if it's not HIGH - check the battery - #endif +#ifdef HELTEC_CAPSULE_SENSOR_V3 + // if external powered that pin will be pulled down + if (digitalRead(EXT_PWR_DETECT) == LOW) { + return true; + } + // if it's not LOW - check the battery +#else + // if external powered that pin will be pulled up + if (digitalRead(EXT_PWR_DETECT) == HIGH) { + return true; + } + // if it's not HIGH - check the battery +#endif #endif return getBattVoltage() > chargingVolt; } @@ -461,11 +461,11 @@ Power::Power() : OSThread("Power") bool Power::analogInit() { #ifdef EXT_PWR_DETECT - #ifdef HELTEC_CAPSULE_SENSOR_V3 - pinMode(EXT_PWR_DETECT, INPUT_PULLUP); - #else - pinMode(EXT_PWR_DETECT, INPUT); - #endif +#ifdef HELTEC_CAPSULE_SENSOR_V3 + pinMode(EXT_PWR_DETECT, INPUT_PULLUP); +#else + pinMode(EXT_PWR_DETECT, INPUT); +#endif #endif #ifdef EXT_CHRG_DETECT pinMode(EXT_CHRG_DETECT, ext_chrg_detect_mode); diff --git a/src/power.h b/src/power.h index c343a45ebd..b970dfeafd 100644 --- a/src/power.h +++ b/src/power.h @@ -1,8 +1,8 @@ #pragma once +#include "../variants/rak2560/RAK9154Sensor.h" #include "PowerStatus.h" #include "concurrency/OSThread.h" #include "configuration.h" -#include "../variants/rak2560/RAK9154Sensor.h" #ifdef ARCH_ESP32 #include @@ -56,31 +56,31 @@ extern RAK9154Sensor rak9154Sensor; class Power : private concurrency::OSThread { -public: - Observable newStatus; + public: + Observable newStatus; - Power(); + Power(); - void shutdown(); - void readPowerStatus(); - virtual bool setup(); - virtual int32_t runOnce() override; - void setStatusHandler(meshtastic::PowerStatus *handler) { statusHandler = handler; } - const uint16_t OCV[11] = {OCV_ARRAY}; + void shutdown(); + void readPowerStatus(); + virtual bool setup(); + virtual int32_t runOnce() override; + void setStatusHandler(meshtastic::PowerStatus *handler) { statusHandler = handler; } + const uint16_t OCV[11] = {OCV_ARRAY}; -protected: - meshtastic::PowerStatus *statusHandler; + protected: + meshtastic::PowerStatus *statusHandler; - /// Setup a xpowers chip axp192/axp2101, return true if found - bool axpChipInit(); - /// Setup a simple ADC input based battery sensor - bool analogInit(); + /// Setup a xpowers chip axp192/axp2101, return true if found + bool axpChipInit(); + /// Setup a simple ADC input based battery sensor + bool analogInit(); -private: - // open circuit voltage lookup table - uint8_t low_voltage_counter; + private: + // open circuit voltage lookup table + uint8_t low_voltage_counter; #ifdef DEBUG_HEAP - uint32_t lastheap; + uint32_t lastheap; #endif }; diff --git a/variants/rak2560/RAK9154Sensor.cpp b/variants/rak2560/RAK9154Sensor.cpp index 15a172c182..9f660947e8 100644 --- a/variants/rak2560/RAK9154Sensor.cpp +++ b/variants/rak2560/RAK9154Sensor.cpp @@ -4,8 +4,8 @@ #include "../modules/Telemetry/Sensor/TelemetrySensor.h" #include "configuration.h" -#include #include "concurrency/Periodic.h" +#include using namespace concurrency; @@ -27,165 +27,157 @@ static uint8_t provision = 0; static void onewire_evt(const uint8_t pid, const uint8_t sid, const SNHUBAPI_EVT_E eid, uint8_t *msg, uint16_t len) { - switch (eid) - { - case SNHUBAPI_EVT_RECV_REQ: - case SNHUBAPI_EVT_RECV_RSP: - break; - - case SNHUBAPI_EVT_QSEND: - mySerial.write(msg, len); - break; - - case SNHUBAPI_EVT_ADD_SID: - // LOG_INFO("+ADD:SID:[%02x]\r\n", msg[0]); - break; - - case SNHUBAPI_EVT_ADD_PID: - // LOG_INFO("+ADD:PID:[%02x]\r\n", msg[0]); + switch (eid) { + case SNHUBAPI_EVT_RECV_REQ: + case SNHUBAPI_EVT_RECV_RSP: + break; + + case SNHUBAPI_EVT_QSEND: + mySerial.write(msg, len); + break; + + case SNHUBAPI_EVT_ADD_SID: + // LOG_INFO("+ADD:SID:[%02x]\r\n", msg[0]); + break; + + case SNHUBAPI_EVT_ADD_PID: + // LOG_INFO("+ADD:PID:[%02x]\r\n", msg[0]); #ifdef BOOT_DATA_REQ - provision = msg[0]; + provision = msg[0]; #endif - break; - - case SNHUBAPI_EVT_GET_INTV: - break; - - case SNHUBAPI_EVT_GET_ENABLE: - break; - - case SNHUBAPI_EVT_SDATA_REQ: - - // LOG_INFO("+EVT:PID[%02x],IPSO[%02x]\r\n",pid,msg[0]); - // for( uint16_t i=1; i 100) - { - dc_prec = 100; - } - break; - case RAK_IPSO_DC_CURRENT: - dc_cur = (msg[2] << 8) + msg[1]; - break; - case RAK_IPSO_DC_VOLTAGE: - dc_vol = (msg[2] << 8) + msg[1]; - dc_vol *= 10; - break; - default: - break; - } - - break; - case SNHUBAPI_EVT_REPORT: - - // LOG_INFO("+EVT:PID[%02x],IPSO[%02x]\r\n",pid,msg[0]); - // for( uint16_t i=1; i 100) - { - dc_prec = 100; - } - break; - case RAK_IPSO_DC_CURRENT: - dc_cur = (msg[1] << 8) + msg[2]; - break; - case RAK_IPSO_DC_VOLTAGE: - dc_vol = (msg[1] << 8) + msg[2]; - dc_vol *= 10; - break; - default: - break; - } - - break; - - case SNHUBAPI_EVT_CHKSUM_ERR: - LOG_INFO("+ERR:CHKSUM\r\n"); - break; - - case SNHUBAPI_EVT_SEQ_ERR: - LOG_INFO("+ERR:SEQUCE\r\n"); - break; - - default: - break; - } + break; + + case SNHUBAPI_EVT_GET_INTV: + break; + + case SNHUBAPI_EVT_GET_ENABLE: + break; + + case SNHUBAPI_EVT_SDATA_REQ: + + // LOG_INFO("+EVT:PID[%02x],IPSO[%02x]\r\n",pid,msg[0]); + // for( uint16_t i=1; i 100) { + dc_prec = 100; + } + break; + case RAK_IPSO_DC_CURRENT: + dc_cur = (msg[2] << 8) + msg[1]; + break; + case RAK_IPSO_DC_VOLTAGE: + dc_vol = (msg[2] << 8) + msg[1]; + dc_vol *= 10; + break; + default: + break; + } + + break; + case SNHUBAPI_EVT_REPORT: + + // LOG_INFO("+EVT:PID[%02x],IPSO[%02x]\r\n",pid,msg[0]); + // for( uint16_t i=1; i 100) { + dc_prec = 100; + } + break; + case RAK_IPSO_DC_CURRENT: + dc_cur = (msg[1] << 8) + msg[2]; + break; + case RAK_IPSO_DC_VOLTAGE: + dc_vol = (msg[1] << 8) + msg[2]; + dc_vol *= 10; + break; + default: + break; + } + + break; + + case SNHUBAPI_EVT_CHKSUM_ERR: + LOG_INFO("+ERR:CHKSUM\r\n"); + break; + + case SNHUBAPI_EVT_SEQ_ERR: + LOG_INFO("+ERR:SEQUCE\r\n"); + break; + + default: + break; + } } static int32_t onewireHandle() { - if (provision != 0) - { - RakSNHub_Protocl_API.get.data(provision); - provision = 0; - } - - while (mySerial.available()) - { - char a = mySerial.read(); - buff[bufflen++] = a; - delay(2); // continue data, timeout=2ms - } - - if (bufflen != 0) - { - RakSNHub_Protocl_API.process((uint8_t *)buff, bufflen); - bufflen = 0; - } - - return 50; + if (provision != 0) { + RakSNHub_Protocl_API.get.data(provision); + provision = 0; + } + + while (mySerial.available()) { + char a = mySerial.read(); + buff[bufflen++] = a; + delay(2); // continue data, timeout=2ms + } + + if (bufflen != 0) { + RakSNHub_Protocl_API.process((uint8_t *)buff, bufflen); + bufflen = 0; + } + + return 50; } int32_t RAK9154Sensor::runOnce() { - onewirePeriodic = new Periodic("onewireHandle", onewireHandle); + onewirePeriodic = new Periodic("onewireHandle", onewireHandle); - mySerial.begin(9600); + mySerial.begin(9600); - RakSNHub_Protocl_API.init(onewire_evt); + RakSNHub_Protocl_API.init(onewire_evt); - status = true; - initialized = true; - return 0; + status = true; + initialized = true; + return 0; } void RAK9154Sensor::setup() { - // Set up oversampling and filter initialization + // Set up oversampling and filter initialization } bool RAK9154Sensor::getMetrics(meshtastic_Telemetry *measurement) { - return true; + return true; } uint16_t RAK9154Sensor::getBusVoltageMv() { - return dc_vol; + return dc_vol; } int RAK9154Sensor::getBusBatteryPercent() { - return (int)dc_prec; + return (int)dc_prec; } bool RAK9154Sensor::isCharging() { - return (dc_cur > 0) ? true : false; + return (dc_cur > 0) ? true : false; } #endif // HAS_RAKPROT \ No newline at end of file diff --git a/variants/rak2560/create_uf2.py b/variants/rak2560/create_uf2.py index d14eaea029..cf6b11606b 100644 --- a/variants/rak2560/create_uf2.py +++ b/variants/rak2560/create_uf2.py @@ -1,22 +1,23 @@ -import sys import struct +import sys Import("env") + # Parse input and create UF2 file def create_uf2(source, target, env): # source_hex = target[0].get_abspath() source_hex = target[0].get_string(False) - source_hex = '.\\'+source_hex + source_hex = ".\\" + source_hex print("#########################################################") - print("Create UF2 from "+source_hex) + print("Create UF2 from " + source_hex) print("#########################################################") # print("Source: " + source_hex) target = source_hex.replace(".hex", "") target = target + ".uf2" # print("Target: " + target) - with open(source_hex, mode='rb') as f: + with open(source_hex, mode="rb") as f: inpbuf = f.read() outbuf = convert_from_hex_to_uf2(inpbuf.decode("utf-8")) @@ -48,9 +49,17 @@ def encode(self, blockno, numblocks): flags = 0x0 if familyid: flags |= 0x2000 - hd = struct.pack(" nRF52840 - IO1 <-> P0.17 (Arduino GPIO number 17) - IO2 <-> P1.02 (Arduino GPIO number 34) - IO3 <-> P0.21 (Arduino GPIO number 21) - IO4 <-> P0.04 (Arduino GPIO number 4) - IO5 <-> P0.09 (Arduino GPIO number 9) - IO6 <-> P0.10 (Arduino GPIO number 10) - IO7 <-> P0.28 (Arduino GPIO number 28) - SW1 <-> P0.01 (Arduino GPIO number 1) - A0 <-> P0.04/AIN2 (Arduino Analog A2 - A1 <-> P0.31/AIN7 (Arduino Analog A7 - SPI_CS <-> P0.26 (Arduino GPIO number 26) - */ - - // RAK4630 LoRa module - - /* Setup of the SX1262 LoRa module ( https://docs.rakwireless.com/Product-Categories/WisBlock/RAK4631/Datasheet/ ) - - P1.10 NSS SPI NSS (Arduino GPIO number 42) - P1.11 SCK SPI CLK (Arduino GPIO number 43) - P1.12 MOSI SPI MOSI (Arduino GPIO number 44) - P1.13 MISO SPI MISO (Arduino GPIO number 45) - P1.14 BUSY BUSY signal (Arduino GPIO number 46) - P1.15 DIO1 DIO1 event interrupt (Arduino GPIO number 47) - P1.06 NRESET NRESET manual reset of the SX1262 (Arduino GPIO number 38) - - Important for successful SX1262 initialization: - - * Setup DIO2 to control the antenna switch - * Setup DIO3 to control the TCXO power supply - * Setup the SX1262 to use it's DCDC regulator and not the LDO - * RAK4630 schematics show GPIO P1.07 connected to the antenna switch, but it should not be initialized, as DIO2 will do the - control of the antenna switch - - SO GPIO 39/TXEN MAY NOT BE DEFINED FOR SUCCESSFUL OPERATION OF THE SX1262 - TG - - */ +/* @note RAK5005-O GPIO mapping to RAK4631 GPIO ports + RAK5005-O <-> nRF52840 + IO1 <-> P0.17 (Arduino GPIO number 17) + IO2 <-> P1.02 (Arduino GPIO number 34) + IO3 <-> P0.21 (Arduino GPIO number 21) + IO4 <-> P0.04 (Arduino GPIO number 4) + IO5 <-> P0.09 (Arduino GPIO number 9) + IO6 <-> P0.10 (Arduino GPIO number 10) + IO7 <-> P0.28 (Arduino GPIO number 28) + SW1 <-> P0.01 (Arduino GPIO number 1) + A0 <-> P0.04/AIN2 (Arduino Analog A2 + A1 <-> P0.31/AIN7 (Arduino Analog A7 + SPI_CS <-> P0.26 (Arduino GPIO number 26) + */ + +// RAK4630 LoRa module + +/* Setup of the SX1262 LoRa module ( https://docs.rakwireless.com/Product-Categories/WisBlock/RAK4631/Datasheet/ ) + +P1.10 NSS SPI NSS (Arduino GPIO number 42) +P1.11 SCK SPI CLK (Arduino GPIO number 43) +P1.12 MOSI SPI MOSI (Arduino GPIO number 44) +P1.13 MISO SPI MISO (Arduino GPIO number 45) +P1.14 BUSY BUSY signal (Arduino GPIO number 46) +P1.15 DIO1 DIO1 event interrupt (Arduino GPIO number 47) +P1.06 NRESET NRESET manual reset of the SX1262 (Arduino GPIO number 38) + +Important for successful SX1262 initialization: + +* Setup DIO2 to control the antenna switch +* Setup DIO3 to control the TCXO power supply +* Setup the SX1262 to use it's DCDC regulator and not the LDO +* RAK4630 schematics show GPIO P1.07 connected to the antenna switch, but it should not be initialized, as DIO2 will do the +control of the antenna switch + +SO GPIO 39/TXEN MAY NOT BE DEFINED FOR SUCCESSFUL OPERATION OF THE SX1262 - TG + +*/ #define DETECTION_SENSOR_EN 4 From 11c3ca541fbf8bc7fcbddd97ac2e408a2e16886e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20G=C3=B6ttgens?= Date: Sun, 16 Jun 2024 20:03:45 +0200 Subject: [PATCH 46/65] add proper RAK variant and change pathspec --- src/platform/nrf52/architecture.h | 2 ++ variants/rak2560/platformio.ini | 2 +- variants/rak2560/variant.h | 5 +++-- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/platform/nrf52/architecture.h b/src/platform/nrf52/architecture.h index 18a4d75f57..b66552a284 100644 --- a/src/platform/nrf52/architecture.h +++ b/src/platform/nrf52/architecture.h @@ -42,6 +42,8 @@ #define HW_VENDOR meshtastic_HardwareModel_NRF52840DK #elif defined(ARDUINO_NRF52840_PPR) #define HW_VENDOR meshtastic_HardwareModel_PPR +#elif defined(RAK2560) +#define HW_VENDOR meshtastic_HardwareModel_RAK2560 #elif defined(RAK4630) #define HW_VENDOR meshtastic_HardwareModel_RAK4631 #elif defined(TTGO_T_ECHO) diff --git a/variants/rak2560/platformio.ini b/variants/rak2560/platformio.ini index 71b235aaca..ff667aadfa 100644 --- a/variants/rak2560/platformio.ini +++ b/variants/rak2560/platformio.ini @@ -21,4 +21,4 @@ debug_tool = jlink ;upload_protocol = jlink extra_scripts = ${env.extra_scripts} - ../firmware/variants/rak2560/create_uf2.py \ No newline at end of file + ./variants/rak2560/create_uf2.py \ No newline at end of file diff --git a/variants/rak2560/variant.h b/variants/rak2560/variant.h index 7187c8a50b..0c1c9aed90 100644 --- a/variants/rak2560/variant.h +++ b/variants/rak2560/variant.h @@ -16,10 +16,11 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -#ifndef _VARIANT_RAK4630_ -#define _VARIANT_RAK4630_ +#ifndef _VARIANT_RAK2560_ +#define _VARIANT_RAK2560_ #define RAK4630 +#define RAK2560 /** Master clock frequency */ #define VARIANT_MCK (64000000ul) From 4fe281cf7fb07aec5e7a0f0e20e13651a721c3bb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20G=C3=B6ttgens?= Date: Sun, 16 Jun 2024 20:11:58 +0200 Subject: [PATCH 47/65] tryfix linter error --- variants/rak2560/create_uf2.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/variants/rak2560/create_uf2.py b/variants/rak2560/create_uf2.py index cf6b11606b..af78f3e097 100644 --- a/variants/rak2560/create_uf2.py +++ b/variants/rak2560/create_uf2.py @@ -1,7 +1,6 @@ import struct -import sys -Import("env") +Import("env") # noqa: F821 # Parse input and create UF2 file @@ -29,7 +28,7 @@ def create_uf2(source, target, env): # Add callback after .hex file was created -env.AddPostAction("$BUILD_DIR/${PROGNAME}.hex", create_uf2) +env.AddPostAction("$BUILD_DIR/${PROGNAME}.hex", create_uf2) # noqa: F821 # UF2 creation taken from uf2conv.py UF2_MAGIC_START0 = 0x0A324655 # "UF2\n" @@ -97,7 +96,7 @@ def convert_from_hex_to_uf2(buf): break elif tp == 0: addr = upper | (rec[1] << 8) | rec[2] - if appstartaddr == None: + if appstartaddr is None: appstartaddr = addr i = 4 while i < len(rec) - 1: From aca0807acfbd286473fa66c603fd34b1bd0f7de3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20G=C3=B6ttgens?= Date: Sun, 16 Jun 2024 20:41:23 +0200 Subject: [PATCH 48/65] more try more fix --- .trunk/configs/.bandit | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 .trunk/configs/.bandit diff --git a/.trunk/configs/.bandit b/.trunk/configs/.bandit new file mode 100644 index 0000000000..d286ded897 --- /dev/null +++ b/.trunk/configs/.bandit @@ -0,0 +1,2 @@ +[bandit] +skips = B101 \ No newline at end of file From 369d3797200ba27cbb93929d05bb2368e913d8c7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20G=C3=B6ttgens?= Date: Sun, 16 Jun 2024 21:08:34 +0200 Subject: [PATCH 49/65] CI is creating the uf2 file during build --- variants/rak2560/platformio.ini | 3 --- 1 file changed, 3 deletions(-) diff --git a/variants/rak2560/platformio.ini b/variants/rak2560/platformio.ini index ff667aadfa..96c1bfa92b 100644 --- a/variants/rak2560/platformio.ini +++ b/variants/rak2560/platformio.ini @@ -19,6 +19,3 @@ lib_deps = debug_tool = jlink ; If not set we will default to uploading over serial (first it forces bootloader entry by talking 1200bps to cdcacm) ;upload_protocol = jlink -extra_scripts = - ${env.extra_scripts} - ./variants/rak2560/create_uf2.py \ No newline at end of file From 7aea056ac0bdaf0e101202549796a749f6589273 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20G=C3=B6ttgens?= Date: Sun, 16 Jun 2024 22:43:16 +0200 Subject: [PATCH 50/65] exclude debs from release zip --- .github/workflows/main_matrix.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/main_matrix.yml b/.github/workflows/main_matrix.yml index 89b71acb84..25a0fbad22 100644 --- a/.github/workflows/main_matrix.yml +++ b/.github/workflows/main_matrix.yml @@ -254,7 +254,7 @@ jobs: chmod +x ./output/device-update.sh - name: Zip firmware - run: zip -j -9 -r ./firmware-${{ steps.version.outputs.version }}.zip ./output + run: zip -j -9 -r ./firmware-${{ steps.version.outputs.version }}.zip ./output -x *.deb - uses: actions/download-artifact@v4 with: From ea69b999f9b602c7baba6508d63c27985872e18d Mon Sep 17 00:00:00 2001 From: geeksville Date: Sun, 16 Jun 2024 13:59:38 -0700 Subject: [PATCH 51/65] Add rak4631_dap variant for debugging with NanoDAP debug probe device. --- variants/rak4631/platformio.ini | 30 +++++++++++++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) diff --git a/variants/rak4631/platformio.ini b/variants/rak4631/platformio.ini index 4870d4b68e..b9bf42655d 100644 --- a/variants/rak4631/platformio.ini +++ b/variants/rak4631/platformio.ini @@ -18,5 +18,33 @@ lib_deps = rakwireless/RAKwireless NCP5623 RGB LED library@^1.0.2 https://github.com/meshtastic/RAK12034-BMX160.git#4821355fb10390ba8557dc43ca29a023bcfbb9d9 debug_tool = jlink + ; If not set we will default to uploading over serial (first it forces bootloader entry by talking 1200bps to cdcacm) -;upload_protocol = jlink \ No newline at end of file +; Note: as of 6/2013 the serial/bootloader based programming takes approximately 30 seconds +;upload_protocol = jlink + +; Allows programming and debug via the RAK NanoDAP as the default debugger tool for the RAK4631 (it is only $10!) +; programming time is about the same as the bootloader version. +; For information on this see the meshtastic developers documentation for "Development on the NRF52" +[env:rak4631_dap] +extends = env:rak4631 +; pyocd pack --i nrf52840 +; eventually use platformio/tool-pyocd@^2.3600.0 instad +upload_protocol = custom +upload_command = pyocd flash -t nrf52840 $UPLOADERFLAGS $SOURCE + +; Only reprogram the board if the code has changed +debug_load_mode = modified +;debug_load_mode = manual +debug_tool = custom +; We manually pass in the elf file so that pyocd can reverse engineer FreeRTOS data (running threads, etc...) +debug_server = + pyocd + gdbserver + -t + nrf52840 + --elf + ${platformio.build_dir}/${this.__env__}/firmware.elf +; The following is not needed because it automatically tries do this +;debug_server_ready_pattern = -.*GDB server started on port \d+.* +;debug_port = localhost:3333 \ No newline at end of file From 163a732ddc5f904685091fd571328ee54a6f74b0 Mon Sep 17 00:00:00 2001 From: geeksville Date: Sun, 16 Jun 2024 17:17:19 -0700 Subject: [PATCH 52/65] Turn off vscode cmake prompt - we don't use cmake on meshtastic (#4122) --- .vscode/settings.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index e86d31c7d1..07e198f0a7 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -3,5 +3,6 @@ "editor.defaultFormatter": "trunk.io", "trunk.enableWindows": true, "files.insertFinalNewline": false, - "files.trimFinalNewlines": false + "files.trimFinalNewlines": false, + "cmake.configureOnOpen": false } From 7afa8107ae5f8f5c8d9a9fba5173d1450c54b8b1 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Sun, 16 Jun 2024 19:22:51 -0500 Subject: [PATCH 53/65] [create-pull-request] automated change (#4121) Co-authored-by: thebentern <9000580+thebentern@users.noreply.github.com> --- version.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version.properties b/version.properties index a26da1996d..268987418b 100644 --- a/version.properties +++ b/version.properties @@ -1,4 +1,4 @@ [VERSION] major = 2 minor = 3 -build = 13 +build = 14 From 15250a566a3bce90a3449481f5a1d0ff513441de Mon Sep 17 00:00:00 2001 From: geeksville Date: Sun, 16 Jun 2024 17:17:19 -0700 Subject: [PATCH 54/65] Turn off vscode cmake prompt - we don't use cmake on meshtastic (#4122) --- .vscode/settings.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index e86d31c7d1..07e198f0a7 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -3,5 +3,6 @@ "editor.defaultFormatter": "trunk.io", "trunk.enableWindows": true, "files.insertFinalNewline": false, - "files.trimFinalNewlines": false + "files.trimFinalNewlines": false, + "cmake.configureOnOpen": false } From c593e7ce56a804b4526f4778e8c7c400c5511235 Mon Sep 17 00:00:00 2001 From: geeksville Date: Sun, 16 Jun 2024 13:59:38 -0700 Subject: [PATCH 55/65] Add rak4631_dap variant for debugging with NanoDAP debug probe device. use board_level = extra --- variants/rak4631/platformio.ini | 31 ++++++++++++++++++++++++++++++- 1 file changed, 30 insertions(+), 1 deletion(-) diff --git a/variants/rak4631/platformio.ini b/variants/rak4631/platformio.ini index 4870d4b68e..58a8eb5e46 100644 --- a/variants/rak4631/platformio.ini +++ b/variants/rak4631/platformio.ini @@ -18,5 +18,34 @@ lib_deps = rakwireless/RAKwireless NCP5623 RGB LED library@^1.0.2 https://github.com/meshtastic/RAK12034-BMX160.git#4821355fb10390ba8557dc43ca29a023bcfbb9d9 debug_tool = jlink + ; If not set we will default to uploading over serial (first it forces bootloader entry by talking 1200bps to cdcacm) -;upload_protocol = jlink \ No newline at end of file +; Note: as of 6/2013 the serial/bootloader based programming takes approximately 30 seconds +;upload_protocol = jlink + +; Allows programming and debug via the RAK NanoDAP as the default debugger tool for the RAK4631 (it is only $10!) +; programming time is about the same as the bootloader version. +; For information on this see the meshtastic developers documentation for "Development on the NRF52" +[env:rak4631_dap] +extends = env:rak4631 +board_level = extra +; pyocd pack --i nrf52840 +; eventually use platformio/tool-pyocd@^2.3600.0 instad +upload_protocol = custom +upload_command = pyocd flash -t nrf52840 $UPLOADERFLAGS $SOURCE + +; Only reprogram the board if the code has changed +debug_load_mode = modified +;debug_load_mode = manual +debug_tool = custom +; We manually pass in the elf file so that pyocd can reverse engineer FreeRTOS data (running threads, etc...) +debug_server = + pyocd + gdbserver + -t + nrf52840 + --elf + ${platformio.build_dir}/${this.__env__}/firmware.elf +; The following is not needed because it automatically tries do this +;debug_server_ready_pattern = -.*GDB server started on port \d+.* +;debug_port = localhost:3333 \ No newline at end of file From 12b8dc1918592baaaf72111d57cb98558eb24f3f Mon Sep 17 00:00:00 2001 From: Ben Meadors Date: Mon, 17 Jun 2024 06:09:50 -0500 Subject: [PATCH 56/65] Revert "[create-pull-request] automated change (#4121)" (#4124) This reverts commit 7afa8107ae5f8f5c8d9a9fba5173d1450c54b8b1. --- version.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version.properties b/version.properties index 268987418b..a26da1996d 100644 --- a/version.properties +++ b/version.properties @@ -1,4 +1,4 @@ [VERSION] major = 2 minor = 3 -build = 14 +build = 13 From 83f5ba0161725a597591c530ff509f2a5da27461 Mon Sep 17 00:00:00 2001 From: todd-herbert Date: Mon, 17 Jun 2024 23:14:20 +1200 Subject: [PATCH 57/65] Update OLED ref (#4125) Upstream changes to the library temporarily reverted to restore debug info frame --- platformio.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platformio.ini b/platformio.ini index a1beb8e7c5..83c4924c45 100644 --- a/platformio.ini +++ b/platformio.ini @@ -80,7 +80,7 @@ monitor_speed = 115200 lib_deps = jgromes/RadioLib@~6.6.0 - https://github.com/meshtastic/esp8266-oled-ssd1306.git#69ba98fa30e67b12d4577b121f210f3eb7049d6b ; ESP8266_SSD1306 + https://github.com/meshtastic/esp8266-oled-ssd1306.git#dcacac5d2c7942376bc17f7079cced6a73cb659f ; ESP8266_SSD1306 mathertel/OneButton@^2.5.0 ; OneButton library for non-blocking button debounce https://github.com/meshtastic/arduino-fsm.git#7db3702bf0cfe97b783d6c72595e3f38e0b19159 https://github.com/meshtastic/TinyGPSPlus.git#71a82db35f3b973440044c476d4bcdc673b104f4 From 5d2f7d1962de15b811c34f34909e50f571b030da Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Mon, 17 Jun 2024 07:17:36 -0500 Subject: [PATCH 58/65] [create-pull-request] automated change (#4127) Co-authored-by: thebentern <9000580+thebentern@users.noreply.github.com> --- version.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version.properties b/version.properties index a26da1996d..268987418b 100644 --- a/version.properties +++ b/version.properties @@ -1,4 +1,4 @@ [VERSION] major = 2 minor = 3 -build = 13 +build = 14 From b6066a78c1983ffd3be6034115261916b2232dbc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20G=C3=B6ttgens?= Date: Mon, 17 Jun 2024 15:09:38 +0200 Subject: [PATCH 59/65] WIP --- src/detect/ScanI2CTwoWire.cpp | 11 ++++----- src/input/cardKbI2cImpl.cpp | 42 +++++++++++++++++++++++++++++++++-- src/input/kbI2cBase.cpp | 38 ------------------------------- 3 files changed, 46 insertions(+), 45 deletions(-) diff --git a/src/detect/ScanI2CTwoWire.cpp b/src/detect/ScanI2CTwoWire.cpp index b045905098..86408b8d2e 100644 --- a/src/detect/ScanI2CTwoWire.cpp +++ b/src/detect/ScanI2CTwoWire.cpp @@ -148,7 +148,7 @@ void ScanI2CTwoWire::scanPort(I2CPort port, uint8_t *address, uint8_t asize) { concurrency::LockGuard guard((concurrency::Lock *)&lock); - LOG_DEBUG("Scanning for i2c devices on port %d\n", port); + LOG_DEBUG("Scanning for I2C devices on port %d\n", port); uint8_t err; @@ -172,10 +172,11 @@ void ScanI2CTwoWire::scanPort(I2CPort port, uint8_t *address, uint8_t asize) #endif for (addr.address = 1; addr.address < 127; addr.address++) { - if (asize != 0) - if (in_array(address, asize, addr.address)) + if (asize != 0) { + if (!in_array(address, asize, addr.address)) continue; - + LOG_DEBUG("Scanning address 0x%x\n", addr.address); + } i2cBus->beginTransmission(addr.address); #ifdef ARCH_PORTDUINO if (i2cBus->read() != -1) @@ -369,7 +370,7 @@ void ScanI2CTwoWire::scanPort(I2CPort port, uint8_t *address, uint8_t asize) LOG_INFO("Device found at address 0x%x was not able to be enumerated\n", addr.address); } } else if (err == 4) { - LOG_ERROR("Unknown error at address 0x%x\n", addr); + LOG_ERROR("Unknown error at address 0x%x\n", addr.address); } // Check if a type was found for the enumerated device - save, if so diff --git a/src/input/cardKbI2cImpl.cpp b/src/input/cardKbI2cImpl.cpp index e000f36eb0..d10f1118fc 100644 --- a/src/input/cardKbI2cImpl.cpp +++ b/src/input/cardKbI2cImpl.cpp @@ -1,5 +1,7 @@ #include "cardKbI2cImpl.h" #include "InputBroker.h" +#include "detect/ScanI2C.h" +#include "detect/ScanI2CTwoWire.h" CardKbI2cImpl *cardKbI2cImpl; @@ -8,8 +10,44 @@ CardKbI2cImpl::CardKbI2cImpl() : KbI2cBase("cardKB") {} void CardKbI2cImpl::init() { if (cardkb_found.address == 0x00) { - disable(); - return; + LOG_DEBUG("Rescanning for I2C keyboard\n"); + uint8_t i2caddr_scan[] = {CARDKB_ADDR, TDECK_KB_ADDR, BBQ10_KB_ADDR}; + uint8_t i2caddr_asize = 3; + auto i2cScanner = std::unique_ptr(new ScanI2CTwoWire()); + +#if defined(I2C_SDA1) + i2cScanner->scanPort(ScanI2C::I2CPort::WIRE1, i2caddr_scan, i2caddr_asize); +#endif + i2cScanner->scanPort(ScanI2C::I2CPort::WIRE, i2caddr_scan, i2caddr_asize); + auto kb_info = i2cScanner->firstKeyboard(); + + if (kb_info.type != ScanI2C::DeviceType::NONE) { + cardkb_found = kb_info.address; + switch (kb_info.type) { + case ScanI2C::DeviceType::RAK14004: + kb_model = 0x02; + break; + case ScanI2C::DeviceType::CARDKB: + kb_model = 0x00; + break; + case ScanI2C::DeviceType::TDECKKB: + // assign an arbitrary value to distinguish from other models + kb_model = 0x10; + break; + case ScanI2C::DeviceType::BBQ10KB: + // assign an arbitrary value to distinguish from other models + kb_model = 0x11; + break; + default: + // use this as default since it's also just zero + LOG_WARN("kb_info.type is unknown(0x%02x), setting kb_model=0x00\n", kb_info.type); + kb_model = 0x00; + } + } + if (cardkb_found.address == 0x00) { + disable(); + return; + } } inputBroker->registerSource(this); diff --git a/src/input/kbI2cBase.cpp b/src/input/kbI2cBase.cpp index ce22edb93d..024b16b9ef 100644 --- a/src/input/kbI2cBase.cpp +++ b/src/input/kbI2cBase.cpp @@ -30,44 +30,6 @@ uint8_t read_from_14004(TwoWire *i2cBus, uint8_t reg, uint8_t *data, uint8_t len int32_t KbI2cBase::runOnce() { - if (cardkb_found.address == 0x00) { - // Input device is not detected. Rescan now. - auto i2cScanner = std::unique_ptr(new ScanI2CTwoWire()); - uint8_t i2caddr_scan[] = {CARDKB_ADDR, TDECK_KB_ADDR, BBQ10_KB_ADDR}; - uint8_t i2caddr_asize = 3; -#if defined(I2C_SDA1) - i2cScanner->scanPort(ScanI2C::I2CPort::WIRE1, i2caddr_scan, i2caddr_asize); -#endif - i2cScanner->scanPort(ScanI2C::I2CPort::WIRE, i2caddr_scan, i2caddr_asize); - auto kb_info = i2cScanner->firstKeyboard(); - - if (kb_info.type != ScanI2C::DeviceType::NONE) { - cardkb_found = kb_info.address; - switch (kb_info.type) { - case ScanI2C::DeviceType::RAK14004: - kb_model = 0x02; - break; - case ScanI2C::DeviceType::CARDKB: - kb_model = 0x00; - break; - case ScanI2C::DeviceType::TDECKKB: - // assign an arbitrary value to distinguish from other models - kb_model = 0x10; - break; - case ScanI2C::DeviceType::BBQ10KB: - // assign an arbitrary value to distinguish from other models - kb_model = 0x11; - break; - default: - // use this as default since it's also just zero - LOG_WARN("kb_info.type is unknown(0x%02x), setting kb_model=0x00\n", kb_info.type); - kb_model = 0x00; - } - } - if (cardkb_found.address == 0x00) - return INT32_MAX; - } - if (!i2cBus) { switch (cardkb_found.port) { case ScanI2C::WIRE1: From 7a25e0b69ae571555605b9b9fd1a620a083889e3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20G=C3=B6ttgens?= Date: Mon, 17 Jun 2024 17:03:32 +0200 Subject: [PATCH 60/65] don't close the wire when we didn't find anything. We might rescan later. --- src/main.cpp | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index 6797c83759..3b009a179b 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -421,10 +421,6 @@ void setup() auto i2cCount = i2cScanner->countDevices(); if (i2cCount == 0) { LOG_INFO("No I2C devices found\n"); - Wire.end(); -#ifdef I2C_SDA1 - Wire1.end(); -#endif } else { LOG_INFO("%i I2C devices found\n", i2cCount); } From 9d8a5221a97f13b64c5f3fe585eb8284c3224fef Mon Sep 17 00:00:00 2001 From: mverch67 Date: Mon, 17 Jun 2024 20:17:56 +0200 Subject: [PATCH 61/65] fix for MESHTASTIC_EXCLUDE_INPUTBROKER --- src/input/InputBroker.cpp | 2 +- src/input/cardKbI2cImpl.cpp | 1 + src/input/cardKbI2cImpl.h | 1 - src/modules/Modules.cpp | 1 + src/modules/Telemetry/Sensor/OPT3001Sensor.cpp | 11 ++++++++--- src/modules/Telemetry/Sensor/OPT3001Sensor.h | 9 ++++++++- 6 files changed, 19 insertions(+), 6 deletions(-) diff --git a/src/input/InputBroker.cpp b/src/input/InputBroker.cpp index b06c7400f5..cb73e32bad 100644 --- a/src/input/InputBroker.cpp +++ b/src/input/InputBroker.cpp @@ -1,7 +1,7 @@ #include "InputBroker.h" #include "PowerFSM.h" // needed for event trigger -InputBroker *inputBroker; +InputBroker *inputBroker = nullptr; InputBroker::InputBroker(){}; diff --git a/src/input/cardKbI2cImpl.cpp b/src/input/cardKbI2cImpl.cpp index e000f36eb0..3cc70fa152 100644 --- a/src/input/cardKbI2cImpl.cpp +++ b/src/input/cardKbI2cImpl.cpp @@ -1,5 +1,6 @@ #include "cardKbI2cImpl.h" #include "InputBroker.h" +#include "main.h" CardKbI2cImpl *cardKbI2cImpl; diff --git a/src/input/cardKbI2cImpl.h b/src/input/cardKbI2cImpl.h index 1e6e87dfd3..811a0558c8 100644 --- a/src/input/cardKbI2cImpl.h +++ b/src/input/cardKbI2cImpl.h @@ -1,6 +1,5 @@ #pragma once #include "kbI2cBase.h" -#include "main.h" /** * @brief The idea behind this class to have static methods for the event handlers. diff --git a/src/modules/Modules.cpp b/src/modules/Modules.cpp index 1b4bbc3b4a..ba1f5c11ea 100644 --- a/src/modules/Modules.cpp +++ b/src/modules/Modules.cpp @@ -42,6 +42,7 @@ #include "modules/Telemetry/DeviceTelemetry.h" #endif #if HAS_SENSOR && !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR +#include "main.h" #include "modules/Telemetry/AirQualityTelemetry.h" #include "modules/Telemetry/EnvironmentTelemetry.h" #endif diff --git a/src/modules/Telemetry/Sensor/OPT3001Sensor.cpp b/src/modules/Telemetry/Sensor/OPT3001Sensor.cpp index 0d76e2897f..d0e38bf889 100644 --- a/src/modules/Telemetry/Sensor/OPT3001Sensor.cpp +++ b/src/modules/Telemetry/Sensor/OPT3001Sensor.cpp @@ -1,7 +1,10 @@ -#include "OPT3001Sensor.h" +#include "configuration.h" + +#if !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR + #include "../mesh/generated/meshtastic/telemetry.pb.h" +#include "OPT3001Sensor.h" #include "TelemetrySensor.h" -#include "configuration.h" #include OPT3001Sensor::OPT3001Sensor() : TelemetrySensor(meshtastic_TelemetrySensorType_OPT3001, "OPT3001") {} @@ -41,4 +44,6 @@ bool OPT3001Sensor::getMetrics(meshtastic_Telemetry *measurement) LOG_INFO("Lux: %f\n", measurement->variant.environment_metrics.lux); return true; -} \ No newline at end of file +} + +#endif \ No newline at end of file diff --git a/src/modules/Telemetry/Sensor/OPT3001Sensor.h b/src/modules/Telemetry/Sensor/OPT3001Sensor.h index 4a8deef218..2ac149319a 100644 --- a/src/modules/Telemetry/Sensor/OPT3001Sensor.h +++ b/src/modules/Telemetry/Sensor/OPT3001Sensor.h @@ -1,3 +1,8 @@ +#pragma once +#include "configuration.h" + +#if !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR + #include "../mesh/generated/meshtastic/telemetry.pb.h" #include "TelemetrySensor.h" #include @@ -14,4 +19,6 @@ class OPT3001Sensor : public TelemetrySensor OPT3001Sensor(); virtual int32_t runOnce() override; virtual bool getMetrics(meshtastic_Telemetry *measurement) override; -}; \ No newline at end of file +}; + +#endif \ No newline at end of file From cd60ee80bdd0f6ab73f3ce9b26ce251819c8b9a4 Mon Sep 17 00:00:00 2001 From: mverch67 Date: Mon, 17 Jun 2024 21:17:25 +0200 Subject: [PATCH 62/65] fix wrong include file exclusion --- src/main.cpp | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index 6797c83759..57009ae46a 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -41,13 +41,14 @@ #endif #if !MESHTASTIC_EXCLUDE_BLUETOOTH #include "nimble/NimbleBluetooth.h" -NimbleBluetooth *nimbleBluetooth; +NimbleBluetooth *nimbleBluetooth = nullptr; #endif #endif #ifdef ARCH_NRF52 #include "NRF52Bluetooth.h" -NRF52Bluetooth *nrf52Bluetooth; +NRF52Bluetooth *nrf52Bluetooth = nullptr; +; #endif #if HAS_WIFI @@ -94,23 +95,26 @@ NRF52Bluetooth *nrf52Bluetooth; #include "ButtonThread.h" #endif +#include "AmbientLightingThread.h" #include "PowerFSMThread.h" #if !defined(ARCH_PORTDUINO) && !defined(ARCH_STM32WL) && !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR #include "AccelerometerThread.h" -#include "AmbientLightingThread.h" -AccelerometerThread *accelerometerThread; +AccelerometerThread *accelerometerThread = nullptr; +; #endif #ifdef HAS_I2S #include "AudioThread.h" -AudioThread *audioThread; +AudioThread *audioThread = nullptr; +; #endif using namespace concurrency; // We always create a screen object, but we only init it if we find the hardware -graphics::Screen *screen; +graphics::Screen *screen = nullptr; +; // Global power status meshtastic::PowerStatus *powerStatus = new meshtastic::PowerStatus(); From 5e92136ed043cd7b647523ff593a982ce52f033c Mon Sep 17 00:00:00 2001 From: mverch67 Date: Mon, 17 Jun 2024 21:19:36 +0200 Subject: [PATCH 63/65] semi colon --- src/main.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main.cpp b/src/main.cpp index 57009ae46a..5ee895c9cb 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -101,7 +101,6 @@ NRF52Bluetooth *nrf52Bluetooth = nullptr; #if !defined(ARCH_PORTDUINO) && !defined(ARCH_STM32WL) && !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR #include "AccelerometerThread.h" AccelerometerThread *accelerometerThread = nullptr; -; #endif #ifdef HAS_I2S From e822525ce5d2252b8a9fa2eb562044be4fb1a948 Mon Sep 17 00:00:00 2001 From: mverch67 Date: Mon, 17 Jun 2024 21:23:07 +0200 Subject: [PATCH 64/65] more semi colons >_< --- src/main.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index 5ee895c9cb..a81f9206c9 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -106,14 +106,12 @@ AccelerometerThread *accelerometerThread = nullptr; #ifdef HAS_I2S #include "AudioThread.h" AudioThread *audioThread = nullptr; -; #endif using namespace concurrency; // We always create a screen object, but we only init it if we find the hardware graphics::Screen *screen = nullptr; -; // Global power status meshtastic::PowerStatus *powerStatus = new meshtastic::PowerStatus(); From 5cebe4a0a7a80e540a3568ea45c99b8d7f47f3dd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20G=C3=B6ttgens?= Date: Mon, 17 Jun 2024 23:24:27 +0200 Subject: [PATCH 65/65] trunk fmt --- src/input/cardKbI2cImpl.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/input/cardKbI2cImpl.cpp b/src/input/cardKbI2cImpl.cpp index af0958f947..4bc5ee4ead 100644 --- a/src/input/cardKbI2cImpl.cpp +++ b/src/input/cardKbI2cImpl.cpp @@ -1,7 +1,7 @@ #include "cardKbI2cImpl.h" #include "InputBroker.h" -#include "main.h" #include "detect/ScanI2CTwoWire.h" +#include "main.h" CardKbI2cImpl *cardKbI2cImpl;