8 Commits

Author SHA1 Message Date
Tabascl
8ff1d8be9d Bump version numbers 2024-07-07 23:52:03 +02:00
Tabascl
78b2a62643 Remove aggregator, fix changing HWMON paths
Add logic to use actual device paths for the PWM sensors instead of their
standart HWMON paths.

This was done after noticing that due to the load order of kernel modules,
the index of HWMON paths could change.
2024-07-07 22:19:27 +02:00
e2509cea8b Various fixes
- Change unit path
- Rename method
- Make CurrentPWM method return its value in PWM instead of percent
2023-10-08 13:50:33 +02:00
0a6bab36be Hysteresis, Inhibit-Stop Timeframe 2023-08-28 14:55:07 +02:00
d1649b7de1 Bump version 2023-07-24 13:58:12 +02:00
ff72f8d2ea Add support for zero-fan mode, fix sensor identifiers 2023-07-24 13:55:53 +02:00
ad12f7a981 Switch to meson build system 2023-07-23 23:43:47 +02:00
33a760489e Remove NVIDIA stuff 2023-07-23 18:04:17 +02:00
22 changed files with 352 additions and 221 deletions

View File

@@ -1,19 +1,21 @@
pkgname=fantasize
pkgver=0.1.9
pkgver=0.3.0
pkgrel=1
pkgdesc='C++ fan control for Linux'
url='https://github.com/Tabascl/fantasize.git'
source=("$pkgname-$pkgver.tar.gz::https://github.com/Tabascl/fantasize/archive/refs/tags/v$pkgver.tar.gz")
arch=('x86_64')
license=('GPL3')
makedepends=('git' 'cmake' 'nlohmann-json' 'boost' 'cuda')
makedepends=('git' 'meson' 'nlohmann-json' 'boost')
sha256sums=('SKIP')
build() {
cmake -S "$pkgname-$pkgver/app" -B build -DCMAKE_BUILD_TYPE=Release
cmake --build build
meson setup build "$pkgname-$pkgver/app" -Dbuildtype=Release
cd build
meson compile
}
package() {
cmake --install build --prefix "$pkgdir/" --verbose
cd build
meson install
}

View File

@@ -1,37 +0,0 @@
cmake_minimum_required(VERSION 3.0)
project(fantasize VERSION 0.1.8)
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
find_package(nlohmann_json 3.11.2 REQUIRED)
find_package(Boost 1.74 COMPONENTS program_options log log_setup date_time REQUIRED)
add_executable(${PROJECT_NAME}
src/main.cxx
src/sensor/LMSensorsFacade.cxx
src/sensor/GPUSensorsFacade.cxx
src/sensor/Sensor.cxx
src/sensor/NvidiaSensor.cxx
src/sensor/LMSensor.cxx
src/pwm/PWMControl.cxx
src/pwm/PWMControlFacade.cxx
src/fan/HwmonFan.cxx
src/fan/FanCurve.cxx
src/fan/FanLabeler.cxx
src/fan/Aggregators.cxx
src/FanGenerator.cxx
src/Serializer.cxx
src/sensor/SensorManager.cxx
src/Controller.cxx
src/Settings.cxx
src/App.cxx
)
set_property(TARGET ${PROJECT_NAME} PROPERTY CXX_STANDARD 20)
target_include_directories(${PROJECT_NAME} PUBLIC include /opt/cuda)
target_link_libraries(${PROJECT_NAME} PUBLIC sensors nvidia-ml nlohmann_json::nlohmann_json tbb ${Boost_LIBRARIES})
install(TARGETS ${PROJECT_NAME} DESTINATION usr/local/bin)
install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/unit/fantasize.service DESTINATION usr/lib/systemd/system)

View File

