diff --git a/.gitignore b/.gitignore index cc742c6c1..2c3dbd9d8 100644 --- a/.gitignore +++ b/.gitignore @@ -41,3 +41,12 @@ src/mesh/raspihttp/private_key.pem # Ignore logo (set at build time with platformio-custom.py) data/boot/logo.* + + +managed_components +dependencies.lock + +log_* +sdkconfig +sdkconfig.* +!sdkconfig.defaults \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 000000000..d570718ba --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,6 @@ +# This file supports the ESP-IDF framework only. +# Specifically, it targets the ESP32-C6 due to limited support in PlatformIO (see: https://github.com/platformio/platform-espressif32/issues/1225). +# Currently, we need to compile NimBLE CPP manually to enable BLE, and possibly WiFi, for ESP32-C6 targets. +cmake_minimum_required(VERSION 3.16.0) +include($ENV{IDF_PATH}/tools/cmake/project.cmake) +project(firmware) diff --git a/arch/esp32/esp32c6.ini b/arch/esp32/esp32c6.ini index 1afb9b547..f3c903a9f 100644 --- a/arch/esp32/esp32c6.ini +++ b/arch/esp32/esp32c6.ini @@ -17,9 +17,7 @@ build_flags = -DMESHTASTIC_EXCLUDE_WEBSERVER ;-DDEBUG_HEAP ; TEMP - -DHAS_BLUETOOTH=0 -DMESHTASTIC_EXCLUDE_PAXCOUNTER - -DMESHTASTIC_EXCLUDE_BLUETOOTH lib_deps = ${arduino_base.lib_deps} @@ -33,6 +31,8 @@ lib_deps = https://github.com/meshtastic/ESP32_Codec2/archive/633326c78ac251c059ab3a8c430fcdf25b41672f.zip # renovate: datasource=custom.pio depName=rweather/Crypto packageName=rweather/library/Crypto rweather/Crypto@0.4.0 + # renovate: datasource=github-tags depName=esp-nimble-cpp packageName=h2zero/esp-nimble-cpp + https://github.com/h2zero/esp-nimble-cpp/archive/2.2.1.zip build_src_filter = ${esp32_base.build_src_filter} - diff --git a/sdkconfig.defaults b/sdkconfig.defaults new file mode 100644 index 000000000..61d5a1560 --- /dev/null +++ b/sdkconfig.defaults @@ -0,0 +1,37 @@ +# # This file configures the ESP-IDF framework for the ESP32 platform. +# It enables BLE functionality using NimBLE and optimizes for minimal power consumption and size. +# Refer to the ESP-IDF Kconfig documentation for more details: https://docs.espressif.com/projects/esp-idf/en/v5.1.6/esp32c6/api-reference/kconfig.html +# CONFIG_AUTOSTART_ARDUINO is not set +# CONFIG_WS2812_LED_ENABLE is not set +CONFIG_FREERTOS_HZ=1000 +CONFIG_MBEDTLS_PSK_MODES=y +CONFIG_MBEDTLS_KEY_EXCHANGE_PSK=y +CONFIG_BOOTLOADER_COMPILER_OPTIMIZATION_SIZE=y +CONFIG_COMPILER_OPTIMIZATION_SIZE=y +CONFIG_ESPTOOLPY_FLASHSIZE_4MB=y +CONFIG_ESPTOOLPY_HEADER_FLASHSIZE_UPDATE=y + +# Override some defaults so BT stack is enabled +# in this example +# +# BT config +# +CONFIG_BT_ENABLED=y +CONFIG_BTDM_CTRL_MODE_BLE_ONLY=y +CONFIG_BTDM_CTRL_MODE_BR_EDR_ONLY=n +CONFIG_BTDM_CTRL_MODE_BTDM=n +CONFIG_BT_BLUEDROID_ENABLED=n +CONFIG_BT_NIMBLE_ENABLED=y + +# +# Arduino Configuration +# +# +# Disable all Arduino included BLE libraries +# +CONFIG_ARDUINO_SELECTIVE_COMPILATION=y +# CONFIG_ARDUINO_SELECTIVE_WiFiProv is not set +# CONFIG_ARDUINO_SELECTIVE_BLE is not set +# CONFIG_ARDUINO_SELECTIVE_BluetoothSerial is not set +# CONFIG_ARDUINO_SELECTIVE_SimpleBLE is not set +# end of Arduino Configuration \ No newline at end of file diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt new file mode 100644 index 000000000..7d3548813 --- /dev/null +++ b/src/CMakeLists.txt @@ -0,0 +1,14 @@ +# This file supports the ESP-IDF framework only. +# Specifically, it targets the ESP32-C6 due to limited support in PlatformIO (see: https://github.com/platformio/platform-espressif32/issues/1225). +# Currently, we need to compile NimBLE CPP manually to enable BLE, and possibly WiFi, for ESP32-C6 targets. +FILE(GLOB_RECURSE app_sources ${CMAKE_SOURCE_DIR}/src/*.*) +FILE(GLOB_RECURSE platform_sources ${CMAKE_SOURCE_DIR}/src/platform/**/*.*) +list(REMOVE_ITEM app_sources ${platform_sources}) +FILE(GLOB_RECURSE esp32_sources ${CMAKE_SOURCE_DIR}/src/platform/esp32/*.*) +list(APPEND app_sources ${esp32_sources}) +FILE(GLOB_RECURSE esp32_sources ${CMAKE_SOURCE_DIR}/src/platform/esp32/**/*.*) +list(APPEND app_sources ${esp32_sources}) +list(REMOVE_ITEM app_sources ${CMAKE_SOURCE_DIR}/src/mesh/eth/ethClient.cpp) + +# Register the component with ESP-IDF +idf_component_register(SRCS ${app_sources} INCLUDE_DIRS ${CMAKE_SOURCE_DIR}/src) diff --git a/src/RedirectablePrint.cpp b/src/RedirectablePrint.cpp index 7c8d77651..6dec0bc4a 100644 --- a/src/RedirectablePrint.cpp +++ b/src/RedirectablePrint.cpp @@ -1,8 +1,8 @@ #include "RedirectablePrint.h" #include "NodeDB.h" -#include "RTC.h" #include "concurrency/OSThread.h" #include "configuration.h" +#include "gps/RTC.h" #include "main.h" #include "mesh/generated/meshtastic/mesh.pb.h" #include diff --git a/src/detect/ScanI2C.h b/src/detect/ScanI2C.h index e46c6f623..cfe214c13 100644 --- a/src/detect/ScanI2C.h +++ b/src/detect/ScanI2C.h @@ -28,6 +28,7 @@ class ScanI2C INA219, INA3221, MAX17048, + MAX17261, MCP9808, SHT31, SHT4X, diff --git a/src/detect/ScanI2CTwoWire.cpp b/src/detect/ScanI2CTwoWire.cpp index 9aef9defe..b1d9865aa 100644 --- a/src/detect/ScanI2CTwoWire.cpp +++ b/src/detect/ScanI2CTwoWire.cpp @@ -434,6 +434,19 @@ void ScanI2CTwoWire::scanPort(I2CPort port, uint8_t *address, uint8_t asize) #else SCAN_SIMPLE_CASE(PMSA0031_ADDR, PMSA0031, "PMSA0031", (uint8_t)addr.address) #endif + case MAX1704X_ADDR: + // Try to read the MAX17261 DevName register 0x21 first + // See: + // https://www.analog.com/media/en/technical-documentation/user-guides/max1726x-modelgauge-m5-ez-user-guide.pdf + registerValue = getRegisterValue(ScanI2CTwoWire::RegisterLocation(addr, 0x21), 2); + if (registerValue == 0x3340) { + logFoundDevice("MAX17261", (uint8_t)addr.address); + type = MAX17261; + } else { + logFoundDevice("MAX17048", (uint8_t)addr.address); + type = MAX17048; + } + break; case BMA423_ADDR: // this can also be LIS3DH_ADDR_ALT registerValue = getRegisterValue(ScanI2CTwoWire::RegisterLocation(addr, 0x0F), 2); if (registerValue == 0x3300 || registerValue == 0x3333) { // RAK4631 WisBlock has LIS3DH register at 0x3333 @@ -464,7 +477,6 @@ void ScanI2CTwoWire::scanPort(I2CPort port, uint8_t *address, uint8_t asize) SCAN_SIMPLE_CASE(TSL25911_ADDR, TSL2591, "TSL2591", (uint8_t)addr.address); SCAN_SIMPLE_CASE(MLX90632_ADDR, MLX90632, "MLX90632", (uint8_t)addr.address); SCAN_SIMPLE_CASE(NAU7802_ADDR, NAU7802, "NAU7802", (uint8_t)addr.address); - SCAN_SIMPLE_CASE(MAX1704X_ADDR, MAX17048, "MAX17048", (uint8_t)addr.address); SCAN_SIMPLE_CASE(DFROBOT_RAIN_ADDR, DFROBOT_RAIN, "DFRobot Rain Gauge", (uint8_t)addr.address); SCAN_SIMPLE_CASE(LTR390UV_ADDR, LTR390UV, "LTR390UV", (uint8_t)addr.address); SCAN_SIMPLE_CASE(PCT2075_ADDR, PCT2075, "PCT2075", (uint8_t)addr.address); diff --git a/src/gps/GPS.cpp b/src/gps/GPS.cpp index 9ae7ae97d..4da67f50e 100644 --- a/src/gps/GPS.cpp +++ b/src/gps/GPS.cpp @@ -9,10 +9,10 @@ #include "GpioLogic.h" #include "NodeDB.h" #include "PowerMon.h" -#include "RTC.h" #include "Throttle.h" #include "buzz.h" #include "concurrency/Periodic.h" +#include "gps/RTC.h" #include "meshUtils.h" #include "main.h" // pmu_found diff --git a/src/gps/NMEAWPL.cpp b/src/gps/NMEAWPL.cpp index f4249ca62..5259427e6 100644 --- a/src/gps/NMEAWPL.cpp +++ b/src/gps/NMEAWPL.cpp @@ -1,7 +1,7 @@ #if !MESHTASTIC_EXCLUDE_GPS #include "NMEAWPL.h" #include "GeoCoord.h" -#include "RTC.h" +#include "gps/RTC.h" #include /* ------------------------------------------- diff --git a/src/gps/RTC.cpp b/src/gps/RTC.cpp index e208e2df9..979ceef94 100644 --- a/src/gps/RTC.cpp +++ b/src/gps/RTC.cpp @@ -1,4 +1,4 @@ -#include "RTC.h" +#include "gps/RTC.h" #include "configuration.h" #include "detect/ScanI2C.h" #include "main.h" diff --git a/src/main.cpp b/src/main.cpp index 8263a3144..836870d9a 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -13,13 +13,13 @@ #include "FSCommon.h" #include "Led.h" -#include "RTC.h" #include "SPILock.h" #include "Throttle.h" #include "concurrency/OSThread.h" #include "concurrency/Periodic.h" #include "detect/ScanI2C.h" #include "error.h" +#include "gps/RTC.h" #include "power.h" #if !MESHTASTIC_EXCLUDE_I2C @@ -714,6 +714,7 @@ void setup() scannerToSensorsMap(i2cScanner, ScanI2C::DeviceType::INA219, meshtastic_TelemetrySensorType_INA219); scannerToSensorsMap(i2cScanner, ScanI2C::DeviceType::INA3221, meshtastic_TelemetrySensorType_INA3221); scannerToSensorsMap(i2cScanner, ScanI2C::DeviceType::MAX17048, meshtastic_TelemetrySensorType_MAX17048); + scannerToSensorsMap(i2cScanner, ScanI2C::DeviceType::MAX17261, meshtastic_TelemetrySensorType_CUSTOM_SENSOR); scannerToSensorsMap(i2cScanner, ScanI2C::DeviceType::MCP9808, meshtastic_TelemetrySensorType_MCP9808); scannerToSensorsMap(i2cScanner, ScanI2C::DeviceType::SHT31, meshtastic_TelemetrySensorType_SHT31); scannerToSensorsMap(i2cScanner, ScanI2C::DeviceType::SHTC3, meshtastic_TelemetrySensorType_SHTC3); @@ -1612,3 +1613,15 @@ void loop() } } #endif + +#if !defined(CONFIG_AUTOSTART_ARDUINO) && (ESP_IDF_VERSION_MAJOR * 100 + ESP_IDF_VERSION_MINOR * 10 + ESP_IDF_VERSION_PATCH) > 512 +// Define app_main to bridge Arduino and ESP-IDF +extern "C" void app_main(void) +{ + setup(); + while (1) { + loop(); + vTaskDelay(1); // Allows FreeRTOS to manage tasks + } +} +#endif \ No newline at end of file diff --git a/src/mesh/MeshService.cpp b/src/mesh/MeshService.cpp index 2cc4197c1..b5f271516 100644 --- a/src/mesh/MeshService.cpp +++ b/src/mesh/MeshService.cpp @@ -9,8 +9,8 @@ #include "MeshService.h" #include "NodeDB.h" #include "PowerFSM.h" -#include "RTC.h" #include "TypeConversions.h" +#include "gps/RTC.h" #include "main.h" #include "mesh-pb-constants.h" #include "meshUtils.h" diff --git a/src/mesh/NodeDB.cpp b/src/mesh/NodeDB.cpp index c8eba1b2e..2578fade8 100644 --- a/src/mesh/NodeDB.cpp +++ b/src/mesh/NodeDB.cpp @@ -12,12 +12,12 @@ #include "NodeDB.h" #include "PacketHistory.h" #include "PowerFSM.h" -#include "RTC.h" #include "Router.h" #include "SPILock.h" #include "SafeFile.h" #include "TypeConversions.h" #include "error.h" +#include "gps/RTC.h" #include "main.h" #include "mesh-pb-constants.h" #include "meshUtils.h" diff --git a/src/mesh/PhoneAPI.cpp b/src/mesh/PhoneAPI.cpp index a3a8a2087..41a20a242 100644 --- a/src/mesh/PhoneAPI.cpp +++ b/src/mesh/PhoneAPI.cpp @@ -29,7 +29,7 @@ #include "mqtt/MQTT.h" #endif #include "Throttle.h" -#include +#include "gps/RTC.h" // Flag to indicate a heartbeat was received and we should send queue status bool heartbeatReceived = false; diff --git a/src/mesh/Router.cpp b/src/mesh/Router.cpp index c7e32c4a1..f144135a4 100644 --- a/src/mesh/Router.cpp +++ b/src/mesh/Router.cpp @@ -4,9 +4,9 @@ #include "MeshRadio.h" #include "MeshService.h" #include "NodeDB.h" -#include "RTC.h" #include "configuration.h" #include "detect/LoRaRadioType.h" +#include "gps/RTC.h" #include "main.h" #include "mesh-pb-constants.h" #include "meshUtils.h" diff --git a/src/mesh/StreamAPI.cpp b/src/mesh/StreamAPI.cpp index 20026767e..553159db5 100644 --- a/src/mesh/StreamAPI.cpp +++ b/src/mesh/StreamAPI.cpp @@ -1,8 +1,8 @@ #include "StreamAPI.h" #include "PowerFSM.h" -#include "RTC.h" #include "Throttle.h" #include "configuration.h" +#include "gps/RTC.h" #define START1 0x94 #define START2 0xc3 diff --git a/src/mesh/eth/ethClient.cpp b/src/mesh/eth/ethClient.cpp index 2b4f63512..99605666e 100644 --- a/src/mesh/eth/ethClient.cpp +++ b/src/mesh/eth/ethClient.cpp @@ -1,8 +1,8 @@ #include "mesh/eth/ethClient.h" #include "NodeDB.h" -#include "RTC.h" #include "concurrency/Periodic.h" #include "configuration.h" +#include "gps/RTC.h" #include "main.h" #include "mesh/api/ethServerAPI.h" #include "target_specific.h" diff --git a/src/mesh/wifi/WiFiAPClient.cpp b/src/mesh/wifi/WiFiAPClient.cpp index 1133ad424..0d321aa5c 100644 --- a/src/mesh/wifi/WiFiAPClient.cpp +++ b/src/mesh/wifi/WiFiAPClient.cpp @@ -1,8 +1,8 @@ #include "configuration.h" #if HAS_WIFI #include "NodeDB.h" -#include "RTC.h" #include "concurrency/Periodic.h" +#include "gps/RTC.h" #include "mesh/wifi/WiFiAPClient.h" #include "main.h" diff --git a/src/modules/AdminModule.cpp b/src/modules/AdminModule.cpp index 407003f7e..d861528fe 100644 --- a/src/modules/AdminModule.cpp +++ b/src/modules/AdminModule.cpp @@ -3,9 +3,9 @@ #include "MeshService.h" #include "NodeDB.h" #include "PowerFSM.h" -#include "RTC.h" #include "SPILock.h" #include "input/InputBroker.h" +#include "gps/RTC.h" #include "meshUtils.h" #include #include // for better whitespace handling diff --git a/src/modules/ExternalNotificationModule.cpp b/src/modules/ExternalNotificationModule.cpp index 2f2934984..77ca9fede 100644 --- a/src/modules/ExternalNotificationModule.cpp +++ b/src/modules/ExternalNotificationModule.cpp @@ -16,10 +16,10 @@ #include "ExternalNotificationModule.h" #include "MeshService.h" #include "NodeDB.h" -#include "RTC.h" #include "Router.h" #include "buzz/buzz.h" #include "configuration.h" +#include "gps/RTC.h" #include "main.h" #include "mesh/generated/meshtastic/rtttl.pb.h" #include diff --git a/src/modules/NeighborInfoModule.cpp b/src/modules/NeighborInfoModule.cpp index 97dc17001..481483526 100644 --- a/src/modules/NeighborInfoModule.cpp +++ b/src/modules/NeighborInfoModule.cpp @@ -2,7 +2,7 @@ #include "Default.h" #include "MeshService.h" #include "NodeDB.h" -#include "RTC.h" +#include "gps/RTC.h" #include NeighborInfoModule *neighborInfoModule; diff --git a/src/modules/NodeInfoModule.cpp b/src/modules/NodeInfoModule.cpp index 0060e99fa..fc2031cca 100644 --- a/src/modules/NodeInfoModule.cpp +++ b/src/modules/NodeInfoModule.cpp @@ -2,9 +2,9 @@ #include "Default.h" #include "MeshService.h" #include "NodeDB.h" -#include "RTC.h" #include "Router.h" #include "configuration.h" +#include "gps/RTC.h" #include "main.h" #include diff --git a/src/modules/PositionModule.cpp b/src/modules/PositionModule.cpp index 8b6a9f19c..acfec3b93 100644 --- a/src/modules/PositionModule.cpp +++ b/src/modules/PositionModule.cpp @@ -4,12 +4,12 @@ #include "GPS.h" #include "MeshService.h" #include "NodeDB.h" -#include "RTC.h" #include "Router.h" #include "TypeConversions.h" #include "airtime.h" #include "configuration.h" #include "gps/GeoCoord.h" +#include "gps/RTC.h" #include "main.h" #include "mesh/compression/unishox2.h" #include "meshUtils.h" diff --git a/src/modules/PowerStressModule.cpp b/src/modules/PowerStressModule.cpp index d487fe6fc..feed175de 100644 --- a/src/modules/PowerStressModule.cpp +++ b/src/modules/PowerStressModule.cpp @@ -3,9 +3,9 @@ #include "MeshService.h" #include "NodeDB.h" #include "PowerMon.h" -#include "RTC.h" #include "Router.h" #include "configuration.h" +#include "gps/RTC.h" #include "main.h" #include "sleep.h" #include "target_specific.h" diff --git a/src/modules/RangeTestModule.cpp b/src/modules/RangeTestModule.cpp index d1d2d9ead..197606a3c 100644 --- a/src/modules/RangeTestModule.cpp +++ b/src/modules/RangeTestModule.cpp @@ -13,12 +13,12 @@ #include "MeshService.h" #include "NodeDB.h" #include "PowerFSM.h" -#include "RTC.h" #include "Router.h" #include "SPILock.h" #include "airtime.h" #include "configuration.h" #include "gps/GeoCoord.h" +#include "gps/RTC.h" #include #include diff --git a/src/modules/RemoteHardwareModule.cpp b/src/modules/RemoteHardwareModule.cpp index 04cfeb651..ef2b23c8f 100644 --- a/src/modules/RemoteHardwareModule.cpp +++ b/src/modules/RemoteHardwareModule.cpp @@ -1,9 +1,9 @@ #include "RemoteHardwareModule.h" #include "MeshService.h" #include "NodeDB.h" -#include "RTC.h" #include "Router.h" #include "configuration.h" +#include "gps/RTC.h" #include "main.h" #include diff --git a/src/modules/SerialModule.cpp b/src/modules/SerialModule.cpp index 7485f1c2d..d5a48fe0a 100644 --- a/src/modules/SerialModule.cpp +++ b/src/modules/SerialModule.cpp @@ -3,9 +3,9 @@ #include "MeshService.h" #include "NMEAWPL.h" #include "NodeDB.h" -#include "RTC.h" #include "Router.h" #include "configuration.h" +#include "gps/RTC.h" #include #include diff --git a/src/modules/StoreForwardModule.cpp b/src/modules/StoreForwardModule.cpp index 72ac99118..7fa7dde6c 100644 --- a/src/modules/StoreForwardModule.cpp +++ b/src/modules/StoreForwardModule.cpp @@ -15,11 +15,11 @@ #include "StoreForwardModule.h" #include "MeshService.h" #include "NodeDB.h" -#include "RTC.h" #include "Router.h" #include "Throttle.h" #include "airtime.h" #include "configuration.h" +#include "gps/RTC.h" #include "memGet.h" #include "mesh-pb-constants.h" #include "mesh/generated/meshtastic/storeforward.pb.h" diff --git a/src/modules/Telemetry/AirQualityTelemetry.cpp b/src/modules/Telemetry/AirQualityTelemetry.cpp index 21a563b9d..4fd116823 100644 --- a/src/modules/Telemetry/AirQualityTelemetry.cpp +++ b/src/modules/Telemetry/AirQualityTelemetry.cpp @@ -8,9 +8,9 @@ #include "MeshService.h" #include "NodeDB.h" #include "PowerFSM.h" -#include "RTC.h" #include "Router.h" #include "detect/ScanI2CTwoWire.h" +#include "gps/RTC.h" #include "main.h" #include diff --git a/src/modules/Telemetry/DeviceTelemetry.cpp b/src/modules/Telemetry/DeviceTelemetry.cpp index 08fd09db0..29463fe23 100644 --- a/src/modules/Telemetry/DeviceTelemetry.cpp +++ b/src/modules/Telemetry/DeviceTelemetry.cpp @@ -4,10 +4,10 @@ #include "MeshService.h" #include "NodeDB.h" #include "PowerFSM.h" -#include "RTC.h" #include "RadioLibInterface.h" #include "Router.h" #include "configuration.h" +#include "gps/RTC.h" #include "main.h" #include "memGet.h" #include diff --git a/src/modules/Telemetry/EnvironmentTelemetry.cpp b/src/modules/Telemetry/EnvironmentTelemetry.cpp index 8926b171c..129e468fc 100644 --- a/src/modules/Telemetry/EnvironmentTelemetry.cpp +++ b/src/modules/Telemetry/EnvironmentTelemetry.cpp @@ -8,12 +8,12 @@ #include "MeshService.h" #include "NodeDB.h" #include "PowerFSM.h" -#include "RTC.h" #include "Router.h" #include "UnitConversions.h" #include "buzz.h" #include "graphics/SharedUIDisplay.h" #include "graphics/images.h" +#include "gps/RTC.h" #include "main.h" #include "modules/ExternalNotificationModule.h" #include "power.h" diff --git a/src/modules/Telemetry/HealthTelemetry.cpp b/src/modules/Telemetry/HealthTelemetry.cpp index 215e49c7a..5d6f6bc2f 100644 --- a/src/modules/Telemetry/HealthTelemetry.cpp +++ b/src/modules/Telemetry/HealthTelemetry.cpp @@ -8,9 +8,9 @@ #include "MeshService.h" #include "NodeDB.h" #include "PowerFSM.h" -#include "RTC.h" #include "Router.h" #include "UnitConversions.h" +#include "gps/RTC.h" #include "main.h" #include "power.h" #include "sleep.h" diff --git a/src/modules/Telemetry/Sensor/MAX17261Sensor.cpp b/src/modules/Telemetry/Sensor/MAX17261Sensor.cpp new file mode 100644 index 000000000..91504a725 --- /dev/null +++ b/src/modules/Telemetry/Sensor/MAX17261Sensor.cpp @@ -0,0 +1,176 @@ +#include "MAX17261Sensor.h" + +#if !MESHTASTIC_EXCLUDE_I2C && !defined(ARCH_STM32WL) && __has_include() + +MAX17048Singleton *MAX17048Singleton::GetInstance() +{ + if (pinstance == nullptr) { + pinstance = new MAX17048Singleton(); + } + return pinstance; +} + +MAX17048Singleton::MAX17048Singleton() {} + +MAX17048Singleton::~MAX17048Singleton() {} + +MAX17048Singleton *MAX17048Singleton::pinstance{nullptr}; + +bool MAX17048Singleton::runOnce(TwoWire *theWire) +{ + initialized = begin(theWire); + LOG_DEBUG("%s::runOnce %s", sensorStr, initialized ? "began ok" : "begin failed"); + return initialized; +} + +bool MAX17048Singleton::isBatteryCharging() +{ + float volts = cellVoltage(); + if (isnan(volts)) { + LOG_DEBUG("%s::isBatteryCharging not connected", sensorStr); + return 0; + } + + MAX17048ChargeSample sample; + sample.chargeRate = chargeRate(); // charge/discharge rate in percent/hr + sample.cellPercent = cellPercent(); // state of charge in percent 0 to 100 + chargeSamples.push(sample); // save a sample into a fifo buffer + + // Keep the fifo buffer trimmed + while (chargeSamples.size() > MAX17048_CHARGING_SAMPLES) + chargeSamples.pop(); + + // Based on the past n samples, is the lipo charging, discharging or idle + if (chargeSamples.front().chargeRate > MAX17048_CHARGING_MINIMUM_RATE && + chargeSamples.back().chargeRate > MAX17048_CHARGING_MINIMUM_RATE) { + if (chargeSamples.front().cellPercent > chargeSamples.back().cellPercent) + chargeState = MAX17048ChargeState::EXPORT; + else if (chargeSamples.front().cellPercent < chargeSamples.back().cellPercent) + chargeState = MAX17048ChargeState::IMPORT; + else + chargeState = MAX17048ChargeState::IDLE; + } else { + chargeState = MAX17048ChargeState::IDLE; + } + + LOG_DEBUG("%s::isBatteryCharging %s volts: %.3f soc: %.3f rate: %.3f", sensorStr, chargeLabels[chargeState], volts, + sample.cellPercent, sample.chargeRate); + return chargeState == MAX17048ChargeState::IMPORT; +} + +uint16_t MAX17048Singleton::getBusVoltageMv() +{ + float volts = cellVoltage(); + if (isnan(volts)) { + LOG_DEBUG("%s::getBusVoltageMv is not connected", sensorStr); + return 0; + } + LOG_DEBUG("%s::getBusVoltageMv %.3fmV", sensorStr, volts); + return (uint16_t)(volts * 1000.0f); +} + +uint8_t MAX17048Singleton::getBusBatteryPercent() +{ + float soc = cellPercent(); + LOG_DEBUG("%s::getBusBatteryPercent %.1f%%", sensorStr, soc); + return clamp(static_cast(round(soc)), static_cast(0), static_cast(100)); +} + +uint16_t MAX17048Singleton::getTimeToGoSecs() +{ + float rate = chargeRate(); // charge/discharge rate in percent/hr + float soc = cellPercent(); // state of charge in percent 0 to 100 + soc = clamp(soc, 0.0f, 100.0f); // clamp soc between 0 and 100% + float ttg = ((100.0f - soc) / rate) * 3600.0f; // calculate seconds to charge/discharge + LOG_DEBUG("%s::getTimeToGoSecs %.0f seconds", sensorStr, ttg); + return (uint16_t)ttg; +} + +bool MAX17048Singleton::isBatteryConnected() +{ + float volts = cellVoltage(); + if (isnan(volts)) { + LOG_DEBUG("%s::isBatteryConnected is not connected", sensorStr); + return false; + } + + // if a valid voltage is returned, then battery must be connected + return true; +} + +bool MAX17048Singleton::isExternallyPowered() +{ + float volts = cellVoltage(); + if (isnan(volts)) { + // if the battery is not connected then there must be external power + LOG_DEBUG("%s::isExternallyPowered battery is", sensorStr); + return true; + } + // if the bus voltage is over MAX17048_BUS_POWER_VOLTS, then the external power + // is assumed to be connected + LOG_DEBUG("%s::isExternallyPowered %s connected", sensorStr, volts >= MAX17048_BUS_POWER_VOLTS ? "is" : "is not"); + return volts >= MAX17048_BUS_POWER_VOLTS; +} + +#if (HAS_TELEMETRY && (!MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR || !MESHTASTIC_EXCLUDE_POWER_TELEMETRY)) + +MAX17048Sensor::MAX17048Sensor() : TelemetrySensor(meshtastic_TelemetrySensorType_MAX17048, "MAX17048") {} + +int32_t MAX17048Sensor::runOnce() +{ + if (isInitialized()) { + LOG_INFO("Init sensor: %s is already initialised", sensorName); + return true; + } + + LOG_INFO("Init sensor: %s", sensorName); + if (!hasSensor()) { + return DEFAULT_SENSOR_MINIMUM_WAIT_TIME_BETWEEN_READS; + } + + // Get a singleton instance and initialise the max17048 + if (max17048 == nullptr) { + max17048 = MAX17048Singleton::GetInstance(); + } + status = max17048->runOnce(nodeTelemetrySensorsMap[sensorType].second); + return initI2CSensor(); +} + +void MAX17048Sensor::setup() {} + +bool MAX17048Sensor::getMetrics(meshtastic_Telemetry *measurement) +{ + LOG_DEBUG("MAX17048 getMetrics id: %i", measurement->which_variant); + + float volts = max17048->cellVoltage(); + if (isnan(volts)) { + LOG_DEBUG("MAX17048 getMetrics battery is not connected"); + return false; + } + + float rate = max17048->chargeRate(); // charge/discharge rate in percent/hr + float soc = max17048->cellPercent(); // state of charge in percent 0 to 100 + soc = clamp(soc, 0.0f, 100.0f); // clamp soc between 0 and 100% + float ttg = (100.0f - soc) / rate; // calculate hours to charge/discharge + + LOG_DEBUG("MAX17048 getMetrics volts: %.3fV soc: %.1f%% ttg: %.1f hours", volts, soc, ttg); + if ((int)measurement->which_variant == meshtastic_Telemetry_power_metrics_tag) { + measurement->variant.power_metrics.has_ch1_voltage = true; + measurement->variant.power_metrics.ch1_voltage = volts; + } else if ((int)measurement->which_variant == meshtastic_Telemetry_device_metrics_tag) { + measurement->variant.device_metrics.has_battery_level = true; + measurement->variant.device_metrics.has_voltage = true; + measurement->variant.device_metrics.battery_level = static_cast(round(soc)); + measurement->variant.device_metrics.voltage = volts; + } + return true; +} + +uint16_t MAX17048Sensor::getBusVoltageMv() +{ + return max17048->getBusVoltageMv(); +}; + +#endif + +#endif \ No newline at end of file diff --git a/src/modules/Telemetry/Sensor/MAX17261Sensor.h b/src/modules/Telemetry/Sensor/MAX17261Sensor.h new file mode 100644 index 000000000..f01cf7f58 --- /dev/null +++ b/src/modules/Telemetry/Sensor/MAX17261Sensor.h @@ -0,0 +1,111 @@ +#pragma once + +#ifndef MAX17261_SENSOR_H +#define MAX17261_SENSOR_H + +#include "configuration.h" + +#if !MESHTASTIC_EXCLUDE_I2C && !defined(ARCH_STM32WL) && __has_include() + +// Samples to store in a buffer to determine if the battery is charging or discharging +#define MAX17048_CHARGING_SAMPLES 3 + +// Threshold to determine if the battery is on charge, in percent/hour +#define MAX17048_CHARGING_MINIMUM_RATE 1.0f + +// Threshold to determine if the board has bus power +#define MAX17048_BUS_POWER_VOLTS 4.195f + +#include "../mesh/generated/meshtastic/telemetry.pb.h" +#include "TelemetrySensor.h" +#include "VoltageSensor.h" + +#include "meshUtils.h" +#include +#include + +struct MAX17048ChargeSample { + float cellPercent; + float chargeRate; +}; + +enum MAX17048ChargeState { IDLE, EXPORT, IMPORT }; + +// Singleton wrapper for the Adafruit_MAX17048 class +class MAX17048Singleton : public Adafruit_MAX17048 +{ + private: + static MAX17048Singleton *pinstance; + bool initialized = false; + std::queue chargeSamples; + MAX17048ChargeState chargeState = IDLE; + const String chargeLabels[3] = {F("idle"), F("export"), F("import")}; + const char *sensorStr = "MAX17048Sensor"; + + protected: + MAX17048Singleton(); + ~MAX17048Singleton(); + + public: + // Create a singleton instance (not thread safe) + static MAX17048Singleton *GetInstance(); + + // Singletons should not be cloneable. + MAX17048Singleton(MAX17048Singleton &other) = delete; + + // Singletons should not be assignable. + void operator=(const MAX17048Singleton &) = delete; + + // Initialise the sensor (not thread safe) + virtual bool runOnce(TwoWire *theWire = &Wire); + + // Get the current bus voltage + uint16_t getBusVoltageMv(); + + // Get the state of charge in percent 0 to 100 + uint8_t getBusBatteryPercent(); + + // Calculate the seconds to charge/discharge + uint16_t getTimeToGoSecs(); + + // Returns true if the battery sensor has started + inline virtual bool isInitialised() { return initialized; }; + + // Returns true if the battery is currently on charge (not thread safe) + bool isBatteryCharging(); + + // Returns true if a battery is actually connected + bool isBatteryConnected(); + + // Returns true if there is bus or external power connected + bool isExternallyPowered(); +}; + +#if (HAS_TELEMETRY && (!MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR || !MESHTASTIC_EXCLUDE_POWER_TELEMETRY)) + +class MAX17048Sensor : public TelemetrySensor, VoltageSensor +{ + private: + MAX17048Singleton *max17048 = nullptr; + + protected: + virtual void setup() override; + + public: + MAX17048Sensor(); + + // Initialise the sensor + virtual int32_t runOnce() override; + + // Get the current bus voltage and state of charge + virtual bool getMetrics(meshtastic_Telemetry *measurement) override; + + // Get the current bus voltage + virtual uint16_t getBusVoltageMv() override; +}; + +#endif + +#endif + +#endif \ No newline at end of file diff --git a/src/modules/esp32/AudioModule.cpp b/src/modules/esp32/AudioModule.cpp index 77cc94359..f7093632b 100644 --- a/src/modules/esp32/AudioModule.cpp +++ b/src/modules/esp32/AudioModule.cpp @@ -4,8 +4,8 @@ #include "FSCommon.h" #include "MeshService.h" #include "NodeDB.h" -#include "RTC.h" #include "Router.h" +#include "gps/RTC.h" /* AudioModule diff --git a/src/platform/esp32/main-esp32.cpp b/src/platform/esp32/main-esp32.cpp index cdea53c9a..26cde6b2e 100644 --- a/src/platform/esp32/main-esp32.cpp +++ b/src/platform/esp32/main-esp32.cpp @@ -119,9 +119,14 @@ void esp32Setup() LOG_DEBUG("Free heap: %d", ESP.getFreeHeap()); LOG_DEBUG("Total PSRAM: %d", ESP.getPsramSize()); LOG_DEBUG("Free PSRAM: %d", ESP.getFreePsram()); + esp_log_level_set("gpio", ESP_LOG_WARN); + + auto res = nvs_flash_init(); + assert(res == ESP_OK); nvs_stats_t nvs_stats; - auto res = nvs_get_stats(NULL, &nvs_stats); + res = nvs_get_stats(NULL, &nvs_stats); + assert(res == ESP_OK); LOG_DEBUG("NVS: UsedEntries %d, FreeEntries %d, AllEntries %d, NameSpaces %d", nvs_stats.used_entries, nvs_stats.free_entries, nvs_stats.total_entries, nvs_stats.namespace_count); @@ -172,8 +177,9 @@ void esp32Setup() #ifdef CONFIG_IDF_TARGET_ESP32C6 esp_task_wdt_config_t *wdt_config = (esp_task_wdt_config_t *)malloc(sizeof(esp_task_wdt_config_t)); wdt_config->timeout_ms = APP_WATCHDOG_SECS * 1000; + wdt_config->idle_core_mask = 0; wdt_config->trigger_panic = true; - res = esp_task_wdt_init(wdt_config); + res = esp_task_wdt_reconfigure(wdt_config); assert(res == ESP_OK); #else res = esp_task_wdt_init(APP_WATCHDOG_SECS, true); @@ -185,6 +191,17 @@ void esp32Setup() #ifdef HAS_32768HZ enableSlowCLK(); #endif + +#ifdef USE_XIAO_ESP32C6_EXTERNAL_ANTENNA +#warning "Connect an external antenna to your XIAO ESP32C6; otherwise, it may be damaged!" + gpio_reset_pin(GPIO_NUM_3); + gpio_set_direction(GPIO_NUM_3, GPIO_MODE_OUTPUT); + gpio_set_level(GPIO_NUM_3, LOW); + + gpio_reset_pin(GPIO_NUM_14); + gpio_set_direction(GPIO_NUM_14, GPIO_MODE_OUTPUT); + gpio_set_level(GPIO_NUM_14, HIGH); +#endif } /// loop code specific to ESP32 targets diff --git a/src/platform/stm32wl/main-stm32wl.cpp b/src/platform/stm32wl/main-stm32wl.cpp index 3eddbb3cf..b37930736 100644 --- a/src/platform/stm32wl/main-stm32wl.cpp +++ b/src/platform/stm32wl/main-stm32wl.cpp @@ -1,5 +1,5 @@ -#include "RTC.h" #include "configuration.h" +#include "gps/RTC.h" #include #include diff --git a/variants/seeed_xiao_esp32c6/platformio.ini b/variants/seeed_xiao_esp32c6/platformio.ini new file mode 100644 index 000000000..f47bcd9d7 --- /dev/null +++ b/variants/seeed_xiao_esp32c6/platformio.ini @@ -0,0 +1,20 @@ +[env:seeed-xiao-esp32c6] +extends = esp32c6_base +framework = arduino, espidf +board = esp32-c6-devkitm-1 +board_check = true +board_build.partitions = partition-table.csv +upload_protocol = esptool +upload_speed = 921600 +extra_scripts = pre:bin/platformio-custom.py +build_flags = + ${esp32c6_base.build_flags} + -D PRIVATE_HW + -I variants/seeed_xiao_esp32c6 + -D ARDUINO_USB_CDC_ON_BOOT=1 + -D ARDUINO_USB_MODE=1 + -L "${platformio.libdeps_dir}/${this.__env__}/bsec2/src/esp32c3" + -D HAS_BLUETOOTH=1 + -D MESHTASTIC_EXCLUDE_WEBSERVER + -D MESHTASTIC_EXCLUDE_MQTT + -D CONFIG_NIMBLE_CPP_FREERTOS_TASK_BLOCK_BIT=1 diff --git a/variants/seeed_xiao_esp32c6/variant.h b/variants/seeed_xiao_esp32c6/variant.h new file mode 100644 index 000000000..6b38b5409 --- /dev/null +++ b/variants/seeed_xiao_esp32c6/variant.h @@ -0,0 +1,44 @@ +#define LED_PIN 15 +#define LED_STATE_ON 0 // State when LED is lit + +#define BUTTON_PIN 21 // This is the Program Button +#define BUTTON_NEED_PULLUP + +#define I2C_SDA 22 +#define I2C_SCL 23 + +// #define USE_RF95 +#define USE_SX1262 + +#define LORA_MISO 20 +#define LORA_SCK 19 +#define LORA_MOSI 18 + +#ifdef USE_RF95 +#define LORA_CS 17 +#define LORA_RESET 1 +#define LORA_DIO0 0 +#define LORA_DIO1 16 +#endif + +#ifdef USE_SX1262 +#define LORA_CS 21 +#define LORA_DIO1 7 +#define LORA_BUSY 6 +#define LORA_RESET 2 +#define SX126X_CS LORA_CS +#define SX126X_DIO1 LORA_DIO1 +#define SX126X_BUSY LORA_BUSY +#define SX126X_RESET LORA_RESET +#define SX126X_RXEN 4 +#define SX126X_TXEN RADIOLIB_NC +#define SX126X_DIO2_AS_RF_SWITCH +#define SX126X_DIO3_TCXO_VOLTAGE 1.8 +#endif + +#define HAS_GPS 0 +#undef GPS_RX_PIN +#undef GPS_TX_PIN + +// For BLE/WiFi connectivity +// #define USE_XIAO_ESP32C6_EXTERNAL_ANTENNA \ No newline at end of file