Compare commits

...

45 Commits
v1.1 ... master

Author SHA1 Message Date
BlackMark b7895d61c6 Implement hysteresis for setting monitor brightness 2022-07-22 12:35:00 +02:00
BlackMark 77d9a22419 Fix undefined behavior due to recursive mutex locking, and properly clear sensors when re-enumerating 2022-03-28 20:15:45 +02:00
BlackMark 392a03a23d Fix typo in README 2022-01-18 13:43:57 +01:00
BlackMark e796ff3663 Hide unfinished sensors tab 2020-07-17 18:58:46 +02:00
BlackMark de58e2d472 Reset monitor settings upon startup 2020-07-17 18:53:28 +02:00
BlackMark 314b281c03 Set initial slider position to 50 2020-07-17 18:53:15 +02:00
BlackMark 5253dc1df6 Implement monitor reset button 2020-07-17 18:49:28 +02:00
BlackMark 4bdedbc110 Add missing header 2020-07-17 18:44:22 +02:00
BlackMark 42043bcd55 Implement re-enumerate button 2020-07-17 18:35:56 +02:00
BlackMark 45116d8857 Add mutex to protect update thread 2020-07-17 18:35:38 +02:00
BlackMark c930e316c4 Set tray icon to average brightness value 2020-07-17 17:52:18 +02:00
BlackMark 1e3836cb9f Fix type mismatch warning 2020-07-17 17:37:15 +02:00
BlackMark 7ea9638488 Update overall brightness slider if all monitors match 2020-07-17 17:36:00 +02:00
BlackMark ddec3d2431 Collapse else-if 2020-07-17 17:31:56 +02:00
BlackMark aeca6a5dc0 Only update brightness if manual override is enabled 2020-07-17 17:24:43 +02:00
BlackMark 4956dde368 Implement clamping to min and max brightness 2020-07-17 17:21:08 +02:00
BlackMark 348631fedc Only store valid sensor values 2020-07-17 17:00:57 +02:00
BlackMark fc49f1d779 Implement monitor and overall brightness slider 2020-07-17 16:52:47 +02:00
BlackMark 756bb9b6a7 Remove unnecessary circular updates 2020-07-17 16:34:01 +02:00
BlackMark 5943b72fef Implement limits slider 2020-07-17 16:28:15 +02:00
BlackMark 8f4dec0bff Implement overall limit sliders 2020-07-17 16:15:52 +02:00
BlackMark 78f3daf1ff Remove paramater that matches the default 2020-07-17 16:10:10 +02:00
BlackMark 17a4890fdc Refactor clamped and rounded linear interpolation 2020-07-17 14:54:31 +02:00
BlackMark e4f18911f9 Add placeholder for linux version of monitor getName 2020-07-17 14:53:30 +02:00
BlackMark 17a1eab03d Fix missing library for C++17 filesystem 2020-07-17 14:52:49 +02:00
BlackMark 69b14243bc Fix wrong indentation 2020-07-17 14:52:22 +02:00
BlackMark 65b4fbc484 Fix signed-unsigned comparison warning 2020-07-17 14:51:28 +02:00
BlackMark 5b6dd9e62c Add some GUI abstraction and implement basic monitor selection 2020-07-12 21:04:08 +02:00
BlackMark 994e08bebc Add function to get monitor name 2020-07-12 21:02:51 +02:00
BlackMark 86dbcfda4f Reset everything in monitor move constructor 2020-07-12 19:41:52 +02:00
BlackMark 5e4aba8140 Make sensor move constructible 2020-07-12 19:38:35 +02:00
BlackMark 7b791a071b Implement manual override checkboxes 2020-07-12 19:14:15 +02:00
BlackMark 69a68ce67c Refactor monitor tab GUI setup 2020-07-12 19:06:19 +02:00
BlackMark afd6de62a0 Refactor GUI setup 2020-07-12 18:55:41 +02:00
BlackMark cb9a57a24a Make placeholder values obvious 2020-07-12 18:49:11 +02:00
BlackMark 395e58f94d Give UI elements proper names 2020-07-12 18:44:38 +02:00
BlackMark 200ad19d95 Add GUI layout for monitors and sensors 2020-07-12 18:13:53 +02:00
BlackMark 88600b8915 Add revision 2 of PCB 2020-07-12 17:58:24 +02:00
BlackMark d5dad15d0a Implement log rotation 2020-07-09 21:54:12 +02:00
BlackMark 7331532dfa Reflect watchdog reset with startup color 2020-07-09 20:08:20 +02:00
BlackMark 5169ddd4bd Set watchdog to approximately 2s and add refreshing 2020-07-09 19:58:20 +02:00
BlackMark 8e15ee72f3 Add watch dog timer 2020-07-09 19:41:13 +02:00
BlackMark 7a087c918e Remove duplicate include entries 2020-07-09 19:36:54 +02:00
BlackMark 962dc6ab95 Add readme to firmware 2020-07-09 18:52:36 +02:00
BlackMark d88dc95a44 Rename firmware folder 2020-07-09 18:16:41 +02:00
132 changed files with 5137 additions and 171 deletions

View File