@@ -17,16 +17,16 @@
using json = nlohmann::json;
class Serializer
{
class Serializer {
public:
Serializer();
void SerializeFans(std::vector<std::shared_ptr<Fan>> fans);
std::vector<std::shared_ptr<Fan>> DeserializeFans(
std::vector<std::shared_ptr<Sensor>> availableSensors);
std::vector<std::shared_ptr<FanCurve>> DeserializeFanCurves(
std::vector<std::shared_ptr<Sensor>> availableSensors,
std::vector<std::shared_ptr<Fan>> availableFans);
std::vector<std::shared_ptr<Fan>>
DeserializeFans(std::vector<std::shared_ptr<Sensor>> availableSensors);
std::vector<std::shared_ptr<FanCurve>>
DeserializeFanCurves(std::vector<std::shared_ptr<Sensor>> availableSensors,
std::vector<std::shared_ptr<Fan>> availableFans,
bool &everythingFound);
std::shared_ptr<Settings> DeserializeSettings();
private:

View File

@@ -17,8 +17,13 @@ public:
virtual void StartPWM(int value) = 0;
virtual int StartPWM() = 0;
virtual void ZeroFanModeSupported(bool value) = 0;
virtual bool ZeroFanModeSupported() = 0;
virtual void FindPWMLimits() = 0;
virtual void AdjustPWMLimits() = 0;
virtual void EnforceSetValue() = 0;
};
#endif // FAN_H_

View File

@@ -8,30 +8,31 @@
#include <fan/HwmonFan.h>
#include <sensor/Sensor.h>
struct FanStep
{
struct FanStep {
int Temp;
int Percent;
};
class FanCurve
{
class FanCurve {
public:
FanCurve(std::vector<FanStep> steps,
std::vector<std::shared_ptr<Sensor>> sensors,
std::vector<std::shared_ptr<Fan>> fans,
std::unique_ptr<Aggregator> aggregator);
std::unique_ptr<Aggregator> aggregator, int hysteresis);
void DoFanControl();
private:
int AggregateTemperature();
void PrintInfo();
bool ExceedsHysteresis(int temperature);
void ApplyFanPower(std::shared_ptr<Fan> fan, int targetFanPower);
std::vector<FanStep> mSteps;
std::vector<std::shared_ptr<Sensor>> mTempSensors;
std::vector<std::shared_ptr<Fan>> mFans;
std::unique_ptr<Aggregator> mAggregator;
int mHystersis;
int mLastTemperature;
};
#endif // FANCURVE_H_

View File

@@ -24,21 +24,33 @@ public:
void StartPWM(int value) override;
int StartPWM() override;
void ZeroFanModeSupported(bool value) override;
bool ZeroFanModeSupported() override;
void FindPWMLimits() override;
void AdjustPWMLimits() override;
void EnforceSetValue() override;
json toJson() const override;
const std::string toString() const override;
private:
bool InhibitStopPeriodExpired();
void SetPower(int percent);
std::shared_ptr<PWMControl> mPWMControl;
std::shared_ptr<Sensor> mRpmSensor;
std::string mLabel;
int mMinPWM;
int mStartPWM;
int mMinPWM = 0;
int mStartPWM = 0;
bool mZeroFanModeSupported = false;
std::chrono::time_point<std::chrono::steady_clock> mLastAdjustmentTime;
std::chrono::time_point<std::chrono::steady_clock> mLastStartTime;
int mSetValue = 0;
bool mWasStopped = false;
};
#endif // HWMONFAN_H_

View File

@@ -12,11 +12,11 @@ enum class PWM_MODE { DC = 0, PWM };
class PWMControl : public Printable, public Serializable {
public:
PWMControl(std::string controlPath);
PWMControl(std::string controlPath, int deviceIndex);
~PWMControl();
void Power(int percent);
int Power();
void SetPower(int percent);
int CurrentPWM();
void EnableManualControl();
void Reset();
@@ -26,11 +26,11 @@ public:
json toJson() const override;
private:
int mCurrentValue;
std::string mConfigPath;
std::string mControlPath;
std::string mEnablePath;
std::string mModePath;
int mDeviceIndex;
std::string mInitialEnable;
std::string mInitialMode;

View File

@@ -16,9 +16,13 @@ public:
std::vector<std::shared_ptr<Sensor>> TemperatureSensors();
std::vector<std::shared_ptr<Sensor>> RPMSensors();
void ReloadSensors();
private:
template <sensors_subfeature_type T>
std::vector<std::shared_ptr<Sensor>> Sensors();
void InitSensors();
void CleanupSensors();
private:
FILE *mConfigFile;

View File

@@ -12,6 +12,8 @@ public:
std::vector<std::shared_ptr<Sensor>> TemperatureSensors();
std::vector<std::shared_ptr<Sensor>> RPMSensors();
void ReloadSensors();
private:
std::unique_ptr<LMSensorsFacade> mLMSensorsFacade;
std::unique_ptr<GPUSensorsFacade> mGPUSensorsFacade;

37
app/meson.build Normal file
View File

@@ -0,0 +1,37 @@
project('fantasize', 'cpp', version : '0.3.0', default_options : 'cpp_std=c++20')
src = [
'src/main.cxx',
'src/sensor/LMSensorsFacade.cxx',
'src/sensor/Sensor.cxx',
'src/sensor/LMSensor.cxx',
'src/pwm/PWMControl.cxx',
'src/pwm/PWMControlFacade.cxx',
'src/fan/HwmonFan.cxx',
'src/fan/FanCurve.cxx',
'src/fan/FanLabeler.cxx',
'src/fan/Aggregators.cxx',
'src/FanGenerator.cxx',
'src/Serializer.cxx',
'src/sensor/SensorManager.cxx',
'src/Controller.cxx',
'src/Settings.cxx',
'src/App.cxx'
]
deps = [
dependency('nlohmann_json'),
dependency('boost', modules : ['program_options', 'log', 'log_setup', 'date_time', 'thread']),
dependency('tbb'),
meson.get_compiler('cpp').find_library('sensors')
]
inc = include_directories('include')
exe = executable('fantasize',
src,
dependencies: deps,
install: true,
include_directories: inc)
install_data('unit/fantasize.service', install_dir : '/usr/lib/systemd/system')

View File

@@ -1,14 +1,35 @@
#include "fan/Fan.h"
#include "fan/FanCurve.h"
#include <chrono>
#include <execution>
#include <boost/log/attributes/named_scope.hpp>
#include <boost/log/trivial.hpp>
#include <App.h>
#include <memory>
#include <thread>
using namespace std;
void App::Init() {
mFans = mSerializer.DeserializeFans(mSensorManager.RPMSensors());
BOOST_LOG_FUNCTION();
bool everythingFound = false;
mFans = mSerializer.DeserializeFans(mSensorManager.RPMSensors());
auto fanCurves = mSerializer.DeserializeFanCurves(
mSensorManager.TemperatureSensors(), mFans);
mSensorManager.TemperatureSensors(), mFans, everythingFound);
while (!everythingFound) {
BOOST_LOG_TRIVIAL(info) << "Couldn't find every sensor. Retrying in 5s...";
this_thread::sleep_for(chrono::seconds(5));
mSensorManager.ReloadSensors();
mFans = mSerializer.DeserializeFans(mSensorManager.RPMSensors());
fanCurves = mSerializer.DeserializeFanCurves(
mSensorManager.TemperatureSensors(), mFans, everythingFound);
}
mSettings = mSerializer.DeserializeSettings();

View File

@@ -8,7 +8,7 @@
#include <fan/HwmonFan.h>
#include <pwm/PWMControl.h>
#define SETTLE_TIMEOUT 5
#define SETTLE_TIMEOUT 30
using namespace std;
@@ -22,7 +22,7 @@ FanGenerator::FindFans(vector<shared_ptr<Sensor>> rpmSensors,
cout << "Setting all fans to maximum speed" << endl;
for (auto c : pwmControls) {
c->EnableManualControl();
c->Power(100);
c->SetPower(100);
}
// Wait for fans to settle
@@ -41,7 +41,7 @@ FanGenerator::FindFans(vector<shared_ptr<Sensor>> rpmSensors,
for (auto c : pwmControls) {
cout << "Setting " << c->toString()
<< " to 50% and wait for it to settle..." << endl;
c->Power(50);
c->SetPower(50);
this_thread::sleep_for(chrono::seconds(SETTLE_TIMEOUT));
@@ -53,7 +53,7 @@ FanGenerator::FindFans(vector<shared_ptr<Sensor>> rpmSensors,
}
cout << "Setting fan back to 100%" << endl;
c->Power(100);
c->SetPower(100);
}
return mapping;

View File

@@ -1,9 +1,11 @@
#include <filesystem>
#include <fstream>
#include <iostream>
#include <memory>
#include <boost/log/attributes/named_scope.hpp>
#include <boost/log/trivial.hpp>
#include <Serializer.h>
#include <fan/HwmonFan.h>
#include <pwm/PWMControl.h>
@@ -13,16 +15,13 @@
using namespace std;
namespace fs = filesystem;
Serializer::Serializer()
{
Serializer::Serializer() {
if (!fs::exists(SERIALIZATION_DIR)) {
fs::create_directory(SERIALIZATION_DIR);
}
}
void
Serializer::SerializeFans(vector<shared_ptr<Fan>> fans)
{
void Serializer::SerializeFans(vector<shared_ptr<Fan>> fans) {
json obj;
for (auto f : fans) {
@@ -33,11 +32,12 @@ Serializer::SerializeFans(vector<shared_ptr<Fan>> fans)
}
vector<shared_ptr<Fan>>
Serializer::DeserializeFans(vector<shared_ptr<Sensor>> availableSensors)
{
Serializer::DeserializeFans(vector<shared_ptr<Sensor>> availableSensors) {
BOOST_LOG_FUNCTION();
vector<shared_ptr<Fan>> fans;
// Create a for the sensors first, then searching becomes cheaper
// Create a map for the sensors first, then searching becomes cheaper
map<string, shared_ptr<Sensor>> sensorMap;
for (auto s : availableSensors) {
sensorMap[s->toString()] = s;
@@ -46,29 +46,35 @@ Serializer::DeserializeFans(vector<shared_ptr<Sensor>> availableSensors)
auto data = ReadJson();
try {
for (auto &el : data["fans"].items()) {
auto pwmControl = make_shared<PWMControl>(el.value()["PWMControl"]);
auto pwmControl = make_shared<PWMControl>(el.value()["PWMControl"]["Path"], el.value()["PWMControl"]["Index"]);
auto rpmSensor = sensorMap[el.value()["LMSensor"]];
int minPWM = el.value()["MinPWM"];
int startPWM = el.value()["StartPWM"];
string label = el.value()["Label"];
bool zeroFan = el.value()["ZeroFan"];
auto fan = make_shared<HwmonFan>(pwmControl, rpmSensor);
fan->MinPWM(minPWM);
fan->StartPWM(startPWM);
fan->Label(label);
fan->ZeroFanModeSupported(zeroFan);
fans.push_back(fan);
}
} catch (const std::exception &e) {
std::cout << "Deserialization error! Message: " << e.what() << std::endl;
}
BOOST_LOG_TRIVIAL(trace) << "### Available Fans";
for (auto f : fans) {
BOOST_LOG_TRIVIAL(trace) << f->toString();
}
return fans;
}
void
Serializer::WriteJson(json o)
{
void Serializer::WriteJson(json o) {
json obj;
if (fs::exists(fs::path(SERIALIZATION_DIR) / FANS_JSON_FILENAME)) {
@@ -83,18 +89,17 @@ Serializer::WriteJson(json o)
ostrm << obj.dump(2) << "\n";
}
json
Serializer::ReadJson()
{
json Serializer::ReadJson() {
ifstream istrm(fs::path(SERIALIZATION_DIR) / FANS_JSON_FILENAME);
return json::parse(istrm);
}
vector<shared_ptr<FanCurve>>
Serializer::DeserializeFanCurves(
vector<shared_ptr<FanCurve>> Serializer::DeserializeFanCurves(
std::vector<std::shared_ptr<Sensor>> availableSensors,
std::vector<std::shared_ptr<Fan>> availableFans)
{
std::vector<std::shared_ptr<Fan>> availableFans, bool &everythingFound) {
BOOST_LOG_FUNCTION();
everythingFound = true;
auto data = ReadJson();
map<string, shared_ptr<Sensor>> sensorMap;
@@ -121,6 +126,11 @@ Serializer::DeserializeFanCurves(
for (auto &sensor : el.value()["Sensors"].items()) {
if (sensorMap.contains(sensor.value()))
sensors.push_back(sensorMap[sensor.value()]);
else {
BOOST_LOG_TRIVIAL(warning)
<< "Sensor " << sensor.value() << " not found!";
everythingFound = false;
}
}
for (auto &fan : el.value()["Fans"].items()) {
@@ -131,25 +141,24 @@ Serializer::DeserializeFanCurves(
std::unique_ptr<Aggregator> aggregator =
aggregatorFromString(el.value()["AggregateFunction"]);
curves.push_back(
make_shared<FanCurve>(steps, sensors, fans, std::move(aggregator)));
int hysteresis = el.value()["Hysteresis"];
curves.push_back(make_shared<FanCurve>(steps, sensors, fans,
std::move(aggregator), hysteresis));
}
return curves;
}
std::unique_ptr<Aggregator>
Serializer::aggregatorFromString(std::string str) const
{
Serializer::aggregatorFromString(std::string str) const {
if (str == "max")
return std::make_unique<MaxAggregator>();
else
return std::make_unique<AverageAggregator>();
}
shared_ptr<Settings>
Serializer::DeserializeSettings()
{
shared_ptr<Settings> Serializer::DeserializeSettings() {
int frequency = FREQUENCY_DEFAULT;
auto data = ReadJson();

View File

@@ -1,6 +1,6 @@
#include <boost/log/attributes/named_scope.hpp>
#include <iostream>
#include <boost/log/attributes/named_scope.hpp>
#include <boost/log/trivial.hpp>
#include <fan/FanCurve.h>
@@ -11,23 +11,27 @@ using namespace std;
FanCurve::FanCurve(std::vector<FanStep> steps,
std::vector<std::shared_ptr<Sensor>> sensors,
std::vector<std::shared_ptr<Fan>> fans,
std::unique_ptr<Aggregator> aggregator)
: mSteps(steps)
, mTempSensors(sensors)
, mFans(fans)
, mAggregator(std::move(aggregator))
{
std::unique_ptr<Aggregator> aggregator, int hysteresis)
: mSteps(steps), mTempSensors(sensors), mFans(fans),
mAggregator(std::move(aggregator)), mHystersis(hysteresis),
mLastTemperature(INT_MIN) {
PrintInfo();
}
void
FanCurve::DoFanControl()
{
BOOST_LOG_FUNCTION();
void FanCurve::DoFanControl() {
BOOST_LOG_FUNCTION()
int temp = AggregateTemperature();
BOOST_LOG_TRIVIAL(trace) << "## Fans in curve";
for (auto f : mFans)
BOOST_LOG_TRIVIAL(trace) << f->toString();
int t0, t1, p0, p1;
BOOST_LOG_TRIVIAL(trace) << "## Sensors in curve";
for (auto s : mTempSensors)
BOOST_LOG_TRIVIAL(trace) << s->toString();
int temp = mAggregator->aggregate(mTempSensors);
int t0 = 0, t1 = 0, p0 = 0, p1 = 0;
int targetFanPower;
if (temp <= mSteps[0].Temp) {
@@ -35,7 +39,7 @@ FanCurve::DoFanControl()
} else if (temp > mSteps[mSteps.size() - 1].Temp) {
targetFanPower = mSteps[mSteps.size() - 1].Percent;
} else {
for (int i = 0; i < mSteps.size(); i++) {
for (int i = 0; i < (int)mSteps.size(); i++) {
if (temp > mSteps[i].Temp) {
t0 = mSteps[i].Temp;
p0 = mSteps[i].Percent;
@@ -48,26 +52,26 @@ FanCurve::DoFanControl()
targetFanPower = p0 + ((p1 - p0) / (t1 - t0)) * (temp - t0);
}
BOOST_LOG_TRIVIAL(trace) << "Current temp: " << temp;
BOOST_LOG_TRIVIAL(trace) << "Last temp: " << mLastTemperature;
BOOST_LOG_TRIVIAL(trace) << "# Hysteresis check";
if (ExceedsHysteresis(temp)) {
BOOST_LOG_TRIVIAL(trace) << "passed";
for (auto f : mFans) {
if (f->RPM() <= 0) {
BOOST_LOG_TRIVIAL(warning) << "Fan stopped completely!";
f->PWM(f->StartPWM());
f->AdjustPWMLimits();
ApplyFanPower(f, targetFanPower);
mLastTemperature = temp;
}
} else {
f->PWM(targetFanPower);
}
for (auto f : mFans)
f->EnforceSetValue();
BOOST_LOG_TRIVIAL(trace) << "not passed";
}
}
int
FanCurve::AggregateTemperature()
{
return mAggregator->aggregate(mTempSensors);
}
void
FanCurve::PrintInfo()
{
void FanCurve::PrintInfo() {
BOOST_LOG_FUNCTION()
BOOST_LOG_TRIVIAL(info) << "### Fan curve:";
@@ -103,3 +107,22 @@ FanCurve::PrintInfo()
BOOST_LOG_TRIVIAL(info) << sStream.str();
}
bool FanCurve::ExceedsHysteresis(int temperature) {
int lowThreshold = mLastTemperature - mHystersis;
int highThreshold = mLastTemperature + mHystersis;
return temperature <= lowThreshold || temperature >= highThreshold;
}
void FanCurve::ApplyFanPower(std::shared_ptr<Fan> fan, int targetFanPower) {
BOOST_LOG_FUNCTION();
if (!fan->ZeroFanModeSupported() && fan->RPM() <= 0) {
BOOST_LOG_TRIVIAL(warning) << "Fan " << fan->toString() << " stopped completely!";
fan->PWM(fan->StartPWM());
fan->AdjustPWMLimits();
} else {
fan->PWM(targetFanPower);
}
}

View File

@@ -16,7 +16,7 @@ void FanLabeler::RunFanLabelInteraction(
cout << endl;
for (auto f : fans) {
cout << "Setting fan to max power" << endl;
cout << "Setting fan " << f->toString() << " to max power" << endl;
f->PWM(100);

View File

@@ -1,3 +1,4 @@
#include <chrono>
#include <iostream>
#include <ostream>
#include <thread>
@@ -9,6 +10,7 @@
#include <pwm/PWMControl.h>
#define TIMEOUT 10
#define INHIBIT_STOP_PERIOD 120
#define STEP 2
using namespace std;
@@ -21,10 +23,38 @@ HwmonFan::HwmonFan(std::shared_ptr<PWMControl> pwmControl,
void HwmonFan::PWM(int percent) {
if (percent < mMinPWM) {
mPWMControl->Power(mMinPWM);
if (mZeroFanModeSupported && InhibitStopPeriodExpired()) {
SetPower(percent);
mWasStopped = true;
} else {
mPWMControl->Power(percent);
SetPower(mMinPWM);
}
} else {
if (mWasStopped) {
mWasStopped = false;
mLastStartTime = chrono::steady_clock::now();
SetPower(mStartPWM);
} else {
SetPower(percent);
}
}
}
bool HwmonFan::InhibitStopPeriodExpired() {
BOOST_LOG_FUNCTION();
auto result = chrono::steady_clock::now() - mLastStartTime >
chrono::duration(chrono::seconds(INHIBIT_STOP_PERIOD));
BOOST_LOG_TRIVIAL(trace) << "Inhibit-Stop period expired:"
<< (result ? "true" : "false");
return result;
}
void HwmonFan::SetPower(int percent) {
mPWMControl->SetPower(percent);
mSetValue = percent;
}
int HwmonFan::RPM() { return mRpmSensor->value(); }
@@ -39,6 +69,12 @@ void HwmonFan::StartPWM(int value) { mStartPWM = value; }
int HwmonFan::StartPWM() { return mStartPWM; }
void HwmonFan::ZeroFanModeSupported(bool value) {
mZeroFanModeSupported = value;
}
bool HwmonFan::ZeroFanModeSupported() { return mZeroFanModeSupported; }
void HwmonFan::FindPWMLimits() {
cout << "Looking for minimal PWM" << endl;
int minPWM = 0;
@@ -93,13 +129,13 @@ void HwmonFan::AdjustPWMLimits() {
}
}
void HwmonFan::EnforceSetValue() { mPWMControl->SetPower(mSetValue); }
json HwmonFan::toJson() const {
json obj;
obj = {mPWMControl->toJson(),
mRpmSensor->toJson(),
{"Label", mLabel},
{"MinPWM", mMinPWM},
{"StartPWM", mStartPWM}};
obj = {mPWMControl->toJson(), mRpmSensor->toJson(),
{"Label", mLabel}, {"MinPWM", mMinPWM},
{"StartPWM", mStartPWM}, {"ZeroFan", mZeroFanModeSupported}};
return obj;
}
@@ -107,6 +143,6 @@ const string HwmonFan::toString() const {
if (!mLabel.empty()) {
return mLabel;
} else {
return "fan:" + mPWMControl->toString();
return mPWMControl->toString();
}
}

View File

@@ -20,24 +20,16 @@
#include <App.h>
#define PROJECT_VERSION "v0.1.9"
#define PROJECT_VERSION "v0.3.0"
namespace po = boost::program_options;
namespace logging = boost::log;
App app;
static int doInitialSetup = 0;
void signal_handler(int s) { app.Shutdown(); }
void
signal_handler(int s)
{
app.Shutdown();
}
void
InitLogging(bool verbose)
{
void InitLogging(bool verbose) {
logging::add_console_log(
std::clog,
logging::keywords::format =
@@ -66,9 +58,7 @@ InitLogging(bool verbose)
}
}
int
main(int argc, char** argv)
{
int main(int argc, char **argv) {
BOOST_LOG_FUNCTION()
BOOST_LOG_TRIVIAL(info) << "Version: " << PROJECT_VERSION;
@@ -77,8 +67,8 @@ main(int argc, char** argv)
po::options_description desc("Allowed options");
desc.add_options()("help,h", "produce help message")(
"setup,s", po::bool_switch(), "run initial setup")(
"verbose,v", po::bool_switch(), "print debug info");
"setup,s", po::bool_switch(),
"run initial setup")("verbose,v", po::bool_switch(), "print debug info");
po::variables_map vm;
po::store(po::parse_command_line(argc, argv, desc), vm);

View File

@@ -1,8 +1,8 @@
#include <boost/log/attributes/named_scope.hpp>
#include <filesystem>
#include <fstream>
#include <iostream>
#include <boost/log/attributes/named_scope.hpp>
#include <boost/log/trivial.hpp>
#include <pwm/PWMControl.h>
@@ -15,19 +15,27 @@
using namespace std;
namespace fs = filesystem;
PWMControl::PWMControl(string controlPath)
: mControlPath(controlPath)
{
fs::path pathEnable(mControlPath + PWM_POSTFIX_ENABLE);
fs::path pathMode(mControlPath + PWM_POSTFIX_MODE);
PWMControl::PWMControl(string controlPath, int deviceIndex)
: mConfigPath(controlPath), mDeviceIndex(deviceIndex) {
auto path = fs::path{controlPath};
mEnablePath = pathEnable;
mModePath = pathMode;
int fileCount =
distance(fs::directory_iterator(path), fs::directory_iterator{});
if (fileCount != 1)
throw runtime_error("More than one HWMON device present, unsupported");
for (auto de : fs::directory_iterator(path)) {
auto testPath = de.path();
mControlPath =
fs::path{de.path() / (string("pwm").append(to_string(deviceIndex)))}
.string();
}
mEnablePath = fs::path{mControlPath + PWM_POSTFIX_ENABLE}.string();
mModePath = fs::path{mControlPath + PWM_POSTFIX_MODE}.string();
ifstream istrm;
mCurrentValue = Power();
istrm.open(mEnablePath);
istrm >> mInitialEnable;
istrm.close();
@@ -37,55 +45,44 @@ PWMControl::PWMControl(string controlPath)
istrm.close();
}
PWMControl::~PWMControl()
{
PWMControl::~PWMControl() {
BOOST_LOG_FUNCTION();
BOOST_LOG_TRIVIAL(trace) << "Cleanup";
Reset();
}
void
PWMControl::Power(int percent)
{
void PWMControl::SetPower(int percent) {
BOOST_LOG_FUNCTION();
int pwmValue = (PWM_MAX_VALUE * percent) / 100;
if (percent != mCurrentValue) {
if (pwmValue != CurrentPWM()) {
BOOST_LOG_TRIVIAL(trace) << "Updating control value of " << toString()
<< " to " << percent << "% (" << pwmValue << ")";
ofstream ostrm(mControlPath, ios::trunc);
ostrm << pwmValue;
ostrm.close();
mCurrentValue = percent;
}
}
int
PWMControl::Power()
{
int PWMControl::CurrentPWM() {
int value;
ifstream istrm;
istrm.open(mControlPath);
istrm >> value;
return (value * 100) / PWM_MAX_VALUE;
return value;
}
void
PWMControl::EnableManualControl()
{
void PWMControl::EnableManualControl() {
ofstream ostrm(mEnablePath, ios::trunc);
ostrm << static_cast<int>(PWM_ENABLE::MANUAL_CONTROL);
ostrm.close();
}
void
PWMControl::Reset()
{
void PWMControl::Reset() {
ofstream ostrm(mEnablePath, ios::trunc);
ostrm << mInitialEnable;
@@ -97,15 +94,9 @@ PWMControl::Reset()
ostrm.close();
}
const string
PWMControl::toString() const
{
return fs::path(mControlPath).filename();
}
const string PWMControl::toString() const { return fs::path(mControlPath); }
json
PWMControl::toJson() const
{
json obj = { "PWMControl", mControlPath };
json PWMControl::toJson() const {
json obj = {"PWMControl", {{"Path", mConfigPath}, {"Index", mDeviceIndex}}};
return obj;
}

View File

@@ -1,6 +1,7 @@
#include <filesystem>
#include <iostream>
#include <regex>
#include <string>
#include <pwm/PWMControlFacade.h>
@@ -20,14 +21,20 @@ vector<shared_ptr<PWMControl>> PWMControlFacade::PWMControls() {
for (const fs::directory_entry &hwmon_device :
fs::directory_iterator{HWMON_BASE_PATH}) {
// Resolve symlink to get device path instead of hwmon path, the latter of
// which can change
fs::path actual_path =
fs::canonical(HWMON_BASE_PATH / fs::read_symlink(hwmon_device));
for (const fs::directory_entry &control :
fs::directory_iterator{hwmon_device}) {
fs::directory_iterator{actual_path}) {
auto filename = control.path().filename().string();
if (regex_match(filename, re_ctrl)) {
auto controlPath = control.path().string();
auto controlIndex = filename.back() - '0';
auto controlPath = actual_path.parent_path();
controls.push_back(make_shared<PWMControl>(controlPath));
controls.push_back(make_shared<PWMControl>(controlPath, controlIndex));
}
}
}

View File

@@ -1,3 +1,5 @@
#include <iostream>
#include <boost/json/kind.hpp>
#include <sensor/LMSensor.h>
#include <sensors/sensors.h>
@@ -17,7 +19,9 @@ int LMSensor::value() {
}
const string LMSensor::toString() const {
return sensors_get_label(mChipName, mFeature);
ostringstream os;
os << mChipName->prefix << "." << sensors_get_label(mChipName, mFeature);
return os.str();
}
json LMSensor::toJson() const {

View File

@@ -12,12 +12,10 @@ using namespace std;
#define CONFIG_FILE "/etc/conf.d/sensors"
LMSensorsFacade::LMSensorsFacade() : mConfigFile(fopen(CONFIG_FILE, "r")) {
if (sensors_init(mConfigFile) != 0) {
throw runtime_error("Config file doesn't exist");
}
InitSensors();
}
LMSensorsFacade::~LMSensorsFacade() { sensors_cleanup(); }
LMSensorsFacade::~LMSensorsFacade() { CleanupSensors(); }
std::vector<std::shared_ptr<Sensor>> LMSensorsFacade::TemperatureSensors() {
return Sensors<SENSORS_SUBFEATURE_TEMP_INPUT>();
@@ -48,3 +46,16 @@ std::vector<std::shared_ptr<Sensor>> LMSensorsFacade::Sensors() {
return sensors;
}
void LMSensorsFacade::ReloadSensors() {
CleanupSensors();
InitSensors();
}
void LMSensorsFacade::InitSensors() {
if (sensors_init(mConfigFile) != 0) {
throw runtime_error("Config file doesn't exist");
}
}
void LMSensorsFacade::CleanupSensors() { sensors_cleanup(); }

View File

@@ -1,5 +1,8 @@
#include <sensor/SensorManager.h>
#include <boost/log/attributes/named_scope.hpp>
#include <boost/log/trivial.hpp>
using namespace std;
SensorManager::SensorManager()
@@ -7,12 +10,20 @@ SensorManager::SensorManager()
mGPUSensorsFacade(make_unique<GPUSensorsFacade>()) {}
vector<shared_ptr<Sensor>> SensorManager::TemperatureSensors() {
BOOST_LOG_FUNCTION();
vector<shared_ptr<Sensor>> tempSensors;
tempSensors = mLMSensorsFacade->TemperatureSensors();
auto gpuSensors = mGPUSensorsFacade->TemperatureSensors();
tempSensors.insert(tempSensors.end(), gpuSensors.begin(), gpuSensors.end());
BOOST_LOG_TRIVIAL(trace) << "### Temperature sensors:";
for (auto s : tempSensors) {
BOOST_LOG_TRIVIAL(trace) << s->toString();
}
// auto gpuSensors = mGPUSensorsFacade->TemperatureSensors();
// tempSensors.insert(tempSensors.end(), gpuSensors.begin(),
// gpuSensors.end());
return tempSensors;
}
@@ -20,3 +31,5 @@ vector<shared_ptr<Sensor>> SensorManager::TemperatureSensors() {
vector<shared_ptr<Sensor>> SensorManager::RPMSensors() {
return mLMSensorsFacade->RPMSensors();
}
void SensorManager::ReloadSensors() { mLMSensorsFacade->ReloadSensors(); }