diff --git a/application/qml/pages/SettingsPage.qml b/application/qml/pages/SettingsPage.qml index 21a4e53..4e7e389 100644 --- a/application/qml/pages/SettingsPage.qml +++ b/application/qml/pages/SettingsPage.qml @@ -44,6 +44,7 @@ Page { running: true onTriggered: { autoStopCharging.checked = settings.limitEnabled + maxChargeCurrentSlider.value = settings.maxChargeCurrent highLimitSlider.value = settings.highLimit lowLimitSlider.value = settings.lowLimit highAlertSlider.value = settings.highAlert @@ -181,6 +182,24 @@ Page { smallChange: 1 largeChange: 5 } + + SectionHeader { + text: qsTr("Maximum Charge Current") + visible: settings.maxSupportedChargeCurrent > 0 + } + + MySlider { + id: maxChargeCurrentSlider + visible: settings.maxSupportedChargeCurrent > 0 + minimumValue: 500000 + maximumValue: settings.maxSupportedChargeCurrent + stepSize: 100000 + valueText: (value / 1000) + "mA" + onReleased: save() + function save() { + settings.maxChargeCurrent = value + } + } } ////////////////////////////////////////////////// diff --git a/application/service/restore-write-permissions.sh b/application/service/restore-write-permissions.sh index bfc016e..1c7ff69 100755 --- a/application/service/restore-write-permissions.sh +++ b/application/service/restore-write-permissions.sh @@ -18,6 +18,7 @@ chmod 644 /sys/class/power_supply/battery/input_suspend 2>/dev/null chmod 644 /sys/class/power_supply/battery/charging_enabled 2>/dev/null +chmod 644 /sys/class/power_supply/battery/constant_charge_current_max 2>/dev/null chmod 644 /sys/class/power_supply/usb/charger_disable 2>/dev/null chmod 644 /sys/class/power_supply/dollar_cove_battery/enable_charging 2>/dev/null exit 0 diff --git a/application/service/set-write-permissions.sh b/application/service/set-write-permissions.sh index 9e12e72..b995555 100755 --- a/application/service/set-write-permissions.sh +++ b/application/service/set-write-permissions.sh @@ -18,6 +18,7 @@ chmod 666 /sys/class/power_supply/battery/input_suspend 2>/dev/null chmod 666 /sys/class/power_supply/battery/charging_enabled 2>/dev/null +chmod 666 /sys/class/power_supply/battery/constant_charge_current_max 2>/dev/null chmod 666 /sys/class/power_supply/usb/charger_disable 2>/dev/null chmod 666 /sys/class/power_supply/dollar_cove_battery/enable_charging 2>/dev/null exit 0 diff --git a/application/src/battery.cpp b/application/src/battery.cpp index c363b60..ddf06b6 100644 --- a/application/src/battery.cpp +++ b/application/src/battery.cpp @@ -225,6 +225,8 @@ int Battery::getCharge(){ return charge; } int Battery::getCurrent(){ return current; } +int Battery::getMaxChargeCurrent() { return maxChargeCurrent; } + QString Battery::getState() { return state; } QString Battery::getHealth() { return health; } diff --git a/application/src/battery.h b/application/src/battery.h index 02def70..508dfaa 100644 --- a/application/src/battery.h +++ b/application/src/battery.h @@ -31,6 +31,7 @@ class Battery : public QObject Q_OBJECT Q_PROPERTY(int charge READ getCharge NOTIFY chargeChanged) Q_PROPERTY(int current READ getCurrent NOTIFY currentChanged) + Q_PROPERTY(int maxChargeCurrent READ getMaxChargeCurrent) Q_PROPERTY(bool chargerConnected READ getChargerConnected NOTIFY chargerConnectedChanged) Q_PROPERTY(QString state READ getState NOTIFY stateChanged) Q_PROPERTY(bool chargingEnabled READ getChargingEnabled NOTIFY chargingEnabledChanged) @@ -44,6 +45,7 @@ public: int getCharge(); int getCurrent(); + int getMaxChargeCurrent(); bool getCharging(); bool getChargerConnected(); QString getState(); @@ -62,6 +64,7 @@ private: QFile* chargerConnectedFile = nullptr; QFile* stateFile = nullptr; QFile* chargingEnabledFile = nullptr; + QFile* maxChargeCurrentFile = nullptr; Settings* settings = nullptr; Logger* logger = nullptr; @@ -74,6 +77,7 @@ private: bool chargerConnected = false; // Charger plugged in QString state = "idle"; // dis/charging, idle, unknown bool chargingEnabled = true; // Only ever disabled manually + int maxChargeCurrent = 0; // Charge current limit in micro amps QString health = "unknown"; // Good, warm, overheat. Might have Cold or Overvoltage depending on driver int temperature = 0x7FFFFFFF; // This value means "unknown" (32-bit INT_MAX) diff --git a/application/src/settings.cpp b/application/src/settings.cpp index 6dabc1b..44677f6 100644 --- a/application/src/settings.cpp +++ b/application/src/settings.cpp @@ -38,6 +38,8 @@ Settings::Settings(Logger *newLogger, QObject *parent) : QObject(parent) loadInteger(sLimitEnabled, limitEnabled, 0, 1); loadInteger(sLowLimit, lowLimit, 5, 99); loadInteger(sHighLimit, highLimit, 6, 100); + loadInteger(sMaxSupportedChargeCurrent, maxSupportedChargeCurrent, 0, 5000000); + loadInteger(sMaxChargeCurrent, maxChargeCurrent, 0, maxSupportedChargeCurrent); loadInteger(sLogLevel, logLevel, 0, 2); loadString(sLogFilename, logFilename); @@ -72,6 +74,8 @@ int Settings::getLowNotificationsInterval() { return lowNotificationsInte int Settings::getHealthNotificationsInterval() { return healthNotificationsInterval; } int Settings::getLowLimit() { return lowLimit; } int Settings::getHighLimit() { return highLimit; } +int Settings::getMaxChargeCurrent() { return maxChargeCurrent; } +int Settings::getMaxSupportedChargeCurrent() { return maxSupportedChargeCurrent; } bool Settings::getLimitEnabled() { return limitEnabled == 1; } QString Settings::getLowAlertFile() { return lowAlertFile; } QString Settings::getHighAlertFile() { return highAlertFile; } @@ -132,6 +136,11 @@ void Settings::setHighLimit(const int newLimit) { emit highLimitChanged(highLimit); } +void Settings::setMaxChargeCurrent(const int newCurrent) { + if(saveInteger(sMaxChargeCurrent, newCurrent, maxChargeCurrent)) + emit maxChargeCurrentChanged(maxChargeCurrent); +} + void Settings::setLimitEnabled(const bool newEnabled) { if(saveInteger(sLimitEnabled, (newEnabled ? 1 : 0), limitEnabled)) emit limitEnabledChanged(limitEnabled); diff --git a/application/src/settings.h b/application/src/settings.h index 9b3f944..5230140 100644 --- a/application/src/settings.h +++ b/application/src/settings.h @@ -33,6 +33,8 @@ class Settings : public QObject Q_PROPERTY(int healthNotificationsInterval READ getHealthNotificationsInterval WRITE setHealthNotificationsInterval NOTIFY healthNotificationsIntervalChanged) Q_PROPERTY(int highLimit READ getHighLimit WRITE setHighLimit NOTIFY highLimitChanged) Q_PROPERTY(int lowLimit READ getLowLimit WRITE setLowLimit NOTIFY lowLimitChanged) + Q_PROPERTY(int maxChargeCurrent READ getMaxChargeCurrent WRITE setMaxChargeCurrent NOTIFY maxChargeCurrentChanged) + Q_PROPERTY(int maxSupportedChargeCurrent READ getMaxSupportedChargeCurrent NOTIFY maxSupportedChargeCurrentChanged) Q_PROPERTY(bool limitEnabled READ getLimitEnabled WRITE setLimitEnabled NOTIFY limitEnabledChanged) Q_PROPERTY(QString highAlertFile READ getHighAlertFile NOTIFY highAlertFileChanged) Q_PROPERTY(QString lowAlertFile READ getLowAlertFile NOTIFY lowAlertFileChanged) @@ -58,6 +60,8 @@ public: int getHealthNotificationsInterval(); int getLowLimit(); int getHighLimit(); + int getMaxChargeCurrent(); + int getMaxSupportedChargeCurrent(); bool getLimitEnabled(); QString getLowAlertFile(); QString getHighAlertFile(); @@ -79,6 +83,7 @@ public: void setHealthNotificationsInterval(const int newInterval); void setLowLimit(const int newLimit); void setHighLimit(const int newLimit); + void setMaxChargeCurrent(const int newCurrent); void setLimitEnabled(const bool newEnabled); void setNotificationTitle(const QString newText); void setNotificationLowText(const QString newText); @@ -103,6 +108,8 @@ private: int limitEnabled = 1; // Converted to boolean for QML int lowLimit = 65; int highLimit = 70; + int maxChargeCurrent = 0; // micro amps + int maxSupportedChargeCurrent = 0; // micro amps QString lowAlertFile = "/usr/share/sounds/jolla-ambient/stereo/general_warning.wav"; QString highAlertFile = "/usr/share/sounds/jolla-ambient/stereo/positive_confirmation.wav"; QString healthAlertFile = lowAlertFile; @@ -125,6 +132,8 @@ private: const char* sLimitEnabled = "limitEnabled"; const char* sLowLimit = "lowLimit"; const char* sHighLimit = "highLimit"; + const char* sMaxSupportedChargeCurrent = "maxSupportedChargeCurrent"; + const char* sMaxChargeCurrent = "maxChargeCurrent"; const char* sLowAlertFile = "lowAlertFile"; const char* sHighAlertFile = "highAlertFile"; const char* sHealthAlertFile = "healthAlertFile"; @@ -153,6 +162,8 @@ signals: void limitEnabledChanged(bool); void lowLimitChanged(int); void highLimitChanged(int); + void maxChargeCurrentChanged(int); + void maxSupportedChargeCurrentChanged(int); void lowAlertFileChanged(QString); void highAlertFileChanged(QString); void healthAlertFileChanged(QString); diff --git a/service/src/battery.cpp b/service/src/battery.cpp index d9fc334..e60ffb3 100644 --- a/service/src/battery.cpp +++ b/service/src/battery.cpp @@ -63,6 +63,38 @@ Battery::Battery(Logger* newLogger, bool loglevelSet, QCoreApplication *app, QOb if(currentFile) logL("Charging/discharging current file: " + currentFile->fileName()); else logL("Charging/discharging current file: not found!"); + // Maximum charge current in microamps, e.g. 3500000 (3500mA) + filenames.clear(); + filenames << "/sys/class/power_supply/battery/constant_charge_current_max"; + + foreach(const QString& file, filenames) { + if(!maxChargeCurrentFile && QFile::exists(file)) { + maxChargeCurrentFile = new QFile(file, this); + break; + } + } + + if(maxChargeCurrentFile) { + logL("Max charge current file: " + maxChargeCurrentFile->fileName()); + if(maxChargeCurrentFile->open(QIODevice::WriteOnly)) { + maxChargeCurrentFile->close(); + if(maxChargeCurrentFile->open(QIODevice::ReadOnly)) { + maxSupportedChargeCurrent = maxChargeCurrentFile->readLine().trimmed().toInt(); + logL(QString("Maximum supported charge current: %1mA").arg(maxSupportedChargeCurrent / 1000)); + maxChargeCurrentFile->close(); + } + } + else { + logL("Max charge current file is not writable - feature disabled"); + delete maxChargeCurrentFile; + maxChargeCurrentFile = Q_NULLPTR; + } + } + else { + logL("Max charge current file: not found!"); + } + settings->setMaxSupportedChargeCurrent(maxSupportedChargeCurrent); + // Battery/charging status: charging, discharging, full, empty, unknown (others?) filenames.clear(); filenames << "/sys/class/power_supply/battery/status" @@ -161,6 +193,7 @@ Battery::Battery(Logger* newLogger, bool loglevelSet, QCoreApplication *app, QOb else logL("Charger control file: not found!"); connect(settings, SIGNAL(resetTimers()), this, SLOT(resetTimers())); + connect(settings, SIGNAL(setMaxChargeCurrent(int)), this, SLOT(setMaxChargeCurrent(int))); updateTimer = new BackgroundActivity(app); highNotifyTimer = new BackgroundActivity(app); @@ -192,6 +225,8 @@ Battery::Battery(Logger* newLogger, bool loglevelSet, QCoreApplication *app, QOb } Battery::~Battery() { + this->setMaxChargeCurrent(maxSupportedChargeCurrent); + updateTimer->stop(); highNotifyTimer->stop(); lowNotifyTimer->stop(); @@ -447,6 +482,25 @@ bool Battery::setChargingEnabled(const bool isEnabled) { return success; } +void Battery::setMaxChargeCurrent(int newCurrent) { + if(maxChargeCurrentFile) { + logM(QString("Setting max charging current to %1...").arg(newCurrent / 1000)); + if(newCurrent > maxSupportedChargeCurrent) { + newCurrent = maxSupportedChargeCurrent; + } + if(maxChargeCurrentFile->open(QIODevice::WriteOnly)) { + QString data = QString("%1").arg(newCurrent); + if(!maxChargeCurrentFile->write(data.toLocal8Bit())) { + logM("Could not write to max charging current file"); + } + } + else { + logM("Could not open max charging current file"); + } + maxChargeCurrentFile->close(); + } +} + bool Battery::getChargerConnected() { return chargerConnected; } diff --git a/service/src/battery.h b/service/src/battery.h index 1fa29e5..f218a71 100644 --- a/service/src/battery.h +++ b/service/src/battery.h @@ -81,6 +81,7 @@ private: QFile *currentFile = nullptr; QFile *stateFile = nullptr; QFile *chargingEnabledFile = nullptr; + QFile *maxChargeCurrentFile = nullptr; QFile *temperatureFile = nullptr; QFile *healthFile = nullptr; Settings *settings = nullptr; @@ -98,6 +99,8 @@ private: bool chargerConnected = false; // Charger plugged in QString state = "idle"; // dis/charging, idle, unknown bool chargingEnabled = true; // Only ever disabled manually + int maxChargeCurrent = 0; + int maxSupportedChargeCurrent = 0; QString health = "unknown"; // Good, warm, overheat. Might have Cold or Overvoltage depending on driver int temperature = 0x7FFFFFFF; // This value means "unknown" (32-bit INT_MAX) @@ -124,6 +127,7 @@ public slots: void showHighNotification(); void showLowNotification(); void showHealthNotification(); + void setMaxChargeCurrent(int newCurrent); }; #endif // BATTERY_H diff --git a/service/src/settings.cpp b/service/src/settings.cpp index 3b644cb..e03078d 100644 --- a/service/src/settings.cpp +++ b/service/src/settings.cpp @@ -96,11 +96,12 @@ Settings::Settings(Logger* newLogger, QObject *parent) : QObject(parent) notificationHealthWarnText = "Battery health is not good"; notificationHealthCritText = "Battery health is critical"; - // Do this here, because... watcher = new QFileSystemWatcher(QStringList(mySettings->fileName()), this); connect(watcher, SIGNAL(fileChanged(QString)), this, SLOT(updateConfig(QString))); - // ...calling this deletes mySettings! + // To trigger setting the initial config value + maxChargeCurrent = 0; + updateConfig(mySettings->fileName()); } @@ -123,6 +124,8 @@ void Settings::updateConfig(const QString path) { // Use the same file location as GUI for data exchange if(!mySettings) { mySettings = new QSettings(appName, appName, this); + } else { + mySettings->sync(); } logH("Updating configuration..."); @@ -139,6 +142,9 @@ void Settings::updateConfig(const QString path) { loadInteger(sLimitEnabled, limitEnabled, 0, 1); loadInteger(sLowLimit, lowLimit, 5, 99); loadInteger(sHighLimit, highLimit, 6, 100); + if(loadInteger(sMaxChargeCurrent, maxChargeCurrent, 0, 5000000)) { + emit setMaxChargeCurrent(maxChargeCurrent); + } notificationTitle = mySettings->value(sNotificationTitle, notificationTitle).toString(); notificationLowText = mySettings->value(sNotificationLowText, notificationLowText).toString(); @@ -158,9 +164,6 @@ void Settings::updateConfig(const QString path) { logL(QString("Log level set to %1").arg((logLevel == 0 ? "low" : (logLevel == 1 ? "medium" : "high")))); } - delete mySettings; - mySettings = nullptr; - // Let the file system settle... QThread::msleep(100); @@ -180,6 +183,7 @@ void Settings::updateConfig(const QString path) { // Getters condensed int Settings::getLowAlert() { return lowAlert; } int Settings::getHighAlert() { return highAlert; } +int Settings::getMaxChargeCurrent() { return maxChargeCurrent; } int Settings::getHealthAlert() { return healthAlert; } int Settings::getHighNotificationsInterval() { return highNotificationsInterval; } int Settings::getLowNotificationsInterval() { return lowNotificationsInterval; } @@ -197,3 +201,7 @@ QString Settings::getNotificationHealthTitle() { return notificationHealthTi QString Settings::getNotificationHealthWarnText() { return notificationHealthWarnText; } QString Settings::getNotificationHealthCritText() { return notificationHealthCritText; } int Settings::getLogLevel() { return logLevel; } + +void Settings::setMaxSupportedChargeCurrent(int newCurrent) { + mySettings->setValue(sMaxSupportedChargeCurrent, QByteArray::number(newCurrent)); +} diff --git a/service/src/settings.h b/service/src/settings.h index fd5dbc3..3778823 100644 --- a/service/src/settings.h +++ b/service/src/settings.h @@ -34,6 +34,7 @@ public: int getLowAlert(); int getHighAlert(); + int getMaxChargeCurrent(); int getHighNotificationsInterval(); int getLowNotificationsInterval(); int getHealthAlert(); @@ -55,6 +56,8 @@ public: QString getNotificationHealthWarnText(); QString getNotificationHealthCritText(); + void setMaxSupportedChargeCurrent(int newCurrent); + private: Logger* logger; QSettings* mySettings = nullptr; @@ -70,6 +73,7 @@ private: // Default values int lowAlert = 25; int highAlert = 75; + int maxChargeCurrent = 0; int healthAlert = 1; // 0=off, 1=warn, 2=crit int highNotificationsInterval = 60; int lowNotificationsInterval = 60; @@ -101,6 +105,8 @@ private: const char* sLimitEnabled = "limitEnabled"; const char* sLowLimit = "lowLimit"; const char* sHighLimit = "highLimit"; + const char* sMaxChargeCurrent = "maxChargeCurrent"; + const char* sMaxSupportedChargeCurrent = "maxSupportedChargeCurrent"; const char* sLowAlertFile = "lowAlertFile"; const char* sHighAlertFile = "highAlertFile"; const char* sHealthAlertFile = "healthAlertFile"; @@ -120,6 +126,7 @@ private slots: signals: void resetTimers(); + void setMaxChargeCurrent(int newCurrent); }; #endif // SETTINGS_H