@ -1,13 +1,13 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>AdaptiveBrightnessClass</class>
<widget class="QMainWindow" name="AdaptiveBrightnessClass">
<class>MainWindow</class>
<widget class="QMainWindow" name="MainWindow">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>406</width>
<height>306</height>
<width>450</width>
<height>555</height>
</rect>
</property>
<property name="windowTitle">
@ -17,48 +17,541 @@
<iconset resource="AdaptiveBrightness.qrc">
<normaloff>:/AdaptiveBrightness/resources/system.ico</normaloff>:/AdaptiveBrightness/resources/system.ico</iconset>
</property>
<widget class="QWidget" name="centralWidget">
<layout class="QFormLayout" name="formLayout_2">
<widget class="QWidget" name="mainWidget">
<layout class="QGridLayout" name="gridLayout_3">
<item row="0" column="1">
<widget class="QGroupBox" name="groupBox">
<property name="title">
<string>Manual brightness control</string>
<widget class="QTabWidget" name="tabs">
<property name="currentIndex">
<number>0</number>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="0">
<widget class="QSlider" name="horizontalSlider">
<property name="toolTip">
<string>Brightness</string>
</property>
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
</layout>
<widget class="QWidget" name="monitorTab">
<attribute name="title">
<string>Monitors</string>
</attribute>
<layout class="QGridLayout" name="gridLayout_12">
<item row="0" column="0" colspan="2">
<widget class="QGroupBox" name="monitorGroup">
<property name="title">
<string>Monitor</string>
</property>
<layout class="QGridLayout" name="gridLayout_11">
<item row="0" column="0">
<widget class="QComboBox" name="monitorDropdown">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QPushButton" name="monitorEnumerateButton">
<property name="text">
<string>Re-enumerate</string>
</property>
</widget>
</item>
<item row="1" column="0" colspan="2">
<widget class="QGroupBox" name="monitorLimitsGroup">
<property name="title">
<string>Limits</string>
</property>
<layout class="QGridLayout" name="gridLayout_9">
<item row="1" column="1">
<widget class="QSlider" name="monitorMaxBrightnessSlider">
<property name="value">
<number>50</number>
</property>
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QLabel" name="monitorMinBrightnessLabel">
<property name="text">
<string>Minimum</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QSlider" name="monitorMinBrightnessSlider">
<property name="value">
<number>50</number>
</property>
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="monitorMaxBrightnessLabel">
<property name="text">
<string>Maximum</string>
</property>
</widget>
</item>
<item row="0" column="2">
<widget class="QLabel" name="monitorMinBrightnessValueLabel">
<property name="text">
<string>XXX%</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="1" column="2">
<widget class="QLabel" name="monitorMaxBrightnessValueLabel">
<property name="text">
<string>XXX%</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item row="2" column="0" colspan="2">
<widget class="QGroupBox" name="monitorBrightnessGroup">
<property name="title">
<string>Brightness</string>
</property>
<layout class="QGridLayout" name="gridLayout_2">
<item row="0" column="0">
<widget class="QSlider" name="monitorBrightnessSlider">
<property name="value">
<number>50</number>
</property>
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QCheckBox" name="monitorOverrideCheck">
<property name="text">
<string>Manual override</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QLabel" name="monitorBrightnessValueLabel">
<property name="text">
<string>XXX%</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
</layout>
</widget>
</item>
</layout>
</widget>
</item>
<item row="2" column="0" colspan="2">
<widget class="QGroupBox" name="monitorOverallLimitsGroup">
<property name="title">
<string>Overall limits</string>
</property>
<layout class="QGridLayout" name="gridLayout_10">
<item row="0" column="0">
<widget class="QLabel" name="monitorOverallMinBrightnessLabel">
<property name="text">
<string>Minimum</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QSlider" name="monitorOverallMinBrightnessSlider">
<property name="value">
<number>50</number>
</property>
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
<item row="0" column="2">
<widget class="QLabel" name="monitorOverallMinBrightnessValueLabel">
<property name="text">
<string>XXX%</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="monitorOverallMaxBrightnessLabel">
<property name="text">
<string>Maximum</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QSlider" name="monitorOverallMaxBrightnessSlider">
<property name="value">
<number>50</number>
</property>
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
<item row="1" column="2">
<widget class="QLabel" name="monitorOverallMaxBrightnessValueLabel">
<property name="text">
<string>XXX%</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item row="4" column="0" colspan="2">
<spacer name="monitorBottomSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>218</width>
<height>35</height>
</size>
</property>
</spacer>
</item>
<item row="5" column="0">
<widget class="QPushButton" name="monitorResetButton">
<property name="text">
<string>Restore all monitors to defaults</string>
</property>
</widget>
</item>
<item row="5" column="1">
<spacer name="monitorResetSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item row="3" column="0" colspan="2">
<widget class="QGroupBox" name="monitorOverallBrightnessGroup">
<property name="title">
<string>Overall brightness</string>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="0">
<widget class="QSlider" name="monitorOverallBrightnessSlider">
<property name="value">
<number>50</number>
</property>
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QLabel" name="monitorOverallBrightnessValueLabel">
<property name="text">
<string>XXX%</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QCheckBox" name="monitorOverallOverrideCheck">
<property name="text">
<string>Manual override</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item row="1" column="0" colspan="2">
<spacer name="monitorTopSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
<widget class="QWidget" name="sensorsTab">
<attribute name="title">
<string>Sensors</string>
</attribute>
<layout class="QGridLayout" name="gridLayout_8">
<item row="0" column="0" colspan="2">
<widget class="QGroupBox" name="sensorGroup">
<property name="title">
<string>Sensor module</string>
</property>
<layout class="QGridLayout" name="gridLayout_6">
<item row="0" column="1">
<widget class="QPushButton" name="sensorEnumerateButton">
<property name="text">
<string>Re-enumerate</string>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QComboBox" name="sensorDropdown">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
</widget>
</item>
<item row="1" column="0" colspan="2">
<widget class="QGroupBox" name="sensorReadoutGroup">
<property name="title">
<string>Readout</string>
</property>
<layout class="QGridLayout" name="gridLayout_5">
<item row="0" column="0">
<widget class="QTreeWidget" name="sensorReadoutValues">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="frameShape">
<enum>QFrame::NoFrame</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Plain</enum>
</property>
<property name="verticalScrollBarPolicy">
<enum>Qt::ScrollBarAlwaysOff</enum>
</property>
<property name="sizeAdjustPolicy">
<enum>QAbstractScrollArea::AdjustToContents</enum>
</property>
<property name="indentation">
<number>0</number>
</property>
<column>
<property name="text">
<string>Sensor</string>
</property>
</column>
<column>
<property name="text">
<string>Raw value</string>
</property>
</column>
<column>
<property name="text">
<string>Percentage</string>
</property>
</column>
<item>
<property name="text">
<string>LDR1: Front</string>
</property>
<property name="text">
<string>XXXX</string>
</property>
<property name="text">
<string>XXX%</string>
</property>
</item>
<item>
<property name="text">
<string>LDR2: Bottom</string>
</property>
<property name="text">
<string>XXXX</string>
</property>
<property name="text">
<string>XXX%</string>
</property>
</item>
<item>
<property name="text">
<string>LDR3: Top</string>
</property>
<property name="text">
<string>XXXX</string>
</property>
<property name="text">
<string>XXX%</string>
</property>
</item>
</widget>
</item>
</layout>
</widget>
</item>
<item row="2" column="0" colspan="2">
<widget class="QGroupBox" name="sensorAggregationGroup">
<property name="title">
<string>Sensor aggregation</string>
</property>
<layout class="QGridLayout" name="gridLayout_4">
<item row="0" column="0" colspan="2">
<widget class="QLabel" name="sensorAggregationFunctionLabel">
<property name="text">
<string>Function</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QComboBox" name="sensorAggregationFunctionDropdown">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QLabel" name="sensorAggregationResultLabel">
<property name="text">
<string>Module result:</string>
</property>
</widget>
</item>
<item row="1" column="2">
<widget class="QLabel" name="sensorAggregationValueLabel">
<property name="text">
<string>XXX%</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
</layout>
</widget>
</item>
</layout>
</widget>
</item>
<item row="4" column="0">
<widget class="QPushButton" name="sensorResetButton">
<property name="text">
<string>Restore all sensors to defaults</string>
</property>
</widget>
</item>
<item row="4" column="1">
<spacer name="sensorResetSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item row="2" column="0" colspan="2">
<widget class="QGroupBox" name="sensorTotalAggregationGroup">
<property name="title">
<string>Total aggregation</string>
</property>
<layout class="QGridLayout" name="gridLayout_7">
<item row="0" column="0">
<widget class="QLabel" name="sensorTotalAggregationFunctionLabel">
<property name="text">
<string>Function</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QComboBox" name="sensorTotalAggregationFunctionDropdown">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QLabel" name="sensorTotalAggregationResultLabel">
<property name="text">
<string>Result:</string>
</property>
</widget>
</item>
<item row="1" column="2">
<widget class="QLabel" name="sensorTotalAggregationValueLabel">
<property name="text">
<string>XXX%</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item row="1" column="0" colspan="2">
<spacer name="sensorTopSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
<item row="3" column="0" colspan="2">
<spacer name="sensorBottomSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
</widget>
</item>
</layout>
</widget>
<widget class="QMenuBar" name="menuBar">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>406</width>
<height>21</height>
</rect>
</property>
</widget>
<widget class="QToolBar" name="mainToolBar">
<attribute name="toolBarArea">
<enum>TopToolBarArea</enum>
</attribute>
<attribute name="toolBarBreak">
<bool>false</bool>
</attribute>
</widget>
<widget class="QStatusBar" name="statusBar"/>
</widget>
<layoutdefault spacing="6" margin="11"/>
<resources>

View File

