diff --git a/lib/hal/HalDisplay.cpp b/lib/hal/HalDisplay.cpp index 0cccc2fc3..6bc372175 100644 --- a/lib/hal/HalDisplay.cpp +++ b/lib/hal/HalDisplay.cpp @@ -9,14 +9,6 @@ HalDisplay::~HalDisplay() {} void HalDisplay::begin() { einkDisplay.begin(); } -void HalDisplay::setDcPin(int8_t pin) { einkDisplay.setDcPin(pin); } - -void HalDisplay::setBusyActiveHigh(bool activeHigh) { einkDisplay.setBusyActiveHigh(activeHigh); } - -void HalDisplay::setBwOnly(bool bwOnly) { einkDisplay.setBwOnly(bwOnly); } - -void HalDisplay::setControllerType(EInkDisplay::ControllerType type) { einkDisplay.setControllerType(type); } - void HalDisplay::setDisplayDimensions(uint16_t width, uint16_t height) { einkDisplay.setDisplayDimensions(width, height); } void HalDisplay::clearScreen(uint8_t color) const { einkDisplay.clearScreen(color); } diff --git a/lib/hal/HalDisplay.h b/lib/hal/HalDisplay.h index 325107c57..a113f8e38 100644 --- a/lib/hal/HalDisplay.h +++ b/lib/hal/HalDisplay.h @@ -21,10 +21,6 @@ class HalDisplay { void begin(); // Pre-begin display config passthroughs (used by X3 setup path) - void setDcPin(int8_t pin); - void setBusyActiveHigh(bool activeHigh); - void setBwOnly(bool bwOnly); - void setControllerType(EInkDisplay::ControllerType type); void setDisplayDimensions(uint16_t width, uint16_t height); // Display dimensions diff --git a/src/Battery.cpp b/src/Battery.cpp index fc2277b8e..e68a95d29 100644 --- a/src/Battery.cpp +++ b/src/Battery.cpp @@ -1,9 +1,33 @@ #include "Battery.h" +#include -// Meyer's singleton — guaranteed single instance across all translation units. -// Constructed with GPIO0 (X4 ADC default). For X3, main.cpp calls -// battery().setI2CFuelGauge() to switch to BQ27220 I2C reads instead. -BatteryMonitor& battery() { - static BatteryMonitor instance(BAT_GPIO0); +void BatteryProvider::setI2CFuelGauge(uint8_t i2cAddr, uint8_t socRegister) { + _useI2C = true; + _i2cAddr = i2cAddr; + _socRegister = socRegister; +} + +uint16_t BatteryProvider::readPercentage() const { + if (_useI2C) { + // Read SOC directly from I2C fuel gauge (16-bit LE register). + // Returns 0 on I2C error so the UI shows 0% rather than crashing. + Wire.beginTransmission(_i2cAddr); + Wire.write(_socRegister); + if (Wire.endTransmission(false) != 0) return 0; + Wire.requestFrom(_i2cAddr, (uint8_t)2); + if (Wire.available() < 2) return 0; + const uint8_t lo = Wire.read(); + const uint8_t hi = Wire.read(); + const uint16_t soc = (hi << 8) | lo; + return soc > 100 ? 100 : soc; + } + // ADC path: read raw voltage, apply divider, convert via LiPo polynomial + return _adcMonitor.readPercentage(); +} + +// Meyer's singleton — single shared instance across all translation units. +// Defaults to X4 ADC mode. For X3, main.cpp calls setI2CFuelGauge() to switch. +BatteryProvider& battery() { + static BatteryProvider instance; return instance; } diff --git a/src/Battery.h b/src/Battery.h index e66a63f92..ac23c3831 100644 --- a/src/Battery.h +++ b/src/Battery.h @@ -1,11 +1,29 @@ #pragma once #include +#include #define BAT_GPIO0 0 // Battery voltage (X4 ADC pin) -// Shared battery monitor singleton. Returns a single BatteryMonitor instance -// used by all callers (themes, activities, etc.). -// -// - X4: reads battery voltage via ADC on GPIO0 (default, no extra setup needed) -// - X3: reads SOC from BQ27220 fuel gauge via I2C (call setI2CFuelGauge() after Wire.begin()) -BatteryMonitor& battery(); +// Unified battery reader supporting two backends: +// - X4: ADC voltage divider on GPIO0 (default, no setup needed) +// - X3: BQ27220 fuel gauge via I2C at 0x55, SOC register 0x2C +// (call setI2CFuelGauge() after Wire.begin()) +class BatteryProvider { + public: + // Read battery percentage (0-100). Delegates to ADC or I2C depending on mode. + uint16_t readPercentage() const; + + // Switch to I2C fuel gauge mode. Wire.begin() must be called first. + // i2cAddr: fuel gauge I2C address (e.g. 0x55 for BQ27220) + // socRegister: register holding state-of-charge 0-100% (e.g. 0x2C) + void setI2CFuelGauge(uint8_t i2cAddr, uint8_t socRegister); + + private: + BatteryMonitor _adcMonitor{BAT_GPIO0}; + bool _useI2C = false; + uint8_t _i2cAddr = 0; + uint8_t _socRegister = 0; +}; + +// Shared singleton used by themes and activities. +BatteryProvider& battery(); diff --git a/src/main.cpp b/src/main.cpp index eb1a0bfff..cbf3e3c14 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -255,10 +255,6 @@ void onGoHome() { void setupDisplayAndFonts() { if (gpio.getDeviceType() == HalGPIO::DeviceType::X3) { - display.setDcPin(4); - display.setBusyActiveHigh(false); - display.setBwOnly(true); - display.setControllerType(EInkDisplay::ControllerType::SSD1677); display.setDisplayDimensions(792, 528); // X3 has a BQ27220 fuel gauge on I2C (addr 0x55) instead of an ADC voltage // divider. SOC (0-100%) is read directly from register 0x2C.