/* * * Copyright 2015 Malte Veerman maldela@halloarsch.de * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of * the License or (at your option) version 3 or any later version * accepted by the membership of KDE e.V. (or its successor approved * by the membership of KDE e.V.), which shall act as a proxy * defined in Section 14 of version 3 of the license. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * */ #include "pwmfan.h" #include "hwmon.h" #include "fancontrolaction.h" #include #include #include #include #include #include #include #include #include #define MAX_ERRORS_FOR_RPM_ZERO 10 namespace Fancontrol { PwmFan::PwmFan(Hwmon *parent, uint index) : Fan(parent, index), m_pwmStream(new QTextStream), m_modeStream(new QTextStream), m_temp(Q_NULLPTR), m_hasTemp(false), m_minTemp(0), m_maxTemp(100), m_minPwm(255), m_maxPwm(255), m_minStart(255), m_minStop(255), m_zeroRpm(0), m_testStatus(NotStarted) { connect(this, &PwmFan::tempChanged, parent, &Hwmon::updateConfig); connect(this, &PwmFan::hasTempChanged, parent, &Hwmon::updateConfig); connect(this, &PwmFan::minTempChanged, parent, &Hwmon::updateConfig); connect(this, &PwmFan::maxTempChanged, parent, &Hwmon::updateConfig); connect(this, &PwmFan::minPwmChanged, parent, &Hwmon::updateConfig); connect(this, &PwmFan::maxPwmChanged, parent, &Hwmon::updateConfig); connect(this, &PwmFan::minStartChanged, parent, &Hwmon::updateConfig); connect(this, &PwmFan::minStopChanged, parent, &Hwmon::updateConfig); connect(this, &PwmFan::testStatusChanged, parent, &Hwmon::updateConfig); if (QDir(parent->path()).isReadable()) { const auto pwmFile = new QFile(parent->path() + "/pwm" + QString::number(index), this); if (pwmFile->open(QFile::ReadWrite)) { m_pwmStream->setDevice(pwmFile); *m_pwmStream >> m_pwm; } else if (pwmFile->open(QFile::ReadOnly)) { m_pwmStream->setDevice(pwmFile); *m_pwmStream >> m_pwm; } else { qWarning() << "Can't open pwmFile " << pwmFile->fileName(); delete pwmFile; } const auto pwmModeFile = new QFile(parent->path() + "/pwm" + QString::number(index) + "_mode", this); if (pwmModeFile->open(QFile::ReadWrite)) { m_modeStream->setDevice(pwmModeFile); *m_modeStream >> m_pwmMode; } else if (pwmModeFile->open(QFile::ReadOnly)) { m_modeStream->setDevice(pwmModeFile); *m_modeStream >> m_pwmMode; } else { qWarning() << "Can't open pwmModeFile " << pwmModeFile->fileName(); delete pwmModeFile; } } } PwmFan::~PwmFan() { delete m_pwmStream; delete m_modeStream; } void PwmFan::update() { Fan::update(); m_pwmStream->seek(0); setPwm(m_pwmStream->readAll().toInt(), false); m_modeStream->seek(0); setPwmMode(m_modeStream->readAll().toInt(), false); } void PwmFan::reset() { Fan::reset(); setHasTemp(false); setTemp(Q_NULLPTR); delete m_pwmStream->device(); delete m_pwmStream; delete m_modeStream->device(); delete m_modeStream; const auto pwmFile = new QFile(m_parent->path() + "/pwm" + QString::number(m_index), this); if (pwmFile->open(QFile::ReadWrite)) { m_pwmStream = new QTextStream(pwmFile); *m_pwmStream >> m_pwm; } else if (pwmFile->open(QFile::ReadOnly)) { m_pwmStream = new QTextStream(pwmFile); *m_pwmStream >> m_pwm; } else { qWarning() << "Can't open pwmFile " << pwmFile->fileName(); delete pwmFile; } const auto pwmModeFile = new QFile(m_parent->path() + "/pwm" + QString::number(m_index) + "_mode", this); if (pwmModeFile->open(QFile::ReadWrite)) { m_modeStream = new QTextStream(pwmModeFile); *m_modeStream >> m_pwmMode; } else if (pwmModeFile->open(QFile::ReadOnly)) { m_modeStream = new QTextStream(pwmModeFile); *m_modeStream >> m_pwmMode; } else { qWarning() << "Can't open pwmModeFile " << pwmModeFile->fileName(); delete pwmModeFile; } } bool PwmFan::setPwm(int pwm, bool write) { if (m_pwm != pwm) { m_pwm = pwm; emit pwmChanged(); if (write) { setPwmMode(1); if (m_pwmStream->device()->isWritable()) *m_pwmStream << pwm; else { auto action = newFancontrolAction(); if (action.isValid()) { QVariantMap map; map[QStringLiteral("action")] = "write"; map[QStringLiteral("filename")] = qobject_cast(m_pwmStream->device())->fileName(); map[QStringLiteral("content")] = QString::number(pwm); action.setArguments(map); const auto job = action.execute(); if (!job->exec()) { if (job->error() == KAuth::ActionReply::HelperBusyError) { qDebug() << "Helper busy..."; QTimer::singleShot(50, this, [this] (){ setPwmMode(m_pwmMode); }); } emit errorChanged(i18n("Could not set pwm: ") + job->errorText()); } update(); } else emit errorChanged(i18n("Action not supported! Try running the application as root."), true); } } } return true; } bool PwmFan::setPwmMode(int pwmMode, bool write) { if (m_pwmMode != pwmMode) { m_pwmMode = pwmMode; emit pwmModeChanged(); if (write) { if (m_modeStream->device()->isWritable()) *m_modeStream << pwmMode; else { auto action = newFancontrolAction(); if (action.isValid()) { QVariantMap map; map[QStringLiteral("action")] = QVariant("write"); map[QStringLiteral("filename")] = qobject_cast(m_modeStream->device())->fileName(); map[QStringLiteral("content")] = QString::number(pwmMode); action.setArguments(map); const auto job = action.execute(); if (!job->exec()) { if (job->error() == KAuth::ActionReply::HelperBusyError) { qDebug() << "Helper busy..."; QTimer::singleShot(50, this, [this] (){ setPwmMode(m_pwmMode); }); } emit errorChanged(i18n("Could not set pwm mode: ") + job->errorText()); } update(); } else emit errorChanged(i18n("Action not supported! Try running the application as root."), true); } } } return true; } void PwmFan::test() { if (!m_modeStream->device()->isWritable() || !m_pwmStream->device()->isWritable()) { auto action = newFancontrolAction(); if (action.isValid()) { const auto job = action.execute(KAuth::Action::AuthorizeOnlyMode); if (!job->exec()) { emit errorChanged(i18n("Authorization error: ") + job->errorText()); m_testStatus = Error; emit testStatusChanged(); return; } } else { emit errorChanged(i18n("Action not supported! Try running the application as root."), true); return; } } setPwm(255, true); m_testStatus = FindingStop1; emit testStatusChanged(); QTimer::singleShot(500, this, &PwmFan::continueTest); qDebug() << "Start testing..."; } void PwmFan::abortTest() { if (m_testStatus >= FindingStop1 && m_testStatus <= FindingStart) { qDebug() << "Abort testing"; m_testStatus = Cancelled; emit testStatusChanged(); setPwm(255); } } void PwmFan::continueTest() { if (!m_modeStream->device()->isWritable() || !m_pwmStream->device()->isWritable()) { auto action = newFancontrolAction(); if (action.status() != KAuth::Action::AuthorizedStatus) { m_testStatus = Error; emit testStatusChanged(); return; } } update(); switch (m_testStatus) { case FindingStop1: if (m_rpm > 0) { setPwm(qMin(m_pwm * 0.95, m_pwm - 5.0)); m_zeroRpm = 0; } else { if (m_zeroRpm < MAX_ERRORS_FOR_RPM_ZERO) { m_zeroRpm++; } else { m_testStatus = FindingStart; m_zeroRpm = 0; qDebug() << "Start finding start value..."; } } QTimer::singleShot(500, this, &PwmFan::continueTest); break; case FindingStart: if (m_rpm == 0) setPwm(m_pwm + 2); else { m_testStatus = FindingStop2; setMinStart(m_pwm); qDebug() << "Start finding stop value..."; } QTimer::singleShot(1000, this, &PwmFan::continueTest); break; case FindingStop2: if (m_rpm > 0) { setPwm(m_pwm - 1); m_zeroRpm = 0; QTimer::singleShot(1000, this, &PwmFan::continueTest); } else { if (m_zeroRpm < MAX_ERRORS_FOR_RPM_ZERO) { m_zeroRpm++; QTimer::singleShot(500, this, &PwmFan::continueTest); } else { m_testStatus = Finished; emit testStatusChanged(); m_zeroRpm = 0; setMinStop(m_pwm + 5); setPwm(255); qDebug() << "Finished testing PwmFan" << m_index; } } break; default: break; } } bool PwmFan::testing() const { return m_testStatus == FindingStop1 || m_testStatus == FindingStop2 || m_testStatus == FindingStart; } bool PwmFan::active() const { const auto active = KSharedConfig::openConfig(QStringLiteral("fancontrol-gui"))->group("active"); const auto localActive = active.group(m_parent->name()); return localActive.readEntry("pwmfan" + QString::number(m_index), true); } void PwmFan::setActive(bool a) { const auto active = KSharedConfig::openConfig(QStringLiteral("fancontrol-gui"))->group("active"); auto localActive = active.group(m_parent->name()); if (a != localActive.readEntry("pwmfan" + QString::number(m_index), true)) { localActive.writeEntry("pwmfan" + QString::number(m_index), a); emit activeChanged(); } } }