@ -1,14 +1,50 @@
#pragma once
#include <filesystem>
#include <string>
#include <vector>
#include <cstddef>
#include <QDateTime>
#include <QFile>
#include <QMessageLogger>
#include <QString>
#include <QTextStream>
static inline void rotateLog(const std::filesystem::path& logFileName, int numRotatingLogs)
{
const auto generateRotateNames = [&]() {
std::vector<QString> rotateFileNames = {QString().fromStdString(logFileName.string())};
for(int i = 1; i < numRotatingLogs; ++i) {
auto rotateName = logFileName.stem();
rotateName += std::string(".") + std::to_string(i);
rotateName += logFileName.extension();
rotateFileNames.push_back(QString().fromStdString(rotateName.string()));
}
return rotateFileNames;
};
const auto rotateFileNames = generateRotateNames();
for(auto i = static_cast<int>(rotateFileNames.size()) - 2; i >= 0; --i) {
QFile file(rotateFileNames[i]);
QFile newFile(rotateFileNames[i + 1]);
if(file.exists()) {
newFile.remove();
file.rename(rotateFileNames[i + 1]);
}
}
}
void logToFile(QtMsgType msgType, [[maybe_unused]] const QMessageLogContext& msgContext, const QString& msg)
{
constexpr auto LOG_FILE = "AdaptiveBrightness.log";
constexpr auto MAX_LOG_FILE_SIZE = 4 /*MiB*/ * 1024 * 1024;
constexpr auto NUM_ROTATING_LOGS = 4;
const auto logFileName = std::filesystem::path{"AdaptiveBrightness.log"};
const auto dateTime = QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss.zzz");
QString formattedMsg = QString("[%1] ").arg(dateTime);
@ -48,9 +84,15 @@ void logToFile(QtMsgType msgType, [[maybe_unused]] const QMessageLogContext& msg
formattedMsg += QString("%1").arg(msg);
QFile logFile(LOG_FILE);
QFile logFile(QString().fromStdString(logFileName.string()));
logFile.open(QIODevice::WriteOnly | QIODevice::Append);
if(logFile.size() > MAX_LOG_FILE_SIZE) {
logFile.close();
rotateLog(logFileName, NUM_ROTATING_LOGS);
logFile.open(QIODevice::WriteOnly | QIODevice::Append);
}
#if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)
constexpr auto qtEndl = Qt::endl;
#else

View File

@ -5,8 +5,12 @@
#include <cmath>
#include <QAbstractButton>
#include <QCloseEvent>
#include <QGroupBox>
#include <QSlider>
#include <QTabWidget>
#include <QWidget>
#include <QtDebug>
#include <QtGlobal>
@ -15,69 +19,21 @@
#include "sensor_driver.hpp"
#include "utils.hpp"
MainWindow::MainWindow(QWidget* parent) : QMainWindow(parent)
MainWindow::MainWindow(QWidget* parent) : QMainWindow(parent), m_mtx(QMutex::RecursionMode::Recursive)
{
qDebug(ltr("Creating main window"));
m_ui.setupUi(this);
m_manualBrightnessSlider = m_ui.centralWidget->findChild<QGroupBox*>("groupBox")->findChild<QSlider*>("horizontalSlider");
if(m_manualBrightnessSlider) {
connect(m_manualBrightnessSlider, &QSlider::valueChanged, [this](int value) {
const auto mappedBrightness = utils::map(value, 0, 100, 0.f, 1.f);
const auto newBrightness = std::clamp(mappedBrightness, 0.f, 1.f);
qDebug(ltr("Overriding brightness with %1").arg(newBrightness));
m_brightness = newBrightness;
});
}
enumSensors();
enumMonitors();
loadIcons();
setupMonitorsTab();
setupSensorsTab();
if(!QSystemTrayIcon::isSystemTrayAvailable()) {
qWarning(ltr("System tray is not available -> tray icon will be disabled"));
}
else {
qDebug(ltr("System tray is available"));
setupTrayIcon();
m_trayIconMenu = new QMenu(this);
m_showHideAction = m_trayIconMenu->addAction(tr("Show"), [this]() {
if(m_visibility) {
m_showHideAction->setText(tr("Show"));
hide();
}
else {
m_showHideAction->setText(tr("Hide"));
show();
}
m_visibility = !m_visibility;
});
m_trayIconMenu->addSeparator();
m_trayIconMenu->addAction(tr("Quit"), this, &QCoreApplication::quit);
qDebug(ltr("Tray icon context menu initialized"));
m_trayIcon = new QSystemTrayIcon(this);
m_trayIcon->setIcon(*m_errorIcon);
m_trayIcon->setContextMenu(m_trayIconMenu);
m_trayIcon->show();
m_trayIcon->setToolTip(tr("AdaptiveBrightness"));
connect(m_trayIcon, &QSystemTrayIcon::activated, this, &MainWindow::trayIconClicked);
qDebug(ltr("Tray icon initialized"));
}
m_timerThread = new QThread(this);
m_timer = new QTimer(nullptr);
m_timer->setInterval(1000);
m_timer->moveToThread(m_timerThread);
m_timerThread->connect(m_timer, &QTimer::timeout, this, &MainWindow::updateState, Qt::DirectConnection);
m_timer->connect(m_timerThread, SIGNAL(started()), SLOT(start()));
m_timerThread->start();
qDebug(ltr("Tray icon update timer started"));
m_sensors = enumerateSensors();
m_monitors = enumerateMonitors();
setupCallbackTimer();
}
MainWindow::~MainWindow()
@ -96,6 +52,35 @@ void MainWindow::closeEvent(QCloseEvent* event)
event->ignore();
}
void MainWindow::enumSensors()
{
m_sensors.clear();
auto sensors = enumerateSensors();
for(auto& sensor: sensors) {
m_sensors.push_back({std::move(sensor)});
}
}
void MainWindow::enumMonitors()
{
m_mtx.lock();
m_ui.monitorDropdown->clear();
m_monitors.clear();
auto monitors = enumerateMonitors();
for(auto& monitor: monitors) {
const auto currentBrightness = monitor.getBrightness();
m_monitors.push_back({std::move(monitor), 0.f, 1.f, currentBrightness, false});
m_ui.monitorDropdown->addItem(m_monitors.back().driver.getName());
}
m_mtx.unlock();
}
void MainWindow::loadIcons()
{
qDebug(ltr("Loading icons"));
@ -131,13 +116,194 @@ void MainWindow::loadIcons()
qDebug(ltr("Icons loaded"));
}
void MainWindow::setupMonitorsTab()
{
connect(m_ui.monitorDropdown, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &MainWindow::updateCurrentMonitorGUI);
connect(m_ui.monitorEnumerateButton, &QAbstractButton::clicked, [this](bool) { enumMonitors(); });
connect(m_ui.monitorResetButton, &QAbstractButton::clicked, [this](bool) { resetAllMonitorSettings(); });
setupLimitsSlider();
setupOverallLimitsSlider();
setupBrightness();
setupOverallBrightness();
resetAllMonitorSettings();
}
void MainWindow::setupLimitsSlider()
{
connect(m_ui.monitorMinBrightnessSlider, &QSlider::valueChanged, [this](int value) {
m_ui.monitorMinBrightnessValueLabel->setText(tr("%1%").arg(value, 3));
if(value > m_ui.monitorMaxBrightnessSlider->value()) {
m_ui.monitorMaxBrightnessSlider->setValue(value);
}
const auto curIdx = m_ui.monitorDropdown->currentIndex();
m_monitors[curIdx].minBrightness = utils::map(value, 0, 100, 0.f, 1.f);
});
connect(m_ui.monitorMaxBrightnessSlider, &QSlider::valueChanged, [this](int value) {
m_ui.monitorMaxBrightnessValueLabel->setText(tr("%1%").arg(value, 3));
if(value < m_ui.monitorMinBrightnessSlider->value()) {
m_ui.monitorMinBrightnessSlider->setValue(value);
}
const auto curIdx = m_ui.monitorDropdown->currentIndex();
m_monitors[curIdx].maxBrightness = utils::map(value, 0, 100, 0.f, 1.f);
});
}
void MainWindow::setupOverallLimitsSlider()
{
connect(m_ui.monitorOverallMinBrightnessSlider, &QSlider::valueChanged, [this](int value) {
m_ui.monitorOverallMinBrightnessValueLabel->setText(tr("%1%").arg(value, 3));
if(value > m_ui.monitorOverallMaxBrightnessSlider->value()) {
m_ui.monitorOverallMaxBrightnessSlider->setValue(value);
}
for(auto& monitor: m_monitors) {
monitor.minBrightness = utils::map(value, 0, 100, 0.f, 1.f);
}
updateCurrentMonitorGUI(m_ui.monitorDropdown->currentIndex());
});
connect(m_ui.monitorOverallMaxBrightnessSlider, &QSlider::valueChanged, [this](int value) {
m_ui.monitorOverallMaxBrightnessValueLabel->setText(tr("%1%").arg(value, 3));
if(value < m_ui.monitorOverallMinBrightnessSlider->value()) {
m_ui.monitorOverallMinBrightnessSlider->setValue(value);
}
for(auto& monitor: m_monitors) {
monitor.maxBrightness = utils::map(value, 0, 100, 0.f, 1.f);
}
updateCurrentMonitorGUI(m_ui.monitorDropdown->currentIndex());
});
}
void MainWindow::setupBrightness()
{
m_ui.monitorBrightnessSlider->setDisabled(true);
connect(m_ui.monitorBrightnessSlider, &QSlider::valueChanged, [this](int value) {
m_ui.monitorBrightnessValueLabel->setText(tr("%1%").arg(value, 3));
const auto newBrightness = utils::map(value, 0, 100, 0.f, 1.f);
qDebug(ltr("Overriding brightness with %1").arg(newBrightness));
const auto curIdx = m_ui.monitorDropdown->currentIndex();
m_monitors[curIdx].brightness = newBrightness;
});
m_ui.monitorOverrideCheck->setChecked(false);
connect(m_ui.monitorOverrideCheck, &QCheckBox::stateChanged, [this](int state) {
m_ui.monitorBrightnessSlider->setEnabled(state == Qt::CheckState::Checked);
const auto curIdx = m_ui.monitorDropdown->currentIndex();
m_monitors[curIdx].manualOverride = state == Qt::CheckState::Checked;
});
}
void MainWindow::setupOverallBrightness()
{
m_ui.monitorOverallBrightnessSlider->setDisabled(true);
connect(m_ui.monitorOverallBrightnessSlider, &QSlider::valueChanged, [this](int value) {
m_ui.monitorOverallBrightnessValueLabel->setText(tr("%1%").arg(value, 3));
const auto newBrightness = utils::map(value, 0, 100, 0.f, 1.f);
qDebug(ltr("Overriding overall brightness with %1").arg(newBrightness));
for(auto& monitor: m_monitors) {
if(monitor.manualOverride) {
monitor.brightness = newBrightness;
}
}
updateCurrentMonitorGUI(m_ui.monitorDropdown->currentIndex());
});
m_ui.monitorOverallOverrideCheck->setChecked(false);
connect(m_ui.monitorOverallOverrideCheck, &QCheckBox::stateChanged, [this](int state) {
m_ui.monitorOverallBrightnessSlider->setEnabled(state == Qt::CheckState::Checked);
for(auto& monitor: m_monitors) {
monitor.manualOverride = state == Qt::CheckState::Checked;
}
updateCurrentMonitorGUI(m_ui.monitorDropdown->currentIndex());
});
}
void MainWindow::setupSensorsTab()
{
m_ui.tabs->removeTab(1);
}
void MainWindow::setupTrayIcon()
{
loadIcons();
if(!QSystemTrayIcon::isSystemTrayAvailable()) {
qWarning(ltr("System tray is not available -> tray icon will be disabled"));
}
else {
qDebug(ltr("System tray is available"));
m_trayIconMenu = new QMenu(this);
m_showHideAction = m_trayIconMenu->addAction(tr("Show"), [this]() {
if(m_visibility) {
m_showHideAction->setText(tr("Show"));
hide();
}
else {
m_showHideAction->setText(tr("Hide"));
show();
}
m_visibility = !m_visibility;
});
m_trayIconMenu->addSeparator();
m_trayIconMenu->addAction(tr("Quit"), this, &QCoreApplication::quit);
qDebug(ltr("Tray icon context menu initialized"));
m_trayIcon = new QSystemTrayIcon(this);
m_trayIcon->setIcon(*m_errorIcon);
m_trayIcon->setContextMenu(m_trayIconMenu);
m_trayIcon->show();
m_trayIcon->setToolTip(tr("AdaptiveBrightness"));
connect(m_trayIcon, &QSystemTrayIcon::activated, this, &MainWindow::trayIconClicked);
qDebug(ltr("Tray icon initialized"));
}
}
void MainWindow::setupCallbackTimer()
{
m_timerThread = new QThread(this);
m_timer = new QTimer(nullptr);
m_timer->setInterval(1000);
m_timer->moveToThread(m_timerThread);
m_timerThread->connect(m_timer, &QTimer::timeout, this, &MainWindow::updateState, Qt::DirectConnection);
m_timer->connect(m_timerThread, SIGNAL(started()), SLOT(start()));
m_timerThread->start();
qDebug(ltr("Callback timer started"));
}
void MainWindow::resetAllMonitorSettings()
{
m_ui.monitorOverallMinBrightnessSlider->setValue(0);
m_ui.monitorOverallMaxBrightnessSlider->setValue(100);
m_ui.monitorOverallOverrideCheck->setCheckState(Qt::CheckState::Unchecked);
}
void MainWindow::updateCurrentMonitorGUI(int index)
{
if(index == -1) {
return;
}
m_ui.monitorMinBrightnessSlider->setValue(utils::map(m_monitors[index].minBrightness, 0.f, 1.f, 0, 100));
m_ui.monitorMaxBrightnessSlider->setValue(utils::map(m_monitors[index].maxBrightness, 0.f, 1.f, 0, 100));
m_ui.monitorBrightnessSlider->setValue(utils::map(m_monitors[index].brightness, 0.f, 1.f, 0, 100));
m_ui.monitorOverrideCheck->setChecked(m_monitors[index].manualOverride);
}
void MainWindow::updateState()
{
m_mtx.lock();
qDebug(ltr("Updating state"));
bool sensorError = false;
bool monitorError = false;
size_t iconBrightness = 0;
const auto getAverageSensorValue = [this](float& brightness) {
if(m_sensors.empty()) {
@ -147,8 +313,8 @@ void MainWindow::updateState()
std::vector<float> values;
for(auto& sensor: m_sensors) {
const auto sensorValues = sensor.readValues();
if(!sensor) {
const auto sensorValues = sensor.driver.readValues();
if(!sensor.driver) {
return false;
}
values.insert(values.end(), sensorValues.begin(), sensorValues.end());
@ -158,35 +324,22 @@ void MainWindow::updateState()
return true;
};
const auto setAllMonitorsBrightness = [this](float& brightness) {
if(m_monitors.empty()) {
return false;
}
auto brightness = NAN;
bool errorOccurred = false;
for(auto& monitor: m_monitors) {
if(!monitor.setBrightness(brightness)) {
errorOccurred = true;
}
}
return !errorOccurred;
};
if(!getAverageSensorValue(m_brightness)) {
m_sensors = enumerateSensors();
if(!getAverageSensorValue(brightness)) {
enumSensors();
qInfo(ltr("At least one sensor became invalid, re-enumerating sensors found %1 valid sensor(s)").arg(m_sensors.size()));
sensorError = true;
}
const auto roundedBrightness = std::round(utils::map(m_brightness, 0.f, 1.f, 0, 8));
iconBrightness = std::clamp<size_t>(roundedBrightness, 0, 8);
if(!setAllMonitorsBrightness(m_brightness)) {
m_monitors = enumerateMonitors();
if(!setMonitorBrightness(brightness)) {
enumMonitors();
qInfo(ltr("At least one monitor became invalid, re-enumerating monitors found %1 valid monitor(s)").arg(m_monitors.size()));
monitorError = true;
}
const auto iconBrightness = utils::map(brightness, 0.f, 1.f, size_t{0}, size_t{8});
if(!sensorError && !monitorError && m_trayIcon) {
m_trayIcon->setIcon(*m_sensorStateIcons[iconBrightness]);
}
@ -198,12 +351,80 @@ void MainWindow::updateState()
}
if(m_trayIcon) {
m_trayIcon->setToolTip(tr("AdaptiveBrightness - %1%").arg(m_brightness * 100, 0, 'f', 0));
m_trayIcon->setToolTip(tr("AdaptiveBrightness - %1%").arg(brightness * 100, 0, 'f', 0));
}
if(m_manualBrightnessSlider) {
m_manualBrightnessSlider->setValue(utils::map(m_brightness, 0.f, 1.f, 0, 100));
m_mtx.unlock();
}
bool MainWindow::setMonitorBrightness(float& brightness)
{
constexpr auto hysteresis = [](const auto& lowThreshold, const auto& highThreshold, const auto& currentValue, const auto& newValue) {
if(newValue > highThreshold || newValue < lowThreshold)
return newValue;
return currentValue;
};
if(m_monitors.empty()) {
return false;
}
bool errorOccurred = false;
bool allMonitorsSameBrightness = true;
for(size_t i = 0; i < m_monitors.size(); ++i) {
const auto updateMonitorBrightness = [&] {
const auto brightnessRange = m_monitors[i].maxBrightness - m_monitors[i].minBrightness;
const auto hysteresisDelta = m_monitors[i].manualOverride ? 0.f : m_monitors[i].HYSTERESIS_THRESHOLD * brightnessRange;
const auto lowThreshold = std::clamp(m_monitors[i].prevBrightness - hysteresisDelta, m_monitors[i].minBrightness, m_monitors[i].maxBrightness);
const auto highThreshold = std::clamp(m_monitors[i].prevBrightness + hysteresisDelta, m_monitors[i].minBrightness, m_monitors[i].maxBrightness);
if(hysteresis(lowThreshold, highThreshold, m_monitors[i].prevBrightness, m_monitors[i].brightness) != m_monitors[i].prevBrightness) {
qDebug(ltr("Setting monitor %1 brightness from %2 to %3")
.arg(i)
.arg(m_monitors[i].prevBrightness, 0, 'f', 2)
.arg(m_monitors[i].brightness, 0, 'f', 2));
m_monitors[i].prevBrightness = m_monitors[i].brightness;
return m_monitors[i].driver.setBrightness(m_monitors[i].brightness);
}
else {
qDebug(ltr("Hysteresis prevented setting monitor %1 brightness from %2 to %3")
.arg(i)
.arg(m_monitors[i].prevBrightness, 0, 'f', 2)
.arg(m_monitors[i].brightness, 0, 'f', 2));
}
return true;
};
if(!std::isnan(brightness) && !m_monitors[i].manualOverride) {
m_monitors[i].brightness = brightness;
}
m_monitors[i].brightness = std::clamp(m_monitors[i].brightness, m_monitors[i].minBrightness, m_monitors[i].maxBrightness);
if(i > 0 && m_monitors[i - 1].brightness != m_monitors[i].brightness) {
allMonitorsSameBrightness = false;
}
if(!updateMonitorBrightness()) {
errorOccurred = true;
}
else if(m_ui.monitorDropdown->currentIndex() == static_cast<int>(i)) {
updateCurrentMonitorGUI(static_cast<int>(i));
}
}
if(!errorOccurred) {
auto avgBrightness = 0.f;
std::for_each(m_monitors.begin(), m_monitors.end(), [&avgBrightness](const auto& mon) { avgBrightness += mon.brightness; });
avgBrightness /= m_monitors.size();
brightness = avgBrightness;
}
if(allMonitorsSameBrightness) {
m_ui.monitorOverallBrightnessSlider->setValue(utils::map(brightness, 0.f, 1.f, 0, 100));
}
return !errorOccurred;
}
void MainWindow::trayIconClicked(QSystemTrayIcon::ActivationReason reason)

View File

@ -8,6 +8,7 @@
#include <QIcon>
#include <QMainWindow>
#include <QMenu>
#include <QMutex>
#include <QSlider>
#include <QSystemTrayIcon>
#include <QThread>
@ -28,13 +29,33 @@ class MainWindow : public QMainWindow {
private:
void closeEvent(QCloseEvent* event) override;
void enumSensors();
void enumMonitors();
void loadIcons();
void setupMonitorsTab();
void setupLimitsSlider();
void setupOverallLimitsSlider();
void setupBrightness();
void setupOverallBrightness();
void setupSensorsTab();
void setupTrayIcon();
void setupCallbackTimer();
void resetAllMonitorSettings();
void updateCurrentMonitorGUI(int index);
void updateState();
bool setMonitorBrightness(float& brightness);
void trayIconClicked(QSystemTrayIcon::ActivationReason reason);
Ui::AdaptiveBrightnessClass m_ui;
Ui::MainWindow m_ui;
std::array<std::unique_ptr<QIcon>, 9> m_noSensorStateIcons;
std::array<std::unique_ptr<QIcon>, 9> m_sensorStateIcons;
@ -47,11 +68,23 @@ class MainWindow : public QMainWindow {
QThread* m_timerThread = nullptr;
QTimer* m_timer = nullptr;
QMutex m_mtx;
QSlider* m_manualBrightnessSlider = nullptr;
struct SensorData {
Sensor driver;
};
float m_brightness = 0.5f;
struct MonitorData {
static constexpr auto HYSTERESIS_THRESHOLD = 0.05f;
std::vector<Sensor> m_sensors;
std::vector<Monitor> m_monitors;
Monitor driver;
float minBrightness;
float maxBrightness;
float brightness;
float prevBrightness;
bool manualOverride;
};
std::vector<SensorData> m_sensors;
std::vector<MonitorData> m_monitors;
};

View File

@ -10,6 +10,8 @@
#include <physicalmonitorenumerationapi.h>
#include <windows.h>
#include <QString>
namespace detail {
extern BOOL enumMonitorsCallback(HMONITOR, HDC, LPRECT, LPARAM);
@ -26,6 +28,8 @@ class Monitor {
bool setBrightness(float percentage);
float getBrightness();
QString getName() const;
operator bool() const;
private:
@ -53,6 +57,8 @@ class Monitor {
#if defined(__clang__) || defined(__GNUC__)
#include <QString>
class Monitor {
public:
Monitor();
@ -60,6 +66,8 @@ class Monitor {
bool setBrightness(float);
float getBrightness();
QString getName() const;
operator bool() const;
private:

View File

@ -26,6 +26,12 @@ float Monitor::getBrightness()
return NAN;
}
QString Monitor::getName() const
{
qWarning(ltr("Getting monitor name not implemented"));
return "Unknown";
}
Monitor::operator bool() const
{
qWarning(ltr("Checking monitor validity not implemented"));

View File

@ -24,6 +24,8 @@ Monitor::Monitor(Monitor&& other) noexcept
other.m_hMonitor = 0;
other.m_physicalMonitor.name.clear();
other.m_physicalMonitor.handle = 0;
other.m_brightnessRange.reset();
other.m_errorOccurred = false;
}
Monitor::~Monitor()
@ -62,8 +64,7 @@ bool Monitor::setBrightness(float percentage)
return false;
}
const auto mappedBrightness = utils::map(percentage, 0.f, 1.f, m_brightnessRange->first, m_brightnessRange->second);
const auto newBrightness = std::clamp<DWORD>(std::round(mappedBrightness), m_brightnessRange->first, m_brightnessRange->second);
const auto newBrightness = utils::map(percentage, 0.f, 1.f, m_brightnessRange->first, m_brightnessRange->second);
if(!SetMonitorBrightness(m_physicalMonitor.handle, newBrightness)) {
qCritical(ltr("Failed to set brightness of monitor '%1' with handle '0x%2' and physical handle '0x%3', error: %4")
@ -108,7 +109,15 @@ float Monitor::getBrightness()
m_brightnessRange = std::pair{minBrightness, maxBrightness};
m_errorOccurred = false;
return std::clamp(utils::map(brightness, minBrightness, maxBrightness, 0.f, 1.f), 0.f, 1.f);
return utils::map(brightness, minBrightness, maxBrightness, 0.f, 1.f);
}
QString Monitor::getName() const
{
return QString("%1 (0x%2:0x%3)")
.arg(m_physicalMonitor.name)
.arg(reinterpret_cast<qulonglong>(m_hMonitor), 0, 16)
.arg(reinterpret_cast<qulonglong>(m_physicalMonitor.handle), 0, 16);
}
Monitor::operator bool() const

View File

@ -15,6 +15,13 @@ Sensor::~Sensor()
qDebug(ltr("Destroying sensor on serial port %1").arg(m_serialPortName));
}
Sensor::Sensor(Sensor&& other) noexcept : m_serialPortName(other.m_serialPortName), m_errorOccurred(other.m_errorOccurred), m_range(other.m_range)
{
other.m_serialPortName.clear();
other.m_errorOccurred = false;
other.m_range.reset();
}
std::vector<float> Sensor::readValues()
{
qDebug(ltr("Reading values of sensor on port %1").arg(m_serialPortName));
@ -40,8 +47,7 @@ std::vector<float> Sensor::readValues()
std::vector<float> normalizedValues;
for(const auto& value: values) {
const auto mappedValue = utils::map(value, m_range->first, m_range->second, 0.f, 1.f);
normalizedValues.push_back(std::clamp(mappedValue, 0.f, 1.f));
normalizedValues.push_back(utils::map(value, m_range->first, m_range->second, 0.f, 1.f));
}
return normalizedValues;

View File

@ -11,6 +11,8 @@
class Sensor {
public:
Sensor(const Sensor&) = delete;
Sensor(Sensor&& other) noexcept;
~Sensor();
std::vector<float> readValues();
@ -26,7 +28,7 @@ class Sensor {
static constexpr auto SUPPORTED_FIRMWARE = std::string_view{"AdaptiveBrightness v1.2"};
const QString m_serialPortName;
QString m_serialPortName;
bool m_errorOccurred = false;
std::optional<std::pair<int, int>> m_range;

View File

@ -21,7 +21,7 @@ std::vector<Sensor> enumerateSensors()
auto sensor = Sensor(portInfo.portName());
if(sensor.isValidSensor()) {
qInfo(ltr("Successfully enumerated sensor on port %1").arg(portInfo.portName()));
sensors.push_back(sensor);
sensors.push_back(std::move(sensor));
}
}

View File

@ -1,17 +1,30 @@
#pragma once
#include <algorithm>
#include <array>
#include <type_traits>
#include <cmath>
#include <cstddef>
namespace utils {
template<typename InType, typename OutType>
auto map(InType value, InType inMin, InType inMax, OutType outMin, OutType outMax)
auto interpolate(InType value, InType inMin, InType inMax, OutType outMin, OutType outMax)
{
return (value - inMin) * (outMax - outMin) / (inMax - inMin) + outMin;
}
template<typename InType, typename OutType>
auto map(InType value, InType inMin, InType inMax, OutType outMin, OutType outMax)
{
if constexpr(std::is_integral_v<OutType>) {
return std::clamp(static_cast<OutType>(std::round(interpolate(value, inMin, inMax, outMin, outMax))), outMin, outMax);
}
return std::clamp(static_cast<OutType>(interpolate(value, inMin, inMax, outMin, outMax)), outMin, outMax);
}
template<typename>
struct array_size;

File diff suppressed because one or more lines are too long

View File

@ -71,10 +71,16 @@ target_link_libraries(AdaptiveBrightness
Qt5::SerialPort
)
if(CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang|AppleClang")
target_link_libraries(AdaptiveBrightness
stdc++fs
)
endif()
if(MSVC)
target_link_libraries(AdaptiveBrightness
Dxva2.lib
)
target_link_libraries(AdaptiveBrightness
Dxva2.lib
)
endif()
if(MSVC)

14
firmware/.mxproject Normal file

File diff suppressed because one or more lines are too long

View File

@ -6,19 +6,21 @@ GPIO.groupedBy=Group By Peripherals
KeepUserPlacement=false
Mcu.Family=STM32F0
Mcu.IP0=ADC
Mcu.IP1=NVIC
Mcu.IP2=RCC
Mcu.IP3=SYS
Mcu.IP4=USB
Mcu.IP5=USB_DEVICE
Mcu.IPNb=6
Mcu.IP1=IWDG
Mcu.IP2=NVIC
Mcu.IP3=RCC
Mcu.IP4=SYS
Mcu.IP5=USB
Mcu.IP6=USB_DEVICE
Mcu.IPNb=7
Mcu.Name=STM32F042K(4-6)Tx
Mcu.Package=LQFP32
Mcu.Pin0=PA0
Mcu.Pin1=PA1
Mcu.Pin10=PB8
Mcu.Pin11=VP_SYS_VS_Systick
Mcu.Pin12=VP_USB_DEVICE_VS_USB_DEVICE_CDC_FS
Mcu.Pin11=VP_IWDG_VS_IWDG
Mcu.Pin12=VP_SYS_VS_Systick
Mcu.Pin13=VP_USB_DEVICE_VS_USB_DEVICE_CDC_FS
Mcu.Pin2=PA2
Mcu.Pin3=PA7
Mcu.Pin4=PB0
@ -27,7 +29,7 @@ Mcu.Pin6=PA11
Mcu.Pin7=PA12
Mcu.Pin8=PA13
Mcu.Pin9=PA14
Mcu.PinsNb=13
Mcu.PinsNb=14
Mcu.ThirdPartyNb=0
Mcu.UserConstants=
Mcu.UserName=STM32F042K6Tx
@ -87,13 +89,13 @@ ProjectManager.ComputerToolchain=false
ProjectManager.CoupleFile=true
ProjectManager.CustomerFirmwarePackage=
ProjectManager.DefaultFWLocation=true
ProjectManager.DeletePrevious=true
ProjectManager.DeletePrevious=false
ProjectManager.DeviceId=STM32F042K6Tx
ProjectManager.FirmwarePackage=STM32Cube FW_F0 V1.11.0
ProjectManager.FreePins=false
ProjectManager.HalAssertFull=false
ProjectManager.HeapSize=0x000
ProjectManager.KeepUserCode=false
ProjectManager.KeepUserCode=true
ProjectManager.LastFirmware=true
ProjectManager.LibraryCopy=1
ProjectManager.MainLocation=Src
@ -106,7 +108,7 @@ ProjectManager.StackSize=0x700
ProjectManager.TargetToolchain=Makefile
ProjectManager.ToolChainLocation=
ProjectManager.UnderRoot=false
ProjectManager.functionlistsort=1-MX_GPIO_Init-GPIO-false-HAL-true,2-SystemClock_Config-RCC-false-HAL-false,3-MX_ADC_Init-ADC-false-HAL-true,4-MX_USB_DEVICE_Init-USB_DEVICE-false-HAL-false
ProjectManager.functionlistsort=1-MX_GPIO_Init-GPIO-false-HAL-true,2-SystemClock_Config-RCC-false-HAL-false,3-MX_ADC_Init-ADC-false-HAL-true,4-MX_USB_DEVICE_Init-USB_DEVICE-false-HAL-false,5-MX_IWDG_Init-IWDG-false-HAL-true
RCC.AHBFreq_Value=48000000
RCC.APB1Freq_Value=48000000
RCC.APB1TimFreq_Value=48000000
@ -132,6 +134,8 @@ USB_DEVICE.IPParameters=VirtualMode,VirtualModeFS,CLASS_NAME_FS,PRODUCT_STRING_C
USB_DEVICE.PRODUCT_STRING_CDC_FS=AdaptiveBrightness
USB_DEVICE.VirtualMode=Cdc
USB_DEVICE.VirtualModeFS=Cdc_FS
VP_IWDG_VS_IWDG.Mode=IWDG_Activate
VP_IWDG_VS_IWDG.Signal=IWDG_VS_IWDG
VP_SYS_VS_Systick.Mode=SysTick
VP_SYS_VS_Systick.Signal=SYS_VS_Systick
VP_USB_DEVICE_VS_USB_DEVICE_CDC_FS.Mode=CDC_FS

View File

@ -0,0 +1,242 @@
/**
******************************************************************************
* @file stm32f0xx_hal_iwdg.h
* @author MCD Application Team
* @brief Header file of IWDG HAL module.
******************************************************************************
* @attention
*
* <h2><center>&copy; Copyright (c) 2016 STMicroelectronics.
* All rights reserved.</center></h2>
*
* This software component is licensed by ST under BSD 3-Clause license,
* the "License"; You may not use this file except in compliance with the
* License. You may obtain a copy of the License at:
* opensource.org/licenses/BSD-3-Clause
*
******************************************************************************
*/
/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef STM32F0xx_HAL_IWDG_H
#define STM32F0xx_HAL_IWDG_H
#ifdef __cplusplus
extern "C" {
#endif
/* Includes ------------------------------------------------------------------*/
#include "stm32f0xx_hal_def.h"
/** @addtogroup STM32F0xx_HAL_Driver
* @{
*/
/** @defgroup IWDG IWDG
* @{
*/
/* Exported types ------------------------------------------------------------*/
/** @defgroup IWDG_Exported_Types IWDG Exported Types
* @{
*/
/**
* @brief IWDG Init structure definition
*/
typedef struct
{
uint32_t Prescaler; /*!< Select the prescaler of the IWDG.
This parameter can be a value of @ref IWDG_Prescaler */
uint32_t Reload; /*!< Specifies the IWDG down-counter reload value.
This parameter must be a number between Min_Data = 0 and Max_Data = 0x0FFF */
uint32_t Window; /*!< Specifies the window value to be compared to the down-counter.
This parameter must be a number between Min_Data = 0 and Max_Data = 0x0FFF */
} IWDG_InitTypeDef;
/**
* @brief IWDG Handle Structure definition
*/
typedef struct
{
IWDG_TypeDef *Instance; /*!< Register base address */
IWDG_InitTypeDef Init; /*!< IWDG required parameters */
} IWDG_HandleTypeDef;
/**
* @}
*/
/* Exported constants --------------------------------------------------------*/
/** @defgroup IWDG_Exported_Constants IWDG Exported Constants
* @{
*/
/** @defgroup IWDG_Prescaler IWDG Prescaler
* @{
*/
#define IWDG_PRESCALER_4 0x00000000u /*!< IWDG prescaler set to 4 */
#define IWDG_PRESCALER_8 IWDG_PR_PR_0 /*!< IWDG prescaler set to 8 */
#define IWDG_PRESCALER_16 IWDG_PR_PR_1 /*!< IWDG prescaler set to 16 */
#define IWDG_PRESCALER_32 (IWDG_PR_PR_1 | IWDG_PR_PR_0) /*!< IWDG prescaler set to 32 */
#define IWDG_PRESCALER_64 IWDG_PR_PR_2 /*!< IWDG prescaler set to 64 */
#define IWDG_PRESCALER_128 (IWDG_PR_PR_2 | IWDG_PR_PR_0) /*!< IWDG prescaler set to 128 */
#define IWDG_PRESCALER_256 (IWDG_PR_PR_2 | IWDG_PR_PR_1) /*!< IWDG prescaler set to 256 */
/**
* @}
*/
/** @defgroup IWDG_Window_option IWDG Window option
* @{
*/
#define IWDG_WINDOW_DISABLE IWDG_WINR_WIN
/**
* @}
*/
/**
* @}
*/
/* Exported macros -----------------------------------------------------------*/
/** @defgroup IWDG_Exported_Macros IWDG Exported Macros
* @{
*/
/**
* @brief Enable the IWDG peripheral.
* @param __HANDLE__ IWDG handle
* @retval None
*/
#define __HAL_IWDG_START(__HANDLE__) WRITE_REG((__HANDLE__)->Instance->KR, IWDG_KEY_ENABLE)
/**
* @brief Reload IWDG counter with value defined in the reload register
* (write access to IWDG_PR, IWDG_RLR and IWDG_WINR registers disabled).
* @param __HANDLE__ IWDG handle
* @retval None
*/
#define __HAL_IWDG_RELOAD_COUNTER(__HANDLE__) WRITE_REG((__HANDLE__)->Instance->KR, IWDG_KEY_RELOAD)
/**
* @}
*/
/* Exported functions --------------------------------------------------------*/
/** @defgroup IWDG_Exported_Functions IWDG Exported Functions
* @{
*/
/** @defgroup IWDG_Exported_Functions_Group1 Initialization and Start functions
* @{
*/
/* Initialization/Start functions ********************************************/
HAL_StatusTypeDef HAL_IWDG_Init(IWDG_HandleTypeDef *hiwdg);
/**
* @}
*/
/** @defgroup IWDG_Exported_Functions_Group2 IO operation functions
* @{
*/
/* I/O operation functions ****************************************************/
HAL_StatusTypeDef HAL_IWDG_Refresh(IWDG_HandleTypeDef *hiwdg);
/**
* @}
*/
/**
* @}
*/
/* Private constants ---------------------------------------------------------*/
/** @defgroup IWDG_Private_Constants IWDG Private Constants
* @{
*/
/**
* @brief IWDG Key Register BitMask
*/
#define IWDG_KEY_RELOAD 0x0000AAAAu /*!< IWDG Reload Counter Enable */
#define IWDG_KEY_ENABLE 0x0000CCCCu /*!< IWDG Peripheral Enable */
#define IWDG_KEY_WRITE_ACCESS_ENABLE 0x00005555u /*!< IWDG KR Write Access Enable */
#define IWDG_KEY_WRITE_ACCESS_DISABLE 0x00000000u /*!< IWDG KR Write Access Disable */
/**
* @}
*/
/* Private macros ------------------------------------------------------------*/
/** @defgroup IWDG_Private_Macros IWDG Private Macros
* @{
*/
/**
* @brief Enable write access to IWDG_PR, IWDG_RLR and IWDG_WINR registers.
* @param __HANDLE__ IWDG handle
* @retval None
*/
#define IWDG_ENABLE_WRITE_ACCESS(__HANDLE__) WRITE_REG((__HANDLE__)->Instance->KR, IWDG_KEY_WRITE_ACCESS_ENABLE)
/**
* @brief Disable write access to IWDG_PR, IWDG_RLR and IWDG_WINR registers.
* @param __HANDLE__ IWDG handle
* @retval None
*/
#define IWDG_DISABLE_WRITE_ACCESS(__HANDLE__) WRITE_REG((__HANDLE__)->Instance->KR, IWDG_KEY_WRITE_ACCESS_DISABLE)
/**
* @brief Check IWDG prescaler value.
* @param __PRESCALER__ IWDG prescaler value
* @retval None
*/
#define IS_IWDG_PRESCALER(__PRESCALER__) (((__PRESCALER__) == IWDG_PRESCALER_4) || \
((__PRESCALER__) == IWDG_PRESCALER_8) || \
((__PRESCALER__) == IWDG_PRESCALER_16) || \
((__PRESCALER__) == IWDG_PRESCALER_32) || \
((__PRESCALER__) == IWDG_PRESCALER_64) || \
((__PRESCALER__) == IWDG_PRESCALER_128)|| \
((__PRESCALER__) == IWDG_PRESCALER_256))
/**
* @brief Check IWDG reload value.
* @param __RELOAD__ IWDG reload value
* @retval None
*/
#define IS_IWDG_RELOAD(__RELOAD__) ((__RELOAD__) <= IWDG_RLR_RL)
/**
* @brief Check IWDG window value.
* @param __WINDOW__ IWDG window value
* @retval None
*/
#define IS_IWDG_WINDOW(__WINDOW__) ((__WINDOW__) <= IWDG_WINR_WIN)
/**
* @}
*/
/**
* @}
*/
/**
* @}
*/
#ifdef __cplusplus
}
#endif
#endif /* STM32F0xx_HAL_IWDG_H */
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

View File

@ -0,0 +1,264 @@
/**
******************************************************************************
* @file stm32f0xx_hal_iwdg.c
* @author MCD Application Team
* @brief IWDG HAL module driver.
* This file provides firmware functions to manage the following
* functionalities of the Independent Watchdog (IWDG) peripheral:
* + Initialization and Start functions
* + IO operation functions
*
@verbatim
==============================================================================
##### IWDG Generic features #####
==============================================================================
[..]
(+) The IWDG can be started by either software or hardware (configurable
through option byte).
(+) The IWDG is clocked by Low-Speed clock (LSI) and thus stays active even
if the main clock fails.
(+) Once the IWDG is started, the LSI is forced ON and both can not be
disabled. The counter starts counting down from the reset value (0xFFF).
When it reaches the end of count value (0x000) a reset signal is
generated (IWDG reset).
(+) Whenever the key value 0x0000 AAAA is written in the IWDG_KR register,
the IWDG_RLR value is reloaded in the counter and the watchdog reset is
prevented.
(+) The IWDG is implemented in the VDD voltage domain that is still functional
in STOP and STANDBY mode (IWDG reset can wake-up from STANDBY).
IWDGRST flag in RCC_CSR register can be used to inform when an IWDG
reset occurs.
(+) Debug mode : When the microcontroller enters debug mode (core halted),
the IWDG counter either continues to work normally or stops, depending
on DBG_IWDG_STOP configuration bit in DBG module, accessible through
__HAL_DBGMCU_FREEZE_IWDG() and __HAL_DBGMCU_UNFREEZE_IWDG() macros.
[..] Min-max timeout value @32KHz (LSI): ~125us / ~32.7s
The IWDG timeout may vary due to LSI frequency dispersion. STM32F0xx
devices provide the capability to measure the LSI frequency (LSI clock
connected internally to TIM16 CH1 input capture). The measured value
can be used to have an IWDG timeout with an acceptable accuracy.
##### How to use this driver #####
==============================================================================
[..]
(#) Use IWDG using HAL_IWDG_Init() function to :
(++) Enable instance by writing Start keyword in IWDG_KEY register. LSI
clock is forced ON and IWDG counter starts counting down.
(++) Enable write access to configuration registers:
IWDG_PR, IWDG_RLR and IWDG_WINR.
(++) Configure the IWDG prescaler and counter reload value. This reload
value will be loaded in the IWDG counter each time the watchdog is
reloaded, then the IWDG will start counting down from this value.
(++) Wait for status flags to be reset.
(++) Depending on window parameter:
(+++) If Window Init parameter is same as Window register value,
nothing more is done but reload counter value in order to exit
function with exact time base.
(+++) Else modify Window register. This will automatically reload
watchdog counter.
(#) Then the application program must refresh the IWDG counter at regular
intervals during normal operation to prevent an MCU reset, using
HAL_IWDG_Refresh() function.
*** IWDG HAL driver macros list ***
====================================
[..]
Below the list of most used macros in IWDG HAL driver:
(+) __HAL_IWDG_START: Enable the IWDG peripheral
(+) __HAL_IWDG_RELOAD_COUNTER: Reloads IWDG counter with value defined in
the reload register
@endverbatim
******************************************************************************
* @attention
*
* <h2><center>&copy; Copyright (c) 2016 STMicroelectronics.
* All rights reserved.</center></h2>
*
* This software component is licensed by ST under BSD 3-Clause license,
* the "License"; You may not use this file except in compliance with the
* License. You may obtain a copy of the License at:
* opensource.org/licenses/BSD-3-Clause
*
******************************************************************************
*/
/* Includes ------------------------------------------------------------------*/
#include "stm32f0xx_hal.h"
/** @addtogroup STM32F0xx_HAL_Driver
* @{
*/
#ifdef HAL_IWDG_MODULE_ENABLED
/** @addtogroup IWDG
* @brief IWDG HAL module driver.
* @{
*/
/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
/** @defgroup IWDG_Private_Defines IWDG Private Defines
* @{
*/
/* Status register need 5 RC LSI divided by prescaler clock to be updated. With
higher prescaler (256), and according to LSI variation, we need to wait at
least 6 cycles so 48 ms. */
#define HAL_IWDG_DEFAULT_TIMEOUT 48u
/**
* @}
*/
/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
/* Private function prototypes -----------------------------------------------*/
/* Exported functions --------------------------------------------------------*/
/** @addtogroup IWDG_Exported_Functions
* @{
*/
/** @addtogroup IWDG_Exported_Functions_Group1
* @brief Initialization and Start functions.
*
@verbatim
===============================================================================
##### Initialization and Start functions #####
===============================================================================
[..] This section provides functions allowing to:
(+) Initialize the IWDG according to the specified parameters in the
IWDG_InitTypeDef of associated handle.
(+) Manage Window option.
(+) Once initialization is performed in HAL_IWDG_Init function, Watchdog
is reloaded in order to exit function with correct time base.
@endverbatim
* @{
*/
/**
* @brief Initialize the IWDG according to the specified parameters in the
* IWDG_InitTypeDef and start watchdog. Before exiting function,
* watchdog is refreshed in order to have correct time base.
* @param hiwdg pointer to a IWDG_HandleTypeDef structure that contains
* the configuration information for the specified IWDG module.
* @retval HAL status
*/
HAL_StatusTypeDef HAL_IWDG_Init(IWDG_HandleTypeDef *hiwdg)
{
uint32_t tickstart;
/* Check the IWDG handle allocation */
if (hiwdg == NULL)
{
return HAL_ERROR;
}
/* Check the parameters */
assert_param(IS_IWDG_ALL_INSTANCE(hiwdg->Instance));
assert_param(IS_IWDG_PRESCALER(hiwdg->Init.Prescaler));
assert_param(IS_IWDG_RELOAD(hiwdg->Init.Reload));
assert_param(IS_IWDG_WINDOW(hiwdg->Init.Window));
/* Enable IWDG. LSI is turned on automatically */
__HAL_IWDG_START(hiwdg);
/* Enable write access to IWDG_PR, IWDG_RLR and IWDG_WINR registers by writing
0x5555 in KR */
IWDG_ENABLE_WRITE_ACCESS(hiwdg);
/* Write to IWDG registers the Prescaler & Reload values to work with */
hiwdg->Instance->PR = hiwdg->Init.Prescaler;
hiwdg->Instance->RLR = hiwdg->Init.Reload;
/* Check pending flag, if previous update not done, return timeout */
tickstart = HAL_GetTick();
/* Wait for register to be updated */
while (hiwdg->Instance->SR != 0x00u)
{
if ((HAL_GetTick() - tickstart) > HAL_IWDG_DEFAULT_TIMEOUT)
{
return HAL_TIMEOUT;
}
}
/* If window parameter is different than current value, modify window
register */
if (hiwdg->Instance->WINR != hiwdg->Init.Window)
{
/* Write to IWDG WINR the IWDG_Window value to compare with. In any case,
even if window feature is disabled, Watchdog will be reloaded by writing
windows register */
hiwdg->Instance->WINR = hiwdg->Init.Window;
}
else
{
/* Reload IWDG counter with value defined in the reload register */
__HAL_IWDG_RELOAD_COUNTER(hiwdg);
}
/* Return function status */
return HAL_OK;
}
/**
* @}
*/
/** @addtogroup IWDG_Exported_Functions_Group2
* @brief IO operation functions
*
@verbatim
===============================================================================
##### IO operation functions #####
===============================================================================
[..] This section provides functions allowing to:
(+) Refresh the IWDG.
@endverbatim
* @{
*/
/**
* @brief Refresh the IWDG.
* @param hiwdg pointer to a IWDG_HandleTypeDef structure that contains
* the configuration information for the specified IWDG module.
* @retval HAL status
*/
HAL_StatusTypeDef HAL_IWDG_Refresh(IWDG_HandleTypeDef *hiwdg)
{
/* Reload IWDG counter with value defined in the reload register */
__HAL_IWDG_RELOAD_COUNTER(hiwdg);
/* Return function status */
return HAL_OK;
}
/**
* @}
*/
/**
* @}
*/
#endif /* HAL_IWDG_MODULE_ENABLED */
/**
* @}
*/
/**
* @}
*/
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

58
firmware/Inc/iwdg.h Normal file
View File

@ -0,0 +1,58 @@
/**
******************************************************************************
* File Name : IWDG.h
* Description : This file provides code for the configuration
* of the IWDG instances.
******************************************************************************
* @attention
*
* <h2><center>&copy; Copyright (c) 2020 STMicroelectronics.
* All rights reserved.</center></h2>
*
* This software component is licensed by ST under Ultimate Liberty license
* SLA0044, the "License"; You may not use this file except in compliance with
* the License. You may obtain a copy of the License at:
* www.st.com/SLA0044
*
******************************************************************************
*/
/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef __iwdg_H
#define __iwdg_H
#ifdef __cplusplus
extern "C" {
#endif
/* Includes ------------------------------------------------------------------*/
#include "init.h"
/* USER CODE BEGIN Includes */
/* USER CODE END Includes */
extern IWDG_HandleTypeDef hiwdg;
/* USER CODE BEGIN Private defines */
/* USER CODE END Private defines */
void MX_IWDG_Init(void);
/* USER CODE BEGIN Prototypes */
/* USER CODE END Prototypes */
#ifdef __cplusplus
}
#endif
#endif /*__ iwdg_H */
/**
* @}
*/
/**
* @}
*/
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

View File

@ -42,7 +42,7 @@
/*#define HAL_TSC_MODULE_ENABLED */
/*#define HAL_DAC_MODULE_ENABLED */
/*#define HAL_I2S_MODULE_ENABLED */
/*#define HAL_IWDG_MODULE_ENABLED */
#define HAL_IWDG_MODULE_ENABLED
/*#define HAL_LCD_MODULE_ENABLED */
/*#define HAL_LPTIM_MODULE_ENABLED */
/*#define HAL_RNG_MODULE_ENABLED */

Some files were not shown because too many files have changed in this diff Show More